@gtkx/react 0.15.0 → 0.16.0
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/README.md +1 -0
- package/dist/errors.js +3 -0
- package/dist/factory.d.ts +3 -2
- package/dist/factory.js +1 -1
- package/dist/generated/internal.d.ts +28 -1
- package/dist/generated/internal.js +93 -18
- package/dist/generated/jsx.d.ts +1489 -1300
- package/dist/generated/jsx.js +475 -0
- package/dist/host-config.d.ts +3 -1
- package/dist/host-config.js +31 -11
- package/dist/jsx.d.ts +107 -166
- package/dist/jsx.js +58 -69
- package/dist/node.d.ts +3 -1
- package/dist/node.js +5 -3
- package/dist/nodes/abstract/positional-child.d.ts +9 -0
- package/dist/nodes/abstract/positional-child.js +29 -0
- package/dist/nodes/abstract/positional-parent.d.ts +18 -0
- package/dist/nodes/abstract/positional-parent.js +48 -0
- package/dist/nodes/abstract/virtual-container.d.ts +17 -0
- package/dist/nodes/abstract/virtual-container.js +59 -0
- package/dist/nodes/abstract/virtual-single-child.d.ts +18 -0
- package/dist/nodes/abstract/virtual-single-child.js +54 -0
- package/dist/nodes/action-row-child.d.ts +0 -13
- package/dist/nodes/action-row-child.js +14 -12
- package/dist/nodes/action-row.d.ts +6 -1
- package/dist/nodes/action-row.js +4 -37
- package/dist/nodes/adjustable.d.ts +23 -0
- package/dist/nodes/adjustable.js +62 -0
- package/dist/nodes/alert-dialog-response.d.ts +1 -0
- package/dist/nodes/alert-dialog-response.js +86 -0
- package/dist/nodes/animation/animation-controller.d.ts +17 -0
- package/dist/nodes/animation/animation-controller.js +107 -0
- package/dist/nodes/animation/animation-factory.d.ts +15 -0
- package/dist/nodes/animation/animation-factory.js +25 -0
- package/dist/nodes/animation/animation-node.d.ts +9 -0
- package/dist/nodes/animation/animation-node.js +126 -0
- package/dist/nodes/animation/animation-style-sheet.d.ts +16 -0
- package/dist/nodes/animation/animation-style-sheet.js +74 -0
- package/dist/nodes/animation/index.d.ts +4 -0
- package/dist/nodes/animation/index.js +1 -0
- package/dist/nodes/animation/property-mapper.d.ts +11 -0
- package/dist/nodes/animation/property-mapper.js +36 -0
- package/dist/nodes/animation/transform-state.d.ts +11 -0
- package/dist/nodes/animation/transform-state.js +57 -0
- package/dist/nodes/animation/widget-registry.d.ts +5 -0
- package/dist/nodes/animation/widget-registry.js +42 -0
- package/dist/nodes/application.js +17 -7
- package/dist/nodes/autowrapped.js +37 -43
- package/dist/nodes/calendar.js +17 -43
- package/dist/nodes/color-dialog-button.d.ts +1 -0
- package/dist/nodes/color-dialog-button.js +70 -0
- package/dist/nodes/column-view-column.d.ts +3 -3
- package/dist/nodes/column-view-column.js +1 -1
- package/dist/nodes/column-view.js +36 -39
- package/dist/nodes/dialog.d.ts +11 -0
- package/dist/nodes/dialog.js +20 -0
- package/dist/nodes/drawing-area.js +24 -7
- package/dist/nodes/event-controller.d.ts +1 -0
- package/dist/nodes/event-controller.js +96 -0
- package/dist/nodes/expander-row-child.d.ts +0 -14
- package/dist/nodes/expander-row-child.js +14 -12
- package/dist/nodes/expander-row.d.ts +6 -1
- package/dist/nodes/expander-row.js +11 -48
- package/dist/nodes/fixed-child.js +48 -36
- package/dist/nodes/font-dialog-button.d.ts +1 -0
- package/dist/nodes/font-dialog-button.js +90 -0
- package/dist/nodes/grid-child.js +39 -45
- package/dist/nodes/grid.d.ts +1 -0
- package/dist/nodes/grid.js +41 -0
- package/dist/nodes/index.d.ts +17 -9
- package/dist/nodes/index.js +17 -9
- package/dist/nodes/internal/base-item-renderer.d.ts +29 -0
- package/dist/nodes/internal/base-item-renderer.js +88 -0
- package/dist/nodes/internal/base-store.d.ts +9 -0
- package/dist/nodes/internal/base-store.js +20 -0
- package/dist/nodes/internal/child-attachment.d.ts +26 -0
- package/dist/nodes/internal/child-attachment.js +48 -0
- package/dist/nodes/internal/deferred-action.d.ts +8 -0
- package/dist/nodes/internal/deferred-action.js +19 -0
- package/dist/nodes/internal/list-item-renderer.d.ts +14 -15
- package/dist/nodes/internal/list-item-renderer.js +51 -77
- package/dist/nodes/internal/list-store.d.ts +7 -6
- package/dist/nodes/internal/list-store.js +20 -24
- package/dist/nodes/internal/predicates.d.ts +25 -2
- package/dist/nodes/internal/predicates.js +53 -41
- package/dist/nodes/internal/selection-model.d.ts +30 -0
- package/dist/nodes/internal/selection-model.js +91 -0
- package/dist/nodes/internal/signal-store.d.ts +5 -4
- package/dist/nodes/internal/signal-store.js +30 -28
- package/dist/nodes/internal/simple-list-store.js +6 -9
- package/dist/nodes/internal/text-buffer-controller.d.ts +43 -0
- package/dist/nodes/internal/text-buffer-controller.js +287 -0
- package/dist/nodes/internal/text-tag-styles.d.ts +43 -0
- package/dist/nodes/internal/text-tag-styles.js +52 -0
- package/dist/nodes/internal/tree-list-item-renderer.d.ts +15 -14
- package/dist/nodes/internal/tree-list-item-renderer.js +85 -96
- package/dist/nodes/internal/tree-store.d.ts +10 -9
- package/dist/nodes/internal/tree-store.js +31 -35
- package/dist/nodes/internal/utils.d.ts +7 -4
- package/dist/nodes/internal/utils.js +50 -5
- package/dist/nodes/level-bar.js +19 -54
- package/dist/nodes/list-item.d.ts +6 -3
- package/dist/nodes/list-item.js +7 -4
- package/dist/nodes/list-view.js +15 -11
- package/dist/nodes/menu.d.ts +3 -3
- package/dist/nodes/menu.js +3 -3
- package/dist/nodes/models/list.d.ts +11 -13
- package/dist/nodes/models/list.js +16 -73
- package/dist/nodes/models/menu.d.ts +8 -7
- package/dist/nodes/models/menu.js +43 -50
- package/dist/nodes/models/tree-list.d.ts +6 -12
- package/dist/nodes/models/tree-list.js +30 -93
- package/dist/nodes/navigation-page.d.ts +1 -0
- package/dist/nodes/navigation-page.js +27 -32
- package/dist/nodes/navigation-view.js +17 -28
- package/dist/nodes/notebook-page-tab.d.ts +3 -3
- package/dist/nodes/notebook-page-tab.js +11 -14
- package/dist/nodes/notebook-page.d.ts +7 -5
- package/dist/nodes/notebook-page.js +45 -25
- package/dist/nodes/notebook.js +2 -2
- package/dist/nodes/overlay-child.js +90 -30
- package/dist/nodes/pack-child.d.ts +0 -13
- package/dist/nodes/pack-child.js +14 -12
- package/dist/nodes/pack.d.ts +6 -1
- package/dist/nodes/pack.js +4 -37
- package/dist/nodes/popover-menu.js +2 -2
- package/dist/nodes/scale.js +15 -45
- package/dist/nodes/scrolled-window.js +7 -6
- package/dist/nodes/search-bar.d.ts +1 -0
- package/dist/nodes/search-bar.js +40 -0
- package/dist/nodes/shortcut-controller.d.ts +1 -37
- package/dist/nodes/shortcut-controller.js +24 -8
- package/dist/nodes/shortcut.d.ts +5 -4
- package/dist/nodes/shortcut.js +11 -5
- package/dist/nodes/simple-list-view.js +2 -3
- package/dist/nodes/slot.d.ts +6 -9
- package/dist/nodes/slot.js +27 -42
- package/dist/nodes/source-view.js +80 -29
- package/dist/nodes/stack-page.js +20 -22
- package/dist/nodes/stack.js +19 -5
- package/dist/nodes/text-anchor.d.ts +41 -0
- package/dist/nodes/text-anchor.js +59 -0
- package/dist/nodes/text-content.d.ts +10 -0
- package/dist/nodes/text-content.js +1 -0
- package/dist/nodes/text-paintable.d.ts +17 -0
- package/dist/nodes/text-paintable.js +34 -0
- package/dist/nodes/text-segment.d.ts +15 -0
- package/dist/nodes/text-segment.js +29 -0
- package/dist/nodes/text-tag.d.ts +136 -0
- package/dist/nodes/text-tag.js +202 -0
- package/dist/nodes/text-view.d.ts +30 -0
- package/dist/nodes/text-view.js +49 -21
- package/dist/nodes/toggle-group.js +24 -32
- package/dist/nodes/toggle.d.ts +1 -15
- package/dist/nodes/toggle.js +40 -32
- package/dist/nodes/toolbar-child.js +14 -16
- package/dist/nodes/tree-list-item.d.ts +7 -5
- package/dist/nodes/tree-list-item.js +24 -36
- package/dist/nodes/tree-list-view.js +7 -6
- package/dist/nodes/virtual.d.ts +1 -1
- package/dist/nodes/widget.d.ts +2 -16
- package/dist/nodes/widget.js +105 -294
- package/dist/nodes/window.d.ts +9 -3
- package/dist/nodes/window.js +29 -15
- package/dist/registry.d.ts +1 -1
- package/dist/render.js +8 -6
- package/dist/scheduler.d.ts +11 -1
- package/dist/scheduler.js +16 -4
- package/dist/types.d.ts +2 -136
- package/package.json +3 -3
- package/dist/nodes/adjustment.d.ts +0 -48
- package/dist/nodes/adjustment.js +0 -70
- package/dist/nodes/calendar-mark.d.ts +0 -15
- package/dist/nodes/calendar-mark.js +0 -29
- package/dist/nodes/internal/constants.d.ts +0 -1
- package/dist/nodes/internal/constants.js +0 -24
- package/dist/nodes/level-bar-offset.d.ts +0 -13
- package/dist/nodes/level-bar-offset.js +0 -35
- package/dist/nodes/scale-mark.d.ts +0 -17
- package/dist/nodes/scale-mark.js +0 -38
- package/dist/nodes/source-buffer.d.ts +0 -73
- package/dist/nodes/source-buffer.js +0 -149
- package/dist/nodes/text-buffer.d.ts +0 -43
- package/dist/nodes/text-buffer.js +0 -81
- package/dist/nodes/virtual-child.d.ts +0 -18
- package/dist/nodes/virtual-child.js +0 -62
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { isAddable, isAppendable, isContentWidget, isRemovable, isSingleChild } from "./predicates.js";
|
|
2
|
+
export const getAttachmentStrategy = (container) => {
|
|
3
|
+
if (isAppendable(container)) {
|
|
4
|
+
return { type: "appendable", container };
|
|
5
|
+
}
|
|
6
|
+
if (isAddable(container)) {
|
|
7
|
+
return { type: "addable", container };
|
|
8
|
+
}
|
|
9
|
+
if (isContentWidget(container)) {
|
|
10
|
+
return { type: "content", container };
|
|
11
|
+
}
|
|
12
|
+
if (isSingleChild(container)) {
|
|
13
|
+
return { type: "singleChild", container };
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
};
|
|
17
|
+
export const attachChild = (child, strategy) => {
|
|
18
|
+
switch (strategy.type) {
|
|
19
|
+
case "appendable":
|
|
20
|
+
strategy.container.append(child);
|
|
21
|
+
break;
|
|
22
|
+
case "addable":
|
|
23
|
+
strategy.container.add(child);
|
|
24
|
+
break;
|
|
25
|
+
case "content":
|
|
26
|
+
strategy.container.setContent(child);
|
|
27
|
+
break;
|
|
28
|
+
case "singleChild":
|
|
29
|
+
strategy.container.setChild(child);
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
export const detachChild = (child, strategy) => {
|
|
34
|
+
switch (strategy.type) {
|
|
35
|
+
case "appendable":
|
|
36
|
+
case "addable":
|
|
37
|
+
if (isRemovable(strategy.container)) {
|
|
38
|
+
strategy.container.remove(child);
|
|
39
|
+
}
|
|
40
|
+
break;
|
|
41
|
+
case "content":
|
|
42
|
+
strategy.container.setContent(null);
|
|
43
|
+
break;
|
|
44
|
+
case "singleChild":
|
|
45
|
+
strategy.container.setChild(null);
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { scheduleAfterCommit } from "../../scheduler.js";
|
|
2
|
+
export class DeferredAction {
|
|
3
|
+
action;
|
|
4
|
+
priority;
|
|
5
|
+
scheduled = false;
|
|
6
|
+
constructor(action, priority) {
|
|
7
|
+
this.action = action;
|
|
8
|
+
this.priority = priority;
|
|
9
|
+
}
|
|
10
|
+
schedule() {
|
|
11
|
+
if (this.scheduled)
|
|
12
|
+
return;
|
|
13
|
+
this.scheduled = true;
|
|
14
|
+
scheduleAfterCommit(() => {
|
|
15
|
+
this.scheduled = false;
|
|
16
|
+
this.action();
|
|
17
|
+
}, this.priority);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import * as Gtk from "@gtkx/ffi/gtk";
|
|
2
2
|
import type { ReactNode } from "react";
|
|
3
|
+
import type Reconciler from "react-reconciler";
|
|
4
|
+
import { BaseItemRenderer } from "./base-item-renderer.js";
|
|
3
5
|
import type { ListStore } from "./list-store.js";
|
|
4
6
|
export type RenderItemFn<T> = (item: T | null) => ReactNode;
|
|
5
|
-
export declare class ListItemRenderer {
|
|
6
|
-
private
|
|
7
|
-
private
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
private getStore;
|
|
18
|
-
dispose(): void;
|
|
19
|
-
private initialize;
|
|
7
|
+
export declare class ListItemRenderer extends BaseItemRenderer<ListStore> {
|
|
8
|
+
private renderFn;
|
|
9
|
+
private boundItems;
|
|
10
|
+
setRenderFn(renderFn: RenderItemFn<unknown> | null): void;
|
|
11
|
+
rebindItem(id: string): void;
|
|
12
|
+
protected getStoreTypeName(): string;
|
|
13
|
+
protected renderItem(_ptr: number): ReactNode;
|
|
14
|
+
protected getItemFromListItem(listItem: Gtk.ListItem): string | null;
|
|
15
|
+
protected onSetup(listItem: Gtk.ListItem, _ptr: number): Gtk.Widget;
|
|
16
|
+
protected onBind(listItem: Gtk.ListItem, ptr: number, fiberRoot: Reconciler.FiberRoot): void;
|
|
17
|
+
protected onUnbind(listItem: Gtk.ListItem): void;
|
|
18
|
+
protected onTeardown(_listItem: Gtk.ListItem, _ptr: number): void;
|
|
20
19
|
}
|
|
@@ -1,89 +1,63 @@
|
|
|
1
|
-
import { getNativeId } from "@gtkx/ffi";
|
|
2
1
|
import * as Gtk from "@gtkx/ffi/gtk";
|
|
3
|
-
import { createFiberRoot } from "../../fiber-root.js";
|
|
4
2
|
import { reconciler } from "../../reconciler.js";
|
|
5
|
-
import {
|
|
6
|
-
export class ListItemRenderer {
|
|
7
|
-
factory;
|
|
8
|
-
store;
|
|
9
|
-
fiberRoots = new Map();
|
|
10
|
-
tornDown = new Set();
|
|
3
|
+
import { BaseItemRenderer } from "./base-item-renderer.js";
|
|
4
|
+
export class ListItemRenderer extends BaseItemRenderer {
|
|
11
5
|
renderFn = () => null;
|
|
12
|
-
|
|
13
|
-
constructor() {
|
|
14
|
-
this.factory = new Gtk.SignalListItemFactory();
|
|
15
|
-
this.initialize();
|
|
16
|
-
}
|
|
17
|
-
getFactory() {
|
|
18
|
-
return this.factory;
|
|
19
|
-
}
|
|
6
|
+
boundItems = new Map();
|
|
20
7
|
setRenderFn(renderFn) {
|
|
21
8
|
this.renderFn = renderFn;
|
|
22
9
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
10
|
+
rebindItem(id) {
|
|
11
|
+
const ptr = this.boundItems.get(id);
|
|
12
|
+
if (ptr === undefined)
|
|
13
|
+
return;
|
|
14
|
+
const fiberRoot = this.fiberRoots.get(ptr);
|
|
15
|
+
if (!fiberRoot)
|
|
16
|
+
return;
|
|
17
|
+
const item = this.getStore().getItem(id);
|
|
18
|
+
const element = this.renderFn?.(item);
|
|
19
|
+
reconciler.getInstance().updateContainer(element, fiberRoot, null, () => { });
|
|
20
|
+
}
|
|
21
|
+
getStoreTypeName() {
|
|
22
|
+
return "list store";
|
|
23
|
+
}
|
|
24
|
+
renderItem(_ptr) {
|
|
25
|
+
return this.renderFn?.(null);
|
|
26
|
+
}
|
|
27
|
+
getItemFromListItem(listItem) {
|
|
28
|
+
const stringObject = listItem.getItem();
|
|
29
|
+
if (!(stringObject instanceof Gtk.StringObject))
|
|
30
|
+
return null;
|
|
31
|
+
return stringObject.getString();
|
|
32
|
+
}
|
|
33
|
+
onSetup(listItem, _ptr) {
|
|
34
|
+
const box = this.createBox();
|
|
35
|
+
listItem.setChild(box);
|
|
36
|
+
return box;
|
|
37
|
+
}
|
|
38
|
+
onBind(listItem, ptr, fiberRoot) {
|
|
39
|
+
const id = this.getItemFromListItem(listItem);
|
|
40
|
+
if (id !== null) {
|
|
41
|
+
this.boundItems.set(id, ptr);
|
|
32
42
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
this.fiberRoots.clear();
|
|
38
|
-
this.tornDown.clear();
|
|
39
|
-
}
|
|
40
|
-
initialize() {
|
|
41
|
-
signalStore.set(this, this.factory, "setup", (_self, listItem) => {
|
|
42
|
-
const ptr = getNativeId(listItem.handle);
|
|
43
|
-
const box = new Gtk.Box(Gtk.Orientation.VERTICAL);
|
|
44
|
-
if (this.estimatedItemHeight !== undefined) {
|
|
45
|
-
box.setSizeRequest(-1, this.estimatedItemHeight);
|
|
46
|
-
}
|
|
47
|
-
listItem.setChild(box);
|
|
48
|
-
const fiberRoot = createFiberRoot(box);
|
|
49
|
-
this.fiberRoots.set(ptr, fiberRoot);
|
|
50
|
-
const element = this.renderFn?.(null);
|
|
51
|
-
reconciler.getInstance().updateContainer(element, fiberRoot, null, () => { });
|
|
52
|
-
});
|
|
53
|
-
signalStore.set(this, this.factory, "bind", (_self, listItem) => {
|
|
54
|
-
const ptr = getNativeId(listItem.handle);
|
|
55
|
-
const fiberRoot = this.fiberRoots.get(ptr);
|
|
56
|
-
if (!fiberRoot)
|
|
43
|
+
const item = id !== null ? this.getStore().getItem(id) : null;
|
|
44
|
+
const element = this.renderFn?.(item);
|
|
45
|
+
reconciler.getInstance().updateContainer(element, fiberRoot, null, () => {
|
|
46
|
+
if (this.tornDown.has(ptr))
|
|
57
47
|
return;
|
|
58
|
-
|
|
59
|
-
if (!(stringObject instanceof Gtk.StringObject))
|
|
48
|
+
if (this.estimatedItemHeight !== null)
|
|
60
49
|
return;
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return;
|
|
66
|
-
const currentFiberRoot = this.fiberRoots.get(ptr);
|
|
67
|
-
if (!currentFiberRoot)
|
|
68
|
-
return;
|
|
69
|
-
const box = currentFiberRoot.containerInfo;
|
|
70
|
-
if (box instanceof Gtk.Box) {
|
|
71
|
-
box.setSizeRequest(-1, -1);
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
signalStore.set(this, this.factory, "unbind", () => { });
|
|
76
|
-
signalStore.set(this, this.factory, "teardown", (_self, listItem) => {
|
|
77
|
-
const ptr = getNativeId(listItem.handle);
|
|
78
|
-
const fiberRoot = this.fiberRoots.get(ptr);
|
|
79
|
-
if (fiberRoot) {
|
|
80
|
-
this.tornDown.add(ptr);
|
|
81
|
-
reconciler.getInstance().updateContainer(null, fiberRoot, null, () => { });
|
|
82
|
-
queueMicrotask(() => {
|
|
83
|
-
this.fiberRoots.delete(ptr);
|
|
84
|
-
this.tornDown.delete(ptr);
|
|
85
|
-
});
|
|
86
|
-
}
|
|
50
|
+
const currentFiberRoot = this.fiberRoots.get(ptr);
|
|
51
|
+
if (!currentFiberRoot)
|
|
52
|
+
return;
|
|
53
|
+
this.clearBoxSizeRequest(currentFiberRoot.containerInfo);
|
|
87
54
|
});
|
|
88
55
|
}
|
|
56
|
+
onUnbind(listItem) {
|
|
57
|
+
const id = this.getItemFromListItem(listItem);
|
|
58
|
+
if (id !== null) {
|
|
59
|
+
this.boundItems.delete(id);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
onTeardown(_listItem, _ptr) { }
|
|
89
63
|
}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import * as Gtk from "@gtkx/ffi/gtk";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import { BaseStore } from "./base-store.js";
|
|
3
|
+
export type ItemUpdatedCallback = (id: string) => void;
|
|
4
|
+
export declare class ListStore extends BaseStore<unknown> {
|
|
4
5
|
private model;
|
|
5
6
|
private newSortedIds;
|
|
7
|
+
private newIdSet;
|
|
6
8
|
private sortedIds;
|
|
7
|
-
private
|
|
9
|
+
private onItemUpdated;
|
|
10
|
+
setOnItemUpdated(callback: ItemUpdatedCallback | null): void;
|
|
8
11
|
addItem(id: string, item: unknown): void;
|
|
9
12
|
removeItem(id: string): void;
|
|
10
13
|
insertItemBefore(id: string, beforeId: string, item: unknown): void;
|
|
11
14
|
updateItem(id: string, item: unknown): void;
|
|
12
|
-
getItem(id: string): unknown;
|
|
13
15
|
getModel(): Gtk.StringList;
|
|
14
|
-
|
|
15
|
-
private sync;
|
|
16
|
+
protected sync(): void;
|
|
16
17
|
}
|
|
@@ -1,32 +1,37 @@
|
|
|
1
1
|
import * as Gtk from "@gtkx/ffi/gtk";
|
|
2
|
-
import {
|
|
3
|
-
export class ListStore {
|
|
4
|
-
items = new Map();
|
|
2
|
+
import { BaseStore } from "./base-store.js";
|
|
3
|
+
export class ListStore extends BaseStore {
|
|
5
4
|
model = new Gtk.StringList();
|
|
6
5
|
newSortedIds = [];
|
|
6
|
+
newIdSet = new Set();
|
|
7
7
|
sortedIds = [];
|
|
8
|
-
|
|
8
|
+
onItemUpdated = null;
|
|
9
|
+
setOnItemUpdated(callback) {
|
|
10
|
+
this.onItemUpdated = callback;
|
|
11
|
+
}
|
|
9
12
|
addItem(id, item) {
|
|
10
13
|
this.items.set(id, item);
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
if (this.newIdSet.has(id)) {
|
|
15
|
+
const existingIndex = this.newSortedIds.indexOf(id);
|
|
13
16
|
this.newSortedIds.splice(existingIndex, 1);
|
|
14
17
|
}
|
|
15
18
|
this.newSortedIds.push(id);
|
|
19
|
+
this.newIdSet.add(id);
|
|
16
20
|
this.scheduleSync();
|
|
17
21
|
}
|
|
18
22
|
removeItem(id) {
|
|
23
|
+
if (!this.newIdSet.has(id))
|
|
24
|
+
return;
|
|
19
25
|
const index = this.newSortedIds.indexOf(id);
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
26
|
+
this.newSortedIds.splice(index, 1);
|
|
27
|
+
this.newIdSet.delete(id);
|
|
28
|
+
this.items.delete(id);
|
|
29
|
+
this.scheduleSync();
|
|
25
30
|
}
|
|
26
31
|
insertItemBefore(id, beforeId, item) {
|
|
27
32
|
this.items.set(id, item);
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
if (this.newIdSet.has(id)) {
|
|
34
|
+
const existingIndex = this.newSortedIds.indexOf(id);
|
|
30
35
|
this.newSortedIds.splice(existingIndex, 1);
|
|
31
36
|
}
|
|
32
37
|
const beforeIndex = this.newSortedIds.indexOf(beforeId);
|
|
@@ -36,31 +41,22 @@ export class ListStore {
|
|
|
36
41
|
else {
|
|
37
42
|
this.newSortedIds.splice(beforeIndex, 0, id);
|
|
38
43
|
}
|
|
44
|
+
this.newIdSet.add(id);
|
|
39
45
|
this.scheduleSync();
|
|
40
46
|
}
|
|
41
47
|
updateItem(id, item) {
|
|
42
48
|
if (this.items.has(id)) {
|
|
43
49
|
this.items.set(id, item);
|
|
50
|
+
this.onItemUpdated?.(id);
|
|
44
51
|
}
|
|
45
52
|
else {
|
|
46
53
|
this.addItem(id, item);
|
|
47
54
|
}
|
|
48
55
|
}
|
|
49
|
-
getItem(id) {
|
|
50
|
-
return this.items.get(id);
|
|
51
|
-
}
|
|
52
56
|
getModel() {
|
|
53
57
|
return this.model;
|
|
54
58
|
}
|
|
55
|
-
scheduleSync() {
|
|
56
|
-
if (this.shouldSync) {
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
this.shouldSync = true;
|
|
60
|
-
scheduleAfterCommit(() => this.sync(), CommitPriority.LOW);
|
|
61
|
-
}
|
|
62
59
|
sync() {
|
|
63
|
-
this.shouldSync = false;
|
|
64
60
|
const newOrder = this.newSortedIds;
|
|
65
61
|
const oldLength = this.sortedIds.length;
|
|
66
62
|
this.model.splice(0, oldLength, newOrder.length > 0 ? newOrder : undefined);
|
|
@@ -1,4 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime type predicates for GTK widget capability detection.
|
|
3
|
+
*
|
|
4
|
+
* These predicates check for specific APIs that widgets may or may not expose.
|
|
5
|
+
* GTK widgets don't have a consistent interface - different widgets support
|
|
6
|
+
* different child management APIs - so runtime checking is necessary.
|
|
7
|
+
*
|
|
8
|
+
* Predicate evaluation order matters in WidgetNode.appendChild/removeChild:
|
|
9
|
+
* 1. isReorderable (Box, etc.) - reorderChildAfter/insertChildAfter
|
|
10
|
+
* 2. isInsertable (ListBox, etc.) - insert
|
|
11
|
+
* 3. isAppendable (most containers) - append
|
|
12
|
+
* 4. isAddable (some legacy widgets) - add
|
|
13
|
+
* 5. isContentWidget (ActionBar, etc.) - setContent
|
|
14
|
+
* 6. isSingleChild (Bin subclasses) - setChild
|
|
15
|
+
*/
|
|
1
16
|
import * as Gtk from "@gtkx/ffi/gtk";
|
|
17
|
+
import type { Node } from "../../node.js";
|
|
2
18
|
type AppendableWidget = Gtk.Widget & {
|
|
3
19
|
append: (child: Gtk.Widget) => void;
|
|
4
20
|
};
|
|
@@ -29,14 +45,21 @@ type EditableWidget = Gtk.Widget & {
|
|
|
29
45
|
};
|
|
30
46
|
export type AdjustableWidget = Gtk.Widget & {
|
|
31
47
|
setAdjustment: (adjustment: Gtk.Adjustment) => void;
|
|
48
|
+
getValue: () => number;
|
|
32
49
|
};
|
|
33
50
|
export declare const isAppendable: (obj: unknown) => obj is AppendableWidget;
|
|
34
51
|
export declare const isAddable: (obj: unknown) => obj is AddableWidget;
|
|
35
|
-
export declare const
|
|
52
|
+
export declare const isContentWidget: (obj: unknown) => obj is ContentWidget;
|
|
36
53
|
export declare const isSingleChild: (obj: unknown) => obj is SingleChildWidget;
|
|
37
54
|
export declare const isRemovable: (obj: unknown) => obj is RemovableWidget;
|
|
38
55
|
export declare const isReorderable: (obj: unknown) => obj is ReorderableWidget;
|
|
39
56
|
export declare const isInsertable: (obj: unknown) => obj is InsertableWidget;
|
|
40
57
|
export declare const isEditable: (obj: unknown) => obj is EditableWidget;
|
|
41
|
-
export declare const
|
|
58
|
+
export declare const isBufferedType: (type: string) => boolean;
|
|
59
|
+
export type Attachable = {
|
|
60
|
+
canBeChildOf(parent: Node): boolean;
|
|
61
|
+
attachTo(parent: Node): void;
|
|
62
|
+
detachFrom(parent: Node): void;
|
|
63
|
+
};
|
|
64
|
+
export declare function isAttachable(node: Node): node is Node & Attachable;
|
|
42
65
|
export {};
|
|
@@ -1,42 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime type predicates for GTK widget capability detection.
|
|
3
|
+
*
|
|
4
|
+
* These predicates check for specific APIs that widgets may or may not expose.
|
|
5
|
+
* GTK widgets don't have a consistent interface - different widgets support
|
|
6
|
+
* different child management APIs - so runtime checking is necessary.
|
|
7
|
+
*
|
|
8
|
+
* Predicate evaluation order matters in WidgetNode.appendChild/removeChild:
|
|
9
|
+
* 1. isReorderable (Box, etc.) - reorderChildAfter/insertChildAfter
|
|
10
|
+
* 2. isInsertable (ListBox, etc.) - insert
|
|
11
|
+
* 3. isAppendable (most containers) - append
|
|
12
|
+
* 4. isAddable (some legacy widgets) - add
|
|
13
|
+
* 5. isContentWidget (ActionBar, etc.) - setContent
|
|
14
|
+
* 6. isSingleChild (Bin subclasses) - setChild
|
|
15
|
+
*/
|
|
1
16
|
import * as Gtk from "@gtkx/ffi/gtk";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
typeof
|
|
39
|
-
}
|
|
40
|
-
export const isAdjustable = (obj) => {
|
|
41
|
-
return obj instanceof Gtk.Widget && "setAdjustment" in obj && typeof obj.setAdjustment === "function";
|
|
42
|
-
};
|
|
17
|
+
import { resolveContainerClass } from "../../factory.js";
|
|
18
|
+
export const isAppendable = (obj) => obj instanceof Gtk.Widget && "append" in obj && typeof obj.append === "function";
|
|
19
|
+
export const isAddable = (obj) => obj instanceof Gtk.Widget && "add" in obj && typeof obj.add === "function";
|
|
20
|
+
export const isContentWidget = (obj) => obj instanceof Gtk.Widget && "setContent" in obj && typeof obj.setContent === "function";
|
|
21
|
+
export const isSingleChild = (obj) => obj instanceof Gtk.Widget && "setChild" in obj && typeof obj.setChild === "function";
|
|
22
|
+
export const isRemovable = (obj) => obj instanceof Gtk.Widget && "remove" in obj && typeof obj.remove === "function";
|
|
23
|
+
export const isReorderable = (obj) => obj instanceof Gtk.Widget &&
|
|
24
|
+
"reorderChildAfter" in obj &&
|
|
25
|
+
typeof obj.reorderChildAfter === "function" &&
|
|
26
|
+
"insertChildAfter" in obj &&
|
|
27
|
+
typeof obj.insertChildAfter === "function";
|
|
28
|
+
export const isInsertable = (obj) => obj instanceof Gtk.Widget &&
|
|
29
|
+
"insert" in obj &&
|
|
30
|
+
typeof obj.insert === "function" &&
|
|
31
|
+
"getFirstChild" in obj &&
|
|
32
|
+
typeof obj.getFirstChild === "function";
|
|
33
|
+
export const isEditable = (obj) => obj instanceof Gtk.Widget &&
|
|
34
|
+
"getPosition" in obj &&
|
|
35
|
+
typeof obj.getPosition === "function" &&
|
|
36
|
+
"setPosition" in obj &&
|
|
37
|
+
typeof obj.setPosition === "function" &&
|
|
38
|
+
"getText" in obj &&
|
|
39
|
+
typeof obj.getText === "function";
|
|
40
|
+
const isBuffered = (obj) => obj instanceof Gtk.Widget &&
|
|
41
|
+
"getBuffer" in obj &&
|
|
42
|
+
typeof obj.getBuffer === "function" &&
|
|
43
|
+
"setBuffer" in obj &&
|
|
44
|
+
typeof obj.setBuffer === "function";
|
|
45
|
+
export const isBufferedType = (type) => {
|
|
46
|
+
const containerClass = resolveContainerClass(type);
|
|
47
|
+
return containerClass !== null && isBuffered(containerClass.prototype);
|
|
48
|
+
};
|
|
49
|
+
export function isAttachable(node) {
|
|
50
|
+
const candidate = node;
|
|
51
|
+
return (typeof candidate.canBeChildOf === "function" &&
|
|
52
|
+
typeof candidate.attachTo === "function" &&
|
|
53
|
+
typeof candidate.detachFrom === "function");
|
|
54
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type * as Gio from "@gtkx/ffi/gio";
|
|
2
|
+
import * as Gtk from "@gtkx/ffi/gtk";
|
|
3
|
+
import type { SignalStore } from "./signal-store.js";
|
|
4
|
+
type SelectionModel = Gtk.NoSelection | Gtk.SingleSelection | Gtk.MultiSelection;
|
|
5
|
+
export type SelectionModelConfig = {
|
|
6
|
+
owner: object;
|
|
7
|
+
signalStore: SignalStore;
|
|
8
|
+
selectionMode?: Gtk.SelectionMode;
|
|
9
|
+
selected?: string[];
|
|
10
|
+
onSelectionChanged?: (ids: string[]) => void;
|
|
11
|
+
};
|
|
12
|
+
export declare class SelectionModelManager {
|
|
13
|
+
private owner;
|
|
14
|
+
private signalStore;
|
|
15
|
+
private selectionModel;
|
|
16
|
+
private handleSelectionChange;
|
|
17
|
+
private pendingSelection;
|
|
18
|
+
private selectionAction;
|
|
19
|
+
private getSelection;
|
|
20
|
+
private resolveSelectionIndices;
|
|
21
|
+
private getItemCount;
|
|
22
|
+
constructor(config: SelectionModelConfig, model: Gio.ListModel, getSelection: () => string[], resolveSelectionIndices: (ids: string[]) => Gtk.Bitset, getItemCount: () => number);
|
|
23
|
+
getSelectionModel(): SelectionModel;
|
|
24
|
+
update(oldProps: SelectionModelConfig | null, newProps: SelectionModelConfig, model: Gio.ListModel): SelectionModel;
|
|
25
|
+
private initSelectionHandler;
|
|
26
|
+
private createSelectionModel;
|
|
27
|
+
private setSelection;
|
|
28
|
+
private applySelection;
|
|
29
|
+
}
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import * as Gtk from "@gtkx/ffi/gtk";
|
|
2
|
+
import { CommitPriority } from "../../scheduler.js";
|
|
3
|
+
import { DeferredAction } from "./deferred-action.js";
|
|
4
|
+
export class SelectionModelManager {
|
|
5
|
+
owner;
|
|
6
|
+
signalStore;
|
|
7
|
+
selectionModel;
|
|
8
|
+
handleSelectionChange = null;
|
|
9
|
+
pendingSelection = null;
|
|
10
|
+
selectionAction;
|
|
11
|
+
getSelection;
|
|
12
|
+
resolveSelectionIndices;
|
|
13
|
+
getItemCount;
|
|
14
|
+
constructor(config, model, getSelection, resolveSelectionIndices, getItemCount) {
|
|
15
|
+
this.owner = config.owner;
|
|
16
|
+
this.signalStore = config.signalStore;
|
|
17
|
+
this.selectionModel = this.createSelectionModel(config.selectionMode, model);
|
|
18
|
+
this.selectionModel.setModel(model);
|
|
19
|
+
this.getSelection = getSelection;
|
|
20
|
+
this.resolveSelectionIndices = resolveSelectionIndices;
|
|
21
|
+
this.getItemCount = getItemCount;
|
|
22
|
+
this.selectionAction = new DeferredAction(() => this.applySelection(), CommitPriority.LOW);
|
|
23
|
+
this.initSelectionHandler(config.onSelectionChanged);
|
|
24
|
+
this.setSelection(config.selected);
|
|
25
|
+
}
|
|
26
|
+
getSelectionModel() {
|
|
27
|
+
return this.selectionModel;
|
|
28
|
+
}
|
|
29
|
+
update(oldProps, newProps, model) {
|
|
30
|
+
if (oldProps && oldProps.selectionMode !== newProps.selectionMode) {
|
|
31
|
+
this.signalStore.set(this.owner, this.selectionModel, "selection-changed", null);
|
|
32
|
+
this.selectionModel = this.createSelectionModel(newProps.selectionMode, model);
|
|
33
|
+
this.selectionModel.setModel(model);
|
|
34
|
+
this.initSelectionHandler(newProps.onSelectionChanged);
|
|
35
|
+
this.setSelection(newProps.selected);
|
|
36
|
+
return this.selectionModel;
|
|
37
|
+
}
|
|
38
|
+
if (!oldProps || oldProps.onSelectionChanged !== newProps.onSelectionChanged) {
|
|
39
|
+
this.initSelectionHandler(newProps.onSelectionChanged);
|
|
40
|
+
}
|
|
41
|
+
if (!oldProps || oldProps.selected !== newProps.selected) {
|
|
42
|
+
this.setSelection(newProps.selected);
|
|
43
|
+
}
|
|
44
|
+
return this.selectionModel;
|
|
45
|
+
}
|
|
46
|
+
initSelectionHandler(onSelectionChanged) {
|
|
47
|
+
if (!onSelectionChanged) {
|
|
48
|
+
this.signalStore.set(this.owner, this.selectionModel, "selection-changed", null);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
this.handleSelectionChange = () => {
|
|
52
|
+
onSelectionChanged(this.getSelection());
|
|
53
|
+
};
|
|
54
|
+
this.signalStore.set(this.owner, this.selectionModel, "selection-changed", this.handleSelectionChange);
|
|
55
|
+
}
|
|
56
|
+
createSelectionModel(mode, model) {
|
|
57
|
+
const selectionMode = mode ?? Gtk.SelectionMode.SINGLE;
|
|
58
|
+
if (selectionMode === Gtk.SelectionMode.NONE) {
|
|
59
|
+
return new Gtk.NoSelection(model);
|
|
60
|
+
}
|
|
61
|
+
if (selectionMode === Gtk.SelectionMode.MULTIPLE) {
|
|
62
|
+
return new Gtk.MultiSelection(model);
|
|
63
|
+
}
|
|
64
|
+
const selectionModel = new Gtk.SingleSelection(model);
|
|
65
|
+
selectionModel.setAutoselect(selectionMode === Gtk.SelectionMode.BROWSE);
|
|
66
|
+
selectionModel.setCanUnselect(selectionMode !== Gtk.SelectionMode.BROWSE);
|
|
67
|
+
return selectionModel;
|
|
68
|
+
}
|
|
69
|
+
setSelection(ids) {
|
|
70
|
+
this.pendingSelection = ids ?? null;
|
|
71
|
+
this.selectionAction.schedule();
|
|
72
|
+
}
|
|
73
|
+
applySelection() {
|
|
74
|
+
const ids = this.pendingSelection;
|
|
75
|
+
const nItems = this.getItemCount();
|
|
76
|
+
if (nItems === 0 && ids && ids.length > 0) {
|
|
77
|
+
this.setSelection(ids);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
this.pendingSelection = null;
|
|
81
|
+
const selected = ids ? this.resolveSelectionIndices(ids) : new Gtk.Bitset();
|
|
82
|
+
const mask = Gtk.Bitset.newRange(0, nItems);
|
|
83
|
+
if (this.selectionModel instanceof Gtk.SingleSelection) {
|
|
84
|
+
const position = selected.getSize() > 0 ? selected.getNth(0) : Gtk.INVALID_LIST_POSITION;
|
|
85
|
+
this.selectionModel.setSelected(position);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
this.selectionModel.setSelection(selected, mask);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import * as GObject from "@gtkx/ffi/gobject";
|
|
2
2
|
type SignalOwner = object;
|
|
3
3
|
export type SignalHandler = (...args: any[]) => any;
|
|
4
|
-
declare class SignalStore {
|
|
4
|
+
export declare class SignalStore {
|
|
5
5
|
private ownerHandlers;
|
|
6
|
-
private
|
|
7
|
-
private isBlocking;
|
|
6
|
+
private blockDepth;
|
|
8
7
|
private getOwnerMap;
|
|
8
|
+
private wrapHandler;
|
|
9
9
|
private disconnect;
|
|
10
10
|
private connect;
|
|
11
11
|
set(owner: SignalOwner, obj: GObject.GObject, signal: string, handler?: SignalHandler | null): void;
|
|
12
12
|
clear(owner: SignalOwner): void;
|
|
13
13
|
blockAll(): void;
|
|
14
14
|
unblockAll(): void;
|
|
15
|
+
forceUnblockAll(): void;
|
|
15
16
|
}
|
|
16
|
-
export declare
|
|
17
|
+
export declare function getSignalStore(rootContainer: object): SignalStore;
|
|
17
18
|
export {};
|