Merge branch 'pass_events_up' into 'master'

Pass unhandled Lua UI events to the parent

Closes #6630

See merge request OpenMW/openmw!1670
pull/3226/head
Petr Mikheev 3 years ago
commit aa6cba9b17

@ -250,13 +250,14 @@ namespace LuaUtil
sol::table mHiddenData; // same object as Script::mHiddenData in ScriptsContainer sol::table mHiddenData; // same object as Script::mHiddenData in ScriptsContainer
template <typename... Args> template <typename... Args>
void operator()(Args&&... args) const sol::object operator()(Args&&... args) const
{ {
if (mHiddenData[ScriptsContainer::sScriptIdKey] != sol::nil) if (mHiddenData[ScriptsContainer::sScriptIdKey] != sol::nil)
LuaUtil::call(mFunc, std::forward<Args>(args)...); return LuaUtil::call(mFunc, std::forward<Args>(args)...);
else else
Log(Debug::Debug) << "Ignored callback to the removed script " Log(Debug::Debug) << "Ignored callback to the removed script "
<< mHiddenData.get<std::string>(ScriptsContainer::sScriptDebugNameKey); << mHiddenData.get<std::string>(ScriptsContainer::sScriptDebugNameKey);
return sol::nil;
} }
}; };

@ -10,7 +10,8 @@
namespace LuaUi namespace LuaUi
{ {
WidgetExtension::WidgetExtension() WidgetExtension::WidgetExtension()
: mLua(nullptr) : mPropagateEvents(true)
, mLua(nullptr)
, mWidget(nullptr) , mWidget(nullptr)
, mSlot(this) , mSlot(this)
, mLayout(sol::nil) , mLayout(sol::nil)
@ -18,6 +19,7 @@ namespace LuaUi
, mTemplateProperties(sol::nil) , mTemplateProperties(sol::nil)
, mExternal(sol::nil) , mExternal(sol::nil)
, mParent(nullptr) , mParent(nullptr)
, mTemplateChild(false)
{} {}
void WidgetExtension::initialize(lua_State* lua, MyGUI::Widget* self) void WidgetExtension::initialize(lua_State* lua, MyGUI::Widget* self)
@ -81,12 +83,15 @@ namespace LuaUi
void WidgetExtension::attach(WidgetExtension* ext) void WidgetExtension::attach(WidgetExtension* ext)
{ {
ext->mParent = this; ext->mParent = this;
ext->mTemplateChild = false;
ext->widget()->attachToWidget(mSlot->widget()); ext->widget()->attachToWidget(mSlot->widget());
ext->updateCoord(); ext->updateCoord();
} }
void WidgetExtension::attachTemplate(WidgetExtension* ext) void WidgetExtension::attachTemplate(WidgetExtension* ext)
{ {
ext->mParent = this;
ext->mTemplateChild = true;
ext->widget()->attachToWidget(widget()); ext->widget()->attachToWidget(widget());
ext->updateCoord(); ext->updateCoord();
} }
@ -133,7 +138,7 @@ namespace LuaUi
sol::table WidgetExtension::makeTable() const sol::table WidgetExtension::makeTable() const
{ {
return sol::table(mLua, sol::create); return sol::table(lua(), sol::create);
} }
sol::object WidgetExtension::keyEvent(MyGUI::KeyCode code) const sol::object WidgetExtension::keyEvent(MyGUI::KeyCode code) const
@ -142,7 +147,7 @@ namespace LuaUi
keySym.sym = SDLUtil::myGuiKeyToSdl(code); keySym.sym = SDLUtil::myGuiKeyToSdl(code);
keySym.scancode = SDL_GetScancodeFromKey(keySym.sym); keySym.scancode = SDL_GetScancodeFromKey(keySym.sym);
keySym.mod = SDL_GetModState(); keySym.mod = SDL_GetModState();
return sol::make_object(mLua, keySym); return sol::make_object(lua(), keySym);
} }
sol::object WidgetExtension::mouseEvent(int left, int top, MyGUI::MouseButton button = MyGUI::MouseButton::None) const sol::object WidgetExtension::mouseEvent(int left, int top, MyGUI::MouseButton button = MyGUI::MouseButton::None) const
@ -246,6 +251,7 @@ namespace LuaUi
void WidgetExtension::updateProperties() void WidgetExtension::updateProperties()
{ {
mPropagateEvents = propertyValue("propagateEvents", true);
mAbsoluteCoord = propertyValue("position", MyGUI::IntPoint()); mAbsoluteCoord = propertyValue("position", MyGUI::IntPoint());
mAbsoluteCoord = propertyValue("size", MyGUI::IntSize()); mAbsoluteCoord = propertyValue("size", MyGUI::IntSize());
mRelativeCoord = propertyValue("relativePosition", MyGUI::FloatPoint()); mRelativeCoord = propertyValue("relativePosition", MyGUI::FloatPoint());
@ -265,7 +271,7 @@ namespace LuaUi
MyGUI::IntSize WidgetExtension::parentSize() MyGUI::IntSize WidgetExtension::parentSize()
{ {
if (mParent) if (mParent && !mTemplateChild)
return mParent->childScalingSize(); return mParent->childScalingSize();
else else
return widget()->getParentSize(); return widget()->getParentSize();
@ -304,7 +310,7 @@ namespace LuaUi
return mSlot->widget()->getSize(); return mSlot->widget()->getSize();
} }
void WidgetExtension::triggerEvent(std::string_view name, const sol::object& argument = sol::nil) const void WidgetExtension::triggerEvent(std::string_view name, sol::object argument) const
{ {
auto it = mCallbacks.find(name); auto it = mCallbacks.find(name);
if (it != mCallbacks.end()) if (it != mCallbacks.end())
@ -315,57 +321,58 @@ namespace LuaUi
{ {
if (code == MyGUI::KeyCode::None) if (code == MyGUI::KeyCode::None)
{ {
// \todo decide how to handle unicode strings in Lua propagateEvent("textInput", [ch](auto w) {
MyGUI::UString uString; MyGUI::UString uString;
uString.push_back(static_cast<MyGUI::UString::unicode_char>(ch)); uString.push_back(static_cast<MyGUI::UString::unicode_char>(ch));
triggerEvent("textInput", sol::make_object(mLua, uString.asUTF8())); return sol::make_object(w->lua(), uString.asUTF8());
});
} }
else else
triggerEvent("keyPress", keyEvent(code)); propagateEvent("keyPress", [code](auto w){ return w->keyEvent(code); });
} }
void WidgetExtension::keyRelease(MyGUI::Widget*, MyGUI::KeyCode code) void WidgetExtension::keyRelease(MyGUI::Widget*, MyGUI::KeyCode code)
{ {
triggerEvent("keyRelease", keyEvent(code)); propagateEvent("keyRelease", [code](auto w) { return w->keyEvent(code); });
} }
void WidgetExtension::mouseMove(MyGUI::Widget*, int left, int top) void WidgetExtension::mouseMove(MyGUI::Widget*, int left, int top)
{ {
triggerEvent("mouseMove", mouseEvent(left, top)); propagateEvent("mouseMove", [left, top](auto w) { return w->mouseEvent(left, top); });
} }
void WidgetExtension::mouseDrag(MyGUI::Widget*, int left, int top, MyGUI::MouseButton button) void WidgetExtension::mouseDrag(MyGUI::Widget*, int left, int top, MyGUI::MouseButton button)
{ {
triggerEvent("mouseMove", mouseEvent(left, top, button)); propagateEvent("mouseMove", [left, top, button](auto w) { return w->mouseEvent(left, top, button); });
} }
void WidgetExtension::mouseClick(MyGUI::Widget* _widget) void WidgetExtension::mouseClick(MyGUI::Widget* _widget)
{ {
triggerEvent("mouseClick"); propagateEvent("mouseClick", [](auto){ return sol::nil; });
} }
void WidgetExtension::mouseDoubleClick(MyGUI::Widget* _widget) void WidgetExtension::mouseDoubleClick(MyGUI::Widget* _widget)
{ {
triggerEvent("mouseDoubleClick"); propagateEvent("mouseDoubleClick", [](auto){ return sol::nil; });
} }
void WidgetExtension::mousePress(MyGUI::Widget*, int left, int top, MyGUI::MouseButton button) void WidgetExtension::mousePress(MyGUI::Widget*, int left, int top, MyGUI::MouseButton button)
{ {
triggerEvent("mousePress", mouseEvent(left, top, button)); propagateEvent("mousePress", [left, top, button](auto w) { return w->mouseEvent(left, top, button); });
} }
void WidgetExtension::mouseRelease(MyGUI::Widget*, int left, int top, MyGUI::MouseButton button) void WidgetExtension::mouseRelease(MyGUI::Widget*, int left, int top, MyGUI::MouseButton button)
{ {
triggerEvent("mouseRelease", mouseEvent(left, top, button)); propagateEvent("mouseRelease", [left, top, button](auto w) { return w->mouseEvent(left, top, button); });
} }
void WidgetExtension::focusGain(MyGUI::Widget*, MyGUI::Widget*) void WidgetExtension::focusGain(MyGUI::Widget*, MyGUI::Widget*)
{ {
triggerEvent("focusGain"); propagateEvent("focusGain", [](auto){ return sol::nil; });
} }
void WidgetExtension::focusLoss(MyGUI::Widget*, MyGUI::Widget*) void WidgetExtension::focusLoss(MyGUI::Widget*, MyGUI::Widget*)
{ {
triggerEvent("focusLoss"); propagateEvent("focusLoss", [](auto){ return sol::nil; });
} }
} }

