@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.
Files changed (243) hide show
  1. package/dist/browser-main.js +8093 -3042
  2. package/dist/gjs.js +15 -10
  3. package/dist/gjs.node.mjs +10 -5
  4. package/package.json +5 -5
  5. package/src/browser/buttons/color-dialog-button.web.ts +42 -0
  6. package/src/browser/buttons/font-dialog-button.web.ts +42 -0
  7. package/src/browser/buttons/link-button.web.ts +37 -0
  8. package/src/browser/buttons/scale-button.web.ts +36 -0
  9. package/src/browser/buttons/toggle-button.web.ts +35 -0
  10. package/src/browser/controls/check-button.web.ts +38 -0
  11. package/src/browser/controls/gtk-spinner.web.ts +39 -0
  12. package/src/browser/controls/level-bar.web.ts +43 -0
  13. package/src/browser/controls/password-entry.web.ts +36 -0
  14. package/src/browser/controls/progress-bar.web.ts +39 -0
  15. package/src/browser/controls/scale.web.ts +44 -0
  16. package/src/browser/controls/search-entry.web.ts +49 -0
  17. package/src/browser/controls/spin-button.web.ts +40 -0
  18. package/src/browser/controls/switch.web.ts +38 -0
  19. package/src/browser/drawing/drag-icon.web.ts +112 -0
  20. package/src/browser/drawing/drawing-area.web.ts +66 -0
  21. package/src/browser/drawing/gl-area.web.ts +162 -0
  22. package/src/browser/drawing/graphics-offload.web.ts +74 -0
  23. package/src/browser/feedback/dialog.web.ts +76 -0
  24. package/src/browser/feedback/emoji-chooser.web.ts +93 -0
  25. package/src/browser/feedback/gtk-about-dialog.web.ts +105 -0
  26. package/src/browser/feedback/page-setup-unix-dialog.web.ts +93 -0
  27. package/src/browser/feedback/print-unix-dialog.web.ts +111 -0
  28. package/src/browser/feedback/shortcuts-dialog.web.ts +90 -0
  29. package/src/browser/layout/application-window.web.ts +94 -0
  30. package/src/browser/layout/aspect-frame.web.ts +49 -0
  31. package/src/browser/layout/bin.web.ts +41 -0
  32. package/src/browser/layout/breakpoint-bin.web.ts +61 -0
  33. package/src/browser/layout/center-box.web.ts +45 -0
  34. package/src/browser/layout/clamp-scrollable.web.ts +47 -0
  35. package/src/browser/layout/expander.web.ts +52 -0
  36. package/src/browser/layout/fixed.web.ts +51 -0
  37. package/src/browser/layout/frame.web.ts +40 -0
  38. package/src/browser/layout/grid.web.ts +46 -0
  39. package/src/browser/layout/layout-slot.web.ts +60 -0
  40. package/src/browser/layout/multi-layout-view.web.ts +94 -0
  41. package/src/browser/layout/overlay.web.ts +57 -0
  42. package/src/browser/layout/paned.web.ts +69 -0
  43. package/src/browser/layout/popover-bin.web.ts +54 -0
  44. package/src/browser/layout/popover-menu.web.ts +48 -0
  45. package/src/browser/layout/popover.web.ts +61 -0
  46. package/src/browser/layout/revealer.web.ts +53 -0
  47. package/src/browser/layout/scrollbar.web.ts +54 -0
  48. package/src/browser/layout/scrolled-window.web.ts +52 -0
  49. package/src/browser/layout/separator.web.ts +47 -0
  50. package/src/browser/layout/viewport.web.ts +51 -0
  51. package/src/browser/layout/window.web.ts +60 -0
  52. package/src/browser/media/image.web.ts +39 -0
  53. package/src/browser/media/inscription.web.ts +52 -0
  54. package/src/browser/media/media-controls.web.ts +65 -0
  55. package/src/browser/media/picture.web.ts +56 -0
  56. package/src/browser/media/video.web.ts +56 -0
  57. package/src/browser/navigation/popover-menu-bar.web.ts +40 -0
  58. package/src/browser/presentation/calendar.web.ts +49 -0
  59. package/src/browser/presentation/column-view.web.ts +45 -0
  60. package/src/browser/presentation/flow-box.web.ts +52 -0
  61. package/src/browser/presentation/grid-view.web.ts +37 -0
  62. package/src/browser/presentation/list-box.web.ts +48 -0
  63. package/src/browser/presentation/list-view.web.ts +36 -0
  64. package/src/browser/presentation/tree-expander.web.ts +68 -0
  65. package/src/browser/presentation/window-handle.web.ts +42 -0
  66. package/src/browser/rows/preferences-row.web.ts +43 -0
  67. package/src/browser/stories.ts +158 -0
  68. package/src/browser/text/editable-label.web.ts +45 -0
  69. package/src/browser/text/search-bar.web.ts +45 -0
  70. package/src/browser/text/text-view.web.ts +54 -0
  71. package/src/browser/text/text.web.ts +48 -0
  72. package/src/browser/view-switching/notebook.web.ts +67 -0
  73. package/src/browser/view-switching/stack-sidebar.web.ts +68 -0
  74. package/src/browser/view-switching/stack-switcher.web.ts +70 -0
  75. package/src/browser/view-switching/stack.web.ts +72 -0
  76. package/src/browser/view-switching/tab-bar.web.ts +105 -0
  77. package/src/browser/view-switching/tab-button.web.ts +52 -0
  78. package/src/browser/view-switching/tab-overview.web.ts +87 -0
  79. package/src/browser/view-switching/view-switcher-sidebar.web.ts +77 -0
  80. package/src/browser/windows/action-bar.web.ts +66 -0
  81. package/src/browser/windows/gtk-application-window.web.ts +67 -0
  82. package/src/browser/windows/gtk-header-bar.web.ts +61 -0
  83. package/src/browser/windows/gtk-window.web.ts +58 -0
  84. package/src/browser/windows/window-controls.web.ts +54 -0
  85. package/src/buttons/color-dialog-button.meta.ts +16 -0
  86. package/src/buttons/color-dialog-button.story.ts +49 -0
  87. package/src/buttons/font-dialog-button.meta.ts +29 -0
  88. package/src/buttons/font-dialog-button.story.ts +52 -0
  89. package/src/buttons/link-button.meta.ts +18 -0
  90. package/src/buttons/link-button.story.ts +48 -0
  91. package/src/buttons/scale-button.meta.ts +34 -0
  92. package/src/buttons/scale-button.story.ts +50 -0
  93. package/src/buttons/toggle-button.meta.ts +17 -0
  94. package/src/buttons/toggle-button.story.ts +46 -0
  95. package/src/controls/check-button.meta.ts +19 -0
  96. package/src/controls/check-button.story.ts +56 -0
  97. package/src/controls/gtk-spinner.meta.ts +24 -0
  98. package/src/controls/gtk-spinner.story.ts +53 -0
  99. package/src/controls/level-bar.meta.ts +39 -0
  100. package/src/controls/level-bar.story.ts +58 -0
  101. package/src/controls/password-entry.meta.ts +18 -0
  102. package/src/controls/password-entry.story.ts +54 -0
  103. package/src/controls/progress-bar.meta.ts +20 -0
  104. package/src/controls/progress-bar.story.ts +53 -0
  105. package/src/controls/scale.meta.ts +47 -0
  106. package/src/controls/scale.story.ts +66 -0
  107. package/src/controls/search-entry.meta.ts +18 -0
  108. package/src/controls/search-entry.story.ts +57 -0
  109. package/src/controls/spin-button.meta.ts +40 -0
  110. package/src/controls/spin-button.story.ts +55 -0
  111. package/src/controls/switch.meta.ts +18 -0
  112. package/src/controls/switch.story.ts +50 -0
  113. package/src/drawing/drag-icon.meta.ts +39 -0
  114. package/src/drawing/drag-icon.story.ts +117 -0
  115. package/src/drawing/drawing-area.meta.ts +45 -0
  116. package/src/drawing/drawing-area.story.ts +78 -0
  117. package/src/drawing/gl-area.meta.ts +30 -0
  118. package/src/drawing/gl-area.story.ts +113 -0
  119. package/src/drawing/graphics-offload.meta.ts +39 -0
  120. package/src/drawing/graphics-offload.story.ts +73 -0
  121. package/src/feedback/dialog.meta.ts +25 -0
  122. package/src/feedback/dialog.story.ts +78 -0
  123. package/src/feedback/emoji-chooser.meta.ts +10 -0
  124. package/src/feedback/emoji-chooser.story.ts +98 -0
  125. package/src/feedback/gtk-about-dialog.meta.ts +29 -0
  126. package/src/feedback/gtk-about-dialog.story.ts +90 -0
  127. package/src/feedback/page-setup-unix-dialog.meta.ts +37 -0
  128. package/src/feedback/page-setup-unix-dialog.story.ts +70 -0
  129. package/src/feedback/print-unix-dialog.meta.ts +30 -0
  130. package/src/feedback/print-unix-dialog.story.ts +93 -0
  131. package/src/feedback/shortcuts-dialog.meta.ts +12 -0
  132. package/src/feedback/shortcuts-dialog.story.ts +79 -0
  133. package/src/layout/application-window.meta.ts +16 -0
  134. package/src/layout/application-window.story.ts +97 -0
  135. package/src/layout/aspect-frame.meta.ts +19 -0
  136. package/src/layout/aspect-frame.story.ts +62 -0
  137. package/src/layout/bin.meta.ts +15 -0
  138. package/src/layout/bin.story.ts +56 -0
  139. package/src/layout/breakpoint-bin.meta.ts +38 -0
  140. package/src/layout/breakpoint-bin.story.ts +62 -0
  141. package/src/layout/center-box.meta.ts +26 -0
  142. package/src/layout/center-box.story.ts +54 -0
  143. package/src/layout/clamp-scrollable.meta.ts +30 -0
  144. package/src/layout/clamp-scrollable.story.ts +51 -0
  145. package/src/layout/expander.meta.ts +30 -0
  146. package/src/layout/expander.story.ts +62 -0
  147. package/src/layout/fixed.meta.ts +16 -0
  148. package/src/layout/fixed.story.ts +54 -0
  149. package/src/layout/frame.meta.ts +24 -0
  150. package/src/layout/frame.story.ts +51 -0
  151. package/src/layout/grid.meta.ts +45 -0
  152. package/src/layout/grid.story.ts +80 -0
  153. package/src/layout/layout-slot.meta.ts +22 -0
  154. package/src/layout/layout-slot.story.ts +68 -0
  155. package/src/layout/multi-layout-view.meta.ts +31 -0
  156. package/src/layout/multi-layout-view.story.ts +101 -0
  157. package/src/layout/overlay.meta.ts +42 -0
  158. package/src/layout/overlay.story.ts +72 -0
  159. package/src/layout/paned.meta.ts +45 -0
  160. package/src/layout/paned.story.ts +70 -0
  161. package/src/layout/popover-bin.meta.ts +29 -0
  162. package/src/layout/popover-bin.story.ts +66 -0
  163. package/src/layout/popover-menu.meta.ts +54 -0
  164. package/src/layout/popover-menu.story.ts +119 -0
  165. package/src/layout/popover.meta.ts +38 -0
  166. package/src/layout/popover.story.ts +66 -0
  167. package/src/layout/revealer.meta.ts +44 -0
  168. package/src/layout/revealer.story.ts +79 -0
  169. package/src/layout/scrollbar.meta.ts +33 -0
  170. package/src/layout/scrollbar.story.ts +61 -0
  171. package/src/layout/scrolled-window.meta.ts +57 -0
  172. package/src/layout/scrolled-window.story.ts +74 -0
  173. package/src/layout/separator.meta.ts +25 -0
  174. package/src/layout/separator.story.ts +53 -0
  175. package/src/layout/viewport.meta.ts +19 -0
  176. package/src/layout/viewport.story.ts +53 -0
  177. package/src/layout/window.meta.ts +13 -0
  178. package/src/layout/window.story.ts +66 -0
  179. package/src/media/image.meta.ts +24 -0
  180. package/src/media/image.story.ts +48 -0
  181. package/src/media/inscription.meta.ts +45 -0
  182. package/src/media/inscription.story.ts +64 -0
  183. package/src/media/media-controls.meta.ts +30 -0
  184. package/src/media/media-controls.story.ts +58 -0
  185. package/src/media/picture.meta.ts +42 -0
  186. package/src/media/picture.story.ts +81 -0
  187. package/src/media/video.meta.ts +32 -0
  188. package/src/media/video.story.ts +57 -0
  189. package/src/metas.ts +79 -0
  190. package/src/navigation/popover-menu-bar.meta.ts +51 -0
  191. package/src/navigation/popover-menu-bar.story.ts +72 -0
  192. package/src/presentation/calendar.meta.ts +28 -0
  193. package/src/presentation/calendar.story.ts +64 -0
  194. package/src/presentation/column-view.meta.ts +30 -0
  195. package/src/presentation/column-view.story.ts +73 -0
  196. package/src/presentation/flow-box.meta.ts +51 -0
  197. package/src/presentation/flow-box.story.ts +72 -0
  198. package/src/presentation/grid-view.meta.ts +28 -0
  199. package/src/presentation/grid-view.story.ts +64 -0
  200. package/src/presentation/list-box.meta.ts +55 -0
  201. package/src/presentation/list-box.story.ts +68 -0
  202. package/src/presentation/list-view.meta.ts +38 -0
  203. package/src/presentation/list-view.story.ts +73 -0
  204. package/src/presentation/tree-expander.meta.ts +24 -0
  205. package/src/presentation/tree-expander.story.ts +105 -0
  206. package/src/presentation/window-handle.meta.ts +27 -0
  207. package/src/presentation/window-handle.story.ts +53 -0
  208. package/src/rows/preferences-row.meta.ts +15 -0
  209. package/src/rows/preferences-row.story.ts +50 -0
  210. package/src/text/editable-label.meta.ts +17 -0
  211. package/src/text/editable-label.story.ts +47 -0
  212. package/src/text/search-bar.meta.ts +17 -0
  213. package/src/text/search-bar.story.ts +48 -0
  214. package/src/text/text-view.meta.ts +49 -0
  215. package/src/text/text-view.story.ts +69 -0
  216. package/src/text/text.meta.ts +21 -0
  217. package/src/text/text.story.ts +50 -0
  218. package/src/view-switching/notebook.meta.ts +44 -0
  219. package/src/view-switching/notebook.story.ts +77 -0
  220. package/src/view-switching/stack-sidebar.meta.ts +50 -0
  221. package/src/view-switching/stack-sidebar.story.ts +85 -0
  222. package/src/view-switching/stack-switcher.meta.ts +53 -0
  223. package/src/view-switching/stack-switcher.story.ts +95 -0
  224. package/src/view-switching/stack.meta.ts +53 -0
  225. package/src/view-switching/stack.story.ts +95 -0
  226. package/src/view-switching/tab-bar.meta.ts +22 -0
  227. package/src/view-switching/tab-bar.story.ts +85 -0
  228. package/src/view-switching/tab-button.meta.ts +14 -0
  229. package/src/view-switching/tab-button.story.ts +52 -0
  230. package/src/view-switching/tab-overview.meta.ts +21 -0
  231. package/src/view-switching/tab-overview.story.ts +86 -0
  232. package/src/view-switching/view-switcher-sidebar.meta.ts +42 -0
  233. package/src/view-switching/view-switcher-sidebar.story.ts +73 -0
  234. package/src/windows/action-bar.meta.ts +27 -0
  235. package/src/windows/action-bar.story.ts +65 -0
  236. package/src/windows/gtk-application-window.meta.ts +27 -0
  237. package/src/windows/gtk-application-window.story.ts +89 -0
  238. package/src/windows/gtk-header-bar.meta.ts +39 -0
  239. package/src/windows/gtk-header-bar.story.ts +76 -0
  240. package/src/windows/gtk-window.meta.ts +30 -0
  241. package/src/windows/gtk-window.story.ts +64 -0
  242. package/src/windows/window-controls.meta.ts +42 -0
  243. package/src/windows/window-controls.story.ts +61 -0
