"use strict"; import Gtk from "gi://Gtk"; import GObject from "gi://GObject"; import Adw from "gi://Adw"; import GLib from "gi://GLib"; import ScrollManager from "./ScrollManager.js"; import PrefsBoxOrderListEmptyPlaceholder from "./PrefsBoxOrderListEmptyPlaceholder.js"; // Imports to make UI file work. // eslint-disable-next-line import PrefsBoxOrderListBox from "./PrefsBoxOrderListBox.js"; export default class PrefsPage extends Adw.PreferencesPage { static { GObject.registerClass({ GTypeName: "PrefsPage", Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-page.ui", GLib.UriFlags.NONE), InternalChildren: [ "left-box-order-list-box", "center-box-order-list-box", "right-box-order-list-box", ], }, this); } constructor(params = {}) { super(params); this.#setupDNDScroll(); } /** * This function sets up Drag-and-Drop scrolling. * This means that scroll up or down is happening when a Drag-and-Drop * operation is in progress and the user has their cursor either in the * upper or lower 10% of this widget respectively. */ #setupDNDScroll() { // Pass `this.get_first_child()` to the ScrollManager, since this // `PrefsPage` extends an `Adw.PreferencesPage` and the first child of // an `Adw.PreferencesPage` is the built-in `Gtk.ScrolledWindow`. const scrollManager = new ScrollManager(this.get_first_child()); /// Setup GtkDropControllerMotion event controller and make use of its /// events. let controller = new Gtk.DropControllerMotion(); // Scroll, when the pointer is in the right places. controller.connect("motion", (_, _x, y) => { if (y <= this.get_allocated_height() * 0.1) { // If the pointer is currently in the upper ten percent of this // widget, then scroll up. scrollManager.startScrollUp(); } else if (y >= this.get_allocated_height() * 0.9) { // If the pointer is currently in the lower ten percent of this // widget, then scroll down. scrollManager.startScrollDown(); } else { // Otherwise stop scrolling. scrollManager.stopScrollAll(); } }); // Make sure scrolling stops, when DND operation ends. this._dndEnded = true; const stopScrollAllAtDNDEnd = () => { scrollManager.stopScrollAll(); this._dndEnded = true; }; controller.connect("leave", () => { stopScrollAllAtDNDEnd(); }); controller.connect("enter", () => { // Make use of `this._dndEnded` to setup stopScrollAtDNDEnd only // once per DND operation. if (this._dndEnded) { let drag = controller.get_drop().get_drag(); drag.connect("drop-performed", () => { stopScrollAllAtDNDEnd(); }); drag.connect("dnd-finished", () => { stopScrollAllAtDNDEnd(); }); drag.connect("cancel", () => { stopScrollAllAtDNDEnd(); }); this._dndEnded = false; } }); this.add_controller(controller); } onRowMove(listBox, row, direction) { const rowPosition = row.get_index(); if (direction === "up") { // If the direction of the move is up. // Handle the case, where the row is the topmost row in the list box. if (rowPosition === 0) { switch (listBox.boxOrder) { // If the row is also in the topmost list box, then do // nothing and return. case "left-box-order": log("The row is already the topmost row in the topmost box order."); return; // If the row is in the center list box, then move it up to // the left one. case "center-box-order": listBox.removeRow(row); this._left_box_order_list_box.insertRow(row, -1); // First save the box order of the destination, then do // "a save for clean up". this._left_box_order_list_box.saveBoxOrderToSettings(); this._left_box_order_list_box.determineRowMoveActionEnable(); listBox.saveBoxOrderToSettings(); listBox.determineRowMoveActionEnable(); return; // If the row is in the right list box, then move it up to // the center one. case "right-box-order": listBox.removeRow(row); this._center_box_order_list_box.insertRow(row, -1); this._center_box_order_list_box.saveBoxOrderToSettings(); this._center_box_order_list_box.determineRowMoveActionEnable(); listBox.saveBoxOrderToSettings(); listBox.determineRowMoveActionEnable(); return; } } // Else just move the row up in the box. listBox.removeRow(row); listBox.insertRow(row, rowPosition - 1); listBox.saveBoxOrderToSettings(); listBox.determineRowMoveActionEnable(); return; } else { // Else the direction of the move must be down. // Handle the case, where the row is the bottommost row in the list box. const rowNextSibling = row.get_next_sibling(); if (rowNextSibling instanceof PrefsBoxOrderListEmptyPlaceholder || rowNextSibling === null) { switch (listBox.boxOrder) { // If the row is also in the bottommost list box, then do // nothing and return. case "right-box-order": log("The row is already the bottommost row in the bottommost box order."); return; // If the row is in the center list box, then move it down // to the right one. case "center-box-order": listBox.removeRow(row); this._right_box_order_list_box.insertRow(row, 0); this._right_box_order_list_box.saveBoxOrderToSettings(); this._right_box_order_list_box.determineRowMoveActionEnable(); listBox.saveBoxOrderToSettings(); listBox.determineRowMoveActionEnable(); return; // If the row is in the left list box, then move it down to // the center one. case "left-box-order": listBox.removeRow(row); this._center_box_order_list_box.insertRow(row, 0); this._center_box_order_list_box.saveBoxOrderToSettings(); this._center_box_order_list_box.determineRowMoveActionEnable(); listBox.saveBoxOrderToSettings(); listBox.determineRowMoveActionEnable(); return; } } // Else just move the row down in the box. listBox.removeRow(row); listBox.insertRow(row, rowPosition + 1); listBox.saveBoxOrderToSettings(); listBox.determineRowMoveActionEnable(); return; } } }