@gtkx/react 0.1.47 → 0.1.49

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.
Files changed (43) hide show
  1. package/README.md +8 -0
  2. package/dist/codegen/jsx-generator.js +9 -19
  3. package/dist/container-interfaces.d.ts +51 -0
  4. package/dist/container-interfaces.js +5 -0
  5. package/dist/factory.d.ts +1 -1
  6. package/dist/factory.js +17 -3
  7. package/dist/generated/jsx.d.ts +9 -11
  8. package/dist/node.d.ts +4 -4
  9. package/dist/node.js +7 -6
  10. package/dist/nodes/about-dialog.d.ts +9 -0
  11. package/dist/nodes/about-dialog.js +14 -0
  12. package/dist/nodes/action-bar.d.ts +9 -0
  13. package/dist/nodes/action-bar.js +15 -0
  14. package/dist/nodes/column-view.d.ts +32 -7
  15. package/dist/nodes/column-view.js +217 -34
  16. package/dist/nodes/dropdown.d.ts +7 -17
  17. package/dist/nodes/dropdown.js +17 -10
  18. package/dist/nodes/flow-box.d.ts +9 -0
  19. package/dist/nodes/flow-box.js +25 -0
  20. package/dist/nodes/grid.d.ts +6 -3
  21. package/dist/nodes/grid.js +28 -26
  22. package/dist/nodes/list-box.d.ts +9 -0
  23. package/dist/nodes/list-box.js +21 -0
  24. package/dist/nodes/list.d.ts +4 -3
  25. package/dist/nodes/list.js +8 -7
  26. package/dist/nodes/notebook.d.ts +7 -3
  27. package/dist/nodes/notebook.js +31 -14
  28. package/dist/nodes/overlay.d.ts +2 -1
  29. package/dist/nodes/root.d.ts +2 -3
  30. package/dist/nodes/root.js +3 -3
  31. package/dist/nodes/slot.d.ts +1 -2
  32. package/dist/nodes/slot.js +2 -2
  33. package/dist/nodes/text-view.d.ts +2 -7
  34. package/dist/nodes/text-view.js +10 -49
  35. package/dist/nodes/widget.d.ts +6 -5
  36. package/dist/nodes/widget.js +9 -149
  37. package/dist/nodes/window.d.ts +11 -0
  38. package/dist/nodes/window.js +37 -0
  39. package/dist/props.d.ts +5 -0
  40. package/dist/props.js +10 -0
  41. package/dist/reconciler.js +4 -5
  42. package/dist/types.d.ts +22 -2
  43. package/package.json +3 -3
@@ -1,6 +1,8 @@
1
1
  import { getObject, getObjectId } from "@gtkx/ffi";
2
+ import * as GObject from "@gtkx/ffi/gobject";
2
3
  import * as Gtk from "@gtkx/ffi/gtk";
3
4
  import { scheduleFlush } from "../batch.js";
5
+ import { isColumnContainer, isItemContainer, } from "../container-interfaces.js";
4
6
  import { createFiberRoot } from "../fiber-root.js";
5
7
  import { Node } from "../node.js";
6
8
  import { reconciler } from "../reconciler.js";
@@ -10,29 +12,122 @@ export class ColumnViewNode extends Node {
10
12
  }
11
13
  stringList;
12
14
  selectionModel;
15
+ sortListModel;
13
16
  items = [];
14
17
  columns = [];
15
18
  committedLength = 0;
