From 8cbcb82dd4eca46d7cdd4b82305b0f7c5010b534 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 28 Mar 2024 20:01:50 +0100 Subject: [PATCH] Prevent iterator invalidation when updating Lua UI and increase const correctness --- components/lua_ui/container.cpp | 10 +++++----- components/lua_ui/container.hpp | 6 +++--- components/lua_ui/element.cpp | 26 ++++++++++--------------- components/lua_ui/flex.cpp | 4 ++-- components/lua_ui/flex.hpp | 24 +++++++++++++++++------ components/lua_ui/text.cpp | 2 +- components/lua_ui/text.hpp | 2 +- components/lua_ui/textedit.cpp | 2 +- components/lua_ui/textedit.hpp | 2 +- components/lua_ui/widget.cpp | 25 +++++++++++++----------- components/lua_ui/widget.hpp | 34 ++++++++++++++++++++++++--------- 11 files changed, 81 insertions(+), 56 deletions(-) diff --git a/components/lua_ui/container.cpp b/components/lua_ui/container.cpp index 52fea684d7..1999be8169 100644 --- a/components/lua_ui/container.cpp +++ b/components/lua_ui/container.cpp @@ -10,12 +10,12 @@ namespace LuaUi updateSizeToFit(); } - MyGUI::IntSize LuaContainer::childScalingSize() + MyGUI::IntSize LuaContainer::childScalingSize() const { return MyGUI::IntSize(); } - MyGUI::IntSize LuaContainer::templateScalingSize() + MyGUI::IntSize LuaContainer::templateScalingSize() const { return mInnerSize; } @@ -23,14 +23,14 @@ namespace LuaUi void LuaContainer::updateSizeToFit() { MyGUI::IntSize innerSize = MyGUI::IntSize(); - for (auto w : children()) + for (const auto w : children()) { MyGUI::IntCoord coord = w->calculateCoord(); innerSize.width = std::max(innerSize.width, coord.left + coord.width); innerSize.height = std::max(innerSize.height, coord.top + coord.height); } MyGUI::IntSize outerSize = innerSize; - for (auto w : templateChildren()) + for (const auto w : templateChildren()) { MyGUI::IntCoord coord = w->calculateCoord(); outerSize.width = std::max(outerSize.width, coord.left + coord.width); @@ -40,7 +40,7 @@ namespace LuaUi mOuterSize = outerSize; } - MyGUI::IntSize LuaContainer::calculateSize() + MyGUI::IntSize LuaContainer::calculateSize() const { return mOuterSize; } diff --git a/components/lua_ui/container.hpp b/components/lua_ui/container.hpp index 16f19d3c12..ef13dd0638 100644 --- a/components/lua_ui/container.hpp +++ b/components/lua_ui/container.hpp @@ -10,13 +10,13 @@ namespace LuaUi MYGUI_RTTI_DERIVED(LuaContainer) public: - MyGUI::IntSize calculateSize() override; + MyGUI::IntSize calculateSize() const override; void updateCoord() override; protected: void updateChildren() override; - MyGUI::IntSize childScalingSize() override; - MyGUI::IntSize templateScalingSize() override; + MyGUI::IntSize childScalingSize() const override; + MyGUI::IntSize templateScalingSize() const override; private: void updateSizeToFit(); diff --git a/components/lua_ui/element.cpp b/components/lua_ui/element.cpp index ffd763b40b..ceaa746f15 100644 --- a/components/lua_ui/element.cpp +++ b/components/lua_ui/element.cpp @@ -54,25 +54,19 @@ namespace LuaUi if (!ext->isRoot()) destroyWidget(ext); else - ext->detachFromParent(); + ext->detachFromParent(false); } void detachElements(WidgetExtension* ext) { - for (auto* child : ext->children()) - { + auto predicate = [](WidgetExtension* child) { if (child->isRoot()) - child->detachFromParent(); - else - detachElements(child); - } - for (auto* child : ext->templateChildren()) - { - if (child->isRoot()) - child->detachFromParent(); - else - detachElements(child); - } + return true; + detachElements(child); + return false; + }; + ext->detachChildrenIf(predicate); + ext->detachTemplateChildrenIf(predicate); } void destroyRoot(WidgetExtension* ext) @@ -194,8 +188,8 @@ namespace LuaUi throw std::logic_error(std::string("Invalid widget type ") += type); std::string name = layout.get_or(LayoutKeys::name, std::string()); - MyGUI::Widget* widget = MyGUI::Gui::getInstancePtr()->createWidgetT( - type, "", MyGUI::IntCoord(), MyGUI::Align::Default, std::string(), name); + MyGUI::Widget* widget + = MyGUI::Gui::getInstancePtr()->createWidgetT(type, {}, {}, MyGUI::Align::Default, {}, name); WidgetExtension* ext = dynamic_cast(widget); if (!ext) diff --git a/components/lua_ui/flex.cpp b/components/lua_ui/flex.cpp index c55b48ddb7..1a3293d406 100644 --- a/components/lua_ui/flex.cpp +++ b/components/lua_ui/flex.cpp @@ -79,7 +79,7 @@ namespace LuaUi WidgetExtension::updateChildren(); } - MyGUI::IntSize LuaFlex::childScalingSize() + MyGUI::IntSize LuaFlex::childScalingSize() const { // Call the base method to prevent relativeSize feedback loop MyGUI::IntSize size = WidgetExtension::calculateSize(); @@ -88,7 +88,7 @@ namespace LuaUi return size; } - MyGUI::IntSize LuaFlex::calculateSize() + MyGUI::IntSize LuaFlex::calculateSize() const { MyGUI::IntSize size = WidgetExtension::calculateSize(); if (mAutoSized) diff --git a/components/lua_ui/flex.hpp b/components/lua_ui/flex.hpp index 944daaec77..c91ffd00a2 100644 --- a/components/lua_ui/flex.hpp +++ b/components/lua_ui/flex.hpp @@ -11,10 +11,10 @@ namespace LuaUi MYGUI_RTTI_DERIVED(LuaFlex) protected: - MyGUI::IntSize calculateSize() override; + MyGUI::IntSize calculateSize() const override; void updateProperties() override; void updateChildren() override; - MyGUI::IntSize childScalingSize() override; + MyGUI::IntSize childScalingSize() const override; void updateCoord() override; @@ -26,25 +26,37 @@ namespace LuaUi Alignment mArrange; template - T& primary(MyGUI::types::TPoint& point) + T& primary(MyGUI::types::TPoint& point) const { return mHorizontal ? point.left : point.top; } template - T& secondary(MyGUI::types::TPoint& point) + T& secondary(MyGUI::types::TPoint& point) const { return mHorizontal ? point.top : point.left; } template - T& primary(MyGUI::types::TSize& size) + T& primary(MyGUI::types::TSize& size) const { return mHorizontal ? size.width : size.height; } template - T& secondary(MyGUI::types::TSize& size) + T& secondary(MyGUI::types::TSize& size) const + { + return mHorizontal ? size.height : size.width; + } + + template + T primary(const MyGUI::types::TSize& size) const + { + return mHorizontal ? size.width : size.height; + } + + template + T secondary(const MyGUI::types::TSize& size) const { return mHorizontal ? size.height : size.width; } diff --git a/components/lua_ui/text.cpp b/components/lua_ui/text.cpp index e55f1750b9..35aa9402bf 100644 --- a/components/lua_ui/text.cpp +++ b/components/lua_ui/text.cpp @@ -46,7 +46,7 @@ namespace LuaUi updateCoord(); } - MyGUI::IntSize LuaText::calculateSize() + MyGUI::IntSize LuaText::calculateSize() const { if (mAutoSized) return getTextSize(); diff --git a/components/lua_ui/text.hpp b/components/lua_ui/text.hpp index fffe34a3ba..87c01a37e8 100644 --- a/components/lua_ui/text.hpp +++ b/components/lua_ui/text.hpp @@ -21,7 +21,7 @@ namespace LuaUi bool mAutoSized; protected: - MyGUI::IntSize calculateSize() override; + MyGUI::IntSize calculateSize() const override; }; } diff --git a/components/lua_ui/textedit.cpp b/components/lua_ui/textedit.cpp index e12bd20c35..9bd241884a 100644 --- a/components/lua_ui/textedit.cpp +++ b/components/lua_ui/textedit.cpp @@ -63,7 +63,7 @@ namespace LuaUi mEditBox->attachToWidget(this); } - MyGUI::IntSize LuaTextEdit::calculateSize() + MyGUI::IntSize LuaTextEdit::calculateSize() const { MyGUI::IntSize normalSize = WidgetExtension::calculateSize(); if (mAutoSize) diff --git a/components/lua_ui/textedit.hpp b/components/lua_ui/textedit.hpp index 8f23b51746..57e1209aff 100644 --- a/components/lua_ui/textedit.hpp +++ b/components/lua_ui/textedit.hpp @@ -20,7 +20,7 @@ namespace LuaUi void updateProperties() override; void updateCoord() override; void updateChildren() override; - MyGUI::IntSize calculateSize() override; + MyGUI::IntSize calculateSize() const override; private: void textChange(MyGUI::EditBox*); diff --git a/components/lua_ui/widget.cpp b/components/lua_ui/widget.cpp index e61c36c452..3804e70096 100644 --- a/components/lua_ui/widget.cpp +++ b/components/lua_ui/widget.cpp @@ -101,7 +101,7 @@ namespace LuaUi void WidgetExtension::attach(WidgetExtension* ext) { if (ext->mParent != this) - ext->detachFromParent(); + ext->detachFromParent(true); ext->mParent = this; ext->mTemplateChild = false; ext->widget()->attachToWidget(mSlot->widget()); @@ -114,13 +114,16 @@ namespace LuaUi ext->widget()->attachToWidget(widget()); } - void WidgetExtension::detachFromParent() + void WidgetExtension::detachFromParent(bool updateParent) { if (mParent) { - auto children = mParent->children(); - std::erase(children, this); - mParent->setChildren(children); + if (updateParent) + { + auto children = mParent->children(); + std::erase(children, this); + mParent->setChildren(children); + } mParent = nullptr; } widget()->detachFromWidget(); @@ -307,7 +310,7 @@ namespace LuaUi w->updateCoord(); } - MyGUI::IntSize WidgetExtension::parentSize() + MyGUI::IntSize WidgetExtension::parentSize() const { if (!mParent) return widget()->getParentSize(); // size of the layer @@ -317,7 +320,7 @@ namespace LuaUi return mParent->childScalingSize(); } - MyGUI::IntSize WidgetExtension::calculateSize() + MyGUI::IntSize WidgetExtension::calculateSize() const { if (mForceSize) return mForcedCoord.size(); @@ -330,7 +333,7 @@ namespace LuaUi return newSize; } - MyGUI::IntPoint WidgetExtension::calculatePosition(const MyGUI::IntSize& size) + MyGUI::IntPoint WidgetExtension::calculatePosition(const MyGUI::IntSize& size) const { if (mForcePosition) return mForcedCoord.point(); @@ -342,7 +345,7 @@ namespace LuaUi return newPosition; } - MyGUI::IntCoord WidgetExtension::calculateCoord() + MyGUI::IntCoord WidgetExtension::calculateCoord() const { MyGUI::IntCoord newCoord; newCoord = calculateSize(); @@ -350,12 +353,12 @@ namespace LuaUi return newCoord; } - MyGUI::IntSize WidgetExtension::childScalingSize() + MyGUI::IntSize WidgetExtension::childScalingSize() const { return mSlot->widget()->getSize(); } - MyGUI::IntSize WidgetExtension::templateScalingSize() + MyGUI::IntSize WidgetExtension::templateScalingSize() const { return widget()->getSize(); } diff --git a/components/lua_ui/widget.hpp b/components/lua_ui/widget.hpp index 05359705a1..59ac997688 100644 --- a/components/lua_ui/widget.hpp +++ b/components/lua_ui/widget.hpp @@ -31,11 +31,13 @@ namespace LuaUi virtual void deinitialize(); MyGUI::Widget* widget() const { return mWidget; } - WidgetExtension* slot() const { return mSlot; } bool isRoot() const { return mElementRoot; } WidgetExtension* getParent() const { return mParent; } - void detachFromParent(); + void detachFromParent(bool updateParent); + + void detachChildrenIf(auto&& predicate) { detachChildrenIf(predicate, mChildren); } + void detachTemplateChildrenIf(auto&& predicate) { detachChildrenIf(predicate, mTemplateChildren); } void reset(); @@ -65,14 +67,14 @@ namespace LuaUi void setLayout(const sol::table& layout) { mLayout = layout; } template - T externalValue(std::string_view name, const T& defaultValue) + T externalValue(std::string_view name, const T& defaultValue) const { return parseExternal(mExternal, name, defaultValue); } - virtual MyGUI::IntSize calculateSize(); - virtual MyGUI::IntPoint calculatePosition(const MyGUI::IntSize& size); - MyGUI::IntCoord calculateCoord(); + virtual MyGUI::IntSize calculateSize() const; + virtual MyGUI::IntPoint calculatePosition(const MyGUI::IntSize& size) const; + MyGUI::IntCoord calculateCoord() const; virtual bool isTextInput() { return false; } @@ -85,9 +87,9 @@ namespace LuaUi sol::object keyEvent(MyGUI::KeyCode) const; sol::object mouseEvent(int left, int top, MyGUI::MouseButton button) const; - MyGUI::IntSize parentSize(); - virtual MyGUI::IntSize childScalingSize(); - virtual MyGUI::IntSize templateScalingSize(); + MyGUI::IntSize parentSize() const; + virtual MyGUI::IntSize childScalingSize() const; + virtual MyGUI::IntSize templateScalingSize() const; template T propertyValue(std::string_view name, const T& defaultValue) @@ -176,6 +178,20 @@ namespace LuaUi void focusLoss(MyGUI::Widget*, MyGUI::Widget*); void updateVisible(); + + void detachChildrenIf(auto&& predicate, std::vector children) + { + for (auto it = children.begin(); it != children.end();) + { + if (predicate(*it)) + { + (*it)->detachFromParent(false); + it = children.erase(it); + } + else + ++it; + } + } }; class LuaWidget : public MyGUI::Widget, public WidgetExtension