mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-04 01:26:39 +00:00 
			
		
		
		
	Fix child UI Elements created in the same frame as parent
This commit is contained in:
		
							parent
							
								
									7a5493796f
								
							
						
					
					
						commit
						9ae61f1932
					
				
					 3 changed files with 45 additions and 28 deletions
				
			
		| 
						 | 
				
			
			@ -134,7 +134,10 @@ namespace MWLua
 | 
			
		|||
        };
 | 
			
		||||
 | 
			
		||||
        api["updateAll"] = [luaManager = context.mLuaManager, menu]() {
 | 
			
		||||
            LuaUi::Element::forEach(menu, [](LuaUi::Element* e) { e->mUpdate = true; });
 | 
			
		||||
            LuaUi::Element::forEach(menu, [](LuaUi::Element* e) {
 | 
			
		||||
                if (e->mState == LuaUi::Element::Created)
 | 
			
		||||
                    e->mState = LuaUi::Element::Update;
 | 
			
		||||
            });
 | 
			
		||||
            luaManager->addAction([menu]() { LuaUi::Element::forEach(menu, [](LuaUi::Element* e) { e->update(); }); },
 | 
			
		||||
                "Update all menu UI elements");
 | 
			
		||||
        };
 | 
			
		||||
| 
						 | 
				
			
			@ -305,15 +308,15 @@ namespace MWLua
 | 
			
		|||
        element["layout"] = sol::property([](const 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<LuaUi::Element>& element) {
 | 
			
		||||
            if (element->mDestroy || element->mUpdate)
 | 
			
		||||
            if (element->mState != LuaUi::Element::Created)
 | 
			
		||||
                return;
 | 
			
		||||
            element->mUpdate = true;
 | 
			
		||||
            element->mState = LuaUi::Element::Update;
 | 
			
		||||
            luaManager->addAction([element] { wrapAction(element, [&] { element->update(); }); }, "Update UI");
 | 
			
		||||
        };
 | 
			
		||||
        element["destroy"] = [luaManager = context.mLuaManager](const std::shared_ptr<LuaUi::Element>& element) {
 | 
			
		||||
            if (element->mDestroy)
 | 
			
		||||
            if (element->mState == LuaUi::Element::Destroyed)
 | 
			
		||||
                return;
 | 
			
		||||
            element->mDestroy = true;
 | 
			
		||||
            element->mState = LuaUi::Element::Destroy;
 | 
			
		||||
            luaManager->addAction(
 | 
			
		||||
                [element] { wrapAction(element, [&] { LuaUi::Element::erase(element.get()); }); }, "Destroy UI");
 | 
			
		||||
        };
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -89,12 +89,16 @@ namespace LuaUi
 | 
			
		|||
            root->updateCoord();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        WidgetExtension* pluckElementRoot(const sol::object& child)
 | 
			
		||||
        WidgetExtension* pluckElementRoot(const sol::object& child, uint64_t depth)
 | 
			
		||||
        {
 | 
			
		||||
            std::shared_ptr<Element> element = child.as<std::shared_ptr<Element>>();
 | 
			
		||||
            WidgetExtension* root = element->mRoot;
 | 
			
		||||
            if (!root)
 | 
			
		||||
            if (element->mState == Element::Destroyed || element->mState == Element::Destroy)
 | 
			
		||||
                throw std::logic_error("Using a destroyed element as a layout child");
 | 
			
		||||
            // child Element was created in the same frame and its action hasn't been processed yet
 | 
			
		||||
            if (element->mState == Element::New)
 | 
			
		||||
                element->create(depth + 1);
 | 
			
		||||
            WidgetExtension* root = element->mRoot;
 | 
			
		||||
            assert(root);
 | 
			
		||||
            WidgetExtension* parent = root->getParent();
 | 
			
		||||
            if (parent)
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -107,7 +111,7 @@ namespace LuaUi
 | 
			
		|||
            return root;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        WidgetExtension* createWidget(const sol::table& layout, uint64_t depth);
 | 
			
		||||
        WidgetExtension* createWidget(const sol::table& layout, bool isRoot, uint64_t depth);
 | 
			
		||||
        void updateWidget(WidgetExtension* ext, const sol::table& layout, uint64_t depth);
 | 
			
		||||
 | 
			
		||||
        std::vector<WidgetExtension*> updateContent(
 | 
			
		||||
| 
						 | 
				
			
			@ -130,7 +134,7 @@ namespace LuaUi
 | 
			
		|||
                sol::object child = content.at(i);
 | 
			
		||||
                if (child.is<Element>())
 | 
			
		||||
                {
 | 
			
		||||
                    WidgetExtension* root = pluckElementRoot(child);
 | 
			
		||||
                    WidgetExtension* root = pluckElementRoot(child, depth);
 | 
			
		||||
                    if (ext != root)
 | 
			
		||||
                        destroyChild(ext);
 | 
			
		||||
                    result[i] = root;
 | 
			
		||||
| 
						 | 
				
			
			@ -145,7 +149,7 @@ namespace LuaUi
 | 
			
		|||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        destroyChild(ext);
 | 
			
		||||
                        ext = createWidget(newLayout, depth);
 | 
			
		||||
                        ext = createWidget(newLayout, false, depth);
 | 
			
		||||
                    }
 | 
			
		||||
                    result[i] = ext;
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -156,9 +160,9 @@ namespace LuaUi
 | 
			
		|||
            {
 | 
			
		||||
                sol::object child = content.at(i);
 | 
			
		||||
                if (child.is<Element>())
 | 
			
		||||
                    result[i] = pluckElementRoot(child);
 | 
			
		||||
                    result[i] = pluckElementRoot(child, depth);
 | 
			
		||||
                else
 | 
			
		||||
                    result[i] = createWidget(child.as<sol::table>(), depth);
 | 
			
		||||
                    result[i] = createWidget(child.as<sol::table>(), false, depth);
 | 
			
		||||
            }
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -191,7 +195,7 @@ namespace LuaUi
 | 
			
		|||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        WidgetExtension* createWidget(const sol::table& layout, uint64_t depth)
 | 
			
		||||
        WidgetExtension* createWidget(const sol::table& layout, bool isRoot, uint64_t depth)
 | 
			
		||||
        {
 | 
			
		||||
            static auto widgetTypeMap = widgetTypeToName();
 | 
			
		||||
            std::string type = widgetType(layout);
 | 
			
		||||
| 
						 | 
				
			
			@ -205,7 +209,7 @@ namespace LuaUi
 | 
			
		|||
            WidgetExtension* ext = dynamic_cast<WidgetExtension*>(widget);
 | 
			
		||||
            if (!ext)
 | 
			
		||||
                throw std::runtime_error("Invalid widget!");
 | 
			
		||||
            ext->initialize(layout.lua_state(), widget, depth == 0);
 | 
			
		||||
            ext->initialize(layout.lua_state(), widget, isRoot);
 | 
			
		||||
 | 
			
		||||
            updateWidget(ext, layout, depth);
 | 
			
		||||
            return ext;
 | 
			
		||||
| 
						 | 
				
			
			@ -247,8 +251,7 @@ namespace LuaUi
 | 
			
		|||
        : mRoot(nullptr)
 | 
			
		||||
        , mLayout(std::move(layout))
 | 
			
		||||
        , mLayer()
 | 
			
		||||
        , mUpdate(false)
 | 
			
		||||
        , mDestroy(false)
 | 
			
		||||
        , mState(Element::New)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -267,12 +270,12 @@ namespace LuaUi
 | 
			
		|||
        sGameElements.erase(element);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Element::create()
 | 
			
		||||
    void Element::create(uint64_t depth)
 | 
			
		||||
    {
 | 
			
		||||
        assert(!mRoot);
 | 
			
		||||
        if (!mRoot)
 | 
			
		||||
        if (mState == New)
 | 
			
		||||
        {
 | 
			
		||||
            mRoot = createWidget(layout(), 0);
 | 
			
		||||
            mRoot = createWidget(layout(), true, depth);
 | 
			
		||||
            mLayer = setLayer(mRoot, layout());
 | 
			
		||||
            updateRootCoord(mRoot);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -280,15 +283,16 @@ namespace LuaUi
 | 
			
		|||
 | 
			
		||||
    void Element::update()
 | 
			
		||||
    {
 | 
			
		||||
        if (mRoot && mUpdate)
 | 
			
		||||
        if (mState == Update)
 | 
			
		||||
        {
 | 
			
		||||
            assert(mRoot);
 | 
			
		||||
            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);
 | 
			
		||||
                mRoot = createWidget(layout(), true, 0);
 | 
			
		||||
                assert(it != children.end());
 | 
			
		||||
                *it = mRoot;
 | 
			
		||||
                parent->setChildren(children);
 | 
			
		||||
| 
						 | 
				
			
			@ -301,16 +305,18 @@ namespace LuaUi
 | 
			
		|||
            mLayer = setLayer(mRoot, layout());
 | 
			
		||||
            updateRootCoord(mRoot);
 | 
			
		||||
        }
 | 
			
		||||
        mUpdate = false;
 | 
			
		||||
        mState = Created;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Element::destroy()
 | 
			
		||||
    {
 | 
			
		||||
        if (mRoot)
 | 
			
		||||
        if (mState != Destroyed)
 | 
			
		||||
        {
 | 
			
		||||
            destroyRoot(mRoot);
 | 
			
		||||
            mRoot = nullptr;
 | 
			
		||||
            mLayout = sol::make_object(mLayout.lua_state(), sol::nil);
 | 
			
		||||
            if (mState != New)
 | 
			
		||||
                mLayout = sol::make_object(mLayout.lua_state(), sol::nil);
 | 
			
		||||
            mState = Destroyed;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,10 +21,18 @@ namespace LuaUi
 | 
			
		|||
        WidgetExtension* mRoot;
 | 
			
		||||
        sol::object mLayout;
 | 
			
		||||
        std::string mLayer;
 | 
			
		||||
        bool mUpdate;
 | 
			
		||||
        bool mDestroy;
 | 
			
		||||
 | 
			
		||||
        void create();
 | 
			
		||||
        enum State
 | 
			
		||||
        {
 | 
			
		||||
            New,
 | 
			
		||||
            Created,
 | 
			
		||||
            Update,
 | 
			
		||||
            Destroy,
 | 
			
		||||
            Destroyed,
 | 
			
		||||
        };
 | 
			
		||||
        State mState;
 | 
			
		||||
 | 
			
		||||
        void create(uint64_t dept = 0);
 | 
			
		||||
 | 
			
		||||
        void update();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue