The Battle for Wesnoth  1.17.0-dev
scrollbar_container.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2021
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 "gui/core/notifiee.hpp"
21 
22 namespace gui2
23 {
24 class spacer;
25 
26 namespace implementation
27 {
28 struct builder_scroll_label;
29 struct builder_scrollbar_panel;
30 struct builder_styled_widget;
31 }
32 
33 /**
34  * Base class for creating containers with one or two scrollbar(s).
35  *
36  * For now users can't instantiate this class directly and needs to use small
37  * wrapper classes. Maybe in the future users can use the class directly.
38  *
39  * @todo events are not yet send to the content grid.
40  */
42 {
43  friend class debug_layout_graph;
44 
47  friend class listbox;
48  friend class tree_view;
50 
51 public:
52  explicit scrollbar_container(const implementation::builder_styled_widget& builder, const std::string& control_type);
53 
55  {
56  }
57 
58  /** The way to handle the showing or hiding of the scrollbar. */
60  /**
61  * The scrollbar is always shown, whether needed or not.
62  */
64 
65  /**
66  * The scrollbar is never shown even notwhen needed. There's also no space
67  * reserved for the scrollbar.
68  */
70 
71  /**
72  * The scrollbar is shown when the number of items is larger as the visible items.
73  * The space for the scrollbar is always reserved, just in case it's needed after
74  * the initial sizing (due to adding items).
75  */
77 
78  /**
79  * Like AUTO_VISIBLE, but when not needed upon the initial layout phase, the bars
80  * are not shown and no space is reserved for them. (The algorithm hides them by
81  * default.
82  */
84  };
85 
86  /***** ***** ***** ***** layout functions ***** ***** ***** *****/
87 
88  /** See @ref widget::layout_initialize. */
89  virtual void layout_initialize(const bool full_initialization) override;
90 
91  /** See @ref widget::request_reduce_height. */
92  virtual void request_reduce_height(const unsigned maximum_height) override;
93 
94  /** See @ref widget::request_reduce_width. */
95  virtual void request_reduce_width(const unsigned maximum_width) override;
96 
97  /**
98  * See @ref widget::can_wrap.
99  *
100  * @note This function is called before the object is finalized.
101  */
102  virtual bool can_wrap() const override;
103 
104 private:
105  /** See @ref widget::calculate_best_size. */
106  virtual point calculate_best_size() const override;
107 
108 public:
109  /** See @ref widget::place. */
110  virtual void place(const point& origin, const point& size) override;
111 
112  /** See @ref widget::set_origin. */
113  virtual void set_origin(const point& origin) override;
114 
115  /** See @ref widget::set_visible_rectangle. */
116  virtual void set_visible_rectangle(const SDL_Rect& rectangle) override;
117 
118  /***** ***** ***** inherited ****** *****/
119 
120  /** See @ref styled_widget::get_active. */
121  virtual bool get_active() const override;
122 
123  /** See @ref styled_widget::get_state. */
124  virtual unsigned get_state() const override;
125 
126  /** See @ref widget::find_at. */
127  virtual widget* find_at(const point& coordinate, const bool must_be_active) override;
128 
129  /** See @ref widget::find_at. */
130  virtual const widget* find_at(const point& coordinate, const bool must_be_active) const override;
131 
132  /** See @ref widget::find. */
133  widget* find(const std::string& id, const bool must_be_active) override;
134 
135  /** See @ref widget::find. */
136  const widget* find(const std::string& id, const bool must_be_active) const override;
137 
138  /** See @ref widget::disable_click_dismiss. */
139  bool disable_click_dismiss() const override;
140 
141  /***** ***** ***** setters / getters for members ***** ****** *****/
142 
143  /** @note shouldn't be called after being shown in a dialog. */
144  void set_vertical_scrollbar_mode(const scrollbar_mode scrollbar_mode);
145 
147  {
148  return vertical_scrollbar_mode_;
149  }
150 
151  /** @note shouldn't be called after being shown in a dialog. */
152  void set_horizontal_scrollbar_mode(const scrollbar_mode scrollbar_mode);
153 
154  scrollbar_mode get_horizontal_scrollbar_mode() const
155  {
156  return horizontal_scrollbar_mode_;
157  }
158 
160  {
161  return content_grid_.get();
162  }
163 
164  const grid* content_grid() const
165  {
166  return content_grid_.get();
167  }
168 
169  const SDL_Rect& content_visible_area() const
170  {
171  return content_visible_area_;
172  }
173 
174  /***** ***** ***** scrollbar helpers ***** ****** *****/
175 
176  /* Returns at_end status of the vertical scrollbar.
177  *
178  */
179  bool vertical_scrollbar_at_end();
180 
181  /**
182  * Returns current position of the vertical scrollbar.
183  *
184  */
185  unsigned get_vertical_scrollbar_item_position() const;
186 
187  /**
188  * Move the vertical scrollbar to a position.
189  *
190  * @param position The position to scroll to.
191  */
192  void set_vertical_scrollbar_item_position(const unsigned position);
193 
194  /**
195  * Returns current position of the horizontal scrollbar.
196  *
197  */
198  unsigned get_horizontal_scrollbar_item_position() const;
199 
200  /**
201  * Move the horizontal scrollbar to a position.
202  *
203  * @param position The position to scroll to.
204  */
205  void set_horizontal_scrollbar_item_position(const unsigned position);
206 
207  /**
208  * Scrolls the vertical scrollbar.
209  *
210  * @param scroll The position to scroll to.
211  */
212  void scroll_vertical_scrollbar(const scrollbar_base::scroll_mode scroll);
213 
214  /**
215  * Scrolls the horizontal scrollbar.
216  *
217  * @param scroll The position to scroll to.
218  */
219  void scroll_horizontal_scrollbar(const scrollbar_base::scroll_mode scroll);
220 
221  /**
222  * Callback when the scrollbar moves (NOTE maybe only one callback needed).
223  * Maybe also make protected or private and add a friend.
224  */
226  {
227  scrollbar_moved();
228  }
229 
231  {
232  scrollbar_moved();
233  }
234 
235 protected:
236  /**
237  * Shows a certain part of the content.
238  *
239  * When the part to be shown is bigger as the visible viewport the top
240  * left of the wanted rect will be the top left of the viewport.
241  *
242  * @param rect The rect which should be visible.
243  */
244  void show_content_rect(const SDL_Rect& rect);
245 
246  /*
247  * The widget contains the following three grids.
248  *
249  * * _vertical_scrollbar_grid containing at least a widget named
250  * _vertical_scrollbar
251  *
252  * * _horizontal_scrollbar_grid containing at least a widget named
253  * _horizontal_scrollbar
254  *
255  * * _content_grid a grid which holds the contents of the area.
256  *
257  * NOTE maybe just hardcode these in the finalize phase...
258  *
259  */
260 
261  /**
262  * Sets the status of the scrollbar buttons.
263  *
264  * This is needed after the scrollbar moves so the status of the buttons
265  * will be active or inactive as needed.
266  */
267  void set_scrollbar_button_status();
268 
269  /**
270  * Notification if the content of a child needs a resize.
271  *
272  * When a resize is required the container first can try to handle it
273  * itself. If it can't honor the request the function will call @ref
274  * window::invalidate_layout().
275  *
276  * @note Calling this function on a widget with size == (0, 0) results
277  * false but doesn't call invalidate_layout, the engine expects to be in
278  * build up phase with the layout already invalidated.
279  *
280  * @param force_sizing If the contents fit do we want to force a
281  * resize? This is needed in the MP lobby since
282  * items might not be properly placed yet.
283  * (The listboxes with the player info need it.)
284  *
285  * @returns True if the resize is handled, false
286  * otherwise.
287  */
288  bool content_resize_request(const bool force_sizing = false);
289 
290  /**
291  * Request from the content to modify the size of the container.
292  *
293  * When the wanted resize fails the function will call @ref
294  * window::invalidate_layout().
295  *
296  *
297  * @note Calling this function on a widget with size == (0, 0) results
298  * false but doesn't call invalidate_layout, the engine expects to be in
299  * build up phase with the layout already invalidated.
300  *
301  * @note If @ref window::get_need_layout() is true the function returns
302  * false and doesn't try to fit the contents since a layout phase will be
303  * triggered anyway.
304  *
305  * @note This function might replace the @ref content_resize_request above.
306  *
307  * @param width_modification The wanted modification to the width:
308  * * negative values reduce width.
309  * * zero leave width as is.
310  * * positive values increase width.
311  * @param height_modification The wanted modification to the height:
312  * * negative values reduce height.
313  * * zero leave height as is.
314  * * positive values increase height.
315  * @param width_modification_pos
316  * The position where the additional content was
317  * inserted/removed, defaults to -1 which means
318  * 'at end'
319  * @param height_modification_pos
320  * The position where the additional content was
321  * inserted/removed, defaults to -1 which means
322  * 'at end'
323  *
324  * @returns True is wanted modification is accepted false
325  * otherwise.
326  */
327  bool content_resize_request(const int width_modification,
328  const int height_modification,
329  const int width_modification_pos = -1,
330  const int height_modification_pos = -1);
331 
332 private:
333  /**
334  * Helper for @ref content_resize_request.
335  *
336  * Handle the width modification.
337  */
338  bool content_resize_width(const int width_modification, const int width_modification_pos);
339 
340  /**
341  * Helper for @ref content_resize_request.
342  *
343  * Handle the height modification.
344  */
345  bool content_resize_height(const int height_modification, const int width_modification_pos);
346 
347 protected:
348  /***** ***** ***** ***** keyboard functions ***** ***** ***** *****/
349 
350  /**
351  * Home key pressed.
352  *
353  * @param modifier The SDL keyboard modifier when the key was
354  * pressed.
355  * @param handled If the function handles the key it should
356  * set handled to true else do not modify it.
357  * This is used in the keyboard event
358  * changing.
359  */
360  virtual void handle_key_home(SDL_Keymod modifier, bool& handled);
361 
362  /**
363  * End key pressed.
364  *
365  * @param modifier The SDL keyboard modifier when the key was
366  * pressed.
367  * @param handled If the function handles the key it should
368  * set handled to true else do not modify it.
369  * This is used in the keyboard event
370  * changing.
371  */
372  virtual void handle_key_end(SDL_Keymod modifier, bool& handled);
373 
374  /**
375  * Page up key pressed.
376  *
377  * @param modifier The SDL keyboard modifier when the key was
378  * pressed.
379  * @param handled If the function handles the key it should
380  * set handled to true else do not modify it.
381  * This is used in the keyboard event
382  * changing.
383  */
384  virtual void handle_key_page_up(SDL_Keymod modifier, bool& handled);
385 
386  /**
387  * Page down key pressed.
388  *
389  * @param modifier The SDL keyboard modifier when the key was
390  * pressed.
391  * @param handled If the function handles the key it should
392  * set handled to true else do not modify it.
393  * This is used in the keyboard event
394  * changing.
395  */
396  virtual void handle_key_page_down(SDL_Keymod modifier, bool& handled);
397 
398  /**
399  * Up arrow key pressed.
400  *
401  * @param modifier The SDL keyboard modifier when the key was
402  * pressed.
403  * @param handled If the function handles the key it should
404  * set handled to true else do not modify it.
405  * This is used in the keyboard event
406  * changing.
407  */
408  virtual void handle_key_up_arrow(SDL_Keymod modifier, bool& handled);
409 
410  /**
411  * Down arrow key pressed.
412  *
413  * @param modifier The SDL keyboard modifier when the key was
414  * pressed.
415  * @param handled If the function handles the key it should
416  * set handled to true else do not modify it.
417  * This is used in the keyboard event
418  * changing.
419  */
420  virtual void handle_key_down_arrow(SDL_Keymod modifier, bool& handled);
421 
422  /**
423  * Left arrow key pressed.
424  *
425  * @param modifier The SDL keyboard modifier when the key was
426  * pressed.
427  * @param handled If the function handles the key it should
428  * set handled to true else do not modify it.
429  * This is used in the keyboard event
430  * changing.
431  */
432  virtual void handle_key_left_arrow(SDL_Keymod modifier, bool& handled);
433 
434  /**
435  * Right arrow key pressed.
436  *
437  * @param modifier The SDL keyboard modifier when the key was
438  * pressed.
439  * @param handled If the function handles the key it should
440  * set handled to true else do not modify it.
441  * This is used in the keyboard event
442  * changing.
443  */
444  virtual void handle_key_right_arrow(SDL_Keymod modifier, bool& handled);
445 
446 private:
447  /**
448  * Possible states of the widget.
449  *
450  * Note the order of the states must be the same as defined in settings.hpp.
451  */
452  enum state_t {
455  };
456 
457  /**
458  * Current state of the widget.
459  *
460  * The state of the widget determines what to render and how the widget
461  * reacts to certain 'events'.
462  */
464 
465  /**
466  * The mode of how to show the scrollbar.
467  *
468  * This value should only be modified before showing, doing it while
469  * showing results in UB.
470  */
471  scrollbar_mode vertical_scrollbar_mode_, horizontal_scrollbar_mode_;
472 
473  /** These are valid after finalize_setup(). */
474  grid *vertical_scrollbar_grid_, *horizontal_scrollbar_grid_;
475 
476  /** These are valid after finalize_setup(). */
477  scrollbar_base *vertical_scrollbar_, *horizontal_scrollbar_;
478 
479  /** The grid that holds the content. */
480  std::unique_ptr<grid> content_grid_;
481 
482  /** Dummy spacer to hold the contents location. */
484 
485  /**
486  * Cache for the visible area for the content.
487  *
488  * The visible area for the content needs to be updated when scrolling.
489  */
491 
492  /** The builder needs to call us so we do our setup. */
493  void finalize_setup(); // FIXME make protected
494 
495  /**
496  * Function for the subclasses to do their setup.
497  *
498  * This function is called at the end of finalize_setup().
499  */
500  virtual void finalize_subclass()
501  {
502  }
503 
504  /** See @ref widget::layout_children. */
505  virtual void layout_children() override;
506 
507  /** See @ref widget::impl_draw_children. */
508  virtual void impl_draw_children(surface& frame_buffer, int x_offset, int y_offset) override;
509 
510  /** See @ref widget::child_populate_dirty_list. */
511  virtual void child_populate_dirty_list(window& caller, const std::vector<widget*>& call_stack) override;
512 
513  /**
514  * Sets the size of the content grid.
515  *
516  * This function normally just updates the content grid but can be
517  * overridden by a subclass.
518  *
519  * @param origin The origin for the content.
520  * @param size The size of the content.
521  */
522  virtual void set_content_size(const point& origin, const point& size);
523 
524  /** Helper function which needs to be called after the scollbar moved. */
525  void scrollbar_moved();
526 
527 public:
528  /** Static type getter that does not rely on the widget being constructed. */
529  static const std::string& type();
530 
531 private:
532  /** See @ref styled_widget::get_control_type. */
533  virtual const std::string& get_control_type() const override;
534 
535  /***** ***** ***** signal handlers ***** ****** *****/
536 
537  void signal_handler_sdl_key_down(
538  const event::ui_event event, bool& handled, const SDL_Keycode key, SDL_Keymod modifier);
539 
540  void signal_handler_sdl_wheel_up(const event::ui_event event, bool& handled);
541  void signal_handler_sdl_wheel_down(const event::ui_event event, bool& handled);
542  void signal_handler_sdl_wheel_left(const event::ui_event event, bool& handled);
543  void signal_handler_sdl_wheel_right(const event::ui_event event, bool& handled);
544  void signal_handler_sdl_touch_motion(const event::ui_event event, bool& handled,
545  const point& position, const point& distance);
546 
547 public:
549  {
550  return horizontal_scrollbar_;
551  }
552 
554  {
555  return vertical_scrollbar_;
556  }
557 
559  {
560  return horizontal_scrollbar_grid_;
561  }
562 
564  {
565  return vertical_scrollbar_grid_;
566  }
567 };
568 
569 } // namespace gui2
scrollbar_base * vertical_scrollbar()
Base class for a scroll bar.
Definition: scrollbar.hpp:41
Like AUTO_VISIBLE, but when not needed upon the initial layout phase, the bars are not shown and no s...
scrollbar_mode vertical_scrollbar_mode_
The mode of how to show the scrollbar.
Base class for all widgets.
Definition: widget.hpp:49
std::unique_ptr< grid > content_grid_
The grid that holds the content.
spacer * content_
Dummy spacer to hold the contents location.
const grid * content_grid() const
state_t state_
Current state of the widget.
virtual void finalize_subclass()
Function for the subclasses to do their setup.
Generic file dialog.
Definition: field-fwd.hpp:23
The listbox class.
Definition: listbox.hpp:43
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
The scrollbar is shown when the number of items is larger as the visible items.
scrollbar_mode get_horizontal_scrollbar_mode() const
static thread_local std::deque< std::string > call_stack
For printing error messages when WFL parsing or evaluation fails, this contains the names of the WFL ...
Definition: function.cpp:47
A tree view is a control that holds several items of the same or different types. ...
Definition: tree_view.hpp:60
state_t
Possible states of the widget.
void vertical_scrollbar_moved()
Callback when the scrollbar moves (NOTE maybe only one callback needed).
Base class for creating containers with one or two scrollbar(s).
scrollbar_mode get_vertical_scrollbar_mode() const
scrollbar_base * vertical_scrollbar_
These are valid after finalize_setup().
The scrollbar is never shown even notwhen needed.
grid * vertical_scrollbar_grid_
These are valid after finalize_setup().
const SDL_Rect & content_visible_area() const
Holds a 2D point.
Definition: point.hpp:24
Helper to implement private functions without modifying the header.
scroll_mode
scroll &#39;step size&#39;.
Definition: scrollbar.hpp:55
A generic container base class.
The scrollbar is always shown, whether needed or not.
scrollbar_mode
The way to handle the showing or hiding of the scrollbar.
SDL_Rect content_visible_area_
Cache for the visible area for the content.
An empty widget to either fill in a widget since no empty items are allowed or to reserve a fixed spa...
Definition: spacer.hpp:49
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:65
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.
ui_event
The event send to the dispatcher.
Definition: handler.hpp:48
scrollbar_base * horizontal_scrollbar()