@gtkx/react 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +373 -0
- package/README.md +390 -0
- package/dist/codegen/jsx-generator.d.ts +37 -0
- package/dist/codegen/jsx-generator.js +554 -0
- package/dist/factory.d.ts +3 -0
- package/dist/factory.js +59 -0
- package/dist/generated/jsx.d.ts +1598 -0
- package/dist/generated/jsx.js +264 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +14 -0
- package/dist/node.d.ts +13 -0
- package/dist/node.js +1 -0
- package/dist/nodes/action-bar.d.ts +27 -0
- package/dist/nodes/action-bar.js +88 -0
- package/dist/nodes/dialog.d.ts +19 -0
- package/dist/nodes/dialog.js +87 -0
- package/dist/nodes/dropdown.d.ts +41 -0
- package/dist/nodes/dropdown.js +163 -0
- package/dist/nodes/grid.d.ts +41 -0
- package/dist/nodes/grid.js +140 -0
- package/dist/nodes/list.d.ts +46 -0
- package/dist/nodes/list.js +165 -0
- package/dist/nodes/notebook.d.ts +25 -0
- package/dist/nodes/notebook.js +88 -0
- package/dist/nodes/overlay.d.ts +29 -0
- package/dist/nodes/overlay.js +109 -0
- package/dist/nodes/slot.d.ts +17 -0
- package/dist/nodes/slot.js +55 -0
- package/dist/nodes/text.d.ts +16 -0
- package/dist/nodes/text.js +31 -0
- package/dist/nodes/widget.d.ts +19 -0
- package/dist/nodes/widget.js +136 -0
- package/dist/portal.d.ts +3 -0
- package/dist/portal.js +11 -0
- package/dist/reconciler.d.ts +20 -0
- package/dist/reconciler.js +111 -0
- package/dist/render.d.ts +5 -0
- package/dist/render.js +12 -0
- package/dist/signal-utils.d.ts +4 -0
- package/dist/signal-utils.js +7 -0
- package/dist/types.d.ts +13 -0
- package/dist/types.js +1 -0
- package/dist/widget-capabilities.d.ts +46 -0
- package/dist/widget-capabilities.js +32 -0
- package/package.json +52 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import * as Gtk from "@gtkx/ffi/gtk";
|
|
2
|
+
import { appendChild, disconnectSignalHandlers, isConnectable, isModelSettable, isSelectable, removeChild, } from "../widget-capabilities.js";
|
|
3
|
+
const isDropDownWidget = (widget) => isModelSettable(widget) && isSelectable(widget) && isConnectable(widget);
|
|
4
|
+
class DropDownStore {
|
|
5
|
+
stringList;
|
|
6
|
+
items = [];
|
|
7
|
+
labelFn;
|
|
8
|
+
constructor(labelFn) {
|
|
9
|
+
this.stringList = new Gtk.StringList([]);
|
|
10
|
+
this.labelFn = labelFn;
|
|
11
|
+
}
|
|
12
|
+
getModel() {
|
|
13
|
+
return this.stringList.ptr;
|
|
14
|
+
}
|
|
15
|
+
append(item) {
|
|
16
|
+
const label = this.labelFn(item);
|
|
17
|
+
this.stringList.append(label);
|
|
18
|
+
this.items.push(item);
|
|
19
|
+
}
|
|
20
|
+
remove(item) {
|
|
21
|
+
const index = this.items.indexOf(item);
|
|
22
|
+
if (index !== -1) {
|
|
23
|
+
this.stringList.remove(index);
|
|
24
|
+
this.items.splice(index, 1);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
getItem(index) {
|
|
28
|
+
return this.items[index];
|
|
29
|
+
}
|
|
30
|
+
get length() {
|
|
31
|
+
return this.items.length;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const dropdownStores = new WeakMap();
|
|
35
|
+
const getOrCreateStore = (widget, labelFn) => {
|
|
36
|
+
let store = dropdownStores.get(widget);
|
|
37
|
+
if (!store) {
|
|
38
|
+
store = new DropDownStore(labelFn);
|
|
39
|
+
dropdownStores.set(widget, store);
|
|
40
|
+
widget.setModel(store.getModel());
|
|
41
|
+
}
|
|
42
|
+
return store;
|
|
43
|
+
};
|
|
44
|
+
export class DropDownNode {
|
|
45
|
+
static needsWidget = true;
|
|
46
|
+
static matches(type, widget) {
|
|
47
|
+
if (type !== "DropDown" && type !== "DropDown.Root")
|
|
48
|
+
return false;
|
|
49
|
+
return widget !== null && isDropDownWidget(widget);
|
|
50
|
+
}
|
|
51
|
+
widget;
|
|
52
|
+
labelFn;
|
|
53
|
+
onSelectionChanged;
|
|
54
|
+
signalHandlers = new Map();
|
|
55
|
+
constructor(_type, widget, props) {
|
|
56
|
+
if (!isDropDownWidget(widget)) {
|
|
57
|
+
throw new Error("DropDownNode requires a DropDown widget");
|
|
58
|
+
}
|
|
59
|
+
this.widget = widget;
|
|
60
|
+
this.labelFn = props.itemLabel ?? ((item) => String(item));
|
|
61
|
+
this.onSelectionChanged = props.onSelectionChanged;
|
|
62
|
+
getOrCreateStore(this.widget, this.labelFn);
|
|
63
|
+
if (this.onSelectionChanged) {
|
|
64
|
+
const handler = () => {
|
|
65
|
+
const index = this.widget.getSelected();
|
|
66
|
+
const store = dropdownStores.get(this.widget);
|
|
67
|
+
const item = store?.getItem(index);
|
|
68
|
+
this.onSelectionChanged?.(item, index);
|
|
69
|
+
};
|
|
70
|
+
const handlerId = this.widget.connect("notify::selected", handler);
|
|
71
|
+
this.signalHandlers.set("notify::selected", handlerId);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
getWidget() {
|
|
75
|
+
return this.widget;
|
|
76
|
+
}
|
|
77
|
+
getLabelFn() {
|
|
78
|
+
return this.labelFn;
|
|
79
|
+
}
|
|
80
|
+
appendChild(child) {
|
|
81
|
+
child.attachToParent(this);
|
|
82
|
+
}
|
|
83
|
+
removeChild(child) {
|
|
84
|
+
child.detachFromParent(this);
|
|
85
|
+
}
|
|
86
|
+
insertBefore(child, _before) {
|
|
87
|
+
this.appendChild(child);
|
|
88
|
+
}
|
|
89
|
+
attachToParent(parent) {
|
|
90
|
+
const parentWidget = parent.getWidget?.();
|
|
91
|
+
if (parentWidget) {
|
|
92
|
+
appendChild(parentWidget, this.widget);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
detachFromParent(parent) {
|
|
96
|
+
const parentWidget = parent.getWidget?.();
|
|
97
|
+
if (parentWidget) {
|
|
98
|
+
removeChild(parentWidget, this.widget);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
updateProps(oldProps, newProps) {
|
|
102
|
+
if (oldProps.onSelectionChanged !== newProps.onSelectionChanged) {
|
|
103
|
+
this.onSelectionChanged = newProps.onSelectionChanged;
|
|
104
|
+
}
|
|
105
|
+
const consumedProps = new Set(["children", "itemLabel", "onSelectionChanged"]);
|
|
106
|
+
const allKeys = new Set([...Object.keys(oldProps), ...Object.keys(newProps)]);
|
|
107
|
+
for (const key of allKeys) {
|
|
108
|
+
if (consumedProps.has(key))
|
|
109
|
+
continue;
|
|
110
|
+
const oldValue = oldProps[key];
|
|
111
|
+
const newValue = newProps[key];
|
|
112
|
+
if (oldValue === newValue)
|
|
113
|
+
continue;
|
|
114
|
+
if (key.startsWith("on")) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const setterName = `set${key.charAt(0).toUpperCase()}${key.slice(1)}`;
|
|
118
|
+
const setter = this.widget[setterName];
|
|
119
|
+
if (typeof setter === "function") {
|
|
120
|
+
setter.call(this.widget, newValue);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
mount() { }
|
|
125
|
+
dispose() {
|
|
126
|
+
disconnectSignalHandlers(this.widget, this.signalHandlers);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
export class DropDownItemNode {
|
|
130
|
+
static needsWidget = false;
|
|
131
|
+
static matches(type, _widget) {
|
|
132
|
+
return type === "DropDown.Item";
|
|
133
|
+
}
|
|
134
|
+
item;
|
|
135
|
+
constructor(_type, _widget, props) {
|
|
136
|
+
this.item = props.item;
|
|
137
|
+
}
|
|
138
|
+
getItem() {
|
|
139
|
+
return this.item;
|
|
140
|
+
}
|
|
141
|
+
appendChild(_child) { }
|
|
142
|
+
removeChild(_child) { }
|
|
143
|
+
insertBefore(_child, _before) { }
|
|
144
|
+
attachToParent(parent) {
|
|
145
|
+
if (!(parent instanceof DropDownNode))
|
|
146
|
+
return;
|
|
147
|
+
const widget = parent.getWidget();
|
|
148
|
+
const labelFn = parent.getLabelFn() ?? ((item) => String(item));
|
|
149
|
+
const store = getOrCreateStore(widget, labelFn);
|
|
150
|
+
store.append(this.item);
|
|
151
|
+
}
|
|
152
|
+
detachFromParent(parent) {
|
|
153
|
+
if (!(parent instanceof DropDownNode))
|
|
154
|
+
return;
|
|
155
|
+
const widget = parent.getWidget();
|
|
156
|
+
const store = dropdownStores.get(widget);
|
|
157
|
+
if (store) {
|
|
158
|
+
store.remove(this.item);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
updateProps(_oldProps, _newProps) { }
|
|
162
|
+
mount() { }
|
|
163
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type * as Gtk from "@gtkx/ffi/gtk";
|
|
2
|
+
import type { Props } from "../factory.js";
|
|
3
|
+
import type { Node } from "../node.js";
|
|
4
|
+
import { type GridAttachable, type Removable } from "../widget-capabilities.js";
|
|
5
|
+
interface GridWidget extends Gtk.Widget, GridAttachable, Removable {
|
|
6
|
+
}
|
|
7
|
+
export declare class GridNode implements Node<GridWidget> {
|
|
8
|
+
static needsWidget: boolean;
|
|
9
|
+
static matches(type: string, widget: Gtk.Widget | null): widget is GridWidget;
|
|
10
|
+
private widget;
|
|
11
|
+
constructor(_type: string, widget: Gtk.Widget, _props: Props);
|
|
12
|
+
getWidget(): GridWidget;
|
|
13
|
+
appendChild(child: Node): void;
|
|
14
|
+
removeChild(child: Node): void;
|
|
15
|
+
insertBefore(child: Node, _before: Node): void;
|
|
16
|
+
attachToParent(parent: Node): void;
|
|
17
|
+
detachFromParent(parent: Node): void;
|
|
18
|
+
updateProps(oldProps: Props, newProps: Props): void;
|
|
19
|
+
mount(): void;
|
|
20
|
+
}
|
|
21
|
+
export declare class GridChildNode implements Node {
|
|
22
|
+
static needsWidget: boolean;
|
|
23
|
+
static matches(type: string, _widget: Gtk.Widget | null): _widget is Gtk.Widget;
|
|
24
|
+
private column;
|
|
25
|
+
private row;
|
|
26
|
+
private columnSpan;
|
|
27
|
+
private rowSpan;
|
|
28
|
+
private childWidget;
|
|
29
|
+
private parentGrid;
|
|
30
|
+
constructor(_type: string, _widget: Gtk.Widget, props: Props);
|
|
31
|
+
appendChild(child: Node): void;
|
|
32
|
+
removeChild(child: Node): void;
|
|
33
|
+
insertBefore(child: Node, _before: Node): void;
|
|
34
|
+
private attachChildToGrid;
|
|
35
|
+
private detachChildFromGrid;
|
|
36
|
+
attachToParent(parent: Node): void;
|
|
37
|
+
detachFromParent(parent: Node): void;
|
|
38
|
+
updateProps(oldProps: Props, newProps: Props): void;
|
|
39
|
+
mount(): void;
|
|
40
|
+
}
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { appendChild, isGridAttachable, isRemovable, removeChild, } from "../widget-capabilities.js";
|
|
2
|
+
const isGridWidget = (widget) => isGridAttachable(widget) && isRemovable(widget);
|
|
3
|
+
export class GridNode {
|
|
4
|
+
static needsWidget = true;
|
|
5
|
+
static matches(type, widget) {
|
|
6
|
+
if (type !== "Grid" && type !== "Grid.Root")
|
|
7
|
+
return false;
|
|
8
|
+
return widget !== null && isGridWidget(widget);
|
|
9
|
+
}
|
|
10
|
+
widget;
|
|
11
|
+
constructor(_type, widget, _props) {
|
|
12
|
+
if (!isGridWidget(widget)) {
|
|
13
|
+
throw new Error("GridNode requires a Grid widget");
|
|
14
|
+
}
|
|
15
|
+
this.widget = widget;
|
|
16
|
+
}
|
|
17
|
+
getWidget() {
|
|
18
|
+
return this.widget;
|
|
19
|
+
}
|
|
20
|
+
appendChild(child) {
|
|
21
|
+
child.attachToParent(this);
|
|
22
|
+
}
|
|
23
|
+
removeChild(child) {
|
|
24
|
+
child.detachFromParent(this);
|
|
25
|
+
}
|
|
26
|
+
insertBefore(child, _before) {
|
|
27
|
+
this.appendChild(child);
|
|
28
|
+
}
|
|
29
|
+
attachToParent(parent) {
|
|
30
|
+
const parentWidget = parent.getWidget?.();
|
|
31
|
+
if (parentWidget) {
|
|
32
|
+
appendChild(parentWidget, this.widget);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
detachFromParent(parent) {
|
|
36
|
+
const parentWidget = parent.getWidget?.();
|
|
37
|
+
if (parentWidget) {
|
|
38
|
+
removeChild(parentWidget, this.widget);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
updateProps(oldProps, newProps) {
|
|
42
|
+
const consumedProps = new Set(["children"]);
|
|
43
|
+
const allKeys = new Set([...Object.keys(oldProps), ...Object.keys(newProps)]);
|
|
44
|
+
for (const key of allKeys) {
|
|
45
|
+
if (consumedProps.has(key))
|
|
46
|
+
continue;
|
|
47
|
+
const oldValue = oldProps[key];
|
|
48
|
+
const newValue = newProps[key];
|
|
49
|
+
if (oldValue === newValue)
|
|
50
|
+
continue;
|
|
51
|
+
if (key.startsWith("on")) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const setterName = `set${key.charAt(0).toUpperCase()}${key.slice(1)}`;
|
|
55
|
+
const setter = this.widget[setterName];
|
|
56
|
+
if (typeof setter === "function") {
|
|
57
|
+
setter.call(this.widget, newValue);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
mount() { }
|
|
62
|
+
}
|
|
63
|
+
export class GridChildNode {
|
|
64
|
+
static needsWidget = false;
|
|
65
|
+
static matches(type, _widget) {
|
|
66
|
+
return type === "Grid.Child";
|
|
67
|
+
}
|
|
68
|
+
column;
|
|
69
|
+
row;
|
|
70
|
+
columnSpan;
|
|
71
|
+
rowSpan;
|
|
72
|
+
childWidget = null;
|
|
73
|
+
parentGrid = null;
|
|
74
|
+
constructor(_type, _widget, props) {
|
|
75
|
+
this.column = props.column ?? 0;
|
|
76
|
+
this.row = props.row ?? 0;
|
|
77
|
+
this.columnSpan = props.columnSpan ?? 1;
|
|
78
|
+
this.rowSpan = props.rowSpan ?? 1;
|
|
79
|
+
}
|
|
80
|
+
appendChild(child) {
|
|
81
|
+
const widget = child.getWidget?.();
|
|
82
|
+
if (widget) {
|
|
83
|
+
this.childWidget = widget;
|
|
84
|
+
if (this.parentGrid) {
|
|
85
|
+
this.attachChildToGrid();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
removeChild(child) {
|
|
90
|
+
const widget = child.getWidget?.();
|
|
91
|
+
if (widget && this.childWidget === widget) {
|
|
92
|
+
this.detachChildFromGrid();
|
|
93
|
+
this.childWidget = null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
insertBefore(child, _before) {
|
|
97
|
+
this.appendChild(child);
|
|
98
|
+
}
|
|
99
|
+
attachChildToGrid() {
|
|
100
|
+
if (!this.parentGrid || !this.childWidget)
|
|
101
|
+
return;
|
|
102
|
+
const grid = this.parentGrid.getWidget();
|
|
103
|
+
grid.attach(this.childWidget.ptr, this.column, this.row, this.columnSpan, this.rowSpan);
|
|
104
|
+
}
|
|
105
|
+
detachChildFromGrid() {
|
|
106
|
+
if (!this.parentGrid || !this.childWidget)
|
|
107
|
+
return;
|
|
108
|
+
const grid = this.parentGrid.getWidget();
|
|
109
|
+
grid.remove(this.childWidget.ptr);
|
|
110
|
+
}
|
|
111
|
+
attachToParent(parent) {
|
|
112
|
+
if (parent instanceof GridNode) {
|
|
113
|
+
this.parentGrid = parent;
|
|
114
|
+
if (this.childWidget) {
|
|
115
|
+
this.attachChildToGrid();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
detachFromParent(parent) {
|
|
120
|
+
if (parent instanceof GridNode) {
|
|
121
|
+
this.detachChildFromGrid();
|
|
122
|
+
this.parentGrid = null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
updateProps(oldProps, newProps) {
|
|
126
|
+
const positionChanged = oldProps.column !== newProps.column ||
|
|
127
|
+
oldProps.row !== newProps.row ||
|
|
128
|
+
oldProps.columnSpan !== newProps.columnSpan ||
|
|
129
|
+
oldProps.rowSpan !== newProps.rowSpan;
|
|
130
|
+
if (positionChanged) {
|
|
131
|
+
this.detachChildFromGrid();
|
|
132
|
+
this.column = newProps.column ?? 0;
|
|
133
|
+
this.row = newProps.row ?? 0;
|
|
134
|
+
this.columnSpan = newProps.columnSpan ?? 1;
|
|
135
|
+
this.rowSpan = newProps.rowSpan ?? 1;
|
|
136
|
+
this.attachChildToGrid();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
mount() { }
|
|
140
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as Gtk from "@gtkx/ffi/gtk";
|
|
2
|
+
import type { Props } from "../factory.js";
|
|
3
|
+
import type { Node } from "../node.js";
|
|
4
|
+
interface ListViewWidget extends Gtk.Widget {
|
|
5
|
+
setModel(model: unknown): void;
|
|
6
|
+
setFactory(factory: unknown): void;
|
|
7
|
+
}
|
|
8
|
+
export declare class ListViewNode<T = unknown> implements Node<ListViewWidget> {
|
|
9
|
+
static needsWidget: boolean;
|
|
10
|
+
static matches(type: string, widget: Gtk.Widget | null): widget is ListViewWidget;
|
|
11
|
+
private widget;
|
|
12
|
+
private stringList;
|
|
13
|
+
private selectionModel;
|
|
14
|
+
private factory;
|
|
15
|
+
private items;
|
|
16
|
+
private renderItem;
|
|
17
|
+
private signalHandlers;
|
|
18
|
+
private factorySignalHandlers;
|
|
19
|
+
constructor(_type: string, widget: Gtk.Widget, props: Props);
|
|
20
|
+
getWidget(): ListViewWidget;
|
|
21
|
+
appendChild(child: Node): void;
|
|
22
|
+
removeChild(child: Node): void;
|
|
23
|
+
insertBefore(child: Node, _before: Node): void;
|
|
24
|
+
attachToParent(parent: Node): void;
|
|
25
|
+
detachFromParent(parent: Node): void;
|
|
26
|
+
addItem(item: T): void;
|
|
27
|
+
removeItem(item: T): void;
|
|
28
|
+
updateProps(oldProps: Props, newProps: Props): void;
|
|
29
|
+
mount(): void;
|
|
30
|
+
dispose(): void;
|
|
31
|
+
}
|
|
32
|
+
export declare class ListItemNode<T = unknown> implements Node {
|
|
33
|
+
static needsWidget: boolean;
|
|
34
|
+
static matches(type: string, _widget: Gtk.Widget | null): _widget is Gtk.Widget;
|
|
35
|
+
private item;
|
|
36
|
+
constructor(_type: string, _widget: Gtk.Widget, props: Props);
|
|
37
|
+
getItem(): T;
|
|
38
|
+
appendChild(_child: Node): void;
|
|
39
|
+
removeChild(_child: Node): void;
|
|
40
|
+
insertBefore(_child: Node, _before: Node): void;
|
|
41
|
+
attachToParent(parent: Node): void;
|
|
42
|
+
detachFromParent(parent: Node): void;
|
|
43
|
+
updateProps(_oldProps: Props, _newProps: Props): void;
|
|
44
|
+
mount(): void;
|
|
45
|
+
}
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import * as Gtk from "@gtkx/ffi/gtk";
|
|
2
|
+
import { appendChild, disconnectSignalHandlers, isConnectable, removeChild } from "../widget-capabilities.js";
|
|
3
|
+
const isListViewWidget = (widget) => "setModel" in widget &&
|
|
4
|
+
typeof widget.setModel === "function" &&
|
|
5
|
+
"setFactory" in widget &&
|
|
6
|
+
typeof widget.setFactory === "function";
|
|
7
|
+
const LIST_VIEW_TYPES = ["ListView", "ListView.Root"];
|
|
8
|
+
export class ListViewNode {
|
|
9
|
+
static needsWidget = true;
|
|
10
|
+
static matches(type, widget) {
|
|
11
|
+
if (!LIST_VIEW_TYPES.includes(type) && !type.startsWith("ListView"))
|
|
12
|
+
return false;
|
|
13
|
+
return widget !== null && isListViewWidget(widget);
|
|
14
|
+
}
|
|
15
|
+
widget;
|
|
16
|
+
stringList;
|
|
17
|
+
selectionModel;
|
|
18
|
+
factory;
|
|
19
|
+
items = [];
|
|
20
|
+
renderItem = null;
|
|
21
|
+
signalHandlers = new Map();
|
|
22
|
+
factorySignalHandlers = new Map();
|
|
23
|
+
constructor(_type, widget, props) {
|
|
24
|
+
if (!isListViewWidget(widget)) {
|
|
25
|
+
throw new Error("ListViewNode requires a ListView widget");
|
|
26
|
+
}
|
|
27
|
+
this.widget = widget;
|
|
28
|
+
this.stringList = new Gtk.StringList([]);
|
|
29
|
+
this.selectionModel = new Gtk.SingleSelection(this.stringList);
|
|
30
|
+
this.factory = new Gtk.SignalListItemFactory();
|
|
31
|
+
this.renderItem = props.renderItem;
|
|
32
|
+
const setupHandlerId = this.factory.connect("setup", (listItemPtr) => {
|
|
33
|
+
const listItem = Object.create(Gtk.ListItem.prototype);
|
|
34
|
+
listItem.ptr = listItemPtr;
|
|
35
|
+
if (this.renderItem) {
|
|
36
|
+
const widget = this.renderItem(null);
|
|
37
|
+
listItem.setChild(widget);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
this.factorySignalHandlers.set("setup", setupHandlerId);
|
|
41
|
+
const bindHandlerId = this.factory.connect("bind", (listItemPtr) => {
|
|
42
|
+
const listItem = Object.create(Gtk.ListItem.prototype);
|
|
43
|
+
listItem.ptr = listItemPtr;
|
|
44
|
+
const position = listItem.getPosition();
|
|
45
|
+
const item = this.items[position];
|
|
46
|
+
if (this.renderItem && item !== undefined) {
|
|
47
|
+
const widget = this.renderItem(item);
|
|
48
|
+
listItem.setChild(widget);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
this.factorySignalHandlers.set("bind", bindHandlerId);
|
|
52
|
+
this.widget.setModel(this.selectionModel.ptr);
|
|
53
|
+
this.widget.setFactory(this.factory.ptr);
|
|
54
|
+
}
|
|
55
|
+
getWidget() {
|
|
56
|
+
return this.widget;
|
|
57
|
+
}
|
|
58
|
+
appendChild(child) {
|
|
59
|
+
child.attachToParent(this);
|
|
60
|
+
}
|
|
61
|
+
removeChild(child) {
|
|
62
|
+
child.detachFromParent(this);
|
|
63
|
+
}
|
|
64
|
+
insertBefore(child, _before) {
|
|
65
|
+
this.appendChild(child);
|
|
66
|
+
}
|
|
67
|
+
attachToParent(parent) {
|
|
68
|
+
const parentWidget = parent.getWidget?.();
|
|
69
|
+
if (parentWidget) {
|
|
70
|
+
appendChild(parentWidget, this.widget);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
detachFromParent(parent) {
|
|
74
|
+
const parentWidget = parent.getWidget?.();
|
|
75
|
+
if (parentWidget) {
|
|
76
|
+
removeChild(parentWidget, this.widget);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
addItem(item) {
|
|
80
|
+
this.items.push(item);
|
|
81
|
+
this.stringList.append("");
|
|
82
|
+
}
|
|
83
|
+
removeItem(item) {
|
|
84
|
+
const index = this.items.indexOf(item);
|
|
85
|
+
if (index !== -1) {
|
|
86
|
+
this.items.splice(index, 1);
|
|
87
|
+
this.stringList.remove(index);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
updateProps(oldProps, newProps) {
|
|
91
|
+
if (oldProps.renderItem !== newProps.renderItem) {
|
|
92
|
+
this.renderItem = newProps.renderItem;
|
|
93
|
+
}
|
|
94
|
+
const consumedProps = new Set(["children", "renderItem"]);
|
|
95
|
+
const allKeys = new Set([...Object.keys(oldProps), ...Object.keys(newProps)]);
|
|
96
|
+
for (const key of allKeys) {
|
|
97
|
+
if (consumedProps.has(key))
|
|
98
|
+
continue;
|
|
99
|
+
const oldValue = oldProps[key];
|
|
100
|
+
const newValue = newProps[key];
|
|
101
|
+
if (oldValue === newValue)
|
|
102
|
+
continue;
|
|
103
|
+
if (key.startsWith("on")) {
|
|
104
|
+
const eventName = key
|
|
105
|
+
.slice(2)
|
|
106
|
+
.replace(/([A-Z])/g, "-$1")
|
|
107
|
+
.toLowerCase()
|
|
108
|
+
.replace(/^-/, "");
|
|
109
|
+
const oldHandlerId = this.signalHandlers.get(eventName);
|
|
110
|
+
if (oldHandlerId !== undefined && isConnectable(this.widget)) {
|
|
111
|
+
this.signalHandlers.delete(eventName);
|
|
112
|
+
}
|
|
113
|
+
if (typeof newValue === "function" && isConnectable(this.widget)) {
|
|
114
|
+
const handlerId = this.widget.connect(eventName, newValue);
|
|
115
|
+
this.signalHandlers.set(eventName, handlerId);
|
|
116
|
+
}
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const setterName = `set${key.charAt(0).toUpperCase()}${key.slice(1)}`;
|
|
120
|
+
const setter = this.widget[setterName];
|
|
121
|
+
if (typeof setter === "function") {
|
|
122
|
+
setter.call(this.widget, newValue);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
mount() { }
|
|
127
|
+
dispose() {
|
|
128
|
+
disconnectSignalHandlers(this.widget, this.signalHandlers);
|
|
129
|
+
disconnectSignalHandlers(this.factory, this.factorySignalHandlers);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const LIST_WIDGETS = ["ListView", "ColumnView", "GridView"];
|
|
133
|
+
export class ListItemNode {
|
|
134
|
+
static needsWidget = false;
|
|
135
|
+
static matches(type, _widget) {
|
|
136
|
+
const dotIndex = type.indexOf(".");
|
|
137
|
+
if (dotIndex === -1)
|
|
138
|
+
return false;
|
|
139
|
+
const widgetType = type.slice(0, dotIndex);
|
|
140
|
+
const suffix = type.slice(dotIndex + 1);
|
|
141
|
+
return suffix === "Item" && LIST_WIDGETS.includes(widgetType);
|
|
142
|
+
}
|
|
143
|
+
item;
|
|
144
|
+
constructor(_type, _widget, props) {
|
|
145
|
+
this.item = props.item;
|
|
146
|
+
}
|
|
147
|
+
getItem() {
|
|
148
|
+
return this.item;
|
|
149
|
+
}
|
|
150
|
+
appendChild(_child) { }
|
|
151
|
+
removeChild(_child) { }
|
|
152
|
+
insertBefore(_child, _before) { }
|
|
153
|
+
attachToParent(parent) {
|
|
154
|
+
if (parent instanceof ListViewNode) {
|
|
155
|
+
parent.addItem(this.item);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
detachFromParent(parent) {
|
|
159
|
+
if (parent instanceof ListViewNode) {
|
|
160
|
+
parent.removeItem(this.item);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
updateProps(_oldProps, _newProps) { }
|
|
164
|
+
mount() { }
|
|
165
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type * as Gtk from "@gtkx/ffi/gtk";
|
|
2
|
+
import type { Props } from "../factory.js";
|
|
3
|
+
import type { Node } from "../node.js";
|
|
4
|
+
import { type NotebookLike } from "../widget-capabilities.js";
|
|
5
|
+
interface NotebookWidget extends Gtk.Widget, NotebookLike {
|
|
6
|
+
}
|
|
7
|
+
export declare class NotebookNode implements Node<NotebookWidget> {
|
|
8
|
+
static needsWidget: boolean;
|
|
9
|
+
static matches(type: string, widget: Gtk.Widget | null): widget is NotebookWidget;
|
|
10
|
+
private widget;
|
|
11
|
+
private signalHandlers;
|
|
12
|
+
constructor(_type: string, widget: Gtk.Widget, _props: Props);
|
|
13
|
+
getWidget(): NotebookWidget;
|
|
14
|
+
appendChild(child: Node): void;
|
|
15
|
+
removeChild(child: Node): void;
|
|
16
|
+
insertBefore(child: Node, _before: Node): void;
|
|
17
|
+
attachToParent(parent: Node): void;
|
|
18
|
+
detachFromParent(parent: Node): void;
|
|
19
|
+
attachChild(childWidget: Gtk.Widget): void;
|
|
20
|
+
detachChild(childWidget: Gtk.Widget): void;
|
|
21
|
+
updateProps(oldProps: Props, newProps: Props): void;
|
|
22
|
+
mount(): void;
|
|
23
|
+
dispose(): void;
|
|
24
|
+
}
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { appendChild, disconnectSignalHandlers, isConnectable, isNotebookLike, removeChild, } from "../widget-capabilities.js";
|
|
2
|
+
const isNotebookWidget = (widget) => isNotebookLike(widget);
|
|
3
|
+
export class NotebookNode {
|
|
4
|
+
static needsWidget = true;
|
|
5
|
+
static matches(type, widget) {
|
|
6
|
+
if (type !== "Notebook" && type !== "Notebook.Root")
|
|
7
|
+
return false;
|
|
8
|
+
return widget !== null && isNotebookWidget(widget);
|
|
9
|
+
}
|
|
10
|
+
widget;
|
|
11
|
+
signalHandlers = new Map();
|
|
12
|
+
constructor(_type, widget, _props) {
|
|
13
|
+
if (!isNotebookWidget(widget)) {
|
|
14
|
+
throw new Error("NotebookNode requires a Notebook widget");
|
|
15
|
+
}
|
|
16
|
+
this.widget = widget;
|
|
17
|
+
}
|
|
18
|
+
getWidget() {
|
|
19
|
+
return this.widget;
|
|
20
|
+
}
|
|
21
|
+
appendChild(child) {
|
|
22
|
+
child.attachToParent(this);
|
|
23
|
+
}
|
|
24
|
+
removeChild(child) {
|
|
25
|
+
child.detachFromParent(this);
|
|
26
|
+
}
|
|
27
|
+
insertBefore(child, _before) {
|
|
28
|
+
this.appendChild(child);
|
|
29
|
+
}
|
|
30
|
+
attachToParent(parent) {
|
|
31
|
+
const parentWidget = parent.getWidget?.();
|
|
32
|
+
if (parentWidget) {
|
|
33
|
+
appendChild(parentWidget, this.widget);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
detachFromParent(parent) {
|
|
37
|
+
const parentWidget = parent.getWidget?.();
|
|
38
|
+
if (parentWidget) {
|
|
39
|
+
removeChild(parentWidget, this.widget);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
attachChild(childWidget) {
|
|
43
|
+
this.widget.appendPage(childWidget.ptr, undefined);
|
|
44
|
+
}
|
|
45
|
+
detachChild(childWidget) {
|
|
46
|
+
const pageNum = this.widget.pageNum(childWidget.ptr);
|
|
47
|
+
if (pageNum >= 0) {
|
|
48
|
+
this.widget.removePage(pageNum);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
updateProps(oldProps, newProps) {
|
|
52
|
+
const consumedProps = new Set(["children"]);
|
|
53
|
+
const allKeys = new Set([...Object.keys(oldProps), ...Object.keys(newProps)]);
|
|
54
|
+
for (const key of allKeys) {
|
|
55
|
+
if (consumedProps.has(key))
|
|
56
|
+
continue;
|
|
57
|
+
const oldValue = oldProps[key];
|
|
58
|
+
const newValue = newProps[key];
|
|
59
|
+
if (oldValue === newValue)
|
|
60
|
+
continue;
|
|
61
|
+
if (key.startsWith("on")) {
|
|
62
|
+
const eventName = key
|
|
63
|
+
.slice(2)
|
|
64
|
+
.replace(/([A-Z])/g, "-$1")
|
|
65
|
+
.toLowerCase()
|
|
66
|
+
.replace(/^-/, "");
|
|
67
|
+
const oldHandlerId = this.signalHandlers.get(eventName);
|
|
68
|
+
if (oldHandlerId !== undefined && isConnectable(this.widget)) {
|
|
69
|
+
this.signalHandlers.delete(eventName);
|
|
70
|
+
}
|
|
71
|
+
if (typeof newValue === "function" && isConnectable(this.widget)) {
|
|
72
|
+
const handlerId = this.widget.connect(eventName, newValue);
|
|
73
|
+
this.signalHandlers.set(eventName, handlerId);
|
|
74
|
+
}
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const setterName = `set${key.charAt(0).toUpperCase()}${key.slice(1)}`;
|
|
78
|
+
const setter = this.widget[setterName];
|
|
79
|
+
if (typeof setter === "function") {
|
|
80
|
+
setter.call(this.widget, newValue);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
mount() { }
|
|
85
|
+
dispose() {
|
|
86
|
+
disconnectSignalHandlers(this.widget, this.signalHandlers);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type * as Gtk from "@gtkx/ffi/gtk";
|
|
2
|
+
import type { Props } from "../factory.js";
|
|
3
|
+
import type { Node } from "../node.js";
|
|
4
|
+
interface OverlayWidget extends Gtk.Widget {
|
|
5
|
+
setChild(child: unknown): void;
|
|
6
|
+
addOverlay(widget: unknown): void;
|
|
7
|
+
removeOverlay(widget: unknown): void;
|
|
8
|
+
}
|
|
9
|
+
export declare class OverlayNode implements Node<OverlayWidget> {
|
|
10
|
+
static needsWidget: boolean;
|
|
11
|
+
static matches(type: string, widget: Gtk.Widget | null): widget is OverlayWidget;
|
|
12
|
+
private widget;
|
|
13
|
+
private mainChild;
|
|
14
|
+
private overlayChildren;
|
|
15
|
+
private signalHandlers;
|
|
16
|
+
constructor(_type: string, widget: Gtk.Widget, _props: Props);
|
|
17
|
+
getWidget(): OverlayWidget;
|
|
18
|
+
appendChild(child: Node): void;
|
|
19
|
+
removeChild(child: Node): void;
|
|
20
|
+
insertBefore(child: Node, _before: Node): void;
|
|
21
|
+
attachToParent(parent: Node): void;
|
|
22
|
+
detachFromParent(parent: Node): void;
|
|
23
|
+
attachChild(childWidget: Gtk.Widget): void;
|
|
24
|
+
detachChild(childWidget: Gtk.Widget): void;
|
|
25
|
+
updateProps(oldProps: Props, newProps: Props): void;
|
|
26
|
+
mount(): void;
|
|
27
|
+
dispose(): void;
|
|
28
|
+
}
|
|
29
|
+
export {};
|