1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-01 09:09:42 +00:00

Wrap Lua settings widgets into an Adapter widget

This commit is contained in:
uramer 2022-01-29 23:06:43 +01:00
parent db9e734a6a
commit 086a7d9bc5
13 changed files with 168 additions and 44 deletions

View file

@ -242,9 +242,9 @@ namespace MWGui
getWidget(mScriptList, "ScriptList"); getWidget(mScriptList, "ScriptList");
getWidget(mScriptBox, "ScriptBox"); getWidget(mScriptBox, "ScriptBox");
getWidget(mScriptView, "ScriptView"); getWidget(mScriptView, "ScriptView");
getWidget(mScriptAdapter, "ScriptAdapter");
getWidget(mScriptDisabled, "ScriptDisabled"); getWidget(mScriptDisabled, "ScriptDisabled");
getWidget(mScriptDescription, "ScriptDescription"); getWidget(mScriptDescription, "ScriptDescription");
mScriptChild = nullptr;
#ifndef WIN32 #ifndef WIN32
// hide gamma controls since it currently does not work under Linux // hide gamma controls since it currently does not work under Linux
@ -732,8 +732,7 @@ namespace MWGui
void SettingsWindow::renderScriptSettings() void SettingsWindow::renderScriptSettings()
{ {
if (mCurrentPage >= 0) mScriptAdapter->detach();
LuaUi::attachToWidget(mCurrentPage);
mCurrentPage = -1; mCurrentPage = -1;
mScriptList->removeAllItems(); mScriptList->removeAllItems();
mScriptView->setCanvasSize({0, 0}); mScriptView->setCanvasSize({0, 0});
@ -766,18 +765,14 @@ namespace MWGui
void SettingsWindow::onScriptListSelection(MyGUI::ListBox*, size_t index) void SettingsWindow::onScriptListSelection(MyGUI::ListBox*, size_t index)
{ {
if (mCurrentPage >= 0) mScriptAdapter->detach();
LuaUi::attachToWidget(mCurrentPage);
mCurrentPage = -1; mCurrentPage = -1;
if (index < mScriptList->getItemCount()) if (index < mScriptList->getItemCount())
{ {
mCurrentPage = *mScriptList->getItemDataAt<size_t>(index); mCurrentPage = *mScriptList->getItemDataAt<size_t>(index);
LuaUi::attachToWidget(mCurrentPage, mScriptView); LuaUi::attachPageAt(mCurrentPage, mScriptAdapter);
} }
mScriptChild = mScriptView->getChildCount() > 0 ? mScriptView->getChildAt(0) : nullptr; MyGUI::IntSize canvasSize = mScriptAdapter->getSize();
MyGUI::IntSize canvasSize = mScriptChild ? mScriptChild->getSize() : MyGUI::IntSize();
if (mScriptChild)
mScriptChild->setVisible(mScriptView->getVisible());
mScriptView->setCanvasSize(canvasSize); mScriptView->setCanvasSize(canvasSize);
} }
@ -787,14 +782,13 @@ namespace MWGui
{ {
mScriptDescription->setVisible(false); mScriptDescription->setVisible(false);
mScriptView->setVisible(true); mScriptView->setVisible(true);
if (mScriptChild)
mScriptChild->setVisible(true);
return;
} }
size_t page = *mScriptList->getItemDataAt<size_t>(index); else {
mScriptDescription->setCaption(LuaUi::scriptSettingsPageAt(page).mDescription); size_t page = *mScriptList->getItemDataAt<size_t>(index);
mScriptDescription->setVisible(true); mScriptDescription->setCaption(LuaUi::scriptSettingsPageAt(page).mDescription);
mScriptView->setVisible(false); mScriptDescription->setVisible(true);
mScriptView->setVisible(false);
}
} }
void SettingsWindow::onRebindAction(MyGUI::Widget* _sender) void SettingsWindow::onRebindAction(MyGUI::Widget* _sender)

View file

