File: widget.hpp

package info (click to toggle)
openmw 0.49.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 33,992 kB
  • sloc: cpp: 372,479; xml: 2,149; sh: 1,403; python: 797; makefile: 26
file content (203 lines) | stat: -rw-r--r-- 7,319 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#ifndef OPENMW_LUAUI_WIDGET
#define OPENMW_LUAUI_WIDGET

#include <functional>
#include <map>

#include <MyGUI_Widget.h>
#include <sol/sol.hpp>

#include <components/lua/asyncpackage.hpp>

#include "properties.hpp"

namespace LuaUi
{
    /*
     * extends MyGUI::Widget and its child classes
     * memory ownership is controlled by MyGUI
     * it is important not to call any WidgetExtension methods after destroying the MyGUI::Widget
     */
    class WidgetExtension
    {
    public:
        WidgetExtension();

        virtual ~WidgetExtension() = default;

        // must be called after creating the underlying MyGUI::Widget
        void initialize(lua_State* lua, MyGUI::Widget* self, bool isRoot);
        // must be called after before destroying the underlying MyGUI::Widget
        virtual void deinitialize();

        MyGUI::Widget* widget() const { return mWidget; }

        bool isRoot() const { return mElementRoot; }
        WidgetExtension* getParent() const { return mParent; }
        void detachFromParent();

        void detachChildrenIf(auto&& predicate) { detachChildrenIf(predicate, mChildren); }
        void detachTemplateChildrenIf(auto&& predicate) { detachChildrenIf(predicate, mTemplateChildren); }

        void reset();

        const std::vector<WidgetExtension*>& children() { return mChildren; }
        void setChildren(const std::vector<WidgetExtension*>&);

        const std::vector<WidgetExtension*>& templateChildren() { return mTemplateChildren; }
        void setTemplateChildren(const std::vector<WidgetExtension*>&);

        void setCallback(const std::string&, const LuaUtil::Callback&);
        void clearCallbacks();

        void setProperties(const sol::main_object& props);
        void setTemplateProperties(const sol::main_object& props) { mTemplateProperties = props; }

        void setExternal(const sol::main_object& external) { mExternal = external; }

        MyGUI::IntCoord forcedCoord();
        void forceCoord(const MyGUI::IntCoord& offset);
        void forceSize(const MyGUI::IntSize& size);
        void forcePosition(const MyGUI::IntPoint& pos);
        void clearForced();

        virtual void updateCoord();

        const sol::main_table& getLayout() { return mLayout; }
        void setLayout(const sol::table& layout) { mLayout = layout; }

        template <typename T>
        T externalValue(std::string_view name, const T& defaultValue) const
        {
            return parseExternal(mExternal, name, defaultValue);
        }

        virtual MyGUI::IntSize calculateSize() const;
        virtual MyGUI::IntPoint calculatePosition(const MyGUI::IntSize& size) const;
        MyGUI::IntCoord calculateCoord() const;

        virtual bool isTextInput() { return false; }

    protected:
        virtual void initialize();
        void registerEvents(MyGUI::Widget* w);
        void clearEvents(MyGUI::Widget* w);

        sol::table makeTable() const;
        sol::object keyEvent(MyGUI::KeyCode) const;
        sol::object mouseEvent(int left, int top, MyGUI::MouseButton button) const;

        MyGUI::IntSize parentSize() const;
        virtual MyGUI::IntSize childScalingSize() const;
        virtual MyGUI::IntSize templateScalingSize() const;

        template <typename T>
        T propertyValue(std::string_view name, const T& defaultValue)
        {
            return parseProperty(mProperties, mTemplateProperties, name, defaultValue);
        }

        WidgetExtension* findDeepInTemplates(std::string_view flagName);
        std::vector<WidgetExtension*> findAllInTemplates(std::string_view flagName);

        virtual void updateTemplate();
        virtual void updateProperties();
        virtual void updateChildren() {}

        lua_State* lua() const { return mLua; }

        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.call(argumentFactory(w), w->mLayout);
                    shouldPropagate = res.is<bool>() && res.as<bool>();
                }
                if (w->mParent && w->mPropagateEvents && shouldPropagate)
                    w = w->mParent;
                else
                    w = nullptr;
            }
        }

        bool mForcePosition;
        bool mForceSize;
        // offsets the position and size, used only in C++ widget code
        MyGUI::IntCoord mForcedCoord;
        // position and size in pixels
        MyGUI::IntCoord mAbsoluteCoord;
        // position and size as a ratio of parent size
        MyGUI::FloatCoord mRelativeCoord;
        // negative position offset as a ratio of this widget's size
        // used in combination with relative coord to align the widget, e. g. center it
        MyGUI::FloatSize mAnchor;

        bool mPropagateEvents;
        bool mVisible; // used to implement updateVisible

    private:
        // use lua_State* instead of sol::state_view because MyGUI requires a default constructor
        lua_State* mLua;
        MyGUI::Widget* mWidget;
        std::vector<WidgetExtension*> mChildren;
        std::vector<WidgetExtension*> mTemplateChildren;
        WidgetExtension* mSlot;
        std::map<std::string, LuaUtil::Callback, std::less<>> mCallbacks;
        sol::main_table mLayout;
        sol::main_object mProperties;
        sol::main_object mTemplateProperties;
        sol::main_object mExternal;
        WidgetExtension* mParent;
        bool mTemplateChild;
        bool mElementRoot;

        void attach(WidgetExtension* ext);
        void attachTemplate(WidgetExtension* ext);

        WidgetExtension* findDeep(std::string_view name);
        void findAll(std::string_view flagName, std::vector<WidgetExtension*>& result);

        void updateChildrenCoord();

        void keyPress(MyGUI::Widget*, MyGUI::KeyCode, MyGUI::Char);
        void keyRelease(MyGUI::Widget*, MyGUI::KeyCode);
        void mouseMove(MyGUI::Widget*, int, int);
        void mouseDrag(MyGUI::Widget*, int, int, MyGUI::MouseButton);
        void mouseClick(MyGUI::Widget*);
        void mouseDoubleClick(MyGUI::Widget*);
        void mousePress(MyGUI::Widget*, int, int, MyGUI::MouseButton);
        void mouseRelease(MyGUI::Widget*, int, int, MyGUI::MouseButton);
        void focusGain(MyGUI::Widget*, MyGUI::Widget*);
        void focusLoss(MyGUI::Widget*, MyGUI::Widget*);

        void updateVisible();

        void detachChildrenIf(auto&& predicate, std::vector<WidgetExtension*>& children)
        {
            for (auto it = children.begin(); it != children.end();)
            {
                if (predicate(*it))
                {
                    (*it)->detachFromParent();
                    it = children.erase(it);
                }
                else
                    ++it;
            }
        }
    };

    class LuaWidget : public MyGUI::Widget, public WidgetExtension
    {
        MYGUI_RTTI_DERIVED(LuaWidget)
    };
}

#endif // !OPENMW_LUAUI_WIDGET