Mon, 01 Nov 2021 06:57:22 +0200
* A bug in widget system is fixed
1247 | 1 | #pragma once |
2 | ||
1250 | 3 | #include "../Layer.h" |
1247 | 4 | #include "../Geometry/Point.h" |
1251 | 5 | #include "../Input/Keyboard.h" |
1624 | 6 | #include "../Property.h" |
1393
dacae7e9c56f
#103: Geometry properties for common geometry members
cemkalyoncu
parents:
1383
diff
changeset
|
7 | #include "../Geometry/PointProperty.h" |
dacae7e9c56f
#103: Geometry properties for common geometry members
cemkalyoncu
parents:
1383
diff
changeset
|
8 | #include "../Geometry/SizeProperty.h" |
1741 | 9 | #include "Dimension.h" |
1247 | 10 | |
11 | namespace Gorgon { namespace UI { | |
1250 | 12 | |
1284 | 13 | class WidgetContainer; |
14 | ||
1247 | 15 | /** |
1284 | 16 | * This class is the base for all widgets. |
17 | */ | |
1465 | 18 | class Widget { |
1741 | 19 | friend class WidgetContainer; |
1744 | 20 | //non virtual functions for VS |
21 | void resize_(const UnitSize &size) { | |
22 | Resize(size); | |
23 | } | |
1394 | 24 | |
1247 | 25 | public: |
26 | ||
1741 | 27 | explicit Widget(const UnitSize &size) : Location(this), Size(this), Tooltip(this), size(size) { |
1393
dacae7e9c56f
#103: Geometry properties for common geometry members
cemkalyoncu
parents:
1383
diff
changeset
|
28 | } |
dacae7e9c56f
#103: Geometry properties for common geometry members
cemkalyoncu
parents:
1383
diff
changeset
|
29 | |
1465 | 30 | Widget(Widget &&) = default; |
1450
0c2bcf1bf63a
#183 ComponentStack CoordinateToValue is fixed
cemkalyoncu
parents:
1394
diff
changeset
|
31 | |
1510 | 32 | virtual ~Widget(); |
1247 | 33 | |
1741 | 34 | /// Moves this widget to the given position. Widget might be |
35 | /// moved by organizers. | |
36 | void Move(UnitDimension x, UnitDimension y) { Move({x, y}); } | |
1247 | 37 | |
1284 | 38 | /// Moves this widget to the given position. |
1741 | 39 | void Move(const UnitPoint &value); |
40 | ||
41 | /// Returns the location of the widget. This is the assigned location | |
42 | /// and may not reflect actual position. Widget might be moved by | |
43 | /// organizers. | |
44 | UnitPoint GetLocation() const { | |
45 | return location; | |
1740 | 46 | } |
1253 | 47 | |
1741 | 48 | /// Returns the current location of the widget in pixels. This might |
49 | /// be different than location that is set. | |
50 | virtual Geometry::Point GetCurrentLocation() const = 0; | |
1253 | 51 | |
1746 | 52 | /// Returns the current location converted to requested units |
53 | UnitPoint GetCalculatedLocation(Dimension::Unit units = Dimension::MilliUnitSize) const { | |
54 | return Convert(units, GetCurrentLocation()); | |
55 | } | |
56 | ||
1284 | 57 | /// Changes the size of the widget. |
1744 | 58 | void Resize(UnitDimension w, UnitDimension h) { Resize({w, h}); }; |
1284 | 59 | |
60 | /// Changes the size of the widget. | |
1741 | 61 | virtual void Resize(const UnitSize &size); |
1253 | 62 | |
1284 | 63 | /// Returns the size of the widget |
1741 | 64 | UnitSize GetSize() const { |
65 | return size; | |
66 | } | |
67 | ||
68 | /// Returns the current size of the widget in pixels. This might be | |
69 | /// different than the size that is set. | |
70 | virtual Geometry::Size GetCurrentSize() const = 0; | |
1284 | 71 | |
1746 | 72 | /// Returns the current size converted to requested units |
73 | UnitSize GetCalculatedSize(Dimension::Unit units = Dimension::MilliUnitSize) const { | |
74 | return Convert(units, GetCurrentSize()); | |
75 | } | |
1741 | 76 | /// Returns the bounds of the widget in pixels. |
77 | Geometry::Bounds GetBounds() const { return {GetCurrentLocation(), GetCurrentSize()}; } | |
1284 | 78 | |
79 | /// Returns the width of the widget | |
1741 | 80 | UnitDimension GetWidth() const { return GetSize().Width; } |
1284 | 81 | |
82 | /// Returns the height of the widget | |
1741 | 83 | UnitDimension GetHeight() const { return GetSize().Height; } |
1284 | 84 | |
1741 | 85 | /// Returns the width of the widget in pixels. |
86 | int GetCurrentWidth() const { return GetCurrentSize().Width; } | |
87 | ||
88 | /// Returns the height of the widget in pixels. | |
89 | int GetCurrentHeight() const { return GetCurrentSize().Height; } | |
90 | ||
1284 | 91 | /// Sets the width of the widget |
1747 | 92 | virtual void SetWidth(UnitDimension width) { Resize(width, GetHeight()); } |
1494
33abdc8b5e5b
#203: All organizers are able to stream widgets and text
cemkalyoncu
parents:
1488
diff
changeset
|
93 | |
1284 | 94 | /// Sets the height of the widget |
1747 | 95 | virtual void SetHeight(UnitDimension height) { Resize(GetWidth(), height); } |
1247 | 96 | |
1249 | 97 | /// Activates the widget. This might perform the action if the |
98 | /// widget is a button, forward the focus if it is a label or | |
99 | /// focus if it is an input field. | |
100 | virtual bool Activate() = 0; | |
1266 | 101 | |
1284 | 102 | /// Removes the widget from its parent. Returns true if the widget |
103 | /// has no parent after the operation. | |
104 | bool Remove(); | |
1249 | 105 | |
1279 | 106 | /// If this widget can be focused currently |
107 | bool AllowFocus() const { return allowfocus() && visible; } | |
108 | ||
1249 | 109 | /// Transfers the focus to this widget. Returns true if the focus |
110 | /// is actually transferred to this widget | |
111 | bool Focus(); | |
112 | ||
113 | /// Removes the focus from this widget if this widget is focused. | |
114 | /// This function will not transfer the focus to another widget. | |
115 | bool Defocus(); | |
1279 | 116 | |
117 | /// Returns if this widget is focused. | |
118 | bool IsFocused() const { return focus; } | |
119 | ||
120 | /// Shows this widget, widgets are visible by default. | |
1503
38acd13739cc
#205 Close button (template, show/hide, enable/disable, events)
cemkalyoncu
parents:
1494
diff
changeset
|
121 | virtual void Show() { SetVisible(true); } |
1279 | 122 | |
123 | /// Hides this widget, when hidden, widgets cannot gain focus | |
1566 | 124 | virtual void Hide() { SetVisible(false); } |
1279 | 125 | |
126 | /// Toggles the visibility state of the widget. | |
1566 | 127 | void ToggleVisible() { SetVisible(!IsVisible ()); } |
1279 | 128 | |
1280 | 129 | /// Changes the visibility of the widget |
1566 | 130 | virtual void SetVisible(bool value); |
1279 | 131 | |
132 | /// Returns if the widget is visible | |
1566 | 133 | virtual bool IsVisible() const { |
1279 | 134 | return visible; |
135 | } | |
1383
c844540dd8c0
#129: EnsureVisible function, tabbing to a widget ensures that widget is scrolled
cemkalyoncu
parents:
1370
diff
changeset
|
136 | |
c844540dd8c0
#129: EnsureVisible function, tabbing to a widget ensures that widget is scrolled
cemkalyoncu
parents:
1370
diff
changeset
|
137 | /// Ensures this widget is visible in its container by scrolling it |
c844540dd8c0
#129: EnsureVisible function, tabbing to a widget ensures that widget is scrolled
cemkalyoncu
parents:
1370
diff
changeset
|
138 | /// into view. This function will not change visibility of the widget |
c844540dd8c0
#129: EnsureVisible function, tabbing to a widget ensures that widget is scrolled
cemkalyoncu
parents:
1370
diff
changeset
|
139 | /// and will return false if the widget is not visible. This function |
c844540dd8c0
#129: EnsureVisible function, tabbing to a widget ensures that widget is scrolled
cemkalyoncu
parents:
1370
diff
changeset
|
140 | /// cannot be expected to take outside factors into account, such as |
c844540dd8c0
#129: EnsureVisible function, tabbing to a widget ensures that widget is scrolled
cemkalyoncu
parents:
1370
diff
changeset
|
141 | /// occlusion. |
c844540dd8c0
#129: EnsureVisible function, tabbing to a widget ensures that widget is scrolled
cemkalyoncu
parents:
1370
diff
changeset
|
142 | bool EnsureVisible() const; |
1252 | 143 | |
1369 | 144 | /// Enables the widget so that the user can interact with it |
145 | void Enable() { SetEnabled(true); } | |
146 | ||
147 | /// Disables the widget so that the user cannot interact with it | |
148 | void Disable() { SetEnabled(false); } | |
149 | ||
150 | /// Toggles enabled state of the widget | |
151 | void ToggleEnabled() { SetEnabled(!IsEnabled()); } | |
152 | ||
153 | /// Sets the enabled state of the widget | |
154 | virtual void SetEnabled(bool value) = 0; | |
155 | ||
156 | /// Returns whether the widget is enabled. | |
157 | virtual bool IsEnabled() const = 0; | |
158 | ||
1284 | 159 | /// Returns if this widget has a parent |
160 | bool HasParent() const { return parent != nullptr; } | |
1252 | 161 | |
1284 | 162 | /// Returns the parent of this widget, throws if it does not have |
163 | /// a parent. | |
164 | WidgetContainer &GetParent() const; | |
1484 | 165 | |
166 | /// Sets floating status of this widget. Floating widgets will not | |
167 | /// be moved or resized by organizers. | |
1488 | 168 | virtual void SetFloating(bool value) { |
1484 | 169 | if(floating != value) |
170 | boundschanged(); | |
171 | ||
172 | floating = value; | |
173 | } | |
174 | ||
175 | /// Returns floating status of this widget. Floating widgets will not | |
176 | /// be moved or resized by organizers. | |
177 | bool IsFloating() const { | |
178 | return floating; | |
179 | } | |
1250 | 180 | |
1284 | 181 | /// This function should be called whenever a key is pressed or released. |
1567 | 182 | virtual bool KeyPressed(Input::Key, float) { return false; } |
1251 | 183 | |
1284 | 184 | /// This function should be called whenever a character is received from |
185 | /// operating system. | |
1567 | 186 | virtual bool CharacterPressed(Char) { return false; } |
1338 | 187 | |
188 | /// For widgets that supports it, this will trigger finalization the user | |
189 | /// interaction. This may cause widget fire change event or reorganize | |
190 | /// itself. | |
191 | virtual bool Done() { return true; } | |
1624 | 192 | |
193 | /// Sets the tooltip to the given value. This will immediately update the display if it is | |
194 | /// currently displayed. | |
195 | void SetTooltip(const std::string &value) { | |
196 | if(tooltip != value) { | |
197 | tooltip = value; | |
198 | TooltipChangedEvent(); | |
199 | } | |
200 | } | |
201 | ||
202 | /// Removes the tooltip from this widget | |
203 | void RemoveTooltip() { | |
204 | SetTooltip(""); | |
205 | } | |
206 | ||
207 | /// Returns the tooltip of this widget. | |
208 | std::string GetTooltip() const { | |
209 | return tooltip; | |
210 | } | |
1251 | 211 | |
1746 | 212 | /// Converts the given size in units to pixels |
1751 | 213 | int Convert(const UnitDimension &val, bool isvertical, bool issize = false) const; |
1746 | 214 | |
215 | /// Converts the given size in units to pixels | |
216 | Geometry::Size Convert(const UnitSize &size) const; | |
217 | ||
218 | /// Converts the given location in units to pixels | |
219 | Geometry::Point Convert(const UnitPoint &location) const; | |
220 | ||
221 | /// Converts the given size in units to requested units. | |
1751 | 222 | UnitDimension Convert(Dimension::Unit target, const UnitDimension &val, bool isvertical, bool issize = false) const; |
1746 | 223 | |
224 | /// Converts the given size in units to requested units. | |
225 | UnitSize Convert(Dimension::Unit target, const UnitSize &size) const; | |
226 | ||
227 | /// Converts the given location in units to requested units. | |
228 | UnitPoint Convert(Dimension::Unit target, const UnitPoint &location) const; | |
229 | ||
1284 | 230 | /// This event will be fired when the widget receives or looses focus. |
1465 | 231 | Event<Widget> FocusEvent = Event<Widget>{*this}; |
1280 | 232 | |
1284 | 233 | /// This event will be fired when the area that the widget occupies on |
234 | /// its container is changed. It will be fired when the widget is hidden | |
235 | /// or shown or its parent is changed. Movement, resize and parent change | |
236 | /// will not trigger this event if the widget is not visible. Similarly, | |
237 | /// if the object does not have a parent movement and resize will not | |
238 | /// trigger this event. Organizers use this event to rearrange widgets, | |
239 | /// thus it is not advisable to remove all handlers from this event. | |
1624 | 240 | Event<Widget> BoundsChangedEvent = Event<Widget>{*this}; |
1356 | 241 | |
1621
0010d369a70c
#300 MouseEnterEvent and MouseLeaveEvent for widgets
cemkalyoncu
parents:
1567
diff
changeset
|
242 | /// This event will be fired when the mouse enters the widget area. |
1624 | 243 | Event<Widget> MouseEnterEvent = Event<Widget>{*this}; |
1621
0010d369a70c
#300 MouseEnterEvent and MouseLeaveEvent for widgets
cemkalyoncu
parents:
1567
diff
changeset
|
244 | |
0010d369a70c
#300 MouseEnterEvent and MouseLeaveEvent for widgets
cemkalyoncu
parents:
1567
diff
changeset
|
245 | /// This event will be fired when the mouse exits the widget area. |
1624 | 246 | Event<Widget> MouseLeaveEvent = Event<Widget>{*this}; |
247 | ||
248 | /// This event will be fired when the tooltip of the widget is changed | |
249 | Event<Widget> TooltipChangedEvent = Event<Widget>{*this}; | |
250 | ||
251 | /// This event will be fired before the widget is destroyed. This event | |
252 | /// is fired in the middle of the destruction. It is not safe to access | |
253 | /// the widget at this point. Only the aliases to this widget should be | |
254 | /// invalidated in the event handlers registered to this function. | |
255 | Event<Widget> DestroyedEvent = Event<Widget>{*this}; | |
1621
0010d369a70c
#300 MouseEnterEvent and MouseLeaveEvent for widgets
cemkalyoncu
parents:
1567
diff
changeset
|
256 | |
1741 | 257 | Geometry::basic_PointProperty<Widget, UnitPoint, &Widget::GetLocation, &Widget::Move> Location; |
1744 | 258 | Geometry::basic_SizeProperty<Widget, UnitSize, &Widget::GetSize, &Widget::resize_> Size; |
1624 | 259 | TextualProperty<Widget, std::string, &Widget::GetTooltip, &Widget::SetTooltip> Tooltip; |
1393
dacae7e9c56f
#103: Geometry properties for common geometry members
cemkalyoncu
parents:
1383
diff
changeset
|
260 | |
1356 | 261 | /// This is a debug feature |
262 | void setname(std::string value) { | |
263 | #ifndef NDEBUG | |
264 | dbgname = value; | |
265 | #endif | |
266 | } | |
267 | ||
268 | #ifndef NDEBUG | |
269 | std::string dbgname; | |
270 | #endif | |
1280 | 271 | |
1249 | 272 | protected: |
1741 | 273 | /// Should resize the widget in pixels |
274 | virtual void resize(const Geometry::Size &size) = 0; | |
275 | ||
276 | /// Should move the widget in pixels | |
277 | virtual void move(const Geometry::Point &value) = 0; | |
278 | ||
1284 | 279 | /// Called when it is about to be added to the given container |
280 | virtual bool addingto(WidgetContainer &) { return true; } | |
281 | ||
282 | /// When called, widget should locate itself on to this layer. | |
283 | virtual void addto(Layer &layer) = 0; | |
1250 | 284 | |
1284 | 285 | /// Called when this widget added to the given container |
1370 | 286 | virtual void addedto(WidgetContainer &container); |
1250 | 287 | |
1284 | 288 | /// When called, widget should remove itself from the given layer |
289 | virtual void removefrom(Layer &layer) = 0; | |
1266 | 290 | |
1284 | 291 | /// Called before this widget is removed from its parent. |
292 | virtual bool removingfrom() { return true; } | |
1250 | 293 | |
1284 | 294 | /// Called after this widget is removed from its parent. |
1286 | 295 | virtual void removed(); |
1250 | 296 | |
1284 | 297 | /// When called, widget should reorder itself in layer hierarchy |
298 | virtual void setlayerorder(Layer &layer, int order) = 0; | |
1266 | 299 | |
1284 | 300 | /// Should return true if the widget can be focused |
1249 | 301 | virtual bool allowfocus() const { return true; } |
302 | ||
303 | /// This is called after the focus is transferred to this widget. | |
1356 | 304 | virtual void focused(); |
1249 | 305 | |
306 | /// Should return true if the widget can loose the focus right now. | |
1279 | 307 | /// Even if you return false, you still might be forced to loose |
308 | /// focus, even without this function getting called. | |
1249 | 309 | virtual bool canloosefocus() const { return true; } |
310 | ||
1279 | 311 | /// This is called after the focus is lost. This is called even if |
312 | /// focus removal is forced. | |
1356 | 313 | virtual void focuslost(); |
1247 | 314 | |
1286 | 315 | /// Call this function when the widget bounds is changed |
316 | virtual void boundschanged(); | |
1487
66f8110078d5
#196: Dropdown closes when it is displaced or lost focus
cemkalyoncu
parents:
1484
diff
changeset
|
317 | |
1566 | 318 | /// Call this function when the bounds of the parent is changed |
1742 | 319 | virtual void parentboundschanged(); |
1566 | 320 | |
1369 | 321 | /// This function is called when the parent's enabled state changes. |
1562 | 322 | virtual void parentenabledchanged(bool /*state*/) { } |
323 | ||
324 | /// This function is called when this widget is made or unmade default. | |
325 | virtual void setdefaultstate(bool /*default*/) { } | |
326 | ||
327 | /// This function is called when this widget is made or unmade cancel. | |
328 | virtual void setcancelstate(bool /*cancel*/) { } | |
1286 | 329 | |
1623 | 330 | virtual void mouseenter(); |
331 | ||
332 | virtual void mouseleave(); | |
1744 | 333 | |
334 | /// This function will recalculate location and the size of the widget | |
335 | /// and if there is a change it will call necessary functions. | |
336 | void calculatebounds(); | |
1623 | 337 | |
1624 | 338 | std::string tooltip; |
1741 | 339 | |
1745 | 340 | /// last set location, used to determine if move is necessary |
341 | Geometry::Point llocation = {0, 0}; | |
342 | ||
343 | /// last set size, used to determine if resize is necessary | |
344 | Geometry::Size lsize = {-1, -1}; | |
1624 | 345 | |
1247 | 346 | private: |
347 | bool visible = true; | |
348 | bool enabled = true; | |
1249 | 349 | bool focus = false; |
1484 | 350 | bool floating= false; |
1741 | 351 | |
1753 | 352 | UnitPoint location = {0, 0}; |
353 | UnitSize size = {-1, -1}; | |
1279 | 354 | |
355 | /// Never call this function | |
356 | virtual void hide() = 0; | |
357 | ||
358 | /// Never call this function | |
359 | virtual void show() = 0; | |
360 | ||
1284 | 361 | WidgetContainer *parent = nullptr; |
1247 | 362 | }; |
363 | ||
364 | ||
1741 | 365 | } |
366 | namespace Widgets { | |
367 | using UI::Pixels; | |
368 | using UI::Percentage; | |
369 | using UI::Units; | |
370 | using UI::Dimension; | |
371 | using UI::UnitDimension; | |
372 | } | |
373 | } |