@ -90,8 +90,28 @@ namespace LuaUi
virtual void updateProperties(); virtual void updateProperties();
virtual void updateChildren() {}; virtual void updateChildren() {};
lua_State* lua() { return mLua; } lua_State* lua() const { return mLua; }
void triggerEvent(std::string_view name, const sol::object& argument) const;
void triggerEvent(std::string_view name, sol::object argument) const;
template<class ArgFactory>
void propagateEvent(std::string_view name, const ArgFactory& argumentFactory) const
{
const WidgetExtension* w = this;
while (w)
{
bool shouldPropagate = true;
auto it = w->mCallbacks.find(name);
if (it != w->mCallbacks.end())
{
sol::object res = it->second(argumentFactory(w), w->mLayout);
shouldPropagate = res.is<bool>() && res.as<bool>();
}
if (w->mParent && w->mPropagateEvents && shouldPropagate)
w = w->mParent;
else
w = nullptr;
}
}
// offsets the position and size, used only in C++ widget code // offsets the position and size, used only in C++ widget code
MyGUI::IntCoord mForcedCoord; MyGUI::IntCoord mForcedCoord;
@ -103,6 +123,8 @@ namespace LuaUi
// used in combination with relative coord to align the widget, e. g. center it // used in combination with relative coord to align the widget, e. g. center it
MyGUI::FloatSize mAnchor; MyGUI::FloatSize mAnchor;
bool mPropagateEvents;
private: private:
// use lua_State* instead of sol::state_view because MyGUI requires a default constructor // use lua_State* instead of sol::state_view because MyGUI requires a default constructor
lua_State* mLua; lua_State* mLua;
@ -116,6 +138,7 @@ namespace LuaUi
sol::object mTemplateProperties; sol::object mTemplateProperties;
sol::object mExternal; sol::object mExternal;
WidgetExtension* mParent; WidgetExtension* mParent;
bool mTemplateChild;
void attach(WidgetExtension* ext); void attach(WidgetExtension* ext);
void attachTemplate(WidgetExtension* ext); void attachTemplate(WidgetExtension* ext);

@ -32,12 +32,19 @@ Properties
* - visible * - visible
- boolean (true) - boolean (true)
- Defines if the widget is visible - Defines if the widget is visible
* - propagateEvents
- boolean (true)
- Allows base widget events to propagate to the widget's parent.
.. TODO: document the mouse pointer property, when API for reading / adding pointer types is available .. TODO: document the mouse pointer property, when API for reading / adding pointer types is available
Events Events
------ ------
Base widget events are special, they can propagate up to the parent widget.
This can be prevented by changing the `propagateEvents` property, or by assigning an event handler.
The event is still allowed to propagate if the event handler returns `true`.
.. list-table:: .. list-table::
:header-rows: 1 :header-rows: 1
:widths: 20 20 60 :widths: 20 20 60

Loading…
Cancel
Save