From 4a4cef570955e2bdf303829bf4ffe35f06ed9754 Mon Sep 17 00:00:00 2001 From: uramer Date: Sat, 11 Nov 2023 13:34:56 +0100 Subject: [PATCH] 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);