nomen-lang 0.7.0 → 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.
- package/core/System/Buffer.nm +32 -0
- package/core/System/ClassBuffer.nm +24 -0
- package/core/System/Controls/Alert.nm +326 -0
- package/core/System/Controls/App.nm +147 -0
- package/core/System/Controls/Button.nm +119 -1
- package/core/System/Controls/CheckBox.nm +24 -0
- package/core/System/Controls/ColorPicker.nm +307 -0
- package/core/System/Controls/ComboBox.nm +430 -0
- package/core/System/Controls/Container.nm +837 -9
- package/core/System/Controls/Control.nm +443 -0
- package/core/System/Controls/DatePicker.nm +288 -0
- package/core/System/Controls/Form.nm +70 -0
- package/core/System/Controls/GroupBox.nm +267 -0
- package/core/System/Controls/ImageView.nm +311 -0
- package/core/System/Controls/LevelIndicator.nm +305 -0
- package/core/System/Controls/ListView.nm +633 -0
- package/core/System/Controls/Menu.nm +428 -0
- package/core/System/Controls/NumberInput.nm +56 -0
- package/core/System/Controls/OtpInput.nm +50 -0
- package/core/System/Controls/OutlineView.nm +598 -0
- package/core/System/Controls/Pagination.nm +142 -0
- package/core/System/Controls/Popover.nm +296 -0
- package/core/System/Controls/Progress.nm +348 -0
- package/core/System/Controls/Radio.nm +292 -0
- package/core/System/Controls/Scrollable.nm +584 -0
- package/core/System/Controls/SearchField.nm +326 -0
- package/core/System/Controls/SecureField.nm +344 -0
- package/core/System/Controls/Segmented.nm +380 -0
- package/core/System/Controls/Select.nm +340 -0
- package/core/System/Controls/Separator.nm +198 -0
- package/core/System/Controls/Sheet.nm +329 -0
- package/core/System/Controls/Slider.nm +315 -0
- package/core/System/Controls/Spinner.nm +287 -0
- package/core/System/Controls/SplitView.nm +509 -0
- package/core/System/Controls/Stepper.nm +349 -0
- package/core/System/Controls/Switch.nm +259 -0
- package/core/System/Controls/Table.nm +833 -0
- package/core/System/Controls/Tabs.nm +500 -0
- package/core/System/Controls/Text.nm +108 -11
- package/core/System/Controls/TextBox.nm +112 -1
- package/core/System/Controls/TextView.nm +329 -0
- package/core/System/Controls/Toggle.nm +346 -0
- package/core/System/Controls/Toolbar.nm +501 -0
- package/core/System/Controls/Tooltip.nm +76 -0
- package/core/System/Controls/Window.nm +1549 -91
- package/core/System/List.nm +34 -0
- package/core/System/Map.nm +21 -4
- package/core/System/Set.nm +14 -0
- package/dist/index.mjs +3425 -710
- package/package.json +1 -1
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A context menu attachable to any control (NSMenu via `view.menu`)
|
|
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
|
+
* Right-clicking an attached control shows the menu natively — AppKit runs
|
|
10
|
+
* its own modal tracking loop, so the manual event loop is untouched. Each
|
|
11
|
+
* item carries a tag (its index) and a shared target whose action records
|
|
12
|
+
* the tag in a C global; `clicked_item` polls it (edge-triggered: the read
|
|
13
|
+
* resets it to -1, "none"), and `on_item_select` is the registered form —
|
|
14
|
+
* the drain consumes the selection, the handler reads it through
|
|
15
|
+
* `selected_item`.
|
|
16
|
+
* iOS presentation differs (UIContextMenu-
|
|
17
|
+
* Interaction needs a scene-attached view — see GUI_PLAN Tier 2; the iOS
|
|
18
|
+
* blocks are TODO stubs).
|
|
19
|
+
**/
|
|
20
|
+
pub mv struct Menu : Control {
|
|
21
|
+
var uint64 handle = 0
|
|
22
|
+
|
|
23
|
+
// File-scope helper: the shared item target. The action records the
|
|
24
|
+
// clicked item's tag (shared — one Menu per process, like List's row
|
|
25
|
+
// storage).
|
|
26
|
+
pub func #init = (self) {
|
|
27
|
+
```
|
|
28
|
+
#arch: c
|
|
29
|
+
#platform: macos
|
|
30
|
+
#scope: file
|
|
31
|
+
static long g_menu_last_tag = -1;
|
|
32
|
+
static id g_menu_target = 0;
|
|
33
|
+
|
|
34
|
+
static void nomen_menu_item_action(id self, SEL cmd, id sender) {
|
|
35
|
+
(void)self; (void)cmd;
|
|
36
|
+
g_menu_last_tag = ((long(*)(id, SEL))objc_msgSend)(sender, sel_registerName("tag"));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static id nomen_menu_target(void) {
|
|
40
|
+
Class Mt = objc_getClass("NomenMenuTarget");
|
|
41
|
+
if (!Mt) {
|
|
42
|
+
Mt = objc_allocateClassPair(objc_getClass("NSObject"), "NomenMenuTarget", 0);
|
|
43
|
+
if (Mt) {
|
|
44
|
+
class_addMethod(Mt, sel_registerName("nomenMenuItemAction:"),
|
|
45
|
+
(IMP)nomen_menu_item_action, "v@:@");
|
|
46
|
+
objc_registerClassPair(Mt);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (!g_menu_target) {
|
|
50
|
+
g_menu_target = ((id(*)(id, SEL))objc_msgSend)(Mt, sel_registerName("new"));
|
|
51
|
+
}
|
|
52
|
+
return g_menu_target;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Edge-triggered read: the poll consumes the tag (resets to -1).
|
|
56
|
+
long nomen_menu_last_tag(void) {
|
|
57
|
+
long tag = g_menu_last_tag;
|
|
58
|
+
g_menu_last_tag = -1;
|
|
59
|
+
return tag;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// The on_item_select drain's consume-and-stash: the drain consumes
|
|
63
|
+
// the selected tag exactly like the poll, and STASHES it for the
|
|
64
|
+
// handler body to read through Menu.selected_item (the drain runs
|
|
65
|
+
// first in its pump arm, so the stash is fresh when the handler
|
|
66
|
+
// body runs).
|
|
67
|
+
long g_menu_selected_tag = -1;
|
|
68
|
+
unsigned char nomen_menu_take_select(void) {
|
|
69
|
+
long tag = nomen_menu_last_tag();
|
|
70
|
+
if (tag < 0) return 0;
|
|
71
|
+
g_menu_selected_tag = tag;
|
|
72
|
+
return 1;
|
|
73
|
+
}
|
|
74
|
+
long nomen_menu_selected_tag(void) {
|
|
75
|
+
return g_menu_selected_tag;
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
```
|
|
79
|
+
#arch: aarch64_use_c
|
|
80
|
+
#platform: macos
|
|
81
|
+
#scope: file
|
|
82
|
+
static long g_menu_last_tag = -1;
|
|
83
|
+
static id g_menu_target = 0;
|
|
84
|
+
|
|
85
|
+
static void nomen_menu_item_action(id self, SEL cmd, id sender) {
|
|
86
|
+
(void)self; (void)cmd;
|
|
87
|
+
g_menu_last_tag = ((long(*)(id, SEL))objc_msgSend)(sender, sel_registerName("tag"));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
static id nomen_menu_target(void) {
|
|
91
|
+
Class Mt = objc_getClass("NomenMenuTarget");
|
|
92
|
+
if (!Mt) {
|
|
93
|
+
Mt = objc_allocateClassPair(objc_getClass("NSObject"), "NomenMenuTarget", 0);
|
|
94
|
+
if (Mt) {
|
|
95
|
+
class_addMethod(Mt, sel_registerName("nomenMenuItemAction:"),
|
|
96
|
+
(IMP)nomen_menu_item_action, "v@:@");
|
|
97
|
+
objc_registerClassPair(Mt);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (!g_menu_target) {
|
|
101
|
+
g_menu_target = ((id(*)(id, SEL))objc_msgSend)(Mt, sel_registerName("new"));
|
|
102
|
+
}
|
|
103
|
+
return g_menu_target;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Edge-triggered read: the poll consumes the tag (resets to -1).
|
|
107
|
+
long nomen_menu_last_tag(void) {
|
|
108
|
+
long tag = g_menu_last_tag;
|
|
109
|
+
g_menu_last_tag = -1;
|
|
110
|
+
return tag;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// The on_item_select drain's consume-and-stash (see the c twin
|
|
114
|
+
// above).
|
|
115
|
+
long g_menu_selected_tag = -1;
|
|
116
|
+
unsigned char nomen_menu_take_select(void) {
|
|
117
|
+
long tag = nomen_menu_last_tag();
|
|
118
|
+
if (tag < 0) return 0;
|
|
119
|
+
g_menu_selected_tag = tag;
|
|
120
|
+
return 1;
|
|
121
|
+
}
|
|
122
|
+
long nomen_menu_selected_tag(void) {
|
|
123
|
+
return g_menu_selected_tag;
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
```
|
|
127
|
+
#arch: c
|
|
128
|
+
#platform: macos
|
|
129
|
+
id menu = ((id(*)(id, SEL))objc_msgSend)(
|
|
130
|
+
((id(*)(id, SEL))objc_msgSend)((id)objc_getClass("NSMenu"), sel_registerName("alloc")),
|
|
131
|
+
sel_registerName("init"));
|
|
132
|
+
self.handle = (uint64_t)menu;
|
|
133
|
+
```
|
|
134
|
+
```
|
|
135
|
+
#arch: aarch64_use_c
|
|
136
|
+
#platform: macos
|
|
137
|
+
id menu = ((id(*)(id, SEL))objc_msgSend)(
|
|
138
|
+
((id(*)(id, SEL))objc_msgSend)((id)objc_getClass("NSMenu"), sel_registerName("alloc")),
|
|
139
|
+
sel_registerName("init"));
|
|
140
|
+
self->handle = (uint64_t)menu;
|
|
141
|
+
```
|
|
142
|
+
```
|
|
143
|
+
#arch: c
|
|
144
|
+
#platform: ios
|
|
145
|
+
/* TODO: iOS — UIContextMenuInteraction needs a scene-attached view
|
|
146
|
+
* (see GUI_PLAN Tier 2; defer). */
|
|
147
|
+
```
|
|
148
|
+
```
|
|
149
|
+
#arch: aarch64_use_c
|
|
150
|
+
#platform: ios
|
|
151
|
+
/* TODO: iOS (see #init) */
|
|
152
|
+
```
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Append a clickable item. Its tag (and the `clicked_item` value it
|
|
156
|
+
// reports) is its ENTRY index in the menu — separators consume an index
|
|
157
|
+
// too, so `add_item` after `add_separator` reports the entry count.
|
|
158
|
+
pub func add_item = (self, string title) {
|
|
159
|
+
```
|
|
160
|
+
#arch: c
|
|
161
|
+
#platform: macos
|
|
162
|
+
id menu = (id)self->handle;
|
|
163
|
+
long tag = ((long(*)(id, SEL))objc_msgSend)(menu, sel_registerName("numberOfItems"));
|
|
164
|
+
id item = ((id(*)(id, SEL, id, SEL, id))objc_msgSend)(
|
|
165
|
+
((id(*)(id, SEL))objc_msgSend)((id)objc_getClass("NSMenuItem"), sel_registerName("alloc")),
|
|
166
|
+
sel_registerName("initWithTitle:action:keyEquivalent:"),
|
|
167
|
+
((id(*)(id, SEL, const char*))objc_msgSend)(
|
|
168
|
+
(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), title.ptr),
|
|
169
|
+
sel_registerName("nomenMenuItemAction:"),
|
|
170
|
+
((id(*)(id, SEL, const char*))objc_msgSend)(
|
|
171
|
+
(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), ""));
|
|
172
|
+
((void(*)(id, SEL, long))objc_msgSend)(item, sel_registerName("setTag:"), tag);
|
|
173
|
+
((void(*)(id, SEL, id))objc_msgSend)(item, sel_registerName("setTarget:"), nomen_menu_target());
|
|
174
|
+
((void(*)(id, SEL, id))objc_msgSend)(menu, sel_registerName("addItem:"), item);
|
|
175
|
+
((void(*)(id, SEL))objc_msgSend)(item, sel_registerName("release"));
|
|
176
|
+
```
|
|
177
|
+
```
|
|
178
|
+
#arch: aarch64_use_c
|
|
179
|
+
#platform: macos
|
|
180
|
+
id menu = (id)self->handle;
|
|
181
|
+
long tag = ((long(*)(id, SEL))objc_msgSend)(menu, sel_registerName("numberOfItems"));
|
|
182
|
+
id item = ((id(*)(id, SEL, id, SEL, id))objc_msgSend)(
|
|
183
|
+
((id(*)(id, SEL))objc_msgSend)((id)objc_getClass("NSMenuItem"), sel_registerName("alloc")),
|
|
184
|
+
sel_registerName("initWithTitle:action:keyEquivalent:"),
|
|
185
|
+
((id(*)(id, SEL, const char*))objc_msgSend)(
|
|
186
|
+
(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), title.ptr),
|
|
187
|
+
sel_registerName("nomenMenuItemAction:"),
|
|
188
|
+
((id(*)(id, SEL, const char*))objc_msgSend)(
|
|
189
|
+
(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), ""));
|
|
190
|
+
((void(*)(id, SEL, long))objc_msgSend)(item, sel_registerName("setTag:"), tag);
|
|
191
|
+
((void(*)(id, SEL, id))objc_msgSend)(item, sel_registerName("setTarget:"), nomen_menu_target());
|
|
192
|
+
((void(*)(id, SEL, id))objc_msgSend)(menu, sel_registerName("addItem:"), item);
|
|
193
|
+
((void(*)(id, SEL))objc_msgSend)(item, sel_registerName("release"));
|
|
194
|
+
```
|
|
195
|
+
```
|
|
196
|
+
#arch: c
|
|
197
|
+
#platform: ios
|
|
198
|
+
/* TODO: iOS (see #init) */
|
|
199
|
+
```
|
|
200
|
+
```
|
|
201
|
+
#arch: aarch64_use_c
|
|
202
|
+
#platform: ios
|
|
203
|
+
/* TODO: iOS (see #init) */
|
|
204
|
+
```
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Append a separator line.
|
|
208
|
+
pub func add_separator = (self) {
|
|
209
|
+
```
|
|
210
|
+
#arch: c
|
|
211
|
+
#platform: macos
|
|
212
|
+
id sep = ((id(*)(id, SEL))objc_msgSend)(
|
|
213
|
+
(id)objc_getClass("NSMenuItem"), sel_registerName("separatorItem"));
|
|
214
|
+
((void(*)(id, SEL, id))objc_msgSend)((id)self->handle, sel_registerName("addItem:"), sep);
|
|
215
|
+
```
|
|
216
|
+
```
|
|
217
|
+
#arch: aarch64_use_c
|
|
218
|
+
#platform: macos
|
|
219
|
+
id sep = ((id(*)(id, SEL))objc_msgSend)(
|
|
220
|
+
(id)objc_getClass("NSMenuItem"), sel_registerName("separatorItem"));
|
|
221
|
+
((void(*)(id, SEL, id))objc_msgSend)((id)self->handle, sel_registerName("addItem:"), sep);
|
|
222
|
+
```
|
|
223
|
+
```
|
|
224
|
+
#arch: c
|
|
225
|
+
#platform: ios
|
|
226
|
+
/* TODO: iOS (see #init) */
|
|
227
|
+
```
|
|
228
|
+
```
|
|
229
|
+
#arch: aarch64_use_c
|
|
230
|
+
#platform: ios
|
|
231
|
+
/* TODO: iOS (see #init) */
|
|
232
|
+
```
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Show this menu on right-click of the control with the given handle.
|
|
236
|
+
pub func attach = (self, uint64 handle) {
|
|
237
|
+
```
|
|
238
|
+
#arch: c
|
|
239
|
+
#platform: macos
|
|
240
|
+
((void(*)(id, SEL, id))objc_msgSend)((id)handle, sel_registerName("setMenu:"), (id)self->handle);
|
|
241
|
+
```
|
|
242
|
+
```
|
|
243
|
+
#arch: aarch64_use_c
|
|
244
|
+
#platform: macos
|
|
245
|
+
((void(*)(id, SEL, id))objc_msgSend)((id)handle, sel_registerName("setMenu:"), (id)self->handle);
|
|
246
|
+
```
|
|
247
|
+
```
|
|
248
|
+
#arch: c
|
|
249
|
+
#platform: ios
|
|
250
|
+
/* TODO: iOS (see #init) */
|
|
251
|
+
```
|
|
252
|
+
```
|
|
253
|
+
#arch: aarch64_use_c
|
|
254
|
+
#platform: ios
|
|
255
|
+
/* TODO: iOS (see #init) */
|
|
256
|
+
```
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// The number of ENTRIES (items + separators).
|
|
260
|
+
pub func item_count = (self, out int) {
|
|
261
|
+
```
|
|
262
|
+
#arch: c
|
|
263
|
+
#platform: macos
|
|
264
|
+
return (int)((long(*)(id, SEL))objc_msgSend)(
|
|
265
|
+
(id)self->handle, sel_registerName("numberOfItems"));
|
|
266
|
+
```
|
|
267
|
+
```
|
|
268
|
+
#arch: aarch64_use_c
|
|
269
|
+
#platform: macos
|
|
270
|
+
return (int)((long(*)(id, SEL))objc_msgSend)(
|
|
271
|
+
(id)self->handle, sel_registerName("numberOfItems"));
|
|
272
|
+
```
|
|
273
|
+
```
|
|
274
|
+
#arch: c
|
|
275
|
+
#platform: ios
|
|
276
|
+
/* TODO: iOS (see #init) */
|
|
277
|
+
return 0;
|
|
278
|
+
```
|
|
279
|
+
```
|
|
280
|
+
#arch: aarch64_use_c
|
|
281
|
+
#platform: ios
|
|
282
|
+
/* TODO: iOS (see #init) */
|
|
283
|
+
return 0;
|
|
284
|
+
```
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// The tag of the most recently clicked item since the last read
|
|
288
|
+
// (edge-triggered; -1 = none). Poll it in the manual loop.
|
|
289
|
+
pub func clicked_item = (self, out int) {
|
|
290
|
+
```
|
|
291
|
+
#arch: c
|
|
292
|
+
#platform: macos
|
|
293
|
+
extern long nomen_menu_last_tag(void);
|
|
294
|
+
long tag = nomen_menu_last_tag();
|
|
295
|
+
return (int)tag;
|
|
296
|
+
```
|
|
297
|
+
```
|
|
298
|
+
#arch: aarch64_use_c
|
|
299
|
+
#platform: macos
|
|
300
|
+
extern long nomen_menu_last_tag(void);
|
|
301
|
+
long tag = nomen_menu_last_tag();
|
|
302
|
+
return (int)tag;
|
|
303
|
+
```
|
|
304
|
+
```
|
|
305
|
+
#arch: c
|
|
306
|
+
#platform: ios
|
|
307
|
+
/* TODO: iOS (see #init) */
|
|
308
|
+
return -1;
|
|
309
|
+
```
|
|
310
|
+
```
|
|
311
|
+
#arch: aarch64_use_c
|
|
312
|
+
#platform: ios
|
|
313
|
+
/* TODO: iOS (see #init) */
|
|
314
|
+
return -1;
|
|
315
|
+
```
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// The on_item_select desugar's drain (docs/HANDLERS.md): the synthesized
|
|
319
|
+
// pump arm polls this per frame. The selection is CONSUMED by the drain
|
|
320
|
+
// — like the poll, one record has one consumer, so a selection fires an
|
|
321
|
+
// arm exactly once — and the consumed tag is stashed for the handler
|
|
322
|
+
// body, which reads it through selected_item. The poll and the drain
|
|
323
|
+
// share one record: a selection consumed by one never reaches the other.
|
|
324
|
+
pub func take_item_select = (self, out bool) {
|
|
325
|
+
```
|
|
326
|
+
#arch: c
|
|
327
|
+
#platform: macos
|
|
328
|
+
extern unsigned char nomen_menu_take_select(void);
|
|
329
|
+
return nomen_menu_take_select();
|
|
330
|
+
```
|
|
331
|
+
```
|
|
332
|
+
#arch: aarch64_use_c
|
|
333
|
+
#platform: macos
|
|
334
|
+
extern unsigned char nomen_menu_take_select(void);
|
|
335
|
+
return nomen_menu_take_select();
|
|
336
|
+
```
|
|
337
|
+
```
|
|
338
|
+
#arch: c
|
|
339
|
+
#platform: ios
|
|
340
|
+
/* TODO: iOS (see #init) */
|
|
341
|
+
return false;
|
|
342
|
+
```
|
|
343
|
+
```
|
|
344
|
+
#arch: aarch64_use_c
|
|
345
|
+
#platform: ios
|
|
346
|
+
/* TODO: iOS (see #init) */
|
|
347
|
+
return false;
|
|
348
|
+
```
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// The tag the last take_item_select consumed (-1 before the first
|
|
352
|
+
// selection) — the handler body's payload getter. The control-scoped
|
|
353
|
+
// analog of the dispatch-window getters (win.click_x() et al): the
|
|
354
|
+
// record is the menu's own, so the payload rides the menu, not the
|
|
355
|
+
// window.
|
|
356
|
+
pub func selected_item = (self, out int) {
|
|
357
|
+
```
|
|
358
|
+
#arch: c
|
|
359
|
+
#platform: macos
|
|
360
|
+
extern long nomen_menu_selected_tag(void);
|
|
361
|
+
return (int)nomen_menu_selected_tag();
|
|
362
|
+
```
|
|
363
|
+
```
|
|
364
|
+
#arch: aarch64_use_c
|
|
365
|
+
#platform: macos
|
|
366
|
+
extern long nomen_menu_selected_tag(void);
|
|
367
|
+
return (int)nomen_menu_selected_tag();
|
|
368
|
+
```
|
|
369
|
+
```
|
|
370
|
+
#arch: c
|
|
371
|
+
#platform: ios
|
|
372
|
+
/* TODO: iOS (see #init) */
|
|
373
|
+
return -1;
|
|
374
|
+
```
|
|
375
|
+
```
|
|
376
|
+
#arch: aarch64_use_c
|
|
377
|
+
#platform: ios
|
|
378
|
+
/* TODO: iOS (see #init) */
|
|
379
|
+
return -1;
|
|
380
|
+
```
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// ── Control trait conformance ──
|
|
384
|
+
// A menu is not laid out: it has no frame of its own (it presents at the
|
|
385
|
+
// cursor under the attached control's right-click).
|
|
386
|
+
pub func set_frame = (ref self, int x, int y, int width, int height) {
|
|
387
|
+
// No-op: the menu presents at the cursor.
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
pub func intrinsic_size = (self, out Size) {
|
|
391
|
+
var s = Size()
|
|
392
|
+
return s
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
pub func measure = (self, BoxConstraints constraints, out Size) {
|
|
396
|
+
var s = Size()
|
|
397
|
+
return s
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
func #destroy = () {
|
|
401
|
+
```
|
|
402
|
+
#arch: c
|
|
403
|
+
#platform: macos
|
|
404
|
+
if (self->handle) {
|
|
405
|
+
((void(*)(id, SEL))objc_msgSend)((id)self->handle, sel_registerName("release"));
|
|
406
|
+
self->handle = 0;
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
```
|
|
410
|
+
#arch: aarch64_use_c
|
|
411
|
+
#platform: macos
|
|
412
|
+
if (self->handle) {
|
|
413
|
+
((void(*)(id, SEL))objc_msgSend)((id)self->handle, sel_registerName("release"));
|
|
414
|
+
self->handle = 0;
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
```
|
|
418
|
+
#arch: c
|
|
419
|
+
#platform: ios
|
|
420
|
+
/* TODO: iOS (see #init) */
|
|
421
|
+
```
|
|
422
|
+
```
|
|
423
|
+
#arch: aarch64_use_c
|
|
424
|
+
#platform: ios
|
|
425
|
+
/* TODO: iOS (see #init) */
|
|
426
|
+
```
|
|
427
|
+
}
|
|
428
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A number field with stepper nudges — TextBox + Stepper composed
|
|
3
|
+
*
|
|
4
|
+
* PURE COMPOSITION (GUI_PLAN Tier 3 "reachable earlier"): no new native
|
|
5
|
+
* control, no drawing — a TextBox for the text and a Stepper for the
|
|
6
|
+
* nudges, wired side by side into the caller's grid (the box fills the
|
|
7
|
+
* row, the stepper takes its intrinsic width).
|
|
8
|
+
*
|
|
9
|
+
* `set_value` drives both controls: the stepper holds the value, the text
|
|
10
|
+
* mirrors it (whole values as ints, fractions via the float's %f
|
|
11
|
+
* rendering). Stepper clicks update the stepper — but free-typed text is
|
|
12
|
+
* NOT parsed back in v1 (no string→float round-trip yet), so editing the
|
|
13
|
+
* text only changes the display until the next nudge. Hit-test the box and
|
|
14
|
+
* stepper through their handles (fields read like every control's
|
|
15
|
+
* `handle`).
|
|
16
|
+
**/
|
|
17
|
+
pub mv struct NumberInput {
|
|
18
|
+
var TextBox box
|
|
19
|
+
var Stepper step
|
|
20
|
+
|
|
21
|
+
pub func #init = (self, Window window) {
|
|
22
|
+
self.box = TextBox(window)
|
|
23
|
+
self.step = Stepper(window)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// The stepper's range and nudge size.
|
|
27
|
+
pub func set_range = (ref self, float min, float max, float increment) {
|
|
28
|
+
self.step.set_min(min)
|
|
29
|
+
self.step.set_max(max)
|
|
30
|
+
self.step.set_increment(increment)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Drive BOTH controls: the stepper holds the value, the text mirrors it
|
|
34
|
+
// (the float's %f rendering).
|
|
35
|
+
pub func set_value = (ref self, float v) {
|
|
36
|
+
self.step.set_value(v)
|
|
37
|
+
var text = v.to_string()
|
|
38
|
+
self.box.set_text(text)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// The current value (the stepper's — typed text is not parsed back in
|
|
42
|
+
// v1; the next nudge overwrites the text).
|
|
43
|
+
pub func value = (self, out float) {
|
|
44
|
+
return self.step.value()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Wire the pair into the caller's grid under `parent`: an hstack with
|
|
48
|
+
// the box filling the row and the stepper at its intrinsic width.
|
|
49
|
+
// Hit-testing works through the usual grid.contains on the fields'
|
|
50
|
+
// handles.
|
|
51
|
+
pub func add_to = (ref self, ref Container grid, int parent, int span) {
|
|
52
|
+
var int hs = grid.add_hstack(parent, 6, span)
|
|
53
|
+
grid.add_to(hs, self.box.handle, 0, 24, 1, 1)
|
|
54
|
+
grid.add_to_intrinsic(hs, self.step.handle, 1)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A one-time-code field — five SecureFields composed
|
|
3
|
+
*
|
|
4
|
+
* PURE COMPOSITION (GUI_PLAN Tier 3 "reachable earlier"): no new native
|
|
5
|
+
* control, no drawing — five single-character SecureFields wired in a row
|
|
6
|
+
* into the caller's grid. `code` concatenates whatever the five fields
|
|
7
|
+
* hold (incomplete codes read as-is — no per-field auto-advance in v1;
|
|
8
|
+
* fields are hit-tested through their handles like every control's).
|
|
9
|
+
**/
|
|
10
|
+
pub mv struct OtpInput {
|
|
11
|
+
var SecureField f0
|
|
12
|
+
var SecureField f1
|
|
13
|
+
var SecureField f2
|
|
14
|
+
var SecureField f3
|
|
15
|
+
var SecureField f4
|
|
16
|
+
|
|
17
|
+
pub func #init = (self, Window window) {
|
|
18
|
+
self.f0 = SecureField(window)
|
|
19
|
+
self.f1 = SecureField(window)
|
|
20
|
+
self.f2 = SecureField(window)
|
|
21
|
+
self.f3 = SecureField(window)
|
|
22
|
+
self.f4 = SecureField(window)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Wire the five fields into the caller's grid under `parent`: an hstack
|
|
26
|
+
// of fixed-width boxes.
|
|
27
|
+
pub func add_to = (ref self, ref Container grid, int parent, int span) {
|
|
28
|
+
var int hs = grid.add_hstack(parent, 8, span)
|
|
29
|
+
grid.add_to(hs, self.f0.handle, 36, 28, 0, 1)
|
|
30
|
+
grid.add_to(hs, self.f1.handle, 36, 28, 0, 1)
|
|
31
|
+
grid.add_to(hs, self.f2.handle, 36, 28, 0, 1)
|
|
32
|
+
grid.add_to(hs, self.f3.handle, 36, 28, 0, 1)
|
|
33
|
+
grid.add_to(hs, self.f4.handle, 36, 28, 0, 1)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// The concatenated contents of the five fields, in order.
|
|
37
|
+
pub func code = (self, out string) {
|
|
38
|
+
return self.f0.get_text() + self.f1.get_text() + self.f2.get_text()
|
|
39
|
+
+self.f3.get_text() + self.f4.get_text()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Empty every field.
|
|
43
|
+
pub func clear = (ref self) {
|
|
44
|
+
self.f0.set_text("")
|
|
45
|
+
self.f1.set_text("")
|
|
46
|
+
self.f2.set_text("")
|
|
47
|
+
self.f3.set_text("")
|
|
48
|
+
self.f4.set_text("")
|
|
49
|
+
}
|
|
50
|
+
}
|