The Battle for Wesnoth  1.17.21+dev
scrollbar_container.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2023
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  /**
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  * Callback when the scrollbar moves (NOTE maybe only one callback needed).
228  * Maybe also make protected or private and add a friend.
229  */
231  {
232  scrollbar_moved();
233  }
234 
236  {
237  scrollbar_moved();
238  }
239 
240 protected:
241  /**
242  * Shows a certain part of the content.
243  *
244  * When the part to be shown is bigger as the visible viewport the top
245  * left of the wanted rect will be the top left of the viewport.
246  *
247  * @param rect The rect which should be visible.
248  */
249  void show_content_rect(const SDL_Rect& rect);
250 
251  /*
252  * The widget contains the following three grids.
253  *
254  * * _vertical_scrollbar_grid containing at least a widget named
255  * _vertical_scrollbar
256  *
257  * * _horizontal_scrollbar_grid containing at least a widget named
258  * _horizontal_scrollbar
259  *
260  * * _content_grid a grid which holds the contents of the area.
261  *
262  * NOTE maybe just hardcode these in the finalize phase...
263  *
264  */
265 
266  /**
267  * Sets the status of the scrollbar buttons.
268  *
269  * This is needed after the scrollbar moves so the status of the buttons
270  * will be active or inactive as needed.
271  */
273 
274  /**
275  * Notification if the content of a child needs a resize.
276  *
277  * When a resize is required the container first can try to handle it
278  * itself. If it can't honor the request the function will call @ref
279  * window::invalidate_layout().
280  *
281  * @note Calling this function on a widget with size == (0, 0) results
282  * false but doesn't call invalidate_layout, the engine expects to be in
283  * build up phase with the layout already invalidated.
284  *
285  * @param force_sizing If the contents fit do we want to force a
286  * resize? This is needed in the MP lobby since
287  * items might not be properly placed yet.
288  * (The listboxes with the player info need it.)
289  *
290  * @returns True if the resize is handled, false
291  * otherwise.
292  */
293  bool content_resize_request(const bool force_sizing = false);
294 
295  /**
296  * Request from the content to modify the size of the container.
297  *
298  * When the wanted resize fails the function will call @ref
299  * window::invalidate_layout().
300  *
301  *
302  * @note Calling this function on a widget with size == (0, 0) results
303  * false but doesn't call invalidate_layout, the engine expects to be in
304  * build up phase with the layout already invalidated.
305  *
306  * @note If @ref window::get_need_layout() is true the function returns
307  * false and doesn't try to fit the contents since a layout phase will be
308  * triggered anyway.
309  *
310  * @note This function might replace the @ref content_resize_request above.
311  *
312  * @param width_modification The wanted modification to the width:
313  * * negative values reduce width.
314  * * zero leave width as is.
315  * * positive values increase width.
316  * @param height_modification The wanted modification to the height:
317  * * negative values reduce height.
318  * * zero leave height as is.
319  * * positive values increase height.
320  * @param width_modification_pos
321  * The position where the additional content was
322  * inserted/removed, defaults to -1 which means
323  * 'at end'
324  * @param height_modification_pos
325  * The position where the additional content was
326  * inserted/removed, defaults to -1 which means
327  * 'at end'
328  *
329  * @returns True is wanted modification is accepted false
330  * otherwise.
331  */
332  bool content_resize_request(const int width_modification,
333  const int height_modification,
334  const int width_modification_pos = -1,
335  const int height_modification_pos = -1);
336 
337 private:
338  /**
339  * Helper for @ref content_resize_request.
340  *
341  * Handle the width modification.
342  */
343  bool content_resize_width(const int width_modification, const int width_modification_pos);
344 
345  /**
346  * Helper for @ref content_resize_request.
347  *
348  * Handle the height modification.
349  */
350  bool content_resize_height(const int height_modification, const int width_modification_pos);
351 
352 protected:
353  /***** ***** ***** ***** keyboard functions ***** ***** ***** *****/
354 
355  /**
356  * Home key pressed.
357  *
358  * @param modifier The SDL keyboard modifier when the key was
359  * pressed.
360  * @param handled If the function handles the key it should
361  * set handled to true else do not modify it.
362  * This is used in the keyboard event
363  * changing.
364  */
365  virtual void handle_key_home(SDL_Keymod modifier, bool& handled);
366 
367  /**
368  * End key pressed.
369  *
370  * @param modifier The SDL keyboard modifier when the key was
371  * pressed.
372  * @param handled If the function handles the key it should
373  * set handled to true else do not modify it.
374  * This is used in the keyboard event
375  * changing.
376  */
377  virtual void handle_key_end(SDL_Keymod modifier, bool& handled);
378 
379  /**
380  * Page up key pressed.
381  *
382  * @param modifier The SDL keyboard modifier when the key was
383  * pressed.
384  * @param handled If the function handles the key it should
385  * set handled to true else do not modify it.
386  * This is used in the keyboard event
387  * changing.
388  */
389  virtual void handle_key_page_up(SDL_Keymod modifier, bool& handled);
390 
391  /**
392  * Page down key pressed.
393  *
394  * @param modifier The SDL keyboard modifier when the key was
395  * pressed.
396  * @param handled If the function handles the key it should
397  * set handled to true else do not modify it.
398  * This is used in the keyboard event
399  * changing.
400  */
401  virtual void handle_key_page_down(SDL_Keymod modifier, bool& handled);
402 
403  /**
404  * Up arrow key pressed.
405  *
406  * @param modifier The SDL keyboard modifier when the key was
407  * pressed.
408  * @param handled If the function handles the key it should
409  * set handled to true else do not modify it.
410  * This is used in the keyboard event
411  * changing.
412  */
413  virtual void handle_key_up_arrow(SDL_Keymod modifier, bool& handled);
414 
415  /**
416  * Down arrow key pressed.
417  *
418  * @param modifier The SDL keyboard modifier when the key was
419  * pressed.
420  * @param handled If the function handles the key it should
421  * set handled to true else do not modify it.
422  * This is used in the keyboard event
423  * changing.
424  */
425  virtual void handle_key_down_arrow(SDL_Keymod modifier, bool& handled);
426 
427  /**
428  * Left arrow key pressed.
429  *
430  * @param modifier The SDL keyboard modifier when the key was
431  * pressed.
432  * @param handled If the function handles the key it should
433  * set handled to true else do not modify it.
434  * This is used in the keyboard event
435  * changing.
436  */
437  virtual void handle_key_left_arrow(SDL_Keymod modifier, bool& handled);
438 
439  /**
440  * Right arrow key pressed.
441  *
442  * @param modifier The SDL keyboard modifier when the key was
443  * pressed.
444  * @param handled If the function handles the key it should
445  * set handled to true else do not modify it.
446  * This is used in the keyboard event
447  * changing.
448  */
449  virtual void handle_key_right_arrow(SDL_Keymod modifier, bool& handled);
450 
451 private:
452  /**
453  * Possible states of the widget.
454  *
455  * Note the order of the states must be the same as defined in settings.hpp.
456  */
457  enum state_t {
460  };
461 
462  /**
463  * Current state of the widget.
464  *
465  * The state of the widget determines what to render and how the widget
466  * reacts to certain 'events'.
467  */
469 
470  /**
471  * The mode of how to show the scrollbar.
472  *
473  * This value should only be modified before showing, doing it while
474  * showing results in UB.
475  */
477 
478  /** These are valid after finalize_setup(). */
480 
481  /** These are valid after finalize_setup(). */
483 
484  /** The grid that holds the content. */
485  std::unique_ptr<grid> content_grid_;
486 
487  /** Dummy spacer to hold the contents location. */
489 
490  /**
491  * Cache for the visible area for the content.
492  *
493  * The visible area for the content needs to be updated when scrolling.
494  */
496 
497  /** The builder needs to call us so we do our setup. */
498  void finalize_setup(); // FIXME make protected
499 
500  /**
501  * Function for the subclasses to do their setup.
502  *
503  * This function is called at the end of finalize_setup().
504  */
505  virtual void finalize_subclass()
506  {
507  }
508 
509  /** See @ref widget::layout_children. */
510  virtual void layout_children() override;
511 
512  /** See @ref widget::impl_draw_children. */
513  virtual void impl_draw_children() override;
514 
515  /**
516  * Sets the size of the content grid.
517  *
518  * This function normally just updates the content grid but can be
519  * overridden by a subclass.
520  *
521  * @param origin The origin for the content.
522  * @param size The size of the content.
523  */
524  virtual void set_content_size(const point& origin, const point& size);
525 
526  /** Helper function which needs to be called after the scollbar moved. */
527  void scrollbar_moved();
528 
529 public:
530  /** Static type getter that does not rely on the widget being constructed. */
531  static const std::string& type();
532 
533 private:
534  /** See @ref styled_widget::get_control_type. */
535  virtual const std::string& get_control_type() const override;
536 
537  /***** ***** ***** signal handlers ***** ****** *****/
538 
540  const event::ui_event event, bool& handled, const SDL_Keycode key, SDL_Keymod modifier);
541 
542  void signal_handler_sdl_wheel_up(const event::ui_event event, bool& handled);
543  void signal_handler_sdl_wheel_down(const event::ui_event event, bool& handled);
544  void signal_handler_sdl_wheel_left(const event::ui_event event, bool& handled);
545  void signal_handler_sdl_wheel_right(const event::ui_event event, bool& handled);
546  void signal_handler_sdl_touch_motion(const event::ui_event event, bool& handled,
547  const point& position, const point& distance);
548 
549 public:
551  {
552  return horizontal_scrollbar_;
553  }
554 
556  {
557  return vertical_scrollbar_;
558  }
559 
561  {
563  }
564 
566  {
568  }
569 };
570 
571 } // namespace gui2
A generic container base class.
Base container class.
Definition: grid.hpp:32
The listbox class.
Definition: listbox.hpp:46
Base class for a scroll bar.
Definition: scrollbar.hpp:42
scroll_mode
scroll 'step size'.
Definition: scrollbar.hpp:55
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
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 moved.
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.
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.
An empty widget to either fill in a widget since no empty items are allowed or to reserve a fixed spa...
Definition: spacer.hpp:50
A tree view is a control that holds several items of the same or different types.
Definition: tree_view.hpp:61
Base class for all widgets.
Definition: widget.hpp:54
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
std::unique_ptr< class walker_base > walker_ptr
Definition: widget.hpp:43
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:87
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