1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-05 15:55:45 +00:00

Allow changing element root widget type, prevent use after free in script settings

This commit is contained in:
uramer 2022-01-28 21:35:05 +01:00
parent 64df4f54c6
commit a972a54ea9
6 changed files with 73 additions and 26 deletions

View File

@ -207,9 +207,9 @@ namespace MWGui
}
}
SettingsWindow::SettingsWindow() :
WindowBase("openmw_settings_window.layout"),
mKeyboardMode(true)
SettingsWindow::SettingsWindow() : WindowBase("openmw_settings_window.layout")
, mKeyboardMode(true)
, mCurrentPage(-1)
{
bool terrain = Settings::Manager::getBool("distant terrain", "Terrain");
const std::string widgetName = terrain ? "RenderingDistanceSlider" : "LargeRenderingDistanceSlider";
@ -729,8 +729,8 @@ namespace MWGui
void SettingsWindow::renderScriptSettings()
{
while (mScriptView->getChildCount() > 0)
mScriptView->getChildAt(0)->detachFromWidget();
LuaUi::attachToWidget(mCurrentPage);
mCurrentPage = -1;
mScriptList->removeAllItems();
mScriptView->setCanvasSize({0, 0});
@ -763,13 +763,13 @@ namespace MWGui
void SettingsWindow::onScriptListSelection(MyGUI::Widget*, size_t index)
{
while (mScriptView->getChildCount() > 0)
mScriptView->getChildAt(0)->detachFromWidget();
if (mCurrentPage >= 0)
LuaUi::attachToWidget(mCurrentPage);
mCurrentPage = -1;
if (index >= mScriptList->getItemCount())
return;
size_t scriptIndex = *mScriptList->getItemDataAt<size_t>(index);
LuaUi::ScriptSettings script = LuaUi::scriptSettings()[scriptIndex];
LuaUi::attachToWidget(script, mScriptView);
mCurrentPage = *mScriptList->getItemDataAt<size_t>(index);
LuaUi::attachToWidget(mCurrentPage, mScriptView);
MyGUI::IntSize canvasSize;
if (mScriptView->getChildCount() > 0)
canvasSize = mScriptView->getChildAt(0)->getSize();

View File

@ -49,6 +49,7 @@ namespace MWGui
MyGUI::Widget* mScriptBox;
MyGUI::ScrollView* mScriptView;
MyGUI::EditBox* mScriptDisabled;
int mCurrentPage;
void onTabChanged(MyGUI::TabControl* _sender, size_t index);
void onOkButtonClicked(MyGUI::Widget* _sender);

View File

@ -138,7 +138,7 @@ namespace LuaUi
ext->setChildren(updateContent(ext->children(), layout.get<sol::object>(LayoutKeys::content)));
}
void setLayer(WidgetExtension* ext, const sol::table& layout)
std::string setLayer(WidgetExtension* ext, const sol::table& layout)
{
MyGUI::ILayer* layerNode = ext->widget()->getLayer();
std::string currentLayer = layerNode ? layerNode->getName() : std::string();
@ -149,15 +149,18 @@ namespace LuaUi
{
MyGUI::LayerManager::getInstance().attachToLayerNode(newLayer, ext->widget());
}
return newLayer;
}
std::map<Element*, std::shared_ptr<Element>> Element::sAllElements;
Element::Element(sol::table layout)
: mRoot{ nullptr }
, mLayout{ std::move(layout) }
, mUpdate{ false }
, mDestroy{ false }
: mRoot(nullptr)
, mAttachedTo(nullptr)
, mLayout(std::move(layout))
, mLayer()
, mUpdate(false)
, mDestroy(false)
{}
@ -174,7 +177,8 @@ namespace LuaUi
if (!mRoot)
{
mRoot = createWidget(mLayout);
setLayer(mRoot, mLayout);
mLayer = setLayer(mRoot, mLayout);
updateAttachment();
}
}
@ -182,8 +186,17 @@ namespace LuaUi
{
if (mRoot && mUpdate)
{
updateWidget(mRoot, mLayout);
setLayer(mRoot, mLayout);
if (mRoot->widget()->getTypeName() != widgetType(mLayout))
{
destroyWidget(mRoot);
mRoot = createWidget(mLayout);
}
else
{
updateWidget(mRoot, mLayout);
}
mLayer = setLayer(mRoot, mLayout);
updateAttachment();
}
mUpdate = false;
}
@ -195,4 +208,35 @@ namespace LuaUi
mRoot = nullptr;
sAllElements.erase(this);
}
void Element::attachToWidget(MyGUI::Widget* w)
{
if (mAttachedTo && w)
throw std::logic_error("A UI element can't be attached to two widgets at once");
mAttachedTo = w;
updateAttachment();
}
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";
if (mRoot->widget()->getParent() != mAttachedTo)
{
mRoot->widget()->attachToWidget(mAttachedTo);
mRoot->updateCoord();
}
}
else
{
if (mRoot->widget()->getParent() != nullptr)
{
mRoot->widget()->detachFromWidget();
}
}
}
}

View File

@ -9,8 +9,10 @@ namespace LuaUi
{
static std::shared_ptr<Element> make(sol::table layout);
LuaUi::WidgetExtension* mRoot;
WidgetExtension* mRoot;
MyGUI::Widget* mAttachedTo;
sol::table mLayout;
std::string mLayer;
bool mUpdate;
bool mDestroy;
@ -22,9 +24,12 @@ namespace LuaUi
friend void clearUserInterface();
void attachToWidget(MyGUI::Widget* w = nullptr);
private:
Element(sol::table layout);
static std::map<Element*, std::shared_ptr<Element>> sAllElements;
void updateAttachment();
};
}

View File

@ -26,12 +26,9 @@ namespace LuaUi
allSettings.clear();
}
void attachToWidget(const ScriptSettings& script, MyGUI::Widget* widget)
void attachToWidget(size_t index, MyGUI::Widget* widget)
{
WidgetExtension* root = script.mElement->mRoot;
if (!root)
return;
root->widget()->attachToWidget(widget);
root->updateCoord();
if (0 <= index && index < allSettings.size())
allSettings[index].mElement->attachToWidget(widget);
}
}

View File

@ -19,7 +19,7 @@ namespace LuaUi
const std::vector<ScriptSettings>& scriptSettings();
void registerSettings(const ScriptSettings& script);
void clearSettings();
void attachToWidget(const ScriptSettings& script, MyGUI::Widget* widget);
void attachToWidget(size_t index, MyGUI::Widget* widget = nullptr);
}
#endif // !OPENMW_LUAUI_SCRIPTSETTINGS