@@ -0,0 +1,117 @@
1
+ // Gtk.DragIcon — the widget that follows the pointer, reached the only way it can be
2
+ // reached: a drag source. Drag the row; the icon that comes with the drag is this widget,
3
+ // and GTK destroys it when the drag ends. original implementation.
4
+
5
+ import Gtk from 'gi://Gtk?version=4.0';
6
+ import Gdk from 'gi://Gdk?version=4.0';
7
+ import GObject from 'gi://GObject?version=2.0';
8
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
9
+ import { dragIconMeta } from './drag-icon.meta.js';
10
+
11
+ /** The value the drag offers, as both renderers offer it: a string, a colour, or nothing. */
12
+ type DragValue = string | { red: number; green: number; blue: number; alpha: number } | null;
13
+
14
+ /** Story: a draggable row whose drag icon is a `GtkDragIcon`, with the value bound to args. */
15
+ export class DragIconStory extends StoryWidget {
16
+ private _row: Gtk.Box | null = null;
17
+ private _source: Gtk.DragSource | null = null;
18
+ private _hint: Gtk.Label | null = null;
19
+
20
+ static {
21
+ GObject.registerClass({ GTypeName: 'AdwStorybookDragIcon' }, DragIconStory);
22
+ }
23
+
24
+ constructor() {
25
+ super(StoryWidget.fromMeta(DragIconStory.getMetadata(), 'Default'));
26
+ }
27
+
28
+ static getMetadata(): StoryMeta {
29
+ return { ...dragIconMeta, component: Gtk.DragIcon.$gtype };
30
+ }
31
+
32
+ initialize(): void {
33
+ const box = new Gtk.Box({
34
+ orientation: Gtk.Orientation.VERTICAL,
35
+ spacing: 12,
36
+ halign: Gtk.Align.CENTER,
37
+ valign: Gtk.Align.CENTER,
38
+ });
39
+ this._hint = new Gtk.Label({ label: 'Drag the row and watch the pointer' });
40
+ this._hint.add_css_class('dim-label');
41
+
42
+ this._row = new Gtk.Box({
43
+ orientation: Gtk.Orientation.HORIZONTAL,
44
+ spacing: 12,
45
+ cssClasses: ['card'],
46
+ });
47
+ this._row.append(this._buildLabel());
48
+
49
+ // `GtkDragSource` is an EVENT CONTROLLER, not a widget: the doc's own snippet
50
+ // creates one, connects `prepare` and `drag-begin`, and hands it to
51
+ // `gtk_widget_add_controller` (gtkdragsource.c:44-58).
52
+ this._source = Gtk.DragSource.new();
53
+ this._source.actions = (this.args.actions as string) === 'move' ? Gdk.DragAction.MOVE : Gdk.DragAction.COPY;
54
+ this._source.connect('prepare', () => this._contentProvider());
55
+ this._source.connect('drag-begin', (_source: Gtk.DragSource, drag: Gdk.Drag) => this._setIcon(drag));
56
+ this._row.add_controller(this._source);
57
+
58
+ this._apply();
59
+ box.append(this._hint);
60
+ box.append(this._row);
61
+ this.addContent(box);
62
+ }
63
+
64
+ updateArgs(_args: StoryArgs): void {
65
+ if (this._source === null) return;
66
+ this._source.actions = (this.args.actions as string) === 'move' ? Gdk.DragAction.MOVE : Gdk.DragAction.COPY;
67
+ this._apply();
68
+ }
69
+
70
+ /** What the drag offers, which is also what decides the icon — the two are one thing. */
71
+ private _value(): DragValue {
72
+ switch (this.args.value) {
73
+ case 'rgba':
74
+ return { red: 0.25, green: 0.55, blue: 0.95, alpha: 1 };
75
+ case 'none':
76
+ return null;
77
+ default:
78
+ return 'Report.odt';
79
+ }
80
+ }
81
+
82
+ /** `::prepare` answers the content provider, set just in time rather than ahead. */
83
+ private _contentProvider(): Gdk.ContentProvider | null {
84
+ const value = this._value();
85
+ return value === null ? null : Gdk.ContentProvider.new_for_value(value);
86
+ }
87
+
88
+ /**
89
+ * `::drag-begin` is where an icon of your own is set: `gtk_drag_icon_get_for_drag`
90
+ * (gtkdragicon.c:400-421) is the ONLY way to reach one, and
91
+ * `gtk_drag_icon_create_widget_for_value` (:529-556) is what decides what a value shows.
92
+ */
93
+ private _setIcon(drag: Gdk.Drag): void {
94
+ const value = this._value();
95
+ const icon = Gtk.DragIcon.get_for_drag(drag);
96
+ const child = value === null ? null : Gtk.DragIcon.create_widget_for_value(value);
97
+ // `set_child` unparents the old child and shows the icon (:468-489), so this is
98
+ // also how an icon that had none starts showing.
99
+ icon.set_child(child);
100
+ }
101
+
102
+ private _buildLabel(): Gtk.Label {
103
+ return new Gtk.Label({ label: 'Report.odt', cssClasses: ['heading'] });
104
+ }
105
+
106
+ private _apply(): void {
107
+ if (this._hint === null) return;
108
+ this._hint.label =
109
+ this.args.value === 'none'
110
+ ? 'Drag the row — no icon, because the value has no widget to show'
111
+ : 'Drag the row and watch the pointer';
112
+ }
113
+ }
114
+
115
+ GObject.type_ensure(DragIconStory.$gtype);
116
+
117
+ export const DragIconStories: StoryModule = { stories: [DragIconStory] };
@@ -0,0 +1,45 @@
1
+ // Shared, renderer-agnostic metadata for the Drawing Area story. Imported by the GTK
2
+ // renderer (drawing-area.story.ts) and the browser renderer
3
+ // (browser/drawing/drawing-area.web.ts), so both expose identical controls.
4
+
5
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
6
+
7
+ export const drawingAreaMeta: StoryMeta = {
8
+ title: 'Drawing/Drawing Area',
9
+ description:
10
+ 'Gtk.DrawingArea — a blank widget that owns a size and a callback and nothing else: whatever you ' +
11
+ 'see is what `set_draw_func` painted. `content-width` and `content-height` are the MINIMUM and ' +
12
+ 'natural size at once, so a parent can hand the area more room but never less; at 0 the area has ' +
13
+ 'no intrinsic size at all and fills whatever it is given.',
14
+ controls: [
15
+ {
16
+ name: 'contentWidth',
17
+ label: 'Content width',
18
+ type: ControlType.RANGE,
19
+ min: 0,
20
+ max: 320,
21
+ step: 16,
22
+ defaultValue: 160,
23
+ },
24
+ {
25
+ name: 'contentHeight',
26
+ label: 'Content height',
27
+ type: ControlType.RANGE,
28
+ min: 0,
29
+ max: 320,
30
+ step: 16,
31
+ defaultValue: 120,
32
+ },
33
+ {
34
+ name: 'shape',
35
+ label: 'Shape',
36
+ type: ControlType.SELECT,
37
+ options: [
38
+ { label: 'Circle', value: 'circle' },
39
+ { label: 'Grid', value: 'grid' },
40
+ { label: 'Crosshair', value: 'crosshair' },
41
+ ],
42
+ defaultValue: 'circle',
43
+ },
44
+ ],
45
+ };
@@ -0,0 +1,78 @@
1
+ // Gtk.DrawingArea — a blank widget you paint on.
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 { drawingAreaMeta } from './drawing-area.meta.js';
8
+
9
+ /** Story: a Gtk.DrawingArea with a draw function and the size properties bound to args. */
10
+ export class DrawingAreaStory extends StoryWidget {
11
+ private _box: Gtk.Box | null = null;
12
+ private _area: Gtk.DrawingArea | null = null;
13
+
14
+ static {
15
+ GObject.registerClass({ GTypeName: 'AdwStorybookDrawingArea' }, DrawingAreaStory);
16
+ }
17
+
18
+ constructor() {
19
+ super(StoryWidget.fromMeta(DrawingAreaStory.getMetadata(), 'Default'));
20
+ }
21
+
22
+ static getMetadata(): StoryMeta {
23
+ return { ...drawingAreaMeta, component: Gtk.DrawingArea.$gtype };
24
+ }
25
+
26
+ initialize(): void {
27
+ this._area = new Gtk.DrawingArea();
28
+ // The area paints itself: the draw function reads the widget's colour rather than a
29
+ // hard-coded one, so the shape follows the theme in either renderer.
30
+ this._area.set_draw_func((area, cr, width, height) => {
31
+ // `get_color` is the function GTK's own documented draw_function reads
32
+ // (gtkdrawingarea.c:88-104), so the shape follows the widget's own colour.
33
+ const color = area.get_color();
34
+ cr.setSourceRGBA(color.red, color.green, color.blue, color.alpha);
35
+ cr.rectangle(0, 0, width, height);
36
+ cr.fill();
37
+ cr.setSourceRGBA(1 - color.red, 1 - color.green, 1 - color.blue, color.alpha);
38
+ switch (this.args.shape) {
39
+ case 'grid':
40
+ for (let x = 0; x < width; x += 16) {
41
+ cr.rectangle(x, 0, 8, height);
42
+ cr.fill();
43
+ }
44
+ break;
45
+ case 'crosshair':
46
+ cr.rectangle(width / 2 - 1, 0, 2, height);
47
+ cr.rectangle(0, height / 2 - 1, width, 2);
48
+ cr.fill();
49
+ break;
50
+ default:
51
+ cr.arc(width / 2, height / 2, Math.min(width, height) / 2, 0, 2 * Math.PI);
52
+ cr.fill();
53
+ break;
54
+ }
55
+ });
56
+ this._box = new Gtk.Box({ halign: Gtk.Align.CENTER, valign: Gtk.Align.CENTER });
57
+ this._box.append(this._area);
58
+ this._apply();
59
+ this.addContent(this._box);
60
+ }
61
+
62
+ updateArgs(_args: StoryArgs): void {
63
+ // A new size invalidates the picture GTK has of the area, and `queue_draw` is the
64
+ // documented way to ask for the draw function again (gtkdrawingarea.c:127-129).
65
+ this._area?.queue_draw();
66
+ this._apply();
67
+ }
68
+
69
+ private _apply(): void {
70
+ if (!this._area) return;
71
+ this._area.content_width = this.args.contentWidth as number;
72
+ this._area.content_height = this.args.contentHeight as number;
73
+ }
74
+ }
75
+
76
+ GObject.type_ensure(DrawingAreaStory.$gtype);
77
+
78
+ export const DrawingAreaStories: StoryModule = { stories: [DrawingAreaStory] };
@@ -0,0 +1,30 @@
1
+ // Shared, renderer-agnostic metadata for the GL Area story. Imported by the GTK
2
+ // renderer (gl-area.story.ts) and the browser renderer
3
+ // (browser/drawing/gl-area.web.ts), so both expose identical controls.
4
+
5
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
6
+
7
+ export const glAreaMeta: StoryMeta = {
8
+ title: 'Drawing/GL Area',
9
+ description:
10
+ 'Gtk.GLArea — a widget whose contents are drawn on a GPU. GTK emits `::resize` before the first ' +
11
+ '`::render` and the render flag is cleared AFTER the signal, so a handler may queue another frame ' +
12
+ 'with `queue_render()`. Here the replica is a `<canvas>` with a real WebGL context: the browser has ' +
13
+ 'no desktop GL, so `api` always reports the ES flavour it was given.',
14
+ controls: [
15
+ { name: 'autoRender', label: 'Auto render', type: ControlType.BOOLEAN, defaultValue: true },
16
+ { name: 'hasDepthBuffer', label: 'Depth buffer', type: ControlType.BOOLEAN, defaultValue: false },
17
+ {
18
+ name: 'allowedApis',
19
+ label: 'Allowed APIs',
20
+ type: ControlType.SELECT,
21
+ options: [
22
+ { label: 'GL and GLES (default)', value: 'gl gles' },
23
+ { label: 'GLES only', value: 'gles' },
24
+ { label: 'GL only', value: 'gl' },
25
+ ],
26
+ defaultValue: 'gl gles',
27
+ },
28
+ { name: 'spinning', label: 'Spin the triangle', type: ControlType.BOOLEAN, defaultValue: true },
29
+ ],
30
+ };
@@ -0,0 +1,113 @@
1
+ // Gtk.GLArea — the widget whose contents are drawn on a GPU.
2
+ // original implementation.
3
+
4
+ import Gtk from 'gi://Gtk?version=4.0';
5
+ import Gdk from 'gi://Gdk?version=4.0';
6
+ import GLib from 'gi://GLib?version=2.0';
7
+ import GObject from 'gi://GObject?version=2.0';
8
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
9
+ import { glAreaMeta } from './gl-area.meta.js';
10
+
11
+ /** 33 ms is about thirty frames a second, the tick GTK's own demos use. */
12
+ const TICK_MS = 33;
13
+
14
+ /**
15
+ * Story: a Gtk.GLArea whose lifecycle is the subject — `::resize` before the first
16
+ * `::render`, `queue_render()` from a tick, and the two flags bound to args.
17
+ *
18
+ * WHAT THIS STORY DOES NOT DRAW, AND WHY. Painting the triangle needs `gi://GL` calls
19
+ * (`glCreateShader`, `glDrawArrays`, …), and a GL binding is not one of this storybook's
20
+ * dependencies — every other story here is widget-shaped, and importing a binding to fill
21
+ * one would make the one GL widget the one that cannot be built. So the area renders
22
+ * nothing and the readout below it shows what the SIGNALS did: the device-pixel viewport
23
+ * from `::resize`, and how many frames `::render` produced. The browser story draws the
24
+ * same triangle for real, because a `<canvas>` has WebGL built in.
25
+ */
26
+ export class GLAreaStory extends StoryWidget {
27
+ private _area: Gtk.GLArea | null = null;
28
+ private _readout: Gtk.Label | null = null;
29
+ private _box: Gtk.Box | null = null;
30
+ private _tick = 0;
31
+ private _renders = 0;
32
+ private _viewport = '—';
33
+
34
+ static {
35
+ GObject.registerClass({ GTypeName: 'AdwStorybookGLArea' }, GLAreaStory);
36
+ }
37
+
38
+ constructor() {
39
+ super(StoryWidget.fromMeta(GLAreaStory.getMetadata(), 'Default'));
40
+ }
41
+
42
+ static getMetadata(): StoryMeta {
43
+ return { ...glAreaMeta, component: Gtk.GLArea.$gtype };
44
+ }
45
+
46
+ initialize(): void {
47
+ this._area = new Gtk.GLArea({ widthRequest: 240, heightRequest: 160 });
48
+ this._readout = new Gtk.Label({ label: '—' });
49
+ this._readout.add_css_class('dimmed');
50
+
51
+ // `::resize` comes BEFORE the first `::render` and on every later allocation: the
52
+ // order a GL program depends on to know its viewport (gtkglarea.c:797-807). The
53
+ // numbers are DEVICE pixels — `w = width * scale` (:761-763).
54
+ this._area.connect('resize', (_area, width: number, height: number) => {
55
+ this._viewport = `${width} × ${height}`;
56
+ this._refresh();
57
+ });
58
+ this._area.connect('render', () => {
59
+ this._renders += 1;
60
+ this._refresh();
61
+ });
62
+
63
+ this._box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, spacing: 6 });
64
+ this._box.append(this._area);
65
+ this._box.append(this._readout);
66
+ this._apply();
67
+ this.addContent(this._box);
68
+ }
69
+
70
+ updateArgs(_args: StoryArgs): void {
71
+ this._stop();
72
+ this._apply();
73
+ this._start();
74
+ }
75
+
76
+ private _apply(): void {
77
+ if (!this._area) return;
78
+ // `allowed_apis` REFUSES a realized area (`g_return_if_fail (!realized)`,
79
+ // gtkglarea.c:1242), so it belongs before the first render, not after it.
80
+ this._area.allowed_apis = this.args.allowedApis === 'gles' ? Gdk.GLAPI.GLES : Gdk.GLAPI.GL | Gdk.GLAPI.GLES;
81
+ this._area.auto_render = this.args.autoRender as boolean;
82
+ this._area.has_depth_buffer = this.args.hasDepthBuffer as boolean;
83
+ }
84
+
85
+ /**
86
+ * `queue_render()` is how a GL application asks for the next frame (gtkglarea.c:1465):
87
+ * the flag is set and a redraw queued, and `::render` runs on that frame. Nothing here
88
+ * redraws on its own, which is the point — `auto-render` decides whether a draw the
89
+ * element was asked for ends in `::render`, not whether frames appear.
90
+ */
91
+ private _start(): void {
92
+ if (!this._area || !this.args.spinning) return;
93
+ this._tick = GLib.timeout_add(GLib.PRIORITY_DEFAULT, TICK_MS, () => {
94
+ this._area?.queue_render();
95
+ return GLib.SOURCE_CONTINUE;
96
+ });
97
+ }
98
+
99
+ private _stop(): void {
100
+ if (this._tick === 0) return;
101
+ GLib.source_remove(this._tick);
102
+ this._tick = 0;
103
+ }
104
+
105
+ private _refresh(): void {
106
+ if (!this._readout) return;
107
+ this._readout.label = `viewport ${this._viewport} device px · ${this._renders} renders`;
108
+ }
109
+ }
110
+
111
+ GObject.type_ensure(GLAreaStory.$gtype);
112
+
113
+ export const GLAreaStories: StoryModule = { stories: [GLAreaStory] };
@@ -0,0 +1,39 @@
1
+ // Shared, renderer-agnostic metadata for the Graphics Offload story. Imported by the GTK
2
+ // renderer (graphics-offload.story.ts) and the browser renderer
3
+ // (browser/drawing/graphics-offload.web.ts), so both expose identical controls.
4
+
5
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
6
+
7
+ export const graphicsOffloadMeta: StoryMeta = {
8
+ title: 'Drawing/Graphics Offload',
9
+ description:
10
+ 'Gtk.GraphicsOffload — a wrapper that asks the compositor to take its ONE child as it is, which ' +
11
+ 'is worth doing for content that changes every frame. `enabled` says whether it is attempted, and ' +
12
+ "`black-background` paints the letterbox bars. The passthrough itself is the platform's: no browser " +
13
+ 'API hands a surface to a compositor, so the replica carries the enum, the black rectangle and the ' +
14
+ 'bin layout, and says plainly which part is missing.',
15
+ controls: [
16
+ {
17
+ name: 'enabled',
18
+ label: 'Enabled',
19
+ type: ControlType.SELECT,
20
+ options: [
21
+ { label: 'Enabled (default)', value: 'enabled' },
22
+ { label: 'Disabled', value: 'disabled' },
23
+ ],
24
+ defaultValue: 'enabled',
25
+ },
26
+ { name: 'blackBackground', label: 'Black background', type: ControlType.BOOLEAN, defaultValue: false },
27
+ {
28
+ name: 'child',
29
+ label: 'Child',
30
+ type: ControlType.SELECT,
31
+ options: [
32
+ { label: 'Label', value: 'label' },
33
+ { label: 'Image', value: 'image' },
34
+ { label: 'Row of labels', value: 'box' },
35
+ ],
36
+ defaultValue: 'image',
37
+ },
38
+ ],
39
+ };
@@ -0,0 +1,73 @@
1
+ // Gtk.GraphicsOffload — one child, handed to the compositor as it is.
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 { graphicsOffloadMeta } from './graphics-offload.meta.js';
8
+
9
+ /** Story: a Gtk.GraphicsOffload around one child, with `enabled` and the black rect bound to args. */
10
+ export class GraphicsOffloadStory extends StoryWidget {
11
+ private _offload: Gtk.GraphicsOffload | null = null;
12
+ private _box: Gtk.Box | null = null;
13
+
14
+ static {
15
+ GObject.registerClass({ GTypeName: 'AdwStorybookGraphicsOffload' }, GraphicsOffloadStory);
16
+ }
17
+
18
+ constructor() {
19
+ super(StoryWidget.fromMeta(GraphicsOffloadStory.getMetadata(), 'Default'));
20
+ }
21
+
22
+ static getMetadata(): StoryMeta {
23
+ return { ...graphicsOffloadMeta, component: Gtk.GraphicsOffload.$gtype };
24
+ }
25
+
26
+ initialize(): void {
27
+ this._offload = new Gtk.GraphicsOffload({ widthRequest: 280, heightRequest: 96 });
28
+ // The order is the property order (gtkgraphicsoffload.c:366-380, :423-437): `enabled`
29
+ // first — it syncs the subsurface — then the black rectangle, which paints before the child.
30
+ this._offload.enabled = (this.args.enabled as string) === 'disabled' ? 1 : 0;
31
+ this._offload.black_background = this.args.blackBackground as boolean;
32
+ this._box = new Gtk.Box({ halign: Gtk.Align.CENTER, valign: Gtk.Align.CENTER });
33
+ this._box.append(this._offload);
34
+ this._applyChild();
35
+ this.addContent(this._box);
36
+ }
37
+
38
+ updateArgs(_args: StoryArgs): void {
39
+ if (!this._offload) return;
40
+ this._offload.enabled = (this.args.enabled as string) === 'disabled' ? 1 : 0;
41
+ this._offload.black_background = this.args.blackBackground as boolean;
42
+ this._applyChild();
43
+ }
44
+
45
+ /** The wrapper holds exactly ONE child, so changing it means replacing it. */
46
+ private _applyChild(): void {
47
+ if (!this._offload) return;
48
+ let child: Gtk.Widget;
49
+ switch (this.args.child) {
50
+ case 'label':
51
+ child = new Gtk.Label({ label: 'The child of an offloaded layer' });
52
+ break;
53
+ case 'box': {
54
+ // A row of three labels, centred — the bin layout hands it the whole
55
+ // allocation whatever its own request is.
56
+ const row = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL, spacing: 12 });
57
+ for (const text of ['One', 'Two', 'Three']) row.append(new Gtk.Label({ label: text }));
58
+ child = new Gtk.CenterBox();
59
+ (child as Gtk.CenterBox).set_center_widget(row);
60
+ break;
61
+ }
62
+ default:
63
+ child = new Gtk.Image({ iconName: 'camera-photo-symbolic', pixelSize: 48 });
64
+ break;
65
+ }
66
+ // `set_child` unparents the old one and notifies (gtkgraphicsoffload.c:317-336).
67
+ this._offload.child = child;
68
+ }
69
+ }
70
+
71
+ GObject.type_ensure(GraphicsOffloadStory.$gtype);
72
+
73
+ export const GraphicsOffloadStories: StoryModule = { stories: [GraphicsOffloadStory] };
@@ -0,0 +1,25 @@
1
+ // Shared, renderer-agnostic metadata for the Dialog story. Imported by
2
+ // both the GTK renderer (dialog.story.ts) and the browser renderer
3
+ // (browser/feedback/dialog.web.ts) so the two expose identical controls.
4
+
5
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
6
+
7
+ export const dialogMeta: StoryMeta = {
8
+ title: 'Feedback/Dialog',
9
+ description:
10
+ 'Adw.Dialog — the generic dialog: arbitrary content over a scrim, anchored as a floating card on a wide window and as a bottom sheet on a narrow one.',
11
+ controls: [
12
+ { name: 'title', label: 'Title', type: ControlType.TEXT, defaultValue: 'Preferences' },
13
+ {
14
+ name: 'presentation',
15
+ label: 'Presentation',
16
+ type: ControlType.SELECT,
17
+ options: [
18
+ { label: 'Auto', value: 'auto' },
19
+ { label: 'Floating', value: 'floating' },
20
+ { label: 'Bottom sheet', value: 'bottom-sheet' },
21
+ ],
22
+ defaultValue: 'auto',
23
+ },
24
+ ],
25
+ };
@@ -0,0 +1,78 @@
1
+ // Adw.Dialog — the generic dialog: arbitrary content over a scrim.
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 { dialogMeta } from './dialog.meta.js';
9
+
10
+ /**
11
+ * The meta's `presentation` NICK → the enum member, spelled out rather than cast.
12
+ *
13
+ * `Adw.DialogPresentationMode` is a GIR enum and the control carries a string, so
14
+ * `as Adw.DialogPresentationMode` would be a lie the compiler cannot see: it hands the
15
+ * property the string `"bottom-sheet"`. Every renderer of this story reads the SAME
16
+ * nick out of the shared meta, and this table is where GTK turns it back into a number.
17
+ */
18
+ const DIALOG_PRESENTATION: Record<string, Adw.DialogPresentationMode> = {
19
+ auto: Adw.DialogPresentationMode.AUTO,
20
+ floating: Adw.DialogPresentationMode.FLOATING,
21
+ 'bottom-sheet': Adw.DialogPresentationMode.BOTTOM_SHEET,
22
+ };
23
+
24
+ /** Story: Adw.Dialog presented from a button, holding a preferences page as its child. */
25
+ export class DialogStory extends StoryWidget {
26
+ private _button: Gtk.Button | null = null;
27
+
28
+ static {
29
+ GObject.registerClass({ GTypeName: 'AdwStorybookDialog' }, DialogStory);
30
+ }
31
+
32
+ constructor() {
33
+ super(StoryWidget.fromMeta(DialogStory.getMetadata(), 'Default'));
34
+ }
35
+
36
+ static getMetadata(): StoryMeta {
37
+ return { ...dialogMeta, component: Adw.Dialog.$gtype };
38
+ }
39
+
40
+ initialize(): void {
41
+ this._button = new Gtk.Button({
42
+ label: 'Show dialog',
43
+ halign: Gtk.Align.CENTER,
44
+ valign: Gtk.Align.CENTER,
45
+ });
46
+ this._button.add_css_class('pill');
47
+ this._button.add_css_class('suggested-action');
48
+ this._button.connect('clicked', () => this._present());
49
+
50
+ this.addContent(this._button);
51
+ }
52
+
53
+ private _present(): void {
54
+ // ONE child, and it is a property (`Adw.Dialog:child`), not a pack: this is the
55
+ // dialog the specialised ones are written as subclasses of.
56
+ const group = new Adw.PreferencesGroup({ title: 'Appearance' });
57
+ group.add(new Adw.SwitchRow({ title: 'Dark style', subtitle: 'Use a dark colour scheme', active: true }));
58
+
59
+ const page = new Adw.PreferencesPage({ title: 'General' });
60
+ page.add(group);
61
+
62
+ const dialog = new Adw.Dialog({
63
+ title: this.args.title as string,
64
+ child: page,
65
+ presentation_mode: DIALOG_PRESENTATION[this.args.presentation as string],
66
+ });
67
+
68
+ dialog.present(this);
69
+ }
70
+
71
+ updateArgs(_args: StoryArgs): void {
72
+ // The dialog reads the latest args each time it is presented; nothing to mutate live.
73
+ }
74
+ }
75
+
76
+ GObject.type_ensure(DialogStory.$gtype);
77
+
78
+ export const DialogStories: StoryModule = { stories: [DialogStory] };
@@ -0,0 +1,10 @@
1
+ // Shared, renderer-agnostic metadata for the Gtk.EmojiChooser story.
2
+
3
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
4
+
5
+ export const emojiChooserMeta: StoryMeta = {
6
+ title: 'Feedback/Emoji Chooser',
7
+ description:
8
+ 'Gtk.EmojiChooser — the popover a text widget opens to insert an emoji: a search entry over nine named sections, a toolbar that follows the scroll position, and an emoji-picked signal.',
9
+ controls: [{ name: 'search', label: 'Search', type: ControlType.TEXT, defaultValue: 'smile' }],
10
+ };