16
- constructor(type, props, app) {
17
- super(type, props, app);
19
+ sortColumn = null;
20
+ sortOrder = Gtk.SortType.ASCENDING;
21
+ sortFn = null;
22
+ isSorting = false;
23
+ onSortChange = null;
24
+ sorterChangedHandlerId = null;
25
+ lastNotifiedColumn = null;
26
+ lastNotifiedOrder = Gtk.SortType.ASCENDING;
27
+ constructor(type, props) {
28
+ super(type, props);
18
29
  this.stringList = new Gtk.StringList([]);
19
- this.selectionModel = new Gtk.SingleSelection(this.stringList);
30
+ this.sortListModel = new Gtk.SortListModel(this.stringList, this.widget.getSorter());
31
+ this.sortListModel.setIncremental(true);
32
+ this.selectionModel = new Gtk.SingleSelection(this.sortListModel);
20
33
  this.widget.setModel(this.selectionModel);
34
+ this.sortColumn = props.sortColumn ?? null;
35
+ this.sortOrder = props.sortOrder ?? Gtk.SortType.ASCENDING;
36
+ this.sortFn = props.sortFn ?? null;
37
+ this.onSortChange =
38
+ props.onSortChange ?? null;
39
+ this.connectSorterChangedSignal();
40
+ }
41
+ connectSorterChangedSignal() {
42
+ const sorter = this.widget.getSorter();
43
+ if (!sorter || !this.onSortChange)
44
+ return;
45
+ this.sorterChangedHandlerId = sorter.connect("changed", () => {
46
+ this.waitForSortComplete(() => this.notifySortChange());
47
+ });
48
+ }
49
+ waitForSortComplete(callback) {
50
+ const sortingInProgress = this.sortListModel.getPending() > 0;
51
+ if (sortingInProgress) {
52
+ setTimeout(() => this.waitForSortComplete(callback), 0);
53
+ }
54
+ else {
55
+ callback();
56
+ }
57
+ }
58
+ disconnectSorterChangedSignal() {
59
+ if (this.sorterChangedHandlerId === null)
60
+ return;
61
+ const sorter = this.widget.getSorter();
62
+ if (sorter) {
63
+ GObject.signalHandlerDisconnect(sorter, this.sorterChangedHandlerId);
64
+ }
65
+ this.sorterChangedHandlerId = null;
66
+ }
67
+ notifySortChange() {
68
+ if (!this.onSortChange)
69
+ return;
70
+ const baseSorter = this.widget.getSorter();
71
+ if (!baseSorter)
72
+ return;
73
+ const sorter = getObject(baseSorter.ptr, Gtk.ColumnViewSorter);
74
+ const column = sorter.getPrimarySortColumn();
75
+ const order = sorter.getPrimarySortOrder();
76
+ const columnId = column?.getId() ?? null;
77
+ const sortStateUnchanged = columnId === this.lastNotifiedColumn && order === this.lastNotifiedOrder;
78
+ if (sortStateUnchanged) {
79
+ return;
80
+ }
81
+ this.lastNotifiedColumn = columnId;
82
+ this.lastNotifiedOrder = order;
83
+ this.onSortChange(columnId, order);
21
84
  }
22
85
  getItems() {
23
86
  return this.items;
24
87
  }
25
- addColumn(column) {
26
- this.columns.push(column);
27
- const gtkColumn = column.getGtkColumn();
28
- this.widget.appendColumn(gtkColumn);
29
- column.setColumnView(this);
88
+ getSortFn() {
89
+ return this.sortFn;
90
+ }
91
+ compareItems(a, b, columnId) {
92
+ if (this.isSorting || !this.sortFn)
93
+ return 0;
94
+ this.isSorting = true;
95
+ try {
96
+ return this.sortFn(a, b, columnId);
97
+ }
98
+ finally {
99
+ this.isSorting = false;
100
+ }
101
+ }
102
+ addColumn(columnNode) {
103
+ this.columns.push(columnNode);
104
+ const column = columnNode.getColumn();
105
+ this.widget.appendColumn(column);
106
+ columnNode.setColumnView(this);
107
+ if (columnNode.getId() === this.sortColumn && this.sortColumn !== null) {
108
+ this.applySortByColumn();
109
+ }
110
+ }
111
+ applySortByColumn() {
112
+ if (this.sortColumn === null) {
113
+ this.widget.sortByColumn(this.sortOrder, null);
114
+ return;
115
+ }
116
+ if (!this.columns)
117
+ return;
118
+ const column = this.columns.find((c) => c.getId() === this.sortColumn);
119
+ if (column) {
120
+ this.widget.sortByColumn(this.sortOrder, column.getColumn());
121
+ }
122
+ }
123
+ findColumnById(id) {
124
+ return this.columns.find((c) => c.getId() === id);
30
125
  }
31
126
  removeColumn(column) {
32
127
  const index = this.columns.indexOf(column);
33
128
  if (index !== -1) {
34
129
  this.columns.splice(index, 1);
35
- this.widget.removeColumn(column.getGtkColumn());
130
+ this.widget.removeColumn(column.getColumn());
36
131
  column.setColumnView(null);
37
132
  }
38
133
  }
@@ -43,15 +138,15 @@ export class ColumnViewNode extends Node {
43
138
  return;
44
139
  }
45
140
  this.columns.splice(beforeIndex, 0, column);
46
- this.widget.insertColumn(beforeIndex, column.getGtkColumn());
141
+ this.widget.insertColumn(beforeIndex, column.getColumn());
47
142
  column.setColumnView(this);
48
143
  }
49
144
  syncStringList = () => {
50
145
  const newLength = this.items.length;
51
146
  if (newLength === this.committedLength)
52
147
  return;
53
- const placeholders = Array.from({ length: newLength }, () => "");
54
- this.stringList.splice(0, this.committedLength, placeholders);
148
+ const itemIndicesForSorter = Array.from({ length: newLength }, (_, i) => String(i));
149
+ this.stringList.splice(0, this.committedLength, itemIndicesForSorter);
55
150
  this.committedLength = newLength;
56
151
  };
57
152
  addItem(item) {
@@ -75,6 +170,47 @@ export class ColumnViewNode extends Node {
75
170
  scheduleFlush(this.syncStringList);
76
171
  }
77
172
  }
173
+ consumedProps() {
174
+ const consumed = super.consumedProps();
175
+ consumed.add("sortColumn");
176
+ consumed.add("sortOrder");
177
+ consumed.add("onSortChange");
178
+ consumed.add("sortFn");
179
+ return consumed;
180
+ }
181
+ updateProps(oldProps, newProps) {
182
+ super.updateProps(oldProps, newProps);
183
+ const newSortColumn = newProps.sortColumn ?? null;
184
+ const newSortOrder = newProps.sortOrder ?? Gtk.SortType.ASCENDING;
185
+ const newSortFn = newProps.sortFn ?? null;
186
+ const newOnSortChange = newProps.onSortChange ?? null;
187
+ if (oldProps.onSortChange !== newProps.onSortChange) {
188
+ const hadCallback = this.onSortChange !== null;
189
+ this.onSortChange = newOnSortChange;
190
+ const hasCallback = this.onSortChange !== null;
191
+ const callbackAdded = !hadCallback && hasCallback;
192
+ const callbackRemoved = hadCallback && !hasCallback;
193
+ if (callbackAdded) {
194
+ this.connectSorterChangedSignal();
195
+ }
196
+ else if (callbackRemoved) {
197
+ this.disconnectSorterChangedSignal();
198
+ }
199
+ }
200
+ if (oldProps.sortFn !== newProps.sortFn) {
201
+ this.sortFn = newSortFn;
202
+ if (this.columns) {
203
+ for (const column of this.columns) {
204
+ column.updateSorterFromRoot();
205
+ }
206
+ }
207
+ }
208
+ if (oldProps.sortColumn !== newProps.sortColumn || oldProps.sortOrder !== newProps.sortOrder) {
209
+ this.sortColumn = newSortColumn;
210
+ this.sortOrder = newSortOrder;
211
+ this.applySortByColumn();
212
+ }
213
+ }
78
214
  }
