From f037dc814d5447efee884328d83398d56ee59260 Mon Sep 17 00:00:00 2001 From: uramer Date: Sat, 11 Nov 2023 11:35:58 +0100 Subject: [PATCH 01/13] Allow UI Elements in UI Content --- components/lua_ui/content.cpp | 3 +++ components/lua_ui/content.hpp | 2 +- components/lua_ui/content.lua | 22 ++++++++++++---------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/components/lua_ui/content.cpp b/components/lua_ui/content.cpp index 2e1d4ca0c4..dd169a9291 100644 --- a/components/lua_ui/content.cpp +++ b/components/lua_ui/content.cpp @@ -1,4 +1,5 @@ #include "content.hpp" +#include "element.hpp" namespace LuaUi { @@ -14,6 +15,8 @@ namespace LuaUi bool isValidContent(const sol::object& object) { + if (object.is()) + return true; if (object.get_type() != sol::type::table) return false; sol::table table = object; diff --git a/components/lua_ui/content.hpp b/components/lua_ui/content.hpp index c8bb82ecf3..945f833b48 100644 --- a/components/lua_ui/content.hpp +++ b/components/lua_ui/content.hpp @@ -22,7 +22,7 @@ namespace LuaUi : mTable(std::move(table)) { if (!isValidContent(mTable)) - throw std::domain_error("Expected a Content table"); + throw std::domain_error("Invalid UI Content"); } size_t size() const { return mTable.size(); } diff --git a/components/lua_ui/content.lua b/components/lua_ui/content.lua index fbd39d5f68..99fdb86b70 100644 --- a/components/lua_ui/content.lua +++ b/components/lua_ui/content.lua @@ -1,12 +1,17 @@ local M = {} M.__Content = true + +function validateContentChild(v) + if not (type(v) == 'table' or v.__type and v.__type.name == 'LuaUi::Element') then + error('Content can only contain tables and Elements') + end +end + M.new = function(source) local result = {} result.__nameIndex = {} for i, v in ipairs(source) do - if type(v) ~= 'table' then - error('Content can only contain tables') - end + validateContentChild(v) result[i] = v if type(v.name) == 'string' then result.__nameIndex[v.name] = i @@ -38,9 +43,7 @@ end local methods = { insert = function(self, index, value) validateIndex(self, index) - if type(value) ~= 'table' then - error('Content can only contain tables') - end + validateContentChild(value) for i = #self, index, -1 do rawset(self, i + 1, rawget(self, i)) local name = rawget(self, i + 1) @@ -56,7 +59,7 @@ local methods = { indexOf = function(self, value) if type(value) == 'string' then return self.__nameIndex[value] - elseif type(value) == 'table' then + else for i = 1, #self do if rawget(self, i) == value then return i @@ -113,10 +116,9 @@ M.__newindex = function(self, key, value) local index = getIndexFromKey(self, key) if value == nil then remove(self, index) - elseif type(value) == 'table' then - assign(self, index, value) else - error('Content can only contain tables') + validateContentChild(value) + assign(self, index, value) end end M.__tostring = function(self) From 4a4cef570955e2bdf303829bf4ffe35f06ed9754 Mon Sep 17 00:00:00 2001 From: uramer Date: Sat, 11 Nov 2023 13:34:56 +0100 Subject: [PATCH 02/13] Attach elements to each other, safely destroy --- components/lua_ui/adapter.cpp | 2 +- components/lua_ui/content.hpp | 8 ++-- components/lua_ui/element.cpp | 78 +++++++++++++++++++++++++++++------ components/lua_ui/widget.cpp | 4 +- components/lua_ui/widget.hpp | 5 ++- 5 files changed, 78 insertions(+), 19 deletions(-) diff --git a/components/lua_ui/adapter.cpp b/components/lua_ui/adapter.cpp index 2fd6365977..6db9420398 100644 --- a/components/lua_ui/adapter.cpp +++ b/components/lua_ui/adapter.cpp @@ -18,7 +18,7 @@ namespace LuaUi { mContainer = MyGUI::Gui::getInstancePtr()->createWidget( "", MyGUI::IntCoord(), MyGUI::Align::Default, "", ""); - mContainer->initialize(luaState, mContainer); + mContainer->initialize(luaState, mContainer, false); mContainer->onCoordChange([this](WidgetExtension* ext, MyGUI::IntCoord coord) { setSize(coord.size()); }); mContainer->widget()->attachToWidget(this); } diff --git a/components/lua_ui/content.hpp b/components/lua_ui/content.hpp index 945f833b48..1a0379b817 100644 --- a/components/lua_ui/content.hpp +++ b/components/lua_ui/content.hpp @@ -43,17 +43,17 @@ namespace LuaUi } void insert(size_t index, const sol::table& table) { callMethod("insert", toLua(index), table); } - sol::table at(size_t index) const + sol::object at(size_t index) const { if (index < size()) - return mTable.get(toLua(index)); + return mTable.get(toLua(index)); else throw std::range_error("Invalid Content index"); } - sol::table at(std::string_view name) const + sol::object at(std::string_view name) const { if (indexOf(name).has_value()) - return mTable.get(name); + return mTable.get(name); else throw std::range_error("Invalid Content key"); } diff --git a/components/lua_ui/element.cpp b/components/lua_ui/element.cpp index 4fe9349b9e..b15647b1c4 100644 --- a/components/lua_ui/element.cpp +++ b/components/lua_ui/element.cpp @@ -49,6 +49,36 @@ namespace LuaUi MyGUI::Gui::getInstancePtr()->destroyWidget(ext->widget()); } + void destroyChild(LuaUi::WidgetExtension* ext) + { + if (!ext->isRoot()) + destroyWidget(ext); + } + + void detachElements(LuaUi::WidgetExtension* ext) + { + for (auto* child : ext->children()) + { + if (child->isRoot()) + child->widget()->detachFromWidget(); + else + detachElements(child); + } + for (auto* child : ext->templateChildren()) + { + if (child->isRoot()) + child->widget()->detachFromWidget(); + else + detachElements(child); + } + } + + void destroyRoot(LuaUi::WidgetExtension* ext) + { + detachElements(ext); + destroyWidget(ext); + } + WidgetExtension* createWidget(const sol::table& layout, uint64_t depth); void updateWidget(WidgetExtension* ext, const sol::table& layout, uint64_t depth); @@ -60,7 +90,7 @@ namespace LuaUi if (contentObj == sol::nil) { for (WidgetExtension* w : children) - destroyWidget(w); + destroyChild(w); return result; } ContentView content(LuaUtil::cast(contentObj)); @@ -69,22 +99,46 @@ namespace LuaUi for (size_t i = 0; i < minSize; i++) { WidgetExtension* ext = children[i]; - sol::table newLayout = content.at(i); - if (ext->widget()->getTypeName() == widgetType(newLayout)) + sol::object child = content.at(i); + if (child.is()) { - updateWidget(ext, newLayout, depth); + std::shared_ptr element = child.as>(); + if (ext != element->mRoot) + destroyChild(ext); + result[i] = element->mRoot; + element->mRoot->updateCoord(); } else { - destroyWidget(ext); - ext = createWidget(newLayout, depth); + sol::table newLayout = child.as(); + if (ext->widget()->getTypeName() == widgetType(newLayout)) + { + updateWidget(ext, newLayout, depth); + } + else + { + destroyChild(ext); + ext = createWidget(newLayout, depth); + } + result[i] = ext; } - result[i] = ext; } for (size_t i = minSize; i < children.size(); i++) - destroyWidget(children[i]); + destroyChild(children[i]); for (size_t i = minSize; i < content.size(); i++) - result[i] = createWidget(content.at(i), depth); + { + sol::object child = content.at(i); + if (child.is()) + { + std::shared_ptr element = child.as>(); + result[i] = element->mRoot; + element->mRoot->updateCoord(); + } + else + { + result[i] = createWidget(child.as(), depth); + } + } return result; } @@ -130,7 +184,7 @@ namespace LuaUi WidgetExtension* ext = dynamic_cast(widget); if (!ext) throw std::runtime_error("Invalid widget!"); - ext->initialize(layout.lua_state(), widget); + ext->initialize(layout.lua_state(), widget, depth == 0); updateWidget(ext, layout, depth); return ext; @@ -201,7 +255,7 @@ namespace LuaUi { if (mRoot->widget()->getTypeName() != widgetType(layout())) { - destroyWidget(mRoot); + destroyRoot(mRoot); mRoot = createWidget(layout(), 0); } else @@ -218,7 +272,7 @@ namespace LuaUi { if (mRoot) { - destroyWidget(mRoot); + destroyRoot(mRoot); mRoot = nullptr; mLayout = sol::make_object(mLayout.lua_state(), sol::nil); } diff --git a/components/lua_ui/widget.cpp b/components/lua_ui/widget.cpp index e3188f6136..2e505ff9a8 100644 --- a/components/lua_ui/widget.cpp +++ b/components/lua_ui/widget.cpp @@ -18,13 +18,15 @@ namespace LuaUi , mExternal(sol::nil) , mParent(nullptr) , mTemplateChild(false) + , mElementRoot(false) { } - void WidgetExtension::initialize(lua_State* lua, MyGUI::Widget* self) + void WidgetExtension::initialize(lua_State* lua, MyGUI::Widget* self, bool isRoot) { mLua = lua; mWidget = self; + mElementRoot = isRoot; initialize(); updateTemplate(); } diff --git a/components/lua_ui/widget.hpp b/components/lua_ui/widget.hpp index 81698b0479..e5edd91113 100644 --- a/components/lua_ui/widget.hpp +++ b/components/lua_ui/widget.hpp @@ -26,13 +26,15 @@ namespace LuaUi virtual ~WidgetExtension() = default; // must be called after creating the underlying MyGUI::Widget - void initialize(lua_State* lua, MyGUI::Widget* self); + void initialize(lua_State* lua, MyGUI::Widget* self, bool isRoot); // must be called after before destroying the underlying MyGUI::Widget virtual void deinitialize(); MyGUI::Widget* widget() const { return mWidget; } WidgetExtension* slot() const { return mSlot; } + bool isRoot() const { return mElementRoot; } + void reset(); const std::vector& children() { return mChildren; } @@ -152,6 +154,7 @@ namespace LuaUi sol::object mExternal; WidgetExtension* mParent; bool mTemplateChild; + bool mElementRoot; void attach(WidgetExtension* ext); void attachTemplate(WidgetExtension* ext); From a36360cbde80084b86f489ca79c069ab910aae43 Mon Sep 17 00:00:00 2001 From: uramer Date: Sat, 11 Nov 2023 13:42:35 +0100 Subject: [PATCH 03/13] Update parent coords when updating element --- components/lua_ui/element.cpp | 10 ++++++++++ components/lua_ui/widget.hpp | 1 + 2 files changed, 11 insertions(+) diff --git a/components/lua_ui/element.cpp b/components/lua_ui/element.cpp index b15647b1c4..996ba67bb4 100644 --- a/components/lua_ui/element.cpp +++ b/components/lua_ui/element.cpp @@ -79,6 +79,14 @@ namespace LuaUi destroyWidget(ext); } + void updateRootCoord(LuaUi::WidgetExtension* ext) + { + LuaUi::WidgetExtension* root = ext; + while (root->getParent()) + root = root->getParent(); + root->updateCoord(); + } + WidgetExtension* createWidget(const sol::table& layout, uint64_t depth); void updateWidget(WidgetExtension* ext, const sol::table& layout, uint64_t depth); @@ -246,6 +254,7 @@ namespace LuaUi mRoot = createWidget(layout(), 0); mLayer = setLayer(mRoot, layout()); updateAttachment(); + updateRootCoord(mRoot); } } @@ -264,6 +273,7 @@ namespace LuaUi } mLayer = setLayer(mRoot, layout()); updateAttachment(); + updateRootCoord(mRoot); } mUpdate = false; } diff --git a/components/lua_ui/widget.hpp b/components/lua_ui/widget.hpp index e5edd91113..0902434e19 100644 --- a/components/lua_ui/widget.hpp +++ b/components/lua_ui/widget.hpp @@ -34,6 +34,7 @@ namespace LuaUi WidgetExtension* slot() const { return mSlot; } bool isRoot() const { return mElementRoot; } + WidgetExtension* getParent() const { return mParent; } void reset(); From 919e067ab7a6f2f07422cb23c916f63348c4af58 Mon Sep 17 00:00:00 2001 From: uramer Date: Sat, 11 Nov 2023 13:46:16 +0100 Subject: [PATCH 04/13] Error when encountering destroyed widgets --- components/lua_ui/element.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/lua_ui/element.cpp b/components/lua_ui/element.cpp index 996ba67bb4..dc8f2e6175 100644 --- a/components/lua_ui/element.cpp +++ b/components/lua_ui/element.cpp @@ -113,6 +113,8 @@ namespace LuaUi std::shared_ptr element = child.as>(); if (ext != element->mRoot) destroyChild(ext); + if (!element->mRoot) + throw std::logic_error("Using a destroyed element as a layout child"); result[i] = element->mRoot; element->mRoot->updateCoord(); } @@ -139,6 +141,8 @@ namespace LuaUi if (child.is()) { std::shared_ptr element = child.as>(); + if (!element->mRoot) + throw std::logic_error("Using a destroyed element as a layout child"); result[i] = element->mRoot; element->mRoot->updateCoord(); } From 4ba2aca3d38f381d221d703e7407604643cec619 Mon Sep 17 00:00:00 2001 From: uramer Date: Sat, 11 Nov 2023 13:51:22 +0100 Subject: [PATCH 05/13] Handle Element root changing type --- components/lua_ui/element.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/lua_ui/element.cpp b/components/lua_ui/element.cpp index dc8f2e6175..cc75a258d5 100644 --- a/components/lua_ui/element.cpp +++ b/components/lua_ui/element.cpp @@ -269,7 +269,12 @@ namespace LuaUi if (mRoot->widget()->getTypeName() != widgetType(layout())) { destroyRoot(mRoot); + WidgetExtension* parent = mRoot->getParent(); + auto children = parent->children(); + auto it = std::find(children.begin(), children.end(), mRoot); mRoot = createWidget(layout(), 0); + *it = mRoot; + parent->setChildren(children); } else { From cf84386cc27bdb24aafe3a4ab1b24b9450d4d915 Mon Sep 17 00:00:00 2001 From: uramer Date: Sat, 11 Nov 2023 14:07:36 +0100 Subject: [PATCH 06/13] Use Element Content children for Settings UI --- components/lua_ui/adapter.cpp | 14 +++++++++---- components/lua_ui/container.hpp | 1 + components/lua_ui/element.cpp | 35 ++------------------------------- components/lua_ui/element.hpp | 5 ----- 4 files changed, 13 insertions(+), 42 deletions(-) diff --git a/components/lua_ui/adapter.cpp b/components/lua_ui/adapter.cpp index 6db9420398..c9afd4db0d 100644 --- a/components/lua_ui/adapter.cpp +++ b/components/lua_ui/adapter.cpp @@ -44,14 +44,20 @@ namespace LuaUi void LuaAdapter::attachElement() { - if (mElement.get()) - mElement->attachToWidget(mContainer); + if (!mElement.get()) + return; + if (!mElement->mRoot) + throw std::logic_error("Attempting to use a destroyed UI Element"); + mContainer->setChildren({ mElement->mRoot }); + mElement->mRoot->updateCoord(); + mContainer->updateCoord(); } void LuaAdapter::detachElement() { - if (mElement.get()) - mElement->detachFromWidget(); + mContainer->setChildren({}); + if (mElement && mElement->mRoot) + mElement->mRoot->widget()->detachFromWidget(); mElement = nullptr; } } diff --git a/components/lua_ui/container.hpp b/components/lua_ui/container.hpp index 79d3cd8fa8..16f19d3c12 100644 --- a/components/lua_ui/container.hpp +++ b/components/lua_ui/container.hpp @@ -9,6 +9,7 @@ namespace LuaUi { MYGUI_RTTI_DERIVED(LuaContainer) + public: MyGUI::IntSize calculateSize() override; void updateCoord() override; diff --git a/components/lua_ui/element.cpp b/components/lua_ui/element.cpp index cc75a258d5..013e6fc85d 100644 --- a/components/lua_ui/element.cpp +++ b/components/lua_ui/element.cpp @@ -53,6 +53,8 @@ namespace LuaUi { if (!ext->isRoot()) destroyWidget(ext); + else + ext->widget()->detachFromWidget(); } void detachElements(LuaUi::WidgetExtension* ext) @@ -235,7 +237,6 @@ namespace LuaUi Element::Element(sol::table layout) : mRoot(nullptr) - , mAttachedTo(nullptr) , mLayout(std::move(layout)) , mLayer() , mUpdate(false) @@ -257,7 +258,6 @@ namespace LuaUi { mRoot = createWidget(layout(), 0); mLayer = setLayer(mRoot, layout()); - updateAttachment(); updateRootCoord(mRoot); } } @@ -281,7 +281,6 @@ namespace LuaUi updateWidget(mRoot, layout(), 0); } mLayer = setLayer(mRoot, layout()); - updateAttachment(); updateRootCoord(mRoot); } mUpdate = false; @@ -297,34 +296,4 @@ namespace LuaUi } sAllElements.erase(this); } - - void Element::attachToWidget(WidgetExtension* w) - { - if (mAttachedTo) - throw std::logic_error("A UI element can't be attached to two widgets at once"); - mAttachedTo = w; - updateAttachment(); - } - - void Element::detachFromWidget() - { - if (mRoot) - mRoot->widget()->detachFromWidget(); - if (mAttachedTo) - mAttachedTo->setChildren({}); - mAttachedTo = nullptr; - } - - void Element::updateAttachment() - { - if (!mRoot) - return; - if (mAttachedTo) - { - if (!mLayer.empty()) - Log(Debug::Warning) << "Ignoring element's layer " << mLayer << " because it's attached to a widget"; - mAttachedTo->setChildren({ mRoot }); - mAttachedTo->updateCoord(); - } - } } diff --git a/components/lua_ui/element.hpp b/components/lua_ui/element.hpp index b57af92fee..5aadb1beab 100644 --- a/components/lua_ui/element.hpp +++ b/components/lua_ui/element.hpp @@ -17,7 +17,6 @@ namespace LuaUi } WidgetExtension* mRoot; - WidgetExtension* mAttachedTo; sol::object mLayout; std::string mLayer; bool mUpdate; @@ -31,14 +30,10 @@ namespace LuaUi friend void clearUserInterface(); - void attachToWidget(WidgetExtension* w); - void detachFromWidget(); - private: Element(sol::table layout); sol::table layout() { return LuaUtil::cast(mLayout); } static std::map> sAllElements; - void updateAttachment(); }; } From 86ea12a45820cafb4a956c0eb8ff74ab4ed74007 Mon Sep 17 00:00:00 2001 From: uramer Date: Sat, 11 Nov 2023 14:44:17 +0100 Subject: [PATCH 07/13] Handle moving element into another element layout --- components/lua_ui/element.cpp | 36 +++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/components/lua_ui/element.cpp b/components/lua_ui/element.cpp index 013e6fc85d..ede87bc991 100644 --- a/components/lua_ui/element.cpp +++ b/components/lua_ui/element.cpp @@ -88,6 +88,23 @@ namespace LuaUi root = root->getParent(); root->updateCoord(); } + WidgetExtension* pluckElementRoot(const sol::object& child) + { + std::shared_ptr element = child.as>(); + WidgetExtension* root = element->mRoot; + if (!root) + throw std::logic_error("Using a destroyed element as a layout child"); + WidgetExtension* parent = root->getParent(); + if (parent) + { + auto children = parent->children(); + std::remove(children.begin(), children.end(), root); + parent->setChildren(children); + root->widget()->detachFromWidget(); + } + root->updateCoord(); + return root; + } WidgetExtension* createWidget(const sol::table& layout, uint64_t depth); void updateWidget(WidgetExtension* ext, const sol::table& layout, uint64_t depth); @@ -112,13 +129,10 @@ namespace LuaUi sol::object child = content.at(i); if (child.is()) { - std::shared_ptr element = child.as>(); - if (ext != element->mRoot) + WidgetExtension* root = pluckElementRoot(child); + if (ext != root) destroyChild(ext); - if (!element->mRoot) - throw std::logic_error("Using a destroyed element as a layout child"); - result[i] = element->mRoot; - element->mRoot->updateCoord(); + result[i] = root; } else { @@ -141,15 +155,8 @@ namespace LuaUi { sol::object child = content.at(i); if (child.is()) - { - std::shared_ptr element = child.as>(); - if (!element->mRoot) - throw std::logic_error("Using a destroyed element as a layout child"); - result[i] = element->mRoot; - element->mRoot->updateCoord(); - } + result[i] = pluckElementRoot(child); else - { result[i] = createWidget(child.as(), depth); } } @@ -275,6 +282,7 @@ namespace LuaUi mRoot = createWidget(layout(), 0); *it = mRoot; parent->setChildren(children); + mRoot->updateCoord(); } else { From f3a7b087ebc988590acf486de7a96ec0eafd7f18 Mon Sep 17 00:00:00 2001 From: uramer Date: Sat, 11 Nov 2023 14:44:37 +0100 Subject: [PATCH 08/13] Clean up unncesesary namespace prefixes --- components/lua_ui/element.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/components/lua_ui/element.cpp b/components/lua_ui/element.cpp index ede87bc991..71f2ba9c96 100644 --- a/components/lua_ui/element.cpp +++ b/components/lua_ui/element.cpp @@ -43,13 +43,13 @@ namespace LuaUi return type; } - void destroyWidget(LuaUi::WidgetExtension* ext) + void destroyWidget(WidgetExtension* ext) { ext->deinitialize(); MyGUI::Gui::getInstancePtr()->destroyWidget(ext->widget()); } - void destroyChild(LuaUi::WidgetExtension* ext) + void destroyChild(WidgetExtension* ext) { if (!ext->isRoot()) destroyWidget(ext); @@ -57,7 +57,7 @@ namespace LuaUi ext->widget()->detachFromWidget(); } - void detachElements(LuaUi::WidgetExtension* ext) + void detachElements(WidgetExtension* ext) { for (auto* child : ext->children()) { @@ -75,19 +75,20 @@ namespace LuaUi } } - void destroyRoot(LuaUi::WidgetExtension* ext) + void destroyRoot(WidgetExtension* ext) { detachElements(ext); destroyWidget(ext); } - void updateRootCoord(LuaUi::WidgetExtension* ext) + void updateRootCoord(WidgetExtension* ext) { - LuaUi::WidgetExtension* root = ext; + WidgetExtension* root = ext; while (root->getParent()) root = root->getParent(); root->updateCoord(); } + WidgetExtension* pluckElementRoot(const sol::object& child) { std::shared_ptr element = child.as>(); @@ -158,7 +159,6 @@ namespace LuaUi result[i] = pluckElementRoot(child); else result[i] = createWidget(child.as(), depth); - } } return result; } @@ -172,7 +172,7 @@ namespace LuaUi ext->setTemplateChildren(updateContent(ext->templateChildren(), content, depth)); } - void setEventCallbacks(LuaUi::WidgetExtension* ext, const sol::object& eventsObj) + void setEventCallbacks(WidgetExtension* ext, const sol::object& eventsObj) { ext->clearCallbacks(); if (eventsObj == sol::nil) From 416fa331f15f44174c76b74133990f75b89d0e6b Mon Sep 17 00:00:00 2001 From: uramer Date: Sat, 11 Nov 2023 15:38:04 +0100 Subject: [PATCH 09/13] Implement UI Element tostring --- apps/openmw/mwlua/uibindings.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwlua/uibindings.cpp b/apps/openmw/mwlua/uibindings.cpp index d42f7b0637..98a653949d 100644 --- a/apps/openmw/mwlua/uibindings.cpp +++ b/apps/openmw/mwlua/uibindings.cpp @@ -95,6 +95,13 @@ namespace MWLua MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager(); auto element = context.mLua->sol().new_usertype("Element"); + element[sol::meta_function::to_string] = [](const LuaUi::Element& element) { + std::stringstream res; + res << "UiElement"; + if (element.mLayer != "") + res << "[" << element.mLayer << "]"; + return res.str(); + }; element["layout"] = sol::property([](LuaUi::Element& element) { return element.mLayout; }, [](LuaUi::Element& element, const sol::table& layout) { element.mLayout = layout; }); element["update"] = [luaManager = context.mLuaManager](const std::shared_ptr& element) { From 39df270ff2a604853210ecd761e309aecc39823d Mon Sep 17 00:00:00 2001 From: uramer Date: Sat, 11 Nov 2023 16:00:56 +0100 Subject: [PATCH 10/13] Update UI Content docs --- files/lua_api/openmw/ui.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/files/lua_api/openmw/ui.lua b/files/lua_api/openmw/ui.lua index 2fefe4fd84..53ff57d276 100644 --- a/files/lua_api/openmw/ui.lua +++ b/files/lua_api/openmw/ui.lua @@ -164,9 +164,9 @@ --- -- Content. An array-like container, which allows to reference elements by their name. --- Implements [iterables#List](iterables.html#List) of #Layout and [iterables#Map](iterables.html#Map) of #string to #Layout. +-- Implements [iterables#List](iterables.html#List) of #Layout or #Element and [iterables#Map](iterables.html#Map) of #string to #Layout or #Element. -- @type Content --- @list <#Layout> +-- @list <#any> -- @usage -- local content = ui.content { -- { name = 'input' }, @@ -200,27 +200,27 @@ -- @function [parent=#Content] __index -- @param self -- @param #string name --- @return #Layout +-- @return #any --- -- Puts the layout at given index by shifting all the elements after it -- @function [parent=#Content] insert -- @param self -- @param #number index --- @param #Layout layout +-- @param #any layoutOrElement --- -- Adds the layout at the end of the Content -- (same as calling insert with `last index + 1`) -- @function [parent=#Content] add -- @param self --- @param #Layout layout +-- @param #any layoutOrElement --- -- Finds the index of the given layout. If it is not in the container, returns nil -- @function [parent=#Content] indexOf -- @param self --- @param #Layout layout +-- @param #any layoutOrElement -- @return #number, #nil index --- From d214f6f6ef2ceb726e029d0be3b9df9f1e1a808b Mon Sep 17 00:00:00 2001 From: uramer Date: Fri, 17 Nov 2023 18:02:34 +0100 Subject: [PATCH 11/13] Get rid of unncesesary onCoordChange --- components/lua_ui/adapter.cpp | 7 ++++++- components/lua_ui/adapter.hpp | 2 ++ components/lua_ui/widget.cpp | 4 ---- components/lua_ui/widget.hpp | 7 ------- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/components/lua_ui/adapter.cpp b/components/lua_ui/adapter.cpp index c9afd4db0d..44493f6f46 100644 --- a/components/lua_ui/adapter.cpp +++ b/components/lua_ui/adapter.cpp @@ -19,10 +19,15 @@ namespace LuaUi mContainer = MyGUI::Gui::getInstancePtr()->createWidget( "", MyGUI::IntCoord(), MyGUI::Align::Default, "", ""); mContainer->initialize(luaState, mContainer, false); - mContainer->onCoordChange([this](WidgetExtension* ext, MyGUI::IntCoord coord) { setSize(coord.size()); }); + mContainer->widget()->eventChangeCoord += MyGUI::newDelegate(this, &LuaAdapter::containerChangedCoord); mContainer->widget()->attachToWidget(this); } + void LuaAdapter::containerChangedCoord(MyGUI::Widget*) + { + setSize(mContainer->getSize()); + } + void LuaAdapter::attach(const std::shared_ptr& element) { detachElement(); diff --git a/components/lua_ui/adapter.hpp b/components/lua_ui/adapter.hpp index d699e4992f..1524a55425 100644 --- a/components/lua_ui/adapter.hpp +++ b/components/lua_ui/adapter.hpp @@ -25,6 +25,8 @@ namespace LuaUi void attachElement(); void detachElement(); + + void containerChangedCoord(MyGUI::Widget*); }; } diff --git a/components/lua_ui/widget.cpp b/components/lua_ui/widget.cpp index 2e505ff9a8..855ba29b3c 100644 --- a/components/lua_ui/widget.cpp +++ b/components/lua_ui/widget.cpp @@ -42,8 +42,6 @@ namespace LuaUi clearCallbacks(); clearEvents(mWidget); - mOnCoordChange.reset(); - for (WidgetExtension* w : mChildren) w->deinitialize(); for (WidgetExtension* w : mTemplateChildren) @@ -264,8 +262,6 @@ namespace LuaUi if (oldCoord != newCoord) mWidget->setCoord(newCoord); updateChildrenCoord(); - if (oldCoord != newCoord && mOnCoordChange.has_value()) - mOnCoordChange.value()(this, newCoord); } void WidgetExtension::setProperties(const sol::object& props) diff --git a/components/lua_ui/widget.hpp b/components/lua_ui/widget.hpp index 0902434e19..1cda09b41b 100644 --- a/components/lua_ui/widget.hpp +++ b/components/lua_ui/widget.hpp @@ -69,11 +69,6 @@ namespace LuaUi return parseExternal(mExternal, name, defaultValue); } - void onCoordChange(const std::optional>& callback) - { - mOnCoordChange = callback; - } - virtual MyGUI::IntSize calculateSize(); virtual MyGUI::IntPoint calculatePosition(const MyGUI::IntSize& size); MyGUI::IntCoord calculateCoord(); @@ -176,8 +171,6 @@ namespace LuaUi void focusGain(MyGUI::Widget*, MyGUI::Widget*); void focusLoss(MyGUI::Widget*, MyGUI::Widget*); - std::optional> mOnCoordChange; - void updateVisible(); }; From 9403f06618ff583ae7663fc3da2627fa8970cca1 Mon Sep 17 00:00:00 2001 From: uramer Date: Fri, 17 Nov 2023 18:15:07 +0100 Subject: [PATCH 12/13] Fix visibility breaking after multiple updates --- components/lua_ui/widget.cpp | 11 ++++++----- components/lua_ui/widget.hpp | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/components/lua_ui/widget.cpp b/components/lua_ui/widget.cpp index 855ba29b3c..9550c9de73 100644 --- a/components/lua_ui/widget.cpp +++ b/components/lua_ui/widget.cpp @@ -9,6 +9,7 @@ namespace LuaUi : mForcePosition(false) , mForceSize(false) , mPropagateEvents(true) + , mVisible(true) , mLua(nullptr) , mWidget(nullptr) , mSlot(this) @@ -92,10 +93,9 @@ namespace LuaUi { // workaround for MyGUI bug // parent visibility doesn't affect added children - MyGUI::Widget* widget = this->widget(); - MyGUI::Widget* parent = widget->getParent(); - bool inheritedVisible = widget->getVisible() && (parent == nullptr || parent->getInheritedVisible()); - widget->setVisible(inheritedVisible); + MyGUI::Widget* parent = widget()->getParent(); + bool inheritedVisible = mVisible && (parent == nullptr || parent->getInheritedVisible()); + widget()->setVisible(inheritedVisible); } void WidgetExtension::attach(WidgetExtension* ext) @@ -278,7 +278,8 @@ namespace LuaUi mRelativeCoord = propertyValue("relativePosition", MyGUI::FloatPoint()); mRelativeCoord = propertyValue("relativeSize", MyGUI::FloatSize()); mAnchor = propertyValue("anchor", MyGUI::FloatSize()); - mWidget->setVisible(propertyValue("visible", true)); + mVisible = propertyValue("visible", true); + mWidget->setVisible(mVisible); mWidget->setPointer(propertyValue("pointer", std::string("arrow"))); mWidget->setAlpha(propertyValue("alpha", 1.f)); mWidget->setInheritsAlpha(propertyValue("inheritAlpha", true)); diff --git a/components/lua_ui/widget.hpp b/components/lua_ui/widget.hpp index 1cda09b41b..c72b64ae3b 100644 --- a/components/lua_ui/widget.hpp +++ b/components/lua_ui/widget.hpp @@ -135,6 +135,7 @@ namespace LuaUi MyGUI::FloatSize mAnchor; bool mPropagateEvents; + bool mVisible; // used to implement updateVisible private: // use lua_State* instead of sol::state_view because MyGUI requires a default constructor From 2be3824d9ed3942c8229c6617b1ce53a5fc93c56 Mon Sep 17 00:00:00 2001 From: uramer Date: Fri, 24 Nov 2023 20:41:54 +0100 Subject: [PATCH 13/13] Clarify child element update behavior in the documentation --- files/lua_api/openmw/ui.lua | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/files/lua_api/openmw/ui.lua b/files/lua_api/openmw/ui.lua index 53ff57d276..451f919077 100644 --- a/files/lua_api/openmw/ui.lua +++ b/files/lua_api/openmw/ui.lua @@ -228,10 +228,35 @@ -- @type Element --- --- Refreshes the rendered element to match the current layout state +-- Refreshes the rendered element to match the current layout state. +-- Refreshes positions and sizes, but not the layout of the child Elements. -- @function [parent=#Element] update -- @param self +-- @usage +-- local child = ui.create { +-- type = ui.TYPE.Text, +-- props = { +-- text = 'child 1', +-- }, +-- } +-- local parent = ui.create { +-- content = ui.content { +-- child, +-- { +-- type = ui.TYPE.Text, +-- props = { +-- text = 'parent 1', +-- }, +-- } +-- } +-- } +-- -- ... +-- child.layout.props.text = 'child 2' +-- parent.layout.content[2].props.text = 'parent 2' +-- parent:update() -- will show 'parent 2', but 'child 1' + + --- -- Destroys the element -- @function [parent=#Element] destroy