mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 17:26:38 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			309 lines
		
	
	
	
		
			9.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			309 lines
		
	
	
	
		
			9.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "widget.hpp"
 | |
| 
 | |
| #include <SDL_events.h>
 | |
| 
 | |
| #include "text.hpp"
 | |
| #include "textedit.hpp"
 | |
| #include "window.hpp"
 | |
| 
 | |
| namespace LuaUi
 | |
| {
 | |
|     WidgetExtension::WidgetExtension()
 | |
|         : mForcedCoord()
 | |
|         , mAbsoluteCoord()
 | |
|         , mRelativeCoord()
 | |
|         , mAnchor()
 | |
|     {}
 | |
| 
 | |
|     void WidgetExtension::triggerEvent(std::string_view name, const sol::object& argument = sol::nil) const
 | |
|     {
 | |
|         auto it = mCallbacks.find(name);
 | |
|         if (it != mCallbacks.end())
 | |
|             it->second(argument);
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::create(lua_State* lua, MyGUI::Widget* self)
 | |
|     {
 | |
|         mLua = lua;
 | |
|         mWidget = self;
 | |
| 
 | |
|         mWidget->eventChangeCoord += MyGUI::newDelegate(this, &WidgetExtension::updateChildrenCoord);
 | |
| 
 | |
|         initialize();
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::initialize()
 | |
|     {
 | |
|         // \todo might be more efficient to only register these if there are Lua callbacks
 | |
|         mWidget->eventKeyButtonPressed += MyGUI::newDelegate(this, &WidgetExtension::keyPress);
 | |
|         mWidget->eventKeyButtonReleased += MyGUI::newDelegate(this, &WidgetExtension::keyRelease);
 | |
|         mWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &WidgetExtension::mouseClick);
 | |
|         mWidget->eventMouseButtonDoubleClick += MyGUI::newDelegate(this, &WidgetExtension::mouseDoubleClick);
 | |
|         mWidget->eventMouseButtonPressed += MyGUI::newDelegate(this, &WidgetExtension::mousePress);
 | |
|         mWidget->eventMouseButtonReleased += MyGUI::newDelegate(this, &WidgetExtension::mouseRelease);
 | |
|         mWidget->eventMouseMove += MyGUI::newDelegate(this, &WidgetExtension::mouseMove);
 | |
|         mWidget->eventMouseDrag += MyGUI::newDelegate(this, &WidgetExtension::mouseDrag);
 | |
| 
 | |
|         mWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &WidgetExtension::focusGain);
 | |
|         mWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &WidgetExtension::focusLoss);
 | |
|         mWidget->eventKeySetFocus += MyGUI::newDelegate(this, &WidgetExtension::focusGain);
 | |
|         mWidget->eventKeyLostFocus += MyGUI::newDelegate(this, &WidgetExtension::focusLoss);
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::destroy()
 | |
|     {
 | |
|         clearCallbacks();
 | |
|         deinitialize();
 | |
| 
 | |
|         for (WidgetExtension* child : mContent)
 | |
|             child->destroy();
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::deinitialize()
 | |
|     {
 | |
|         mWidget->eventKeyButtonPressed.clear();
 | |
|         mWidget->eventKeyButtonReleased.clear();
 | |
|         mWidget->eventMouseButtonClick.clear();
 | |
|         mWidget->eventMouseButtonDoubleClick.clear();
 | |
|         mWidget->eventMouseButtonPressed.clear();
 | |
|         mWidget->eventMouseButtonReleased.clear();
 | |
|         mWidget->eventMouseMove.clear();
 | |
|         mWidget->eventMouseDrag.m_event.clear();
 | |
| 
 | |
|         mWidget->eventMouseSetFocus.clear();
 | |
|         mWidget->eventMouseLostFocus.clear();
 | |
|         mWidget->eventKeySetFocus.clear();
 | |
|         mWidget->eventKeyLostFocus.clear();
 | |
|     }
 | |
| 
 | |
|     sol::table WidgetExtension::makeTable() const
 | |
|     {
 | |
|         return sol::table(mLua, sol::create);
 | |
|     }
 | |
| 
 | |
|     sol::object WidgetExtension::keyEvent(MyGUI::KeyCode code) const
 | |
|     {
 | |
|         SDL_Keysym keySym;
 | |
|         // MyGUI key codes are not one to one with SDL key codes
 | |
|         // \todo refactor sdlmappings.cpp to map this back to SDL correctly
 | |
|         keySym.sym = static_cast<SDL_Keycode>(code.getValue());
 | |
|         keySym.scancode = SDL_GetScancodeFromKey(keySym.sym);
 | |
|         keySym.mod = SDL_GetModState();
 | |
|         return sol::make_object(mLua, keySym);
 | |
|     }
 | |
| 
 | |
|     sol::object WidgetExtension::mouseEvent(int left, int top, MyGUI::MouseButton button = MyGUI::MouseButton::None) const
 | |
|     {
 | |
|         auto position = osg::Vec2f(left, top);
 | |
|         auto absolutePosition = mWidget->getAbsolutePosition();
 | |
|         auto offset = position - osg::Vec2f(absolutePosition.left, absolutePosition.top);
 | |
|         sol::table table = makeTable();
 | |
|         table["position"] = position;
 | |
|         table["offset"] = offset;
 | |
|         // \todo refactor sdlmappings.cpp to map this back to SDL properly
 | |
|         table["button"] = button.getValue() + 1;
 | |
|         return table;
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::addChild(WidgetExtension* ext)
 | |
|     {
 | |
|         mContent.push_back(ext);
 | |
|     }
 | |
| 
 | |
|     WidgetExtension* WidgetExtension::childAt(size_t index) const
 | |
|     {
 | |
|         return mContent.at(index);
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::assignChild(size_t index, WidgetExtension* ext)
 | |
|     {
 | |
|         if (mContent.size() <= index)
 | |
|             throw std::logic_error("Invalid widget child index");
 | |
|         mContent[index] = ext;
 | |
|     }
 | |
| 
 | |
|     WidgetExtension* WidgetExtension::eraseChild(size_t index)
 | |
|     {
 | |
|         if (mContent.size() <= index)
 | |
|             throw std::logic_error("Invalid widget child index");
 | |
|         auto it = mContent.begin() + index;
 | |
|         WidgetExtension* ext = *it;
 | |
|         mContent.erase(it);
 | |
|         return ext;
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::setCallback(const std::string& name, const LuaUtil::Callback& callback)
 | |
|     {
 | |
|         mCallbacks[name] = callback;
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::clearCallbacks()
 | |
|     {
 | |
|         mCallbacks.clear();
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::setProperty(std::string_view name, sol::object value)
 | |
|     {
 | |
|         if (!setPropertyRaw(name, value))
 | |
|             Log(Debug::Error) << "Invalid value of property " << name
 | |
|                               << ": " << LuaUtil::toString(value);
 | |
|     }
 | |
| 
 | |
|     MyGUI::IntCoord WidgetExtension::forcedOffset()
 | |
|     {
 | |
|         return mForcedCoord;
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::setForcedOffset(const MyGUI::IntCoord& offset)
 | |
|     {
 | |
|         mForcedCoord = offset;
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::updateCoord()
 | |
|     {
 | |
|         mWidget->setCoord(calculateCoord());
 | |
|     }
 | |
| 
 | |
|     bool WidgetExtension::setPropertyRaw(std::string_view name, sol::object value)
 | |
|     {
 | |
|         if (name == "position")
 | |
|         {
 | |
|             if (!value.is<osg::Vec2f>())
 | |
|                 return false;
 | |
|             auto v = value.as<osg::Vec2f>();
 | |
|             mAbsoluteCoord.left = v.x();
 | |
|             mAbsoluteCoord.top = v.y();
 | |
|         }
 | |
|         else if (name == "size")
 | |
|         {
 | |
|             if (!value.is<osg::Vec2f>())
 | |
|                 return false;
 | |
|             auto v = value.as<osg::Vec2f>();
 | |
|             mAbsoluteCoord.width = v.x();
 | |
|             mAbsoluteCoord.height = v.y();
 | |
|         }
 | |
|         else if (name == "relativePosition")
 | |
|         {
 | |
|             if (!value.is<osg::Vec2f>())
 | |
|                 return false;
 | |
|             auto v = value.as<osg::Vec2f>();
 | |
|             mRelativeCoord.left = v.x();
 | |
|             mRelativeCoord.top = v.y();
 | |
|         }
 | |
|         else if (name == "relativeSize")
 | |
|         {
 | |
|             if (!value.is<osg::Vec2f>())
 | |
|                 return false;
 | |
|             auto v = value.as<osg::Vec2f>();
 | |
|             mRelativeCoord.width = v.x();
 | |
|             mRelativeCoord.height = v.y();
 | |
|         }
 | |
|         else if (name == "anchor")
 | |
|         {
 | |
|             if (!value.is<osg::Vec2f>())
 | |
|                 return false;
 | |
|             auto v = value.as<osg::Vec2f>();
 | |
|             mAnchor.width = v.x();
 | |
|             mAnchor.height = v.y();
 | |
|         }
 | |
|         else if (name == "visible")
 | |
|         {
 | |
|             if (!value.is<bool>())
 | |
|                 return false;
 | |
|             mWidget->setVisible(value.as<bool>());
 | |
|         }
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::updateChildrenCoord(MyGUI::Widget* _widget)
 | |
|     {
 | |
|         for (auto& child : mContent)
 | |
|             child->updateCoord();
 | |
|     }
 | |
| 
 | |
|     MyGUI::IntSize WidgetExtension::calculateSize()
 | |
|     {
 | |
|         const MyGUI::IntSize& parentSize = mWidget->getParentSize();
 | |
|         MyGUI::IntSize newSize;
 | |
|         newSize = mAbsoluteCoord.size() + mForcedCoord.size();
 | |
|         newSize.width += mRelativeCoord.width * parentSize.width;
 | |
|         newSize.height += mRelativeCoord.height * parentSize.height;
 | |
|         return newSize;
 | |
|     }
 | |
| 
 | |
|     MyGUI::IntPoint WidgetExtension::calculatePosition(const MyGUI::IntSize& size)
 | |
|     {
 | |
|         const MyGUI::IntSize& parentSize = mWidget->getParentSize();
 | |
|         MyGUI::IntPoint newPosition;
 | |
|         newPosition = mAbsoluteCoord.point() + mForcedCoord.point();
 | |
|         newPosition.left += mRelativeCoord.left * parentSize.width - mAnchor.width * size.width;
 | |
|         newPosition.top += mRelativeCoord.top * parentSize.height - mAnchor.height * size.height;
 | |
|         return newPosition;
 | |
|     }
 | |
| 
 | |
|     MyGUI::IntCoord WidgetExtension::calculateCoord()
 | |
|     {
 | |
|         MyGUI::IntCoord newCoord;
 | |
|         newCoord = calculateSize();
 | |
|         newCoord = calculatePosition(newCoord.size());
 | |
|         return newCoord;
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::keyPress(MyGUI::Widget*, MyGUI::KeyCode code, MyGUI::Char ch)
 | |
|     {
 | |
|         if (code == MyGUI::KeyCode::None)
 | |
|         {
 | |
|             // \todo decide how to handle unicode strings in Lua
 | |
|             MyGUI::UString uString;
 | |
|             uString.push_back(static_cast<MyGUI::UString::unicode_char>(ch));
 | |
|             triggerEvent("textInput", sol::make_object(mLua, uString.asUTF8()));
 | |
|         }
 | |
|         else
 | |
|             triggerEvent("keyPress", keyEvent(code));
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::keyRelease(MyGUI::Widget*, MyGUI::KeyCode code)
 | |
|     {
 | |
|         triggerEvent("keyRelease", keyEvent(code));
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::mouseMove(MyGUI::Widget*, int left, int top)
 | |
|     {
 | |
|         triggerEvent("mouseMove", mouseEvent(left, top));
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::mouseDrag(MyGUI::Widget*, int left, int top, MyGUI::MouseButton button)
 | |
|     {
 | |
|         triggerEvent("mouseMove", mouseEvent(left, top, button));
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::mouseClick(MyGUI::Widget* _widget)
 | |
|     {
 | |
|         triggerEvent("mouseClick");
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::mouseDoubleClick(MyGUI::Widget* _widget)
 | |
|     {
 | |
|         triggerEvent("mouseDoubleClick");
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::mousePress(MyGUI::Widget*, int left, int top, MyGUI::MouseButton button)
 | |
|     {
 | |
|         triggerEvent("mousePress", mouseEvent(left, top, button));
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::mouseRelease(MyGUI::Widget*, int left, int top, MyGUI::MouseButton button)
 | |
|     {
 | |
|         triggerEvent("mouseRelease", mouseEvent(left, top, button));
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::focusGain(MyGUI::Widget*, MyGUI::Widget*)
 | |
|     {
 | |
|         triggerEvent("focusGain");
 | |
|     }
 | |
| 
 | |
|     void WidgetExtension::focusLoss(MyGUI::Widget*, MyGUI::Widget*)
 | |
|     {
 | |
|         triggerEvent("focusLoss");
 | |
|     }
 | |
| }
 |