79
215
  export class ColumnViewColumnNode extends Node {
80
216
  static matches(type) {
@@ -83,24 +219,30 @@ export class ColumnViewColumnNode extends Node {
83
219
  isVirtual() {
84
220
  return true;
85
221
  }
86
- gtkColumn;
222
+ column;
87
223
  factory;
88
224
  renderCell;
89
225
  columnView = null;
90
226
  listItemCache = new Map();
91
- constructor(type, props, app) {
92
- super(type, props, app);
227
+ columnId = null;
228
+ sorter = null;
229
+ constructor(type, props) {
230
+ super(type, props);
93
231
  this.factory = new Gtk.SignalListItemFactory();
94
- this.gtkColumn = new Gtk.ColumnViewColumn(props.title, this.factory);
232
+ this.column = new Gtk.ColumnViewColumn(props.title, this.factory);
95
233
  this.renderCell = props.renderCell;
234
+ this.columnId = props.id ?? null;
235
+ if (this.columnId !== null) {
236
+ this.column.setId(this.columnId);
237
+ }
96
238
  if (props.expand !== undefined) {
97
- this.gtkColumn.setExpand(props.expand);
239
+ this.column.setExpand(props.expand);
98
240
  }
99
241
  if (props.resizable !== undefined) {
100
- this.gtkColumn.setResizable(props.resizable);
242
+ this.column.setResizable(props.resizable);
101
243
  }
102
244
  if (props.fixedWidth !== undefined) {
103
- this.gtkColumn.setFixedWidth(props.fixedWidth);
245
+ this.column.setFixedWidth(props.fixedWidth);
104
246
  }
105
247
  this.factory.connect("setup", (_self, listItemObj) => {
106
248
  const listItem = getObject(listItemObj.ptr, Gtk.ListItem);
@@ -142,19 +284,55 @@ export class ColumnViewColumnNode extends Node {
142
284
  }
143
285
  });
144
286
  }
145
- getGtkColumn() {
146
- return this.gtkColumn;
287
+ getColumn() {
288
+ return this.column;
289
+ }
290
+ getId() {
291
+ return this.columnId;
147
292
  }
148
293
  setColumnView(columnView) {
149
294
  this.columnView = columnView;
295
+ this.updateSorterFromRoot();
296
+ }
297
+ updateSorterFromRoot() {
298
+ if (!this.columnView || this.columnId === null) {
299
+ this.column.setSorter(null);
300
+ this.sorter = null;
301
+ return;
302
+ }
303
+ const rootSortFn = this.columnView.getSortFn();
304
+ if (rootSortFn === null) {
305
+ this.column.setSorter(null);
306
+ this.sorter = null;
307
+ return;
308
+ }
309
+ const columnId = this.columnId;
310
+ const columnView = this.columnView;
311
+ const wrappedSortFn = (stringObjPtrA, stringObjPtrB) => {
312
+ const items = columnView.getItems();
313
+ const stringObjA = getObject(stringObjPtrA, Gtk.StringObject);
314
+ const stringObjB = getObject(stringObjPtrB, Gtk.StringObject);
315
+ const indexA = Number.parseInt(stringObjA.getString(), 10);
316
+ const indexB = Number.parseInt(stringObjB.getString(), 10);
317
+ if (Number.isNaN(indexA) || Number.isNaN(indexB))
318
+ return 0;
319
+ const itemA = items[indexA] ?? null;
320
+ const itemB = items[indexB] ?? null;
321
+ if (itemA === null || itemB === null)
322
+ return 0;
323
+ const result = columnView.compareItems(itemA, itemB, columnId);
324
+ return typeof result === "number" ? result : 0;
325
+ };
326
+ this.sorter = new Gtk.CustomSorter(wrappedSortFn);
327
+ this.column.setSorter(this.sorter);
150
328
  }
151
329
  attachToParent(parent) {
152
- if (parent instanceof ColumnViewNode) {
330
+ if (isColumnContainer(parent)) {
153
331
  parent.addColumn(this);
154
332
  }
155
333
  }
156
334
  attachToParentBefore(parent, before) {
157
- if (parent instanceof ColumnViewNode && before instanceof ColumnViewColumnNode) {
335
+ if (isColumnContainer(parent) && before instanceof ColumnViewColumnNode) {
158
336
  parent.insertColumnBefore(this, before);
159
337
  }
160
338
  else {
@@ -162,7 +340,7 @@ export class ColumnViewColumnNode extends Node {
162
340
  }
163
341
  }
164
342
  detachFromParent(parent) {
165
- if (parent instanceof ColumnViewNode) {
343
+ if (isColumnContainer(parent)) {
166
344
  parent.removeColumn(this);
167
345
  }
168
346
  }
@@ -173,25 +351,30 @@ export class ColumnViewColumnNode extends Node {
173
351
  consumed.add("expand");
174
352
  consumed.add("resizable");
175
353
  consumed.add("fixedWidth");
354
+ consumed.add("id");
176
355
  return consumed;
177
356
  }
178
357
  updateProps(oldProps, newProps) {
179
358
  if (oldProps.renderCell !== newProps.renderCell) {
180
359
  this.renderCell = newProps.renderCell;
181
360
  }
182
- if (!this.gtkColumn)
361
+ if (!this.column)
183
362
  return;
184
363
  if (oldProps.title !== newProps.title) {
185
- this.gtkColumn.setTitle(newProps.title);
364
+ this.column.setTitle(newProps.title);
186
365
  }
187
366
  if (oldProps.expand !== newProps.expand) {
188
- this.gtkColumn.setExpand(newProps.expand);
367
+ this.column.setExpand(newProps.expand);
189
368
  }
190
369
  if (oldProps.resizable !== newProps.resizable) {
191
- this.gtkColumn.setResizable(newProps.resizable);
370
+ this.column.setResizable(newProps.resizable);
192
371
  }
193
372
  if (oldProps.fixedWidth !== newProps.fixedWidth) {
194
- this.gtkColumn.setFixedWidth(newProps.fixedWidth);
373
+ this.column.setFixedWidth(newProps.fixedWidth);
374
+ }
375
+ if (oldProps.id !== newProps.id) {
376
+ this.columnId = newProps.id ?? null;
377
+ this.column.setId(this.columnId);
195
378
  }
196
379
  }
197
380
  }
@@ -203,20 +386,20 @@ export class ColumnViewItemNode extends Node {
203
386
  return true;
204
387
  }
205
388
  item;
206
- constructor(type, props, app) {
207
- super(type, props, app);
389
+ constructor(type, props) {
390
+ super(type, props);
208
391
  this.item = props.item;
209
392
  }
210
393
  getItem() {
211
394
  return this.item;
212
395
  }
213
396
  attachToParent(parent) {
214
- if (parent instanceof ColumnViewNode) {
397
+ if (isItemContainer(parent)) {
215
398
  parent.addItem(this.item);
216
399
  }
217
400
  }
218
401
  attachToParentBefore(parent, before) {
219
- if (parent instanceof ColumnViewNode && before instanceof ColumnViewItemNode) {
402
+ if (isItemContainer(parent) && before instanceof ColumnViewItemNode) {
220
403
  parent.insertItemBefore(this.item, before.getItem());
221
404
  }
222
405
  else {
@@ -224,7 +407,7 @@ export class ColumnViewItemNode extends Node {
224
407
  }
225
408
  }
226
409
  detachFromParent(parent) {
227
- if (parent instanceof ColumnViewNode) {
410
+ if (isItemContainer(parent)) {
228
411
  parent.removeItem(this.item);
229
412
  }
230
413
  }
@@ -1,24 +1,15 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
+ import { type ItemContainer } from "../container-interfaces.js";
2
3
  import type { Props } from "../factory.js";
3
4
  import { Node } from "../node.js";
4
- type ItemLabelFn = (item: unknown) => string;
5
- declare class DropDownStore {
6
- private stringList;
7
- private items;
8
- private labelFn;
9
- constructor(labelFn: ItemLabelFn);
10
- getModel(): Gtk.StringList;
11
- append(item: unknown): void;
12
- remove(item: unknown): void;
13
- getItem(index: number): unknown;
14
- get length(): number;
15
- }
16
- export declare class DropDownNode extends Node<Gtk.DropDown> {
5
+ export declare class DropDownNode extends Node<Gtk.DropDown> implements ItemContainer<unknown> {
17
6
  static matches(type: string): boolean;
18
7
  private store;
19
8
  private onSelectionChanged?;
20
- constructor(type: string, props: Props, app: Gtk.Application);
21
- getStore(): DropDownStore;
9
+ constructor(type: string, props: Props);
10
+ addItem(item: unknown): void;
11
+ insertItemBefore(item: unknown, _beforeItem: unknown): void;
12
+ removeItem(item: unknown): void;
22
13
  protected consumedProps(): Set<string>;
23
14
  updateProps(oldProps: Props, newProps: Props): void;
24
15
  }
@@ -26,9 +17,8 @@ export declare class DropDownItemNode extends Node<never> {
26
17
  static matches(type: string): boolean;
27
18
  protected isVirtual(): boolean;
28
19
  private item;
29
- constructor(type: string, props: Props, app: Gtk.Application);
20
+ constructor(type: string, props: Props);
30
21
  getItem(): unknown;
31
22
  attachToParent(parent: Node): void;
32
23
  detachFromParent(parent: Node): void;
33
24
  }
34
- export {};
@@ -1,4 +1,5 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
+ import { isItemContainer } from "../container-interfaces.js";
2
3
  import { Node } from "../node.js";
3
4
  class DropDownStore {
4
5
  stringList;
@@ -36,8 +37,8 @@ export class DropDownNode extends Node {
36
37
  }
37
38
  store;
38
39
  onSelectionChanged;
39
- constructor(type, props, app) {
40
- super(type, props, app);
40
+ constructor(type, props) {
41
+ super(type, props);
41
42
  const labelFn = props.itemLabel ?? ((item) => String(item));
42
43
  this.onSelectionChanged = props.onSelectionChanged;
43
44
  this.store = new DropDownStore(labelFn);
@@ -51,8 +52,14 @@ export class DropDownNode extends Node {
51
52
  this.connectSignal(this.widget, "notify::selected", handler);
52
53
  }
53
54
  }
54
- getStore() {
55
- return this.store;
55
+ addItem(item) {
56
+ this.store.append(item);
57
+ }
58
+ insertItemBefore(item, _beforeItem) {
59
+ this.addItem(item);
60
+ }
61
+ removeItem(item) {
62
+ this.store.remove(item);
56
63
  }
57
64
  consumedProps() {
58
65
  const consumed = super.consumedProps();
@@ -75,21 +82,21 @@ export class DropDownItemNode extends Node {
75
82
  return true;
76
83
  }
77
84
  item;
78
- constructor(type, props, app) {
79
- super(type, props, app);
85
+ constructor(type, props) {
86
+ super(type, props);
80
87
  this.item = props.item;
81
88
  }
82
89
  getItem() {
83
90
  return this.item;
84
91
  }
85
92
  attachToParent(parent) {
86
- if (!(parent instanceof DropDownNode))
93
+ if (!isItemContainer(parent))
87
94
  return;
88
- parent.getStore().append(this.item);
95
+ parent.addItem(this.item);
89
96
  }
90
97
  detachFromParent(parent) {
91
- if (!(parent instanceof DropDownNode))
98
+ if (!isItemContainer(parent))
92
99
  return;
93
- parent.getStore().remove(this.item);
100
+ parent.removeItem(this.item);
94
101
  }
95
102
  }
@@ -0,0 +1,9 @@
1
+ import type * as Gtk from "@gtkx/ffi/gtk";
2
+ import type { ChildContainer } from "../container-interfaces.js";
3
+ import { Node } from "../node.js";
4
+ export declare class FlowBoxNode extends Node<Gtk.FlowBox> implements ChildContainer {
5
+ static matches(type: string): boolean;
6
+ attachChild(child: Gtk.Widget): void;
7
+ insertChildBefore(child: Gtk.Widget, before: Gtk.Widget): void;
8
+ detachChild(child: Gtk.Widget): void;
9
+ }
@@ -0,0 +1,25 @@
1
+ import { Node } from "../node.js";
2
+ const isFlowBoxChild = (widget) => "getIndex" in widget && "getChild" in widget && typeof widget.getIndex === "function";
3
+ export class FlowBoxNode extends Node {
4
+ static matches(type) {
5
+ return type === "FlowBox";
6
+ }
7
+ attachChild(child) {
8
+ this.widget.append(child);
9
+ }
10
+ insertChildBefore(child, before) {
11
+ const beforeParent = before.getParent();
12
+ if (beforeParent && isFlowBoxChild(beforeParent)) {
13
+ this.widget.insert(child, beforeParent.getIndex());
14
+ }
15
+ else {
16
+ this.widget.append(child);
17
+ }
18
+ }
19
+ detachChild(child) {
20
+ const flowBoxChild = child.getParent();
21
+ if (flowBoxChild) {
22
+ this.widget.remove(flowBoxChild);
23
+ }
24
+ }
25
+ }
@@ -1,8 +1,11 @@
1
1
  import type * as Gtk from "@gtkx/ffi/gtk";
2
+ import { type GridContainer } from "../container-interfaces.js";
2
3
  import type { Props } from "../factory.js";
3
4
  import { Node } from "../node.js";
4
- export declare class GridNode extends Node<Gtk.Grid> {
5
+ export declare class GridNode extends Node<Gtk.Grid> implements GridContainer {
5
6
  static matches(type: string): boolean;
7
+ attachToGrid(child: Gtk.Widget, column: number, row: number, colSpan: number, rowSpan: number): void;
8
+ removeFromGrid(child: Gtk.Widget): void;
6
9
  }
7
10
  export declare class GridChildNode extends Node<never> {
8
11
  static matches(type: string): boolean;
@@ -12,8 +15,8 @@ export declare class GridChildNode extends Node<never> {
12
15
  private columnSpan;
13
16
  private rowSpan;
14
17
  private childWidget;
15
- private parentGrid;
16
- constructor(type: string, props: Props, app: Gtk.Application);
18
+ private parentContainer;
19
+ constructor(type: string, props: Props);
17
20
  appendChild(child: Node): void;
18
21
  removeChild(child: Node): void;
19
22
  private attachChildToGrid;
@@ -1,8 +1,16 @@
1
+ import { isGridContainer } from "../container-interfaces.js";
1
2
  import { Node } from "../node.js";
3
+ import { getNumberProp } from "../props.js";
2
4
  export class GridNode extends Node {
3
5
  static matches(type) {
4
6
  return type === "Grid.Root";
5
7
  }
8
+ attachToGrid(child, column, row, colSpan, rowSpan) {
9
+ this.widget.attach(child, column, row, colSpan, rowSpan);
10
+ }
11
+ removeFromGrid(child) {
12
+ this.widget.remove(child);
13
+ }
6
14
  }
7
15
  export class GridChildNode extends Node {
8
16
  static matches(type) {
@@ -16,19 +24,19 @@ export class GridChildNode extends Node {
16
24
  columnSpan;
17
25
  rowSpan;
18
26
  childWidget = null;
19
- parentGrid = null;
20
- constructor(type, props, app) {
21
- super(type, props, app);
22
- this.column = props.column ?? 0;
23
- this.row = props.row ?? 0;
24
- this.columnSpan = props.columnSpan ?? 1;
25
- this.rowSpan = props.rowSpan ?? 1;
27
+ parentContainer = null;
28
+ constructor(type, props) {
29
+ super(type, props);
30
+ this.column = getNumberProp(props, "column", 0);
31
+ this.row = getNumberProp(props, "row", 0);
32
+ this.columnSpan = getNumberProp(props, "columnSpan", 1);
33
+ this.rowSpan = getNumberProp(props, "rowSpan", 1);
26
34
  }
27
35
  appendChild(child) {
28
36
  const widget = child.getWidget();
29
37
  if (widget) {
30
38
  this.childWidget = widget;
31
- if (this.parentGrid) {
39
+ if (this.parentContainer) {
32
40
  this.attachChildToGrid();
33
41
  }
34
42
  }
@@ -41,33 +49,27 @@ export class GridChildNode extends Node {
41
49
  }
42
50
  }
43
51
  attachChildToGrid() {
44
- if (!this.parentGrid || !this.childWidget)
52
+ if (!this.parentContainer || !this.childWidget)
45
53
  return;
46
- const grid = this.parentGrid.getWidget();
47
- if (!grid)
48
- return;
49
- grid.attach(this.childWidget, this.column, this.row, this.columnSpan, this.rowSpan);
54
+ this.parentContainer.attachToGrid(this.childWidget, this.column, this.row, this.columnSpan, this.rowSpan);
50
55
  }
51
56
  detachChildFromGrid() {
52
- if (!this.parentGrid || !this.childWidget)
53
- return;
54
- const grid = this.parentGrid.getWidget();
55
- if (!grid)
57
+ if (!this.parentContainer || !this.childWidget)
56
58
  return;
57
- grid.remove(this.childWidget);
59
+ this.parentContainer.removeFromGrid(this.childWidget);
58
60
  }
59
61
  attachToParent(parent) {
60
- if (parent instanceof GridNode) {
61
- this.parentGrid = parent;
62
+ if (isGridContainer(parent)) {
63
+ this.parentContainer = parent;
62
64
  if (this.childWidget) {
63
65
  this.attachChildToGrid();
64
66
  }
65
67
  }
66
68
  }
67
69
  detachFromParent(parent) {
68
- if (parent instanceof GridNode) {
70
+ if (isGridContainer(parent)) {
69
71
  this.detachChildFromGrid();
70
- this.parentGrid = null;
72
+ this.parentContainer = null;
71
73
  }
72
74
  }
73
75
  updateProps(oldProps, newProps) {
@@ -77,10 +79,10 @@ export class GridChildNode extends Node {
77
79
  oldProps.rowSpan !== newProps.rowSpan;
78
80
  if (positionChanged) {
79
81
  this.detachChildFromGrid();
80
- this.column = newProps.column ?? 0;
81
- this.row = newProps.row ?? 0;
82
- this.columnSpan = newProps.columnSpan ?? 1;
83
- this.rowSpan = newProps.rowSpan ?? 1;
82
+ this.column = getNumberProp(newProps, "column", 0);
83
+ this.row = getNumberProp(newProps, "row", 0);
84
+ this.columnSpan = getNumberProp(newProps, "columnSpan", 1);
85
+ this.rowSpan = getNumberProp(newProps, "rowSpan", 1);
84
86
  this.attachChildToGrid();
85
87
  }
86
88
  }
@@ -0,0 +1,9 @@
1
+ import type * as Gtk from "@gtkx/ffi/gtk";
2
+ import type { ChildContainer } from "../container-interfaces.js";
3
+ import { Node } from "../node.js";
4
+ export declare class ListBoxNode extends Node<Gtk.ListBox> implements ChildContainer {
5
+ static matches(type: string): boolean;
6
+ attachChild(child: Gtk.Widget): void;
7
+ insertChildBefore(child: Gtk.Widget, before: Gtk.Widget): void;
8
+ detachChild(child: Gtk.Widget): void;
9
+ }
@@ -0,0 +1,21 @@
1
+ import { Node } from "../node.js";
2
+ const isListBoxRow = (widget) => "getIndex" in widget && "isSelected" in widget && typeof widget.getIndex === "function";
3
+ export class ListBoxNode extends Node {
4
+ static matches(type) {
5
+ return type === "ListBox";
6
+ }
7
+ attachChild(child) {
8
+ this.widget.append(child);
9
+ }
10
+ insertChildBefore(child, before) {
11
+ if (isListBoxRow(before)) {
12
+ this.widget.insert(child, before.getIndex());
13
+ }
14
+ else {
15
+ this.widget.append(child);
16
+ }
17
+ }
18
+ detachChild(child) {
19
+ this.widget.remove(child);
20
+ }
21
+ }