nomen-lang 0.7.1 → 0.8.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 (50) hide show
  1. package/core/System/Buffer.nm +32 -0
  2. package/core/System/ClassBuffer.nm +24 -0
  3. package/core/System/Controls/Alert.nm +326 -0
  4. package/core/System/Controls/App.nm +147 -0
  5. package/core/System/Controls/Button.nm +119 -1
  6. package/core/System/Controls/CheckBox.nm +24 -0
  7. package/core/System/Controls/ColorPicker.nm +307 -0
  8. package/core/System/Controls/ComboBox.nm +430 -0
  9. package/core/System/Controls/Container.nm +837 -9
  10. package/core/System/Controls/Control.nm +443 -0
  11. package/core/System/Controls/DatePicker.nm +288 -0
  12. package/core/System/Controls/Form.nm +70 -0
  13. package/core/System/Controls/GroupBox.nm +267 -0
  14. package/core/System/Controls/ImageView.nm +311 -0
  15. package/core/System/Controls/LevelIndicator.nm +305 -0
  16. package/core/System/Controls/ListView.nm +633 -0
  17. package/core/System/Controls/Menu.nm +428 -0
  18. package/core/System/Controls/NumberInput.nm +56 -0
  19. package/core/System/Controls/OtpInput.nm +50 -0
  20. package/core/System/Controls/OutlineView.nm +598 -0
  21. package/core/System/Controls/Pagination.nm +142 -0
  22. package/core/System/Controls/Popover.nm +296 -0
  23. package/core/System/Controls/Progress.nm +348 -0
  24. package/core/System/Controls/Radio.nm +292 -0
  25. package/core/System/Controls/Scrollable.nm +584 -0
  26. package/core/System/Controls/SearchField.nm +326 -0
  27. package/core/System/Controls/SecureField.nm +344 -0
  28. package/core/System/Controls/Segmented.nm +380 -0
  29. package/core/System/Controls/Select.nm +340 -0
  30. package/core/System/Controls/Separator.nm +198 -0
  31. package/core/System/Controls/Sheet.nm +329 -0
  32. package/core/System/Controls/Slider.nm +315 -0
  33. package/core/System/Controls/Spinner.nm +287 -0
  34. package/core/System/Controls/SplitView.nm +509 -0
  35. package/core/System/Controls/Stepper.nm +349 -0
  36. package/core/System/Controls/Switch.nm +259 -0
  37. package/core/System/Controls/Table.nm +833 -0
  38. package/core/System/Controls/Tabs.nm +500 -0
  39. package/core/System/Controls/Text.nm +108 -11
  40. package/core/System/Controls/TextBox.nm +112 -1
  41. package/core/System/Controls/TextView.nm +329 -0
  42. package/core/System/Controls/Toggle.nm +346 -0
  43. package/core/System/Controls/Toolbar.nm +501 -0
  44. package/core/System/Controls/Tooltip.nm +76 -0
  45. package/core/System/Controls/Window.nm +1549 -91
  46. package/core/System/List.nm +34 -0
  47. package/core/System/Map.nm +21 -4
  48. package/core/System/Set.nm +14 -0
  49. package/dist/index.mjs +2556 -656
  50. package/package.json +1 -1
