载入中...
搜索中...
未找到
UI.cpp
浏览该文件的文档.
1#include "ui/UI.h"
2#include "ui/DatabasePanel.h"
3#include "ui/EditorShell.h"
5
6#include "ui/Inspector.h"
7#include "ui/ScenePanel.h"
8#include "ui/Theme.h"
9#include "ui/UISystem.h"
10#include "ui/Widget.h"
11
12#include "common/config.h"
13#include "common/Module.h"
14#include "graphics/Graphics.h"
15#include "window/Window.h"
16#include "window/sdl/Window.h"
17
18#include <simplesquirrel/simplesquirrel.hpp>
19
20#if !(defined(EVENGINE_WEBGPU) && defined(__EMSCRIPTEN__))
21#include <Poco/JSON/Array.h>
22#include <Poco/JSON/Object.h>
23#include <Poco/JSON/Parser.h>
24#include <Poco/JSON/Stringifier.h>
25#endif
26
27#include <algorithm>
28#include <chrono>
29#include <cstdio>
30#include <cstring>
31#include <sstream>
32#include <stdexcept>
33
34namespace eve::ui {
35namespace {
36
38void callScriptHandler(ssq::Function &fn, const std::string &kind, const UIEvent &ev) {
39 HSQUIRRELVM vm = fn.getHandle();
40 if (!vm) return;
41 const SQInteger top = sq_gettop(vm);
42 sq_pushobject(vm, fn.getRaw());
43 sq_pushroottable(vm); // env
44 if (kind == "click") {
45 if (SQ_FAILED(sq_call(vm, 1, SQFalse, SQTrue))) {
46 sq_settop(vm, top);
47 return;
48 }
49 } else {
50 sq_pushstring(vm, kind.c_str(), -1);
51 if (kind == "toggle") sq_pushbool(vm, ev.toggleValue ? SQTrue : SQFalse);
52 else if (kind == "value") sq_pushfloat(vm, ev.floatValue);
53 else sq_pushstring(vm, ev.textValue.c_str(), -1);
54 if (SQ_FAILED(sq_call(vm, 3, SQFalse, SQTrue))) {
55 sq_settop(vm, top);
56 return;
57 }
58 }
59 sq_settop(vm, top);
60}
61
62#if !(defined(EVENGINE_WEBGPU) && defined(__EMSCRIPTEN__))
63// JSON UI asset helpers (defined below saveTreeJson/loadTreeJson).
64void nodeToJson(const UIHost::Tree &tree, const UINode &n, Poco::JSON::Object &o);
65WidgetDesc descFromJson(const Poco::JSON::Object &o);
66#endif
67
69const char *kUIComponentScript = R"SQ(
70eve.UIComponent <- class {
71 hostName = ""
72 dirty = true
73 forceFull = false
74 _ui = null
75
76 constructor(uiInstance = null) {
77 _ui = uiInstance
78 hostName = ""
79 dirty = true
80 forceFull = false
81 }
82
83 function setUI(uiInstance) { _ui = uiInstance }
84
85 function mountAs(name) {
86 hostName = name
87 dirty = true
88 forceFull = true
89 updateIfDirty()
90 }
91
92 function setState() { dirty = true }
93 function markDirty() { dirty = true }
94
95 // Override in subclass: call this.ui().beginWindow / text / button / end ...
96 function build() {}
97
98 function ui() {
99 if (_ui != null) return _ui
100 try {
101 if (::ui != null) return ::ui
102 } catch (e) {}
103 _ui = ::eve.UI()
104 return _ui
105 }
106
107 function updateIfDirty() {
108 if (!dirty) return false
109 local u = ui()
110 u.beginBuild()
111 build()
112 local name = hostName
113 if (name == null || name == "") name = "default"
114 if (forceFull) {
115 u.mountBuildAs(name)
116 forceFull = false
117 } else {
118 u.remountBuildAs(name)
119 }
120 dirty = false
121 return true
122 }
123
124 function rebuild(force = false) {
125 dirty = true
126 forceFull = force
127 return updateIfDirty()
128 }
129}
130// Note: eve.Component is reserved for script ECS (see exposeECS). Use eve.UIComponent.
131)SQ";
132
133void injectUIComponentClass(ssq::Table &eveTable) {
134 HSQUIRRELVM vm = eveTable.getHandle();
135 const SQInteger top = sq_gettop(vm);
136 if (SQ_FAILED(sq_compilebuffer(vm, kUIComponentScript,
137 static_cast<SQInteger>(std::strlen(kUIComponentScript)),
138 "UIComponent.nut", SQTrue))) {
139 sq_settop(vm, top);
140 return;
141 }
142 sq_pushroottable(vm);
143 sq_call(vm, 1, SQFalse, SQTrue);
144 sq_settop(vm, top);
145}
146
147} // namespace
148
150
153
154bool UI::isBackendReady() const { return backend_ && backend_->isInitialized(); }
155
157 if (!backend_) backend_ = createImGuiBackend();
158 if (backend_->isInitialized()) return true;
159 auto *win = eve::ModuleManager::getInstance<eve::window::Window>("Window");
160 auto *gfx = eve::ModuleManager::getInstance<eve::graphics::Graphics>("Graphics");
161 if (!win || !gfx) return false;
162 auto *sdlWin = dynamic_cast<eve::window::sdl::Window *>(win);
163 if (!sdlWin) return false;
164 auto *native = static_cast<SDL_Window *>(sdlWin->getHandle());
165 if (!native) return false;
166 const bool ok = backend_->init(native, gfx);
167 if (ok) UISystem::setBackend(backend_.get());
168 return ok;
169}
170
172 if (backend_) backend_->shutdown();
173}
174
175void UI::processEvent(const SDL_Event *event) {
176 if (backend_) backend_->processEvent(event);
177}
178
180 if (!isBackendReady()) {
181 if (!initBackend()) return;
182 }
183 updateHostTweens();
184 if (inspector_ && inspector_->isOpen()) inspector_->sync();
185 if (databasePanel_ && databasePanel_->isOpen()) databasePanel_->sync();
186 backend_->newFrame();
188}
189
190void UI::updateHostTweens() {
191 if (hostTweens_.empty()) return;
192 const double now =
193 std::chrono::duration<double, std::milli>(std::chrono::steady_clock::now().time_since_epoch())
194 .count();
195 for (auto &t : hostTweens_) {
196 if (!t.host) continue;
197 auto m = t.host->meta();
198 const double elapsed = now - t.startMs;
199 if (t.durationMs <= 0.0 || elapsed >= t.durationMs) {
200 m->hasPos = true;
201 m->posX = t.toX;
202 m->posY = t.toY;
203 t.host = nullptr; // done; removed below
204 continue;
205 }
206 const float k = float(elapsed / t.durationMs);
207 const float ease = k * k * (3.f - 2.f * k); // smoothstep
208 m->hasPos = true;
209 m->posX = t.fromX + (t.toX - t.fromX) * ease;
210 m->posY = t.fromY + (t.toY - t.fromY) * ease;
211 }
212 hostTweens_.erase(std::remove_if(hostTweens_.begin(), hostTweens_.end(),
213 [](const HostTween &t) { return t.host == nullptr; }),
214 hostTweens_.end());
215}
216
218 // Copy before dispatch: UISystem::dispatchEvents() consumes the pending list.
219 const std::vector<UIEvent> events = UISystem::pendingEvents();
221 for (const auto &ev : events) {
222 if (!ev.host) continue;
223 fireScriptHandlers(ev);
224 }
225}
226
227void UI::fireScriptHandlers(const UIEvent &ev) {
228 for (const auto &h : scriptHandlers_) {
229 if (h.hostName != ev.hostName || h.nodeId != ev.nodeId) continue;
230 if (h.kind == "click" && ev.kind == "click") {
231 ssq::Function fn = h.fn;
232 callScriptHandler(fn, "click", ev);
233 } else if (h.kind == ev.kind &&
234 (ev.kind == "toggle" || ev.kind == "value" || ev.kind == "text")) {
235 ssq::Function fn = h.fn;
236 callScriptHandler(fn, ev.kind, ev);
237 }
238 }
239}
240
241void UI::onClick(const std::string &id, ssq::Function fn) {
242 if (!selected_ || id.empty()) return;
243 scriptHandlers_.push_back(
244 ScriptHandler(selected_->getName(), id, "click", std::move(fn)));
245}
246
247void UI::onChange(const std::string &id, ssq::Function fn) {
248 if (!selected_ || id.empty()) return;
249 for (const char *kind : {"toggle", "value", "text"}) {
250 scriptHandlers_.push_back(ScriptHandler(selected_->getName(), id, kind, fn));
251 }
252}
253
255 return backend_ ? backend_->wantCaptureMouse() : false;
256}
257
259 return backend_ ? backend_->wantCaptureKeyboard() : false;
260}
261
262UIHost *UI::findHost(const std::string &name) const { return UISystem::findHost(name); }
263
264UIHost *UI::findHostByOwner(uint32_t ownerId) const {
265 return UISystem::findHostByOwner(ownerId);
266}
267
268bool UI::select(const std::string &name) {
269 UIHost *h = findHost(name);
270 if (!h) return false;
271 selected_ = h;
272 return true;
273}
274
275void UI::bindOwner(uint32_t ownerId) {
276 if (selected_) selected_->setOwnerId(ownerId);
277}
278
279UIHost *UI::ensureSelected(const std::string &preferredName) {
280 if (selected_) return selected_;
281 if (!preferredName.empty()) {
282 if (UIHost *h = findHost(preferredName)) {
283 selected_ = h;
284 return selected_;
285 }
286 selected_ = UIHost::createHost(preferredName);
287 return selected_;
288 }
289 selected_ = UIHost::createHost("default");
290 return selected_;
291}
292
293UIHost *UI::mountAs(const std::string &name, WidgetDesc root) {
294 UIHost *h = findHost(name);
295 if (!h) h = UIHost::createHost(name);
296 else h->setName(name);
297 h->setTree(std::move(root));
298 selected_ = h;
299 return h;
300}
301
303 if (selected_) {
304 selected_->setTree(std::move(root));
305 return selected_;
306 }
307 return mountAs("default", std::move(root));
308}
309
311 UIHost *h = ensureSelected();
312 h->setTree(std::move(root));
313 return h;
314}
315
317 UIHost *h = ensureSelected();
318 h->setTreeReconcile(std::move(root));
319 return h;
320}
321
322UIHost *UI::remountAs(const std::string &name, WidgetDesc root) {
323 return mountAs(name, std::move(root));
324}
325
327 openStack_.clear();
328 hasBuiltRoot_ = false;
329 builtRoot_ = WidgetDesc{};
330}
331
332void UI::pushOpen(WidgetDesc d) { openStack_.push_back(std::move(d)); }
333
334WidgetDesc &UI::currentParent() {
335 if (openStack_.empty()) throw std::runtime_error("ui: widget outside beginWindow/beginGroup");
336 return openStack_.back();
337}
338
339void UI::beginWindow(const std::string &title, const std::string &id) {
340 if (openStack_.empty() && hasBuiltRoot_) beginBuild();
341 pushOpen(window(title, {}, id));
342}
343
344void UI::beginGroup(const std::string &id) { pushOpen(group({}, id)); }
345
346void UI::beginList(const std::string &id) { pushOpen(group({}, id)); }
347
348void UI::beginCollapsing(const std::string &label, const std::string &id, bool open) {
349 pushOpen(collapsingHeader(label, {}, id, open));
350}
351
352void UI::beginChild(const std::string &id, float width, float height) {
353 pushOpen(child(id, {}, width, height));
354}
355
356void UI::beginScrollList(const std::string &id, float height, float itemHeight) {
357 pushOpen(scrollList(id, {}, height, itemHeight));
358}
359
360namespace {
361
362std::string toLowerCopy(std::string s) {
363 for (char &c : s) {
364 if (c >= 'A' && c <= 'Z') c = char(c - 'A' + 'a');
365 }
366 return s;
367}
368
369FlexDirection parseFlexDirection(const std::string &direction) {
370 const std::string d = toLowerCopy(direction);
371 if (d == "column" || d == "col" || d == "vertical" || d == "v") return FlexDirection::Column;
372 return FlexDirection::Row;
373}
374
375FlexAlign parseFlexAlign(const std::string &align) {
376 const std::string a = toLowerCopy(align);
377 if (a == "center") return FlexAlign::Center;
378 if (a == "end" || a == "right" || a == "bottom") return FlexAlign::End;
379 if (a == "stretch") return FlexAlign::Stretch;
380 return FlexAlign::Start;
381}
382
383FlexJustify parseFlexJustify(const std::string &justify) {
384 const std::string j = toLowerCopy(justify);
385 if (j == "center") return FlexJustify::Center;
386 if (j == "end" || j == "right" || j == "bottom") return FlexJustify::End;
387 if (j == "spacebetween" || j == "space-between" || j == "between")
389 if (j == "spacearound" || j == "space-around" || j == "around") return FlexJustify::SpaceAround;
390 return FlexJustify::Start;
391}
392
393} // namespace
394
395void UI::beginFlex(const std::string &direction, const std::string &id, float gap) {
396 WidgetDesc d = flex(parseFlexDirection(direction), {}, id);
397 d.gap = gap;
398 pushOpen(std::move(d));
399}
400
401void UI::beginRow(const std::string &id, float gap) { beginFlex("row", id, gap); }
402
403void UI::beginColumn(const std::string &id, float gap) { beginFlex("column", id, gap); }
404
405void UI::end() {
406 if (openStack_.empty()) throw std::runtime_error("ui: end() without begin");
407 WidgetDesc finished = std::move(openStack_.back());
408 openStack_.pop_back();
409 if (openStack_.empty()) {
410 builtRoot_ = std::move(finished);
411 hasBuiltRoot_ = true;
412 } else {
413 openStack_.back().children.push_back(std::move(finished));
414 }
415}
416
417void UI::addText(const std::string &content, const std::string &id) {
418 currentParent().children.push_back(text(content, id));
419}
420
421void UI::addTextWrapped(const std::string &content, float width, const std::string &id) {
422 WidgetDesc d = text(content, id);
423 d.wrapWidth = width;
424 currentParent().children.push_back(std::move(d));
425}
426
427void UI::addButton(const std::string &label, const std::string &id) {
428 currentParent().children.push_back(button(label, id));
429}
430
431void UI::addSameLine(const std::string &id) { currentParent().children.push_back(sameLine(id)); }
432
433void UI::addSeparator(const std::string &id) {
434 currentParent().children.push_back(separator(id));
435}
436
437void UI::addCheckbox(const std::string &label, bool checked, const std::string &id) {
438 currentParent().children.push_back(checkbox(label, checked, id));
439}
440
441void UI::addSlider(const std::string &label, float value, float minV, float maxV,
442 const std::string &id) {
443 currentParent().children.push_back(slider(label, value, minV, maxV, id));
444}
445
446void UI::addProgress(float fraction, const std::string &id, const std::string &overlay) {
447 currentParent().children.push_back(progress(fraction, id, overlay));
448}
449
450void UI::addImage(const std::string &id, float width, float height) {
451 currentParent().children.push_back(image(id, width, height));
452}
453
454void UI::addImageButton(const std::string &id, float width, float height) {
455 currentParent().children.push_back(imageButton(id, width, height));
456}
457
458void UI::addViewport(const std::string &id, float width, float height) {
459 currentParent().children.push_back(viewport(id, width, height));
460}
461
462void UI::addCombo(const std::string &label, const std::string &options, int selected,
463 const std::string &id) {
464 std::vector<std::string> items;
465 size_t start = 0;
466 while (start <= options.size()) {
467 const size_t end = options.find('\n', start);
468 items.push_back(options.substr(start, end == std::string::npos ? std::string::npos
469 : end - start));
470 if (end == std::string::npos) break;
471 start = end + 1;
472 }
473 currentParent().children.push_back(combo(label, items, selected, id));
474}
475
476void UI::addInputText(const std::string &label, const std::string &value, const std::string &id) {
477 currentParent().children.push_back(inputText(label, value, id));
478}
479
480void UI::addSpacer(const std::string &id, float grow) {
481 currentParent().children.push_back(spacer(id, grow));
482}
483
484void UI::setItemFlexGrow(float grow) {
485 WidgetDesc &parent = currentParent();
486 if (parent.children.empty()) return;
487 parent.children.back().flexGrow = grow;
488}
489
490void UI::setItemSize(float width, float height) {
491 WidgetDesc &parent = currentParent();
492 if (parent.children.empty()) return;
493 parent.children.back().sizeX = width;
494 parent.children.back().sizeY = height;
495}
496
497void UI::setItemMargin(float l, float t, float r, float b) {
498 WidgetDesc &parent = currentParent();
499 if (parent.children.empty()) return;
500 parent.children.back().marginL = l;
501 parent.children.back().marginT = t;
502 parent.children.back().marginR = r;
503 parent.children.back().marginB = b;
504}
505
506void UI::setItemPadding(float l, float t, float r, float b) {
507 WidgetDesc &parent = currentParent();
508 if (parent.children.empty()) return;
509 parent.children.back().paddingL = l;
510 parent.children.back().paddingT = t;
511 parent.children.back().paddingR = r;
512 parent.children.back().paddingB = b;
513}
514
515void UI::setItemMinSize(float w, float h) {
516 WidgetDesc &parent = currentParent();
517 if (parent.children.empty()) return;
518 parent.children.back().minSizeX = w;
519 parent.children.back().minSizeY = h;
520}
521
522void UI::setItemMaxSize(float w, float h) {
523 WidgetDesc &parent = currentParent();
524 if (parent.children.empty()) return;
525 parent.children.back().maxSizeX = w;
526 parent.children.back().maxSizeY = h;
527}
528
529void UI::setItemPercent(float w, float h) {
530 WidgetDesc &parent = currentParent();
531 if (parent.children.empty()) return;
532 parent.children.back().percentW = w;
533 parent.children.back().percentH = h;
534}
535
536void UI::setItemAbsolute(float anchorX, float anchorY, float x, float y) {
537 WidgetDesc &parent = currentParent();
538 if (parent.children.empty()) return;
539 parent.children.back().absolute = true;
540 parent.children.back().anchorX = anchorX;
541 parent.children.back().anchorY = anchorY;
542 parent.children.back().posX = x;
543 parent.children.back().posY = y;
544}
545
546void UI::setFlexAlign(const std::string &align) {
547 WidgetDesc &parent = currentParent();
548 if (parent.type != NodeType::Flex) return;
549 parent.alignItems = parseFlexAlign(align);
550}
551
552void UI::setFlexJustify(const std::string &justify) {
553 WidgetDesc &parent = currentParent();
554 if (parent.type != NodeType::Flex) return;
555 parent.justifyContent = parseFlexJustify(justify);
556}
557
558void UI::addListItem(const std::string &label, const std::string &id) {
559 WidgetDesc &parent = currentParent();
560 std::string itemId = id;
561 if (itemId.empty())
562 itemId = parent.id + "/" + std::to_string(parent.children.size());
563 parent.children.push_back(button(label, itemId).withKey(itemId));
564}
565
566bool UI::buildComplete() const { return openStack_.empty() && hasBuiltRoot_; }
567
569 if (!buildComplete()) return false;
570 remount(std::move(builtRoot_));
571 hasBuiltRoot_ = false;
572 builtRoot_ = WidgetDesc{};
573 return true;
574}
575
576bool UI::mountBuildAs(const std::string &name) {
577 if (!buildComplete()) return false;
578 mountAs(name, std::move(builtRoot_));
579 hasBuiltRoot_ = false;
580 builtRoot_ = WidgetDesc{};
581 return true;
582}
583
584bool UI::remountBuildAs(const std::string &name) {
585 if (!buildComplete()) return false;
586 UIHost *h = findHost(name);
587 if (!h) h = UIHost::createHost(name);
588 h->setTreeReconcile(std::move(builtRoot_));
589 selected_ = h;
590 hasBuiltRoot_ = false;
591 builtRoot_ = WidgetDesc{};
592 return true;
593}
594
595bool UI::setListItems(const std::string &listId, const std::vector<std::string> &items) {
596 if (!selected_) return false;
597 WidgetDesc listNode = listButtons(listId, items);
598 auto *existing = selected_->findById(listId);
599 if (existing && existing->type == NodeType::Group) {
600 selected_->setTreeReconcile(
601 window(selected_->getName().empty() ? "List" : selected_->getName(),
602 {std::move(listNode)}, "root"));
603 return true;
604 }
605 selected_->setTree(
606 window(selected_->getName().empty() ? "List" : selected_->getName(), {std::move(listNode)},
607 "root"));
608 return true;
609}
610
611void UI::setText(const std::string &id, const std::string &text) {
612 if (selected_) selected_->setTextById(id, text);
613}
614
615void UI::setTextWrap(const std::string &id, float width) {
616 if (!selected_) return;
617 if (auto *n = selected_->findById(id)) n->wrapWidth = width;
618}
619
620void UI::setVisible(const std::string &id, bool visible) {
621 if (selected_) selected_->setVisibleById(id, visible);
622}
623
624void UI::setChecked(const std::string &id, bool checked) {
625 if (selected_) selected_->setCheckedById(id, checked);
626}
627
628void UI::setValue(const std::string &id, float value) {
629 if (selected_) selected_->setValueById(id, value);
630}
631
632void UI::setValueText(const std::string &id, const std::string &value) {
633 if (selected_) selected_->setValueTextById(id, value);
634}
635
636void UI::setImageTint(const std::string &id, float r, float g, float b, float a) {
637 if (!selected_) return;
638 if (auto *n = selected_->findById(id)) {
639 n->tintR = r;
640 n->tintG = g;
641 n->tintB = b;
642 n->tintA = a;
643 }
644}
645
646void UI::setImageUv(const std::string &id, float u0, float v0, float u1, float v1) {
647 if (!selected_) return;
648 if (auto *n = selected_->findById(id)) {
649 n->uv0x = u0;
650 n->uv0y = v0;
651 n->uv1x = u1;
652 n->uv1y = v1;
653 }
654}
655
656void UI::setImageNinePatch(const std::string &id, float l, float t, float r, float b) {
657 if (!selected_) return;
658 if (auto *n = selected_->findById(id)) {
659 n->borderL = l;
660 n->borderT = t;
661 n->borderR = r;
662 n->borderB = b;
663 }
664}
665
666void UI::setImageCornerRadius(const std::string &id, float radius) {
667 if (!selected_) return;
668 if (auto *n = selected_->findById(id)) n->cornerRadius = radius;
669}
670
671void UI::setImageTextureId(const std::string &id, uint64_t textureId) {
672 if (!selected_) return;
673 if (auto *n = selected_->findById(id)) n->textureId = textureId;
674}
675
677 if (!isBackendReady()) {
678 if (!initBackend()) return 0;
679 }
680 return backend_ ? backend_->registerTexture(tex) : 0;
681}
682
683float UI::getValue(const std::string &id) const {
684 if (!selected_) return 0.f;
685 if (auto *n = selected_->findById(id)) return n->value;
686 return 0.f;
687}
688
689std::string UI::getValueText(const std::string &id) const {
690 if (!selected_) return {};
691 if (auto *n = selected_->findById(id)) return n->valueText;
692 return {};
693}
694
695bool UI::getChecked(const std::string &id) const {
696 if (!selected_) return false;
697 if (auto *n = selected_->findById(id)) return n->checked;
698 return false;
699}
700
701void UI::setHostVisible(bool visible) {
702 if (selected_) selected_->setVisible(visible);
703}
704
706 if (selected_) selected_->setLayer(layer);
707}
708
709void UI::setHostModal(bool modal) {
710 if (selected_) selected_->setModal(modal);
711}
712
713void UI::setHostOverlay(bool overlay) {
714 if (selected_) selected_->meta()->overlay = overlay;
715}
716
717void UI::setHostPos(float x, float y, float pivotX, float pivotY) {
718 if (!selected_) return;
719 auto m = selected_->meta();
720 m->hasPos = true;
721 m->posX = x;
722 m->posY = y;
723 m->pivotX = pivotX;
724 m->pivotY = pivotY;
725}
726
727void UI::setHostAnchor(float x, float y) {
728 if (!selected_) return;
729 auto m = selected_->meta();
730 m->anchorX = x;
731 m->anchorY = y;
732}
733
734void UI::setHostSize(float w, float h) {
735 if (!selected_) return;
736 auto m = selected_->meta();
737 m->hasSize = true;
738 m->sizeX = w;
739 m->sizeY = h;
740}
741
742void UI::setHostPercent(float w, float h) {
743 if (!selected_) return;
744 auto m = selected_->meta();
745 m->percentW = w;
746 m->percentH = h;
747}
748
749void UI::animateHostPos(float x, float y, float durationMs) {
750 if (!selected_) return;
751 auto m = selected_->meta();
752 HostTween t;
753 t.host = selected_;
754 t.fromX = m->hasPos ? m->posX : 0.f;
755 t.fromY = m->hasPos ? m->posY : 0.f;
756 t.toX = x;
757 t.toY = y;
758 t.startMs =
759 std::chrono::duration<double, std::milli>(std::chrono::steady_clock::now().time_since_epoch())
760 .count();
761 t.durationMs = std::max(0.0, double(durationMs));
762 m->hasPos = true;
763 hostTweens_.push_back(t);
764}
765
766std::string UI::consumeClick() { return UISystem::consumeClick(); }
767
769
771
773
774bool UI::setTheme(const std::string &name) { return setThemeByName(name); }
775
776std::string UI::getTheme() const { return globalThemeName(); }
777
781
785
786void UI::setScale(float scale) {
787 if (!isBackendReady()) {
788 if (!initBackend()) return;
789 }
790 if (backend_) backend_->setScale(scale);
792}
793
794float UI::getScale() const {
795 return backend_ ? backend_->getScale() : 1.f;
796}
797
798std::string UI::getStats() const {
799 const UIStats &s = UISystem::stats();
800 char buf[160];
801 std::snprintf(buf, sizeof(buf), "hosts=%d nodes=%d measureMs=%.3f walkMs=%.3f", s.hostCount,
802 s.nodeCount, s.measureMs, s.walkMs);
803 return buf;
804}
805
806#if !(defined(EVENGINE_WEBGPU) && defined(__EMSCRIPTEN__))
807std::string UI::saveTreeJson() const {
808 if (!selected_) return "{}";
809 auto t = selected_->tree();
810 Poco::JSON::Object root;
811 root.set("host", selected_->getName());
812 if (t->root >= 0) nodeToJson(*t, t->nodes[size_t(t->root)], root);
813 std::ostringstream oss;
814 Poco::JSON::Stringifier::stringify(root, oss, 1);
815 return oss.str();
816}
817
818bool UI::loadTreeJson(const std::string &json) {
819 if (!selected_ || json.empty()) return false;
820 try {
821 Poco::JSON::Parser parser;
822 const Poco::Dynamic::Var result = parser.parse(json);
823 const Poco::JSON::Object::Ptr obj = result.extract<Poco::JSON::Object::Ptr>();
824 if (!obj) return false;
825 WidgetDesc root = descFromJson(*obj);
826 selected_->setTree(std::move(root));
827 return true;
828 } catch (...) {
829 return false;
830 }
831}
832#else
833// The Emscripten/WebGPU runtime trims Poco; keep the API but no-op.
834std::string UI::saveTreeJson() const { return "{}"; }
835bool UI::loadTreeJson(const std::string &) { return false; }
836#endif
837
838graphics::Canvas *UI::viewportCanvas(const std::string &id) {
839 if (!selected_ || id.empty()) return nullptr;
840 const std::string key = selected_->getName() + "/" + id;
841 ViewportState *vs = UISystem::viewportState(selected_->getName(), id);
842 if (!vs) vs = UISystem::ensureViewport(key, 320, 240);
843 return vs ? vs->canvas : nullptr;
844}
845
846bool UI::viewportHovered(const std::string &id) {
847 if (!selected_) return false;
848 if (auto *vs = UISystem::viewportState(selected_->getName(), id)) return vs->hovered;
849 return false;
850}
851
852bool UI::viewportActive(const std::string &id) {
853 if (!selected_) return false;
854 if (auto *vs = UISystem::viewportState(selected_->getName(), id)) return vs->active;
855 return false;
856}
857
858float UI::viewportMouseX(const std::string &id) {
859 if (!selected_) return 0.f;
860 if (auto *vs = UISystem::viewportState(selected_->getName(), id)) return vs->mouseX;
861 return 0.f;
862}
863
864float UI::viewportMouseY(const std::string &id) {
865 if (!selected_) return 0.f;
866 if (auto *vs = UISystem::viewportState(selected_->getName(), id)) return vs->mouseY;
867 return 0.f;
868}
869
870float UI::viewportDragDX(const std::string &id) {
871 if (!selected_) return 0.f;
872 if (auto *vs = UISystem::viewportState(selected_->getName(), id)) return vs->dragDX;
873 return 0.f;
874}
875
876float UI::viewportDragDY(const std::string &id) {
877 if (!selected_) return 0.f;
878 if (auto *vs = UISystem::viewportState(selected_->getName(), id)) return vs->dragDY;
879 return 0.f;
880}
881
882float UI::viewportWheel(const std::string &id) {
883 if (!selected_) return 0.f;
884 if (auto *vs = UISystem::viewportState(selected_->getName(), id)) return vs->wheel;
885 return 0.f;
886}
887
888#if !(defined(EVENGINE_WEBGPU) && defined(__EMSCRIPTEN__))
889namespace {
890
891const char *nodeTypeName(NodeType t) {
892 switch (t) {
893 case NodeType::Window: return "window";
894 case NodeType::Text: return "text";
895 case NodeType::Button: return "button";
896 case NodeType::SameLine: return "sameLine";
897 case NodeType::Group: return "group";
898 case NodeType::Separator: return "separator";
899 case NodeType::Checkbox: return "checkbox";
900 case NodeType::Slider: return "slider";
901 case NodeType::Progress: return "progress";
902 case NodeType::InputText: return "inputText";
903 case NodeType::CollapsingHeader: return "collapsingHeader";
904 case NodeType::Child: return "child";
905 case NodeType::Flex: return "flex";
906 case NodeType::Spacer: return "spacer";
907 case NodeType::Image: return "image";
908 case NodeType::ImageButton: return "imageButton";
909 case NodeType::Combo: return "combo";
910 }
911 return "text";
912}
913
914NodeType nodeTypeFromName(const std::string &s) {
915 if (s == "window") return NodeType::Window;
916 if (s == "button") return NodeType::Button;
917 if (s == "sameLine") return NodeType::SameLine;
918 if (s == "group") return NodeType::Group;
919 if (s == "separator") return NodeType::Separator;
920 if (s == "checkbox") return NodeType::Checkbox;
921 if (s == "slider") return NodeType::Slider;
922 if (s == "progress") return NodeType::Progress;
923 if (s == "inputText") return NodeType::InputText;
924 if (s == "collapsingHeader") return NodeType::CollapsingHeader;
925 if (s == "child") return NodeType::Child;
926 if (s == "flex") return NodeType::Flex;
927 if (s == "spacer") return NodeType::Spacer;
928 if (s == "image") return NodeType::Image;
929 if (s == "imageButton") return NodeType::ImageButton;
930 if (s == "combo") return NodeType::Combo;
931 return NodeType::Text;
932}
933
934void nodeToJson(const UIHost::Tree &tree, const UINode &n, Poco::JSON::Object &o) {
935 o.set("type", nodeTypeName(n.type));
936 if (!n.id.empty()) o.set("id", n.id);
937 if (!n.key.empty()) o.set("key", n.key);
938 if (!n.text.empty()) o.set("text", n.text);
939 if (!n.valueText.empty()) o.set("valueText", n.valueText);
940 if (!n.visible) o.set("visible", false);
941 if (n.checked) o.set("checked", true);
942 if (!n.open) o.set("open", false);
943 if (n.value != 0.f) o.set("value", n.value);
944 if (n.minValue != 0.f) o.set("minValue", n.minValue);
945 if (n.maxValue != 1.f) o.set("maxValue", n.maxValue);
946 if (n.sizeX != 0.f) o.set("sizeX", n.sizeX);
947 if (n.sizeY != 0.f) o.set("sizeY", n.sizeY);
948 if (n.marginL != 0.f || n.marginT != 0.f || n.marginR != 0.f || n.marginB != 0.f)
949 o.set("margin", Poco::Dynamic::Array({n.marginL, n.marginT, n.marginR, n.marginB}));
950 if (n.paddingL != 0.f || n.paddingT != 0.f || n.paddingR != 0.f || n.paddingB != 0.f)
951 o.set("padding", Poco::Dynamic::Array({n.paddingL, n.paddingT, n.paddingR, n.paddingB}));
952 if (n.minSizeX != 0.f) o.set("minSizeX", n.minSizeX);
953 if (n.minSizeY != 0.f) o.set("minSizeY", n.minSizeY);
954 if (n.maxSizeX != 0.f) o.set("maxSizeX", n.maxSizeX);
955 if (n.maxSizeY != 0.f) o.set("maxSizeY", n.maxSizeY);
956 if (n.percentW != 0.f) o.set("percentW", n.percentW);
957 if (n.percentH != 0.f) o.set("percentH", n.percentH);
958 if (n.absolute) {
959 o.set("absolute", true);
960 o.set("anchorX", n.anchorX);
961 o.set("anchorY", n.anchorY);
962 o.set("posX", n.posX);
963 o.set("posY", n.posY);
964 }
965 if (n.wrapWidth != 0.f) o.set("wrapWidth", n.wrapWidth);
966 if (n.flexDirection != FlexDirection::Row)
967 o.set("flexDirection", n.flexDirection == FlexDirection::Column ? "column" : "row");
968 if (n.alignItems != FlexAlign::Start) o.set("alignItems", int(n.alignItems));
969 if (n.justifyContent != FlexJustify::Start) o.set("justifyContent", int(n.justifyContent));
970 if (n.gap >= 0.f) o.set("gap", n.gap);
971 if (n.flexGrow != 0.f) o.set("flexGrow", n.flexGrow);
972 if (n.tintR != 1.f || n.tintG != 1.f || n.tintB != 1.f || n.tintA != 1.f)
973 o.set("tint", Poco::Dynamic::Array({n.tintR, n.tintG, n.tintB, n.tintA}));
974 if (n.borderL != 0.f || n.borderT != 0.f || n.borderR != 0.f || n.borderB != 0.f)
975 o.set("border", Poco::Dynamic::Array({n.borderL, n.borderT, n.borderR, n.borderB}));
976 if (n.cornerRadius != 0.f) o.set("cornerRadius", n.cornerRadius);
977 if (n.uv0x != 0.f || n.uv0y != 0.f || n.uv1x != 1.f || n.uv1y != 1.f)
978 o.set("uv", Poco::Dynamic::Array({n.uv0x, n.uv0y, n.uv1x, n.uv1y}));
979
980 Poco::JSON::Array children;
981 for (int c = n.firstChild; c >= 0; c = tree.nodes[size_t(c)].nextSibling) {
982 Poco::JSON::Object child;
983 nodeToJson(tree, tree.nodes[size_t(c)], child);
984 children.add(child);
985 }
986 if (children.size() > 0) o.set("children", children);
987}
988
989float fnum(const Poco::Dynamic::Var &v, float def = 0.f) {
990 try {
991 return float(v.convert<double>());
992 } catch (...) {
993 return def;
994 }
995}
996
997void applyCommonFields(WidgetDesc &d, const Poco::JSON::Object &o) {
998 if (o.has("id")) d.id = o.getValue<std::string>("id");
999 if (o.has("key")) d.key = o.getValue<std::string>("key");
1000 if (o.has("text")) d.text = o.getValue<std::string>("text");
1001 if (o.has("valueText")) d.valueText = o.getValue<std::string>("valueText");
1002 if (o.has("visible")) d.visible = o.getValue<bool>("visible");
1003 if (o.has("checked")) d.checked = o.getValue<bool>("checked");
1004 if (o.has("open")) d.open = o.getValue<bool>("open");
1005 if (o.has("value")) d.value = fnum(o.get("value"));
1006 if (o.has("minValue")) d.minValue = fnum(o.get("minValue"));
1007 if (o.has("maxValue")) d.maxValue = fnum(o.get("maxValue"));
1008 if (o.has("sizeX")) d.sizeX = fnum(o.get("sizeX"));
1009 if (o.has("sizeY")) d.sizeY = fnum(o.get("sizeY"));
1010 if (o.has("margin")) {
1011 const Poco::Dynamic::Array a = o.get("margin").extract<Poco::Dynamic::Array>();
1012 if (a.size() >= 4) {
1013 d.marginL = fnum(a[0]);
1014 d.marginT = fnum(a[1]);
1015 d.marginR = fnum(a[2]);
1016 d.marginB = fnum(a[3]);
1017 }
1018 }
1019 if (o.has("padding")) {
1020 const Poco::Dynamic::Array a = o.get("padding").extract<Poco::Dynamic::Array>();
1021 if (a.size() >= 4) {
1022 d.paddingL = fnum(a[0]);
1023 d.paddingT = fnum(a[1]);
1024 d.paddingR = fnum(a[2]);
1025 d.paddingB = fnum(a[3]);
1026 }
1027 }
1028 if (o.has("minSizeX")) d.minSizeX = fnum(o.get("minSizeX"));
1029 if (o.has("minSizeY")) d.minSizeY = fnum(o.get("minSizeY"));
1030 if (o.has("maxSizeX")) d.maxSizeX = fnum(o.get("maxSizeX"));
1031 if (o.has("maxSizeY")) d.maxSizeY = fnum(o.get("maxSizeY"));
1032 if (o.has("percentW")) d.percentW = fnum(o.get("percentW"));
1033 if (o.has("percentH")) d.percentH = fnum(o.get("percentH"));
1034 if (o.has("absolute")) d.absolute = o.getValue<bool>("absolute");
1035 if (o.has("anchorX")) d.anchorX = fnum(o.get("anchorX"));
1036 if (o.has("anchorY")) d.anchorY = fnum(o.get("anchorY"));
1037 if (o.has("posX")) d.posX = fnum(o.get("posX"));
1038 if (o.has("posY")) d.posY = fnum(o.get("posY"));
1039 if (o.has("wrapWidth")) d.wrapWidth = fnum(o.get("wrapWidth"));
1040 if (o.has("flexDirection")) d.flexDirection =
1041 o.getValue<std::string>("flexDirection") == "column" ? FlexDirection::Column
1043 if (o.has("alignItems")) d.alignItems = FlexAlign(int(fnum(o.get("alignItems"))));
1044 if (o.has("justifyContent"))
1045 d.justifyContent = FlexJustify(int(fnum(o.get("justifyContent"))));
1046 if (o.has("gap")) d.gap = fnum(o.get("gap"), -1.f);
1047 if (o.has("flexGrow")) d.flexGrow = fnum(o.get("flexGrow"));
1048 if (o.has("tint")) {
1049 const Poco::Dynamic::Array a = o.get("tint").extract<Poco::Dynamic::Array>();
1050 if (a.size() >= 4) {
1051 d.tintR = fnum(a[0], 1.f);
1052 d.tintG = fnum(a[1], 1.f);
1053 d.tintB = fnum(a[2], 1.f);
1054 d.tintA = fnum(a[3], 1.f);
1055 }
1056 }
1057 if (o.has("border")) {
1058 const Poco::Dynamic::Array a = o.get("border").extract<Poco::Dynamic::Array>();
1059 if (a.size() >= 4) {
1060 d.borderL = fnum(a[0]);
1061 d.borderT = fnum(a[1]);
1062 d.borderR = fnum(a[2]);
1063 d.borderB = fnum(a[3]);
1064 }
1065 }
1066 if (o.has("cornerRadius")) d.cornerRadius = fnum(o.get("cornerRadius"));
1067 if (o.has("uv")) {
1068 const Poco::Dynamic::Array a = o.get("uv").extract<Poco::Dynamic::Array>();
1069 if (a.size() >= 4) {
1070 d.uv0x = fnum(a[0]);
1071 d.uv0y = fnum(a[1]);
1072 d.uv1x = fnum(a[2], 1.f);
1073 d.uv1y = fnum(a[3], 1.f);
1074 }
1075 }
1076}
1077
1078WidgetDesc descFromJson(const Poco::JSON::Object &o) {
1079 WidgetDesc d;
1080 d.type = nodeTypeFromName(o.optValue<std::string>("type", "text"));
1081 applyCommonFields(d, o);
1082 if (o.has("children")) {
1083 const Poco::JSON::Array::Ptr children = o.getArray("children");
1084 for (size_t i = 0; i < children->size(); ++i) {
1085 const Poco::JSON::Object::Ptr child = children->getObject(i);
1086 if (child) d.children.push_back(descFromJson(*child));
1087 }
1088 }
1089 return d;
1090}
1091
1092} // namespace
1093#endif
1094
1095void UI::mountSimple(const std::string &title, const std::string &labelText,
1096 const std::string &buttonText) {
1097 mountAs("default", window(title, {text(labelText, "label"), button(buttonText, "btn")}, "root"));
1098}
1099
1101 if (!inspector_) inspector_ = std::make_unique<Inspector>();
1102 inspector_->setPickScene([this]() { return callPickHandler(); });
1103 inspector_->open();
1104 return inspector_->isOpen();
1105}
1106
1108 if (inspector_) inspector_->close();
1109}
1110
1112 if (!inspector_) inspector_ = std::make_unique<Inspector>();
1113 inspector_->refresh();
1114 return inspector_->instanceCount() > 0;
1115}
1116
1117bool UI::inspectSelectClass(const std::string &name) {
1118 if (!inspector_) inspector_ = std::make_unique<Inspector>();
1119 inspector_->setPickScene([this]() { return callPickHandler(); });
1120 inspector_->open(); // scans classes and mounts the panel if not open yet
1121 return inspector_->selectClass(name);
1122}
1123
1124bool UI::inspectObject(ssq::Object object) {
1125 if (!inspector_) inspector_ = std::make_unique<Inspector>();
1126 inspector_->setPickScene([this]() { return callPickHandler(); });
1127 inspector_->open(); // scans classes and mounts the panel if not open yet
1128 return inspector_->inspectObject(object);
1129}
1130
1131bool UI::inspectSetPickHandler(ssq::Function fn) {
1133 if (!rt) return false;
1134 HSQUIRRELVM squirrel = rt->handle();
1135 const SQInteger top = sq_gettop(squirrel);
1136 sq_pushroottable(squirrel);
1137 sq_pushstring(squirrel, "eve", -1);
1138 if (SQ_FAILED(sq_get(squirrel, -2)) ||
1139 sq_gettype(squirrel, -1) != OT_TABLE) {
1140 sq_settop(squirrel, top);
1141 return false;
1142 }
1143 sq_pushstring(squirrel, "_inspectorPickHandler", -1);
1144 sq_pushobject(squirrel, fn.getRaw());
1145 sq_newslot(squirrel, -3, SQFalse);
1146 sq_settop(squirrel, top);
1147 return true;
1148}
1149
1150ssq::Object UI::callPickHandler() {
1152 if (!rt) return {};
1153 HSQUIRRELVM squirrel = rt->handle();
1154 const SQInteger top = sq_gettop(squirrel);
1155 sq_pushroottable(squirrel);
1156 sq_pushstring(squirrel, "eve", -1);
1157 if (SQ_FAILED(sq_get(squirrel, -2)) ||
1158 sq_gettype(squirrel, -1) != OT_TABLE) {
1159 sq_settop(squirrel, top);
1160 return {};
1161 }
1162 sq_pushstring(squirrel, "_inspectorPickHandler", -1);
1163 if (SQ_FAILED(sq_get(squirrel, -2)) ||
1164 (sq_gettype(squirrel, -1) != OT_CLOSURE &&
1165 sq_gettype(squirrel, -1) != OT_NATIVECLOSURE)) {
1166 sq_settop(squirrel, top);
1167 return {};
1168 }
1169 sq_pushroottable(squirrel); // environment
1170 if (SQ_FAILED(sq_call(squirrel, 1, SQTrue, SQTrue))) {
1171 sq_settop(squirrel, top);
1172 return {};
1173 }
1174 if (sq_gettype(squirrel, -1) != OT_INSTANCE) {
1175 sq_settop(squirrel, top);
1176 return {};
1177 }
1178 ssq::Object out(squirrel);
1179 sq_getstackobj(squirrel, -1, &out.getRaw());
1180 sq_addref(squirrel, &out.getRaw());
1181 sq_settop(squirrel, top);
1182 return out;
1183}
1184
1186 if (!inspector_) inspector_ = std::make_unique<Inspector>();
1187 inspector_->setPickScene([this]() { return callPickHandler(); });
1188 inspector_->open();
1189 const ssq::Object picked = callPickHandler();
1190 if (picked.getType() != ssq::Type::INSTANCE) return false;
1191 return inspector_->inspectObject(picked);
1192}
1193
1195 return inspector_ && inspector_->addInstance();
1196}
1197
1199 if (!databasePanel_) databasePanel_ = std::make_unique<DatabasePanel>();
1200 databasePanel_->open();
1201 return databasePanel_->isOpen();
1202}
1203
1205 if (databasePanel_) databasePanel_->close();
1206}
1207
1209 if (!databasePanel_) databasePanel_ = std::make_unique<DatabasePanel>();
1210 databasePanel_->refresh();
1211 return databasePanel_->isOpen();
1212}
1213
1214bool UI::dbSelectClass(const std::string &name) {
1215 if (!databasePanel_) databasePanel_ = std::make_unique<DatabasePanel>();
1216 databasePanel_->refresh();
1217 return databasePanel_->selectClass(name);
1218}
1219
1220uint64_t UI::dbRegister(ssq::Object object, const std::string &label) {
1221 if (!databasePanel_) databasePanel_ = std::make_unique<DatabasePanel>();
1222 databasePanel_->open(); // mount the panel so the entry becomes visible
1223 return databasePanel_->registerObject(object, label);
1224}
1225
1227 if (!databasePanel_) databasePanel_ = std::make_unique<DatabasePanel>();
1228 databasePanel_->open();
1229 return databasePanel_->createInstance();
1230}
1231
1232bool UI::dbUnregister(uint64_t id) {
1233 return databasePanel_ && databasePanel_->unregister(id);
1234}
1235
1237 if (!inspector_) inspector_ = std::make_unique<Inspector>();
1238 inspector_->setPickScene([this]() { return callPickHandler(); });
1239 inspector_->open();
1240 if (!databasePanel_) databasePanel_ = std::make_unique<DatabasePanel>();
1241 databasePanel_->open();
1242 if (!scenePanel_) scenePanel_ = std::make_unique<ScenePanel>();
1243 scenePanel_->setPickHandler([this](const std::string &nodeId) {
1244 callScenePickHandler(nodeId);
1245 });
1246 scenePanel_->open();
1247 if (!editorShell_) editorShell_ = std::make_unique<EditorShell>();
1248 editorShell_->open(inspector_->host(), databasePanel_->host(),
1249 scenePanel_->host());
1250 editorShell_->selectPanel("inspector");
1251 return editorShell_->isOpen();
1252}
1253
1255 if (editorShell_) editorShell_->close();
1256}
1257
1258bool UI::editorSelectPanel(const std::string &name) {
1259 return editorShell_ && editorShell_->selectPanel(name);
1260}
1261
1263 if (!scenePanel_) scenePanel_ = std::make_unique<ScenePanel>();
1264 scenePanel_->setPickHandler([this](const std::string &nodeId) {
1265 callScenePickHandler(nodeId);
1266 });
1267 scenePanel_->open();
1268 return scenePanel_->isOpen();
1269}
1270
1272 if (scenePanel_) scenePanel_->close();
1273}
1274
1275bool UI::sceneSelectNode(const std::string &id) {
1276 return scenePanel_ && scenePanel_->selectNode(id);
1277}
1278
1279bool UI::sceneSetPickHandler(ssq::Function fn) {
1281 if (!rt) return false;
1282 HSQUIRRELVM squirrel = rt->handle();
1283 const SQInteger top = sq_gettop(squirrel);
1284 sq_pushroottable(squirrel);
1285 sq_pushstring(squirrel, "eve", -1);
1286 if (SQ_FAILED(sq_get(squirrel, -2)) ||
1287 sq_gettype(squirrel, -1) != OT_TABLE) {
1288 sq_settop(squirrel, top);
1289 return false;
1290 }
1291 sq_pushstring(squirrel, "_scenePickHandler", -1);
1292 sq_pushobject(squirrel, fn.getRaw());
1293 sq_newslot(squirrel, -3, SQFalse);
1294 sq_settop(squirrel, top);
1295 return true;
1296}
1297
1298void UI::callScenePickHandler(const std::string &nodeId) {
1300 if (!rt) return;
1301 HSQUIRRELVM squirrel = rt->handle();
1302 const SQInteger top = sq_gettop(squirrel);
1303 sq_pushroottable(squirrel);
1304 sq_pushstring(squirrel, "eve", -1);
1305 if (SQ_FAILED(sq_get(squirrel, -2)) ||
1306 sq_gettype(squirrel, -1) != OT_TABLE) {
1307 sq_settop(squirrel, top);
1308 return;
1309 }
1310 sq_pushstring(squirrel, "_scenePickHandler", -1);
1311 if (SQ_FAILED(sq_get(squirrel, -2)) ||
1312 (sq_gettype(squirrel, -1) != OT_CLOSURE &&
1313 sq_gettype(squirrel, -1) != OT_NATIVECLOSURE)) {
1314 sq_settop(squirrel, top);
1315 return;
1316 }
1317 sq_pushroottable(squirrel); // environment
1318 sq_pushstring(squirrel, nodeId.c_str(), -1); // node id argument
1319 sq_call(squirrel, 2, SQFalse, SQTrue);
1320 sq_settop(squirrel, top);
1321}
1322
1323void UI::expose(ssq::Table &table) {
1324 auto cls = table.addClass(name, UI::create, false);
1325 expose(cls);
1326 injectUIComponentClass(table);
1327}
1328
1329void UI::expose(ssq::Class &cls) {
1330 cls.addFunc("getName", &UI::getName);
1331 cls.addFunc("initBackend", &UI::initBackend);
1332 cls.addFunc("isBackendReady", &UI::isBackendReady);
1333 cls.addFunc("beginFrameAndRender", &UI::beginFrameAndRender);
1334 cls.addFunc("dispatchEvents", &UI::dispatchEvents);
1335 cls.addFunc("wantCaptureMouse", &UI::wantCaptureMouse);
1336 cls.addFunc("wantCaptureKeyboard", &UI::wantCaptureKeyboard);
1337
1338 cls.addFunc("select", &UI::select);
1339 cls.addFunc("bindOwner", &UI::bindOwner);
1340 cls.addFunc("mountBuildAs", &UI::mountBuildAs);
1341 cls.addFunc("remountBuildAs", &UI::remountBuildAs);
1342
1343 cls.addFunc("beginBuild", &UI::beginBuild);
1344 cls.addFunc("beginWindow", &UI::beginWindow);
1345 cls.addFunc("beginGroup", &UI::beginGroup);
1346 cls.addFunc("beginList", &UI::beginList);
1347 cls.addFunc("beginCollapsing", &UI::beginCollapsing);
1348 cls.addFunc("beginChild", &UI::beginChild);
1349 cls.addFunc("beginScrollList", &UI::beginScrollList);
1350 cls.addFunc("beginFlex", &UI::beginFlex);
1351 cls.addFunc("beginRow", &UI::beginRow);
1352 cls.addFunc("beginColumn", &UI::beginColumn);
1353 cls.addFunc("end", &UI::end);
1354 cls.addFunc("text", &UI::addText);
1355 cls.addFunc("textWrapped", &UI::addTextWrapped);
1356 cls.addFunc("button", &UI::addButton);
1357 cls.addFunc("sameLine", &UI::addSameLine);
1358 cls.addFunc("separator", &UI::addSeparator);
1359 cls.addFunc("checkbox", &UI::addCheckbox);
1360 cls.addFunc("slider", &UI::addSlider);
1361 cls.addFunc("progress", &UI::addProgress);
1362 cls.addFunc("image", &UI::addImage);
1363 cls.addFunc("imageButton", &UI::addImageButton);
1364 cls.addFunc("viewport", &UI::addViewport);
1365 cls.addFunc("combo", &UI::addCombo);
1366 cls.addFunc("inputText", &UI::addInputText);
1367 cls.addFunc("spacer", &UI::addSpacer);
1368 cls.addFunc("setItemFlexGrow", &UI::setItemFlexGrow);
1369 cls.addFunc("setItemSize", &UI::setItemSize);
1370 cls.addFunc("setItemMargin", &UI::setItemMargin);
1371 cls.addFunc("setItemPadding", &UI::setItemPadding);
1372 cls.addFunc("setItemMinSize", &UI::setItemMinSize);
1373 cls.addFunc("setItemMaxSize", &UI::setItemMaxSize);
1374 cls.addFunc("setItemPercent", &UI::setItemPercent);
1375 cls.addFunc("setItemAbsolute", &UI::setItemAbsolute);
1376 cls.addFunc("setFlexAlign", &UI::setFlexAlign);
1377 cls.addFunc("setFlexJustify", &UI::setFlexJustify);
1378 cls.addFunc("listItem", &UI::addListItem);
1379 cls.addFunc("mountBuild", &UI::mountBuild);
1380
1381 cls.addFunc("setText", &UI::setText);
1382 cls.addFunc("setTextWrap", &UI::setTextWrap);
1383 cls.addFunc("setVisible", &UI::setVisible);
1384 cls.addFunc("setChecked", &UI::setChecked);
1385 cls.addFunc("setValue", &UI::setValue);
1386 cls.addFunc("setValueText", &UI::setValueText);
1387 cls.addFunc("setImageTint", &UI::setImageTint);
1388 cls.addFunc("setImageUv", &UI::setImageUv);
1389 cls.addFunc("setImageNinePatch", &UI::setImageNinePatch);
1390 cls.addFunc("setImageCornerRadius", &UI::setImageCornerRadius);
1391 cls.addFunc("getValue", &UI::getValue);
1392 cls.addFunc("getValueText", &UI::getValueText);
1393 cls.addFunc("getChecked", &UI::getChecked);
1394 cls.addFunc("setHostVisible", &UI::setHostVisible);
1395 cls.addFunc("setHostLayer", &UI::setHostLayer);
1396 cls.addFunc("setHostModal", &UI::setHostModal);
1397 cls.addFunc("setHostOverlay", &UI::setHostOverlay);
1398 cls.addFunc("setHostPos", &UI::setHostPos);
1399 cls.addFunc("setHostAnchor", &UI::setHostAnchor);
1400 cls.addFunc("setHostSize", &UI::setHostSize);
1401 cls.addFunc("setHostPercent", &UI::setHostPercent);
1402 cls.addFunc("animateHostPos", &UI::animateHostPos);
1403 cls.addFunc("consumeClick", &UI::consumeClick);
1404 cls.addFunc("consumeChange", &UI::consumeChange);
1405 cls.addFunc("onClick", &UI::onClick);
1406 cls.addFunc("onChange", &UI::onChange);
1407
1408 cls.addFunc("setThemeDark", &UI::setThemeDark);
1409 cls.addFunc("setThemeLight", &UI::setThemeLight);
1410 cls.addFunc("setTheme", &UI::setTheme);
1411 cls.addFunc("getTheme", &UI::getTheme);
1412 cls.addFunc("setNavKeyboard", &UI::setNavKeyboard);
1413 cls.addFunc("setNavGamepad", &UI::setNavGamepad);
1414 cls.addFunc("setScale", &UI::setScale);
1415 cls.addFunc("getScale", &UI::getScale);
1416 cls.addFunc("getStats", &UI::getStats);
1417 cls.addFunc("saveTreeJson", &UI::saveTreeJson);
1418 cls.addFunc("loadTreeJson", &UI::loadTreeJson);
1419 cls.addFunc("viewportCanvas", &UI::viewportCanvas);
1420 cls.addFunc("viewportHovered", &UI::viewportHovered);
1421 cls.addFunc("viewportActive", &UI::viewportActive);
1422 cls.addFunc("viewportMouseX", &UI::viewportMouseX);
1423 cls.addFunc("viewportMouseY", &UI::viewportMouseY);
1424 cls.addFunc("viewportDragDX", &UI::viewportDragDX);
1425 cls.addFunc("viewportDragDY", &UI::viewportDragDY);
1426 cls.addFunc("viewportWheel", &UI::viewportWheel);
1427
1428 cls.addFunc("mountSimple", &UI::mountSimple);
1429
1430 cls.addFunc("inspect", &UI::inspectOpen);
1431 cls.addFunc("inspectClose", &UI::inspectClose);
1432 cls.addFunc("inspectRefresh", &UI::inspectRefresh);
1433 cls.addFunc("inspectSelectClass", &UI::inspectSelectClass);
1434 cls.addFunc("inspectObject", &UI::inspectObject);
1435 cls.addFunc("inspectSetPickHandler", &UI::inspectSetPickHandler);
1436 cls.addFunc("inspectPickScene", &UI::inspectPickScene);
1437 cls.addFunc("inspectAddInstance", &UI::inspectAddInstance);
1438
1439 cls.addFunc("dbOpen", &UI::dbOpen);
1440 cls.addFunc("dbClose", &UI::dbClose);
1441 cls.addFunc("dbRefresh", &UI::dbRefresh);
1442 cls.addFunc("dbSelectClass", &UI::dbSelectClass);
1443 cls.addFunc("dbRegister", &UI::dbRegister);
1444 cls.addFunc("dbCreateInstance", &UI::dbCreateInstance);
1445 cls.addFunc("dbUnregister", &UI::dbUnregister);
1446
1447 cls.addFunc("editorOpen", &UI::editorOpen);
1448 cls.addFunc("editorClose", &UI::editorClose);
1449 cls.addFunc("editorSelectPanel", &UI::editorSelectPanel);
1450
1451 cls.addFunc("sceneOpen", &UI::sceneOpen);
1452 cls.addFunc("sceneClose", &UI::sceneClose);
1453 cls.addFunc("sceneSelectNode", &UI::sceneSelectNode);
1454 cls.addFunc("sceneSetPickHandler", &UI::sceneSetPickHandler);
1455}
1456
1457} // namespace eve::ui
struct SQVM * HSQUIRRELVM
Tok kind
std::string value
HSQUIRRELVM vm
Definition ECS.cpp:20
HSQOBJECT cls
Definition ECS.cpp:21
std::string title
std::vector< HostEvent > events
std::string id
int y
Definition Grass.cpp:135
float height
Definition Grass.cpp:235
int x
Definition Grass.cpp:135
glm::vec3 n
Definition Grass.cpp:64
int h
int w
const FusedGroup & group
uint32_t a
uint32_t b
uint32_t c
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:24
int width
TileLayer * layer
const char * name
Definition RockMesh.cpp:21
SettlementPipeline::Stage fn
bool enabled
int d
int v
std::string image
float scale
Definition TreeMesh.cpp:122
int parent
Definition TreeMesh.cpp:175
int children
Definition TreeMesh.cpp:177
float m[16]
uint32_t s
Definition Weather.cpp:28
static Runtime * runtime()
Active runtime associated with the last expose() call, or nullptr.
Definition Module.cpp:68
virtual std::string getName() const =0
HSQUIRRELVM handle() const noexcept
Raw Squirrel VM handle; nullptr after shutdown.
Definition Runtime.cpp:453
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
Definition Texture.h:17
ECS mount point for one UI panel/screen. Subclass to attach UI to game entities, e....
Definition UIHost.h:130
bool setTreeReconcile(WidgetDesc root)
Key-aware patch when structure matches; else full replace.
Definition UIHost.cpp:28
static UIHost * createHost(const std::string &name="")
Definition UIHost.cpp:11
void setTree(WidgetDesc root)
Full replace.
Definition UIHost.cpp:26
void setCheckedById(const std::string &id, bool checked)
Definition UIHost.cpp:67
void setLayer(int layer)
Definition UIHost.h:209
void setValueById(const std::string &id, float value)
Definition UIHost.cpp:71
void setOwnerId(uint32_t id)
Attaches the host to an owner id (scene/UI ownership).
Definition UIHost.h:177
const std::string & getName()
Definition UIHost.cpp:24
void setVisible(bool v)
Host visibility / layer / modality.
Definition UIHost.h:208
void setModal(bool modal)
Definition UIHost.h:210
void setVisibleById(const std::string &id, bool visible)
Definition UIHost.cpp:63
UINode * findById(const std::string &id)
Looks up a node by id or reconciliation key.
Definition UIHost.cpp:41
void setValueTextById(const std::string &id, const std::string &value)
Definition UIHost.cpp:75
void setTextById(const std::string &id, const std::string &text)
Widget state updates by node id.
Definition UIHost.cpp:59
static ViewportState * ensureViewport(const std::string &key, int w, int h)
Definition UISystem.cpp:538
static const UIStats & stats()
Definition UISystem.cpp:536
static void setBackend(UIBackend *backend)
Definition UISystem.cpp:534
static std::string consumeChange()
Pop next change as "name/node"; empty if none.
Definition UISystem.cpp:696
static UIHost * findHost(const std::string &name)
Lookup by Meta.name across the UIHost View.
Definition UISystem.cpp:561
static void dispatchEvents()
Definition UISystem.cpp:628
static UIHost * findHostByOwner(uint32_t ownerId)
First host with Meta.ownerId == ownerId, or nullptr.
Definition UISystem.cpp:573
static std::string consumeClick()
Pop next click as "name/node"; empty if none.
Definition UISystem.cpp:678
static void render()
Walk all UIHost (+ subclasses) via ECS View.
Definition UISystem.cpp:585
static std::vector< UIEvent > & pendingEvents()
Definition UISystem.cpp:530
static ViewportState * viewportState(const std::string &hostName, const std::string &nodeId)
Definition UISystem.cpp:556
Declarative UI module (eve.UI).
Definition UI.h:34
UIHost * findHost(const std::string &name) const
Finds a host by name, or nullptr.
Definition UI.cpp:262
bool inspectSelectClass(const std::string &name)
Selects a class in the inspector (creates its first instance).
Definition UI.cpp:1117
void setTextWrap(const std::string &id, float width)
Definition UI.cpp:615
bool mountBuild()
Finishes the build pass and mounts the built tree.
Definition UI.cpp:568
void addCombo(const std::string &label, const std::string &options, int selected, const std::string &id="")
Definition UI.cpp:462
float viewportMouseX(const std::string &id)
Definition UI.cpp:858
bool wantCaptureKeyboard() const
True when the UI wants to capture keyboard input this frame.
Definition UI.cpp:258
uint64_t registerTexture(graphics::Texture *tex)
Definition UI.cpp:676
std::string consumeClick()
Returns the id of the clicked widget since the last frame (or "").
Definition UI.cpp:766
bool initBackend()
Creates the platform UI backend (ImGui); true on success.
Definition UI.cpp:156
void setHostPercent(float w, float h)
Definition UI.cpp:742
void setImageTextureId(const std::string &id, uint64_t textureId)
Definition UI.cpp:671
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:717
std::string saveTreeJson() const
Definition UI.cpp:807
bool editorSelectPanel(const std::string &name)
Shows one docked panel ("inspector"/"database"; "" hides all).
Definition UI.cpp:1258
bool inspectPickScene()
Calls the pick handler and inspects the returned object.
Definition UI.cpp:1185
void dispatchEvents()
Dispatches queued widget callbacks (click/toggle/value/text).
Definition UI.cpp:217
void setItemPercent(float w, float h)
Definition UI.cpp:529
void bindOwner(uint32_t ownerId)
Binds the selected host to a UI/scene owner id.
Definition UI.cpp:275
void addText(const std::string &content, const std::string &id="")
Adds a text label to the current container.
Definition UI.cpp:417
void setImageCornerRadius(const std::string &id, float radius)
Definition UI.cpp:666
void processEvent(const SDL_Event *event)
Feeds an SDL event into the UI backend (before window/game handling).
Definition UI.cpp:175
void setHostSize(float w, float h)
Definition UI.cpp:734
bool inspectOpen()
Opens the auto-generated inspector (scans reflected classes).
Definition UI.cpp:1100
bool sceneOpen()
Opens the scene panel (tree + selected node properties).
Definition UI.cpp:1262
bool sceneSetPickHandler(ssq::Function fn)
Registers the script callback for the scene panel Pick button. The callback (stored as eve....
Definition UI.cpp:1279
void editorClose()
Closes the editor shell (and its docked panels).
Definition UI.cpp:1254
void shutdownBackend()
Destroys the platform UI backend.
Definition UI.cpp:171
float viewportDragDX(const std::string &id)
Definition UI.cpp:870
UIHost * findHostByOwner(uint32_t ownerId) const
Finds the host bound to an owner id, or nullptr.
Definition UI.cpp:264
float getValue(const std::string &id) const
Definition UI.cpp:683
UIHost * mount(WidgetDesc root)
Mounts the tree as an auto-named host and selects it.
Definition UI.cpp:302
~UI() override
Definition UI.cpp:152
void addSpacer(const std::string &id="", float grow=1.f)
Flexible empty space inside Flex (default grow=1).
Definition UI.cpp:480
void addImage(const std::string &id="", float width=0.f, float height=0.f)
Definition UI.cpp:450
bool viewportActive(const std::string &id)
Definition UI.cpp:852
void setNavKeyboard(bool enabled)
Enables/disables keyboard navigation support.
Definition UI.cpp:778
void setItemMaxSize(float w, float h)
Definition UI.cpp:522
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:595
void setItemPadding(float l, float t, float r, float b)
Definition UI.cpp:506
void setItemFlexGrow(float grow)
Set flex item props on the most recently added child of the current open container....
Definition UI.cpp:484
void beginWindow(const std::string &title, const std::string &id="root")
Opens a window for the current build pass.
Definition UI.cpp:339
void end()
Closes the innermost open container.
Definition UI.cpp:405
bool remountBuildAs(const std::string &name)
Like mountBuildAs but reconciles by key when possible.
Definition UI.cpp:584
void sceneClose()
Closes the scene panel.
Definition UI.cpp:1271
void beginFlex(const std::string &direction="row", const std::string &id="", float gap=-1.f)
Begin a Flex container.
Definition UI.cpp:395
void addInputText(const std::string &label, const std::string &value, const std::string &id="")
Adds an editable text field.
Definition UI.cpp:476
bool editorOpen()
Opens the menu bar and docks the inspector + database panels.
Definition UI.cpp:1236
void addViewport(const std::string &id, float width=0.f, float height=0.f)
Definition UI.cpp:458
void addImageButton(const std::string &id, float width, float height)
Definition UI.cpp:454
std::string getStats() const
Definition UI.cpp:798
void beginGroup(const std::string &id="")
Opens a group container in the current build pass.
Definition UI.cpp:344
void onClick(const std::string &id, ssq::Function fn)
Definition UI.cpp:241
void beginCollapsing(const std::string &label, const std::string &id="", bool open=true)
Opens a collapsible header.
Definition UI.cpp:348
bool setTheme(const std::string &name)
Named preset: "dark" / "light" (case-insensitive). Returns false if unknown.
Definition UI.cpp:774
void setHostLayer(int layer)
Definition UI.cpp:705
void setThemeLight()
Definition UI.cpp:772
void setItemAbsolute(float anchorX, float anchorY, float x=0.f, float y=0.f)
Definition UI.cpp:536
UIHost * remountAs(const std::string &name, WidgetDesc root)
Creates/replaces a named host (does not select it).
Definition UI.cpp:322
void beginFrameAndRender()
Builds and presents the current frame's UI.
Definition UI.cpp:179
bool select(const std::string &name)
Selects a named host; false when it does not exist.
Definition UI.cpp:268
float getScale() const
Current UI scale factor.
Definition UI.cpp:794
void setItemMargin(float l, float t, float r, float b)
Definition UI.cpp:497
bool viewportHovered(const std::string &id)
Definition UI.cpp:846
float viewportWheel(const std::string &id)
Definition UI.cpp:882
void setScale(float scale)
Global UI scale factor (default 1).
Definition UI.cpp:786
void beginColumn(const std::string &id="", float gap=-1.f)
Opens a column flex container.
Definition UI.cpp:403
void setNavGamepad(bool enabled)
Definition UI.cpp:782
void setItemSize(float width, float height)
Sets width/height on the most recently added child.
Definition UI.cpp:490
void setHostModal(bool modal)
Marks the host as a modal (blocks other hosts) / overlay.
Definition UI.cpp:709
void addCheckbox(const std::string &label, bool checked, const std::string &id="")
Adds a checkbox.
Definition UI.cpp:437
bool inspectRefresh()
Re-scans script classes; true when any class is reflected.
Definition UI.cpp:1111
bool dbSelectClass(const std::string &name)
Selects the class shown in the grid.
Definition UI.cpp:1214
bool isBackendReady() const
True once the backend exists.
Definition UI.cpp:154
void beginBuild()
Imperative builder: open a new build pass (see beginWindow etc.).
Definition UI.cpp:326
bool dbRefresh()
Re-scans reflected classes; true when any class exists.
Definition UI.cpp:1208
void addSlider(const std::string &label, float value, float minV, float maxV, const std::string &id="")
Adds a slider.
Definition UI.cpp:441
void setFlexAlign(const std::string &align)
Set Flex container align/justify on the current open Flex (no-op otherwise).
Definition UI.cpp:546
void addProgress(float fraction, const std::string &id="", const std::string &overlay="")
Adds a progress bar.
Definition UI.cpp:446
bool getChecked(const std::string &id) const
Definition UI.cpp:695
uint64_t dbRegister(ssq::Object object, const std::string &label)
Registers a live script object in the database grid.
Definition UI.cpp:1220
bool sceneSelectNode(const std::string &id)
Selects a scene node by id.
Definition UI.cpp:1275
void setHostVisible(bool visible)
Host-level state.
Definition UI.cpp:701
graphics::Canvas * viewportCanvas(const std::string &id)
Definition UI.cpp:838
uint64_t dbCreateInstance()
Creates + registers an instance of the selected class.
Definition UI.cpp:1226
void setImageUv(const std::string &id, float u0, float v0, float u1, float v1)
Definition UI.cpp:646
void addTextWrapped(const std::string &content, float width, const std::string &id="")
Definition UI.cpp:421
void setText(const std::string &id, const std::string &text)
Widget state setters/getters on the current host (by node id).
Definition UI.cpp:611
void beginList(const std::string &id)
Opens a list container (rows added with addListItem).
Definition UI.cpp:346
void addSeparator(const std::string &id="")
Adds a separator line.
Definition UI.cpp:433
void beginChild(const std::string &id, float width=0.f, float height=120.f)
Opens a sized child region.
Definition UI.cpp:352
void setHostAnchor(float x, float y)
Definition UI.cpp:727
void setImageNinePatch(const std::string &id, float l, float t, float r, float b)
Definition UI.cpp:656
void addSameLine(const std::string &id="")
Adds an inline-break spacer.
Definition UI.cpp:431
void setImageTint(const std::string &id, float r, float g, float b, float a=1.f)
Definition UI.cpp:636
void setThemeDark()
Applies the dark/light built-in theme.
Definition UI.cpp:770
void onChange(const std::string &id, ssq::Function fn)
Definition UI.cpp:247
UIHost * mountAs(const std::string &name, WidgetDesc root)
Creates/replaces a named host from a WidgetDesc tree and selects it.
Definition UI.cpp:293
bool inspectObject(ssq::Object object)
Inspects a caller-provided live script instance.
Definition UI.cpp:1124
std::string consumeChange()
Returns the id of the changed widget since the last frame (or "").
Definition UI.cpp:768
bool dbUnregister(uint64_t id)
Removes an entry from the database grid.
Definition UI.cpp:1232
bool inspectAddInstance()
Creates another instance of the selected inspector class.
Definition UI.cpp:1194
void setItemMinSize(float w, float h)
Definition UI.cpp:515
void beginScrollList(const std::string &id="", float height=0.f, float itemHeight=0.f)
Definition UI.cpp:356
void animateHostPos(float x, float y, float durationMs)
Definition UI.cpp:749
void setHostOverlay(bool overlay)
Definition UI.cpp:713
void setValueText(const std::string &id, const std::string &value)
Definition UI.cpp:632
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:1095
void beginRow(const std::string &id="", float gap=-1.f)
Opens a row flex container.
Definition UI.cpp:401
bool wantCaptureMouse() const
True when the UI wants to capture mouse input this frame.
Definition UI.cpp:254
void addButton(const std::string &label, const std::string &id="")
Adds a button to the current container.
Definition UI.cpp:427
bool mountBuildAs(const std::string &name)
Finishes the build pass and mounts as a named host.
Definition UI.cpp:576
float viewportDragDY(const std::string &id)
Definition UI.cpp:876
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:1131
void setFlexJustify(const std::string &justify)
Sets Flex container justify on the current open Flex.
Definition UI.cpp:552
bool dbOpen()
Opens the database panel (class menu + editable instance grid).
Definition UI.cpp:1198
std::string getValueText(const std::string &id) const
Definition UI.cpp:689
void setValue(const std::string &id, float value)
Definition UI.cpp:628
void addListItem(const std::string &label, const std::string &id="")
Append one list row button (call inside beginList).
Definition UI.cpp:558
void inspectClose()
Closes the inspector panel.
Definition UI.cpp:1107
UIHost * remountReconcile(WidgetDesc root)
Remount with key reconcile (props-only when structure matches).
Definition UI.cpp:316
void setVisible(const std::string &id, bool visible)
Definition UI.cpp:620
std::string getTheme() const
Name of the active theme.
Definition UI.cpp:776
void dbClose()
Closes the database panel.
Definition UI.cpp:1204
void setChecked(const std::string &id, bool checked)
Definition UI.cpp:624
bool loadTreeJson(const std::string &json)
Definition UI.cpp:818
UIHost * remount(WidgetDesc root)
Replaces the selected host's tree.
Definition UI.cpp:310
float viewportMouseY(const std::string &id)
Definition UI.cpp:864
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:439
void registerEditorHostCapabilities()
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:291
WidgetDesc text(std::string content, std::string id)
Static text label.
Definition Widget.cpp:235
WidgetDesc scrollList(std::string id, std::vector< WidgetDesc > children, float height, float itemHeight)
Definition Widget.cpp:398
WidgetDesc progress(float fraction, std::string id, std::string overlay)
Progress bar; fraction is clamped to [0,1].
Definition Widget.cpp:305
FlexDirection
Main-axis direction for Flex containers.
Definition UIHost.h:36
WidgetDesc checkbox(std::string label, bool checked, std::string id, std::function< void(bool)> onToggle)
Checkbox with a label; fires onToggle.
Definition Widget.cpp:279
std::unique_ptr< UIBackend > createImGuiBackend()
Default backend: Dear ImGui + SDL + Vulkan (see ui/imgui/).
WidgetDesc separator(std::string id)
Horizontal separator line.
Definition Widget.cpp:271
bool setThemeByName(const std::string &name)
Apply a named preset ("dark" / "light"). Case-insensitive. Returns false if unknown.
Definition Theme.cpp:110
NodeType
Widget node kinds understood by the UI renderer.
Definition UIHost.h:13
WidgetDesc combo(std::string label, std::vector< std::string > options, int selected, std::string id, std::function< void(int)> onValue)
Definition Widget.cpp:315
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:363
WidgetDesc listButtons(std::string listId, const std::vector< std::string > &items)
Default list: one Button per item, id = listId + "/" + index.
Definition Widget.cpp:470
void setThemeUiScale(float scale)
Logical (point-space) UI scale. Default 1.0.
Definition Theme.cpp:123
FlexJustify
Main-axis distribution of free space in a Flex container.
Definition UIHost.h:42
WidgetDesc flex(FlexDirection direction, std::vector< WidgetDesc > children, std::string id)
Elastic layout container (row/column). Prefer row / column shorthands.
Definition Widget.cpp:421
WidgetDesc imageButton(std::string id, float width, float height, std::function< void()> onClick)
Definition Widget.cpp:342
WidgetDesc window(std::string title, std::vector< WidgetDesc > children, std::string id)
Top-level window widget with a title bar.
Definition Widget.cpp:225
WidgetDesc collapsingHeader(std::string label, std::vector< WidgetDesc > children, std::string id, bool defaultOpen)
Collapsible header containing child widgets.
Definition Widget.cpp:375
WidgetDesc sameLine(std::string id)
Holds the next widget on the same line as the previous one.
Definition Widget.cpp:263
WidgetDesc button(std::string label, std::string id, std::function< void()> onClick)
Clickable button; fires onClick.
Definition Widget.cpp:244
const std::string & globalThemeName()
Current preset name: "dark", "light", or "custom".
Definition Theme.cpp:101
FlexAlign
Cross-axis alignment of Flex children.
Definition UIHost.h:39
Theme & globalTheme()
Definition Theme.cpp:99
WidgetDesc viewport(std::string id, float width, float height)
Definition Widget.cpp:353
WidgetDesc child(std::string id, std::vector< WidgetDesc > children, float width, float height)
Scrollable child region with an explicit size.
Definition Widget.cpp:387
bool navEnableKeyboard
Definition Theme.h:70
bool navEnableGamepad
Definition Theme.h:71
std::string kind
Definition UISystem.h:22
std::string nodeId
Definition UISystem.h:21
std::string hostName
Definition UISystem.h:20
graphics::Canvas * canvas
Definition UISystem.h:57
Declarative widget description (build once / on dirty → flatten into UIHost::Tree).
Definition Widget.h:13
std::vector< WidgetDesc > children
Definition Widget.h:74