@ -1,6 +1,8 @@
#ifndef MWGUI_SETTINGS_H #ifndef MWGUI_SETTINGS_H
#define MWGUI_SETTINGS_H #define MWGUI_SETTINGS_H
#include <components/lua_ui/adapter.hpp>
#include "windowbase.hpp" #include "windowbase.hpp"
namespace MWGui namespace MWGui
@ -48,14 +50,11 @@ namespace MWGui
MyGUI::ListBox* mScriptList; MyGUI::ListBox* mScriptList;
MyGUI::Widget* mScriptBox; MyGUI::Widget* mScriptBox;
MyGUI::ScrollView* mScriptView; MyGUI::ScrollView* mScriptView;
LuaUi::LuaAdapter* mScriptAdapter;
MyGUI::EditBox* mScriptDisabled; MyGUI::EditBox* mScriptDisabled;
MyGUI::EditBox* mScriptDescription; MyGUI::EditBox* mScriptDescription;
int mCurrentPage; int mCurrentPage;
// only necessary to work around a MyGUI bug
// adding a child to an invisible widget doesn't make the child invisible
MyGUI::Widget* mScriptChild;
void onTabChanged(MyGUI::TabControl* _sender, size_t index); void onTabChanged(MyGUI::TabControl* _sender, size_t index);
void onOkButtonClicked(MyGUI::Widget* _sender); void onOkButtonClicked(MyGUI::Widget* _sender);
void onTextureFilteringChanged(MyGUI::ComboBox* _sender, size_t pos); void onTextureFilteringChanged(MyGUI::ComboBox* _sender, size_t pos);

View file

@ -166,7 +166,7 @@ add_component_dir (queries
add_component_dir (lua_ui add_component_dir (lua_ui
properties widget element util layers content scriptsettings properties widget element util layers content scriptsettings
text textedit window image adapter text textedit window image
) )

View file

@ -0,0 +1,65 @@
#include "adapter.hpp"
#include <MyGUI_Gui.h>
#include "element.hpp"
namespace LuaUi
{
namespace
{
sol::state luaState;
}
LuaAdapter::LuaAdapter()
: mElement(nullptr)
, mContent(nullptr)
{
MyGUI::Widget* widget = MyGUI::Gui::getInstancePtr()->createWidgetT(
"LuaWidget", "",
MyGUI::IntCoord(), MyGUI::Align::Default,
std::string(), "");
mContent = dynamic_cast<WidgetExtension*>(widget);
if (!mContent)
throw std::runtime_error("Invalid widget!");
mContent->initialize(luaState, widget);
mContent->onSizeChange([this](MyGUI::IntSize size)
{
setSize(size);
});
mContent->widget()->attachToWidget(this);
}
void LuaAdapter::attach(const std::shared_ptr<Element>& element)
{
detachElement();
mElement = element;
attachElement();
setSize(mContent->widget()->getSize());
// workaround for MyGUI bug
// parent visibility doesn't affect added children
setVisible(!getVisible());
setVisible(!getVisible());
}
void LuaAdapter::detach()
{
detachElement();
setSize({ 0, 0 });
}
void LuaAdapter::attachElement()
{
if (mElement.get())
mElement->attachToWidget(mContent);
}
void LuaAdapter::detachElement()
{
if (mElement.get())
mElement->detachFromWidget();
mElement = nullptr;
}
}

View file

@ -0,0 +1,29 @@
#ifndef OPENMW_LUAUI_ADAPTER
#define OPENMW_LUAUI_ADAPTER
#include <MyGUI_Widget.h>
namespace LuaUi
{
class WidgetExtension;
struct Element;
class LuaAdapter : public MyGUI::Widget
{
MYGUI_RTTI_DERIVED(LuaAdapter)
public:
LuaAdapter();
void attach(const std::shared_ptr<Element>& element);
void detach();
bool empty() { return mElement.get() == nullptr; }
private:
WidgetExtension* mContent;
std::shared_ptr<Element> mElement;
void attachElement();
void detachElement();
};
}
#endif // !OPENMW_LUAUI_ADAPTER

View file

@ -4,6 +4,7 @@
#include "content.hpp" #include "content.hpp"
#include "util.hpp" #include "util.hpp"
#include "widget.hpp"
namespace LuaUi namespace LuaUi
{ {
@ -209,14 +210,26 @@ namespace LuaUi
sAllElements.erase(this); sAllElements.erase(this);
} }
void Element::attachToWidget(MyGUI::Widget* w) void Element::attachToWidget(WidgetExtension* w)
{ {
if (mAttachedTo && w) if (mAttachedTo)
throw std::logic_error("A UI element can't be attached to two widgets at once"); throw std::logic_error("A UI element can't be attached to two widgets at once");
mAttachedTo = w; mAttachedTo = w;
updateAttachment(); updateAttachment();
} }
void Element::detachFromWidget()
{
if (mRoot)
{
mRoot->onSizeChange({});
mRoot->widget()->detachFromWidget();
}
if (mAttachedTo)
mAttachedTo->setChildren({});
mAttachedTo = nullptr;
}
void Element::updateAttachment() void Element::updateAttachment()
{ {
if (!mRoot) if (!mRoot)
@ -225,18 +238,17 @@ namespace LuaUi
{ {
if (!mLayer.empty()) if (!mLayer.empty())
Log(Debug::Warning) << "Ignoring element's layer " << mLayer << " because it's attached to a widget"; Log(Debug::Warning) << "Ignoring element's layer " << mLayer << " because it's attached to a widget";
if (mRoot->widget()->getParent() != mAttachedTo) mAttachedTo->setChildren({ mRoot });
auto callback = [this](MyGUI::IntSize size)
{ {
mRoot->widget()->attachToWidget(mAttachedTo); if (!mAttachedTo)
mRoot->updateCoord(); return;
} mAttachedTo->setForcedSize(mRoot->widget()->getSize());
} mAttachedTo->updateCoord();
else };
{ mRoot->onSizeChange(callback);
if (mRoot->widget()->getParent() != nullptr) mRoot->updateCoord();
{ callback(mRoot->widget()->getSize());
mRoot->widget()->detachFromWidget();
}
} }
} }
} }

