1 /** @file widget.h  Base class for widgets.
2  *
3  * @authors Copyright © 2005-2017 Jaakko Keränen <jaakko.keranen@iki.fi>
4  * @authors Copyright © 2005-2014 Daniel Swanson <danij@dengine.net>
5  *
6  * @par License
7  * GPL: http://www.gnu.org/licenses/gpl.html
8  *
9  * <small>This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by the
11  * Free Software Foundation; either version 2 of the License, or (at your
12  * option) any later version. This program is distributed in the hope that it
13  * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15  * Public License for more details. You should have received a copy of the GNU
16  * General Public License along with this program; if not, write to the Free
17  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18  * 02110-1301 USA</small>
19  */
20 
21 #ifndef LIBCOMMON_UI_WIDGET
22 #define LIBCOMMON_UI_WIDGET
23 
24 #include "doomsday.h"
25 
26 #include <QFlags>
27 #include <QVariant>
28 #include <de/Rectangle>
29 #include <de/String>
30 #include "common.h"
31 
32 namespace common {
33 namespace menu {
34 
35 class Page;
36 
37 /**
38  * Base class from which all menu widgets must be derived.
39  *
40  * @ingroup menu
41  */
42 class Widget
43 {
44 public:
45     /// Required Page is presently missing. @ingroup errors
46     DENG2_ERROR(MissingPageError);
47 
48     enum Flag
49     {
50         Hidden        = 0x1,
51         Disabled      = 0x2,    ///< Currently disabled (non-interactive).
52         Paused        = 0x4,    ///< Paused widgets do not tick.
53 
54         Active        = 0x10,   ///< In the active state (meaning is widget specific).
55         Focused       = 0x20,   ///< Currently focused.
56         NoFocus       = 0x40,   ///< Can never receive focus.
57         DefaultFocus  = 0x80,   ///< Has focus by default.
58         PositionFixed = 0x100,  ///< XY position is fixed and predefined; automatic layout does not apply.
59         LayoutOffset  = 0x200,  ///< Predefined XY position is applied to the dynamic layout origin.
60 
61         LeftColumn    = 0x400,  ///< Widget is laid out to the page's left column.
62         RightColumn   = 0x800,  ///< Widget is laid out to the page's right column.
63 
64         /// @todo We need a new dynamic id mechanism.
65         Id7           = 0x1000000,
66         Id6           = 0x2000000,
67         Id5           = 0x4000000,
68         Id4           = 0x8000000,
69         Id3           = 0x10000000,
70         Id2           = 0x20000000,
71         Id1           = 0x40000000,
72         Id0           = 0x80000000,
73 
74         DefaultFlags  = 0
75     };
76     Q_DECLARE_FLAGS(Flags, Flag)
77 
78     /**
79      * Logical Action identifiers. Associated with/to events which trigger user-definable
80      * callbacks according to widget-specific logic.
81      */
82     enum Action
83     {
84         Modified,     ///< The internal "modified" status was changed.
85         Deactivated,  ///< Deactivated i.e., no longer active.
86         Activated,    ///< Becomes "active".
87         Closed,       ///< Normally means changed-state to be discarded.
88         FocusLost,    ///< Loses selection "focus".
89         FocusGained,  ///< Gains selection "focus".
90     };
91 
92     typedef void (*ActionCallback)  (Widget &, Action);
93     typedef void (*OnTickCallback)  (Widget &);
94 
95     typedef int (*CommandResponder) (Widget &, menucommand_e);
96 
97 public:
98     Widget();
99     virtual ~Widget();
100 
DENG2_CAST_METHODS()101     DENG2_CAST_METHODS()
102 
103     virtual void draw() const {}
104 
105     /// Update the geometry for this widget.
updateGeometry()106     virtual void updateGeometry() {}
107 
108     /// Respond to the given (input) event @a ev.
109     /// @return  @c true if the event is eaten.
110     virtual int handleEvent(event_t const &ev);
111 
112     /// Respond to the given (input) event @a ev.
113     /// @return  @c true if the event is eaten.
114     virtual int handleEvent_Privileged(event_t const &ev);
115 
116     /// Respond to the given menu @a command.
117     /// @return  @c true if the command was eaten.
118     virtual int handleCommand(menucommand_e command);
119 
120     /// Configure a custom command responder to override the default mechanism.
121     Widget &setCommandResponder(CommandResponder newResponder);
122 
123     /// Delegate handling of @a command to the relevant responder.
124     /// @return  @c true if the command was eaten.
125     int cmdResponder(menucommand_e command);
126 
127     /// Process time (the "tick") for this object.
128     virtual void tick();
129 
130     Widget &setOnTickCallback(OnTickCallback newCallback);
131 
132     /**
133      * Returns @c true if a Page is presently attributed to the widget.
134      * @see page(), setPage()
135      */
136     bool hasPage() const;
137 
138     /**
139      * Change the Page attributed to the widget to @a newPage. Not that this will only
140      * affect the Widget > Page side of the relationship.
141      *
142      * @param newPage  New Page to attribute. Use @c 0 to clear. Ownership unaffected.
143      *
144      * @see page(), hasPage()
145      */
146     Widget &setPage(Page *newPage);
147 
148     /**
149      * Returns a reference to the Page presently attributed to the widget.
150      * @see hasPage()
151      */
152     Page &page() const;
153 
154     /// Convenient method of returning a pointer to the presently attributed Page, if any.
pagePtr()155     inline Page *pagePtr() const { return hasPage()? &page() : 0; }
156 
157     /**
158      * Sets or clears one or more flags.
159      *
160      * @param flags      Flags to modify.
161      * @param operation  Operation to perform on the flags.
162      *
163      * @return  Reference to this Widget.
164      */
165     Widget &setFlags(Flags flagsToChange, de::FlagOp operation = de::SetFlags);
166     Flags flags() const;
167 
setLeft()168     Widget &setLeft() { return setFlags(LeftColumn); }
setRight()169     Widget &setRight() { return setFlags(RightColumn); }
170 
isActive()171     inline bool isActive()   const { return flags() & Active;   }
isFocused()172     inline bool isFocused()  const { return flags() & Focused;  }
isHidden()173     inline bool isHidden()   const { return flags() & Hidden;   }
isDisabled()174     inline bool isDisabled() const { return flags() & Disabled; }
isPaused()175     inline bool isPaused()   const { return flags() & Paused;   }
176 
177     /**
178      * Retrieve the current geometry of widget within the two-dimensioned
179      * coordinate space of the owning object.
180      *
181      * @return  Rectangluar region of the parent space.
182      */
183     de::Rectanglei &geometry();
184     de::Rectanglei const &geometry() const;
185 
186     /**
187      * Retreive the current fixed origin coordinates.
188      *
189      * @param ob  MNObject-derived instance.
190      * @return  Fixed origin.
191      */
192     de::Vector2i fixedOrigin() const;
fixedX()193     inline int fixedX() const { return fixedOrigin().x; }
fixedY()194     inline int fixedY() const { return fixedOrigin().y; }
195 
196     Widget &setFixedOrigin(de::Vector2i const &newOrigin);
197     Widget &setFixedX(int x);
198     Widget &setFixedY(int y);
199 
200     Widget &setGroup(int newGroup);
201     int group() const;
202 
203     Widget &setShortcut(int ddkey);
204     int shortcut();
205 
206     Widget &setColor(int newPageColor);
207     int color() const;
208 
209     Widget &setFont(int newPageFont);
210     int font() const;
211 
212     Widget &setHelpInfo(de::String newHelpInfo);
213     de::String const &helpInfo() const;
214 
215     /**
216      * Returns @c true if a triggerable action is defined for the specified @a id.
217      */
218     bool hasAction(Action id) const;
219 
220     Widget &setAction(Action id, ActionCallback callback);
221 
222     /**
223      * Trigger the ActionCallback associated with @a id, if any.
224      * @param id  Unique identifier of the action.
225      */
226     void execAction(Action id);
227 
228     Widget &setUserValue(QVariant const &newValue);
229     QVariant const &userValue() const;
230 
231     Widget &setUserValue2(QVariant const &newValue);
232     QVariant const &userValue2() const;
233 
234     float scrollingFadeout() const;
235     float scrollingFadeout(int yTop, int yBottom) const;
236     de::Vector4f selectionFlashColor(const de::Vector4f &noFlashColor) const;
237 
238     virtual void pageActivated();
239 
240     static de::String labelText(const de::String &text, const de::String &context = "Menu Label");
241 
242 private:
243     DENG2_PRIVATE(d)
244 };
245 
246 Q_DECLARE_OPERATORS_FOR_FLAGS(Widget::Flags)
247 
248 } // namespace menu
249 } // namespace common
250 
251 #endif // LIBCOMMON_UI_WIDGET
252