@thi.ng/imgui 2.2.12 → 2.2.14

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/gui.js CHANGED
@@ -1,418 +1,403 @@
1
1
  import { set2 } from "@thi.ng/vectors/set";
2
- import { DEFAULT_THEME, Key, KeyModifier, MouseButton, NONE, } from "./api.js";
3
- export const defGUI = (opts) => new IMGUI(opts);
4
- export class IMGUI {
5
- attribs;
6
- layers;
7
- mouse;
8
- buttons;
9
- key;
10
- modifiers;
11
- prevMouse;
12
- prevButtons;
13
- prevKey;
14
- prevModifiers;
15
- hotID;
16
- activeID;
17
- focusID;
18
- lastID;
19
- cursor;
20
- t0;
21
- time;
22
- draw;
23
- currIDs;
24
- prevIDs;
25
- themeStack;
26
- disabledStack;
27
- resources;
28
- states;
29
- sizes;
30
- constructor(opts) {
31
- this.mouse = [-1e3, -1e3];
32
- this.prevMouse = [-1e3, -1e3];
33
- this.key = this.prevKey = "";
34
- this.buttons =
35
- this.prevButtons =
36
- this.modifiers =
37
- this.prevModifiers =
38
- 0;
39
- this.hotID = this.activeID = this.focusID = this.lastID = "";
40
- this.currIDs = new Set();
41
- this.prevIDs = new Set();
42
- this.resources = new Map();
43
- this.sizes = new Map();
44
- this.states = new Map();
45
- this.layers = [[], []];
46
- this.attribs = {};
47
- this.cursor = "default";
48
- this.disabledStack = [false];
49
- this.setTheme(opts.theme || {});
50
- this.draw = true;
51
- this.t0 = Date.now();
52
- }
53
- get theme() {
54
- const stack = this.themeStack;
55
- return stack[stack.length - 1];
56
- }
57
- get disabled() {
58
- const stack = this.disabledStack;
59
- return stack[stack.length - 1];
60
- }
61
- /**
62
- * Clears all shape layers and resets theme / disabled stacks.
63
- */
64
- clear() {
65
- this.layers[0].length = 0;
66
- this.layers[1].length = 0;
67
- this.themeStack.length = 1;
68
- this.disabledStack.length = 1;
69
- }
70
- /**
71
- * Sets mouse position and current mouse button flags (i.e.
72
- * `MouseEvent.buttons`).
73
- *
74
- * @param p -
75
- * @param buttons -
76
- */
77
- setMouse(p, buttons) {
78
- set2(this.prevMouse, this.mouse);
79
- set2(this.mouse, p);
80
- this.prevButtons = this.buttons;
81
- this.buttons = buttons;
82
- return this;
83
- }
84
- /**
85
- * Sets internal key state from given key event details.
86
- *
87
- * @param e -
88
- */
89
- setKey(e) {
90
- if (e.type === "keydown") {
91
- this.prevKey = this.key;
92
- this.key = e.key;
93
- }
94
- this.prevModifiers = this.modifiers;
95
- this.modifiers =
96
- (~~e.shiftKey * KeyModifier.SHIFT) |
97
- (~~e.ctrlKey * KeyModifier.CONTROL) |
98
- (~~e.metaKey * KeyModifier.META) |
99
- (~~e.altKey * KeyModifier.ALT);
100
- return this;
101
- }
102
- /**
103
- * Merges given theme settings with {@link DEFAULT_THEME} and resets theme
104
- * stack.
105
- *
106
- * @param theme -
107
- */
108
- setTheme(theme) {
109
- this.themeStack = [{ ...DEFAULT_THEME, ...theme }];
110
- }
111
- /**
112
- * Merges given theme settings with current theme and pushes result
113
- * on theme stack.
114
- *
115
- * IMPORTANT: Currently IMGUI only supports one font and ignores any
116
- * font changes pushed on the theme stack.
117
- *
118
- * @param theme -
119
- */
120
- beginTheme(theme) {
121
- const stack = this.themeStack;
122
- stack.push({ ...stack[stack.length - 1], ...theme });
123
- }
124
- /**
125
- * Removes current theme from stack (unless only one theme left).
126
- */
127
- endTheme() {
128
- __popIfNotLast(this.themeStack);
129
- }
130
- /**
131
- * Applies component function with given theme, then restores
132
- * previous theme and returns component result.
133
- *
134
- * @param theme -
135
- * @param component -
136
- */
137
- withTheme(theme, component) {
138
- this.beginTheme(theme);
139
- const res = component();
140
- this.themeStack.pop();
141
- return res;
142
- }
143
- /**
144
- * Pushes given disabled component state flag on stack (default:
145
- * true, i.e. disabled). Pass `false` to temporarily enable
146
- * components.
147
- *
148
- * @param disabled -
149
- */
150
- beginDisabled(disabled = true) {
151
- this.disabledStack.push(disabled);
152
- }
153
- /**
154
- * Removes current disabled flag from stack (unless only one theme left).
155
- */
156
- endDisabled() {
157
- __popIfNotLast(this.disabledStack);
158
- }
159
- /**
160
- * Applies component function with given disabled flag, then
161
- * restores previous disabled state and returns component result.
162
- *
163
- * @param disabled -
164
- * @param component -
165
- */
166
- withDisabled(disabled, component) {
167
- this.disabledStack.push(disabled);
168
- const res = component();
169
- this.disabledStack.pop();
170
- return res;
171
- }
172
- /**
173
- * Sets `focusID` to given `id` if the component can receive focus.
174
- * Returns true if component is focused.
175
- *
176
- * @param id -
177
- */
178
- requestFocus(id) {
179
- if (this.disabled)
180
- return false;
181
- if (this.focusID === "" || this.activeID === id) {
182
- this.focusID = id;
183
- return true;
184
- }
185
- return this.focusID === id;
186
- }
187
- /**
188
- * Attempts to switch focus to next, or if Shift is pressed, to
189
- * previous component. This is meant be called ONLY from component
190
- * key handlers.
191
- */
192
- switchFocus() {
193
- this.focusID = this.isShiftDown() ? this.lastID : "";
194
- this.key = "";
195
- }
196
- /**
197
- * Returns true if left mouse button is pressed.
198
- */
199
- isMouseDown() {
200
- return (this.buttons & MouseButton.LEFT) > 0;
201
- }
202
- isShiftDown() {
203
- return (this.modifiers & KeyModifier.SHIFT) > 0;
204
- }
205
- isControlDown() {
206
- return (this.modifiers & KeyModifier.CONTROL) > 0;
207
- }
208
- isMetaDown() {
209
- return (this.modifiers & KeyModifier.META) > 0;
210
- }
211
- isAltDown() {
212
- return (this.modifiers & KeyModifier.ALT) > 0;
213
- }
214
- isPrevMouseDown() {
215
- return (this.prevButtons & MouseButton.LEFT) > 0;
216
- }
217
- isPrevShiftDown() {
218
- return (this.prevModifiers & KeyModifier.SHIFT) > 0;
219
- }
220
- isPrevControlDown() {
221
- return (this.prevModifiers & KeyModifier.CONTROL) > 0;
222
- }
223
- isPrevMetaDown() {
224
- return (this.prevModifiers & KeyModifier.META) > 0;
225
- }
226
- isPrevAltDown() {
227
- return (this.prevModifiers & KeyModifier.ALT) > 0;
228
- }
229
- /**
230
- * Prepares IMGUI for next frame:
231
- *
232
- * - Resets `hotID`, `cursor`
233
- * - Resets theme & disabled stacks
234
- * - Clears all draw layers
235
- * - Updates elapsed time.
236
- *
237
- * By default all components will emit draw shapes, however this can
238
- * be disabled by passing `false` as argument. This is useful for
239
- * use cases where the GUI is not updated at high frame rates and so
240
- * would require two invocations per update cycle for immediate
241
- * visual feedback:
242
- *
243
- * ```
244
- * gui.begin(false); // update state only, no draw
245
- * updateMyGUI();
246
- * gui.end();
247
- * gui.begin(true); // run once more, with draw enabled (default)
248
- * updateMyGUI();
249
- * gui.end();
250
- * ```
251
- *
252
- * @param draw -
253
- */
254
- begin(draw = true) {
255
- this.hotID = "";
256
- this.cursor = "default";
257
- this.draw = draw;
258
- this.clear();
259
- this.time = (Date.now() - this.t0) * 1e-3;
260
- }
261
- /**
262
- * Performs end-of-frame handling & component cache cleanup. Also
263
- * removes cached state and resources of all unused components.
264
- */
265
- end() {
266
- if (!this.buttons) {
267
- this.activeID = "";
268
- }
269
- else {
270
- if (this.activeID === "") {
271
- this.activeID = NONE;
272
- this.focusID = NONE;
273
- this.lastID = "";
274
- }
275
- }
276
- this.key === Key.TAB && (this.focusID = "");
277
- this.key = "";
278
- this.gc();
279
- }
280
- /**
281
- * Garbage collect unused component state / resources.
282
- */
283
- gc() {
284
- const { currIDs, prevIDs } = this;
285
- for (let id of prevIDs) {
286
- if (!currIDs.has(id)) {
287
- this.resources.delete(id);
288
- this.sizes.delete(id);
289
- this.states.delete(id);
290
- }
291
- }
292
- this.prevIDs = currIDs;
293
- this.currIDs = prevIDs;
294
- prevIDs.clear();
295
- }
296
- bgColor(hover) {
297
- return this.disabled
298
- ? this.theme.bgDisabled
299
- : hover
300
- ? this.theme.bgHover
301
- : this.theme.bg;
302
- }
303
- fgColor(hover) {
304
- return this.disabled
305
- ? this.theme.fgDisabled
306
- : hover
307
- ? this.theme.fgHover
308
- : this.theme.fg;
309
- }
310
- textColor(hover) {
311
- return this.disabled
312
- ? this.theme.textDisabled
313
- : hover
314
- ? this.theme.textHover
315
- : this.theme.text;
316
- }
317
- focusColor(id) {
318
- return this.focusID === id ? this.theme.focus : undefined;
319
- }
320
- /**
321
- * Returns pixel width of given string based on current theme's font
322
- * settings.
323
- *
324
- * IMPORTANT: Currently only monospace fonts are supported.
325
- *
326
- * @param txt -
327
- */
328
- textWidth(txt) {
329
- return this.theme.charWidth * txt.length;
330
- }
331
- /**
332
- * Marks given component ID as used and checks `hash` to determine
333
- * if the component's resource cache should be cleared. This hash
334
- * value should be based on any values (e.g. layout info) which
335
- * might invalidate cached resources.
336
- *
337
- * @param id -
338
- * @param hash -
339
- */
340
- registerID(id, hash) {
341
- this.currIDs.add(id);
342
- if (this.sizes.get(id) !== hash) {
343
- // console.warn("cache miss:", id, hash);
344
- this.sizes.set(id, hash);
345
- this.resources.delete(id);
346
- }
347
- }
348
- /**
349
- * Attempts to retrieve cached resource for given component `id` and
350
- * resource `hash`. If unsuccessful, calls resource `ctor` function
351
- * to create it, caches result and returns it.
352
- *
353
- * {@link IMGUI.registerID}
354
- *
355
- * @param id -
356
- * @param hash -
357
- * @param ctor -
358
- */
359
- resource(id, hash, ctor) {
360
- let res;
361
- let c = this.resources.get(id);
362
- !c && this.resources.set(id, (c = new Map()));
363
- return c.get(hash) || (c.set(hash, (res = ctor())), res);
364
- }
365
- /**
366
- * Attempts to retrieve cached component state for given `id`. If
367
- * unsuccessful, calls state `ctor` function, caches result and
368
- * returns it.
369
- *
370
- * @param id -
371
- * @param ctor -
372
- */
373
- state(id, ctor) {
374
- let res = this.states.get(id);
375
- return res !== undefined
376
- ? res
377
- : (this.states.set(id, (res = ctor())), res);
378
- }
379
- /**
380
- * Stores / overrides given local state value for component `id` in
381
- * cache.
382
- *
383
- * @param id -
384
- * @param state -
385
- */
386
- setState(id, state) {
387
- this.states.set(id, state);
388
- }
389
- /**
390
- * Sets cursor property to given `id`. This setting is cleared at
391
- * the beginning of each frame (default value: "default").
392
- *
393
- * @param id -
394
- */
395
- setCursor(id) {
396
- this.cursor = id;
397
- }
398
- add(...els) {
399
- this.layers[0].push(...els);
400
- }
401
- addOverlay(...els) {
402
- this.layers[1].push(...els);
403
- }
404
- /**
405
- * Returns hiccup representation of all shapes/text primitives
406
- * created by components in the current frame.
407
- */
408
- toHiccup() {
409
- return [
410
- "g",
411
- { font: this.theme.font },
412
- ...this.layers[0],
413
- ...this.layers[1],
414
- ];
415
- }
2
+ import {
3
+ DEFAULT_THEME,
4
+ Key,
5
+ KeyModifier,
6
+ MouseButton,
7
+ NONE
8
+ } from "./api.js";
9
+ const defGUI = (opts) => new IMGUI(opts);
10
+ class IMGUI {
11
+ attribs;
12
+ layers;
13
+ mouse;
14
+ buttons;
15
+ key;
16
+ modifiers;
17
+ prevMouse;
18
+ prevButtons;
19
+ prevKey;
20
+ prevModifiers;
21
+ hotID;
22
+ activeID;
23
+ focusID;
24
+ lastID;
25
+ cursor;
26
+ t0;
27
+ time;
28
+ draw;
29
+ currIDs;
30
+ prevIDs;
31
+ themeStack;
32
+ disabledStack;
33
+ resources;
34
+ states;
35
+ sizes;
36
+ constructor(opts) {
37
+ this.mouse = [-1e3, -1e3];
38
+ this.prevMouse = [-1e3, -1e3];
39
+ this.key = this.prevKey = "";
40
+ this.buttons = this.prevButtons = this.modifiers = this.prevModifiers = 0;
41
+ this.hotID = this.activeID = this.focusID = this.lastID = "";
42
+ this.currIDs = /* @__PURE__ */ new Set();
43
+ this.prevIDs = /* @__PURE__ */ new Set();
44
+ this.resources = /* @__PURE__ */ new Map();
45
+ this.sizes = /* @__PURE__ */ new Map();
46
+ this.states = /* @__PURE__ */ new Map();
47
+ this.layers = [[], []];
48
+ this.attribs = {};
49
+ this.cursor = "default";
50
+ this.disabledStack = [false];
51
+ this.setTheme(opts.theme || {});
52
+ this.draw = true;
53
+ this.t0 = Date.now();
54
+ }
55
+ get theme() {
56
+ const stack = this.themeStack;
57
+ return stack[stack.length - 1];
58
+ }
59
+ get disabled() {
60
+ const stack = this.disabledStack;
61
+ return stack[stack.length - 1];
62
+ }
63
+ /**
64
+ * Clears all shape layers and resets theme / disabled stacks.
65
+ */
66
+ clear() {
67
+ this.layers[0].length = 0;
68
+ this.layers[1].length = 0;
69
+ this.themeStack.length = 1;
70
+ this.disabledStack.length = 1;
71
+ }
72
+ /**
73
+ * Sets mouse position and current mouse button flags (i.e.
74
+ * `MouseEvent.buttons`).
75
+ *
76
+ * @param p -
77
+ * @param buttons -
78
+ */
79
+ setMouse(p, buttons) {
80
+ set2(this.prevMouse, this.mouse);
81
+ set2(this.mouse, p);
82
+ this.prevButtons = this.buttons;
83
+ this.buttons = buttons;
84
+ return this;
85
+ }
86
+ /**
87
+ * Sets internal key state from given key event details.
88
+ *
89
+ * @param e -
90
+ */
91
+ setKey(e) {
92
+ if (e.type === "keydown") {
93
+ this.prevKey = this.key;
94
+ this.key = e.key;
95
+ }
96
+ this.prevModifiers = this.modifiers;
97
+ this.modifiers = ~~e.shiftKey * KeyModifier.SHIFT | ~~e.ctrlKey * KeyModifier.CONTROL | ~~e.metaKey * KeyModifier.META | ~~e.altKey * KeyModifier.ALT;
98
+ return this;
99
+ }
100
+ /**
101
+ * Merges given theme settings with {@link DEFAULT_THEME} and resets theme
102
+ * stack.
103
+ *
104
+ * @param theme -
105
+ */
106
+ setTheme(theme) {
107
+ this.themeStack = [{ ...DEFAULT_THEME, ...theme }];
108
+ }
109
+ /**
110
+ * Merges given theme settings with current theme and pushes result
111
+ * on theme stack.
112
+ *
113
+ * IMPORTANT: Currently IMGUI only supports one font and ignores any
114
+ * font changes pushed on the theme stack.
115
+ *
116
+ * @param theme -
117
+ */
118
+ beginTheme(theme) {
119
+ const stack = this.themeStack;
120
+ stack.push({ ...stack[stack.length - 1], ...theme });
121
+ }
122
+ /**
123
+ * Removes current theme from stack (unless only one theme left).
124
+ */
125
+ endTheme() {
126
+ __popIfNotLast(this.themeStack);
127
+ }
128
+ /**
129
+ * Applies component function with given theme, then restores
130
+ * previous theme and returns component result.
131
+ *
132
+ * @param theme -
133
+ * @param component -
134
+ */
135
+ withTheme(theme, component) {
136
+ this.beginTheme(theme);
137
+ const res = component();
138
+ this.themeStack.pop();
139
+ return res;
140
+ }
141
+ /**
142
+ * Pushes given disabled component state flag on stack (default:
143
+ * true, i.e. disabled). Pass `false` to temporarily enable
144
+ * components.
145
+ *
146
+ * @param disabled -
147
+ */
148
+ beginDisabled(disabled = true) {
149
+ this.disabledStack.push(disabled);
150
+ }
151
+ /**
152
+ * Removes current disabled flag from stack (unless only one theme left).
153
+ */
154
+ endDisabled() {
155
+ __popIfNotLast(this.disabledStack);
156
+ }
157
+ /**
158
+ * Applies component function with given disabled flag, then
159
+ * restores previous disabled state and returns component result.
160
+ *
161
+ * @param disabled -
162
+ * @param component -
163
+ */
164
+ withDisabled(disabled, component) {
165
+ this.disabledStack.push(disabled);
166
+ const res = component();
167
+ this.disabledStack.pop();
168
+ return res;
169
+ }
170
+ /**
171
+ * Sets `focusID` to given `id` if the component can receive focus.
172
+ * Returns true if component is focused.
173
+ *
174
+ * @param id -
175
+ */
176
+ requestFocus(id) {
177
+ if (this.disabled)
178
+ return false;
179
+ if (this.focusID === "" || this.activeID === id) {
180
+ this.focusID = id;
181
+ return true;
182
+ }
183
+ return this.focusID === id;
184
+ }
185
+ /**
186
+ * Attempts to switch focus to next, or if Shift is pressed, to
187
+ * previous component. This is meant be called ONLY from component
188
+ * key handlers.
189
+ */
190
+ switchFocus() {
191
+ this.focusID = this.isShiftDown() ? this.lastID : "";
192
+ this.key = "";
193
+ }
194
+ /**
195
+ * Returns true if left mouse button is pressed.
196
+ */
197
+ isMouseDown() {
198
+ return (this.buttons & MouseButton.LEFT) > 0;
199
+ }
200
+ isShiftDown() {
201
+ return (this.modifiers & KeyModifier.SHIFT) > 0;
202
+ }
203
+ isControlDown() {
204
+ return (this.modifiers & KeyModifier.CONTROL) > 0;
205
+ }
206
+ isMetaDown() {
207
+ return (this.modifiers & KeyModifier.META) > 0;
208
+ }
209
+ isAltDown() {
210
+ return (this.modifiers & KeyModifier.ALT) > 0;
211
+ }
212
+ isPrevMouseDown() {
213
+ return (this.prevButtons & MouseButton.LEFT) > 0;
214
+ }
215
+ isPrevShiftDown() {
216
+ return (this.prevModifiers & KeyModifier.SHIFT) > 0;
217
+ }
218
+ isPrevControlDown() {
219
+ return (this.prevModifiers & KeyModifier.CONTROL) > 0;
220
+ }
221
+ isPrevMetaDown() {
222
+ return (this.prevModifiers & KeyModifier.META) > 0;
223
+ }
224
+ isPrevAltDown() {
225
+ return (this.prevModifiers & KeyModifier.ALT) > 0;
226
+ }
227
+ /**
228
+ * Prepares IMGUI for next frame:
229
+ *
230
+ * - Resets `hotID`, `cursor`
231
+ * - Resets theme & disabled stacks
232
+ * - Clears all draw layers
233
+ * - Updates elapsed time.
234
+ *
235
+ * By default all components will emit draw shapes, however this can
236
+ * be disabled by passing `false` as argument. This is useful for
237
+ * use cases where the GUI is not updated at high frame rates and so
238
+ * would require two invocations per update cycle for immediate
239
+ * visual feedback:
240
+ *
241
+ * ```
242
+ * gui.begin(false); // update state only, no draw
243
+ * updateMyGUI();
244
+ * gui.end();
245
+ * gui.begin(true); // run once more, with draw enabled (default)
246
+ * updateMyGUI();
247
+ * gui.end();
248
+ * ```
249
+ *
250
+ * @param draw -
251
+ */
252
+ begin(draw = true) {
253
+ this.hotID = "";
254
+ this.cursor = "default";
255
+ this.draw = draw;
256
+ this.clear();
257
+ this.time = (Date.now() - this.t0) * 1e-3;
258
+ }
259
+ /**
260
+ * Performs end-of-frame handling & component cache cleanup. Also
261
+ * removes cached state and resources of all unused components.
262
+ */
263
+ end() {
264
+ if (!this.buttons) {
265
+ this.activeID = "";
266
+ } else {
267
+ if (this.activeID === "") {
268
+ this.activeID = NONE;
269
+ this.focusID = NONE;
270
+ this.lastID = "";
271
+ }
272
+ }
273
+ this.key === Key.TAB && (this.focusID = "");
274
+ this.key = "";
275
+ this.gc();
276
+ }
277
+ /**
278
+ * Garbage collect unused component state / resources.
279
+ */
280
+ gc() {
281
+ const { currIDs, prevIDs } = this;
282
+ for (let id of prevIDs) {
283
+ if (!currIDs.has(id)) {
284
+ this.resources.delete(id);
285
+ this.sizes.delete(id);
286
+ this.states.delete(id);
287
+ }
288
+ }
289
+ this.prevIDs = currIDs;
290
+ this.currIDs = prevIDs;
291
+ prevIDs.clear();
292
+ }
293
+ bgColor(hover) {
294
+ return this.disabled ? this.theme.bgDisabled : hover ? this.theme.bgHover : this.theme.bg;
295
+ }
296
+ fgColor(hover) {
297
+ return this.disabled ? this.theme.fgDisabled : hover ? this.theme.fgHover : this.theme.fg;
298
+ }
299
+ textColor(hover) {
300
+ return this.disabled ? this.theme.textDisabled : hover ? this.theme.textHover : this.theme.text;
301
+ }
302
+ focusColor(id) {
303
+ return this.focusID === id ? this.theme.focus : void 0;
304
+ }
305
+ /**
306
+ * Returns pixel width of given string based on current theme's font
307
+ * settings.
308
+ *
309
+ * IMPORTANT: Currently only monospace fonts are supported.
310
+ *
311
+ * @param txt -
312
+ */
313
+ textWidth(txt) {
314
+ return this.theme.charWidth * txt.length;
315
+ }
316
+ /**
317
+ * Marks given component ID as used and checks `hash` to determine
318
+ * if the component's resource cache should be cleared. This hash
319
+ * value should be based on any values (e.g. layout info) which
320
+ * might invalidate cached resources.
321
+ *
322
+ * @param id -
323
+ * @param hash -
324
+ */
325
+ registerID(id, hash) {
326
+ this.currIDs.add(id);
327
+ if (this.sizes.get(id) !== hash) {
328
+ this.sizes.set(id, hash);
329
+ this.resources.delete(id);
330
+ }
331
+ }
332
+ /**
333
+ * Attempts to retrieve cached resource for given component `id` and
334
+ * resource `hash`. If unsuccessful, calls resource `ctor` function
335
+ * to create it, caches result and returns it.
336
+ *
337
+ * {@link IMGUI.registerID}
338
+ *
339
+ * @param id -
340
+ * @param hash -
341
+ * @param ctor -
342
+ */
343
+ resource(id, hash, ctor) {
344
+ let res;
345
+ let c = this.resources.get(id);
346
+ !c && this.resources.set(id, c = /* @__PURE__ */ new Map());
347
+ return c.get(hash) || (c.set(hash, res = ctor()), res);
348
+ }
349
+ /**
350
+ * Attempts to retrieve cached component state for given `id`. If
351
+ * unsuccessful, calls state `ctor` function, caches result and
352
+ * returns it.
353
+ *
354
+ * @param id -
355
+ * @param ctor -
356
+ */
357
+ state(id, ctor) {
358
+ let res = this.states.get(id);
359
+ return res !== void 0 ? res : (this.states.set(id, res = ctor()), res);
360
+ }
361
+ /**
362
+ * Stores / overrides given local state value for component `id` in
363
+ * cache.
364
+ *
365
+ * @param id -
366
+ * @param state -
367
+ */
368
+ setState(id, state) {
369
+ this.states.set(id, state);
370
+ }
371
+ /**
372
+ * Sets cursor property to given `id`. This setting is cleared at
373
+ * the beginning of each frame (default value: "default").
374
+ *
375
+ * @param id -
376
+ */
377
+ setCursor(id) {
378
+ this.cursor = id;
379
+ }
380
+ add(...els) {
381
+ this.layers[0].push(...els);
382
+ }
383
+ addOverlay(...els) {
384
+ this.layers[1].push(...els);
385
+ }
386
+ /**
387
+ * Returns hiccup representation of all shapes/text primitives
388
+ * created by components in the current frame.
389
+ */
390
+ toHiccup() {
391
+ return [
392
+ "g",
393
+ { font: this.theme.font },
394
+ ...this.layers[0],
395
+ ...this.layers[1]
396
+ ];
397
+ }
416
398
  }
417
- /** @internal */
418
399
  const __popIfNotLast = (stack) => stack.length > 1 && stack.pop();
400
+ export {
401
+ IMGUI,
402
+ defGUI
403
+ };