View file

@ -10,7 +10,7 @@ namespace LuaUi
static std::shared_ptr<Element> make(sol::table layout); static std::shared_ptr<Element> make(sol::table layout);
WidgetExtension* mRoot; WidgetExtension* mRoot;
MyGUI::Widget* mAttachedTo; WidgetExtension* mAttachedTo;
sol::table mLayout; sol::table mLayout;
std::string mLayer; std::string mLayer;
bool mUpdate; bool mUpdate;
@ -24,7 +24,8 @@ namespace LuaUi
friend void clearUserInterface(); friend void clearUserInterface();
void attachToWidget(MyGUI::Widget* w = nullptr); void attachToWidget(WidgetExtension* w);
void detachFromWidget();
private: private:
Element(sol::table layout); Element(sol::table layout);

View file

@ -1,8 +1,10 @@
#include "scriptsettings.hpp" #include "scriptsettings.hpp"
#include <map> #include <map>
#include <sol/sol.hpp>
#include "element.hpp" #include "element.hpp"
#include "adapter.hpp"
namespace LuaUi namespace LuaUi
{ {
@ -19,7 +21,7 @@ namespace LuaUi
if (!element.get()) if (!element.get())
Log(Debug::Warning) << "A script settings page has no UI element assigned"; Log(Debug::Warning) << "A script settings page has no UI element assigned";
return { return {
name, description, element.get() name, description, element
}; };
} }
} }
@ -44,13 +46,14 @@ namespace LuaUi
allPages.clear(); allPages.clear();
} }
void attachToWidget(size_t index, MyGUI::Widget* widget) void attachPageAt(size_t index, LuaAdapter* adapter)
{ {
if (index < allPages.size()) if (index < allPages.size())
{ {
ScriptSettingsPage page = parse(allPages[index]); ScriptSettingsPage page = parse(allPages[index]);
if (page.mElement) adapter->detach();
page.mElement->attachToWidget(widget); if (page.mElement.get())
adapter->attach(page.mElement);
} }
} }
} }

View file

@ -1,7 +1,6 @@
#ifndef OPENMW_LUAUI_SCRIPTSETTINGS #ifndef OPENMW_LUAUI_SCRIPTSETTINGS
#define OPENMW_LUAUI_SCRIPTSETTINGS #define OPENMW_LUAUI_SCRIPTSETTINGS
#include <vector>
#include <string> #include <string>
#include <string_view> #include <string_view>
@ -9,18 +8,19 @@
namespace LuaUi namespace LuaUi
{ {
class LuaAdapter;
struct Element; struct Element;
struct ScriptSettingsPage struct ScriptSettingsPage
{ {
std::string mName; std::string mName;
std::string mDescription; std::string mDescription;
Element* mElement; // TODO: figure out if this can lead to use after free std::shared_ptr<Element> mElement;
}; };
size_t scriptSettingsPageCount(); size_t scriptSettingsPageCount();
ScriptSettingsPage scriptSettingsPageAt(size_t index); ScriptSettingsPage scriptSettingsPageAt(size_t index);
void registerSettingsPage(const sol::table& options); void registerSettingsPage(const sol::table& options);
void clearSettings(); void clearSettings();
void attachToWidget(size_t index, MyGUI::Widget* widget = nullptr); void attachPageAt(size_t index, LuaAdapter* adapter);
} }
#endif // !OPENMW_LUAUI_SCRIPTSETTINGS #endif // !OPENMW_LUAUI_SCRIPTSETTINGS

View file

