Fix child UI Elements created in the same frame as parent

fix-osga-rotate-wildly
uramer 10 months ago
parent 7a5493796f
commit 9ae61f1932

@ -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…
Cancel
Save