The Battle for Wesnoth  1.17.8+dev
widget.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2007 - 2022
3  by Mark de Wever <koraq@xs4all.nl>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #pragma once
17 
18 #include "color.hpp"
21 #include "scripting/lua_ptr.hpp"
22 #include "sdl/point.hpp"
23 #include "sdl/rect.hpp"
24 
25 #include <string>
26 
27 class surface;
28 
29 namespace gui2
30 {
31 /* Data format used by styled_widget::set_members to set settings for a single widget. */
32 using widget_item = std::map<std::string, t_string>;
33 
34 /* Indexes multiple @ref widget_item maps by widget ID. */
35 using widget_data = std::map<std::string, widget_item>;
36 
37 struct builder_widget;
38 class window;
39 class grid;
40 
41 namespace iteration
42 {
43 using walker_ptr = std::unique_ptr<class walker_base>;
44 } // namespace iteration
45 
46 /**
47  * Base class for all widgets.
48  *
49  * From this abstract all other widgets should derive. It contains the minimal
50  * info needed for a real widget and some pure abstract functions which need to
51  * be implemented by classes deriving from this class.
52  */
53 class widget : public event_executor, public event::dispatcher, public enable_lua_ptr<widget>
54 {
55  friend class debug_layout_graph;
56  friend class window; // needed for modifying the layout_size.
57 
58 
59  /***** ***** ***** ***** ***** Types. ***** ***** ***** ***** *****/
60 
61 public:
62  /** Visibility settings done by the user. */
63  enum class visibility
64  {
65  /**
66  * The user sets the widget visible, that means:
67  * * The widget is visible.
68  * * @ref find_at always 'sees' the widget (the active flag is
69  * tested later).
70  * * The widget (if active) handles events (and sends events to
71  * its children).
72  * * The widget is drawn.
73  */
74  visible,
75 
76  /**
77  * The user sets the widget hidden, that means:
78  * * The widget is invisible but keeps its size.
79  * * @ref find_at 'sees' the widget if active is @c false.
80  * * The widget doesn't handle events (and doesn't send events to
81  * its children).
82  */
83  hidden,
84 
85  /**
86  * The user set the widget invisible, that means:
87  * * The widget is invisible and its grid cell has size 0,0.
88  * * @ref find_at never 'sees' the widget.
89  * * The widget doesn't handle events (and doesn't send events to
90  * its children).
91  */
92  invisible
93  };
94 
95  /**
96  * Visibility set by the engine.
97  *
98  * This state only will be used if @ref visible_ is @ref visibility::visible
99  * depending on this state the widget might not be visible after all.
100  */
101  enum class redraw_action
102  {
103  // TODO: draw_manager/hwaccel - are these still useful?
104  /**
105  * The widget is fully visible.
106  *
107  * The widget should be drawn. The entire widget's rectangle
108  * should be redrawn.
109  */
110  full,
111 
112  /**
113  * The widget is partly visible.
114  *
115  * The should be drawn. The rectangle to redraw in determined
116  * by @ref clipping_rectangle_
117  */
118  partly,
119 
120  /**
121  * The widget is not visible.
122  *
123  * The widget should not be drawn.
124  */
125  none
126  };
127 
128  enum class debug_border {
129  /** No border. */
130  none,
131  /** Single-pixel outline. */
132  outline,
133  /** Flood-filled rectangle. */
134  fill,
135  };
136 
137  /***** ***** ***** Constructor and destructor. ***** ***** *****/
138 
139 public:
140  widget(const widget&) = delete;
141  widget& operator=(const widget&) = delete;
142 
143  /** @deprecated use the second overload. */
144  widget();
145 
146  /**
147  * Constructor.
148  *
149  * @param builder The builder object with the settings for the
150  * object.
151  */
152  explicit widget(const builder_widget& builder);
153 
154  virtual ~widget() override;
155 
156 
157  /***** ***** ***** ***** ID functions. ***** ***** ***** *****/
158 
159 public:
160  /*** *** *** *** *** *** Setters and getters. *** *** *** *** *** ***/
161 
162  void set_id(const std::string& id);
163  const std::string& id() const;
164 
165  /*** *** *** *** *** *** *** *** Members. *** *** *** *** *** *** *** ***/
166 
167 private:
168  /**
169  * The id is the unique name of the widget in a certain context.
170  *
171  * This is needed for certain widgets so the engine knows which widget is
172  * which. E.g. it knows which button is pressed and thus which engine action
173  * is connected to the button. This doesn't mean that the id is unique in a
174  * window, e.g. a listbox can have the same id for every row.
175  */
176  std::string id_;
177 
178 
179  /***** ***** ***** ***** Parent functions ***** ***** ***** *****/
180 
181 public:
182  /**
183  * Get the parent window.
184  *
185  * @returns Pointer to parent window.
186  * @retval nullptr No parent window found.
187  */
188  window* get_window();
189 
190  /** The constant version of @ref get_window. */
191  const window* get_window() const;
192 
193  /**
194  * Get the parent grid.
195  *
196  * @returns Pointer to parent grid.
197  * @retval nullptr No parent grid found.
198  */
199  grid* get_parent_grid();
200 
201  /*** *** *** *** *** *** Setters and getters. *** *** *** *** *** ***/
202 
203  void set_parent(widget* parent);
204  widget* parent();
205 
206  /*** *** *** *** *** *** *** *** Members. *** *** *** *** *** *** *** ***/
207 
208 private:
209  /**
210  * The parent widget.
211  *
212  * If the widget has a parent it contains a pointer to the parent, else it
213  * is set to @c nullptr.
214  */
216 
217 
218  /***** ***** ***** ***** Size and layout functions. ***** ***** ***** *****/
219 
220 public:
221  /**
222  * How the layout engine works.
223  *
224  * Every widget has a member @ref layout_size_ which holds the best size in
225  * the current layout phase. When the windows starts the layout phase it
226  * calls @ref layout_initialize which resets this value.
227  *
228  * Every widget has two function to get the best size. @ref get_best_size
229  * tests whether layout_size_ is set and if so returns that value otherwise
230  * it calls @ref calculate_best_size so the size can be updated.
231  *
232  * During the layout phase some functions can modify layout_size_ so the
233  * next call to @ref get_best_size returns the currently best size. This
234  * means that after the layout phase @ref get_best_size still returns this
235  * value.
236  */
237 
238  /**
239  * Initialises the layout phase.
240  *
241  * Clears the initial best size for the widgets.
242  *
243  * See @ref layout_algorithm for more information.
244  *
245  * @param full_initialization For widgets with scrollbars it hides them
246  * unless the mode is
247  * scrollbar_mode::ALWAYS_VISIBLE. For
248  * other widgets this flag is a @em NOP.
249  */
250  virtual void layout_initialize(const bool full_initialization);
251 
252  /**
253  * Tries to reduce the width of a widget.
254  *
255  * This function tries to do it 'friendly' and only use scrollbars or
256  * tries to wrap the widget.
257  *
258  * See @ref layout_algorithm for more information.
259  *
260  * @param maximum_width The wanted maximum width.
261  */
262  virtual void request_reduce_width(const unsigned maximum_width) = 0;
263 
264  /**
265  * Tries to reduce the width of a widget.
266  *
267  * This function does it more aggressively and should only be used when
268  * using scrollbars and wrapping failed.
269  *
270  * @todo Make pure virtual.
271  *
272  * See @ref layout_algorithm for more information.
273  *
274  * @param maximum_width The wanted maximum width.
275  */
276  virtual void demand_reduce_width(const unsigned maximum_width);
277 
278  /**
279  * Tries to reduce the height of a widget.
280  *
281  * This function tries to do it 'friendly' and only use scrollbars.
282  *
283  * @todo Make pure virtual.
284  *
285  * See @ref layout_algorithm for more information.
286  *
287  * @param maximum_height The wanted maximum height.
288  */
289  virtual void request_reduce_height(const unsigned maximum_height);
290 
291  /**
292  * Tries to reduce the height of a widget.
293  *
294  * This function does it more aggressively and should only be used when
295  * using scrollbars failed.
296  *
297  * @todo Make pure virtual.
298  *
299  * See @ref layout_algorithm for more information.
300  *
301  * @param maximum_height The wanted maximum height.
302  */
303  virtual void demand_reduce_height(const unsigned maximum_height);
304 
305  /**
306  * Gets the best size for the widget.
307  *
308  * During the layout phase a best size will be determined, several stages
309  * might change the best size. This function will return the currently best
310  * size as determined during the layout phase.
311  *
312  * @returns The best size for the widget.
313  */
314  point get_best_size() const;
315 
316 private:
317  /**
318  * Calculates the best size.
319  *
320  * This function calculates the best size and ignores the current values in
321  * the layout phase. Note containers can call the @ref get_best_size() of
322  * their children since it is meant to update itself.
323  *
324  * @returns The best size for the widget.
325  */
326  virtual point calculate_best_size() const = 0;
327 
328 public:
329  /**
330  * Whether the mouse move/click event go 'through' this widget.
331  */
332  virtual bool can_mouse_focus() const { return true; }
333  /**
334  * Can the widget wrap.
335  *
336  * When a widget can wrap it can reduce its width by increasing its
337  * height. When a layout is too wide it should first try to wrap and if
338  * that fails it should check the vertical scrollbar status. After wrapping
339  * the height might (probably will) change so the layout engine needs to
340  * recalculate the height after wrapping.
341  */
342  virtual bool can_wrap() const;
343 
344  /**
345  * Sets the origin of the widget.
346  *
347  * This function can be used to move the widget without triggering a
348  * redraw. The location is an absolute position, if a relative move is
349  * required use @ref move.
350  *
351  * @param origin The new origin.
352  */
353  virtual void set_origin(const point& origin);
354 
355  /**
356  * Sets the size of the widget.
357  *
358  * This version is meant to resize a widget, since the origin isn't
359  * modified. This can be used if a widget needs to change its size and the
360  * layout will be fixed later.
361  *
362  * @param size The size of the widget.
363  */
364  virtual void set_size(const point& size);
365 
366  /**
367  * Places the widget.
368  *
369  * This function is normally called by a layout function to do the
370  * placement of a widget.
371  *
372  * @param origin The position of top left of the widget.
373  * @param size The size of the widget.
374  */
375  virtual void place(const point& origin, const point& size);
376 
377  /**
378  * Moves a widget.
379  *
380  * This function can be used to move the widget without queueing a redraw.
381  *
382  * @todo Implement the function to all derived classes.
383  *
384  * @param x_offset The amount of pixels to move the widget in
385  * the x-direction.
386  * @param y_offset The amount of pixels to move the widget in
387  * the y-direction.
388  */
389  virtual void move(const int x_offset, const int y_offset);
390 
391  /**
392  * Sets the horizontal alignment of the widget within its parent grid.
393  *
394  * @param alignment The new alignment.
395  */
396  virtual void set_horizontal_alignment(const std::string& alignment);
397 
398  /**
399  * Sets the horizontal alignment of the widget within its parent grid.
400  *
401  * @param alignment The new alignment.
402  */
403  virtual void set_vertical_alignment(const std::string& alignment);
404 
405  /**
406  * Allows a widget to update its children.
407  *
408  * Before the window is populating the dirty list the widgets can update
409  * their content, which allows delayed initialization. This delayed
410  * initialization is only allowed if the widget resizes itself, not when
411  * being placed.
412  */
413  virtual void layout_children();
414 
415  /**
416  * Returns the screen origin of the widget.
417  *
418  * @returns The origin of the widget.
419  */
420  point get_origin() const;
421 
422  /**
423  * Returns the size of the widget.
424  *
425  * @returns The size of the widget.
426  */
427  point get_size() const;
428 
429  /**
430  * Gets the bounding rectangle of the widget on the screen.
431  *
432  * @returns The bounding rectangle of the widget.
433  */
434  rect get_rectangle() const;
435 
436  /*** *** *** *** *** *** Setters and getters. *** *** *** *** *** ***/
437 
438  int get_x() const;
439 
440  int get_y() const;
441 
442  unsigned get_width() const;
443 
444  unsigned get_height() const;
445 
446 protected:
447  void set_layout_size(const point& size);
448  const point& layout_size() const;
449 
450  /**
451  * Throws away @ref layout_size_.
452  *
453  * Use with care: this function does not recurse to child widgets.
454  *
455  * See @ref layout_algorithm for more information.
456  */
457  void clear_layout_size() { set_layout_size(point()); }
458 
459 public:
460  void set_linked_group(const std::string& linked_group);
461 
462  /*** *** *** *** *** *** *** *** Members. *** *** *** *** *** *** *** ***/
463 
464 private:
465  /** The x-coordinate of the widget on the screen. */
466  int x_;
467 
468  /** The y-coordinate of the widget on the screen. */
469  int y_;
470 
471  /** The width of the widget. */
472  unsigned width_;
473 
474  /** The height of the widget. */
475  unsigned height_;
476 
477  /**
478  * The best size for the widget.
479  *
480  * When 0,0 the real best size is returned, but in the layout phase a
481  * wrapping or a scrollbar might change the best size for that widget.
482  * This variable holds that best value.
483  *
484  * If the widget size hasn't been changed from the default that
485  * calculate_best_size() returns, layout_size_ is (0,0).
486  */
488 
489 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
490 
491  /**
492  * Debug helper to store last value of get_best_size().
493  *
494  * We're mutable so calls can stay const and this is disabled in
495  * production code.
496  */
497  mutable point last_best_size_;
498 
499 #endif
500 
501  /**
502  * The linked group the widget belongs to.
503  *
504  * @todo For now the linked group is initialized when the layout of the
505  * widget is initialized. The best time to set it would be upon adding the
506  * widget in the window. Need to look whether it is possible in a clean way.
507  * Maybe a signal just prior to showing a window where the widget can do
508  * some of it's on things, would also be nice for widgets that need a
509  * finalizer function.
510  */
511  std::string linked_group_;
512 
513 
514  /***** ***** ***** ***** Drawing functions. ***** ***** ***** *****/
515 
516 public:
517  /**
518  * Calculates the blitting rectangle of the widget.
519  *
520  * The blitting rectangle is the entire widget rectangle.
521  *
522  * @returns The drawing rectangle.
523  */
524  SDL_Rect calculate_blitting_rectangle() const;
525 
526  /**
527  * Calculates the clipping rectangle of the widget.
528  *
529  * The clipping rectangle is used then the @ref redraw_action_ is
530  * @ref redraw_action::partly.
531  *
532  * @returns The clipping rectangle.
533  */
534  SDL_Rect calculate_clipping_rectangle() const;
535 
536  /**
537  * Draws the background of a widget.
538  *
539  * Derived should override @ref impl_draw_background instead of changing
540  * this function.
541  */
542  void draw_background();
543 
544  /**
545  * Draws the children of a widget.
546  *
547  * Containers should draw their children when they get this request.
548  *
549  * Derived should override @ref impl_draw_children instead of changing
550  * this function.
551  */
552  void draw_children();
553 
554  /**
555  * Draws the foreground of the widget.
556  *
557  * Some widgets e.g. panel and window have a back and foreground layer this
558  * function requests the drawing of the foreground.
559  *
560  * Derived should override @ref impl_draw_foreground instead of changing
561  * this function.
562  */
563  void draw_foreground();
564 
565 private:
566  /** See @ref draw_background. */
567  virtual void impl_draw_background()
568  {
569  }
570 
571  /** See @ref draw_children. */
572  virtual void impl_draw_children()
573  {
574  }
575 
576  /** See @ref draw_foreground. */
577  virtual void impl_draw_foreground()
578  {
579  }
580 
581 public:
582  /**
583  * Gets the dirty rectangle of the widget.
584  *
585  * Depending on the @ref redraw_action_ it returns the rectangle this
586  * widget dirties while redrawing.
587  *
588  * @returns The dirty rectangle.
589  */
590  SDL_Rect get_dirty_rectangle() const;
591 
592  /**
593  * Sets the visible rectangle for a widget.
594  *
595  * This function sets the @ref redraw_action_ and the
596  * @ref clipping_rectangle_.
597  *
598  * @param rectangle The visible rectangle in screen coordinates.
599  */
600  virtual void set_visible_rectangle(const SDL_Rect& rectangle);
601 
602  /**
603  * Indicates that this widget should be redrawn.
604  *
605  * This function should be called by widgets whenever their visible
606  * state changes.
607  */
608  void queue_redraw();
609 
610  /**
611  * Indicate that specific region of the screen should be redrawn.
612  *
613  * This is in absolute drawing-space coordinates, and not constrained
614  * to the current widget.
615  */
616  void queue_redraw(const rect& region);
617 
618  /*** *** *** *** *** *** Setters and getters. *** *** *** *** *** ***/
619 
620  void set_visible(const visibility visible);
621  visibility get_visible() const;
622 
623  redraw_action get_drawing_action() const;
624 
625  void set_debug_border_mode(const debug_border debug_border_mode);
626 
627  void set_debug_border_color(const color_t debug_border_color);
628 
629  /*** *** *** *** *** *** *** *** Members. *** *** *** *** *** *** *** ***/
630 
631 private:
632  /** Field for the status of the visibility. */
634 
635  /** Field for the action to do on a drawing request. */
637 
638  /** The clipping rectangle if a widget is partly visible. */
640 
641  /**
642  * Mode for drawing the debug border.
643  *
644  * The debug border is a helper border to determine where a widget is
645  * placed. It is only intended for debugging purposes.
646  */
648 
649  /** The color for the debug border. */
651 
652  void draw_debug_border();
653 
654  /***** ***** ***** ***** Query functions ***** ***** ***** *****/
655 
656 public:
657  /**
658  * Returns the widget at the wanted coordinates.
659  *
660  * @param coordinate The coordinate which should be inside the
661  * widget.
662  * @param must_be_active The widget should be active, not all widgets
663  * have an active flag, those who don't ignore
664  * flag.
665  *
666  * @returns The widget with the id.
667  * @retval nullptr No widget at the wanted coordinate found (or
668  * not active if must_be_active was set).
669  */
670  virtual widget* find_at(const point& coordinate,
671  const bool must_be_active);
672 
673  /** The constant version of @ref find_at. */
674  virtual const widget* find_at(const point& coordinate,
675  const bool must_be_active) const;
676 
677  /**
678  * Returns @em a widget with the wanted id.
679  *
680  * @note Since the id might not be unique inside a container there is no
681  * guarantee which widget is returned.
682  *
683  * @param id The id of the widget to find.
684  * @param must_be_active The widget should be active, not all widgets
685  * have an active flag, those who don't ignore
686  * flag.
687  *
688  * @returns The widget with the id.
689  * @retval nullptr No widget with the id found (or not active if
690  * must_be_active was set).
691  */
692  virtual widget* find(const std::string& id, const bool must_be_active);
693 
694  /** The constant version of @ref find. */
695  virtual const widget* find(const std::string& id,
696  const bool must_be_active) const;
697 
698  /**
699  * Does the widget contain the widget.
700  *
701  * Widgets can be containers which have more widgets inside them, this
702  * function will traverse in those child widgets and tries to find the
703  * wanted widget.
704  *
705  * @param widget Pointer to the widget to find.
706  *
707  * @returns Whether or not the @p widget was found.
708  */
709  virtual bool has_widget(const widget& widget) const;
710 
711 private:
712  /** See @ref event::dispatcher::is_at. */
713  virtual bool is_at(const point& coordinate) const override;
714 
715  /**
716  * Is the coordinate inside our area.
717  *
718  * Helper for find_at so also looks at our visibility.
719  *
720  * @param coordinate The coordinate which should be inside the
721  * widget.
722  * @param must_be_active The widget should be active, not all widgets
723  * have an active flag, those who don't ignore
724  * flag.
725  *
726  * @returns Status.
727  */
728  bool is_at(const point& coordinate, const bool must_be_active) const;
729 
730  /**
731  * Is the widget and every single one of its parents visible?
732  *
733  * @param widget Widget where to start the check.
734  * @param must_be_active The widget should be active, not all widgets
735  * have an active flag, those who don't ignore
736  * flag.
737  *
738  * @returns Status.
739  */
740  bool recursive_is_visible(const widget* widget, const bool must_be_active) const;
741 
742  /***** ***** ***** ***** Miscellaneous ***** ***** ****** *****/
743 
744 public:
745  /** Does the widget disable easy close? */
746  virtual bool disable_click_dismiss() const = 0;
747 
748  /** Creates a new walker object on the heap. */
749  virtual iteration::walker_ptr create_walker() = 0;
750 };
751 
752 } // namespace gui2
Contains the info needed to instantiate a widget.
virtual void impl_draw_background()
See draw_background.
Definition: widget.hpp:567
std::unique_ptr< class walker_base > walker_ptr
Definition: widget.hpp:43
redraw_action
Visibility set by the engine.
Definition: widget.hpp:101
Base class for event handling.
Definition: dispatcher.hpp:151
widget * parent_
The parent widget.
Definition: widget.hpp:215
unsigned height_
The height of the widget.
Definition: widget.hpp:475
Base class for all widgets.
Definition: widget.hpp:53
virtual void impl_draw_foreground()
See draw_foreground.
Definition: widget.hpp:577
redraw_action redraw_action_
Field for the action to do on a drawing request.
Definition: widget.hpp:636
point get_size(const locator &i_locator, bool skip_cache)
Returns the width and height of an image.
Definition: picture.cpp:978
std::string id_
The id is the unique name of the widget in a certain context.
Definition: widget.hpp:176
visibility visible_
Field for the status of the visibility.
Definition: widget.hpp:633
Generic file dialog.
Base container class.
Definition: grid.hpp:31
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
std::map< std::string, t_string > widget_item
Definition: widget.hpp:32
virtual void impl_draw_children()
See draw_children.
Definition: widget.hpp:572
The basic class for representing 8-bit RGB or RGBA colour values.
Definition: color.hpp:58
point layout_size_
The best size for the widget.
Definition: widget.hpp:487
std::string linked_group_
The linked group the widget belongs to.
Definition: widget.hpp:511
int y_
The y-coordinate of the widget on the screen.
Definition: widget.hpp:469
Event execution calls.
virtual bool can_mouse_focus() const
Whether the mouse move/click event go &#39;through&#39; this widget.
Definition: widget.hpp:332
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:215
debug_border debug_border_mode_
Mode for drawing the debug border.
Definition: widget.hpp:647
color_t debug_border_color_
The color for the debug border.
Definition: widget.hpp:650
An abstract description of a rectangle with integer coordinates.
Definition: rect.hpp:46
visibility
Visibility settings done by the user.
Definition: widget.hpp:63
Holds a 2D point.
Definition: point.hpp:24
void clear_layout_size()
Throws away layout_size_.
Definition: widget.hpp:457
unsigned width_
The width of the widget.
Definition: widget.hpp:472
SDL_Window * get_window()
Definition: video.cpp:638
Contains the SDL_Rect helper code.
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:193
std::map< std::string, widget_item > widget_data
Definition: widget.hpp:35
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
base class of top level items, the only item which needs to store the final canvases to draw on...
Definition: window.hpp:66
int x_
The x-coordinate of the widget on the screen.
Definition: widget.hpp:466
void fill(const SDL_Rect &rect, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Fill an area with the given colour.
Definition: draw.cpp:41
rect clipping_rectangle_
The clipping rectangle if a widget is partly visible.
Definition: widget.hpp:639