The Battle for Wesnoth  1.19.7+dev
scrollbar_container.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2024
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 
20 
21 namespace gui2
22 {
23 class spacer;
24 
25 namespace implementation
26 {
27 struct builder_scrollbar_container;
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_scrollbar_container& 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 protected:
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_view id, const bool must_be_active) override;
134 
135  /** See @ref widget::find. */
136  const widget* find(const std::string_view 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  /**
142  * See @ref widget::create_walker.
143  */
144  virtual iteration::walker_ptr create_walker() override;
145 
146  /***** ***** ***** setters / getters for members ***** ****** *****/
147 
148  /** @note shouldn't be called after being shown in a dialog. */
150 
152  {
154  }
155 
156  /** @note shouldn't be called after being shown in a dialog. */
158 
160  {
162  }
163 
165  {
166  return content_grid_.get();
167  }
168 
169  const grid* content_grid() const
170  {
171  return content_grid_.get();
172  }
173 
174  const SDL_Rect& content_visible_area() const
175  {
176  return content_visible_area_;
177  }
178 
179  /***** ***** ***** scrollbar helpers ***** ****** *****/
180 
181  /* Returns at_end status of the vertical scrollbar.
182  *
183  */
185 
186  /**
187  * Returns current position of the vertical scrollbar.
188  *
189  */
190  unsigned get_vertical_scrollbar_item_position() const;
191 
192  /**
193  * Move the vertical scrollbar to a position.
194  *
195  * @param position The position to scroll to.
196  */
197  void set_vertical_scrollbar_item_position(const unsigned position);
198 
199  /**
200  * Returns current position of the horizontal scrollbar.
201  *
202  */
204 
205  /**
206  * Move the horizontal scrollbar to a position.
207  *
208  * @param position The position to scroll to.
209  */
210  void set_horizontal_scrollbar_item_position(const unsigned position);
211 
212  /**
213  * Scrolls the vertical scrollbar.
214  *
215  * @param scroll The position to scroll to.
216  */
218 
219  /**
220  * Scrolls the horizontal scrollbar.
221  *
222  * @param scroll The position to scroll to.
223  */
225 
226  /**
227  * Scrolls the vertical scrollbar by pixel.
228  *
229  * @param pixels The number of pixels the bar scrolls by.
230  */
231  void scroll_vertical_scrollbar_by(const int pixels);
232 
233  /**
234  * Scrolls the horizontal scrollbar by pixel.
235  *
236  * @param pixels The number of pixels the bar scrolls by.
237  */
238  void scroll_horizontal_scrollbar_by(const int pixels);
239 
240  /**
241  * Callback when the scrollbar moves (NOTE maybe only one callback needed).
242  * Maybe also make protected or private and add a friend.
243  */
245  {
246  scrollbar_moved();
247  }
248 
250  {
251  scrollbar_moved();
252  }
253 
254 protected:
255  /**
256  * Shows a certain part of the content.
257  *
258  * When the part to be shown is bigger as the visible viewport the top
259  * left of the wanted rect will be the top left of the viewport.
260  *
261  * @param rect The rect which should be visible.
262  */
263  void show_content_rect(const SDL_Rect& rect);
264 
265  /*
266  * The widget contains the following three grids.
267  *
268  * * _vertical_scrollbar_grid containing at least a widget named
269  * _vertical_scrollbar
270  *
271  * * _horizontal_scrollbar_grid containing at least a widget named
272  * _horizontal_scrollbar
273  *
274  * * _content_grid a grid which holds the contents of the area.
275  *
276  * NOTE maybe just hardcode these in the finalize phase...
277  *
278  */
279 
280  /**
281  * Sets the status of the scrollbar buttons.
282  *
283  * This is needed after the scrollbar moves so the status of the buttons
284  * will be active or inactive as needed.
285  */
287 
288  /**
289  * Notification if the content of a child needs a resize.
290  *
291  * When a resize is required the container first can try to handle it
292  * itself. If it can't honor the request the function will call @ref
293  * window::invalidate_layout().
294  *
295  * @note Calling this function on a widget with size == (0, 0) results
296  * false but doesn't call invalidate_layout, the engine expects to be in
297  * build up phase with the layout already invalidated.
298  *
299  * @param force_sizing If the contents fit do we want to force a
300  * resize? This is needed in the MP lobby since
301  * items might not be properly placed yet.
302  * (The listboxes with the player info need it.)
303  *
304  * @returns True if the resize is handled, false
305  * otherwise.
306  */
307  bool content_resize_request(const bool force_sizing = false);
308 
309  /**
310  * Request from the content to modify the size of the container.
311  *
312  * When the wanted resize fails the function will call @ref
313  * window::invalidate_layout().
314  *
315  *
316  * @note Calling this function on a widget with size == (0, 0) results
317  * false but doesn't call invalidate_layout, the engine expects to be in
318  * build up phase with the layout already invalidated.
319  *
320  * @note If @ref window::get_need_layout() is true the function returns
321  * false and doesn't try to fit the contents since a layout phase will be
322  * triggered anyway.
323  *
324  * @note This function might replace the @ref content_resize_request above.
325  *
326  * @param width_modification The wanted modification to the width:
327  * * negative values reduce width.
328  * * zero leave width as is.
329  * * positive values increase width.
330  * @param height_modification The wanted modification to the height:
331  * * negative values reduce height.
332  * * zero leave height as is.
333  * * positive values increase height.
334  * @param width_modification_pos
335  * The position where the additional content was
336  * inserted/removed, defaults to -1 which means
337  * 'at end'
338  * @param height_modification_pos
339  * The position where the additional content was
340  * inserted/removed, defaults to -1 which means
341  * 'at end'
342  *
343  * @returns True is wanted modification is accepted false
344  * otherwise.
345  */
346  bool content_resize_request(const int width_modification,
347  const int height_modification,
348  const int width_modification_pos = -1,
349  const int height_modification_pos = -1);
350 
351 private:
352  /**
353  * Helper for @ref content_resize_request.
354  *
355  * Handle the width modification.
356  */
357  bool content_resize_width(const int width_modification, const int width_modification_pos);
358 
359  /**
360  * Helper for @ref content_resize_request.
361  *
362  * Handle the height modification.
363  */
364  bool content_resize_height(const int height_modification, const int width_modification_pos);
365 
366 protected:
367  /***** ***** ***** ***** keyboard functions ***** ***** ***** *****/
368 
369  /**
370  * Home key pressed.
371  *
372  * @param modifier The SDL keyboard modifier when the key was
373  * pressed.
374  * @param handled If the function handles the key it should
375  * set handled to true else do not modify it.
376  * This is used in the keyboard event
377  * changing.
378  */
379  virtual void handle_key_home(SDL_Keymod modifier, bool& handled);
380 
381  /**
382  * End key pressed.
383  *
384  * @param modifier The SDL keyboard modifier when the key was
385  * pressed.
386  * @param handled If the function handles the key it should
387  * set handled to true else do not modify it.
388  * This is used in the keyboard event
389  * changing.
390  */
391  virtual void handle_key_end(SDL_Keymod modifier, bool& handled);
392 
393  /**
394  * Page up key pressed.
395  *
396  * @param modifier The SDL keyboard modifier when the key was
397  * pressed.
398  * @param handled If the function handles the key it should
399  * set handled to true else do not modify it.
400  * This is used in the keyboard event
401  * changing.
402  */
403  virtual void handle_key_page_up(SDL_Keymod modifier, bool& handled);
404 
405  /**
406  * Page down key pressed.
407  *
408  * @param modifier The SDL keyboard modifier when the key was
409  * pressed.
410  * @param handled If the function handles the key it should
411  * set handled to true else do not modify it.
412  * This is used in the keyboard event
413  * changing.
414  */
415  virtual void handle_key_page_down(SDL_Keymod modifier, bool& handled);
416 
417  /**
418  * Up arrow key pressed.
419  *
420  * @param modifier The SDL keyboard modifier when the key was
421  * pressed.
422  * @param handled If the function handles the key it should
423  * set handled to true else do not modify it.
424  * This is used in the keyboard event
425  * changing.
426  */
427  virtual void handle_key_up_arrow(SDL_Keymod modifier, bool& handled);
428 
429  /**
430  * Down arrow key pressed.
431  *
432  * @param modifier The SDL keyboard modifier when the key was
433  * pressed.
434  * @param handled If the function handles the key it should
435  * set handled to true else do not modify it.
436  * This is used in the keyboard event
437  * changing.
438  */
439  virtual void handle_key_down_arrow(SDL_Keymod modifier, bool& handled);
440 
441  /**
442  * Left arrow key pressed.
443  *
444  * @param modifier The SDL keyboard modifier when the key was
445  * pressed.
446  * @param handled If the function handles the key it should
447  * set handled to true else do not modify it.
448  * This is used in the keyboard event
449  * changing.
450  */
451  virtual void handle_key_left_arrow(SDL_Keymod modifier, bool& handled);
452 
453  /**
454  * Right arrow key pressed.
455  *
456  * @param modifier The SDL keyboard modifier when the key was
457  * pressed.
458  * @param handled If the function handles the key it should
459  * set handled to true else do not modify it.
460  * This is used in the keyboard event
461  * changing.
462  */
463  virtual void handle_key_right_arrow(SDL_Keymod modifier, bool& handled);
464 
465 protected:
466  /** The builder needs to call us so we do our setup. */
467  void finalize_setup();
468 
469 private:
470  /**
471  * Possible states of the widget.
472  *
473  * Note the order of the states must be the same as defined in settings.hpp.
474  */
475  enum state_t {
478  };
479 
480  /**
481  * Current state of the widget.
482  *
483  * The state of the widget determines what to render and how the widget
484  * reacts to certain 'events'.
485  */
487 
488  /**
489  * The mode of how to show the scrollbar.
490  *
491  * This value should only be modified before showing, doing it while
492  * showing results in UB.
493  */
495 
496  /** These are valid after finalize_setup(). */
498 
499  /** These are valid after finalize_setup(). */
501 
502  /** The grid that holds the content. */
503  std::unique_ptr<grid> content_grid_;
504 
505  /** Dummy spacer to hold the contents location. */
507 
508  /**
509  * Cache for the visible area for the content.
510  *
511  * The visible area for the content needs to be updated when scrolling.
512  */
514 
515  /**
516  * Function for the subclasses to do their setup.
517  *
518  * This function is called at the end of finalize_setup().
519  */
520  virtual void finalize_subclass()
521  {
522  }
523 
524  /** See @ref widget::layout_children. */
525  virtual void layout_children() override;
526 
527  /** See @ref widget::impl_draw_children. */
528  virtual void impl_draw_children() override;
529 
530  /**
531  * Sets the size of the content grid.
532  *
533  * This function normally just updates the content grid but can be
534  * overridden by a subclass.
535  *
536  * @param origin The origin for the content.
537  * @param size The size of the content.
538  */
539  virtual void set_content_size(const point& origin, const point& size);
540 
541  /** Helper function which needs to be called after the scollbar moves by item. */
542  void scrollbar_moved();
543 
544 public:
545  /** To be called after the scollbar moves manually (by pixel) to move the viewport.
546  * Shifts the viewport origin pixels_x left and pixels_y right.*/
547  void move_viewport(const int pixels_x, const int pixels_y);
548 
549  /** Static type getter that does not rely on the widget being constructed. */
550  static const std::string& type();
551 
552 private:
553  /** See @ref styled_widget::get_control_type. */
554  virtual const std::string& get_control_type() const override;
555 
556  /***** ***** ***** signal handlers ***** ****** *****/
557 
559  const event::ui_event event, bool& handled, const SDL_Keycode key, SDL_Keymod modifier);
560 
561  void signal_handler_sdl_wheel_up(const event::ui_event event, bool& handled);
562  void signal_handler_sdl_wheel_down(const event::ui_event event, bool& handled);
563  void signal_handler_sdl_wheel_left(const event::ui_event event, bool& handled);
564  void signal_handler_sdl_wheel_right(const event::ui_event event, bool& handled);
565  void signal_handler_sdl_touch_motion(const event::ui_event event, bool& handled,
566  const point& position, const point& distance);
567 
568 public:
570  {
571  return horizontal_scrollbar_;
572  }
573 
575  {
576  return vertical_scrollbar_;
577  }
578 
580  {
582  }
583 
585  {
587  }
588 };
589 
590 namespace implementation
591 {
593 {
594  explicit builder_scrollbar_container(const config& cfg);
595 
598 };
599 
600 } // namespace implementation
601 
602 } // namespace gui2
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:172
A generic container base class.
Base container class.
Definition: grid.hpp:32
The listbox class.
Definition: listbox.hpp:41
Base class for a scroll bar.
Definition: scrollbar.hpp:39
scroll_mode
scroll 'step size'.
Definition: scrollbar.hpp:52
Base class for creating containers with one or two scrollbar(s).
SDL_Rect content_visible_area_
Cache for the visible area for the content.
virtual void handle_key_home(SDL_Keymod modifier, bool &handled)
Home key pressed.
void set_horizontal_scrollbar_item_position(const unsigned position)
Move the horizontal scrollbar to a position.
void signal_handler_sdl_wheel_left(const event::ui_event event, bool &handled)
virtual void handle_key_down_arrow(SDL_Keymod modifier, bool &handled)
Down arrow key pressed.
virtual bool get_active() const override
See styled_widget::get_active.
void scroll_vertical_scrollbar(const scrollbar_base::scroll_mode scroll)
Scrolls the vertical scrollbar.
virtual void finalize_subclass()
Function for the subclasses to do their setup.
state_t state_
Current state of the widget.
scrollbar_mode
The way to handle the showing or hiding of the scrollbar.
@ ALWAYS_INVISIBLE
The scrollbar is never shown even notwhen needed.
@ ALWAYS_VISIBLE
The scrollbar is always shown, whether needed or not.
@ AUTO_VISIBLE_FIRST_RUN
Like AUTO_VISIBLE, but when not needed upon the initial layout phase, the bars are not shown and no s...
@ AUTO_VISIBLE
The scrollbar is shown when the number of items is larger as the visible items.
virtual const std::string & get_control_type() const override
See styled_widget::get_control_type.
virtual void layout_children() override
See widget::layout_children.
virtual void layout_initialize(const bool full_initialization) override
See widget::layout_initialize.
void set_vertical_scrollbar_mode(const scrollbar_mode scrollbar_mode)
void finalize_setup()
The builder needs to call us so we do our setup.
virtual void set_visible_rectangle(const SDL_Rect &rectangle) override
See widget::set_visible_rectangle.
void signal_handler_sdl_wheel_up(const event::ui_event event, bool &handled)
virtual bool can_wrap() const override
See widget::can_wrap.
virtual void set_origin(const point &origin) override
See widget::set_origin.
static const std::string & type()
Static type getter that does not rely on the widget being constructed.
void signal_handler_sdl_touch_motion(const event::ui_event event, bool &handled, const point &position, const point &distance)
unsigned get_horizontal_scrollbar_item_position() const
Returns current position of the horizontal scrollbar.
void signal_handler_sdl_wheel_right(const event::ui_event event, bool &handled)
spacer * content_
Dummy spacer to hold the contents location.
virtual void place(const point &origin, const point &size) override
See widget::place.
void set_horizontal_scrollbar_mode(const scrollbar_mode scrollbar_mode)
scrollbar_mode get_horizontal_scrollbar_mode() const
void set_scrollbar_button_status()
Sets the status of the scrollbar buttons.
scrollbar_mode get_vertical_scrollbar_mode() const
void move_viewport(const int pixels_x, const int pixels_y)
To be called after the scollbar moves manually (by pixel) to move the viewport.
virtual void handle_key_page_up(SDL_Keymod modifier, bool &handled)
Page up key pressed.
virtual void request_reduce_height(const unsigned maximum_height) override
See widget::request_reduce_height.
virtual iteration::walker_ptr create_walker() override
See widget::create_walker.
unsigned get_vertical_scrollbar_item_position() const
Returns current position of the vertical scrollbar.
void scroll_horizontal_scrollbar(const scrollbar_base::scroll_mode scroll)
Scrolls the horizontal scrollbar.
void signal_handler_sdl_key_down(const event::ui_event event, bool &handled, const SDL_Keycode key, SDL_Keymod modifier)
scrollbar_container(const implementation::builder_scrollbar_container &builder, const std::string &control_type)
void set_vertical_scrollbar_item_position(const unsigned position)
Move the vertical scrollbar to a position.
scrollbar_base * vertical_scrollbar_
These are valid after finalize_setup().
virtual unsigned get_state() const override
See styled_widget::get_state.
virtual point calculate_best_size() const override
See widget::calculate_best_size.
widget * find(const std::string_view id, const bool must_be_active) override
See widget::find.
void scrollbar_moved()
Helper function which needs to be called after the scollbar moves by item.
const grid * content_grid() const
void signal_handler_sdl_wheel_down(const event::ui_event event, bool &handled)
bool content_resize_width(const int width_modification, const int width_modification_pos)
Helper for content_resize_request.
std::unique_ptr< grid > content_grid_
The grid that holds the content.
bool disable_click_dismiss() const override
See widget::disable_click_dismiss.
bool content_resize_height(const int height_modification, const int width_modification_pos)
Helper for content_resize_request.
void scroll_horizontal_scrollbar_by(const int pixels)
Scrolls the horizontal scrollbar by pixel.
virtual void handle_key_page_down(SDL_Keymod modifier, bool &handled)
Page down key pressed.
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
bool content_resize_request(const bool force_sizing=false)
Notification if the content of a child needs a resize.
grid * vertical_scrollbar_grid_
These are valid after finalize_setup().
virtual void impl_draw_children() override
See widget::impl_draw_children.
scrollbar_base * vertical_scrollbar()
const SDL_Rect & content_visible_area() const
scrollbar_base * horizontal_scrollbar_
virtual void set_content_size(const point &origin, const point &size)
Sets the size of the content grid.
void vertical_scrollbar_moved()
Callback when the scrollbar moves (NOTE maybe only one callback needed).
void show_content_rect(const SDL_Rect &rect)
Shows a certain part of the content.
virtual void request_reduce_width(const unsigned maximum_width) override
See widget::request_reduce_width.
scrollbar_base * horizontal_scrollbar()
virtual void handle_key_end(SDL_Keymod modifier, bool &handled)
End key pressed.
virtual void handle_key_up_arrow(SDL_Keymod modifier, bool &handled)
Up arrow key pressed.
virtual void handle_key_left_arrow(SDL_Keymod modifier, bool &handled)
Left arrow key pressed.
virtual void handle_key_right_arrow(SDL_Keymod modifier, bool &handled)
Right arrow key pressed.
scrollbar_mode vertical_scrollbar_mode_
The mode of how to show the scrollbar.
state_t
Possible states of the widget.
void scroll_vertical_scrollbar_by(const int pixels)
Scrolls the vertical scrollbar by pixel.
Base class for all widgets.
Definition: widget.hpp:55
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
std::unique_ptr< class walker_base > walker_ptr
Definition: widget.hpp:44
Generic file dialog.
Contains the implementation details for lexical_cast and shouldn't be used directly.
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:85
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode
scrollbar_container::scrollbar_mode vertical_scrollbar_mode
Helper to implement private functions without modifying the header.
Holds a 2D point.
Definition: point.hpp:25
An abstract description of a rectangle with integer coordinates.
Definition: rect.hpp:47