@gjsify/example-gtk-adwaita-storybook 0.53.0 → 0.55.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/dist/browser-main.js +8093 -3042
- package/dist/gjs.js +15 -10
- package/dist/gjs.node.mjs +10 -5
- package/package.json +5 -5
- package/src/browser/buttons/color-dialog-button.web.ts +42 -0
- package/src/browser/buttons/font-dialog-button.web.ts +42 -0
- package/src/browser/buttons/link-button.web.ts +37 -0
- package/src/browser/buttons/scale-button.web.ts +36 -0
- package/src/browser/buttons/toggle-button.web.ts +35 -0
- package/src/browser/controls/check-button.web.ts +38 -0
- package/src/browser/controls/gtk-spinner.web.ts +39 -0
- package/src/browser/controls/level-bar.web.ts +43 -0
- package/src/browser/controls/password-entry.web.ts +36 -0
- package/src/browser/controls/progress-bar.web.ts +39 -0
- package/src/browser/controls/scale.web.ts +44 -0
- package/src/browser/controls/search-entry.web.ts +49 -0
- package/src/browser/controls/spin-button.web.ts +40 -0
- package/src/browser/controls/switch.web.ts +38 -0
- package/src/browser/drawing/drag-icon.web.ts +112 -0
- package/src/browser/drawing/drawing-area.web.ts +66 -0
- package/src/browser/drawing/gl-area.web.ts +162 -0
- package/src/browser/drawing/graphics-offload.web.ts +74 -0
- package/src/browser/feedback/dialog.web.ts +76 -0
- package/src/browser/feedback/emoji-chooser.web.ts +93 -0
- package/src/browser/feedback/gtk-about-dialog.web.ts +105 -0
- package/src/browser/feedback/page-setup-unix-dialog.web.ts +93 -0
- package/src/browser/feedback/print-unix-dialog.web.ts +111 -0
- package/src/browser/feedback/shortcuts-dialog.web.ts +90 -0
- package/src/browser/layout/application-window.web.ts +94 -0
- package/src/browser/layout/aspect-frame.web.ts +49 -0
- package/src/browser/layout/bin.web.ts +41 -0
- package/src/browser/layout/breakpoint-bin.web.ts +61 -0
- package/src/browser/layout/center-box.web.ts +45 -0
- package/src/browser/layout/clamp-scrollable.web.ts +47 -0
- package/src/browser/layout/expander.web.ts +52 -0
- package/src/browser/layout/fixed.web.ts +51 -0
- package/src/browser/layout/frame.web.ts +40 -0
- package/src/browser/layout/grid.web.ts +46 -0
- package/src/browser/layout/layout-slot.web.ts +60 -0
- package/src/browser/layout/multi-layout-view.web.ts +94 -0
- package/src/browser/layout/overlay.web.ts +57 -0
- package/src/browser/layout/paned.web.ts +69 -0
- package/src/browser/layout/popover-bin.web.ts +54 -0
- package/src/browser/layout/popover-menu.web.ts +48 -0
- package/src/browser/layout/popover.web.ts +61 -0
- package/src/browser/layout/revealer.web.ts +53 -0
- package/src/browser/layout/scrollbar.web.ts +54 -0
- package/src/browser/layout/scrolled-window.web.ts +52 -0
- package/src/browser/layout/separator.web.ts +47 -0
- package/src/browser/layout/viewport.web.ts +51 -0
- package/src/browser/layout/window.web.ts +60 -0
- package/src/browser/media/image.web.ts +39 -0
- package/src/browser/media/inscription.web.ts +52 -0
- package/src/browser/media/media-controls.web.ts +65 -0
- package/src/browser/media/picture.web.ts +56 -0
- package/src/browser/media/video.web.ts +56 -0
- package/src/browser/navigation/popover-menu-bar.web.ts +40 -0
- package/src/browser/presentation/calendar.web.ts +49 -0
- package/src/browser/presentation/column-view.web.ts +45 -0
- package/src/browser/presentation/flow-box.web.ts +52 -0
- package/src/browser/presentation/grid-view.web.ts +37 -0
- package/src/browser/presentation/list-box.web.ts +48 -0
- package/src/browser/presentation/list-view.web.ts +36 -0
- package/src/browser/presentation/tree-expander.web.ts +68 -0
- package/src/browser/presentation/window-handle.web.ts +42 -0
- package/src/browser/rows/preferences-row.web.ts +43 -0
- package/src/browser/stories.ts +158 -0
- package/src/browser/text/editable-label.web.ts +45 -0
- package/src/browser/text/search-bar.web.ts +45 -0
- package/src/browser/text/text-view.web.ts +54 -0
- package/src/browser/text/text.web.ts +48 -0
- package/src/browser/view-switching/notebook.web.ts +67 -0
- package/src/browser/view-switching/stack-sidebar.web.ts +68 -0
- package/src/browser/view-switching/stack-switcher.web.ts +70 -0
- package/src/browser/view-switching/stack.web.ts +72 -0
- package/src/browser/view-switching/tab-bar.web.ts +105 -0
- package/src/browser/view-switching/tab-button.web.ts +52 -0
- package/src/browser/view-switching/tab-overview.web.ts +87 -0
- package/src/browser/view-switching/view-switcher-sidebar.web.ts +77 -0
- package/src/browser/windows/action-bar.web.ts +66 -0
- package/src/browser/windows/gtk-application-window.web.ts +67 -0
- package/src/browser/windows/gtk-header-bar.web.ts +61 -0
- package/src/browser/windows/gtk-window.web.ts +58 -0
- package/src/browser/windows/window-controls.web.ts +54 -0
- package/src/buttons/color-dialog-button.meta.ts +16 -0
- package/src/buttons/color-dialog-button.story.ts +49 -0
- package/src/buttons/font-dialog-button.meta.ts +29 -0
- package/src/buttons/font-dialog-button.story.ts +52 -0
- package/src/buttons/link-button.meta.ts +18 -0
- package/src/buttons/link-button.story.ts +48 -0
- package/src/buttons/scale-button.meta.ts +34 -0
- package/src/buttons/scale-button.story.ts +50 -0
- package/src/buttons/toggle-button.meta.ts +17 -0
- package/src/buttons/toggle-button.story.ts +46 -0
- package/src/controls/check-button.meta.ts +19 -0
- package/src/controls/check-button.story.ts +56 -0
- package/src/controls/gtk-spinner.meta.ts +24 -0
- package/src/controls/gtk-spinner.story.ts +53 -0
- package/src/controls/level-bar.meta.ts +39 -0
- package/src/controls/level-bar.story.ts +58 -0
- package/src/controls/password-entry.meta.ts +18 -0
- package/src/controls/password-entry.story.ts +54 -0
- package/src/controls/progress-bar.meta.ts +20 -0
- package/src/controls/progress-bar.story.ts +53 -0
- package/src/controls/scale.meta.ts +47 -0
- package/src/controls/scale.story.ts +66 -0
- package/src/controls/search-entry.meta.ts +18 -0
- package/src/controls/search-entry.story.ts +57 -0
- package/src/controls/spin-button.meta.ts +40 -0
- package/src/controls/spin-button.story.ts +55 -0
- package/src/controls/switch.meta.ts +18 -0
- package/src/controls/switch.story.ts +50 -0
- package/src/drawing/drag-icon.meta.ts +39 -0
- package/src/drawing/drag-icon.story.ts +117 -0
- package/src/drawing/drawing-area.meta.ts +45 -0
- package/src/drawing/drawing-area.story.ts +78 -0
- package/src/drawing/gl-area.meta.ts +30 -0
- package/src/drawing/gl-area.story.ts +113 -0
- package/src/drawing/graphics-offload.meta.ts +39 -0
- package/src/drawing/graphics-offload.story.ts +73 -0
- package/src/feedback/dialog.meta.ts +25 -0
- package/src/feedback/dialog.story.ts +78 -0
- package/src/feedback/emoji-chooser.meta.ts +10 -0
- package/src/feedback/emoji-chooser.story.ts +98 -0
- package/src/feedback/gtk-about-dialog.meta.ts +29 -0
- package/src/feedback/gtk-about-dialog.story.ts +90 -0
- package/src/feedback/page-setup-unix-dialog.meta.ts +37 -0
- package/src/feedback/page-setup-unix-dialog.story.ts +70 -0
- package/src/feedback/print-unix-dialog.meta.ts +30 -0
- package/src/feedback/print-unix-dialog.story.ts +93 -0
- package/src/feedback/shortcuts-dialog.meta.ts +12 -0
- package/src/feedback/shortcuts-dialog.story.ts +79 -0
- package/src/layout/application-window.meta.ts +16 -0
- package/src/layout/application-window.story.ts +97 -0
- package/src/layout/aspect-frame.meta.ts +19 -0
- package/src/layout/aspect-frame.story.ts +62 -0
- package/src/layout/bin.meta.ts +15 -0
- package/src/layout/bin.story.ts +56 -0
- package/src/layout/breakpoint-bin.meta.ts +38 -0
- package/src/layout/breakpoint-bin.story.ts +62 -0
- package/src/layout/center-box.meta.ts +26 -0
- package/src/layout/center-box.story.ts +54 -0
- package/src/layout/clamp-scrollable.meta.ts +30 -0
- package/src/layout/clamp-scrollable.story.ts +51 -0
- package/src/layout/expander.meta.ts +30 -0
- package/src/layout/expander.story.ts +62 -0
- package/src/layout/fixed.meta.ts +16 -0
- package/src/layout/fixed.story.ts +54 -0
- package/src/layout/frame.meta.ts +24 -0
- package/src/layout/frame.story.ts +51 -0
- package/src/layout/grid.meta.ts +45 -0
- package/src/layout/grid.story.ts +80 -0
- package/src/layout/layout-slot.meta.ts +22 -0
- package/src/layout/layout-slot.story.ts +68 -0
- package/src/layout/multi-layout-view.meta.ts +31 -0
- package/src/layout/multi-layout-view.story.ts +101 -0
- package/src/layout/overlay.meta.ts +42 -0
- package/src/layout/overlay.story.ts +72 -0
- package/src/layout/paned.meta.ts +45 -0
- package/src/layout/paned.story.ts +70 -0
- package/src/layout/popover-bin.meta.ts +29 -0
- package/src/layout/popover-bin.story.ts +66 -0
- package/src/layout/popover-menu.meta.ts +54 -0
- package/src/layout/popover-menu.story.ts +119 -0
- package/src/layout/popover.meta.ts +38 -0
- package/src/layout/popover.story.ts +66 -0
- package/src/layout/revealer.meta.ts +44 -0
- package/src/layout/revealer.story.ts +79 -0
- package/src/layout/scrollbar.meta.ts +33 -0
- package/src/layout/scrollbar.story.ts +61 -0
- package/src/layout/scrolled-window.meta.ts +57 -0
- package/src/layout/scrolled-window.story.ts +74 -0
- package/src/layout/separator.meta.ts +25 -0
- package/src/layout/separator.story.ts +53 -0
- package/src/layout/viewport.meta.ts +19 -0
- package/src/layout/viewport.story.ts +53 -0
- package/src/layout/window.meta.ts +13 -0
- package/src/layout/window.story.ts +66 -0
- package/src/media/image.meta.ts +24 -0
- package/src/media/image.story.ts +48 -0
- package/src/media/inscription.meta.ts +45 -0
- package/src/media/inscription.story.ts +64 -0
- package/src/media/media-controls.meta.ts +30 -0
- package/src/media/media-controls.story.ts +58 -0
- package/src/media/picture.meta.ts +42 -0
- package/src/media/picture.story.ts +81 -0
- package/src/media/video.meta.ts +32 -0
- package/src/media/video.story.ts +57 -0
- package/src/metas.ts +79 -0
- package/src/navigation/popover-menu-bar.meta.ts +51 -0
- package/src/navigation/popover-menu-bar.story.ts +72 -0
- package/src/presentation/calendar.meta.ts +28 -0
- package/src/presentation/calendar.story.ts +64 -0
- package/src/presentation/column-view.meta.ts +30 -0
- package/src/presentation/column-view.story.ts +73 -0
- package/src/presentation/flow-box.meta.ts +51 -0
- package/src/presentation/flow-box.story.ts +72 -0
- package/src/presentation/grid-view.meta.ts +28 -0
- package/src/presentation/grid-view.story.ts +64 -0
- package/src/presentation/list-box.meta.ts +55 -0
- package/src/presentation/list-box.story.ts +68 -0
- package/src/presentation/list-view.meta.ts +38 -0
- package/src/presentation/list-view.story.ts +73 -0
- package/src/presentation/tree-expander.meta.ts +24 -0
- package/src/presentation/tree-expander.story.ts +105 -0
- package/src/presentation/window-handle.meta.ts +27 -0
- package/src/presentation/window-handle.story.ts +53 -0
- package/src/rows/preferences-row.meta.ts +15 -0
- package/src/rows/preferences-row.story.ts +50 -0
- package/src/text/editable-label.meta.ts +17 -0
- package/src/text/editable-label.story.ts +47 -0
- package/src/text/search-bar.meta.ts +17 -0
- package/src/text/search-bar.story.ts +48 -0
- package/src/text/text-view.meta.ts +49 -0
- package/src/text/text-view.story.ts +69 -0
- package/src/text/text.meta.ts +21 -0
- package/src/text/text.story.ts +50 -0
- package/src/view-switching/notebook.meta.ts +44 -0
- package/src/view-switching/notebook.story.ts +77 -0
- package/src/view-switching/stack-sidebar.meta.ts +50 -0
- package/src/view-switching/stack-sidebar.story.ts +85 -0
- package/src/view-switching/stack-switcher.meta.ts +53 -0
- package/src/view-switching/stack-switcher.story.ts +95 -0
- package/src/view-switching/stack.meta.ts +53 -0
- package/src/view-switching/stack.story.ts +95 -0
- package/src/view-switching/tab-bar.meta.ts +22 -0
- package/src/view-switching/tab-bar.story.ts +85 -0
- package/src/view-switching/tab-button.meta.ts +14 -0
- package/src/view-switching/tab-button.story.ts +52 -0
- package/src/view-switching/tab-overview.meta.ts +21 -0
- package/src/view-switching/tab-overview.story.ts +86 -0
- package/src/view-switching/view-switcher-sidebar.meta.ts +42 -0
- package/src/view-switching/view-switcher-sidebar.story.ts +73 -0
- package/src/windows/action-bar.meta.ts +27 -0
- package/src/windows/action-bar.story.ts +65 -0
- package/src/windows/gtk-application-window.meta.ts +27 -0
- package/src/windows/gtk-application-window.story.ts +89 -0
- package/src/windows/gtk-header-bar.meta.ts +39 -0
- package/src/windows/gtk-header-bar.story.ts +76 -0
- package/src/windows/gtk-window.meta.ts +30 -0
- package/src/windows/gtk-window.story.ts +64 -0
- package/src/windows/window-controls.meta.ts +42 -0
- package/src/windows/window-controls.story.ts +61 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Shared, renderer-agnostic metadata for the Grid story. Imported by the GTK
|
|
2
|
+
// renderer (grid.story.ts) and the browser renderer (browser/layout/grid.web.ts),
|
|
3
|
+
// so both expose identical controls.
|
|
4
|
+
|
|
5
|
+
import { ControlType, type StoryMeta } from '@gjsify/stories';
|
|
6
|
+
|
|
7
|
+
export const gridMeta: StoryMeta = {
|
|
8
|
+
title: 'Layout/Grid',
|
|
9
|
+
description:
|
|
10
|
+
'Gtk.Grid — a table of cells sized by what is in them, filled row by row. The two spacings are the ' +
|
|
11
|
+
'gap between lines, the two homogeneous flags make every line the same, and a vertical grid attaches ' +
|
|
12
|
+
'down the rows instead of across the columns.',
|
|
13
|
+
controls: [
|
|
14
|
+
{
|
|
15
|
+
name: 'columnSpacing',
|
|
16
|
+
label: 'Column spacing',
|
|
17
|
+
type: ControlType.RANGE,
|
|
18
|
+
min: 0,
|
|
19
|
+
max: 36,
|
|
20
|
+
step: 2,
|
|
21
|
+
defaultValue: 12,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: 'rowSpacing',
|
|
25
|
+
label: 'Row spacing',
|
|
26
|
+
type: ControlType.RANGE,
|
|
27
|
+
min: 0,
|
|
28
|
+
max: 36,
|
|
29
|
+
step: 2,
|
|
30
|
+
defaultValue: 12,
|
|
31
|
+
},
|
|
32
|
+
{ name: 'columnHomogeneous', label: 'Column homogeneous', type: ControlType.BOOLEAN, defaultValue: false },
|
|
33
|
+
{ name: 'rowHomogeneous', label: 'Row homogeneous', type: ControlType.BOOLEAN, defaultValue: false },
|
|
34
|
+
{
|
|
35
|
+
name: 'orientation',
|
|
36
|
+
label: 'Orientation',
|
|
37
|
+
type: ControlType.SELECT,
|
|
38
|
+
options: [
|
|
39
|
+
{ label: 'Horizontal', value: 'horizontal' },
|
|
40
|
+
{ label: 'Vertical', value: 'vertical' },
|
|
41
|
+
],
|
|
42
|
+
defaultValue: 'horizontal',
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Gtk.Grid — a table of cells filled row by row.
|
|
2
|
+
// original implementation.
|
|
3
|
+
|
|
4
|
+
import Gtk from 'gi://Gtk?version=4.0';
|
|
5
|
+
import GObject from 'gi://GObject?version=2.0';
|
|
6
|
+
import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
|
|
7
|
+
import { gridMeta } from './grid.meta.js';
|
|
8
|
+
|
|
9
|
+
/** Story: a Gtk.Grid of four labels with its spacings, homogeneity and orientation bound to args. */
|
|
10
|
+
export class GridStory extends StoryWidget {
|
|
11
|
+
private _grid: Gtk.Grid | null = null;
|
|
12
|
+
private _cells: Gtk.Label[] = [];
|
|
13
|
+
private _orientation: Gtk.Orientation | null = null;
|
|
14
|
+
|
|
15
|
+
static {
|
|
16
|
+
GObject.registerClass({ GTypeName: 'AdwStorybookGrid' }, GridStory);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
constructor() {
|
|
20
|
+
super(StoryWidget.fromMeta(GridStory.getMetadata(), 'Default'));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static getMetadata(): StoryMeta {
|
|
24
|
+
return { ...gridMeta, component: Gtk.Grid.$gtype };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
initialize(): void {
|
|
28
|
+
this._grid = new Gtk.Grid({
|
|
29
|
+
hexpand: true,
|
|
30
|
+
margin_top: 12,
|
|
31
|
+
margin_bottom: 12,
|
|
32
|
+
margin_start: 12,
|
|
33
|
+
margin_end: 12,
|
|
34
|
+
});
|
|
35
|
+
for (const text of ['Name', 'Value', 'Unit', 'editable']) {
|
|
36
|
+
const cell = new Gtk.Label({ label: text, hexpand: true });
|
|
37
|
+
cell.set_margin_top(6);
|
|
38
|
+
cell.set_margin_bottom(6);
|
|
39
|
+
cell.set_margin_start(6);
|
|
40
|
+
cell.set_margin_end(6);
|
|
41
|
+
this._cells.push(cell);
|
|
42
|
+
}
|
|
43
|
+
this._attach();
|
|
44
|
+
this._apply();
|
|
45
|
+
this.addContent(this._grid);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
updateArgs(_args: StoryArgs): void {
|
|
49
|
+
this._apply();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** `attach(child, -1, -1, 1, 1)` — what `Gtk.Builder` writes for a child with no position. */
|
|
53
|
+
private _attach(): void {
|
|
54
|
+
if (!this._grid) return;
|
|
55
|
+
for (const cell of this._cells) this._grid.attach(cell, -1, -1, 1, 1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private _apply(): void {
|
|
59
|
+
if (!this._grid) return;
|
|
60
|
+
const orientation =
|
|
61
|
+
(this.args.orientation as string) === 'vertical' ? Gtk.Orientation.VERTICAL : Gtk.Orientation.HORIZONTAL;
|
|
62
|
+
this._grid.columnSpacing = this.args.columnSpacing as number;
|
|
63
|
+
this._grid.rowSpacing = this.args.rowSpacing as number;
|
|
64
|
+
this._grid.columnHomogeneous = this.args.columnHomogeneous as boolean;
|
|
65
|
+
this._grid.rowHomogeneous = this.args.rowHomogeneous as boolean;
|
|
66
|
+
// A child is attached along the ORIENTATION at the moment it is added
|
|
67
|
+
// (gtkgrid.c:493-507), so turning a filled grid around is re-attaching — which is
|
|
68
|
+
// exactly what the browser renderer's `grid-auto-flow` change does for free.
|
|
69
|
+
if (this._orientation !== null && this._orientation !== orientation) {
|
|
70
|
+
for (const cell of this._cells) this._grid.remove(cell);
|
|
71
|
+
this._attach();
|
|
72
|
+
}
|
|
73
|
+
this._grid.orientation = orientation;
|
|
74
|
+
this._orientation = orientation;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
GObject.type_ensure(GridStory.$gtype);
|
|
79
|
+
|
|
80
|
+
export const GridStories: StoryModule = { stories: [GridStory] };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Shared, renderer-agnostic metadata for the Layout Slot story. Imported by the GTK
|
|
2
|
+
// renderer (layout-slot.story.ts) and the browser renderer
|
|
3
|
+
// (browser/layout/layout-slot.web.ts), so both expose identical controls.
|
|
4
|
+
|
|
5
|
+
import { ControlType, type StoryMeta } from '@gjsify/stories';
|
|
6
|
+
|
|
7
|
+
export const layoutSlotMeta: StoryMeta = {
|
|
8
|
+
title: 'Layout/Layout Slot',
|
|
9
|
+
description:
|
|
10
|
+
'Adw.LayoutSlot is the named hole a layout of an Adw.MultiLayoutView leaves for a ' +
|
|
11
|
+
'child: it takes the child whose id matches, and its visible property follows that ' +
|
|
12
|
+
"child's. On its own it is a bin, which is what this story shows.",
|
|
13
|
+
controls: [
|
|
14
|
+
{ name: 'label', label: 'Child title', type: ControlType.TEXT, defaultValue: 'Inbox' },
|
|
15
|
+
{
|
|
16
|
+
name: 'visible',
|
|
17
|
+
label: 'Child visible',
|
|
18
|
+
type: ControlType.BOOLEAN,
|
|
19
|
+
defaultValue: true,
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Adw.LayoutSlot — the named hole a layout of an Adw.MultiLayoutView leaves for a child.
|
|
2
|
+
// original implementation.
|
|
3
|
+
|
|
4
|
+
import Adw from 'gi://Adw?version=1';
|
|
5
|
+
import Gtk from 'gi://Gtk?version=4.0';
|
|
6
|
+
import GObject from 'gi://GObject?version=2.0';
|
|
7
|
+
import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
|
|
8
|
+
import { layoutSlotMeta } from './layout-slot.meta.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Story: one slot holding one child.
|
|
12
|
+
*
|
|
13
|
+
* A slot only ever exists inside a layout, and a layout only ever exists inside a
|
|
14
|
+
* multi-layout view — the view is what inserts the child whose id matches the slot's. So
|
|
15
|
+
* this story builds the whole pair and names the SLOT, which is the half a reader cannot
|
|
16
|
+
* see anywhere else: the `visible` binding the view installs between the two
|
|
17
|
+
* (adw-multi-layout-view.c:151).
|
|
18
|
+
*/
|
|
19
|
+
export class LayoutSlotStory extends StoryWidget {
|
|
20
|
+
private _view: Adw.MultiLayoutView | null = null;
|
|
21
|
+
private _slot: Adw.LayoutSlot | null = null;
|
|
22
|
+
private _child: Adw.NavigationPage | null = null;
|
|
23
|
+
|
|
24
|
+
static {
|
|
25
|
+
GObject.registerClass({ GTypeName: 'AdwStorybookLayoutSlot' }, LayoutSlotStory);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
constructor() {
|
|
29
|
+
super(StoryWidget.fromMeta(LayoutSlotStory.getMetadata(), 'Default'));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static getMetadata(): StoryMeta {
|
|
33
|
+
return { ...layoutSlotMeta, component: Adw.LayoutSlot.$gtype };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
initialize(): void {
|
|
37
|
+
this._slot = Adw.LayoutSlot.new('primary');
|
|
38
|
+
this._child = new Adw.NavigationPage({
|
|
39
|
+
title: this.args.label as string,
|
|
40
|
+
tag: 'primary',
|
|
41
|
+
child: new Gtk.Label({ label: 'The child the view inserted here.' }),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
this._view = new Adw.MultiLayoutView();
|
|
45
|
+
const layout = Adw.Layout.new(this._slot);
|
|
46
|
+
layout.name = 'only';
|
|
47
|
+
this._view.add_layout(layout);
|
|
48
|
+
this._view.set_child('primary', this._child);
|
|
49
|
+
|
|
50
|
+
this._apply();
|
|
51
|
+
this.addContent(this._view);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
updateArgs(_args: StoryArgs): void {
|
|
55
|
+
this._apply();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private _apply(): void {
|
|
59
|
+
if (!this._child) return;
|
|
60
|
+
this._child.title = this.args.label as string;
|
|
61
|
+
// The binding is child → slot, one way: the slot cannot show what the child hides.
|
|
62
|
+
this._child.visible = this.args.visible as boolean;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
GObject.type_ensure(LayoutSlotStory.$gtype);
|
|
67
|
+
|
|
68
|
+
export const LayoutSlotStories: StoryModule = { stories: [LayoutSlotStory] };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Shared, renderer-agnostic metadata for the Multi Layout View story. Imported by the GTK
|
|
2
|
+
// renderer (multi-layout-view.story.ts) and the browser renderer
|
|
3
|
+
// (browser/layout/multi-layout-view.web.ts), so both expose identical controls.
|
|
4
|
+
|
|
5
|
+
import { ControlType, type StoryMeta } from '@gjsify/stories';
|
|
6
|
+
|
|
7
|
+
export const multiLayoutViewMeta: StoryMeta = {
|
|
8
|
+
title: 'Layout/Multi Layout View',
|
|
9
|
+
description:
|
|
10
|
+
'Adw.MultiLayoutView holds one set of children and several arrangements of them: each ' +
|
|
11
|
+
'child has an id, each layout has slots with ids, and switching layouts re-inserts ' +
|
|
12
|
+
'every child into the slot of the SAME id.',
|
|
13
|
+
controls: [
|
|
14
|
+
{
|
|
15
|
+
name: 'layoutName',
|
|
16
|
+
label: 'Layout',
|
|
17
|
+
type: ControlType.SELECT,
|
|
18
|
+
options: [
|
|
19
|
+
{ label: 'wide (split)', value: 'wide' },
|
|
20
|
+
{ label: 'narrow (stacked)', value: 'narrow' },
|
|
21
|
+
],
|
|
22
|
+
defaultValue: 'wide',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'showDetails',
|
|
26
|
+
label: 'Show the details pane',
|
|
27
|
+
type: ControlType.BOOLEAN,
|
|
28
|
+
defaultValue: true,
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// Adw.MultiLayoutView — one set of children, two arrangements of them.
|
|
2
|
+
// original implementation.
|
|
3
|
+
|
|
4
|
+
import Adw from 'gi://Adw?version=1';
|
|
5
|
+
import Gtk from 'gi://Gtk?version=4.0';
|
|
6
|
+
import GObject from 'gi://GObject?version=2.0';
|
|
7
|
+
import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
|
|
8
|
+
import { multiLayoutViewMeta } from './multi-layout-view.meta.js';
|
|
9
|
+
|
|
10
|
+
/** The two ids every layout here carries: the content, and the secondary pane. */
|
|
11
|
+
const PRIMARY = 'primary';
|
|
12
|
+
const SECONDARY = 'secondary';
|
|
13
|
+
|
|
14
|
+
/** A short list, so the two children are visibly different once they move. */
|
|
15
|
+
function page(rows: readonly (readonly [string, string])[]): Gtk.ListBox {
|
|
16
|
+
const list = new Gtk.ListBox({ selectionMode: Gtk.SelectionMode.NONE });
|
|
17
|
+
for (const [name, detail] of rows) list.append(new Adw.ActionRow({ title: name, subtitle: detail }));
|
|
18
|
+
return list;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** A split-view pane that holds nothing but a slot, so the child lands by id. */
|
|
22
|
+
function slotPage(id: string): Adw.NavigationPage {
|
|
23
|
+
return new Adw.NavigationPage({ title: id, child: Adw.LayoutSlot.new(id), tag: id });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* One arrangement: a split view whose two panes are SLOTS, so the children land by id.
|
|
28
|
+
*
|
|
29
|
+
* `collapsed` is what makes the second arrangement different — and it is the same pair of
|
|
30
|
+
* children either way, which is the whole point of the widget.
|
|
31
|
+
*/
|
|
32
|
+
function arrangement(collapsed: boolean): Adw.NavigationSplitView {
|
|
33
|
+
const view = new Adw.NavigationSplitView({ collapsed, minSidebarWidth: 160 });
|
|
34
|
+
view.sidebar = slotPage(SECONDARY);
|
|
35
|
+
view.content = slotPage(PRIMARY);
|
|
36
|
+
view.set_size_request(420, 220);
|
|
37
|
+
return view;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Story: the same two pages docked, then the same two pages stacked. */
|
|
41
|
+
export class MultiLayoutViewStory extends StoryWidget {
|
|
42
|
+
private _view: Adw.MultiLayoutView | null = null;
|
|
43
|
+
private _details: Gtk.Widget | null = null;
|
|
44
|
+
|
|
45
|
+
static {
|
|
46
|
+
GObject.registerClass({ GTypeName: 'AdwStorybookMultiLayoutView' }, MultiLayoutViewStory);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
constructor() {
|
|
50
|
+
super(StoryWidget.fromMeta(MultiLayoutViewStory.getMetadata(), 'Default'));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static getMetadata(): StoryMeta {
|
|
54
|
+
return { ...multiLayoutViewMeta, component: Adw.MultiLayoutView.$gtype };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
initialize(): void {
|
|
58
|
+
this._details = page([
|
|
59
|
+
['From', 'Adwaita List'],
|
|
60
|
+
['Subject', 'Resizing the window'],
|
|
61
|
+
]);
|
|
62
|
+
this._view = new Adw.MultiLayoutView();
|
|
63
|
+
// `add_layout` makes the FIRST layout current (adw-multi-layout-view.c:553), so the
|
|
64
|
+
// wide one goes in first; the name is set before the second is added, because
|
|
65
|
+
// `add_layout` warns on a duplicate and reads the name to do it.
|
|
66
|
+
const wide = Adw.Layout.new(arrangement(false));
|
|
67
|
+
wide.name = 'wide';
|
|
68
|
+
this._view.add_layout(wide);
|
|
69
|
+
const narrow = Adw.Layout.new(arrangement(true));
|
|
70
|
+
narrow.name = 'narrow';
|
|
71
|
+
this._view.add_layout(narrow);
|
|
72
|
+
|
|
73
|
+
this._view.set_child(
|
|
74
|
+
PRIMARY,
|
|
75
|
+
page([
|
|
76
|
+
['General', '12 unread'],
|
|
77
|
+
['Starred', '3 threads'],
|
|
78
|
+
]),
|
|
79
|
+
);
|
|
80
|
+
this._view.set_child(SECONDARY, this._details);
|
|
81
|
+
|
|
82
|
+
this._apply();
|
|
83
|
+
this.addContent(this._view);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
updateArgs(_args: StoryArgs): void {
|
|
87
|
+
this._apply();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private _apply(): void {
|
|
91
|
+
if (!this._view || !this._details) return;
|
|
92
|
+
// `visible` is bound one way, child to slot, so hiding the CHILD is what takes the
|
|
93
|
+
// hole with it.
|
|
94
|
+
this._details.visible = this.args.showDetails as boolean;
|
|
95
|
+
this._view.layout_name = this.args.layoutName as string;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
GObject.type_ensure(MultiLayoutViewStory.$gtype);
|
|
100
|
+
|
|
101
|
+
export const MultiLayoutViewStories: StoryModule = { stories: [MultiLayoutViewStory] };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Shared, renderer-agnostic metadata for the Overlay story. Imported by the GTK renderer
|
|
2
|
+
// (overlay.story.ts) and the browser renderer (browser/layout/overlay.web.ts), so both
|
|
3
|
+
// expose identical controls.
|
|
4
|
+
|
|
5
|
+
import { ControlType, type StoryMeta } from '@gjsify/stories';
|
|
6
|
+
|
|
7
|
+
export const overlayMeta: StoryMeta = {
|
|
8
|
+
title: 'Layout/Overlay',
|
|
9
|
+
description:
|
|
10
|
+
'Gtk.Overlay — widgets stacked on top of one main child. The main child sizes the overlay; ' +
|
|
11
|
+
'every other child is placed by its own halign/valign, which is what ' +
|
|
12
|
+
'gtk_overlay_get_child_position reads and nothing else. Libadwaita ships no Adw.Overlay ' +
|
|
13
|
+
'and gives the node no rule of its own — the .left/.right/.top/.bottom classes it puts on ' +
|
|
14
|
+
'an edge-aligned child are the whole published contract.',
|
|
15
|
+
controls: [
|
|
16
|
+
{
|
|
17
|
+
name: 'halign',
|
|
18
|
+
label: 'Overlay halign',
|
|
19
|
+
type: ControlType.SELECT,
|
|
20
|
+
options: [
|
|
21
|
+
{ label: 'Fill (the default)', value: 'fill' },
|
|
22
|
+
{ label: 'Start', value: 'start' },
|
|
23
|
+
{ label: 'Center', value: 'center' },
|
|
24
|
+
{ label: 'End', value: 'end' },
|
|
25
|
+
],
|
|
26
|
+
defaultValue: 'end',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'valign',
|
|
30
|
+
label: 'Overlay valign',
|
|
31
|
+
type: ControlType.SELECT,
|
|
32
|
+
options: [
|
|
33
|
+
{ label: 'Fill (the default)', value: 'fill' },
|
|
34
|
+
{ label: 'Start', value: 'start' },
|
|
35
|
+
{ label: 'Center', value: 'center' },
|
|
36
|
+
{ label: 'End', value: 'end' },
|
|
37
|
+
],
|
|
38
|
+
defaultValue: 'end',
|
|
39
|
+
},
|
|
40
|
+
{ name: 'showLabel', label: 'Label the overlay', type: ControlType.BOOLEAN, defaultValue: true },
|
|
41
|
+
],
|
|
42
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Gtk.Overlay — a card with a badge pinned to its bottom end corner.
|
|
2
|
+
// original implementation.
|
|
3
|
+
|
|
4
|
+
import Gtk from 'gi://Gtk?version=4.0';
|
|
5
|
+
import GObject from 'gi://GObject?version=2.0';
|
|
6
|
+
import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
|
|
7
|
+
import { overlayMeta } from './overlay.meta.js';
|
|
8
|
+
|
|
9
|
+
/** `Gtk.Align` for a story arg — `fill` is the DEFAULT and has no `Gtk.Align` member. */
|
|
10
|
+
const ALIGNMENTS: Record<string, Gtk.Align> = {
|
|
11
|
+
start: Gtk.Align.START,
|
|
12
|
+
center: Gtk.Align.CENTER,
|
|
13
|
+
end: Gtk.Align.END,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/** Story: a Gtk.Overlay whose main child is a frame, with a badge over one of its corners. */
|
|
17
|
+
export class OverlayStory extends StoryWidget {
|
|
18
|
+
private _overlay: Gtk.Overlay | null = null;
|
|
19
|
+
private _main: Gtk.Frame | null = null;
|
|
20
|
+
private _badge: Gtk.Box | null = null;
|
|
21
|
+
|
|
22
|
+
static {
|
|
23
|
+
GObject.registerClass({ GTypeName: 'AdwStorybookOverlay' }, OverlayStory);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
constructor() {
|
|
27
|
+
super(StoryWidget.fromMeta(OverlayStory.getMetadata(), 'Default'));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static getMetadata(): StoryMeta {
|
|
31
|
+
return { ...overlayMeta, component: Gtk.Overlay.$gtype };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
initialize(): void {
|
|
35
|
+
this._main = new Gtk.Frame({ width_request: 260, height_request: 160, margin_top: 12, margin_bottom: 12 });
|
|
36
|
+
const mainText = new Gtk.Label({ label: 'Main child — its size is the overlay' });
|
|
37
|
+
mainText.add_css_class('dim-label');
|
|
38
|
+
this._main.set_child(mainText);
|
|
39
|
+
|
|
40
|
+
this._badge = new Gtk.Box({ valign: Gtk.Align.END, halign: Gtk.Align.END });
|
|
41
|
+
this._badge.set_css_classes(['osd', 'flat']);
|
|
42
|
+
this._badge.append(new Gtk.Label({ label: '2' }));
|
|
43
|
+
|
|
44
|
+
this._overlay = new Gtk.Overlay();
|
|
45
|
+
this._overlay.set_child(this._main);
|
|
46
|
+
this._overlay.add_overlay(this._badge);
|
|
47
|
+
this._apply();
|
|
48
|
+
this.addContent(this._overlay);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
updateArgs(_args: StoryArgs): void {
|
|
52
|
+
this._apply();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private _apply(): void {
|
|
56
|
+
if (!this._badge) return;
|
|
57
|
+
// `fill` is `GtkWidget`'s DEFAULT alignment and has no `Gtk.Align` member, so it is
|
|
58
|
+
// spelled as an absent property — the same choice the web element reads as "no
|
|
59
|
+
// halign attribute".
|
|
60
|
+
const halign = ALIGNMENTS[String(this.args.halign)];
|
|
61
|
+
const valign = ALIGNMENTS[String(this.args.valign)];
|
|
62
|
+
if (halign === undefined) this._badge.halign = Gtk.Align.FILL;
|
|
63
|
+
else this._badge.halign = halign;
|
|
64
|
+
if (valign === undefined) this._badge.valign = Gtk.Align.FILL;
|
|
65
|
+
else this._badge.valign = valign;
|
|
66
|
+
this._badge.visible = this.args.showLabel as boolean;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
GObject.type_ensure(OverlayStory.$gtype);
|
|
71
|
+
|
|
72
|
+
export const OverlayStories: StoryModule = { stories: [OverlayStory] };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Shared, renderer-agnostic metadata for the Paned story. Imported by the GTK renderer
|
|
2
|
+
// (paned.story.ts) and the browser renderer (browser/layout/paned.web.ts), so both expose
|
|
3
|
+
// identical controls.
|
|
4
|
+
|
|
5
|
+
import { ControlType, type StoryMeta } from '@gjsify/stories';
|
|
6
|
+
|
|
7
|
+
export const panedMeta: StoryMeta = {
|
|
8
|
+
title: 'Layout/Paned',
|
|
9
|
+
description:
|
|
10
|
+
'Gtk.Paned — two children either side of a divider the user drags. With both children ' +
|
|
11
|
+
'resizable and no position set, GTK divides the paned in PROPORTION TO THE TWO SIZE ' +
|
|
12
|
+
'REQUESTS rather than in half, and it draws the divider as the `separator` node a ' +
|
|
13
|
+
'GtkPanedHandle carries. Libadwaita styles that node in _paned.scss: 1px, 5px when ' +
|
|
14
|
+
'`wide-handle`, with the rule as an inset shadow rather than a fill.',
|
|
15
|
+
controls: [
|
|
16
|
+
{
|
|
17
|
+
name: 'orientation',
|
|
18
|
+
label: 'Orientation',
|
|
19
|
+
type: ControlType.SELECT,
|
|
20
|
+
options: [
|
|
21
|
+
{ label: 'Horizontal', value: 'horizontal' },
|
|
22
|
+
{ label: 'Vertical', value: 'vertical' },
|
|
23
|
+
],
|
|
24
|
+
defaultValue: 'horizontal',
|
|
25
|
+
},
|
|
26
|
+
{ name: 'wideHandle', label: 'Wide handle', type: ControlType.BOOLEAN, defaultValue: false },
|
|
27
|
+
{ name: 'resizeStartChild', label: 'Resize the first child', type: ControlType.BOOLEAN, defaultValue: true },
|
|
28
|
+
{ name: 'resizeEndChild', label: 'Resize the second child', type: ControlType.BOOLEAN, defaultValue: true },
|
|
29
|
+
{
|
|
30
|
+
name: 'shrinkStartChild',
|
|
31
|
+
label: 'The first child may shrink',
|
|
32
|
+
type: ControlType.BOOLEAN,
|
|
33
|
+
defaultValue: true,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'position',
|
|
37
|
+
label: 'Position (0 = derive)',
|
|
38
|
+
type: ControlType.NUMBER,
|
|
39
|
+
min: -1,
|
|
40
|
+
max: 400,
|
|
41
|
+
step: 1,
|
|
42
|
+
defaultValue: -1,
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Gtk.Paned — a draggable divider between two boxes.
|
|
2
|
+
// original implementation.
|
|
3
|
+
|
|
4
|
+
import Gtk from 'gi://Gtk?version=4.0';
|
|
5
|
+
import GObject from 'gi://GObject?version=2.0';
|
|
6
|
+
import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
|
|
7
|
+
import { panedMeta } from './paned.meta.js';
|
|
8
|
+
|
|
9
|
+
function pane(label: string, request: number): Gtk.Box {
|
|
10
|
+
const box = new Gtk.Box({
|
|
11
|
+
orientation: Gtk.Orientation.VERTICAL,
|
|
12
|
+
spacing: 4,
|
|
13
|
+
margin_top: 12,
|
|
14
|
+
margin_bottom: 12,
|
|
15
|
+
margin_start: 12,
|
|
16
|
+
margin_end: 12,
|
|
17
|
+
});
|
|
18
|
+
box.append(new Gtk.Label({ label }));
|
|
19
|
+
const hint = new Gtk.Label({ label: `${request}px of size request` });
|
|
20
|
+
hint.add_css_class('dim-label');
|
|
21
|
+
box.append(hint);
|
|
22
|
+
return box;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Story: a Gtk.Paned whose panes have visibly different requests, so the split is legible. */
|
|
26
|
+
export class PanedStory extends StoryWidget {
|
|
27
|
+
private _paned: Gtk.Paned | null = null;
|
|
28
|
+
|
|
29
|
+
static {
|
|
30
|
+
GObject.registerClass({ GTypeName: 'AdwStorybookPaned' }, PanedStory);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
constructor() {
|
|
34
|
+
super(StoryWidget.fromMeta(PanedStory.getMetadata(), 'Default'));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static getMetadata(): StoryMeta {
|
|
38
|
+
return { ...panedMeta, component: Gtk.Paned.$gtype };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
initialize(): void {
|
|
42
|
+
this._paned = new Gtk.Paned({ orientation: Gtk.Orientation.HORIZONTAL });
|
|
43
|
+
this._paned.set_start_child(pane('First child', 100));
|
|
44
|
+
this._paned.set_end_child(pane('Second child', 300));
|
|
45
|
+
this._paned.set_size_request(400, 140);
|
|
46
|
+
this._apply();
|
|
47
|
+
this.addContent(this._paned);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
updateArgs(_args: StoryArgs): void {
|
|
51
|
+
this._apply();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private _apply(): void {
|
|
55
|
+
if (!this._paned) return;
|
|
56
|
+
this._paned.orientation =
|
|
57
|
+
this.args.orientation === 'vertical' ? Gtk.Orientation.VERTICAL : Gtk.Orientation.HORIZONTAL;
|
|
58
|
+
this._paned.wide_handle = this.args.wideHandle as boolean;
|
|
59
|
+
this._paned.resize_start_child = this.args.resizeStartChild as boolean;
|
|
60
|
+
this._paned.resize_end_child = this.args.resizeEndChild as boolean;
|
|
61
|
+
this._paned.shrink_start_child = this.args.shrinkStartChild as boolean;
|
|
62
|
+
// `set_position (-1)` is the C's own "let the size requests decide" (gtkpaned.c:1874),
|
|
63
|
+
// which is why the control's floor is -1 rather than 0.
|
|
64
|
+
this._paned.position = Number(this.args.position);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
GObject.type_ensure(PanedStory.$gtype);
|
|
69
|
+
|
|
70
|
+
export const PanedStories: StoryModule = { stories: [PanedStory] };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Shared, renderer-agnostic metadata for the Popover Bin story. Imported by the GTK renderer
|
|
2
|
+
// (popover-bin.story.ts) and the browser renderer (browser/layout/popover-bin.web.ts), so
|
|
3
|
+
// both expose identical controls.
|
|
4
|
+
|
|
5
|
+
import { ControlType, type StoryMeta } from '@gjsify/stories';
|
|
6
|
+
|
|
7
|
+
/** The menu a bin builds its popover from — the portable model of ADR 0042. */
|
|
8
|
+
export const POPOVER_BIN_ITEMS = [
|
|
9
|
+
{ label: 'Cut' },
|
|
10
|
+
{ label: 'Copy' },
|
|
11
|
+
{ label: 'Paste' },
|
|
12
|
+
{ label: 'Delete', accel: '<Shift>Delete' },
|
|
13
|
+
] as const;
|
|
14
|
+
|
|
15
|
+
export const popoverBinMeta: StoryMeta = {
|
|
16
|
+
title: 'Layout/Popover Bin',
|
|
17
|
+
description:
|
|
18
|
+
'Gtk.PopoverBin — GTK 4.22’s one-child container with a popover, for the place where "any ' +
|
|
19
|
+
'part of this window can offer a menu" is the answer. `menu-model` builds the popover for ' +
|
|
20
|
+
'you, and `handle-input` is what turns a right click or a long press into a popup — a ' +
|
|
21
|
+
'plain click still reaches the child.',
|
|
22
|
+
// ONE control, because one is all `GtkPopoverBin` has to switch: whether the container
|
|
23
|
+
// claims a gesture. A "which child" control would be inert on both renderings — a bin
|
|
24
|
+
// holds exactly one child and both stories build the same one — and
|
|
25
|
+
// `check-storybook-control-parity.mjs` fails a control that moves and does nothing.
|
|
26
|
+
controls: [
|
|
27
|
+
{ name: 'handleInput', label: 'Right click / long press opens', type: ControlType.BOOLEAN, defaultValue: true },
|
|
28
|
+
],
|
|
29
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Gtk.PopoverBin — one child, and a popover to present from it.
|
|
2
|
+
// original implementation.
|
|
3
|
+
|
|
4
|
+
import Gio from 'gi://Gio?version=2.0';
|
|
5
|
+
import Gtk from 'gi://Gtk?version=4.0';
|
|
6
|
+
import GObject from 'gi://GObject?version=2.0';
|
|
7
|
+
import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
|
|
8
|
+
import { POPOVER_BIN_ITEMS, popoverBinMeta } from './popover-bin.meta.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Story: a Gtk.PopoverBin wrapping a list row, with `handle-input` on so a right click (or a
|
|
12
|
+
* long press on a touchscreen) opens the menu, and a plain click selects the row as usual.
|
|
13
|
+
*
|
|
14
|
+
* The bin's own `menu.popup` action (gtkpopoverbin.c:381) is what the browser rendering
|
|
15
|
+
* exposes as a `popup()` method and a `menu.popup` event, so both reach the same surface a
|
|
16
|
+
* gesture reaches.
|
|
17
|
+
*/
|
|
18
|
+
export class PopoverBinStory extends StoryWidget {
|
|
19
|
+
private _bin: Gtk.PopoverBin | null = null;
|
|
20
|
+
private _list: Gtk.ListBox | null = null;
|
|
21
|
+
|
|
22
|
+
static {
|
|
23
|
+
GObject.registerClass({ GTypeName: 'AdwStorybookPopoverBin' }, PopoverBinStory);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
constructor() {
|
|
27
|
+
super(StoryWidget.fromMeta(PopoverBinStory.getMetadata(), 'Default'));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static getMetadata(): StoryMeta {
|
|
31
|
+
return { ...popoverBinMeta, component: Gtk.PopoverBin.$gtype };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
initialize(): void {
|
|
35
|
+
this._list = new Gtk.ListBox({ selectionMode: Gtk.SelectionMode.SINGLE });
|
|
36
|
+
for (const label of ['Documents', 'Downloads', 'Pictures']) {
|
|
37
|
+
this._list.append(new Gtk.ListBoxRow({ child: new Gtk.Label({ label }) }));
|
|
38
|
+
}
|
|
39
|
+
this._bin = new Gtk.PopoverBin({ child: this._list });
|
|
40
|
+
this._apply();
|
|
41
|
+
this.addContent(this._bin);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
updateArgs(_args: StoryArgs): void {
|
|
45
|
+
this._apply();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private _buildMenu(): Gio.Menu {
|
|
49
|
+
const menu = new Gio.Menu();
|
|
50
|
+
for (const item of POPOVER_BIN_ITEMS)
|
|
51
|
+
menu.append(item.label, `app.${item.label.toLowerCase().replace(/[^a-z0-9]+/g, '-')}`);
|
|
52
|
+
return menu;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private _apply(): void {
|
|
56
|
+
if (!this._bin) return;
|
|
57
|
+
// `gtk_popover_bin_set_menu_model` builds the popover from the model and pins it to
|
|
58
|
+
// GTK_POS_BOTTOM (gtkpopoverbin.c:474-500) — there is nothing to position by hand.
|
|
59
|
+
this._bin.menuModel = this._buildMenu();
|
|
60
|
+
this._bin.handleInput = this.args.handleInput as boolean;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
GObject.type_ensure(PopoverBinStory.$gtype);
|
|
65
|
+
|
|
66
|
+
export const PopoverBinStories: StoryModule = { stories: [PopoverBinStory] };
|