mirror of
https://gitlab.gnome.org/julianschacher/top-bar-organizer.git
synced 2025-10-27 07:09:07 +00:00
Aside from introducing a bunch of type annotations and other code adjustments, also add explicit type checking where necessary. Inline #associateItem into the constructor in PrefsBoxOrderItemRow as the method sets this.item and: > Note that the field needs to be initialized in the constructor itself. > TypeScript does not analyze methods you invoke from the constructor to > detect initializations, because a derived class might override those > methods and fail to initialize the members. https://www.typescriptlang.org/docs/handbook/2/classes.html Explicitly ensure we actually have a Gdk.Drag in #setupDNDScroll in PrefsPage and explicitly only scroll when a DND operation is properly set up. Even tho previously not having a Gdk.Drag in #setupDNDScroll would probably just error out the callback and probably be just fine then, handling this explicitly is at least nicer. Also see the guide on using TypeScript for GNOME Shell Extensions, which was followed for this work to some degree: https://gjs.guide/extensions/development/typescript.html
152 lines
6.3 KiB
TypeScript
152 lines
6.3 KiB
TypeScript
"use strict";
|
|
|
|
import Gtk from "gi://Gtk";
|
|
import Gdk from "gi://Gdk";
|
|
import GObject from "gi://GObject";
|
|
import Adw from "gi://Adw";
|
|
import GLib from "gi://GLib";
|
|
|
|
import type PrefsBoxOrderListBox from "./PrefsBoxOrderListBox.js";
|
|
|
|
export default class PrefsBoxOrderItemRow extends Adw.ActionRow {
|
|
static {
|
|
GObject.registerClass({
|
|
GTypeName: "PrefsBoxOrderItemRow",
|
|
Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-box-order-item-row.ui", GLib.UriFlags.NONE),
|
|
Signals: {
|
|
"move": {
|
|
param_types: [GObject.TYPE_STRING],
|
|
},
|
|
},
|
|
}, this);
|
|
this.install_action("row.forget", null, (self, _actionName, _param) => {
|
|
const parentListBox = self.get_parent() as PrefsBoxOrderListBox;
|
|
parentListBox.removeRow(self as PrefsBoxOrderItemRow);
|
|
parentListBox.saveBoxOrderToSettings();
|
|
parentListBox.determineRowMoveActionEnable();
|
|
});
|
|
this.install_action("row.move-up", null, (self, _actionName, _param) => self.emit("move", "up"));
|
|
this.install_action("row.move-down", null, (self, _actionName, _param) => self.emit("move", "down"));
|
|
}
|
|
|
|
item: string;
|
|
#drag_starting_point_x?: number;
|
|
#drag_starting_point_y?: number;
|
|
|
|
constructor(params = {}, item: string) {
|
|
super(params);
|
|
|
|
// Associate `this` with an item.
|
|
this.item = item;
|
|
if (this.item.startsWith("appindicator-kstatusnotifieritem-")) {
|
|
// Set the title to something nicer, if the associated item is an
|
|
// AppIndicator/KStatusNotifierItem item.
|
|
this.set_title(this.item.replace("appindicator-kstatusnotifieritem-", ""));
|
|
} else if (this.item === "item-role-group-task-up-ultralite") {
|
|
// Set the title to something nicer, if the item in question is the
|
|
// Task Up UltraLite item role group.
|
|
this.set_title("Task Up UltraLite Items");
|
|
} else {
|
|
// Otherwise just set it to `item`.
|
|
this.set_title(this.item);
|
|
}
|
|
}
|
|
|
|
onDragPrepare(_source: Gtk.DragSource, x: number, y: number): Gdk.ContentProvider {
|
|
const value = new GObject.Value();
|
|
value.init(PrefsBoxOrderItemRow.$gtype);
|
|
value.set_object(this);
|
|
|
|
this.#drag_starting_point_x = x;
|
|
this.#drag_starting_point_y = y;
|
|
return Gdk.ContentProvider.new_for_value(value);
|
|
}
|
|
|
|
onDragBegin(_source: Gtk.DragSource, drag: Gdk.Drag): void {
|
|
let dragWidget = new Gtk.ListBox();
|
|
let allocation = this.get_allocation();
|
|
dragWidget.set_size_request(allocation.width, allocation.height);
|
|
|
|
let dragPrefsBoxOrderItemRow = new PrefsBoxOrderItemRow({}, this.item);
|
|
dragWidget.append(dragPrefsBoxOrderItemRow);
|
|
dragWidget.drag_highlight_row(dragPrefsBoxOrderItemRow);
|
|
|
|
let currentDragIcon = Gtk.DragIcon.get_for_drag(drag);
|
|
currentDragIcon.set_child(dragWidget);
|
|
// Even tho this should always be the case, ensure the values for the hotspot aren't undefined.
|
|
if (typeof this.#drag_starting_point_x !== "undefined" &&
|
|
typeof this.#drag_starting_point_y !== "undefined") {
|
|
drag.set_hotspot(this.#drag_starting_point_x, this.#drag_starting_point_y);
|
|
}
|
|
}
|
|
|
|
// Handle a new drop on `this` properly.
|
|
// `value` is the thing getting dropped.
|
|
onDrop(_target: Gtk.DropTarget, value: any, _x: number, _y: number): boolean {
|
|
// According to the type annotations of Gtk.DropTarget, value is of type
|
|
// GObject.Value, so ensure the one we work with is of type
|
|
// PrefsBoxOrderItemRow.
|
|
if (!(value instanceof PrefsBoxOrderItemRow)) {
|
|
// TODO: maybe add logging
|
|
return false;
|
|
}
|
|
|
|
// If `this` got dropped onto itself, do nothing.
|
|
if (value === this) {
|
|
return false;
|
|
}
|
|
|
|
// Get the GtkListBoxes of `this` and the drop value.
|
|
const ownListBox = this.get_parent() as PrefsBoxOrderListBox;
|
|
const valueListBox = value.get_parent() as PrefsBoxOrderListBox;
|
|
|
|
// Get the position of `this` and the drop value.
|
|
const ownPosition = this.get_index();
|
|
const valuePosition = value.get_index();
|
|
|
|
// Remove the drop value from its list box.
|
|
valueListBox.removeRow(value);
|
|
|
|
// Since an element got potentially removed from the list of `this`,
|
|
// get the position of `this` again.
|
|
const updatedOwnPosition = this.get_index();
|
|
|
|
if (ownListBox !== valueListBox) {
|
|
// First handle the case where `this` and the drop value are in
|
|
// different list boxes.
|
|
if ((ownListBox.boxOrder === "right-box-order" && valueListBox.boxOrder === "left-box-order")
|
|
|| (ownListBox.boxOrder === "right-box-order" && valueListBox.boxOrder === "center-box-order")
|
|
|| (ownListBox.boxOrder === "center-box-order" && valueListBox.boxOrder === "left-box-order")) {
|
|
// If the list box of the drop value comes before the list
|
|
// box of `this`, add the drop value after `this`.
|
|
ownListBox.insertRow(value, updatedOwnPosition + 1);
|
|
} else {
|
|
// Otherwise, add the drop value where `this` currently is.
|
|
ownListBox.insertRow(value, updatedOwnPosition);
|
|
}
|
|
} else {
|
|
if (valuePosition < ownPosition) {
|
|
// If the drop value was before `this`, add the drop value
|
|
// after `this`.
|
|
ownListBox.insertRow(value, updatedOwnPosition + 1);
|
|
} else {
|
|
// Otherwise, add the drop value where `this` currently is.
|
|
ownListBox.insertRow(value, updatedOwnPosition);
|
|
}
|
|
}
|
|
|
|
/// Finally save the box order(/s) to settings and make sure move
|
|
/// actions are correctly enabled/disabled.
|
|
ownListBox.saveBoxOrderToSettings();
|
|
ownListBox.determineRowMoveActionEnable();
|
|
// If the list boxes of `this` and the drop value were different, handle
|
|
// the former list box of the drop value as well.
|
|
if (ownListBox !== valueListBox) {
|
|
valueListBox.saveBoxOrderToSettings();
|
|
valueListBox.determineRowMoveActionEnable();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|