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