@ -2,6 +2,7 @@
#include <MyGUI_FactoryManager.h> #include <MyGUI_FactoryManager.h>
#include "adapter.hpp"
#include "widget.hpp" #include "widget.hpp"
#include "text.hpp" #include "text.hpp"
#include "textedit.hpp" #include "textedit.hpp"
@ -16,6 +17,7 @@ namespace LuaUi
void registerAllWidgets() void registerAllWidgets()
{ {
MyGUI::FactoryManager::getInstance().registerFactory<LuaAdapter>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<LuaWidget>("Widget"); MyGUI::FactoryManager::getInstance().registerFactory<LuaWidget>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<LuaText>("Widget"); MyGUI::FactoryManager::getInstance().registerFactory<LuaText>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<LuaTextEdit>("Widget"); MyGUI::FactoryManager::getInstance().registerFactory<LuaTextEdit>("Widget");

View file

@ -194,6 +194,11 @@ namespace LuaUi
mForcedCoord = offset; mForcedCoord = offset;
} }
void WidgetExtension::setForcedSize(const MyGUI::IntSize& size)
{
mForcedCoord = size;
}
void WidgetExtension::updateCoord() void WidgetExtension::updateCoord()
{ {
MyGUI::IntCoord oldCoord = mWidget->getCoord(); MyGUI::IntCoord oldCoord = mWidget->getCoord();
@ -202,7 +207,11 @@ namespace LuaUi
if (oldCoord != newCoord) if (oldCoord != newCoord)
mWidget->setCoord(newCoord); mWidget->setCoord(newCoord);
if (oldCoord.size() != newCoord.size()) if (oldCoord.size() != newCoord.size())
{
updateChildrenCoord(); updateChildrenCoord();
if (mOnSizeChange.has_value())
mOnSizeChange.value()(newCoord.size());
}
} }
void WidgetExtension::setProperties(sol::object props) void WidgetExtension::setProperties(sol::object props)

View file

@ -2,6 +2,7 @@
#define OPENMW_LUAUI_WIDGET #define OPENMW_LUAUI_WIDGET
#include <map> #include <map>
#include <functional>
#include <MyGUI_Widget.h> #include <MyGUI_Widget.h>
#include <sol/sol.hpp> #include <sol/sol.hpp>
@ -44,6 +45,7 @@ namespace LuaUi
MyGUI::IntCoord forcedCoord(); MyGUI::IntCoord forcedCoord();
void setForcedCoord(const MyGUI::IntCoord& offset); void setForcedCoord(const MyGUI::IntCoord& offset);
void setForcedSize(const MyGUI::IntSize& size);
void updateCoord(); void updateCoord();
const sol::table& getLayout() { return mLayout; } const sol::table& getLayout() { return mLayout; }
@ -55,6 +57,11 @@ namespace LuaUi
return parseExternal(mExternal, name, defaultValue); return parseExternal(mExternal, name, defaultValue);
} }
void onSizeChange(const std::optional<std::function<void(MyGUI::IntSize)>>& callback)
{
mOnSizeChange = callback;
}
protected: protected:
virtual void initialize(); virtual void initialize();
sol::table makeTable() const; sol::table makeTable() const;
@ -119,6 +126,8 @@ namespace LuaUi
void mouseRelease(MyGUI::Widget*, int, int, MyGUI::MouseButton); void mouseRelease(MyGUI::Widget*, int, int, MyGUI::MouseButton);
void focusGain(MyGUI::Widget*, MyGUI::Widget*); void focusGain(MyGUI::Widget*, MyGUI::Widget*);
void focusLoss(MyGUI::Widget*, MyGUI::Widget*); void focusLoss(MyGUI::Widget*, MyGUI::Widget*);
std::optional<std::function<void(MyGUI::IntSize)>> mOnSizeChange;
}; };
class LuaWidget : public MyGUI::Widget, public WidgetExtension class LuaWidget : public MyGUI::Widget, public WidgetExtension

View file

@ -664,6 +664,7 @@
<Widget name="ScriptView" type="ScrollView" skin="MW_ScrollViewVH" position="2 2 246 246" align="Stretch"> <Widget name="ScriptView" type="ScrollView" skin="MW_ScrollViewVH" position="2 2 246 246" align="Stretch">
<Property key="CanvasAlign" value="Left Top"/> <Property key="CanvasAlign" value="Left Top"/>
<Property key="CanvasSize" value="246 246"/> <Property key="CanvasSize" value="246 246"/>
<Widget name="ScriptAdapter" type="LuaAdapter" position="0 0 246 246"/>
</Widget> </Widget>
<Widget name="ScriptDescription" type = "EditBox" skin="SandText" position="2 2 246 246" align="Stretch"> <Widget name="ScriptDescription" type = "EditBox" skin="SandText" position="2 2 246 246" align="Stretch">
<Property key="Visible" value="false"/> <Property key="Visible" value="false"/>