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