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