@@ -220,6 +220,14 @@ pub struct Buffer<T> {
220
220
  // reaching here is always a value type (primitive or struct).
221
221
 
222
222
  func alloc = (ref self, int size, out int: out >= size) {
223
+ // Reclaim the old slab before the fresh calloc (the raw body runs
224
+ // for scalar / trivially-destructible elements — plain bytes, so a
225
+ // straight free is sound; mv element types take the specialized
226
+ // body, which per-element destroys first). The exact-cap contract
227
+ // is preserved: the fresh slab is calloc'd at exactly `size`.
228
+ if self.data != 0 {
229
+ free(self.data)
230
+ }
223
231
  self.cap = size
224
232
  self.data = calloc(size, T_SIZE)
225
233
  return self.cap
@@ -550,6 +558,30 @@ pub struct Buffer<T> {
550
558
  self.replace(i, value)
551
559
  }
552
560
 
561
+ // Address of slot `i` (library-only): the ELEMENT BORROW primitive —
562
+ // `ref T x = list.at(i)` (docs/HANDLERS.md Stage 4, the dynamic-tree
563
+ // dispatch) lowers to this, binding the alias to the slot itself rather
564
+ // than to a bitwise copy. The pointer is valid while the buffer is
565
+ // exclusively borrowed and not resized; a `ref self` call on the buffer
566
+ // (push/pop/set/…) invalidates the borrow through the ordinary
567
+ // borrow-invalidation rules. Library-internal: the caller (the `List`
568
+ // wrapper, or trusted internals) bounds-checks; the body is raw-only so
569
+ // the missing-return net does not apply to the raw return.
570
+ pub func slot_ptr = (ref self, int i, out ptr T) {
571
+ ```
572
+ #arch: c
573
+ return (T*)(unsigned long long)self->data + i;
574
+ ```
575
+ ```
576
+ #arch: aarch64
577
+ // x19 = self, x1 = i — the slot address (the load primitive's
578
+ // address-of: data + i * T_SIZE), returned in x0.
579
+ ldr x8, [x19, #8]
580
+ mov x9, #T_SIZE
581
+ madd x0, x1, x9, x8
582
+ ```
583
+ }
584
+
553
585
  // Move slot src into slot dst: overwrite dst with src's bytes and zero
554
586
  // src, so exactly ONE slot owns the value afterwards. The
555
587
  // ownership-transferring primitive behind backward-shift deletion
@@ -58,6 +58,30 @@ pub struct ClassBuffer<T> {
58
58
  ```
59
59
  }
60
60
 
61
+ // Address of slot `i` (library-only): the ELEMENT BORROW primitive for
62
+ // trait/class elements — `ref T x = list.at(i)` (docs/HANDLERS.md Stage
63
+ // 4) reaches here through the List wrapper when the element is a trait
64
+ // (the items buffer is a ClassBuffer). ClassBuffer slots are 8-byte
65
+ // handles, so the slot's CONTENT is the instance pointer: return the
66
+ // stored word, not the slot's address. Library-internal: bounds are the
67
+ // caller's obligation (the List wrapper constrains them).
68
+ pub func slot_ptr = (ref self, int i, out ptr T) {
69
+ ```
70
+ #arch: c
71
+ // The slot's address: through the alias, reads and writes hit the
72
+ // stored handle word. void* converts to the caller's `T*` spelling.
73
+ return (void *)&((unsigned long long *)self->data)[i];
74
+ ```
75
+ ```
76
+ #arch: aarch64
77
+ // 8-byte slots: the address of slot i — loading through it yields
78
+ // the stored handle.
79
+ ldr x8, [x19, #8]
80
+ lsl x9, x1, #3
81
+ add x0, x9, x8
82
+ ```
83
+ }
84
+
61
85
  // Generic (T-typed) counterparts of the _int primitives. ClassBuffer only
62
86
  // ever holds 8-byte class pointers (T_SIZE is 8), so these are
63
87
  // behaviorally identical to their _int counterparts — they exist so
@@ -0,0 +1,326 @@
1
+ /**
2
+ * A system alert dialog (NSAlert)
3
+ *
4
+ * An OWNING STRUCT (STRUCT_PLAN_3 Phase R, tranche 4 — the shape menu): the
5
+ * single field is a platform handle, so the value is movable and its
6
+ * `#destroy` releases what the handle names. The constructor's `self` is
7
+ * the inline instance (the `.` accessor); methods keep the pointer form.
8
+ *
9
+ * Window-coordinated: `run` enters NSAlert's own modal loop (it blocks the
10
+ * caller and pumps its own events, so it works with the manual loop), and
11
+ * returns the clicked button's index (first button = 0). iOS defers —
12
+ * UIAlertController needs a presenting view controller (TODO stubs; see
13
+ * GUI_PLAN Tier 1 #19).
14
+ **/
15
+ pub mv struct Alert : Control {
16
+ var uint64 handle = 0
17
+
18
+ // The `#handle` hook synthesizes `NameHandle` — a copyable, non-owning
19
+ // twin (same public bare-self methods, no destroy) so closures can
20
+ // capture this control without moving it. See GUI.md, "Handles".
21
+ #handle = () {}
22
+
23
+ pub func #init = (self) {
24
+ ```
25
+ #arch: c
26
+ #platform: macos
27
+ id alert = ((id(*)(id, SEL))objc_msgSend)(
28
+ ((id(*)(id, SEL))objc_msgSend)((id)objc_getClass("NSAlert"), sel_registerName("alloc")),
29
+ sel_registerName("init"));
30
+ self.handle = (uint64_t)alert;
31
+ ```
32
+ ```
33
+ #arch: aarch64_use_c
34
+ #platform: macos
35
+ id alert = ((id(*)(id, SEL))objc_msgSend)(
36
+ ((id(*)(id, SEL))objc_msgSend)((id)objc_getClass("NSAlert"), sel_registerName("alloc")),
37
+ sel_registerName("init"));
38
+ self->handle = (uint64_t)alert;
39
+ ```
40
+ ```
41
+ #arch: c
42
+ #platform: ios
43
+ /* TODO: iOS — UIAlertController needs a presenting view controller
44
+ * (see GUI_PLAN Tier 1 #19; defer the iOS block). */
45
+ ```
46
+ ```
47
+ #arch: aarch64_use_c
48
+ #platform: ios
49
+ /* TODO: iOS — UIAlertController needs a presenting view controller
50
+ * (see GUI_PLAN Tier 1 #19; defer the iOS block). */
51
+ ```
52
+ }
53
+
54
+ // The alert's headline (bold first line).
55
+ pub func set_title = (self, string title) {
56
+ ```
57
+ #arch: c
58
+ #platform: macos
59
+ ((void(*)(id, SEL, id))objc_msgSend)(
60
+ (id)self->handle, sel_registerName("setMessageText:"),
61
+ ((id(*)(id, SEL, const char*))objc_msgSend)(
62
+ (id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), title.ptr));
63
+ ```
64
+ ```
65
+ #arch: aarch64_use_c
66
+ #platform: macos
67
+ ((void(*)(id, SEL, id))objc_msgSend)(
68
+ (id)self->handle, sel_registerName("setMessageText:"),
69
+ ((id(*)(id, SEL, const char*))objc_msgSend)(
70
+ (id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), title.ptr));
71
+ ```
72
+ ```
73
+ #arch: c
74
+ #platform: ios
75
+ /* TODO: iOS (see #init) */
76
+ ```
77
+ ```
78
+ #arch: aarch64_use_c
79
+ #platform: ios
80
+ /* TODO: iOS (see #init) */
81
+ ```
82
+ }
83
+
84
+ pub func title = (self, out string) {
85
+ ```
86
+ #arch: c
87
+ #platform: macos
88
+ id str = ((id(*)(id, SEL))objc_msgSend)(
89
+ (id)self->handle, sel_registerName("messageText"));
90
+ if (!str) return (nomen_string){ strdup(""), 0 };
91
+ const char *cstr = ((const char*(*)(id, SEL))objc_msgSend)(
92
+ str, sel_registerName("UTF8String"));
93
+ return (nomen_string){ strdup(cstr), (long)strlen(cstr) };
94
+ ```
95
+ ```
96
+ #arch: aarch64_use_c
97
+ #platform: macos
98
+ id str = ((id(*)(id, SEL))objc_msgSend)(
99
+ (id)self->handle, sel_registerName("messageText"));
100
+ if (!str) return (nomen_string){ strdup(""), 0 };
101
+ const char *cstr = ((const char*(*)(id, SEL))objc_msgSend)(
102
+ str, sel_registerName("UTF8String"));
103
+ return (nomen_string){ strdup(cstr), (long)strlen(cstr) };
104
+ ```
105
+ ```
106
+ #arch: c
107
+ #platform: ios
108
+ /* TODO: iOS (see #init) */
109
+ return (nomen_string){ strdup(""), 0 };
110
+ ```
111
+ ```
112
+ #arch: aarch64_use_c
113
+ #platform: ios
114
+ /* TODO: iOS (see #init) */
115
+ return (nomen_string){ strdup(""), 0 };
116
+ ```
117
+ }
118
+
119
+ // The explanatory second line.
120
+ pub func set_message = (self, string message) {
121
+ ```
122
+ #arch: c
123
+ #platform: macos
124
+ ((void(*)(id, SEL, id))objc_msgSend)(
125
+ (id)self->handle, sel_registerName("setInformativeText:"),
126
+ ((id(*)(id, SEL, const char*))objc_msgSend)(
127
+ (id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), message.ptr));
128
+ ```
129
+ ```
130
+ #arch: aarch64_use_c
131
+ #platform: macos
132
+ ((void(*)(id, SEL, id))objc_msgSend)(
133
+ (id)self->handle, sel_registerName("setInformativeText:"),
134
+ ((id(*)(id, SEL, const char*))objc_msgSend)(
135
+ (id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), message.ptr));
136
+ ```
137
+ ```
138
+ #arch: c
139
+ #platform: ios
140
+ /* TODO: iOS (see #init) */
141
+ ```
142
+ ```
143
+ #arch: aarch64_use_c
144
+ #platform: ios
145
+ /* TODO: iOS (see #init) */
146
+ ```
147
+ }
148
+
149
+ pub func message = (self, out string) {
150
+ ```
151
+ #arch: c
152
+ #platform: macos
153
+ id str = ((id(*)(id, SEL))objc_msgSend)(
154
+ (id)self->handle, sel_registerName("informativeText"));
155
+ if (!str) return (nomen_string){ strdup(""), 0 };
156
+ const char *cstr = ((const char*(*)(id, SEL))objc_msgSend)(
157
+ str, sel_registerName("UTF8String"));
158
+ return (nomen_string){ strdup(cstr), (long)strlen(cstr) };
159
+ ```
160
+ ```
161
+ #arch: aarch64_use_c
162
+ #platform: macos
163
+ id str = ((id(*)(id, SEL))objc_msgSend)(
164
+ (id)self->handle, sel_registerName("informativeText"));
165
+ if (!str) return (nomen_string){ strdup(""), 0 };
166
+ const char *cstr = ((const char*(*)(id, SEL))objc_msgSend)(
167
+ str, sel_registerName("UTF8String"));
168
+ return (nomen_string){ strdup(cstr), (long)strlen(cstr) };
169
+ ```
170
+ ```
171
+ #arch: c
172
+ #platform: ios
173
+ /* TODO: iOS (see #init) */
174
+ return (nomen_string){ strdup(""), 0 };
175
+ ```
176
+ ```
177
+ #arch: aarch64_use_c
178
+ #platform: ios
179
+ /* TODO: iOS (see #init) */
180
+ return (nomen_string){ strdup(""), 0 };
181
+ ```
182
+ }
183
+
184
+ // Append a button (left to right). The FIRST button is the default
185
+ // (Return); the clicked one's index is what `run` returns. A fresh
186
+ // NSAlert carries one default button ("OK") — the first
187
+ // `add_button` REPLACES it, so the count stays what the app adds.
188
+ pub func add_button = (self, string title) {
189
+ ```
190
+ #arch: c
191
+ #platform: macos
192
+ ((void(*)(id, SEL, id))objc_msgSend)(
193
+ (id)self->handle, sel_registerName("addButtonWithTitle:"),
194
+ ((id(*)(id, SEL, const char*))objc_msgSend)(
195
+ (id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), title.ptr));
196
+ ```
197
+ ```
198
+ #arch: aarch64_use_c
199
+ #platform: macos
200
+ ((void(*)(id, SEL, id))objc_msgSend)(
201
+ (id)self->handle, sel_registerName("addButtonWithTitle:"),
202
+ ((id(*)(id, SEL, const char*))objc_msgSend)(
203
+ (id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), title.ptr));
204
+ ```
205
+ ```
206
+ #arch: c
207
+ #platform: ios
208
+ /* TODO: iOS (see #init) */
209
+ ```
210
+ ```
211
+ #arch: aarch64_use_c
212
+ #platform: ios
213
+ /* TODO: iOS (see #init) */
214
+ ```
215
+ }
216
+
217
+ // How many buttons the alert carries.
218
+ pub func button_count = (self, out int) {
219
+ ```
220
+ #arch: c
221
+ #platform: macos
222
+ id buttons = ((id(*)(id, SEL))objc_msgSend)(
223
+ (id)self->handle, sel_registerName("buttons"));
224
+ return (int)((long(*)(id, SEL))objc_msgSend)(buttons, sel_registerName("count"));
225
+ ```
226
+ ```
227
+ #arch: aarch64_use_c
228
+ #platform: macos
229
+ id buttons = ((id(*)(id, SEL))objc_msgSend)(
230
+ (id)self->handle, sel_registerName("buttons"));
231
+ return (int)((long(*)(id, SEL))objc_msgSend)(buttons, sel_registerName("count"));
232
+ ```
233
+ ```
234
+ #arch: c
235
+ #platform: ios
236
+ /* TODO: iOS (see #init) */
237
+ return 0;
238
+ ```
239
+ ```
240
+ #arch: aarch64_use_c
241
+ #platform: ios
242
+ /* TODO: iOS (see #init) */
243
+ return 0;
244
+ ```
245
+ }
246
+
247
+ // Show the alert modally and return the clicked button's index (0 =
248
+ // first button). BLOCKS in NSAlert's own modal loop until dismissed —
249
+ // call it from the event thread when the manual loop can afford to
250
+ // pause (NSAlert pumps its own events, so the UI stays live).
251
+ pub func run = (self, out int) {
252
+ ```
253
+ #arch: c
254
+ #platform: macos
255
+ long code = ((long(*)(id, SEL))objc_msgSend)(
256
+ (id)self->handle, sel_registerName("runModal"));
257
+ return (int)(code - 1000); // NSModalResponseOK = 1000 + button index
258
+ ```
259
+ ```
260
+ #arch: aarch64_use_c
261
+ #platform: macos
262
+ long code = ((long(*)(id, SEL))objc_msgSend)(
263
+ (id)self->handle, sel_registerName("runModal"));
264
+ return (int)(code - 1000); // NSModalResponseOK = 1000 + button index
265
+ ```
266
+ ```
267
+ #arch: c
268
+ #platform: ios
269
+ /* TODO: iOS (see #init) */
270
+ return 0;
271
+ ```
272
+ ```
273
+ #arch: aarch64_use_c
274
+ #platform: ios
275
+ /* TODO: iOS (see #init) */
276
+ return 0;
277
+ ```
278
+ }
279
+
280
+ // ── Control trait conformance ──
281
+ // An alert is a modal, not an in-window view: it measures to nothing and
282
+ // the layout engine never frames it. The conformance exists so an Alert
283
+ // can sit in a Control-typed slot without special-casing.
284
+ pub func set_frame = (ref self, int x, int y, int width, int height) {
285
+ // No-op: modals are positioned by the window server.
286
+ }
287
+
288
+ pub func intrinsic_size = (self, out Size) {
289
+ var s = Size()
290
+ return s
291
+ }
292
+
293
+ pub func measure = (self, BoxConstraints constraints, out Size) {
294
+ var s = Size()
295
+ return s
296
+ }
297
+
298
+ func #destroy = () {
299
+ ```
300
+ #arch: c
301
+ #platform: macos
302
+ if (self->handle) {
303
+ ((void(*)(id, SEL))objc_msgSend)((id)self->handle, sel_registerName("release"));
304
+ self->handle = 0;
305
+ }
306
+ ```
307
+ ```
308
+ #arch: aarch64_use_c
309
+ #platform: macos
310
+ if (self->handle) {
311
+ ((void(*)(id, SEL))objc_msgSend)((id)self->handle, sel_registerName("release"));
312
+ self->handle = 0;
313
+ }
314
+ ```
315
+ ```
316
+ #arch: c
317
+ #platform: ios
318
+ /* TODO: iOS (see #init) */
319
+ ```
320
+ ```
321
+ #arch: aarch64_use_c
322
+ #platform: ios
323
+ /* TODO: iOS (see #init) */
324
+ ```
325
+ }
326
+ }
@@ -0,0 +1,147 @@
1
+ /**
2
+ * The App contract: the object Window.run drives
3
+ *
4
+ * The WinForms/Swift shape for a manual-loop toolkit: instead of pumping
5
+ * `Window.process_events` and re-checking sizes in a `while` loop, the app
6
+ * declares a struct conforming to `App`, moves it into `win.run(mv app)`,
7
+ * and the WINDOW owns everything else — the event pump, the autorelease
8
+ * pool, resize detection, and the relayout of the hosted content (the root
9
+ * `Container` from `win.set_content` plus every `Scrollable.set_content`
10
+ * document). The app implements four hooks:
11
+ *
12
+ * - `start` — called once, after the app has been moved into its final
13
+ * storage but before the window is shown. Register the layout roots here
14
+ * (`win.set_content(ref grid)`, `scroll.set_content(ref grid)`) and do
15
+ * any wiring that needs stable addresses — including click handlers
16
+ * (`self.btn.on_click(func () { ... })`).
17
+ * - `frame` — called every iteration of the run loop with a `FrameEvents`
18
+ * value: the full input record for this frame (click kind/coordinates,
19
+ * `mouse_button`/`mouse_click_count`/`mouse_modifiers` — every button,
20
+ * `scroll_dx`/`scroll_dy`, the keyboard record
21
+ * `key_code`/`key_modifiers`/`key_repeat`/`key_up_code`, the pointer
22
+ * position `mouse_x`/`mouse_y`, and frame time `dt`), and `resized`
23
+ * + the new size when the window's content rect changed. Per-frame value
24
+ * polling (slider → progress mirrors), coordinate-driven input that no
25
+ * event names, and app-owned pane relayouts live here — registered
26
+ * click, right-click, mouse-down, scroll, key, move, and resize handlers
27
+ * dispatch earlier, in `handle_events` (the `.on_click` /
28
+ * `.on_right_click` / `.on_mouse_down` / `.on_scroll` / `.on_key_down` /
29
+ * `.on_key_up` / `.on_mouse_move` / `.on_resize` desugars), and close
30
+ * requests consult `close_requested`.
31
+ * - `handle_events` — the per-frame event pump: drains every registered
32
+ * control event (clicks, focus/blur, text input). Declared here as a
33
+ * default-empty method; the `.on_<event>(closure)` desugars
34
+ * (docs/HANDLERS.md) synthesize the override on conformers with
35
+ * registrations, so user code only writes the registration and never
36
+ * sees the machinery. New control events extend the pump's arms — the
37
+ * App contract is fixed.
38
+ * - `run_handler` — the up-call protocol (Stage 3): a composite with an
39
+ * enrolled event calls back `owner.run_handler(id, ref win)` from its
40
+ * `tick` (the app forwards itself down once per tick). Default-empty;
41
+ * the desugar synthesizes the override dispatching ids to the app's
42
+ * `.on_<event>` handlers.
43
+ *
44
+ * Handlers are METHODS on the app (the `ref self` receiver), so app state —
45
+ * every control field — is reachable without lambda captures (capturing a
46
+ * control MOVES it; a capture-free method reference moves nothing). The
47
+ * `.on_click` desugar is that shape with registration ergonomics: the
48
+ * closure you write IS hoisted into a hidden method, and the dispatch
49
+ * borrow of `self` is taken by the run loop per frame.
50
+ **/
51
+ pub trait App {
52
+ // Called once before the window is shown, after the app is in its
53
+ // final storage. Register layout roots here.
54
+ func start = (ref self, ref Window win) {
55
+ }
56
+
57
+ // Called every frame until the window closes.
58
+ func frame = (ref self, ref Window win, FrameEvents ev) {
59
+ }
60
+
61
+ // The per-frame event pump: drains every registered control event —
62
+ // clicks, focus/blur, text input — through arms the `.on_<event>`
63
+ // desugar (docs/HANDLERS.md) synthesizes on conformers with
64
+ // registrations: one hidden method per closure, one drain arm per
65
+ // registered control, one event-source prologue per family.
66
+ // `Window.run` calls it before `frame`. New control events are new arms
67
+ // in this one slot — the App contract never grows with the event
68
+ // catalog. Conformers without registrations inherit this empty default
69
+ // (trait defaults have precedent: `Enumerable.length`).
70
+ func handle_events = (ref self, ref Window win) {
71
+ }
72
+
73
+ // The up-call protocol (docs/HANDLERS.md Stage 3): a composite the app
74
+ // has enrolled events on calls back into this — `owner.run_handler(id,
75
+ // ref win)` from its `tick` — one vtable hop into the desugar's
76
+ // synthesized override, whose arms dispatch the id to the app's handler.
77
+ // The borrow flows down per call; nothing outlives it. Default-empty,
78
+ // like `handle_events`.
79
+ func run_handler = (ref self, int id, ref Window win) {
80
+ }
81
+
82
+ // Close interception (the unsaved-changes pattern): run consults this
83
+ // on the frame after the user requests close (the red button — the
84
+ // delegate refuses the native close and sets a pending flag). Return
85
+ // false to refuse: the window stays, the flag is cleared, and a later
86
+ // close request consults again. Programmatic `win.close()` is FORCED
87
+ // and bypasses this — handlers closing their own window never trip the
88
+ // interception. Default: allow.
89
+ func close_requested = (ref self, ref Window win, out bool) {
90
+ return true
91
+ }
92
+ }
93
+
94
+ /**
95
+ * One frame's input state, passed to App.frame
96
+ *
97
+ * Pure scalars, so the by-value parameter copies safely (no destroy).
98
+ * Click coordinates are the window's content coordinates, top-left origin
99
+ * (the same values `Window.click_x`/`click_y` report) — translate through
100
+ * `content_click` before hit-testing controls hosted on a Scrollable.
101
+ **/
102
+ pub mv struct FrameEvents {
103
+ // 0 = no mouse-down this frame, 1 = left, 2 = right (edge-triggered:
104
+ // only the frame that pumped the event reports it).
105
+ pub var int click = 0
106
+ pub var int click_x = -1
107
+ pub var int click_y = -1
108
+ // The full mouse record for this frame (0 = no mouse-down): the 1-based
109
+ // button number (1 left, 2 right, 3 middle, 4+ extra buttons), the
110
+ // AppKit click count (2 = double-click), and the device-independent
111
+ // modifier flags (Command = 0x100000, Option = 0x80000, Control =
112
+ // 0x40000, Shift = 0x20000). The same values the `win.mouse_button()` /
113
+ // `mouse_click_count()` / `mouse_modifiers()` getters report to
114
+ // `on_mouse_down` handlers. `click` remains the left/right compat view.
115
+ pub var int mouse_button = 0
116
+ pub var int mouse_click_count = 0
117
+ pub var int mouse_modifiers = 0
118
+ // This frame's accumulated scroll-wheel deltas (dy positive scrolling
119
+ // up/away, dx positive right; trackpad frames sum every small event).
120
+ // `Scrollable.on_scroll` is the registered-handler form.
121
+ pub var int scroll_dx = 0
122
+ pub var int scroll_dy = 0
123
+ // The keyboard record for this frame (-1 = no key this frame): the
124
+ // hardware keycode of the last key-down (Space = 49, Return = 36,
125
+ // arrows = 123–126, letters a…z = 0–25), the modifiers at key-down,
126
+ // whether it was an auto-repeat, and the keycode of the last key-up.
127
+ // `on_key_down` / `on_key_up` are the registered-handler forms; text
128
+ // ENTRY flows through `on_input` (the field editor), not here.
129
+ pub var int key_code = -1
130
+ pub var int key_modifiers = 0
131
+ pub var bool key_repeat = false
132
+ pub var int key_up_code = -1
133
+ // The pointer-MOVE record for this frame (-1 = no movement): the
134
+ // current pointer position. `on_mouse_move` is the registered-handler
135
+ // form; hover/tooltips hit-test this against Container.contains.
136
+ pub var int mouse_x = -1
137
+ pub var int mouse_y = -1
138
+ // Milliseconds since the previous frame (0 on the first) — the
139
+ // animation clock. `win.dt()` reports the same value.
140
+ pub var int dt = 0
141
+ // True when the window's content rect changed since the last frame —
142
+ // the framework has already re-laid-out the registered roots; re-layout
143
+ // App-owned panes (tab pages, split panes) here.
144
+ pub var bool resized = false
145
+ pub var int width = 0
146
+ pub var int height = 0
147
+ }