载入中...
搜索中...
未找到
UI.cpp
浏览该文件的文档.
1#include "ui/UI.h"
2#include "ui/DatabasePanel.h"
4#include "ui/EditorShell.h"
5#include "ui/EventSinkOwner.h"
6#include "ui/ObjectRegistry.h"
10#include "ui/PcgLoadingScreen.h"
19#include "ui/PcgTooltip.h"
21
22#include "ui/Inspector.h"
23#include "ui/ScenePanel.h"
24#include "ui/Theme.h"
25#include "ui/UISystem.h"
26#include "ui/Widget.h"
27#include "ui/ParentScaler.h"
28
29#include "common/Capability.h"
30#include "common/Module.h"
31#include "common/Json.h"
32#include "common/Value.h"
35#include "common/config.h"
36#include "graphics/Graphics.h"
37#include "image/Image.h"
38#include "image/ImageData.h"
40#include "window/Window.h"
41#include "window/sdl/Window.h"
42
43#include <SDL2/SDL_events.h>
44#include <squirrel.h>
45#include <simplesquirrel/simplesquirrel.hpp>
46
47#if !(defined(EVENGINE_WEBGPU) && defined(__EMSCRIPTEN__))
48#include <Poco/JSON/Array.h>
49#include <Poco/JSON/Object.h>
50#include <Poco/JSON/Parser.h>
51#include <Poco/JSON/Stringifier.h>
52#endif
53
54#include <algorithm>
55#include <cstdio>
56#include <cstring>
57#include <iterator>
58#include <sstream>
59#include <stdexcept>
60
61namespace eve::ui {
62namespace {
63
64UI *uiFromStack(HSQUIRRELVM vm) {
65 UI *self = nullptr;
66 if (SQ_FAILED(sq_getinstanceup(vm, 1, reinterpret_cast<SQUserPointer *>(&self), nullptr)) || !self) return nullptr;
67 return self;
68}
69
70std::string optionalEase(HSQUIRRELVM vm, SQInteger idx, SQInteger n) {
71 if (n < idx) return "smoothstep";
72 const SQChar *ease = nullptr;
73 if (SQ_FAILED(sq_getstring(vm, idx, &ease)) || !ease) return "smoothstep";
74 return ease;
75}
76
77float optionalDelay(HSQUIRRELVM vm, SQInteger idx, SQInteger n) {
78 if (n < idx) return 0.f;
79 SQFloat delay = 0.f;
80 if (SQ_FAILED(sq_getfloat(vm, idx, &delay))) return 0.f;
81 return float(delay);
82}
83
85SQInteger sqAnimateHostPos(HSQUIRRELVM vm) {
86 const SQInteger n = sq_gettop(vm);
87 if (n < 4 || n > 6) return sq_throwerror(vm, "UI.animateHostPos expects (x, y, durationMs [, ease [, delayMs]])");
88 UI *self = uiFromStack(vm);
89 if (!self) return sq_throwerror(vm, "invalid UI");
90 SQFloat x = 0.f, y = 0.f, durationMs = 0.f;
91 if (SQ_FAILED(sq_getfloat(vm, 2, &x)) || SQ_FAILED(sq_getfloat(vm, 3, &y)) ||
92 SQ_FAILED(sq_getfloat(vm, 4, &durationMs)))
93 return sq_throwerror(vm, "UI.animateHostPos expects float x/y/durationMs");
94 self->animateHostPos(float(x), float(y), float(durationMs), optionalEase(vm, 5, n), optionalDelay(vm, 6, n));
95 return 0;
96}
97
99SQInteger sqAnimateHostSize(HSQUIRRELVM vm) {
100 const SQInteger n = sq_gettop(vm);
101 if (n < 4 || n > 6) return sq_throwerror(vm, "UI.animateHostSize expects (w, h, durationMs [, ease [, delayMs]])");
102 UI *self = uiFromStack(vm);
103 if (!self) return sq_throwerror(vm, "invalid UI");
104 SQFloat w = 0.f, h = 0.f, durationMs = 0.f;
105 if (SQ_FAILED(sq_getfloat(vm, 2, &w)) || SQ_FAILED(sq_getfloat(vm, 3, &h)) ||
106 SQ_FAILED(sq_getfloat(vm, 4, &durationMs)))
107 return sq_throwerror(vm, "UI.animateHostSize expects float w/h/durationMs");
108 self->animateHostSize(float(w), float(h), float(durationMs), optionalEase(vm, 5, n), optionalDelay(vm, 6, n));
109 return 0;
110}
111
113SQInteger sqAnimateHostOverlayAlpha(HSQUIRRELVM vm) {
114 const SQInteger n = sq_gettop(vm);
115 if (n < 3 || n > 5)
116 return sq_throwerror(vm, "UI.animateHostOverlayAlpha expects (alpha, durationMs [, ease [, delayMs]])");
117 UI *self = uiFromStack(vm);
118 if (!self) return sq_throwerror(vm, "invalid UI");
119 SQFloat alpha = 0.f, durationMs = 0.f;
120 if (SQ_FAILED(sq_getfloat(vm, 2, &alpha)) || SQ_FAILED(sq_getfloat(vm, 3, &durationMs)))
121 return sq_throwerror(vm, "UI.animateHostOverlayAlpha expects float alpha/durationMs");
122 self->animateHostOverlayAlpha(float(alpha), float(durationMs), optionalEase(vm, 4, n), optionalDelay(vm, 5, n));
123 return 0;
124}
125
127SQInteger sqAnimateItemOpacity(HSQUIRRELVM vm) {
128 const SQInteger n = sq_gettop(vm);
129 if (n < 4 || n > 6)
130 return sq_throwerror(vm, "UI.animateItemOpacity expects (id, opacity, durationMs [, ease [, delayMs]])");
131 UI *self = uiFromStack(vm);
132 if (!self) return sq_throwerror(vm, "invalid UI");
133 const SQChar *id = nullptr;
134 SQFloat opacity = 0.f, durationMs = 0.f;
135 if (SQ_FAILED(sq_getstring(vm, 2, &id)) || SQ_FAILED(sq_getfloat(vm, 3, &opacity)) ||
136 SQ_FAILED(sq_getfloat(vm, 4, &durationMs)))
137 return sq_throwerror(vm, "UI.animateItemOpacity expects (string id, float opacity, float durationMs)");
138 self->animateItemOpacity(id ? id : "", float(opacity), float(durationMs), optionalEase(vm, 5, n),
139 optionalDelay(vm, 6, n));
140 return 0;
141}
142
144SQInteger sqAnimateItemPos(HSQUIRRELVM vm) {
145 const SQInteger n = sq_gettop(vm);
146 if (n < 5 || n > 7)
147 return sq_throwerror(vm, "UI.animateItemPos expects (id, x, y, durationMs [, ease [, delayMs]])");
148 UI *self = uiFromStack(vm);
149 if (!self) return sq_throwerror(vm, "invalid UI");
150 const SQChar *id = nullptr;
151 SQFloat x = 0.f, y = 0.f, durationMs = 0.f;
152 if (SQ_FAILED(sq_getstring(vm, 2, &id)) || SQ_FAILED(sq_getfloat(vm, 3, &x)) || SQ_FAILED(sq_getfloat(vm, 4, &y)) ||
153 SQ_FAILED(sq_getfloat(vm, 5, &durationMs)))
154 return sq_throwerror(vm, "UI.animateItemPos expects (string id, float x/y/durationMs)");
155 self->animateItemPos(id ? id : "", float(x), float(y), float(durationMs), optionalEase(vm, 6, n),
156 optionalDelay(vm, 7, n));
157 return 0;
158}
159
161SQInteger sqCancelItemTweens(HSQUIRRELVM vm) {
162 const SQInteger n = sq_gettop(vm);
163 if (n < 1 || n > 2) return sq_throwerror(vm, "UI.cancelItemTweens expects ([id])");
164 UI *self = uiFromStack(vm);
165 if (!self) return sq_throwerror(vm, "invalid UI");
166 if (n < 2) {
167 self->cancelItemTweens("");
168 return 0;
169 }
170 const SQChar *id = nullptr;
171 if (SQ_FAILED(sq_getstring(vm, 2, &id))) return sq_throwerror(vm, "UI.cancelItemTweens id must be a string");
172 self->cancelItemTweens(id ? id : "");
173 return 0;
174}
175
176void addOptionalTweenFunc(ssq::Class &cls, const char *name, SQFUNCTION func, SQInteger minParams,
177 const SQChar *typemask) {
178 HSQUIRRELVM vm = cls.getHandle();
179 sq_pushobject(vm, cls.getRaw());
180 sq_pushstring(vm, name, -1);
181 sq_newclosure(vm, func, 0);
182 sq_setparamscheck(vm, -minParams, typemask);
183 sq_newslot(vm, -3, SQFalse);
184 sq_poptop(vm);
185}
186
187std::string jsonQuoted(const std::string &value) {
188 std::string out = "\"";
189 for (const unsigned char ch : value) {
190 switch (ch) {
191 case '\"': out += "\\\""; break;
192 case '\\': out += "\\\\"; break;
193 case '\n': out += "\\n"; break;
194 case '\r': out += "\\r"; break;
195 case '\t': out += "\\t"; break;
196 default:
197 if (ch >= 0x20) out += static_cast<char>(ch);
198 break;
199 }
200 }
201 out += '\"';
202 return out;
203}
204
206void callScriptHandler(ssq::Function &fn, const std::string &kind, const UIEvent &ev) {
207 HSQUIRRELVM vm = fn.getHandle();
208 if (!vm) return;
209 const SQInteger top = sq_gettop(vm);
210 sq_pushobject(vm, fn.getRaw());
211 sq_pushroottable(vm); // env
212 if (kind == "click") {
213 if (SQ_FAILED(sq_call(vm, 1, SQFalse, SQTrue))) {
214 sq_settop(vm, top);
215 return;
216 }
217 } else {
218 sq_pushstring(vm, kind.c_str(), -1);
219 if (kind == "toggle") sq_pushbool(vm, ev.toggleValue ? SQTrue : SQFalse);
220 else if (kind == "value") sq_pushfloat(vm, ev.floatValue);
221 else sq_pushstring(vm, ev.textValue.c_str(), -1);
222 if (SQ_FAILED(sq_call(vm, 3, SQFalse, SQTrue))) {
223 sq_settop(vm, top);
224 return;
225 }
226 }
227 sq_settop(vm, top);
228}
229
230#if !(defined(EVENGINE_WEBGPU) && defined(__EMSCRIPTEN__))
231// JSON UI asset helpers (defined below saveTreeJson/loadTreeJson).
232void nodeToJson(const UIHost::Tree &tree, const UINode &n, Poco::JSON::Object &o);
233WidgetDesc descFromJson(const Poco::JSON::Object &o);
234#endif
235
237const char *kUIComponentScript = R"SQ(
238if (!("_uiComponents" in eve)) eve._uiComponents <- []
239if (!("_nextUIComponentOwner" in eve)) eve._nextUIComponentOwner <- 0
240
241eve._scheduleUIComponent <- function(component) {
242 if (component == null || component._scheduled) return
243 component._scheduled = true
244 eve._uiComponents.append(component)
245}
246
247eve._flushUIComponents <- function() {
248 local pending = eve._uiComponents
249 eve._uiComponents = []
250 foreach (component in pending) {
251 component._scheduled = false
252 if (component._mounted && component._parent == null && component.dirty)
253 component.updateIfDirty()
254 }
255}
256
257::eve_ui_flush_components <- function() {
258 eve._flushUIComponents()
259}
260
261eve.UIComponent <- class {
262 hostName = ""
263 dirty = true
264 forceFull = false
265 props = null
266 state = null
267 _ui = null
268 _parent = null
269 _mounted = false
270 _scheduled = false
271 _children = null
272 _nextChildren = null
273 _keyedChildren = null
274 _eventBindings = null
275 _eventOwner = 0
276
277 constructor(uiInstance = null, initialProps = null) {
278 _ui = uiInstance
279 hostName = ""
280 dirty = true
281 forceFull = false
282 props = initialProps != null ? initialProps : {}
283 state = {}
284 _parent = null
285 _mounted = false
286 _scheduled = false
287 _children = []
288 _nextChildren = []
289 _keyedChildren = {}
290 _eventBindings = []
291 eve._nextUIComponentOwner += 1
292 _eventOwner = eve._nextUIComponentOwner
293 }
294
295 function setUI(uiInstance) { _ui = uiInstance; return this }
296
297 function _applyProps(nextProps, replace, notify) {
298 if (nextProps == null) return this
299 if (replace) props = {}
300 foreach (key, value in nextProps) props.rawset(key, value)
301 if (notify) markDirty()
302 return this
303 }
304
305 function setProps(nextProps, replace = false) {
306 return _applyProps(nextProps, replace, true)
307 }
308
309 function mountAs(name) {
310 hostName = name
311 dirty = true
312 forceFull = true
313 updateIfDirty()
314 return this
315 }
316
317 function setState(patch = null) {
318 if (patch != null) {
319 foreach (key, value in patch) state.rawset(key, value)
320 }
321 markDirty()
322 return this
323 }
324 function markDirty() {
325 dirty = true
326 if (_parent != null && _parent != this) _parent.markDirty()
327 else if (_mounted) eve._scheduleUIComponent(this)
328 return this
329 }
330
331 // Compose a persistent child instance inside this component's active build pass.
332 function renderChild(component, nextProps = null, replaceProps = false) {
333 if (component == null) return null
334 component._parent = this
335 component.setUI(ui())
336 component._applyProps(nextProps, replaceProps, false)
337 _nextChildren.append(component)
338 local firstMount = !component._mounted
339 component._nextChildren = []
340 component.build()
341 component._finishChildPass()
342 component.dirty = false
343 component._mounted = true
344 if (firstMount) component.onMount()
345 else component.onUpdated()
346 return component
347 }
348
349 // Reuse a child component by a stable key. factory is called only for a new key.
350 function renderKeyed(key, factory, nextProps = null, replaceProps = false) {
351 if (key == null) throw "UIComponent renderKeyed requires a key"
352 local component = null
353 if (key in _keyedChildren) component = _keyedChildren[key]
354 else {
355 component = factory()
356 if (component == null) throw "UIComponent renderKeyed factory returned null"
357 _keyedChildren.rawset(key, component)
358 }
359 return renderChild(component, nextProps, replaceProps)
360 }
361
362 function _bindEvent(kind, id, fn) {
363 if (id == null || id == "" || fn == null) return this
364 foreach (binding in _eventBindings) {
365 if (binding.kind == kind && binding.id == id) {
366 binding.fn = fn
367 if (_mounted) _syncEventHandlers()
368 return this
369 }
370 }
371 _eventBindings.append({ kind = kind, id = id, fn = fn })
372 if (_mounted) _syncEventHandlers()
373 return this
374 }
375
376 function bindClick(id, fn) { return _bindEvent("click", id, fn) }
377 function bindChange(id, fn) { return _bindEvent("change", id, fn) }
378
379 function clearEventBindings() {
380 _eventBindings = []
381 ui().componentClearHandlers(_eventOwner)
382 return this
383 }
384
385 function _rootComponent() {
386 local root = this
387 while (root._parent != null && root._parent != root) root = root._parent
388 return root
389 }
390
391 function _syncEventHandlers() {
392 local u = ui()
393 u.componentClearHandlers(_eventOwner)
394 local root = _rootComponent()
395 if (root.hostName == "" || !u.select(root.hostName)) return
396 foreach (binding in _eventBindings) {
397 if (binding.kind == "click") u.componentOnClick(_eventOwner, binding.id, binding.fn)
398 else u.componentOnChange(_eventOwner, binding.id, binding.fn)
399 }
400 }
401
402 function _syncEventTree() {
403 _syncEventHandlers()
404 foreach (child in _children) child._syncEventTree()
405 }
406
407 function _containsChild(items, child) {
408 foreach (candidate in items) {
409 if (candidate == child) return true
410 }
411 return false
412 }
413
414 function _finishChildPass() {
415 foreach (child in _children) {
416 if (!_containsChild(_nextChildren, child)) child._unmountTree()
417 }
418 local staleKeys = []
419 foreach (key, child in _keyedChildren) {
420 if (!_containsChild(_nextChildren, child)) staleKeys.append(key)
421 }
422 foreach (key in staleKeys) delete _keyedChildren[key]
423 _children = _nextChildren
424 _nextChildren = []
425 }
426
427 function _unmountTree() {
428 if (!_mounted) return false
429 foreach (child in _children) child._unmountTree()
430 _children = []
431 _nextChildren = []
432 _mounted = false
433 _scheduled = false
434 dirty = false
435 ui().componentClearHandlers(_eventOwner)
436 onUnmount()
437 _parent = null
438 return true
439 }
440
441 function unmount() {
442 if (!_unmountTree()) return false
443 local u = ui()
444 if (hostName != "" && u.select(hostName)) u.setHostVisible(false)
445 return true
446 }
447
448 // Override in subclass: call this.ui().beginWindow / text / button / end ...
449 function build() {}
450 function onMount() {}
451 function onUpdated() {}
452 function onUnmount() {}
453
454 function ui() {
455 if (_ui != null) return _ui
456 try {
457 if (::ui != null) return ::ui
458 } catch (e) {}
459 _ui = ::eve.UI()
460 return _ui
461 }
462
463 function updateIfDirty() {
464 if (!dirty) return false
465 local firstMount = !_mounted
466 local u = ui()
467 _scheduled = false
468 dirty = false
469 _nextChildren = []
470 u.beginBuild()
471 build()
472 _finishChildPass()
473 local name = hostName
474 if (name == null || name == "") name = "default"
475 hostName = name
476 if (forceFull) {
477 if (!u.mountBuildAs(name)) throw "UIComponent mount failed: " + name
478 forceFull = false
479 } else {
480 if (!u.remountBuildAs(name)) throw "UIComponent remount failed: " + name
481 }
482 _mounted = true
483 u.setHostVisible(true)
484 if (firstMount) onMount()
485 else onUpdated()
486 _syncEventTree()
487 return true
488 }
489
490 function rebuild(force = false) {
491 dirty = true
492 forceFull = force
493 return updateIfDirty()
494 }
495}
496// Note: eve.Component is reserved for script ECS (see exposeECS). Use eve.UIComponent.
497)SQ";
498
499void injectUIComponentClass(ssq::Table &eveTable) {
500 HSQUIRRELVM vm = eveTable.getHandle();
501 const SQInteger top = sq_gettop(vm);
502 if (SQ_FAILED(sq_compilebuffer(vm, kUIComponentScript,
503 static_cast<SQInteger>(std::strlen(kUIComponentScript)),
504 "UIComponent.nut", SQTrue))) {
505 sq_settop(vm, top);
506 return;
507 }
508 sq_pushroottable(vm);
509 sq_call(vm, 1, SQFalse, SQTrue);
510 sq_settop(vm, top);
511}
512
513class UiRootReleaser final : public eve::script::ISquirrelRootReleaser {
514public:
515 void releaseSquirrelRoots() noexcept override {
516 if (auto* ui = ModuleManager::getInstance<UI>("UI")) ui->releaseSquirrelRoots();
517 }
518};
519
520struct RegisterUiRoots {
521 RegisterUiRoots() {
522 static UiRootReleaser releaser;
523 eve::cap::addListener<eve::script::ISquirrelRootReleaser>(&releaser);
524 }
525} g_uiRoots;
526
527} // namespace
528
530
537 bindUIEventSinkOwner(nullptr);
539}
540
542 databasePanel_.reset();
543 if (!ModuleManager::runtime()) return;
544 try {
546 } catch (...) {
547 }
548}
549
550bool UI::isBackendReady() const { return backend_ && backend_->isInitialized(); }
551
553 if (!backend_) backend_ = createImGuiBackend();
554 if (backend_->isInitialized()) return true;
555 auto *win = eve::ModuleManager::getInstance<eve::window::Window>("Window");
556 auto *gfx = eve::ModuleManager::getInstance<eve::graphics::Graphics>("Graphics");
557 if (!win || !gfx) return false;
558 auto *sdlWin = dynamic_cast<eve::window::sdl::Window *>(win);
559 if (!sdlWin) return false;
560 auto *native = static_cast<SDL_Window *>(sdlWin->getHandle());
561 if (!native) return false;
562 const bool ok = backend_->init(native, gfx);
563 if (ok) UISystem::setBackend(*backend_);
564 return ok;
565}
566
569 releaseNinePatches();
571 if (backend_) backend_->shutdown();
572}
573
574void UI::processEvent(const SDL_Event *event) {
576 event->type == SDL_DROPFILE && event->drop.file)
577 UISystem::enqueuePlatformFileDrop(event->drop.file);
578 if (backend_) backend_->processEvent(event);
579}
580
582 if (!isBackendReady()) {
583 if (!initBackend()) return;
584 }
586 if (inspector_ && inspector_->isOpen()) inspector_->sync();
587 if (databasePanel_ && databasePanel_->isOpen()) databasePanel_->sync();
588 backend_->newFrame();
590}
591
592void UI::tickTweens(double nowMs) { tweens_.tick(nowMs); }
593
594std::size_t UI::getHostTweenCount() const { return tweens_.hostTweenCount(); }
595
596std::size_t UI::getItemTweenCount() const { return tweens_.itemTweenCount(); }
597
599 // Copy before dispatch: UISystem::dispatchEvents() consumes the pending list.
600 const std::vector<UIEvent> events = UISystem::pendingEvents();
602 for (const auto &ev : events) {
603 if (!UIHost::resolve(ev.host)) continue;
604 fireScriptHandlers(ev);
605 }
606}
607
608void UI::fireScriptHandlers(const UIEvent &ev) {
609 for (const auto &h : scriptHandlers_) {
610 if (h.hostName != ev.hostName || h.nodeId != ev.nodeId) continue;
611 if (h.kind == "click" && ev.kind == "click") {
612 ssq::Function fn = h.fn;
613 callScriptHandler(fn, "click", ev);
614 } else if (h.kind == ev.kind &&
615 (ev.kind == "toggle" || ev.kind == "value" || ev.kind == "text")) {
616 ssq::Function fn = h.fn;
617 callScriptHandler(fn, ev.kind, ev);
618 }
619 }
620}
621
622void UI::onClick(const std::string &id, ssq::Function fn) {
623 auto host = resolveSelected();
624 if (!host || id.empty()) return;
625 scriptHandlers_.push_back(ScriptHandler(host->get().getName(), id, "click", std::move(fn)));
626}
627
628void UI::onChange(const std::string &id, ssq::Function fn) {
629 auto host = resolveSelected();
630 if (!host || id.empty()) return;
631 for (const char *kind : {"toggle", "value", "text"}) {
632 scriptHandlers_.push_back(ScriptHandler(host->get().getName(), id, kind, fn));
633 }
634}
635
636void UI::componentOnClick(uint64_t owner, const std::string &id, ssq::Function fn) {
637 auto host = resolveSelected();
638 if (!host || owner == 0 || id.empty()) return;
639 scriptHandlers_.push_back(
640 ScriptHandler(host->get().getName(), id, "click", std::move(fn), owner));
641}
642
643void UI::componentOnChange(uint64_t owner, const std::string &id, ssq::Function fn) {
644 auto host = resolveSelected();
645 if (!host || owner == 0 || id.empty()) return;
646 for (const char *kind : {"toggle", "value", "text"}) {
647 scriptHandlers_.push_back(ScriptHandler(host->get().getName(), id, kind, fn, owner));
648 }
649}
650
651void UI::componentClearHandlers(uint64_t owner) {
652 if (owner == 0) return;
653 std::erase_if(scriptHandlers_, [owner](const ScriptHandler &handler) {
654 return handler.owner == owner;
655 });
656}
657
659 return backend_ ? backend_->wantCaptureMouse() : false;
660}
661
663 return backend_ ? backend_->wantCaptureKeyboard() : false;
664}
665
666UIHostHandle UI::findHost(const std::string &name) const { return UISystem::findHost(name); }
667
668UIHostHandle UI::findHostByOwner(uint32_t ownerId) const { return UISystem::findHostByOwner(ownerId); }
669
670bool UI::select(const std::string &name) {
671 const UIHostHandle h = findHost(name);
672 if (!UIHost::resolve(h)) return false;
673 selected_ = h;
674 return true;
675}
676
677void UI::bindOwner(uint32_t ownerId) {
678 if (auto host = resolveSelected()) host->get().setOwnerId(ownerId);
679}
680
681UIHostHandle UI::ensureSelected(const std::string &preferredName) {
682 if (UIHost::resolve(selected_)) return selected_;
683 selected_ = {};
684 if (!preferredName.empty()) {
685 const UIHostHandle h = findHost(preferredName);
686 if (UIHost::resolve(h)) {
687 selected_ = h;
688 return selected_;
689 }
690 selected_ = UIHost::createHost(preferredName);
691 return selected_;
692 }
693 selected_ = UIHost::createHost("default");
694 return selected_;
695}
696
700 if (!host) {
703 } else {
704 host->get().setName(name);
705 }
706 if (!host) return {};
707 host->get().setTree(std::move(root));
708 selected_ = handle;
709 return handle;
710}
711
713 if (auto host = resolveSelected()) {
714 host->get().setTree(std::move(root));
715 return selected_;
716 }
717 return mountAs("default", std::move(root));
718}
719
721 const UIHostHandle handle = ensureSelected();
722 if (auto host = UIHost::resolve(handle)) host->get().setTree(std::move(root));
723 return handle;
724}
725
727 const UIHostHandle handle = ensureSelected();
728 if (auto host = UIHost::resolve(handle)) host->get().setTreeReconcile(std::move(root));
729 return handle;
730}
731
732UIHostHandle UI::remountAs(const std::string &name, WidgetDesc root) { return mountAs(name, std::move(root)); }
733
734eve::OptionalRef<UIHost> UI::resolveSelected() const noexcept { return UIHost::resolve(selected_); }
735
737 openStack_.clear();
738 hasBuiltRoot_ = false;
739 builtRoot_ = WidgetDesc{};
740}
741
742void UI::pushOpen(WidgetDesc d) { openStack_.push_back(std::move(d)); }
743
744WidgetDesc &UI::currentParent() {
745 if (openStack_.empty()) throw std::runtime_error("ui: widget outside beginWindow/beginGroup");
746 return openStack_.back();
747}
748
749void UI::beginWindow(const std::string &title, const std::string &id) {
750 if (openStack_.empty() && hasBuiltRoot_) beginBuild();
751 pushOpen(window(title, {}, id));
752}
753
754void UI::beginGroup(const std::string &id) { pushOpen(group({}, id)); }
755
756void UI::beginList(const std::string &id) { pushOpen(group({}, id)); }
757
758void UI::beginCollapsing(const std::string &label, const std::string &id, bool open) {
759 pushOpen(collapsingHeader(label, {}, id, open));
760}
761
762void UI::beginChild(const std::string &id, float width, float height) {
763 pushOpen(child(id, {}, width, height));
764}
765
766void UI::beginCard(const std::string &id) { pushOpen(card({}, id)); }
767
768bool UI::beginNinePatch(const std::string &path, const std::string &id, float width,
769 float height) {
770 auto *asset = loadNinePatch(path);
771 if (!asset) return false;
772 WidgetDesc d = ninePatchPanel({}, id, asset->textureId);
773 d.sizeX = width;
774 d.sizeY = height;
775 d.minSizeX = float(asset->info.width);
776 d.minSizeY = float(asset->info.height);
777 d.borderL = float(asset->info.borderLeft);
778 d.borderT = float(asset->info.borderTop);
779 d.borderR = float(asset->info.borderRight);
780 d.borderB = float(asset->info.borderBottom);
781 d.paddingL = float(asset->info.paddingLeft);
782 d.paddingT = float(asset->info.paddingTop);
783 d.paddingR = float(asset->info.paddingRight);
784 d.paddingB = float(asset->info.paddingBottom);
785 pushOpen(std::move(d));
786 return true;
787}
788
789void UI::beginMenuBar(const std::string &id) { pushOpen(menuBar({}, id)); }
790
791void UI::beginMenu(const std::string &label, const std::string &id) {
792 pushOpen(menu(label, {}, id));
793}
794
795void UI::beginToolbar(const std::string &id) { pushOpen(toolbar({}, id)); }
796
797void UI::beginToolbox(const std::string &id, float cellSize, int columns) {
798 pushOpen(toolbox({}, id, cellSize, columns));
799}
800
801void UI::beginSidebar(const std::string &id, float width) {
802 pushOpen(sidebar({}, id, width));
803}
804
805void UI::beginStatusBar(const std::string &id) { pushOpen(statusBar({}, id)); }
806
807void UI::beginScrollList(const std::string &id, float height, float itemHeight) {
808 pushOpen(scrollList(id, {}, height, itemHeight));
809}
810
811namespace {
812
813std::string toLowerCopy(std::string s) {
814 for (char &c : s) {
815 if (c >= 'A' && c <= 'Z') c = char(c - 'A' + 'a');
816 }
817 return s;
818}
819
820FlexDirection parseFlexDirection(const std::string &direction) {
821 const std::string d = toLowerCopy(direction);
822 if (d == "column" || d == "col" || d == "vertical" || d == "v") return FlexDirection::Column;
823 return FlexDirection::Row;
824}
825
826FlexAlign parseFlexAlign(const std::string &align) {
827 const std::string a = toLowerCopy(align);
828 if (a == "center") return FlexAlign::Center;
829 if (a == "end" || a == "right" || a == "bottom") return FlexAlign::End;
830 if (a == "stretch") return FlexAlign::Stretch;
831 return FlexAlign::Start;
832}
833
834FlexJustify parseFlexJustify(const std::string &justify) {
835 const std::string j = toLowerCopy(justify);
836 if (j == "center") return FlexJustify::Center;
837 if (j == "end" || j == "right" || j == "bottom") return FlexJustify::End;
838 if (j == "spacebetween" || j == "space-between" || j == "between")
840 if (j == "spacearound" || j == "space-around" || j == "around") return FlexJustify::SpaceAround;
841 return FlexJustify::Start;
842}
843
844OverflowMode parseOverflowMode(const std::string &overflow) {
845 const std::string value = toLowerCopy(overflow);
846 if (value == "clip" || value == "hidden") return OverflowMode::Clip;
847 if (value == "scroll" || value == "auto") return OverflowMode::Scroll;
849}
850
851FocusMode parseFocusMode(const std::string &mode) {
852 const std::string value = toLowerCopy(mode);
853 if (value == "none") return FocusMode::None;
854 if (value == "click") return FocusMode::Click;
855 return FocusMode::All;
856}
857
858MouseFilter parseMouseFilter(const std::string &filter) {
859 const std::string value = toLowerCopy(filter);
860 if (value == "pass") return MouseFilter::Pass;
861 if (value == "ignore") return MouseFilter::Ignore;
862 return MouseFilter::Stop;
863}
864
865ThemePreset parseThemePreset(const std::string &theme) {
866 const std::string value = toLowerCopy(theme);
867 if (value == "dark") return ThemePreset::Dark;
868 if (value == "light") return ThemePreset::Light;
870}
871
872AccessibilityRole parseAccessibilityRole(const std::string &role) {
873 const std::string value = toLowerCopy(role);
874 if (value == "button") return AccessibilityRole::Button;
875 if (value == "checkbox") return AccessibilityRole::Checkbox;
876 if (value == "slider") return AccessibilityRole::Slider;
877 if (value == "text") return AccessibilityRole::Text;
878 if (value == "textinput" || value == "text-input") return AccessibilityRole::TextInput;
879 if (value == "list") return AccessibilityRole::List;
880 if (value == "listitem" || value == "list-item") return AccessibilityRole::ListItem;
881 if (value == "menu") return AccessibilityRole::Menu;
882 if (value == "menuitem" || value == "menu-item") return AccessibilityRole::MenuItem;
883 if (value == "progress") return AccessibilityRole::Progress;
884 if (value == "region") return AccessibilityRole::Region;
885 if (value == "tab") return AccessibilityRole::Tab;
886 if (value == "window") return AccessibilityRole::Window;
888}
889
890bool parseFocusDirection(const std::string &direction, FocusDirection *out) {
891 if (!out) return false;
892 const std::string value = toLowerCopy(direction);
893 if (value == "next") *out = FocusDirection::Next;
894 else if (value == "previous" || value == "prev") *out = FocusDirection::Previous;
895 else if (value == "left") *out = FocusDirection::Left;
896 else if (value == "right") *out = FocusDirection::Right;
897 else if (value == "up") *out = FocusDirection::Up;
898 else if (value == "down") *out = FocusDirection::Down;
899 else return false;
900 return true;
901}
902
903} // namespace
904
905void UI::beginFlex(const std::string &direction, const std::string &id, float gap) {
906 WidgetDesc d = flex(parseFlexDirection(direction), {}, id);
907 d.gap = gap;
908 pushOpen(std::move(d));
909}
910
911void UI::beginRow(const std::string &id, float gap) { beginFlex("row", id, gap); }
912
913void UI::beginColumn(const std::string &id, float gap) { beginFlex("column", id, gap); }
914
915void UI::beginGrid(int columns, const std::string &id, float columnGap, float rowGap) {
916 WidgetDesc d = grid(columns, {}, id);
917 d.columnGap = columnGap;
918 d.rowGap = rowGap;
919 pushOpen(std::move(d));
920}
921
922void UI::beginSplitPane(const std::string &direction, float ratio, const std::string &id) {
925 d.id = id;
926 d.key = id;
927 d.flexDirection = parseFlexDirection(direction);
928 d.value = std::max(0.1f, std::min(0.9f, ratio));
929 d.minValue = 0.1f;
930 d.maxValue = 0.9f;
931 pushOpen(std::move(d));
932}
933
934void UI::end() {
935 if (openStack_.empty()) throw std::runtime_error("ui: end() without begin");
936 WidgetDesc finished = std::move(openStack_.back());
937 openStack_.pop_back();
938 if (openStack_.empty()) {
939 builtRoot_ = std::move(finished);
940 hasBuiltRoot_ = true;
941 } else {
942 openStack_.back().children.push_back(std::move(finished));
943 }
944}
945
946void UI::addText(const std::string &content, const std::string &id) {
947 currentParent().children.push_back(text(content, id));
948}
949
950void UI::addTextWrapped(const std::string &content, float width, const std::string &id) {
951 WidgetDesc d = text(content, id);
952 d.wrapWidth = width;
953 currentParent().children.push_back(std::move(d));
954}
955
956void UI::addButton(const std::string &label, const std::string &id) {
957 currentParent().children.push_back(button(label, id));
958}
959
960void UI::addIcon(const std::string &name, const std::string &id) {
963 currentParent().children.push_back(icon(value, id));
964}
965
966void UI::addIconButton(const std::string &name, const std::string &label, const std::string &id) {
969 currentParent().children.push_back(iconButton(value, label, id));
970}
971
972void UI::addSameLine(const std::string &id) { currentParent().children.push_back(sameLine(id)); }
973
974void UI::addSeparator(const std::string &id) {
975 currentParent().children.push_back(separator(id));
976}
977
978void UI::addCheckbox(const std::string &label, bool checked, const std::string &id) {
979 currentParent().children.push_back(checkbox(label, checked, id));
980}
981
982void UI::addSlider(const std::string &label, float value, float minV, float maxV,
983 const std::string &id) {
984 currentParent().children.push_back(slider(label, value, minV, maxV, id));
985}
986
987void UI::addColorPalette(const std::string &label, float r, float g, float b, float a,
988 const std::string &id) {
989 currentParent().children.push_back(colorPalette(label, r, g, b, a, id));
990}
991
992void UI::addProgress(float fraction, const std::string &id, const std::string &overlay) {
993 currentParent().children.push_back(progress(fraction, id, overlay));
994}
995
996void UI::addImage(const std::string &id, float width, float height) {
997 currentParent().children.push_back(image(id, width, height));
998}
999
1000bool UI::addNinePatch(const std::string &path, const std::string &id, float width,
1001 float height) {
1002 auto *asset = loadNinePatch(path);
1003 if (!asset) return false;
1004 WidgetDesc d = image(id, width > 0.f ? width : float(asset->info.width),
1005 height > 0.f ? height : float(asset->info.height));
1006 d.textureId = asset->textureId;
1007 d.borderL = float(asset->info.borderLeft);
1008 d.borderT = float(asset->info.borderTop);
1009 d.borderR = float(asset->info.borderRight);
1010 d.borderB = float(asset->info.borderBottom);
1011 currentParent().children.push_back(std::move(d));
1012 return true;
1013}
1014
1015void UI::addImageButton(const std::string &id, float width, float height) {
1016 currentParent().children.push_back(imageButton(id, width, height));
1017}
1018
1019void UI::addViewport(const std::string &id, float width, float height) {
1020 currentParent().children.push_back(viewport(id, width, height));
1021}
1022
1023void UI::addCombo(const std::string &label, const std::string &options, int selected,
1024 const std::string &id) {
1025 std::vector<std::string> items;
1026 size_t start = 0;
1027 while (start <= options.size()) {
1028 const size_t end = options.find('\n', start);
1029 items.push_back(options.substr(start, end == std::string::npos ? std::string::npos
1030 : end - start));
1031 if (end == std::string::npos) break;
1032 start = end + 1;
1033 }
1034 currentParent().children.push_back(combo(label, items, selected, id));
1035}
1036
1037void UI::addInputText(const std::string &label, const std::string &value, const std::string &id) {
1038 currentParent().children.push_back(inputText(label, value, id));
1039}
1040
1041void UI::addSearchField(const std::string &hint, const std::string &value,
1042 const std::string &id) {
1043 currentParent().children.push_back(searchField(hint, value, id));
1044}
1045
1046void UI::addSwitch(const std::string &label, bool checked, const std::string &id) {
1047 currentParent().children.push_back(toggleSwitch(label, checked, id));
1048}
1049
1050void UI::addBadge(const std::string &label, const std::string &id) {
1051 currentParent().children.push_back(badge(label, id));
1052}
1053
1054void UI::addSectionHeader(const std::string &label, const std::string &id) {
1055 currentParent().children.push_back(sectionHeader(label, id));
1056}
1057
1058void UI::addMenuItem(const std::string &label, const std::string &shortcut,
1059 const std::string &id) {
1060 currentParent().children.push_back(menuItem(label, shortcut, id));
1061}
1062
1063void UI::addSpacer(const std::string &id, float grow) {
1064 currentParent().children.push_back(spacer(id, grow));
1065}
1066
1067void UI::setItemFlexGrow(float grow) {
1068 WidgetDesc &parent = currentParent();
1069 if (parent.children.empty()) return;
1070 parent.children.back().flexGrow = grow;
1071}
1072
1073void UI::setItemFlexShrink(float shrink) {
1074 WidgetDesc &parent = currentParent();
1075 if (!parent.children.empty()) parent.children.back().flexShrink = std::max(0.f, shrink);
1076}
1077
1078void UI::setItemFlexBasis(float basis) {
1079 WidgetDesc &parent = currentParent();
1080 if (!parent.children.empty()) parent.children.back().flexBasis = basis;
1081}
1082
1083void UI::setItemAlignSelf(const std::string &align) {
1084 WidgetDesc &parent = currentParent();
1085 if (parent.children.empty()) return;
1086 parent.children.back().alignSelf = align == "inherit" ? -1 : int(parseFlexAlign(align));
1087}
1088
1089void UI::setItemAspectRatio(float ratio) {
1090 WidgetDesc &parent = currentParent();
1091 if (!parent.children.empty()) parent.children.back().aspectRatio = std::max(0.f, ratio);
1092}
1093
1095 WidgetDesc &parent = currentParent();
1096 if (!parent.children.empty()) parent.children.back().gridColumnSpan = std::max(1, span);
1097}
1098
1099void UI::setItemSize(float width, float height) {
1100 WidgetDesc &parent = currentParent();
1101 if (parent.children.empty()) return;
1102 parent.children.back().sizeX = width;
1103 parent.children.back().sizeY = height;
1104}
1105
1106void UI::setItemMargin(float l, float t, float r, float b) {
1107 WidgetDesc &parent = currentParent();
1108 if (parent.children.empty()) return;
1109 parent.children.back().marginL = l;
1110 parent.children.back().marginT = t;
1111 parent.children.back().marginR = r;
1112 parent.children.back().marginB = b;
1113}
1114
1115void UI::setItemPadding(float l, float t, float r, float b) {
1116 WidgetDesc &parent = currentParent();
1117 if (parent.children.empty()) return;
1118 parent.children.back().paddingL = l;
1119 parent.children.back().paddingT = t;
1120 parent.children.back().paddingR = r;
1121 parent.children.back().paddingB = b;
1122}
1123
1124void UI::setItemMinSize(float w, float h) {
1125 WidgetDesc &parent = currentParent();
1126 if (parent.children.empty()) return;
1127 parent.children.back().minSizeX = w;
1128 parent.children.back().minSizeY = h;
1129}
1130
1131void UI::setItemMaxSize(float w, float h) {
1132 WidgetDesc &parent = currentParent();
1133 if (parent.children.empty()) return;
1134 parent.children.back().maxSizeX = w;
1135 parent.children.back().maxSizeY = h;
1136}
1137
1138void UI::setItemPercent(float w, float h) {
1139 WidgetDesc &parent = currentParent();
1140 if (parent.children.empty()) return;
1141 parent.children.back().percentW = w;
1142 parent.children.back().percentH = h;
1143}
1144
1145void UI::setItemAbsolute(float anchorX, float anchorY, float x, float y) {
1146 WidgetDesc &parent = currentParent();
1147 if (parent.children.empty()) return;
1148 parent.children.back().absolute = true;
1149 parent.children.back().anchorX = anchorX;
1150 parent.children.back().anchorY = anchorY;
1151 parent.children.back().posX = x;
1152 parent.children.back().posY = y;
1153}
1154
1155void UI::setItemTooltip(const std::string &text) {
1156 WidgetDesc &parent = currentParent();
1157 if (parent.children.empty()) return;
1158 parent.children.back().tooltip = text;
1159}
1160
1161void UI::setItemDragSource(const std::string &payloadType, const std::string &payloadText) {
1162 WidgetDesc &parent = currentParent();
1163 if (parent.children.empty()) return;
1164 auto &item = parent.children.back();
1165 item.dragSource = !payloadType.empty();
1166 item.dragPayloadType = payloadType;
1167 item.dragPayloadText = payloadText;
1168}
1169
1170void UI::setItemDropTarget(const std::string &acceptedType) {
1171 WidgetDesc &parent = currentParent();
1172 if (parent.children.empty()) return;
1173 auto &item = parent.children.back();
1174 item.dropTarget = !acceptedType.empty();
1175 item.acceptedDropType = acceptedType;
1176}
1177
1179 WidgetDesc &parent = currentParent();
1180 if (!parent.children.empty()) parent.children.back().enabled = enabled;
1181}
1182
1183void UI::setItemSelected(bool selected) {
1184 WidgetDesc &parent = currentParent();
1185 if (!parent.children.empty()) parent.children.back().checked = selected;
1186}
1187
1188void UI::setItemFocusMode(const std::string &mode) {
1189 WidgetDesc &parent = currentParent();
1190 if (!parent.children.empty()) parent.children.back().focusMode = parseFocusMode(mode);
1191}
1192
1193void UI::setItemMouseFilter(const std::string &filter) {
1194 WidgetDesc &parent = currentParent();
1195 if (!parent.children.empty()) parent.children.back().mouseFilter = parseMouseFilter(filter);
1196}
1197
1198void UI::setItemTheme(const std::string &theme) {
1199 WidgetDesc &parent = currentParent();
1200 if (!parent.children.empty()) parent.children.back().themePreset = parseThemePreset(theme);
1201}
1202
1203void UI::setThemeScope(const std::string &theme) {
1204 currentParent().themePreset = parseThemePreset(theme);
1205}
1206
1207void UI::setItemStyleClass(const std::string &name) {
1208 WidgetDesc &parent = currentParent();
1209 if (!parent.children.empty()) parent.children.back().styleClass = name;
1210}
1211
1212void UI::setStyleScope(const std::string &name) { currentParent().styleClass = name; }
1213
1215 WidgetDesc &parent = currentParent();
1216 if (!parent.children.empty()) parent.children.back().tabIndex = index;
1217}
1218
1219void UI::setItemFocusOrder(const std::string &previous, const std::string &next) {
1220 WidgetDesc &parent = currentParent();
1221 if (parent.children.empty()) return;
1222 parent.children.back().focusPrevious = previous;
1223 parent.children.back().focusNext = next;
1224}
1225
1226void UI::setItemFocusNeighbors(const std::string &left, const std::string &right,
1227 const std::string &up, const std::string &down) {
1228 WidgetDesc &parent = currentParent();
1229 if (parent.children.empty()) return;
1230 parent.children.back().focusLeft = left;
1231 parent.children.back().focusRight = right;
1232 parent.children.back().focusUp = up;
1233 parent.children.back().focusDown = down;
1234}
1235
1236void UI::setItemAccessibility(const std::string &role, const std::string &name,
1237 const std::string &description) {
1238 WidgetDesc &parent = currentParent();
1239 if (parent.children.empty()) return;
1240 parent.children.back().accessibilityRole = parseAccessibilityRole(role);
1241 parent.children.back().accessibilityName = name;
1242 parent.children.back().accessibilityDescription = description;
1243}
1244
1245void UI::setFlexAlign(const std::string &align) {
1246 WidgetDesc &parent = currentParent();
1247 if (parent.type != NodeType::Flex) return;
1248 parent.alignItems = parseFlexAlign(align);
1249}
1250
1251void UI::setFlexJustify(const std::string &justify) {
1252 WidgetDesc &parent = currentParent();
1253 if (parent.type != NodeType::Flex) return;
1254 parent.justifyContent = parseFlexJustify(justify);
1255}
1256
1257void UI::setLayoutGaps(float columnGap, float rowGap) {
1258 WidgetDesc &parent = currentParent();
1259 if (parent.type != NodeType::Flex && parent.type != NodeType::Grid) return;
1260 parent.columnGap = columnGap;
1261 parent.rowGap = rowGap;
1262}
1263
1264void UI::setFlexWrap(bool wrap) {
1265 WidgetDesc &parent = currentParent();
1266 if (parent.type == NodeType::Flex)
1267 parent.flexWrap = wrap ? FlexWrap::Wrap : FlexWrap::NoWrap;
1268}
1269
1270void UI::setLayoutOverflow(const std::string &overflow) {
1271 WidgetDesc &parent = currentParent();
1272 if (parent.type == NodeType::Flex || parent.type == NodeType::Grid)
1273 parent.overflow = parseOverflowMode(overflow);
1274}
1275
1276void UI::addListItem(const std::string &label, const std::string &id) {
1277 WidgetDesc &parent = currentParent();
1278 std::string itemId = id;
1279 if (itemId.empty())
1280 itemId = parent.id + "/" + std::to_string(parent.children.size());
1281 parent.children.push_back(button(label, itemId).withKey(itemId));
1282}
1283
1284bool UI::buildComplete() const { return openStack_.empty() && hasBuiltRoot_; }
1285
1287 if (!buildComplete()) return false;
1288 const UIHostHandle handle = remount(std::move(builtRoot_));
1289 if (!UIHost::resolve(handle)) return false;
1290 hasBuiltRoot_ = false;
1291 builtRoot_ = WidgetDesc{};
1292 return true;
1293}
1294
1295bool UI::mountBuildAs(const std::string &name) {
1296 if (!buildComplete()) return false;
1297 const UIHostHandle handle = mountAs(name, std::move(builtRoot_));
1298 if (!UIHost::resolve(handle)) return false;
1299 hasBuiltRoot_ = false;
1300 builtRoot_ = WidgetDesc{};
1301 return true;
1302}
1303
1304bool UI::remountBuildAs(const std::string &name) {
1305 if (!buildComplete()) return false;
1308 auto host = UIHost::resolve(h);
1309 if (!host) return false;
1310 host->get().setTreeReconcile(std::move(builtRoot_));
1311 selected_ = h;
1312 hasBuiltRoot_ = false;
1313 builtRoot_ = WidgetDesc{};
1314 return true;
1315}
1316
1317bool UI::setListItems(const std::string &listId, const std::vector<std::string> &items) {
1318 auto host = resolveSelected();
1319 if (!host) return false;
1320 WidgetDesc listNode = listButtons(listId, items);
1321 auto existing = host->get().findById(listId);
1322 if (existing && existing->get().type == NodeType::Group) {
1323 host->get().setTreeReconcile(
1324 window(host->get().getName().empty() ? "List" : host->get().getName(), {std::move(listNode)}, "root"));
1325 return true;
1326 }
1327 host->get().setTree(
1328 window(host->get().getName().empty() ? "List" : host->get().getName(), {std::move(listNode)}, "root"));
1329 return true;
1330}
1331
1332void UI::setText(const std::string &id, const std::string &text) {
1333 if (auto host = resolveSelected()) host->get().setTextById(id, text);
1334}
1335
1336void UI::setTextWrap(const std::string &id, float width) {
1337 auto host = resolveSelected();
1338 if (!host) return;
1339 if (auto n = host->get().findById(id)) n->get().wrapWidth = width;
1340}
1341
1342void UI::setVisible(const std::string &id, bool visible) {
1343 if (auto host = resolveSelected()) host->get().setVisibleById(id, visible);
1344}
1345
1346void UI::setEnabled(const std::string &id, bool enabled) {
1347 if (auto host = resolveSelected()) host->get().setEnabledById(id, enabled);
1348}
1349
1350void UI::setChecked(const std::string &id, bool checked) {
1351 if (auto host = resolveSelected()) host->get().setCheckedById(id, checked);
1352}
1353
1354void UI::setValue(const std::string &id, float value) {
1355 if (auto host = resolveSelected()) host->get().setValueById(id, value);
1356}
1357
1358void UI::setValueText(const std::string &id, const std::string &value) {
1359 if (auto host = resolveSelected()) host->get().setValueTextById(id, value);
1360}
1361
1362void UI::setColor(const std::string &id, float r, float g, float b, float a) {
1363 setImageTint(id, r, g, b, a);
1364}
1365
1366void UI::setImageTint(const std::string &id, float r, float g, float b, float a) {
1367 auto host = resolveSelected();
1368 if (!host) return;
1369 if (auto n = host->get().findById(id)) {
1370 n->get().tintR = r;
1371 n->get().tintG = g;
1372 n->get().tintB = b;
1373 n->get().tintA = a;
1374 }
1375}
1376
1377void UI::setImageUv(const std::string &id, float u0, float v0, float u1, float v1) {
1378 auto host = resolveSelected();
1379 if (!host) return;
1380 if (auto n = host->get().findById(id)) {
1381 n->get().uv0x = u0;
1382 n->get().uv0y = v0;
1383 n->get().uv1x = u1;
1384 n->get().uv1y = v1;
1385 }
1386}
1387
1388void UI::setImageNinePatch(const std::string &id, float l, float t, float r, float b) {
1389 auto host = resolveSelected();
1390 if (!host) return;
1391 if (auto n = host->get().findById(id)) {
1392 n->get().borderL = l;
1393 n->get().borderT = t;
1394 n->get().borderR = r;
1395 n->get().borderB = b;
1396 }
1397}
1398
1399void UI::setImageCornerRadius(const std::string &id, float radius) {
1400 auto host = resolveSelected();
1401 if (!host) return;
1402 if (auto n = host->get().findById(id)) n->get().cornerRadius = radius;
1403}
1404
1405void UI::setImageTextureId(const std::string &id, uint64_t textureId) {
1406 auto host = resolveSelected();
1407 if (!host) return;
1408 if (auto n = host->get().findById(id)) n->get().textureId = textureId;
1409}
1410
1412 if (!isBackendReady()) {
1413 if (!initBackend()) return 0;
1414 }
1415 return backend_ ? backend_->registerTexture(tex) : 0;
1416}
1417
1418void UI::unregisterTexture(uint64_t textureId) {
1419 if (backend_ && textureId != 0) backend_->unregisterTexture(textureId);
1420}
1421
1422float UI::getValue(const std::string &id) const {
1423 auto host = resolveSelected();
1424 if (!host) return 0.f;
1425 if (auto n = host->get().findById(id)) return n->get().value;
1426 return 0.f;
1427}
1428
1429std::string UI::getValueText(const std::string &id) const {
1430 auto host = resolveSelected();
1431 if (!host) return {};
1432 if (auto n = host->get().findById(id)) return n->get().valueText;
1433 return {};
1434}
1435
1436float UI::getColorR(const std::string &id) const {
1437 auto host = resolveSelected();
1438 if (!host) return 0.f;
1439 if (auto n = host->get().findById(id)) return n->get().tintR;
1440 return 0.f;
1441}
1442
1443float UI::getColorG(const std::string &id) const {
1444 auto host = resolveSelected();
1445 if (!host) return 0.f;
1446 if (auto n = host->get().findById(id)) return n->get().tintG;
1447 return 0.f;
1448}
1449
1450float UI::getColorB(const std::string &id) const {
1451 auto host = resolveSelected();
1452 if (!host) return 0.f;
1453 if (auto n = host->get().findById(id)) return n->get().tintB;
1454 return 0.f;
1455}
1456
1457float UI::getColorA(const std::string &id) const {
1458 auto host = resolveSelected();
1459 if (!host) return 0.f;
1460 if (auto n = host->get().findById(id)) return n->get().tintA;
1461 return 0.f;
1462}
1463
1464bool UI::getChecked(const std::string &id) const {
1465 auto host = resolveSelected();
1466 if (!host) return false;
1467 if (auto n = host->get().findById(id)) return n->get().checked;
1468 return false;
1469}
1470
1471bool UI::setImageNinePatchFile(const std::string &id, const std::string &path) {
1472 auto host = resolveSelected();
1473 if (!host) return false;
1474 auto n = host->get().findById(id);
1475 if (!n || (n->get().type != NodeType::Image && n->get().type != NodeType::ImageButton &&
1476 n->get().type != NodeType::NinePatchPanel))
1477 return false;
1478 auto *asset = loadNinePatch(path);
1479 if (!asset) return false;
1480 n->get().textureId = asset->textureId;
1481 n->get().borderL = float(asset->info.borderLeft);
1482 n->get().borderT = float(asset->info.borderTop);
1483 n->get().borderR = float(asset->info.borderRight);
1484 n->get().borderB = float(asset->info.borderBottom);
1485 if (n->get().type == NodeType::NinePatchPanel) {
1486 n->get().paddingL = float(asset->info.paddingLeft);
1487 n->get().paddingT = float(asset->info.paddingTop);
1488 n->get().paddingR = float(asset->info.paddingRight);
1489 n->get().paddingB = float(asset->info.paddingBottom);
1490 }
1491 return true;
1492}
1493
1494UI::NinePatchResource *UI::loadNinePatch(const std::string &path) {
1495 if (auto found = ninePatches_.find(path); found != ninePatches_.end())
1496 return &found->second;
1497 auto *images = eve::ModuleManager::getInstance<eve::image::Image>("Image");
1498 auto *graphics = eve::ModuleManager::getInstance<eve::graphics::Graphics>("Graphics");
1499 if (!images || !graphics) return nullptr;
1500 try {
1501 // The provider hands back a cache-owned ImageData; the pin keeps it alive
1502 // while the nine-patch border is measured and stripped.
1503 eve::image::ImageData *source = images->newImageDataFromFile(path);
1504 if (source == nullptr) return nullptr;
1505 auto sourcePin = eve::ResourceManager::getInstance().pin(source);
1506 if (!sourcePin.ok()) return nullptr;
1507 eve::ResourcePin keepAlive = std::move(sourcePin).takeValue();
1508 // The pin is the authority from here on; the borrowed pointer may have gone stale
1509 // before the pin was taken.
1510 source = static_cast<eve::image::ImageData *>(keepAlive.get());
1511 NinePatchResource resource;
1512 std::string error;
1513 if (!parseNinePatch(*source, resource.info, &error)) {
1514 std::fprintf(stderr, "[ui] invalid .9.png '%s': %s\n", path.c_str(),
1515 error.c_str());
1516 return nullptr;
1517 }
1518 auto cropped = stripNinePatchBorder(*source);
1519 if (!cropped) return nullptr;
1520 resource.texture = graphics->newTexture(cropped.get());
1521 if (!resource.texture) return nullptr;
1522 resource.textureId = registerTexture(resource.texture);
1523 if (resource.textureId == 0) {
1524 graphics->releaseTexture(resource.texture);
1525 return nullptr;
1526 }
1527 auto inserted = ninePatches_.emplace(path, std::move(resource));
1528 return &inserted.first->second;
1529 } catch (const std::exception &e) {
1530 std::fprintf(stderr, "[ui] failed to load .9.png '%s': %s\n", path.c_str(), e.what());
1531 return nullptr;
1532 }
1533}
1534
1535void UI::releaseNinePatches() {
1536 auto *graphics = eve::ModuleManager::getInstance<eve::graphics::Graphics>("Graphics");
1537 for (auto &[path, resource] : ninePatches_) {
1538 (void)path;
1539 if (backend_ && resource.textureId != 0)
1540 backend_->unregisterTexture(resource.textureId);
1541 if (graphics && resource.texture) graphics->releaseTexture(resource.texture);
1542 }
1543 ninePatches_.clear();
1544}
1545
1546bool UI::requestFocus(const std::string &id) {
1547 if (auto host = resolveSelected()) return host->get().requestFocusById(id);
1548 return false;
1549}
1550
1551bool UI::moveFocus(const std::string &direction) {
1552 auto host = resolveSelected();
1553 if (!host) return false;
1555 return parseFocusDirection(direction, &parsed) && host->get().moveFocus(parsed);
1556}
1557
1558std::string UI::getFocusedId() const {
1559 if (auto host = resolveSelected()) return host->get().focusedId();
1560 return {};
1561}
1562
1564 if (auto host = resolveSelected()) host->get().setVisible(visible);
1565}
1566
1568 if (auto host = resolveSelected()) host->get().setLayer(layer);
1569}
1570
1571void UI::setHostModal(bool modal) {
1572 if (auto host = resolveSelected()) host->get().setModal(modal);
1573}
1574
1575void UI::setHostOverlay(bool overlay) {
1576 if (auto host = resolveSelected()) host->get().meta()->overlay = overlay;
1577}
1578
1579void UI::setHostOverlayAlpha(float alpha) {
1580 if (auto host = resolveSelected()) host->get().meta()->overlayBgAlpha = std::max(0.f, std::min(1.f, alpha));
1581}
1582
1583void UI::setHostMovable(bool movable) {
1584 if (auto host = resolveSelected()) host->get().meta()->lockPos = !movable;
1585}
1586
1588 if (auto host = resolveSelected()) host->get().meta()->lockSize = !resizable;
1589}
1590
1591void UI::setHostPos(float x, float y, float pivotX, float pivotY) {
1592 auto host = resolveSelected();
1593 if (!host) return;
1594 auto m = host->get().meta();
1595 m->hasPos = true;
1596 m->posX = x;
1597 m->posY = y;
1598 m->pivotX = pivotX;
1599 m->pivotY = pivotY;
1600}
1601
1602void UI::setHostWorldAnchor(float x, float y, float z) {
1603 if (auto host = resolveSelected()) host->get().setWorldAnchor(x, y, z);
1604}
1605
1607 if (auto host = resolveSelected()) host->get().clearWorldAnchor();
1608}
1609
1610void UI::setHostWorldEdgePolicy(const std::string &policy, float safeMargin) {
1611 if (auto host = resolveSelected()) {
1612 auto anchor = host->get().worldAnchor();
1613 anchor->edgePolicy = policy == "clamp" ? WorldAnchorEdgePolicy::Clamp
1615 anchor->safeMargin = std::max(0.f, safeMargin);
1616 }
1617}
1618
1619void UI::setHostWorldDistanceScale(bool enabled, float referenceDistance, float minScale,
1620 float maxScale) {
1621 if (auto host = resolveSelected()) {
1622 auto anchor = host->get().worldAnchor();
1623 anchor->distanceScale = enabled;
1624 anchor->referenceDistance = std::max(referenceDistance, 0.001f);
1625 anchor->minScale = std::max(0.01f, std::min(minScale, maxScale));
1626 anchor->maxScale = std::max(anchor->minScale, std::max(minScale, maxScale));
1627 }
1628}
1629
1630void UI::setHostWorldOverlap(bool enabled, int priority, float padding,
1631 float maxDisplacement) {
1632 if (auto host = resolveSelected()) {
1633 auto anchor = host->get().worldAnchor();
1636 anchor->overlapPriority = priority;
1637 anchor->overlapPadding = std::max(0.f, padding);
1638 anchor->maxDisplacement = std::max(0.f, maxDisplacement);
1639 }
1640}
1641
1642std::string UI::getHostWorldState() const {
1643 const auto host = resolveSelected();
1644 if (!host) return "disabled";
1645 switch (host->get().worldAnchor()->state) {
1646 case WorldAnchorState::Visible: return "visible";
1647 case WorldAnchorState::BehindCamera: return "behind-camera";
1648 case WorldAnchorState::OutsideViewport: return "outside-viewport";
1649 case WorldAnchorState::NoCamera: return "no-camera";
1650 case WorldAnchorState::Crowded: return "crowded";
1651 case WorldAnchorState::Disabled: return "disabled";
1652 }
1653 return "disabled";
1654}
1655
1657 if (const auto host = resolveSelected()) return host->get().worldAnchor()->screenX;
1658 return 0.f;
1659}
1660
1662 if (const auto host = resolveSelected()) return host->get().worldAnchor()->screenY;
1663 return 0.f;
1664}
1665
1666void UI::setHostAnchor(float x, float y) {
1667 auto host = resolveSelected();
1668 if (!host) return;
1669 auto m = host->get().meta();
1670 m->anchorX = x;
1671 m->anchorY = y;
1672}
1673
1674void UI::setHostSize(float w, float h) {
1675 auto host = resolveSelected();
1676 if (!host) return;
1677 auto m = host->get().meta();
1678 m->hasSize = true;
1679 m->sizeX = w;
1680 m->sizeY = h;
1681}
1682
1683void UI::setHostPercent(float w, float h) {
1684 auto host = resolveSelected();
1685 if (!host) return;
1686 auto m = host->get().meta();
1687 m->percentW = w;
1688 m->percentH = h;
1689}
1690
1691void UI::animateHostPos(float x, float y, float durationMs, const std::string &ease, float delayMs) {
1692 if (!resolveSelected()) return;
1693 tweens_.animateHostPos(selected_, x, y, durationMs, ease, delayMs, uiTweenWallClockMs());
1694}
1695
1696void UI::animateHostSize(float w, float h, float durationMs, const std::string &ease, float delayMs) {
1697 if (!resolveSelected()) return;
1698 tweens_.animateHostSize(selected_, w, h, durationMs, ease, delayMs, uiTweenWallClockMs());
1699}
1700
1701void UI::animateHostOverlayAlpha(float alpha, float durationMs, const std::string &ease, float delayMs) {
1702 if (!resolveSelected()) return;
1703 tweens_.animateHostOverlayAlpha(selected_, alpha, durationMs, ease, delayMs, uiTweenWallClockMs());
1704}
1705
1706std::string UI::consumeClick() { return UISystem::consumeClick(); }
1707
1709
1710std::string UI::dragDropSupport() const {
1712 ? "supported"
1713 : "unsupported-platform";
1714}
1715
1716std::string UI::consumeDrop() {
1717 auto drop = UISystem::consumeDrop();
1718 if (!drop) return {};
1719 lastDropType_ = std::move(drop->payloadType);
1720 lastDropText_ = std::move(drop->payloadText);
1721 lastDropSource_ = drop->sourceHostName.empty()
1722 ? std::string{}
1723 : drop->sourceHostName + "/" + drop->sourceNodeId;
1724 lastDropOrigin_ = drop->origin == DragDropOrigin::OperatingSystemFile ? "os-file"
1725 : "internal";
1726 return drop->targetHostName.empty() ? drop->targetNodeId
1727 : drop->targetHostName + "/" + drop->targetNodeId;
1728}
1729
1730std::string UI::getDropType() const { return lastDropType_; }
1731
1732std::string UI::getDropText() const { return lastDropText_; }
1733
1734std::string UI::getDropSource() const { return lastDropSource_; }
1735
1736std::string UI::getDropOrigin() const { return lastDropOrigin_; }
1737
1739
1741
1742bool UI::setTheme(const std::string &name) { return setThemeByName(name); }
1743
1744std::string UI::getTheme() const { return globalThemeName(); }
1745
1746std::string UI::defineStyleClass(const std::string &name, const std::string &parent) {
1748}
1749
1750void UI::animateItemOpacity(const std::string &id, float opacity, float durationMs, const std::string &ease,
1751 float delayMs) {
1752 if (!resolveSelected()) return;
1753 // Script-facing facade: missing hosts/nodes are no-ops (same as other UI setters).
1754 tweens_.animateItemOpacity(selected_, id, opacity, durationMs, ease, delayMs, uiTweenWallClockMs())
1755 .ignore("UI.animateItemOpacity: host/node unavailable");
1756}
1757
1758void UI::animateItemPos(const std::string &id, float x, float y, float durationMs, const std::string &ease,
1759 float delayMs) {
1760 if (!resolveSelected()) return;
1761 tweens_.animateItemPos(selected_, id, x, y, durationMs, ease, delayMs, uiTweenWallClockMs())
1762 .ignore("UI.animateItemPos: host/node unavailable");
1763}
1764
1766 if (!resolveSelected()) return;
1767 tweens_.cancelHost(selected_);
1768}
1769
1770void UI::cancelItemTweens(const std::string &id) {
1771 if (!resolveSelected()) return;
1772 tweens_.cancelItem(selected_, id);
1773}
1774
1776 if (!resolveSelected()) return;
1777 tweens_.cancelAll(selected_);
1778}
1779
1780std::string UI::setStyleClassColor(const std::string &name, const std::string &property, float r,
1781 float g, float b, float a) {
1783}
1784
1785std::string UI::setStyleClassMetric(const std::string &name, const std::string &property, float x,
1786 float y) {
1788}
1789
1791
1795
1799
1800void UI::setScale(float scale) {
1801 if (!isBackendReady()) {
1802 if (!initBackend()) return;
1803 }
1804 if (backend_) backend_->setScale(scale);
1806}
1807
1808float UI::getScale() const {
1809 return backend_ ? backend_->getScale() : 1.f;
1810}
1811
1812std::string UI::getStats() const {
1813 const UIStats &s = UISystem::stats();
1814 char buf[160];
1815 std::snprintf(buf, sizeof(buf), "hosts=%d nodes=%d measureMs=%.3f walkMs=%.3f", s.hostCount,
1816 s.nodeCount, s.measureMs, s.walkMs);
1817 return buf;
1818}
1819
1820std::string UI::getLayoutDiagnostics() const {
1821 auto host = resolveSelected();
1822 if (!host) return "{\"nodes\":[]}";
1823 std::ostringstream out;
1824 out << "{\"host\":" << jsonQuoted(host->get().getName()) << ",\"nodes\":[";
1825 bool first = true;
1826 for (const UINode &node : host->get().tree()->nodes) {
1827 if (!first) out << ',';
1828 first = false;
1829 out << "{\"id\":" << jsonQuoted(node.id) << ",\"width\":" << node.measuredW
1830 << ",\"height\":" << node.measuredH << ",\"overflowX\":"
1831 << node.layoutOverflowX << ",\"overflowY\":" << node.layoutOverflowY << '}';
1832 }
1833 out << "]}";
1834 return out.str();
1835}
1836
1837std::string UI::getAccessibilitySnapshot() const {
1838 auto host = resolveSelected();
1839 if (!host) return "{\"nodes\":[]}";
1840 std::ostringstream out;
1841 out << "{\"host\":" << jsonQuoted(host->get().getName()) << ",\"nodes\":[";
1842 bool first = true;
1843 for (const UINode &node : host->get().tree()->nodes) {
1844 if (node.accessibilityRole == AccessibilityRole::Auto &&
1845 node.accessibilityName.empty())
1846 continue;
1847 if (!first) out << ',';
1848 first = false;
1849 out << "{\"id\":" << jsonQuoted(node.id) << ",\"role\":"
1850 << static_cast<int>(node.accessibilityRole) << ",\"name\":"
1851 << jsonQuoted(node.accessibilityName) << ",\"description\":"
1852 << jsonQuoted(node.accessibilityDescription) << ",\"enabled\":"
1853 << (node.enabled ? "true" : "false") << ",\"focused\":"
1854 << (node.focused ? "true" : "false") << '}';
1855 }
1856 out << "]}";
1857 return out.str();
1858}
1859
1860#if !(defined(EVENGINE_WEBGPU) && defined(__EMSCRIPTEN__))
1861std::string UI::saveTreeJson() const {
1862 auto host = resolveSelected();
1863 if (!host) return "{}";
1864 auto t = host->get().tree();
1865 Poco::JSON::Object root;
1866 root.set("schema", "eve.ui.tree");
1867 root.set("version", 4);
1868 root.set("host", host->get().getName());
1869 if (t->root >= 0) nodeToJson(*t, t->nodes[size_t(t->root)], root);
1870 std::ostringstream oss;
1871 Poco::JSON::Stringifier::stringify(root, oss, 1);
1872 return oss.str();
1873}
1874
1875bool UI::loadTreeJson(const std::string &json) {
1876 auto host = resolveSelected();
1877 if (!host || json.empty()) return false;
1878 try {
1879 Poco::JSON::Parser parser;
1880 const Poco::Dynamic::Var result = parser.parse(json);
1881 const Poco::JSON::Object::Ptr obj = result.extract<Poco::JSON::Object::Ptr>();
1882 if (!obj) return false;
1883 if (obj->has("schema") && obj->getValue<std::string>("schema") != "eve.ui.tree")
1884 return false;
1885 const int version = obj->optValue<int>("version", 1);
1886 if (version < 1 || version > 4) return false;
1887 WidgetDesc root = descFromJson(*obj);
1888 host->get().setTree(std::move(root));
1889 return true;
1890 } catch (...) {
1891 return false;
1892 }
1893}
1894#else
1895// WebGPU trims Poco. Use EVCommon's owning Value/JSON path so UI assets retain
1896// their portable core rather than degrading to a silent no-op.
1897std::string UI::saveTreeJson() const {
1898 auto host = resolveSelected();
1899 if (!host) return "{}";
1900 static const char *types[] = {
1901 "window", "text", "button", "sameLine", "group", "separator", "checkbox",
1902 "slider", "progress", "inputText", "collapsingHeader", "child", "flex", "spacer",
1903 "image", "imageButton", "combo", "scrollList", "viewport", "searchField", "switch",
1904 "badge", "card", "sectionHeader", "menuBar", "menu", "menuItem", "toolbar", "toolbox",
1905 "sidebar", "statusBar", "splitPane", "ninePatchPanel", "colorPalette", "grid"};
1906 const auto tree = host->get().tree();
1907 std::function<eve::Value(int)> encode = [&](int index) -> eve::Value {
1908 const UINode &n = tree->nodes[size_t(index)];
1910 const int typeIndex = static_cast<int>(n.type);
1911 node.set("type", typeIndex >= 0 && typeIndex < int(std::size(types)) ? types[typeIndex]
1912 : "text");
1913 if (!n.id.empty()) node.set("id", n.id);
1914 if (!n.key.empty()) node.set("key", n.key);
1915 if (!n.text.empty()) node.set("text", n.text);
1916 if (!n.valueText.empty()) node.set("valueText", n.valueText);
1917 if (!n.tooltip.empty()) node.set("tooltip", n.tooltip);
1918 if (!n.styleClass.empty()) node.set("styleClass", n.styleClass);
1919 node.set("visible", n.visible);
1920 node.set("enabled", n.enabled);
1921 node.set("checked", n.checked);
1922 node.set("value", n.value);
1923 node.set("minValue", n.minValue);
1924 node.set("maxValue", n.maxValue);
1925 node.set("sizeX", n.sizeX);
1926 node.set("sizeY", n.sizeY);
1927 node.set("flexDirection", n.flexDirection == FlexDirection::Column ? "column" : "row");
1928 node.set("alignItems", int(n.alignItems));
1929 node.set("justifyContent", int(n.justifyContent));
1930 node.set("gap", n.gap);
1931 node.set("columnGap", n.columnGap);
1932 node.set("rowGap", n.rowGap);
1933 node.set("flexGrow", n.flexGrow);
1934 node.set("flexShrink", n.flexShrink);
1935 node.set("flexBasis", n.flexBasis);
1936 node.set("alignSelf", n.alignSelf);
1937 node.set("aspectRatio", n.aspectRatio);
1938 node.set("flexWrap", n.flexWrap == FlexWrap::Wrap ? "wrap" : "nowrap");
1939 node.set("overflow", int(n.overflow));
1940 node.set("gridColumns", n.gridColumns);
1941 node.set("gridColumnSpan", n.gridColumnSpan);
1942 node.set("accessibilityRole", int(n.accessibilityRole));
1943 node.set("accessibilityName", n.accessibilityName);
1944 node.set("accessibilityDescription", n.accessibilityDescription);
1946 for (int child = n.firstChild; child >= 0;
1947 child = tree->nodes[size_t(child)].nextSibling)
1949 node.set("children", std::move(children));
1950 return node;
1951 };
1952 eve::Value root = tree->root >= 0 ? encode(tree->root) : eve::Value::object({});
1953 root.set("schema", "eve.ui.tree");
1954 root.set("version", 4);
1955 root.set("host", host->get().getName());
1956 auto encoded = eve::json::stringify(root);
1957 return encoded.ok() ? std::move(encoded).takeValue() : "{}";
1958}
1959
1960bool UI::loadTreeJson(const std::string &text) {
1961 auto host = resolveSelected();
1962 if (!host || text.empty()) return false;
1963 std::string error;
1965 const eve::json::Value root = document.root();
1966 if (!document.valid() || !root.isObject()) return false;
1967 if (root.has("schema") && root.getString("schema") != "eve.ui.tree") return false;
1968 const int version = root.getInt("version", 1);
1969 if (version < 1 || version > 4) return false;
1970 static const char *types[] = {
1971 "window", "text", "button", "sameLine", "group", "separator", "checkbox",
1972 "slider", "progress", "inputText", "collapsingHeader", "child", "flex", "spacer",
1973 "image", "imageButton", "combo", "scrollList", "viewport", "searchField", "switch",
1974 "badge", "card", "sectionHeader", "menuBar", "menu", "menuItem", "toolbar", "toolbox",
1975 "sidebar", "statusBar", "splitPane", "ninePatchPanel", "colorPalette", "grid"};
1976 std::function<WidgetDesc(eve::json::Value)> decode = [&](eve::json::Value value) {
1977 WidgetDesc node;
1978 const std::string type = value.getString("type", "text");
1979 for (int i = 0; i < int(std::size(types)); ++i)
1980 if (type == types[i]) node.type = static_cast<NodeType>(i);
1981 node.id = value.getString("id");
1982 node.key = value.getString("key");
1983 node.text = value.getString("text");
1984 node.valueText = value.getString("valueText");
1985 node.tooltip = value.getString("tooltip");
1986 node.styleClass = value.getString("styleClass");
1987 node.visible = value.getBool("visible", true);
1988 node.enabled = value.getBool("enabled", true);
1989 node.checked = value.getBool("checked", false);
1990 node.value = value.getFloat("value");
1991 node.minValue = value.getFloat("minValue");
1992 node.maxValue = value.getFloat("maxValue", 1.f);
1993 node.sizeX = value.getFloat("sizeX");
1994 node.sizeY = value.getFloat("sizeY");
1995 node.flexDirection = value.getString("flexDirection") == "column" ? FlexDirection::Column
1997 node.alignItems = static_cast<FlexAlign>(value.getInt("alignItems"));
1998 node.justifyContent = static_cast<FlexJustify>(value.getInt("justifyContent"));
1999 node.gap = value.getFloat("gap", -1.f);
2000 node.columnGap = value.getFloat("columnGap", -1.f);
2001 node.rowGap = value.getFloat("rowGap", -1.f);
2002 node.flexGrow = value.getFloat("flexGrow");
2003 node.flexShrink = value.getFloat("flexShrink", 1.f);
2004 node.flexBasis = value.getFloat("flexBasis", -1.f);
2005 node.alignSelf = value.getInt("alignSelf", -1);
2006 node.aspectRatio = value.getFloat("aspectRatio");
2007 node.flexWrap = value.getString("flexWrap") == "wrap" ? FlexWrap::Wrap : FlexWrap::NoWrap;
2008 node.overflow = static_cast<OverflowMode>(value.getInt("overflow"));
2009 node.gridColumns = std::max(1, value.getInt("gridColumns", 1));
2010 node.gridColumnSpan = std::max(1, value.getInt("gridColumnSpan", 1));
2011 node.accessibilityRole = static_cast<AccessibilityRole>(value.getInt("accessibilityRole"));
2012 node.accessibilityName = value.getString("accessibilityName");
2013 node.accessibilityDescription = value.getString("accessibilityDescription");
2014 const eve::json::Value children = value.get("children");
2015 for (size_t i = 0; i < children.size(); ++i)
2016 if (children.at(i).isObject()) node.children.push_back(decode(children.at(i)));
2017 return node;
2018 };
2019 host->get().setTree(decode(root));
2020 return true;
2021}
2022#endif
2023
2024graphics::Canvas *UI::viewportCanvas(const std::string &id) {
2025 auto host = resolveSelected();
2026 if (!host || id.empty()) return nullptr;
2027 const std::string key = host->get().getName() + "/" + id;
2028 if (auto state = UISystem::viewportState(host->get().getName(), id)) return state->get().canvas;
2029 auto ensured = UISystem::ensureViewport(key, 320, 240);
2030 if (!ensured.ok()) return nullptr;
2031 return std::move(ensured).takeValue().get().canvas;
2032}
2033
2034bool UI::viewportHovered(const std::string &id) {
2035 auto host = resolveSelected();
2036 if (!host) return false;
2037 if (auto state = UISystem::viewportState(host->get().getName(), id)) return state->get().hovered;
2038 return false;
2039}
2040
2041bool UI::viewportActive(const std::string &id) {
2042 auto host = resolveSelected();
2043 if (!host) return false;
2044 if (auto state = UISystem::viewportState(host->get().getName(), id)) return state->get().active;
2045 return false;
2046}
2047
2048float UI::viewportMouseX(const std::string &id) {
2049 auto host = resolveSelected();
2050 if (!host) return 0.f;
2051 if (auto state = UISystem::viewportState(host->get().getName(), id)) return state->get().mouseX;
2052 return 0.f;
2053}
2054
2055float UI::viewportMouseY(const std::string &id) {
2056 auto host = resolveSelected();
2057 if (!host) return 0.f;
2058 if (auto state = UISystem::viewportState(host->get().getName(), id)) return state->get().mouseY;
2059 return 0.f;
2060}
2061
2062float UI::viewportDragDX(const std::string &id) {
2063 auto host = resolveSelected();
2064 if (!host) return 0.f;
2065 if (auto state = UISystem::viewportState(host->get().getName(), id)) return state->get().dragDX;
2066 return 0.f;
2067}
2068
2069float UI::viewportDragDY(const std::string &id) {
2070 auto host = resolveSelected();
2071 if (!host) return 0.f;
2072 if (auto state = UISystem::viewportState(host->get().getName(), id)) return state->get().dragDY;
2073 return 0.f;
2074}
2075
2076float UI::viewportWheel(const std::string &id) {
2077 auto host = resolveSelected();
2078 if (!host) return 0.f;
2079 if (auto state = UISystem::viewportState(host->get().getName(), id)) return state->get().wheel;
2080 return 0.f;
2081}
2082
2083#if !(defined(EVENGINE_WEBGPU) && defined(__EMSCRIPTEN__))
2084namespace {
2085
2086const char *nodeTypeName(NodeType t) {
2087 switch (t) {
2088 case NodeType::Window: return "window";
2089 case NodeType::Text: return "text";
2090 case NodeType::Button: return "button";
2091 case NodeType::SameLine: return "sameLine";
2092 case NodeType::Group: return "group";
2093 case NodeType::Separator: return "separator";
2094 case NodeType::Checkbox: return "checkbox";
2095 case NodeType::Slider: return "slider";
2096 case NodeType::Progress: return "progress";
2097 case NodeType::InputText: return "inputText";
2098 case NodeType::CollapsingHeader: return "collapsingHeader";
2099 case NodeType::Child: return "child";
2100 case NodeType::Flex: return "flex";
2101 case NodeType::Spacer: return "spacer";
2102 case NodeType::Image: return "image";
2103 case NodeType::ImageButton: return "imageButton";
2104 case NodeType::Combo: return "combo";
2105 case NodeType::ScrollList: return "scrollList";
2106 case NodeType::Viewport: return "viewport";
2107 case NodeType::SearchField: return "searchField";
2108 case NodeType::Switch: return "switch";
2109 case NodeType::Badge: return "badge";
2110 case NodeType::Card: return "card";
2111 case NodeType::NinePatchPanel: return "ninePatchPanel";
2112 case NodeType::ColorPalette: return "colorPalette";
2113 case NodeType::Grid: return "grid";
2114 case NodeType::SectionHeader: return "sectionHeader";
2115 case NodeType::MenuBar: return "menuBar";
2116 case NodeType::Menu: return "menu";
2117 case NodeType::MenuItem: return "menuItem";
2118 case NodeType::Toolbar: return "toolbar";
2119 case NodeType::Toolbox: return "toolbox";
2120 case NodeType::Sidebar: return "sidebar";
2121 case NodeType::StatusBar: return "statusBar";
2122 case NodeType::SplitPane: return "splitPane";
2123 }
2124 return "text";
2125}
2126
2127NodeType nodeTypeFromName(const std::string &s) {
2128 if (s == "window") return NodeType::Window;
2129 if (s == "button") return NodeType::Button;
2130 if (s == "sameLine") return NodeType::SameLine;
2131 if (s == "group") return NodeType::Group;
2132 if (s == "separator") return NodeType::Separator;
2133 if (s == "checkbox") return NodeType::Checkbox;
2134 if (s == "slider") return NodeType::Slider;
2135 if (s == "progress") return NodeType::Progress;
2136 if (s == "inputText") return NodeType::InputText;
2137 if (s == "collapsingHeader") return NodeType::CollapsingHeader;
2138 if (s == "child") return NodeType::Child;
2139 if (s == "flex") return NodeType::Flex;
2140 if (s == "spacer") return NodeType::Spacer;
2141 if (s == "image") return NodeType::Image;
2142 if (s == "imageButton") return NodeType::ImageButton;
2143 if (s == "combo") return NodeType::Combo;
2144 if (s == "scrollList") return NodeType::ScrollList;
2145 if (s == "viewport") return NodeType::Viewport;
2146 if (s == "searchField") return NodeType::SearchField;
2147 if (s == "switch") return NodeType::Switch;
2148 if (s == "badge") return NodeType::Badge;
2149 if (s == "card") return NodeType::Card;
2150 if (s == "ninePatchPanel") return NodeType::NinePatchPanel;
2151 if (s == "colorPalette" || s == "color-palette" || s == "color") return NodeType::ColorPalette;
2152 if (s == "grid") return NodeType::Grid;
2153 if (s == "sectionHeader") return NodeType::SectionHeader;
2154 if (s == "menuBar") return NodeType::MenuBar;
2155 if (s == "menu") return NodeType::Menu;
2156 if (s == "menuItem") return NodeType::MenuItem;
2157 if (s == "toolbar") return NodeType::Toolbar;
2158 if (s == "toolbox") return NodeType::Toolbox;
2159 if (s == "sidebar") return NodeType::Sidebar;
2160 if (s == "statusBar") return NodeType::StatusBar;
2161 if (s == "splitPane") return NodeType::SplitPane;
2162 return NodeType::Text;
2163}
2164
2165void nodeToJson(const UIHost::Tree &tree, const UINode &n, Poco::JSON::Object &o) {
2166 o.set("type", nodeTypeName(n.type));
2167 if (!n.id.empty()) o.set("id", n.id);
2168 if (!n.key.empty()) o.set("key", n.key);
2169 if (!n.text.empty()) o.set("text", n.text);
2170 if (!n.valueText.empty()) o.set("valueText", n.valueText);
2171 if (!n.tooltip.empty()) o.set("tooltip", n.tooltip);
2172 if (!n.visible) o.set("visible", false);
2173 if (!n.enabled) o.set("enabled", false);
2174 if (n.focusMode != FocusMode::All)
2175 o.set("focusMode", n.focusMode == FocusMode::None ? "none" : "click");
2176 if (n.mouseFilter != MouseFilter::Stop)
2177 o.set("mouseFilter", n.mouseFilter == MouseFilter::Pass ? "pass" : "ignore");
2178 if (n.themePreset != ThemePreset::Inherit)
2179 o.set("theme", n.themePreset == ThemePreset::Dark ? "dark" : "light");
2180 if (!n.styleClass.empty()) o.set("styleClass", n.styleClass);
2181 if (n.tabIndex != 0) o.set("tabIndex", n.tabIndex);
2182 if (!n.focusPrevious.empty()) o.set("focusPrevious", n.focusPrevious);
2183 if (!n.focusNext.empty()) o.set("focusNext", n.focusNext);
2184 if (!n.focusLeft.empty()) o.set("focusLeft", n.focusLeft);
2185 if (!n.focusRight.empty()) o.set("focusRight", n.focusRight);
2186 if (!n.focusUp.empty()) o.set("focusUp", n.focusUp);
2187 if (!n.focusDown.empty()) o.set("focusDown", n.focusDown);
2188 if (n.accessibilityRole != AccessibilityRole::Auto) {
2189 const char *role = "auto";
2190 switch (n.accessibilityRole) {
2191 case AccessibilityRole::Button: role = "button"; break;
2192 case AccessibilityRole::Checkbox: role = "checkbox"; break;
2193 case AccessibilityRole::Slider: role = "slider"; break;
2194 case AccessibilityRole::Text: role = "text"; break;
2195 case AccessibilityRole::TextInput: role = "text-input"; break;
2196 case AccessibilityRole::List: role = "list"; break;
2197 case AccessibilityRole::ListItem: role = "list-item"; break;
2198 case AccessibilityRole::Menu: role = "menu"; break;
2199 case AccessibilityRole::MenuItem: role = "menu-item"; break;
2200 case AccessibilityRole::Progress: role = "progress"; break;
2201 case AccessibilityRole::Region: role = "region"; break;
2202 case AccessibilityRole::Tab: role = "tab"; break;
2203 case AccessibilityRole::Window: role = "window"; break;
2204 case AccessibilityRole::Auto: break;
2205 }
2206 o.set("accessibilityRole", role);
2207 }
2208 if (!n.accessibilityName.empty()) o.set("accessibilityName", n.accessibilityName);
2209 if (!n.accessibilityDescription.empty())
2210 o.set("accessibilityDescription", n.accessibilityDescription);
2211 if (n.dragSource) {
2212 o.set("dragSource", true);
2213 o.set("dragPayloadType", n.dragPayloadType);
2214 o.set("dragPayloadText", n.dragPayloadText);
2215 }
2216 if (n.dropTarget) {
2217 o.set("dropTarget", true);
2218 o.set("acceptedDropType", n.acceptedDropType);
2219 }
2220 if (n.checked) o.set("checked", true);
2221 if (!n.open) o.set("open", false);
2222 if (n.value != 0.f) o.set("value", n.value);
2223 if (n.minValue != 0.f) o.set("minValue", n.minValue);
2224 if (n.maxValue != 1.f) o.set("maxValue", n.maxValue);
2225 if (n.sizeX != 0.f) o.set("sizeX", n.sizeX);
2226 if (n.sizeY != 0.f) o.set("sizeY", n.sizeY);
2227 if (n.marginL != 0.f || n.marginT != 0.f || n.marginR != 0.f || n.marginB != 0.f)
2228 o.set("margin", Poco::Dynamic::Array({n.marginL, n.marginT, n.marginR, n.marginB}));
2229 if (n.paddingL != 0.f || n.paddingT != 0.f || n.paddingR != 0.f || n.paddingB != 0.f)
2230 o.set("padding", Poco::Dynamic::Array({n.paddingL, n.paddingT, n.paddingR, n.paddingB}));
2231 if (n.minSizeX != 0.f) o.set("minSizeX", n.minSizeX);
2232 if (n.minSizeY != 0.f) o.set("minSizeY", n.minSizeY);
2233 if (n.maxSizeX != 0.f) o.set("maxSizeX", n.maxSizeX);
2234 if (n.maxSizeY != 0.f) o.set("maxSizeY", n.maxSizeY);
2235 if (n.percentW != 0.f) o.set("percentW", n.percentW);
2236 if (n.percentH != 0.f) o.set("percentH", n.percentH);
2237 if (n.aspectRatio > 0.f) o.set("aspectRatio", n.aspectRatio);
2238 if (n.absolute) {
2239 o.set("absolute", true);
2240 o.set("anchorX", n.anchorX);
2241 o.set("anchorY", n.anchorY);
2242 o.set("posX", n.posX);
2243 o.set("posY", n.posY);
2244 }
2245 if (n.wrapWidth != 0.f) o.set("wrapWidth", n.wrapWidth);
2246 if (n.flexDirection != FlexDirection::Row)
2247 o.set("flexDirection", n.flexDirection == FlexDirection::Column ? "column" : "row");
2248 if (n.alignItems != FlexAlign::Start) o.set("alignItems", int(n.alignItems));
2249 if (n.justifyContent != FlexJustify::Start) o.set("justifyContent", int(n.justifyContent));
2250 if (n.gap >= 0.f) o.set("gap", n.gap);
2251 if (n.flexGrow != 0.f) o.set("flexGrow", n.flexGrow);
2252 if (n.flexShrink != 1.f) o.set("flexShrink", n.flexShrink);
2253 if (n.flexBasis >= 0.f) o.set("flexBasis", n.flexBasis);
2254 if (n.alignSelf >= 0) o.set("alignSelf", n.alignSelf);
2255 if (n.columnGap >= 0.f) o.set("columnGap", n.columnGap);
2256 if (n.rowGap >= 0.f) o.set("rowGap", n.rowGap);
2257 if (n.flexWrap == FlexWrap::Wrap) o.set("flexWrap", "wrap");
2258 if (n.overflow != OverflowMode::Visible) o.set("overflow", int(n.overflow));
2259 if (n.type == NodeType::Grid) o.set("gridColumns", n.gridColumns);
2260 if (n.gridColumnSpan != 1) o.set("gridColumnSpan", n.gridColumnSpan);
2261 if (n.type == NodeType::ColorPalette || n.tintR != 1.f || n.tintG != 1.f || n.tintB != 1.f ||
2262 n.tintA != 1.f)
2263 o.set("tint", Poco::Dynamic::Array({n.tintR, n.tintG, n.tintB, n.tintA}));
2264 if (n.borderL != 0.f || n.borderT != 0.f || n.borderR != 0.f || n.borderB != 0.f)
2265 o.set("border", Poco::Dynamic::Array({n.borderL, n.borderT, n.borderR, n.borderB}));
2266 if (n.cornerRadius != 0.f) o.set("cornerRadius", n.cornerRadius);
2267 if (n.uv0x != 0.f || n.uv0y != 0.f || n.uv1x != 1.f || n.uv1y != 1.f)
2268 o.set("uv", Poco::Dynamic::Array({n.uv0x, n.uv0y, n.uv1x, n.uv1y}));
2269
2270 Poco::JSON::Array children;
2271 for (int c = n.firstChild; c >= 0; c = tree.nodes[size_t(c)].nextSibling) {
2272 Poco::JSON::Object child;
2273 nodeToJson(tree, tree.nodes[size_t(c)], child);
2274 children.add(child);
2275 }
2276 if (children.size() > 0) o.set("children", children);
2277}
2278
2279float fnum(const Poco::Dynamic::Var &v, float def = 0.f) {
2280 try {
2281 return float(v.convert<double>());
2282 } catch (...) {
2283 return def;
2284 }
2285}
2286
2287void applyCommonFields(WidgetDesc &d, const Poco::JSON::Object &o) {
2288 if (o.has("id")) d.id = o.getValue<std::string>("id");
2289 if (o.has("key")) d.key = o.getValue<std::string>("key");
2290 if (o.has("text")) d.text = o.getValue<std::string>("text");
2291 if (o.has("valueText")) d.valueText = o.getValue<std::string>("valueText");
2292 if (o.has("tooltip")) d.tooltip = o.getValue<std::string>("tooltip");
2293 if (o.has("visible")) d.visible = o.getValue<bool>("visible");
2294 if (o.has("enabled")) d.enabled = o.getValue<bool>("enabled");
2295 if (o.has("focusMode"))
2296 d.focusMode = parseFocusMode(o.getValue<std::string>("focusMode"));
2297 if (o.has("mouseFilter"))
2298 d.mouseFilter = parseMouseFilter(o.getValue<std::string>("mouseFilter"));
2299 if (o.has("theme"))
2300 d.themePreset = parseThemePreset(o.getValue<std::string>("theme"));
2301 if (o.has("styleClass")) d.styleClass = o.getValue<std::string>("styleClass");
2302 if (o.has("tabIndex")) d.tabIndex = int(fnum(o.get("tabIndex")));
2303 if (o.has("focusPrevious"))
2304 d.focusPrevious = o.getValue<std::string>("focusPrevious");
2305 if (o.has("focusNext")) d.focusNext = o.getValue<std::string>("focusNext");
2306 if (o.has("focusLeft")) d.focusLeft = o.getValue<std::string>("focusLeft");
2307 if (o.has("focusRight")) d.focusRight = o.getValue<std::string>("focusRight");
2308 if (o.has("focusUp")) d.focusUp = o.getValue<std::string>("focusUp");
2309 if (o.has("focusDown")) d.focusDown = o.getValue<std::string>("focusDown");
2310 if (o.has("accessibilityRole"))
2311 d.accessibilityRole =
2312 parseAccessibilityRole(o.getValue<std::string>("accessibilityRole"));
2313 if (o.has("accessibilityName"))
2314 d.accessibilityName = o.getValue<std::string>("accessibilityName");
2315 if (o.has("accessibilityDescription"))
2316 d.accessibilityDescription =
2317 o.getValue<std::string>("accessibilityDescription");
2318 if (o.has("dragSource")) d.dragSource = o.getValue<bool>("dragSource");
2319 if (o.has("dragPayloadType"))
2320 d.dragPayloadType = o.getValue<std::string>("dragPayloadType");
2321 if (o.has("dragPayloadText"))
2322 d.dragPayloadText = o.getValue<std::string>("dragPayloadText");
2323 if (o.has("dropTarget")) d.dropTarget = o.getValue<bool>("dropTarget");
2324 if (o.has("acceptedDropType"))
2325 d.acceptedDropType = o.getValue<std::string>("acceptedDropType");
2326 if (o.has("checked")) d.checked = o.getValue<bool>("checked");
2327 if (o.has("open")) d.open = o.getValue<bool>("open");
2328 if (o.has("value")) d.value = fnum(o.get("value"));
2329 if (o.has("minValue")) d.minValue = fnum(o.get("minValue"));
2330 if (o.has("maxValue")) d.maxValue = fnum(o.get("maxValue"));
2331 if (o.has("sizeX")) d.sizeX = fnum(o.get("sizeX"));
2332 if (o.has("sizeY")) d.sizeY = fnum(o.get("sizeY"));
2333 if (o.has("margin")) {
2334 const Poco::JSON::Array::Ptr a = o.getArray("margin");
2335 if (a && a->size() >= 4) {
2336 d.marginL = fnum(a->get(0));
2337 d.marginT = fnum(a->get(1));
2338 d.marginR = fnum(a->get(2));
2339 d.marginB = fnum(a->get(3));
2340 }
2341 }
2342 if (o.has("padding")) {
2343 const Poco::JSON::Array::Ptr a = o.getArray("padding");
2344 if (a && a->size() >= 4) {
2345 d.paddingL = fnum(a->get(0));
2346 d.paddingT = fnum(a->get(1));
2347 d.paddingR = fnum(a->get(2));
2348 d.paddingB = fnum(a->get(3));
2349 }
2350 }
2351 if (o.has("minSizeX")) d.minSizeX = fnum(o.get("minSizeX"));
2352 if (o.has("minSizeY")) d.minSizeY = fnum(o.get("minSizeY"));
2353 if (o.has("maxSizeX")) d.maxSizeX = fnum(o.get("maxSizeX"));
2354 if (o.has("maxSizeY")) d.maxSizeY = fnum(o.get("maxSizeY"));
2355 if (o.has("percentW")) d.percentW = fnum(o.get("percentW"));
2356 if (o.has("percentH")) d.percentH = fnum(o.get("percentH"));
2357 if (o.has("aspectRatio")) d.aspectRatio = fnum(o.get("aspectRatio"));
2358 if (o.has("absolute")) d.absolute = o.getValue<bool>("absolute");
2359 if (o.has("anchorX")) d.anchorX = fnum(o.get("anchorX"));
2360 if (o.has("anchorY")) d.anchorY = fnum(o.get("anchorY"));
2361 if (o.has("posX")) d.posX = fnum(o.get("posX"));
2362 if (o.has("posY")) d.posY = fnum(o.get("posY"));
2363 if (o.has("wrapWidth")) d.wrapWidth = fnum(o.get("wrapWidth"));
2364 if (o.has("flexDirection")) d.flexDirection =
2365 o.getValue<std::string>("flexDirection") == "column" ? FlexDirection::Column
2367 if (o.has("alignItems")) d.alignItems = FlexAlign(int(fnum(o.get("alignItems"))));
2368 if (o.has("justifyContent"))
2369 d.justifyContent = FlexJustify(int(fnum(o.get("justifyContent"))));
2370 if (o.has("gap")) d.gap = fnum(o.get("gap"), -1.f);
2371 if (o.has("flexGrow")) d.flexGrow = fnum(o.get("flexGrow"));
2372 if (o.has("flexShrink")) d.flexShrink = fnum(o.get("flexShrink"), 1.f);
2373 if (o.has("flexBasis")) d.flexBasis = fnum(o.get("flexBasis"), -1.f);
2374 if (o.has("alignSelf")) d.alignSelf = int(fnum(o.get("alignSelf"), -1.f));
2375 if (o.has("columnGap")) d.columnGap = fnum(o.get("columnGap"), -1.f);
2376 if (o.has("rowGap")) d.rowGap = fnum(o.get("rowGap"), -1.f);
2377 if (o.has("flexWrap"))
2378 d.flexWrap = o.getValue<std::string>("flexWrap") == "wrap" ? FlexWrap::Wrap
2380 if (o.has("overflow")) d.overflow = OverflowMode(int(fnum(o.get("overflow"))));
2381 if (o.has("gridColumns"))
2382 d.gridColumns = std::max(1, int(fnum(o.get("gridColumns"), 1.f)));
2383 if (o.has("gridColumnSpan"))
2384 d.gridColumnSpan = std::max(1, int(fnum(o.get("gridColumnSpan"), 1.f)));
2385 if (o.has("tint")) {
2386 const Poco::JSON::Array::Ptr a = o.getArray("tint");
2387 if (a && a->size() >= 4) {
2388 d.tintR = fnum(a->get(0), 1.f);
2389 d.tintG = fnum(a->get(1), 1.f);
2390 d.tintB = fnum(a->get(2), 1.f);
2391 d.tintA = fnum(a->get(3), 1.f);
2392 }
2393 }
2394 if (o.has("border")) {
2395 const Poco::JSON::Array::Ptr a = o.getArray("border");
2396 if (a && a->size() >= 4) {
2397 d.borderL = fnum(a->get(0));
2398 d.borderT = fnum(a->get(1));
2399 d.borderR = fnum(a->get(2));
2400 d.borderB = fnum(a->get(3));
2401 }
2402 }
2403 if (o.has("cornerRadius")) d.cornerRadius = fnum(o.get("cornerRadius"));
2404 if (o.has("uv")) {
2405 const Poco::JSON::Array::Ptr a = o.getArray("uv");
2406 if (a && a->size() >= 4) {
2407 d.uv0x = fnum(a->get(0));
2408 d.uv0y = fnum(a->get(1));
2409 d.uv1x = fnum(a->get(2), 1.f);
2410 d.uv1y = fnum(a->get(3), 1.f);
2411 }
2412 }
2413}
2414
2415WidgetDesc descFromJson(const Poco::JSON::Object &o) {
2416 WidgetDesc d;
2417 d.type = nodeTypeFromName(o.optValue<std::string>("type", "text"));
2418 applyCommonFields(d, o);
2419 if (o.has("children")) {
2420 const Poco::JSON::Array::Ptr children = o.getArray("children");
2421 for (size_t i = 0; i < children->size(); ++i) {
2422 const Poco::JSON::Object::Ptr child =
2423 children->getObject(static_cast<unsigned int>(i));
2424 if (child) d.children.push_back(descFromJson(*child));
2425 }
2426 }
2427 return d;
2428}
2429
2430} // namespace
2431#endif
2432
2433void UI::mountSimple(const std::string &title, const std::string &labelText,
2434 const std::string &buttonText) {
2435 const UIHostHandle handle =
2436 mountAs("default", window(title, {text(labelText, "label"), button(buttonText, "btn")}, "root"));
2437 if (!UIHost::resolve(handle)) return;
2438}
2439
2441 if (!inspector_) inspector_ = std::make_unique<Inspector>();
2442 inspector_->setPickScene([this]() { return callPickHandler(); });
2443 inspector_->open();
2444 return inspector_->isOpen();
2445}
2446
2448 if (inspector_) inspector_->close();
2449}
2450
2452 if (!inspector_) inspector_ = std::make_unique<Inspector>();
2453 inspector_->refresh();
2454 return inspector_->instanceCount() > 0;
2455}
2456
2457bool UI::inspectSelectClass(const std::string &name) {
2458 if (!inspector_) inspector_ = std::make_unique<Inspector>();
2459 inspector_->setPickScene([this]() { return callPickHandler(); });
2460 inspector_->open(); // scans classes and mounts the panel if not open yet
2461 return inspector_->selectClass(name);
2462}
2463
2464bool UI::inspectObject(ssq::Object object) {
2465 if (!inspector_) inspector_ = std::make_unique<Inspector>();
2466 inspector_->setPickScene([this]() { return callPickHandler(); });
2467 inspector_->open(); // scans classes and mounts the panel if not open yet
2468 return inspector_->inspectObject(object);
2469}
2470
2471bool UI::inspectSetPickHandler(ssq::Function fn) {
2473 if (!rt) return false;
2474 HSQUIRRELVM squirrel = rt->handle();
2475 const SQInteger top = sq_gettop(squirrel);
2476 sq_pushroottable(squirrel);
2477 sq_pushstring(squirrel, "eve", -1);
2478 if (SQ_FAILED(sq_get(squirrel, -2)) ||
2479 sq_gettype(squirrel, -1) != OT_TABLE) {
2480 sq_settop(squirrel, top);
2481 return false;
2482 }
2483 sq_pushstring(squirrel, "_inspectorPickHandler", -1);
2484 sq_pushobject(squirrel, fn.getRaw());
2485 sq_newslot(squirrel, -3, SQFalse);
2486 sq_settop(squirrel, top);
2487 return true;
2488}
2489
2490ssq::Object UI::callPickHandler() {
2492 if (!rt) return {};
2493 HSQUIRRELVM squirrel = rt->handle();
2494 const SQInteger top = sq_gettop(squirrel);
2495 sq_pushroottable(squirrel);
2496 sq_pushstring(squirrel, "eve", -1);
2497 if (SQ_FAILED(sq_get(squirrel, -2)) ||
2498 sq_gettype(squirrel, -1) != OT_TABLE) {
2499 sq_settop(squirrel, top);
2500 return {};
2501 }
2502 sq_pushstring(squirrel, "_inspectorPickHandler", -1);
2503 if (SQ_FAILED(sq_get(squirrel, -2)) ||
2504 (sq_gettype(squirrel, -1) != OT_CLOSURE &&
2505 sq_gettype(squirrel, -1) != OT_NATIVECLOSURE)) {
2506 sq_settop(squirrel, top);
2507 return {};
2508 }
2509 sq_pushroottable(squirrel); // environment
2510 if (SQ_FAILED(sq_call(squirrel, 1, SQTrue, SQTrue))) {
2511 sq_settop(squirrel, top);
2512 return {};
2513 }
2514 if (sq_gettype(squirrel, -1) != OT_INSTANCE) {
2515 sq_settop(squirrel, top);
2516 return {};
2517 }
2518 ssq::Object out(squirrel);
2519 sq_getstackobj(squirrel, -1, &out.getRaw());
2520 sq_addref(squirrel, &out.getRaw());
2521 sq_settop(squirrel, top);
2522 return out;
2523}
2524
2526 if (!inspector_) inspector_ = std::make_unique<Inspector>();
2527 inspector_->setPickScene([this]() { return callPickHandler(); });
2528 inspector_->open();
2529 const ssq::Object picked = callPickHandler();
2530 if (picked.getType() != ssq::Type::INSTANCE) return false;
2531 return inspector_->inspectObject(picked);
2532}
2533
2535 return inspector_ && inspector_->addInstance();
2536}
2537
2538namespace {
2539
2540const char *propertyKindName(property_access::PropertyKind kind) {
2542 switch (kind) {
2543 case PropertyKind::Auto: return "auto";
2544 case PropertyKind::Bool: return "bool";
2545 case PropertyKind::Integer: return "integer";
2546 case PropertyKind::Number: return "number";
2547 case PropertyKind::String: return "string";
2548 case PropertyKind::Enum: return "enum";
2549 case PropertyKind::Color: return "color";
2550 case PropertyKind::Vec2: return "vec2";
2551 case PropertyKind::Vec3: return "vec3";
2552 case PropertyKind::Vec4: return "vec4";
2553 case PropertyKind::AssetRef: return "assetRef";
2554 case PropertyKind::ObjectRef: return "objectRef";
2555 case PropertyKind::Struct: return "struct";
2556 case PropertyKind::Array: return "array";
2557 case PropertyKind::Map: return "map";
2558 case PropertyKind::Action: return "action";
2559 case PropertyKind::ReadOnlyText: return "readOnlyText";
2560 }
2561 return "auto";
2562}
2563
2564} // namespace
2565
2566ssq::Object UI::propertySchema(ssq::Object instance) {
2567 Runtime *runtime = ModuleManager::runtime();
2568 if (!runtime) return ssq::Object();
2569 if (instance.getType() != ssq::Type::INSTANCE) return ssq::Object(runtime->handle());
2571 ssq::VM &vm = runtime->vm();
2572 ssq::Table out = vm.newTable();
2573 out.set("typeId", model.schema().typeId);
2574 out.set("version", static_cast<int>(model.schema().version));
2575 ssq::Array properties = vm.newArray();
2576 for (const property_access::PropertyDescriptor &property : model.schema().properties) {
2577 ssq::Table entry = vm.newTable();
2578 entry.set("path", property.path);
2579 entry.set("kind", std::string(propertyKindName(property.kind)));
2580 entry.set("displayName", property.displayName);
2581 entry.set("description", property.description);
2582 entry.set("category", property.category);
2583 entry.set("readOnly", property_access::hasFlag(property.flags, property_access::PropertyFlag::ReadOnly));
2584 entry.set("presenterHint", property.presenterHint);
2585 entry.set("units", property.numeric.units);
2586 if (property.numeric.minimum) entry.set("min", *property.numeric.minimum);
2587 if (property.numeric.maximum) entry.set("max", *property.numeric.maximum);
2588 if (property.numeric.step) entry.set("step", *property.numeric.step);
2589 ssq::Array choices = vm.newArray();
2590 for (const std::string &choice : property.choices) choices.push(choice);
2591 entry.set("choices", choices);
2592 properties.push(entry);
2593 }
2594 out.set("properties", properties);
2595 return out;
2596}
2597
2599 if (!databasePanel_) databasePanel_ = std::make_unique<DatabasePanel>();
2600 databasePanel_->open();
2601 return databasePanel_->isOpen();
2602}
2603
2605 if (databasePanel_) databasePanel_->close();
2606}
2607
2609 if (!databasePanel_) databasePanel_ = std::make_unique<DatabasePanel>();
2610 databasePanel_->refresh();
2611 return databasePanel_->isOpen();
2612}
2613
2614bool UI::dbSelectClass(const std::string &name) {
2615 if (!databasePanel_) databasePanel_ = std::make_unique<DatabasePanel>();
2616 databasePanel_->refresh();
2617 return databasePanel_->selectClass(name);
2618}
2619
2620uint64_t UI::dbRegister(ssq::Object object, const std::string &label) {
2621 if (!databasePanel_) databasePanel_ = std::make_unique<DatabasePanel>();
2622 databasePanel_->open(); // mount the panel so the entry becomes visible
2623 auto result = databasePanel_->registerObject(object, label);
2624 if (!result) return 0;
2625 return result.value().packed();
2626}
2627
2629 if (!databasePanel_) databasePanel_ = std::make_unique<DatabasePanel>();
2630 databasePanel_->open();
2631 auto result = databasePanel_->createInstance();
2632 if (!result) return 0;
2633 return result.value().packed();
2634}
2635
2637 if (!databasePanel_)
2639 eve::Diagnostic::error(eve::DiagnosticCode::NotFound, "database panel is not open", {}, {}, "ui"));
2641 auto result = databasePanel_->unregister(handle);
2642 if (!result.ok()) return eve::Result<void>::failure(result.status());
2643 return eve::Result<void>::success(result.status());
2644}
2645
2647 if (!inspector_) inspector_ = std::make_unique<Inspector>();
2648 inspector_->setPickScene([this]() { return callPickHandler(); });
2649 inspector_->open();
2650 if (!databasePanel_) databasePanel_ = std::make_unique<DatabasePanel>();
2651 databasePanel_->open();
2652 if (!scenePanel_) scenePanel_ = std::make_unique<ScenePanel>();
2653 scenePanel_->setPickHandler([this](const std::string &nodeId) {
2654 callScenePickHandler(nodeId);
2655 });
2656 scenePanel_->open();
2657 if (!editorShell_) editorShell_ = std::make_unique<EditorShell>();
2658 editorShell_->open(inspector_->host(), databasePanel_->host(),
2659 scenePanel_->host());
2660 return editorShell_->isOpen();
2661}
2662
2664 if (editorShell_) editorShell_->close();
2665}
2666
2667bool UI::editorSelectPanel(const std::string &name) {
2668 return editorShell_ && editorShell_->selectPanel(name);
2669}
2670
2672 if (!scenePanel_) scenePanel_ = std::make_unique<ScenePanel>();
2673 scenePanel_->setPickHandler([this](const std::string &nodeId) {
2674 callScenePickHandler(nodeId);
2675 });
2676 scenePanel_->open();
2677 return scenePanel_->isOpen();
2678}
2679
2681 if (scenePanel_) scenePanel_->close();
2682}
2683
2684bool UI::sceneSelectNode(const std::string &id) {
2685 return scenePanel_ && scenePanel_->selectNode(id);
2686}
2687
2688bool UI::sceneSetPickHandler(ssq::Function fn) {
2690 if (!rt) return false;
2691 HSQUIRRELVM squirrel = rt->handle();
2692 const SQInteger top = sq_gettop(squirrel);
2693 sq_pushroottable(squirrel);
2694 sq_pushstring(squirrel, "eve", -1);
2695 if (SQ_FAILED(sq_get(squirrel, -2)) ||
2696 sq_gettype(squirrel, -1) != OT_TABLE) {
2697 sq_settop(squirrel, top);
2698 return false;
2699 }
2700 sq_pushstring(squirrel, "_scenePickHandler", -1);
2701 sq_pushobject(squirrel, fn.getRaw());
2702 sq_newslot(squirrel, -3, SQFalse);
2703 sq_settop(squirrel, top);
2704 return true;
2705}
2706
2707void UI::callScenePickHandler(const std::string &nodeId) {
2709 if (!rt) return;
2710 HSQUIRRELVM squirrel = rt->handle();
2711 const SQInteger top = sq_gettop(squirrel);
2712 sq_pushroottable(squirrel);
2713 sq_pushstring(squirrel, "eve", -1);
2714 if (SQ_FAILED(sq_get(squirrel, -2)) ||
2715 sq_gettype(squirrel, -1) != OT_TABLE) {
2716 sq_settop(squirrel, top);
2717 return;
2718 }
2719 sq_pushstring(squirrel, "_scenePickHandler", -1);
2720 if (SQ_FAILED(sq_get(squirrel, -2)) ||
2721 (sq_gettype(squirrel, -1) != OT_CLOSURE &&
2722 sq_gettype(squirrel, -1) != OT_NATIVECLOSURE)) {
2723 sq_settop(squirrel, top);
2724 return;
2725 }
2726 sq_pushroottable(squirrel); // environment
2727 sq_pushstring(squirrel, nodeId.c_str(), -1); // node id argument
2728 sq_call(squirrel, 2, SQFalse, SQTrue);
2729 sq_settop(squirrel, top);
2730}
2731
2732void UI::expose(ssq::Table &table) {
2733 auto cls = table.addClass(name, UI::create, false);
2734 expose(cls);
2735 injectUIComponentClass(table);
2750}
2751
2752void UI::expose(ssq::Class &cls) {
2753 cls.addFunc("getName", &UI::getName);
2754 cls.addFunc("initBackend", &UI::initBackend);
2755 cls.addFunc("isBackendReady", &UI::isBackendReady);
2756 cls.addFunc("beginFrameAndRender", &UI::beginFrameAndRender);
2757 cls.addFunc("dispatchEvents", &UI::dispatchEvents);
2758 cls.addFunc("wantCaptureMouse", &UI::wantCaptureMouse);
2759 cls.addFunc("wantCaptureKeyboard", &UI::wantCaptureKeyboard);
2760
2761 cls.addFunc("select", &UI::select);
2762 cls.addFunc("bindOwner", &UI::bindOwner);
2763 cls.addFunc("mountBuildAs", &UI::mountBuildAs);
2764 cls.addFunc("remountBuildAs", &UI::remountBuildAs);
2765
2766 cls.addFunc("beginBuild", &UI::beginBuild);
2767 cls.addFunc("beginWindow", &UI::beginWindow);
2768 cls.addFunc("beginGroup", &UI::beginGroup);
2769 cls.addFunc("beginList", &UI::beginList);
2770 cls.addFunc("beginCollapsing", &UI::beginCollapsing);
2771 cls.addFunc("beginChild", &UI::beginChild);
2772 cls.addFunc("beginCard", &UI::beginCard);
2773 cls.addFunc("beginNinePatch", &UI::beginNinePatch);
2774 cls.addFunc("beginMenuBar", &UI::beginMenuBar);
2775 cls.addFunc("beginMenu", &UI::beginMenu);
2776 cls.addFunc("beginToolbar", &UI::beginToolbar);
2777 cls.addFunc("beginToolbox", &UI::beginToolbox);
2778 cls.addFunc("beginSidebar", &UI::beginSidebar);
2779 cls.addFunc("beginStatusBar", &UI::beginStatusBar);
2780 cls.addFunc("beginSplitPane", &UI::beginSplitPane);
2781 cls.addFunc("beginScrollList", &UI::beginScrollList);
2782 cls.addFunc("beginFlex", &UI::beginFlex);
2783 cls.addFunc("beginRow", &UI::beginRow);
2784 cls.addFunc("beginColumn", &UI::beginColumn);
2785 cls.addFunc("beginGrid", &UI::beginGrid);
2786 cls.addFunc("end", &UI::end);
2787 cls.addFunc("text", &UI::addText);
2788 cls.addFunc("textWrapped", &UI::addTextWrapped);
2789 cls.addFunc("button", &UI::addButton);
2790 cls.addFunc("icon", &UI::addIcon);
2791 cls.addFunc("iconButton", &UI::addIconButton);
2792 cls.addFunc("sameLine", &UI::addSameLine);
2793 cls.addFunc("separator", &UI::addSeparator);
2794 cls.addFunc("checkbox", &UI::addCheckbox);
2795 cls.addFunc("slider", &UI::addSlider);
2796 cls.addFunc("colorPalette", &UI::addColorPalette);
2797 cls.addFunc("progress", &UI::addProgress);
2798 cls.addFunc("image", &UI::addImage);
2799 cls.addFunc("ninePatch", &UI::addNinePatch);
2800 cls.addFunc("imageButton", &UI::addImageButton);
2801 cls.addFunc("viewport", &UI::addViewport);
2802 cls.addFunc("combo", &UI::addCombo);
2803 cls.addFunc("inputText", &UI::addInputText);
2804 cls.addFunc("searchField", &UI::addSearchField);
2805 cls.addFunc("switch", &UI::addSwitch);
2806 cls.addFunc("badge", &UI::addBadge);
2807 cls.addFunc("sectionHeader", &UI::addSectionHeader);
2808 cls.addFunc("menuItem", &UI::addMenuItem);
2809 cls.addFunc("spacer", &UI::addSpacer);
2810 cls.addFunc("setItemFlexGrow", &UI::setItemFlexGrow);
2811 cls.addFunc("setItemFlexShrink", &UI::setItemFlexShrink);
2812 cls.addFunc("setItemFlexBasis", &UI::setItemFlexBasis);
2813 cls.addFunc("setItemAlignSelf", &UI::setItemAlignSelf);
2814 cls.addFunc("setItemAspectRatio", &UI::setItemAspectRatio);
2815 cls.addFunc("setItemGridColumnSpan", &UI::setItemGridColumnSpan);
2816 cls.addFunc("setItemSize", &UI::setItemSize);
2817 cls.addFunc("setItemMargin", &UI::setItemMargin);
2818 cls.addFunc("setItemPadding", &UI::setItemPadding);
2819 cls.addFunc("setItemMinSize", &UI::setItemMinSize);
2820 cls.addFunc("setItemMaxSize", &UI::setItemMaxSize);
2821 cls.addFunc("setItemPercent", &UI::setItemPercent);
2822 cls.addFunc("setItemAbsolute", &UI::setItemAbsolute);
2823 cls.addFunc("setItemTooltip", &UI::setItemTooltip);
2824 cls.addFunc("setItemDragSource", &UI::setItemDragSource);
2825 cls.addFunc("setItemDropTarget", &UI::setItemDropTarget);
2826 cls.addFunc("setItemEnabled", &UI::setItemEnabled);
2827 cls.addFunc("setItemSelected", &UI::setItemSelected);
2828 cls.addFunc("setItemFocusMode", &UI::setItemFocusMode);
2829 cls.addFunc("setItemMouseFilter", &UI::setItemMouseFilter);
2830 cls.addFunc("setItemTheme", &UI::setItemTheme);
2831 cls.addFunc("setThemeScope", &UI::setThemeScope);
2832 cls.addFunc("setItemStyleClass", &UI::setItemStyleClass);
2833 cls.addFunc("setStyleScope", &UI::setStyleScope);
2834 cls.addFunc("setItemTabIndex", &UI::setItemTabIndex);
2835 cls.addFunc("setItemFocusOrder", &UI::setItemFocusOrder);
2836 cls.addFunc("setItemFocusNeighbors", &UI::setItemFocusNeighbors);
2837 cls.addFunc("setItemAccessibility", &UI::setItemAccessibility);
2838 cls.addFunc("setFlexAlign", &UI::setFlexAlign);
2839 cls.addFunc("setFlexJustify", &UI::setFlexJustify);
2840 cls.addFunc("setLayoutGaps", &UI::setLayoutGaps);
2841 cls.addFunc("setFlexWrap", &UI::setFlexWrap);
2842 cls.addFunc("setLayoutOverflow", &UI::setLayoutOverflow);
2843 cls.addFunc("listItem", &UI::addListItem);
2844 cls.addFunc("mountBuild", &UI::mountBuild);
2845
2846 cls.addFunc("setText", &UI::setText);
2847 cls.addFunc("setTextWrap", &UI::setTextWrap);
2848 cls.addFunc("setVisible", &UI::setVisible);
2849 cls.addFunc("setEnabled", &UI::setEnabled);
2850 cls.addFunc("setChecked", &UI::setChecked);
2851 cls.addFunc("setValue", &UI::setValue);
2852 cls.addFunc("setValueText", &UI::setValueText);
2853 cls.addFunc("setColor", &UI::setColor);
2854 cls.addFunc("setImageTint", &UI::setImageTint);
2855 cls.addFunc("setImageUv", &UI::setImageUv);
2856 cls.addFunc("setImageNinePatch", &UI::setImageNinePatch);
2857 cls.addFunc("setImageNinePatchFile", &UI::setImageNinePatchFile);
2858 cls.addFunc("setImageCornerRadius", &UI::setImageCornerRadius);
2859 cls.addFunc("setImageTextureId", &UI::setImageTextureId);
2860 cls.addFunc("registerTexture", &UI::registerTexture);
2861 cls.addFunc("unregisterTexture", &UI::unregisterTexture);
2862 cls.addFunc("getValue", &UI::getValue);
2863 cls.addFunc("getValueText", &UI::getValueText);
2864 cls.addFunc("getColorR", &UI::getColorR);
2865 cls.addFunc("getColorG", &UI::getColorG);
2866 cls.addFunc("getColorB", &UI::getColorB);
2867 cls.addFunc("getColorA", &UI::getColorA);
2868 cls.addFunc("getChecked", &UI::getChecked);
2869 cls.addFunc("requestFocus", &UI::requestFocus);
2870 cls.addFunc("moveFocus", &UI::moveFocus);
2871 cls.addFunc("getFocusedId", &UI::getFocusedId);
2872 cls.addFunc("setHostVisible", &UI::setHostVisible);
2873 cls.addFunc("setHostLayer", &UI::setHostLayer);
2874 cls.addFunc("setHostModal", &UI::setHostModal);
2875 cls.addFunc("setHostOverlay", &UI::setHostOverlay);
2876 cls.addFunc("setHostOverlayAlpha", &UI::setHostOverlayAlpha);
2877 cls.addFunc("setHostMovable", &UI::setHostMovable);
2878 cls.addFunc("setHostResizable", &UI::setHostResizable);
2879 cls.addFunc("setHostPos", &UI::setHostPos);
2880 cls.addFunc("setHostWorldAnchor", &UI::setHostWorldAnchor);
2881 cls.addFunc("clearHostWorldAnchor", &UI::clearHostWorldAnchor);
2882 cls.addFunc("setHostWorldEdgePolicy", &UI::setHostWorldEdgePolicy);
2883 cls.addFunc("setHostWorldDistanceScale", &UI::setHostWorldDistanceScale);
2884 cls.addFunc("setHostWorldOverlap", &UI::setHostWorldOverlap);
2885 cls.addFunc("getHostWorldState", &UI::getHostWorldState);
2886 cls.addFunc("getHostWorldScreenX", &UI::getHostWorldScreenX);
2887 cls.addFunc("getHostWorldScreenY", &UI::getHostWorldScreenY);
2888 cls.addFunc("setHostAnchor", &UI::setHostAnchor);
2889 cls.addFunc("setHostSize", &UI::setHostSize);
2890 cls.addFunc("setHostPercent", &UI::setHostPercent);
2891 // Trailing ease/delay (and cancelItemTweens id) are optional in script; C++
2892 // defaults do not reach Squirrel through member-function pointers.
2893 addOptionalTweenFunc(cls, "animateHostPos", sqAnimateHostPos, 4, _SC("xfffsf"));
2894 addOptionalTweenFunc(cls, "animateHostSize", sqAnimateHostSize, 4, _SC("xfffsf"));
2895 addOptionalTweenFunc(cls, "animateHostOverlayAlpha", sqAnimateHostOverlayAlpha, 3, _SC("xffsf"));
2896 addOptionalTweenFunc(cls, "animateItemOpacity", sqAnimateItemOpacity, 4, _SC("xsffsf"));
2897 addOptionalTweenFunc(cls, "animateItemPos", sqAnimateItemPos, 5, _SC("xsfffsf"));
2898 cls.addFunc("cancelHostTweens", &UI::cancelHostTweens);
2899 addOptionalTweenFunc(cls, "cancelItemTweens", sqCancelItemTweens, 1, _SC("xs"));
2900 cls.addFunc("cancelAllTweens", &UI::cancelAllTweens);
2901 cls.addFunc("tickTweens", &UI::tickTweens);
2902 cls.addFunc("getHostTweenCount", &UI::getHostTweenCount);
2903 cls.addFunc("getItemTweenCount", &UI::getItemTweenCount);
2904 cls.addFunc("consumeClick", &UI::consumeClick);
2905 cls.addFunc("consumeChange", &UI::consumeChange);
2906 cls.addFunc("dragDropSupport", &UI::dragDropSupport);
2907 cls.addFunc("consumeDrop", &UI::consumeDrop);
2908 cls.addFunc("getDropType", &UI::getDropType);
2909 cls.addFunc("getDropText", &UI::getDropText);
2910 cls.addFunc("getDropSource", &UI::getDropSource);
2911 cls.addFunc("getDropOrigin", &UI::getDropOrigin);
2912 cls.addFunc("onClick", &UI::onClick);
2913 cls.addFunc("onChange", &UI::onChange);
2914 cls.addFunc("componentOnClick", &UI::componentOnClick);
2915 cls.addFunc("componentOnChange", &UI::componentOnChange);
2916 cls.addFunc("componentClearHandlers", &UI::componentClearHandlers);
2917
2918 cls.addFunc("setThemeDark", &UI::setThemeDark);
2919 cls.addFunc("setThemeLight", &UI::setThemeLight);
2920 cls.addFunc("setTheme", &UI::setTheme);
2921 cls.addFunc("defineStyleClass", &UI::defineStyleClass);
2922 cls.addFunc("setStyleClassColor", &UI::setStyleClassColor);
2923 cls.addFunc("setStyleClassMetric", &UI::setStyleClassMetric);
2924 cls.addFunc("clearStyleClasses", &UI::clearStyleClasses);
2925 cls.addFunc("getTheme", &UI::getTheme);
2926 cls.addFunc("setNavKeyboard", &UI::setNavKeyboard);
2927 cls.addFunc("setNavGamepad", &UI::setNavGamepad);
2928 cls.addFunc("setScale", &UI::setScale);
2929 cls.addFunc("getScale", &UI::getScale);
2930 cls.addFunc("getStats", &UI::getStats);
2931 cls.addFunc("getLayoutDiagnostics", &UI::getLayoutDiagnostics);
2932 cls.addFunc("getAccessibilitySnapshot", &UI::getAccessibilitySnapshot);
2933 cls.addFunc("saveTreeJson", &UI::saveTreeJson);
2934 cls.addFunc("loadTreeJson", &UI::loadTreeJson);
2935 cls.addFunc("viewportCanvas", &UI::viewportCanvas);
2936 cls.addFunc("viewportHovered", &UI::viewportHovered);
2937 cls.addFunc("viewportActive", &UI::viewportActive);
2938 cls.addFunc("viewportMouseX", &UI::viewportMouseX);
2939 cls.addFunc("viewportMouseY", &UI::viewportMouseY);
2940 cls.addFunc("viewportDragDX", &UI::viewportDragDX);
2941 cls.addFunc("viewportDragDY", &UI::viewportDragDY);
2942 cls.addFunc("viewportWheel", &UI::viewportWheel);
2943
2944 cls.addFunc("mountSimple", &UI::mountSimple);
2945
2946 cls.addFunc("inspect", &UI::inspectOpen);
2947 cls.addFunc("inspectClose", &UI::inspectClose);
2948 cls.addFunc("inspectRefresh", &UI::inspectRefresh);
2949 cls.addFunc("inspectSelectClass", &UI::inspectSelectClass);
2950 cls.addFunc("inspectObject", &UI::inspectObject);
2951 cls.addFunc("inspectSetPickHandler", &UI::inspectSetPickHandler);
2952 cls.addFunc("inspectPickScene", &UI::inspectPickScene);
2953 cls.addFunc("inspectAddInstance", &UI::inspectAddInstance);
2954 cls.addFunc("propertySchema", &UI::propertySchema);
2955
2956 cls.addFunc("dbOpen", &UI::dbOpen);
2957 cls.addFunc("dbClose", &UI::dbClose);
2958 cls.addFunc("dbRefresh", &UI::dbRefresh);
2959 cls.addFunc("dbSelectClass", &UI::dbSelectClass);
2960 cls.addFunc("dbRegister", &UI::dbRegister);
2961 cls.addFunc("dbCreateInstance", &UI::dbCreateInstance);
2962 const HSQUIRRELVM vm = cls.getHandle();
2963 cls.addFunc("dbUnregister", [vm](UI *value, uint64_t id) {
2964 if (!value)
2967 "UI instance must not be null", {}, {}, "ui")));
2968 return eve::script::projectResult(vm, value->dbUnregister(id));
2969 });
2970
2971 cls.addFunc("editorOpen", &UI::editorOpen);
2972 cls.addFunc("editorClose", &UI::editorClose);
2973 cls.addFunc("editorSelectPanel", &UI::editorSelectPanel);
2974
2975 cls.addFunc("sceneOpen", &UI::sceneOpen);
2976 cls.addFunc("sceneClose", &UI::sceneClose);
2977 cls.addFunc("sceneSelectNode", &UI::sceneSelectNode);
2978 cls.addFunc("sceneSetPickHandler", &UI::sceneSetPickHandler);
2979}
2980
2981} // namespace eve::ui
double value
Duration start
LogicalId itemId
SQInteger top
float w
Definition AnimClip.cpp:738
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
int root
Definition AnimSmr.cpp:119
const std::string & s
building::EdgeCurveGroup group
float gap
int priority
Vec3 anchor
Definition CaveMesh.cpp:90
struct SQVM * HSQUIRRELVM
std::string title
std::string label
std::string nodeId
HSQUIRRELVM vm
Definition ECS.cpp:20
HSQOBJECT cls
Definition ECS.cpp:21
Object::Ptr theme
bool resizable
tensor::Graph g
Definition GpuGraph.cpp:7
std::uint32_t key
vk::UniqueImage image
glm::vec3 n
Definition Grass.cpp:63
double r
float v
HexVec3 up
HexVec3 left
HexVec3 right
std::int32_t c
std::int32_t first
Icon icon
Definition Icons.cpp:11
int h
std::uint32_t height
std::uint32_t width
std::string text
TokenKind kind
std::array< float, 3 > scale
std::int32_t parent
std::map< std::string, PropertyRule > properties
std::set< std::string > choices
std::string description
HSQOBJECT handler
std::string name
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:26
graphics::Canvas * previous
std::string error
Definition Package.cpp:60
TileLayer * layer
int idx
float radius
std::string path
Definition PlayHost.cpp:110
std::string id
Definition PlayHost.cpp:108
PrimitiveHandle handle
float d
float t
glm::mat4 model
const RoadNode * node
RoadLaneDirection direction
bool found
std::string filter
std::string resource
const SquirrelValueOptions & options
The single Squirrel projection for common Result, Status and Value.
Explicit Value/Owned/Borrowed semantics at the Squirrel boundary.
Battle::Events events
int columns
float opacity
bool visible
Json object
int children
Definition TreeMesh.cpp:295
UIHostHandle host
std::string payloadType
Definition UISystem.cpp:71
std::string payloadText
Definition UISystem.cpp:72
uint32_t index
const UnitySourceAsset & source
Owning, renderer-independent dynamic values.
float m[16]
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
static Runtime * runtime()
Active runtime associated with the last expose() call, or nullptr. @ownership Borrowed; the embedding...
Definition Module.cpp:292
virtual std::string getName() const =0
Returns the name.
eve::Result< ResourcePin > pin(Resource *resource)
Keeps one cached resource alive across unload()/clear()/reload.
Definition Resource.cpp:311
static ResourceManager & getInstance()
Returns the instance.
Definition Resource.cpp:15
void ignore(std::string_view reason={}) const noexcept
Explicitly discard this result after documenting the reason.
Definition Result.h:537
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
static constexpr RuntimeHandle fromPacked(std::uint64_t value) noexcept
Reconstructs a handle from an explicit packed boundary value.
EVENGINE_API_FOUNDATION public API.
Definition Runtime.h:189
HSQUIRRELVM handle() const noexcept
Raw Squirrel VM handle; nullptr after shutdown.
Definition Runtime.cpp:481
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
void set(const std::string &key, Value value)
Insert or replace an object member.
Definition Value.cpp:118
static Value array(Array value)
Compatibility factory for an array value.
Definition Value.h:112
void pushBack(Value value)
Append an element to an array value.
Definition Value.cpp:94
static Value object(Object value)
Compatibility factory for an object value.
Definition Value.h:114
Canvas public API.
Definition Canvas.h:17
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
Definition Texture.h:18
Represents raw pixel data.
Definition ImageData.h:38
EVENGINE_API_FOUNDATION public API.
Definition Json.h:136
bool valid() const
Valid.
Definition Json.h:157
static Document parse(const std::string &text, std::string *error=nullptr)
Parse.
Definition Json.cpp:581
Value root() const
Root.
Definition Json.h:159
EVENGINE_API_FOUNDATION public API.
Definition Json.h:38
Value get(const char *key) const
Returns the value.
Definition Json.cpp:336
int getInt(const char *key, int fallback=0) const
Returns the int.
Definition Json.cpp:422
Adapts one live Squirrel instance to the renderer-independent property model.
Releases C++-owned Squirrel roots before Runtime destroys its VM.
virtual void releaseSquirrelRoots() noexcept=0
Drops every C++-owned Squirrel root this listener still holds.
RAII keep-alive for one RuntimeObjectRegistry entry.
T * get() const noexcept
Borrows the pinned object; valid until the pin is released.
void clearAll()
Removes every entry.
static ObjectRegistry & instance()
Returns the process-local singleton owned by the UI module.
static UIHostHandle createHost(const std::string &name="")
Creates an ECS-owned UI host.
Definition UIHost.cpp:48
static eve::OptionalRef< UIHost > resolve(UIHostHandle handle) noexcept
Resolves a UI host handle with ECS generation checking.
Definition UIHost.cpp:61
static const UIStats & stats()
static void setBackend(UIBackend &backend)
Sets the borrowed backend used for the current UI/render lifetime.
static void clearBackend() noexcept
Clears the backend association before the backend is shut down.
static eve::OptionalRef< ViewportState > viewportState(const std::string &hostName, const std::string &nodeId)
Returns viewport state for a host/node key when it exists.
static void enqueuePlatformFileDrop(const std::string &path)
Copies an OS file-drop path into UI-owned pending state.
static std::string consumeChange()
Pop next change as "name/node"; empty if none.
static UIHostHandle findHost(const std::string &name)
Lookup by Meta.name across the UIHost View.
static void dispatchEvents()
Dispatches events.
static eve::ResultRef< ViewportState > ensureViewport(const std::string &key, int w, int h)
Creates or refreshes offscreen state for a viewport key.
static DragDropSupport dragDropSupport() noexcept
Returns retained drag-and-drop availability for this build target.
static std::string consumeClick()
Pop next click as "name/node"; empty if none.
static void render()
Walk all UIHost (+ subclasses) via ECS View.
static UIHostHandle findHostByOwner(uint32_t ownerId)
Find the first host with Meta.ownerId equal to ownerId, or null.
static std::optional< UIDrop > consumeDrop()
Pops the oldest completed drop, or returns empty when none exists.
static std::vector< UIEvent > & pendingEvents()
Pending events.
Declarative UI module (eve.UI).
Definition UI.h:41
void cancelHostTweens()
Cancel pending host-level tweens on the selected host.
Definition UI.cpp:1765
bool inspectSelectClass(const std::string &name)
Selects a class in the inspector (creates its first instance).
Definition UI.cpp:2457
void setTextWrap(const std::string &id, float width)
Sets the text wrap.
Definition UI.cpp:1336
bool mountBuild()
Finishes the build pass and mounts the built tree.
Definition UI.cpp:1286
void addCombo(const std::string &label, const std::string &options, int selected, const std::string &id="")
Adds combo.
Definition UI.cpp:1023
float viewportMouseX(const std::string &id)
Viewport mouse x.
Definition UI.cpp:2048
void setHostWorldAnchor(float x, float y, float z)
Projects the selected host from a 3D world point through the active Camera3D.
Definition UI.cpp:1602
void addSectionHeader(const std::string &label, const std::string &id="")
Adds a non-collapsible section heading.
Definition UI.cpp:1054
void setItemTheme(const std::string &theme)
Overrides the last item's subtree theme: "inherit", "dark", or "light".
Definition UI.cpp:1198
void setItemDragSource(const std::string &payloadType, const std::string &payloadText)
Marks the most recently added item as a desktop drag source.
Definition UI.cpp:1161
bool setImageNinePatchFile(const std::string &id, const std::string &path)
Applies a .9.png texture and its parsed stretch metadata to an image.
Definition UI.cpp:1471
bool wantCaptureKeyboard() const
True when the UI wants to capture keyboard input this frame.
Definition UI.cpp:662
uint64_t registerTexture(graphics::Texture *tex)
Register an engine texture for UI drawing.
Definition UI.cpp:1411
std::string consumeClick()
Returns the id of the clicked widget since the last frame (or "").
Definition UI.cpp:1706
void setItemFlexShrink(float shrink)
Sets shrink weight on the most recently added flex item.
Definition UI.cpp:1073
bool initBackend()
Creates the platform UI backend (ImGui); true on success.
Definition UI.cpp:552
UIHostHandle mount(WidgetDesc root)
Mounts the tree as an auto-named host and selects it.
Definition UI.cpp:712
void setThemeScope(const std::string &theme)
Overrides the current open container's inherited subtree theme.
Definition UI.cpp:1203
void setHostPercent(float w, float h)
Sets the host percent.
Definition UI.cpp:1683
void setColor(const std::string &id, float r, float g, float b, float a=1.f)
Sets RGBA on a ColorPalette (or image tint) node.
Definition UI.cpp:1362
void animateHostOverlayAlpha(float alpha, float durationMs, const std::string &ease="smoothstep", float delayMs=0.f)
Animate the selected host's overlay background alpha.
Definition UI.cpp:1701
void setImageTextureId(const std::string &id, uint64_t textureId)
Sets the image texture id.
Definition UI.cpp:1405
void setHostPos(float x, float y, float pivotX=0.f, float pivotY=0.f)
Positions the host window with a pivot (0..1 each axis).
Definition UI.cpp:1591
std::string saveTreeJson() const
Saves tree json.
Definition UI.cpp:1861
bool editorSelectPanel(const std::string &name)
Shows one docked panel ("inspector"/"database"; "" hides all).
Definition UI.cpp:2667
bool inspectPickScene()
Calls the pick handler and inspects the returned object.
Definition UI.cpp:2525
UI()
Ui.
Definition UI.cpp:531
std::size_t getItemTweenCount() const
Number of pending item tweens (diagnostics / tests).
Definition UI.cpp:596
void dispatchEvents()
Dispatches queued widget callbacks (click/toggle/value/text).
Definition UI.cpp:598
void setItemFocusMode(const std::string &mode)
Sets the last item's focus mode: "none", "click", or "all".
Definition UI.cpp:1188
void setItemPercent(float w, float h)
Sets the item percent.
Definition UI.cpp:1138
void bindOwner(uint32_t ownerId)
Binds the selected host to a UI/scene owner id.
Definition UI.cpp:677
void addText(const std::string &content, const std::string &id="")
Adds a text label to the current container.
Definition UI.cpp:946
void setImageCornerRadius(const std::string &id, float radius)
Sets the image corner radius.
Definition UI.cpp:1399
std::string getHostWorldState() const
Returns the selected host projection state as a stable lowercase name.
Definition UI.cpp:1642
void processEvent(const SDL_Event *event)
Feeds an SDL event into the UI backend (before window/game handling).
Definition UI.cpp:574
void setHostSize(float w, float h)
Sets the host size.
Definition UI.cpp:1674
bool inspectOpen()
Opens the auto-generated inspector (scans reflected classes).
Definition UI.cpp:2440
std::string getDropSource() const
Returns the source as "host/node", or empty for an OS file.
Definition UI.cpp:1734
void componentOnClick(uint64_t owner, const std::string &id, ssq::Function fn)
Internal UIComponent callback registration scoped to one component owner.
Definition UI.cpp:636
void animateHostSize(float w, float h, float durationMs, const std::string &ease="smoothstep", float delayMs=0.f)
Animate the selected host's explicit window size (px).
Definition UI.cpp:1696
void setItemFlexBasis(float basis)
Sets its main-axis basis; negative restores automatic measurement.
Definition UI.cpp:1078
bool sceneOpen()
Opens the scene panel (tree + selected node properties).
Definition UI.cpp:2671
bool sceneSetPickHandler(ssq::Function fn)
Registers the script callback for the scene panel Pick button. The callback (stored as eve....
Definition UI.cpp:2688
void editorClose()
Closes the editor shell (and its docked panels).
Definition UI.cpp:2663
void shutdownBackend()
Destroys the platform UI backend.
Definition UI.cpp:567
float viewportDragDX(const std::string &id)
Viewport drag dx.
Definition UI.cpp:2062
float getValue(const std::string &id) const
Returns the value.
Definition UI.cpp:1422
~UI() override
Ui.
Definition UI.cpp:536
void addSpacer(const std::string &id="", float grow=1.f)
Flexible empty space inside Flex (default grow=1).
Definition UI.cpp:1063
void addImage(const std::string &id="", float width=0.f, float height=0.f)
Adds image.
Definition UI.cpp:996
void beginMenuBar(const std::string &id="")
Opens a window menu bar.
Definition UI.cpp:789
bool viewportActive(const std::string &id)
Viewport active.
Definition UI.cpp:2041
void setNavKeyboard(bool enabled)
Enables/disables keyboard navigation support.
Definition UI.cpp:1792
float getColorA(const std::string &id) const
Returns the color a.
Definition UI.cpp:1457
void unregisterTexture(uint64_t textureId)
Release a texture id previously returned by registerTexture().
Definition UI.cpp:1418
float getColorR(const std::string &id) const
ColorPalette / image tint channels; missing nodes return 0.
Definition UI.cpp:1436
void setHostWorldOverlap(bool enabled, int priority=0, float padding=4.f, float maxDisplacement=96.f)
Configures deterministic overlap avoidance for projected hosts.
Definition UI.cpp:1630
void setItemMaxSize(float w, float h)
Sets the item max size.
Definition UI.cpp:1131
UIHostHandle findHostByOwner(uint32_t ownerId) const
Finds the host bound to an owner id, or null when absent.
Definition UI.cpp:668
void addIcon(const std::string &name, const std::string &id="")
Adds a semantic icon by name (for example "search" or "save").
Definition UI.cpp:960
void setLayoutOverflow(const std::string &overflow)
Sets overflow behavior: visible, clip, or scroll.
Definition UI.cpp:1270
bool setListItems(const std::string &listId, const std::vector< std::string > &items)
Replace children of a Group listId with buttons for each label (reconcile). Host must already exist a...
Definition UI.cpp:1317
UIHostHandle remountReconcile(WidgetDesc root)
Remount with key reconcile (props-only when structure matches).
Definition UI.cpp:726
void setItemPadding(float l, float t, float r, float b)
Sets the item padding.
Definition UI.cpp:1115
void setItemAspectRatio(float ratio)
Sets width/height ratio on the most recently added item.
Definition UI.cpp:1089
void setItemFlexGrow(float grow)
Set flex item props on the most recently added child of the current open container....
Definition UI.cpp:1067
void beginWindow(const std::string &title, const std::string &id="root")
Opens a window for the current build pass.
Definition UI.cpp:749
UIHostHandle remount(WidgetDesc root)
Replaces the selected host's tree.
Definition UI.cpp:720
float getColorB(const std::string &id) const
Returns the color b.
Definition UI.cpp:1450
void setItemAccessibility(const std::string &role, const std::string &name, const std::string &description="")
Sets the last item's accessibility role, name and description.
Definition UI.cpp:1236
void end()
Closes the innermost open container.
Definition UI.cpp:934
bool remountBuildAs(const std::string &name)
Like mountBuildAs but reconciles by key when possible.
Definition UI.cpp:1304
void sceneClose()
Closes the scene panel.
Definition UI.cpp:2680
eve::Result< void > dbUnregister(uint64_t id)
Removes an entry from the database grid using its packed handle.
Definition UI.cpp:2636
void beginFlex(const std::string &direction="row", const std::string &id="", float gap=-1.f)
Begin a Flex container.
Definition UI.cpp:905
void addInputText(const std::string &label, const std::string &value, const std::string &id="")
Adds an editable text field.
Definition UI.cpp:1037
void setHostMovable(bool movable)
Allows or prevents user movement after the initial position.
Definition UI.cpp:1583
void tickTweens(double nowMs)
Advance pending UI tweens using an explicit clock (ms).
Definition UI.cpp:592
void setItemSelected(bool selected)
Marks the most recently added button as the selected tool/action.
Definition UI.cpp:1183
bool editorOpen()
Opens the menu bar and docks the inspector + database panels.
Definition UI.cpp:2646
void addViewport(const std::string &id, float width=0.f, float height=0.f)
Adds viewport.
Definition UI.cpp:1019
void addImageButton(const std::string &id, float width, float height)
Adds image button.
Definition UI.cpp:1015
UIHostHandle findHost(const std::string &name) const
Finds a host by name, or null when absent.
Definition UI.cpp:666
void addSearchField(const std::string &hint, const std::string &value="", const std::string &id="")
Adds a compact search field.
Definition UI.cpp:1041
std::string getStats() const
Returns the stats.
Definition UI.cpp:1812
void beginToolbox(const std::string &id="", float cellSize=0.f, int columns=0)
Opens a wrapping editor tool grid.
Definition UI.cpp:797
void beginGroup(const std::string &id="")
Opens a group container in the current build pass.
Definition UI.cpp:754
void cancelAllTweens()
Cancel every pending tween on the selected host.
Definition UI.cpp:1775
void onClick(const std::string &id, ssq::Function fn)
On click.
Definition UI.cpp:622
void cancelItemTweens(const std::string &id="")
Cancel pending item tweens on the selected host.
Definition UI.cpp:1770
std::string setStyleClassColor(const std::string &name, const std::string &property, float r, float g, float b, float a=1.f)
Sets a named class color token and returns a stable status string.
Definition UI.cpp:1780
void beginCollapsing(const std::string &label, const std::string &id="", bool open=true)
Opens a collapsible header.
Definition UI.cpp:758
bool setTheme(const std::string &name)
Named preset: "dark" / "light" (case-insensitive). Returns false if unknown.
Definition UI.cpp:1742
void setHostLayer(int layer)
Sets the host layer.
Definition UI.cpp:1567
void setHostResizable(bool resizable)
Allows or prevents user resizing after the initial size.
Definition UI.cpp:1587
void setThemeLight()
Sets the theme light.
Definition UI.cpp:1740
void setItemAbsolute(float anchorX, float anchorY, float x=0.f, float y=0.f)
Sets the item absolute.
Definition UI.cpp:1145
UIHostHandle mountAs(const std::string &name, WidgetDesc root)
Creates/replaces a named host from a WidgetDesc tree and selects it.
Definition UI.cpp:697
void beginFrameAndRender()
Builds and presents the current frame's UI.
Definition UI.cpp:581
void beginGrid(int columns, const std::string &id="", float columnGap=-1.f, float rowGap=-1.f)
Begins a fixed-column grid container.
Definition UI.cpp:915
bool select(const std::string &name)
Selects a named host; false when it does not exist.
Definition UI.cpp:670
void addIconButton(const std::string &name, const std::string &label="", const std::string &id="")
Adds a semantic icon button with an optional visible label.
Definition UI.cpp:966
std::string getAccessibilitySnapshot() const
JSON accessibility snapshot for semantically named nodes in the selected tree.
Definition UI.cpp:1837
float getScale() const
Current UI scale factor.
Definition UI.cpp:1808
void setItemMargin(float l, float t, float r, float b)
Sets the item margin.
Definition UI.cpp:1106
bool viewportHovered(const std::string &id)
Viewport hovered.
Definition UI.cpp:2034
std::string getDropType() const
Returns the payload type of the last successfully consumed drop.
Definition UI.cpp:1730
UIHostHandle remountAs(const std::string &name, WidgetDesc root)
Creates/replaces a named host (does not select it).
Definition UI.cpp:732
void beginCard(const std::string &id="")
Opens a bordered card surface.
Definition UI.cpp:766
float viewportWheel(const std::string &id)
Viewport wheel.
Definition UI.cpp:2076
void setItemFocusNeighbors(const std::string &left, const std::string &right, const std::string &up, const std::string &down)
Sets explicit directional focus neighbors on the last item.
Definition UI.cpp:1226
void setScale(float scale)
Global UI scale factor (default 1).
Definition UI.cpp:1800
void beginColumn(const std::string &id="", float gap=-1.f)
Opens a column flex container.
Definition UI.cpp:913
void setNavGamepad(bool enabled)
Sets the nav gamepad.
Definition UI.cpp:1796
void setItemSize(float width, float height)
Sets width/height on the most recently added child.
Definition UI.cpp:1099
void setHostModal(bool modal)
Marks the host as a modal (blocks other hosts) / overlay.
Definition UI.cpp:1571
void addCheckbox(const std::string &label, bool checked, const std::string &id="")
Adds a checkbox.
Definition UI.cpp:978
bool inspectRefresh()
Re-scans script classes; true when any class is reflected.
Definition UI.cpp:2451
bool dbSelectClass(const std::string &name)
Selects the class shown in the grid.
Definition UI.cpp:2614
bool isBackendReady() const
True once the backend exists.
Definition UI.cpp:550
void beginBuild()
Imperative builder: open a new build pass (see beginWindow etc.).
Definition UI.cpp:736
bool dbRefresh()
Re-scans reflected classes; true when any class exists.
Definition UI.cpp:2608
void addSlider(const std::string &label, float value, float minV, float maxV, const std::string &id="")
Adds a slider.
Definition UI.cpp:982
void setFlexAlign(const std::string &align)
Set Flex container align/justify on the current open Flex (no-op otherwise).
Definition UI.cpp:1245
bool moveFocus(const std::string &direction)
Moves focus by "next", "previous", "left", "right", "up", or "down".
Definition UI.cpp:1551
void addProgress(float fraction, const std::string &id="", const std::string &overlay="")
Adds a progress bar.
Definition UI.cpp:992
bool getChecked(const std::string &id) const
Returns the checked.
Definition UI.cpp:1464
void addSwitch(const std::string &label, bool checked, const std::string &id="")
Adds a modern boolean switch.
Definition UI.cpp:1046
uint64_t dbRegister(ssq::Object object, const std::string &label)
Registers a live script object in the database grid.
Definition UI.cpp:2620
std::string defineStyleClass(const std::string &name, const std::string &parent="")
Declares/replaces a named style class and returns a stable status string.
Definition UI.cpp:1746
void setHostWorldDistanceScale(bool enabled, float referenceDistance=10.f, float minScale=0.65f, float maxScale=1.25f)
Configures distance scaling.
Definition UI.cpp:1619
bool sceneSelectNode(const std::string &id)
Selects a scene node by id.
Definition UI.cpp:2684
std::string dragDropSupport() const
Returns "supported" on desktop builds and "unsupported-platform" elsewhere.
Definition UI.cpp:1710
void setStyleScope(const std::string &name)
Applies a named style class to the current open container.
Definition UI.cpp:1212
void setHostVisible(bool visible)
Host-level state.
Definition UI.cpp:1563
void animateItemPos(const std::string &id, float x, float y, float durationMs, const std::string &ease="smoothstep", float delayMs=0.f)
Animate one node's absolute placement offset (marks the node absolute).
Definition UI.cpp:1758
std::string getFocusedId() const
Returns the focused control id, or an empty string.
Definition UI.cpp:1558
void setItemGridColumnSpan(int span)
Sets the grid-column span of the most recently added item.
Definition UI.cpp:1094
void beginStatusBar(const std::string &id="")
Opens a compact horizontal status strip.
Definition UI.cpp:805
graphics::Canvas * viewportCanvas(const std::string &id)
Returns the offscreen render target of a selected-host Viewport widget.
Definition UI.cpp:2024
uint64_t dbCreateInstance()
Creates and registers an instance of the selected class.
Definition UI.cpp:2628
float getColorG(const std::string &id) const
Returns the color g.
Definition UI.cpp:1443
void setImageUv(const std::string &id, float u0, float v0, float u1, float v1)
Sets the image uv.
Definition UI.cpp:1377
ssq::Object propertySchema(ssq::Object instance)
Return the reflection-derived PropertySchema for a live script instance.
Definition UI.cpp:2566
void clearHostWorldAnchor()
Returns the selected host to ordinary screen-space placement.
Definition UI.cpp:1606
void addTextWrapped(const std::string &content, float width, const std::string &id="")
Adds text wrapped.
Definition UI.cpp:950
void setItemTooltip(const std::string &text)
Sets hover help on the most recently added item.
Definition UI.cpp:1155
bool beginNinePatch(const std::string &path, const std::string &id="", float width=0.f, float height=0.f)
Opens a stretchable .9.png panel; false means the asset is invalid.
Definition UI.cpp:768
void setText(const std::string &id, const std::string &text)
Widget state setters/getters on the current host (by node id).
Definition UI.cpp:1332
void addMenuItem(const std::string &label, const std::string &shortcut="", const std::string &id="")
Adds a selectable menu command.
Definition UI.cpp:1058
void beginList(const std::string &id)
Opens a list container (rows added with addListItem).
Definition UI.cpp:756
void addSeparator(const std::string &id="")
Adds a separator line.
Definition UI.cpp:974
void beginChild(const std::string &id, float width=0.f, float height=120.f)
Opens a sized child region.
Definition UI.cpp:762
void addBadge(const std::string &label, const std::string &id="")
Adds a compact status/category badge.
Definition UI.cpp:1050
float getHostWorldScreenY() const
Returns the selected host's derived screen Y coordinate.
Definition UI.cpp:1661
void setHostAnchor(float x, float y)
Sets the host anchor.
Definition UI.cpp:1666
bool requestFocus(const std::string &id)
Requests keyboard/gamepad focus for a mounted control.
Definition UI.cpp:1546
void setItemMouseFilter(const std::string &filter)
Sets the last item's pointer filter: "stop", "pass", or "ignore".
Definition UI.cpp:1193
bool addNinePatch(const std::string &path, const std::string &id="", float width=0.f, float height=0.f)
Adds a .9.png image after removing its one-pixel marker frame.
Definition UI.cpp:1000
void setImageNinePatch(const std::string &id, float l, float t, float r, float b)
Sets the image nine patch.
Definition UI.cpp:1388
void addSameLine(const std::string &id="")
Adds an inline-break spacer.
Definition UI.cpp:972
void setEnabled(const std::string &id, bool enabled)
Enables or disables a mounted control.
Definition UI.cpp:1346
void setImageTint(const std::string &id, float r, float g, float b, float a=1.f)
Sets the image tint.
Definition UI.cpp:1366
void beginSplitPane(const std::string &direction="row", float ratio=0.25f, const std::string &id="")
Opens a two-child resizable split pane.
Definition UI.cpp:922
std::string getDropText() const
Returns the owning payload text of the last successfully consumed drop.
Definition UI.cpp:1732
void setThemeDark()
Applies the dark/light built-in theme.
Definition UI.cpp:1738
void onChange(const std::string &id, ssq::Function fn)
On change.
Definition UI.cpp:628
void animateHostPos(float x, float y, float durationMs, const std::string &ease="smoothstep", float delayMs=0.f)
Animate the selected host's window position (px).
Definition UI.cpp:1691
void releaseSquirrelRoots() noexcept
Drops database-panel Squirrel roots while the Runtime VM is alive.
Definition UI.cpp:541
bool inspectObject(ssq::Object object)
Inspects a caller-provided live script instance.
Definition UI.cpp:2464
void beginToolbar(const std::string &id="")
Opens a horizontal editor command strip.
Definition UI.cpp:795
std::string consumeChange()
Returns the id of the changed widget since the last frame (or "").
Definition UI.cpp:1708
bool inspectAddInstance()
Creates another instance of the selected inspector class.
Definition UI.cpp:2534
void setHostOverlayAlpha(float alpha)
Sets overlay opacity (0..1); zero also removes the host border and outer padding.
Definition UI.cpp:1579
void setItemMinSize(float w, float h)
Sets the item min size.
Definition UI.cpp:1124
void beginScrollList(const std::string &id="", float height=0.f, float itemHeight=0.f)
Begins scroll list.
Definition UI.cpp:807
void setHostWorldEdgePolicy(const std::string &policy, float safeMargin=8.f)
Configures off-screen handling and safe-edge margin.
Definition UI.cpp:1610
void setHostOverlay(bool overlay)
Sets the host overlay.
Definition UI.cpp:1575
void addColorPalette(const std::string &label, float r, float g, float b, float a=1.f, const std::string &id="")
Adds a color palette (ColorEdit + swatch grid). RGBA is stored on the node tint; read back with getCo...
Definition UI.cpp:987
void setValueText(const std::string &id, const std::string &value)
Sets the value text.
Definition UI.cpp:1358
std::string setStyleClassMetric(const std::string &name, const std::string &property, float x, float y=0.f)
Sets a named class metric token and returns a stable status string.
Definition UI.cpp:1785
std::size_t getHostTweenCount() const
Number of pending host tweens (diagnostics / tests).
Definition UI.cpp:594
void mountSimple(const std::string &title, const std::string &labelText, const std::string &buttonText)
One-shot convenience: a window with a label and a button.
Definition UI.cpp:2433
std::string getDropOrigin() const
Returns "internal", "os-file", or an empty string.
Definition UI.cpp:1736
void beginRow(const std::string &id="", float gap=-1.f)
Opens a row flex container.
Definition UI.cpp:911
void componentClearHandlers(uint64_t owner)
Removes every callback owned by one UIComponent; idempotent on the UI thread.
Definition UI.cpp:651
void setFlexWrap(bool wrap)
Enables or disables line wrapping on the current Flex.
Definition UI.cpp:1264
bool wantCaptureMouse() const
True when the UI wants to capture mouse input this frame.
Definition UI.cpp:658
void addButton(const std::string &label, const std::string &id="")
Adds a button to the current container.
Definition UI.cpp:956
void beginMenu(const std::string &label, const std::string &id="")
Opens a popup menu.
Definition UI.cpp:791
bool mountBuildAs(const std::string &name)
Finishes the build pass and mounts as a named host.
Definition UI.cpp:1295
float viewportDragDY(const std::string &id)
Viewport drag dy.
Definition UI.cpp:2069
bool inspectSetPickHandler(ssq::Function fn)
Registers the script callback used by the inspector Pick button. The callback is stored on the script...
Definition UI.cpp:2471
void setItemEnabled(bool enabled)
Enables or disables the most recently added item.
Definition UI.cpp:1178
void setFlexJustify(const std::string &justify)
Sets Flex container justify on the current open Flex.
Definition UI.cpp:1251
bool dbOpen()
Opens the database panel (class menu + editable instance grid).
Definition UI.cpp:2598
std::string getValueText(const std::string &id) const
Returns the value text.
Definition UI.cpp:1429
void beginSidebar(const std::string &id="", float width=0.f)
Opens a vertical editor side panel.
Definition UI.cpp:801
std::string consumeDrop()
Pops one drop and returns its target as "host/node", or an empty string.
Definition UI.cpp:1716
void setValue(const std::string &id, float value)
Sets the value.
Definition UI.cpp:1354
void setItemStyleClass(const std::string &name)
Applies a named style class to the most recently added item.
Definition UI.cpp:1207
void addListItem(const std::string &label, const std::string &id="")
Append one list row button (call inside beginList).
Definition UI.cpp:1276
void inspectClose()
Closes the inspector panel.
Definition UI.cpp:2447
void setLayoutGaps(float columnGap, float rowGap)
Sets independent column and row gaps on the current Flex/Grid.
Definition UI.cpp:1257
void setVisible(const std::string &id, bool visible)
Sets the visible.
Definition UI.cpp:1342
void componentOnChange(uint64_t owner, const std::string &id, ssq::Function fn)
Internal UIComponent value callback registration scoped to one component owner.
Definition UI.cpp:643
void animateItemOpacity(const std::string &id, float opacity, float durationMs, const std::string &ease="smoothstep", float delayMs=0.f)
Smoothly animates one retained node's transient opacity without rebuilding its tree.
Definition UI.cpp:1750
void setItemTabIndex(int index)
Sets the last item's sequential focus order; negative excludes it.
Definition UI.cpp:1214
std::string getTheme() const
Name of the active theme.
Definition UI.cpp:1744
void clearStyleClasses()
Clears all named style classes.
Definition UI.cpp:1790
void setItemAlignSelf(const std::string &align)
Sets its cross-axis alignment: inherit, start, center, end, or stretch.
Definition UI.cpp:1083
void dbClose()
Closes the database panel.
Definition UI.cpp:2604
void setItemDropTarget(const std::string &acceptedType)
Marks the most recently added item as a desktop drop target.
Definition UI.cpp:1170
void setItemFocusOrder(const std::string &previous, const std::string &next)
Sets explicit previous and next focus neighbors on the last item.
Definition UI.cpp:1219
float getHostWorldScreenX() const
Returns the selected host's derived screen X coordinate.
Definition UI.cpp:1656
void setChecked(const std::string &id, bool checked)
Sets the checked.
Definition UI.cpp:1350
bool loadTreeJson(const std::string &json)
Loads tree json.
Definition UI.cpp:1875
std::string getLayoutDiagnostics() const
JSON diagnostics for measured size and overflow of the selected retained tree.
Definition UI.cpp:1820
float viewportMouseY(const std::string &id)
Viewport mouse y.
Definition UI.cpp:2055
void animateHostSize(UIHostHandle host, float w, float h, float durationMs, const std::string &ease, float delayMs, double nowMs)
Animate selected-host explicit window size.
Definition UiTween.cpp:216
void cancelItem(UIHostHandle host, const std::string &id={})
Cancel every pending item tween for host + id (empty id = all items).
Definition UiTween.cpp:340
void tick(double nowMs)
Advance all pending tweens to nowMs.
Definition UiTween.cpp:354
void cancelAll(UIHostHandle host)
Cancel every pending tween for host.
Definition UiTween.cpp:349
std::size_t hostTweenCount() const noexcept
Number of pending host tweens (tests / diagnostics).
Definition UiTween.h:166
eve::Result< void > animateItemPos(UIHostHandle host, const std::string &id, float x, float y, float durationMs, const std::string &ease, float delayMs, double nowMs)
Animate one absolute node's placement offset.
Definition UiTween.cpp:297
void cancelHost(UIHostHandle host)
Cancel every pending host tween for host.
Definition UiTween.cpp:334
eve::Result< void > animateItemOpacity(UIHostHandle host, const std::string &id, float opacity, float durationMs, const std::string &ease, float delayMs, double nowMs)
Animate one node's transient opacity.
Definition UiTween.cpp:265
void animateHostOverlayAlpha(UIHostHandle host, float alpha, float durationMs, const std::string &ease, float delayMs, double nowMs)
Animate selected-host overlay background alpha.
Definition UiTween.cpp:243
std::size_t itemTweenCount() const noexcept
Number of pending item tweens (tests / diagnostics).
Definition UiTween.h:169
void animateHostPos(UIHostHandle host, float x, float y, float durationMs, const std::string &ease, float delayMs, double nowMs)
Animate selected-host window position.
Definition UiTween.cpp:189
SDL2 desktop/mobile implementation of eve::window::Window.
Definition Window.h:16
char * encode(std::string format, const char *src, size_t srclen, size_t &dstlen, size_t linelen)
Encodes raw bytes (e.g. hex / base64) into a text buffer.
char * decode(std::string format, const char *src, size_t srclen, size_t &dstlen)
Decodes a text buffer (hex / base64) back into raw bytes.
std::variant< std::monostate, std::int64_t, double, std::string, bool > Value
Definition Database.h:26
Result< std::string > stringify(const eve::Value &value)
Serialize the canonical owning Value as deterministic compact JSON.
Definition Json.cpp:563
constexpr bool hasFlag(PropertyFlag value, PropertyFlag flag)
True when flag.
PropertyKind
Semantic property kind used by renderer-independent presenters.
std::unordered_map< std::string, SkillDefinition > & table()
Definition Skill.cpp:65
ssq::Table projectResult(HSQUIRRELVM vm, Result< void > &&result)
Consume and project a void native Result using the common schema.
WidgetDesc collapsingHeader(std::string label, std::vector< WidgetDesc > children, std::string id, bool defaultOpen)
Collapsible header containing child widgets.
Definition Widget.cpp:623
void exposePcgScreenshotSavedNoticeBindings(ssq::Table &t)
Register Pcg screenshot-notice bindings.
StyleClassStatus defineStyleClass(const std::string &name, const std::string &parent)
Declares or replaces one sparse style class. @thread UI thread only. @reentrancy Does not invoke call...
Definition Theme.cpp:82
WidgetDesc menuItem(std::string label, std::string shortcut, std::string id, std::function< void()> onClick, bool selected)
Selectable menu command with an optional shortcut hint.
Definition Widget.cpp:550
void exposePcgPhotoModePanelsBindings(ssq::Table &t)
Register Pcg photo-mode panel bindings.
void registerEditorHostCapabilities()
Registers editor host capabilities.
void exposePcgColorPreviewSyncBindings(ssq::Table &table)
Register Pcg color-preview bindings.
void exposePcgPhotoModeSessionBindings(ssq::Table &table)
Register Pcg photo-mode session bindings.
WidgetDesc badge(std::string label, std::string id)
Compact status/category pill. Tint controls its background color.
Definition Widget.cpp:489
void exposePcgTooltipBindings(ssq::Table &t)
Register Pcg tooltip bindings.
WidgetDesc checkbox(std::string label, bool checked, std::string id, std::function< void(bool)> onToggle)
Checkbox with a label; fires onToggle.
Definition Widget.cpp:353
Icon
Semantic editor icons backed by the bundled Font Awesome 4.7 font.
Definition Icons.h:11
const std::string & globalThemeName()
Current preset name: "dark", "light", or "custom".
Definition Theme.cpp:279
WidgetDesc combo(std::string label, std::vector< std::string > options, int selected, std::string id, std::function< void(float)> onValue)
Combo.
Definition Widget.cpp:405
WidgetDesc statusBar(std::vector< WidgetDesc > children, std::string id)
Compact horizontal status strip; Spacer children absorb free width.
Definition Widget.cpp:596
WidgetDesc slider(std::string label, float value, float minV, float maxV, std::string id, std::function< void(float)> onValue)
Horizontal slider; fires onValue.
Definition Widget.cpp:365
void exposePcgDraggableWindowBindings(ssq::Table &table)
Register Pcg draggable-window bindings.
FlexDirection
Main-axis direction for Flex containers.
Definition UIHost.h:58
void exposePcgPhotoModeValuesBindings(ssq::Table &t)
Register complete Pcg photo-mode value bindings.
void clearStyleClasses()
Clears user-defined style classes. Intended for runtime/test teardown.
Definition Theme.cpp:160
MouseFilter
Pointer event participation and propagation policy.
Definition UIHost.h:85
WidgetDesc imageButton(std::string id, float width, float height, std::function< void()> onClick)
Image button.
Definition Widget.cpp:432
WidgetDesc inputText(std::string label, std::string value, std::string id, std::function< void(const std::string &)> onChange)
Editable text field; fires onTextChange.
Definition Widget.cpp:453
bool setThemeByName(const std::string &name)
Apply a named preset ("dark" / "light"). Case-insensitive. Returns false if unknown.
Definition Theme.cpp:288
void setThemeUiScale(float scale)
Logical (point-space) UI scale. Default 1.0.
Definition Theme.cpp:301
void exposePcgLoadingScreenBindings(ssq::Table &table)
Register Pcg loading-screen bindings.
WidgetDesc window(std::string title, std::vector< WidgetDesc > children, std::string id)
Top-level window widget with a title bar.
Definition Widget.cpp:292
bool parseNinePatch(const image::ImageData &source, NinePatchInfo &out, std::string *error)
Parse a raw, uncompiled Android .9.png image.
Definition NinePatch.cpp:55
void bindUIEventSinkOwner(UI *owner) noexcept
Bind the live UI module into the platform event sink. @ownership Borrowed; cleared when the UI module...
Definition EventSink.cpp:39
WidgetDesc spacer(std::string id, float grow)
Flexible empty space; default flexGrow=1 so it absorbs free space in a Flex parent.
Definition Widget.cpp:697
void exposePcgPhotoModeColorPickerBindings(ssq::Table &t)
Register Pcg photo-mode color-picker bindings.
WidgetDesc child(std::string id, std::vector< WidgetDesc > children, float width, float height)
Scrollable child region with an explicit size.
Definition Widget.cpp:635
NodeType
Widget node kinds understood by the UI renderer.
Definition UIHost.h:19
FocusDirection
Logical focus movement understood by keyboard, gamepad and automation.
Definition UIHost.h:82
StyleClassStatus setStyleClassMetric(const std::string &name, const std::string &property, float x, float y)
Sets padding, rounding, or alpha on an existing style class.
Definition Theme.cpp:128
WidgetDesc toolbar(std::vector< WidgetDesc > children, std::string id)
Horizontal editor command strip; Spacer children absorb free width.
Definition Widget.cpp:563
WidgetDesc menu(std::string label, std::vector< WidgetDesc > children, std::string id)
Popup menu container used inside a MenuBar or another Menu.
Definition Widget.cpp:540
FocusMode
Keyboard/gamepad focus policy for an interactive control.
Definition UIHost.h:79
WidgetDesc progress(float fraction, std::string id, std::string overlay)
Progress bar; fraction is clamped to [0,1].
Definition Widget.cpp:395
FlexJustify
Main-axis distribution of free space in a Flex container.
Definition UIHost.h:70
bool iconFromName(std::string_view name, Icon *out)
Resolves a semantic icon name; accepts kebab-case names case-insensitively.
Definition Icons.cpp:90
const char * styleClassStatusName(StyleClassStatus status)
Stable script-facing spelling of a mutation status.
Definition Theme.cpp:162
WidgetDesc colorPalette(std::string label, float r, float g, float b, float a, std::string id, std::function< void(float)> onValue)
Color editor with a swatch grid (调色板). RGBA is stored in tint channels. valueText may list extra swat...
Definition Widget.cpp:379
WidgetDesc ninePatchPanel(std::vector< WidgetDesc > children, std::string id, uint64_t textureId)
Stretchable textured container with asset-defined content padding.
Definition Widget.cpp:511
void exposeParentScalerBindings(ssq::Table &table)
Register ParentScaler value types and evaluator with the root script table.
void exposePcgPhotoModeRangesBindings(ssq::Table &t)
Register Pcg photo-mode range bindings.
WidgetDesc iconButton(Icon value, std::string label, std::string id, std::function< void()> onClick)
Button containing a semantic icon and optional visible label.
Definition Widget.cpp:323
std::unique_ptr< image::ImageData > stripNinePatchBorder(const image::ImageData &source)
Copy the drawable interior of a parsed .9.png without marker pixels.
WidgetDesc grid(int columns, std::vector< WidgetDesc > children, std::string id)
Fixed-column grid; children are placed in source order.
Definition Widget.cpp:687
ThemePreset
Built-in theme override inherited by a retained UI subtree.
Definition UIHost.h:88
void exposePcgPhotoModeRuntimeUIBindings(ssq::Table &table)
Register Pcg photo-mode runtime UI bindings.
WidgetDesc listButtons(std::string listId, const std::vector< std::string > &items)
Default list: one Button per item, id = listId + "/" + index.
Definition Widget.cpp:728
WidgetDesc viewport(std::string id, float width, float height)
Viewport.
Definition Widget.cpp:443
WidgetDesc searchField(std::string hint, std::string value, std::string id, std::function< void(const std::string &)> onChange)
Compact search field with placeholder text and a bundled search icon.
Definition Widget.cpp:465
WidgetDesc button(std::string label, std::string id, std::function< void()> onClick)
Clickable button; fires onClick.
Definition Widget.cpp:311
WidgetDesc flex(FlexDirection direction, std::vector< WidgetDesc > children, std::string id)
Elastic layout container (row/column). Prefer row / column shorthands.
Definition Widget.cpp:669
WidgetDesc toggleSwitch(std::string label, bool checked, std::string id, std::function< void(bool)> onToggle)
Modern boolean toggle; fires onToggle when changed.
Definition Widget.cpp:477
WidgetDesc sidebar(std::vector< WidgetDesc > children, std::string id, float width)
Vertical editor side panel. Width defaults to 240 logical pixels.
Definition Widget.cpp:586
double uiTweenWallClockMs()
Wall-clock milliseconds from steady_clock (presentation clock).
Definition UiTween.cpp:115
WidgetDesc card(std::vector< WidgetDesc > children, std::string id)
Bordered surface container with editor-friendly padding.
Definition Widget.cpp:502
OverflowMode
Behavior when arranged children exceed the retained layout box.
Definition UIHost.h:64
ecs::EntityHandle UIHostHandle
Definition UIHost.h:16
Theme & globalTheme()
Global theme.
Definition Theme.cpp:277
FlexAlign
Cross-axis alignment of Flex children.
Definition UIHost.h:67
std::unique_ptr< UIBackend > createImGuiBackend()
Default backend: Dear ImGui + SDL + Vulkan (see ui/imgui/).
WidgetDesc toolbox(std::vector< WidgetDesc > children, std::string id, float cellSize, int columns)
Wrapping grid of editor tools with uniform square cells.
Definition Widget.cpp:574
WidgetDesc scrollList(std::string id, std::vector< WidgetDesc > children, float height, float itemHeight)
Scroll list.
Definition Widget.cpp:646
WidgetDesc sectionHeader(std::string label, std::string id)
Non-collapsible editor section heading with an accent marker.
Definition Widget.cpp:522
WidgetDesc separator(std::string id)
Horizontal separator line.
Definition Widget.cpp:345
void exposePcgControllerSelectionBindings(ssq::Table &t)
Register Pcg controller-selection bindings.
AccessibilityRole
Platform-neutral accessibility role exposed by controls.
Definition UIHost.h:107
WidgetDesc sameLine(std::string id)
Holds the next widget on the same line as the previous one.
Definition Widget.cpp:337
void registerUIAutomationCapabilities()
Registers ui automation capabilities.
void exposePcgPhotoModeApplyPlanBindings(ssq::Table &t)
Register Pcg photo-mode application-plan bindings.
StyleClassStatus setStyleClassColor(const std::string &name, const std::string &property, float r, float g, float b, float a)
Sets text/background/border/accent RGBA on an existing style class.
Definition Theme.cpp:99
WidgetDesc menuBar(std::vector< WidgetDesc > children, std::string id)
Window menu bar container. Must be a direct child of a Window.
Definition Widget.cpp:531
Build metadata (engine git commit, build time, third-party version).
Definition Build.cpp:16
std::optional< std::reference_wrapper< T > > OptionalRef
Optional borrowed reference; it does not extend T's lifetime.
Definition BorrowedRef.h:24
SettlementPipeline::Stage fn
bool enabled
One stable property description consumed by any UI shell.
bool navEnableKeyboard
Definition Theme.h:121
bool navEnableGamepad
Definition Theme.h:122
UIEvent public API.
Definition UISystem.h:24
std::string kind
Definition UISystem.h:29
std::string nodeId
Definition UISystem.h:27
std::string hostName
Definition UISystem.h:26
Retained UI widget node (arena tree). Conceptual counterpart of eve::scene::SceneNode; built declarat...
Definition UIHost.h:128
UIStats public API.
Definition UISystem.h:68
Declarative widget description (build once / on dirty → flatten into UIHost::Tree).
Definition Widget.h:15
std::vector< WidgetDesc > children
Definition Widget.h:111
NodeType type
Definition Widget.h:16
std::string styleClass
Definition Widget.h:30
ThemePreset themePreset
Definition Widget.h:29