The Battle for Wesnoth  1.17.12+dev
scrollbar_container.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2022
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. */
149  void set_vertical_scrollbar_mode(const scrollbar_mode scrollbar_mode);
150 
152  {
153  return vertical_scrollbar_mode_;
154  }
155 
156  /** @note shouldn't be called after being shown in a dialog. */
157  void set_horizontal_scrollbar_mode(const scrollbar_mode scrollbar_mode);
158 
159  scrollbar_mode get_horizontal_scrollbar_mode() const
160  {
161  return horizontal_scrollbar_mode_;
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  */
184  bool vertical_scrollbar_at_end();
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  */
203  unsigned get_horizontal_scrollbar_item_position() const;
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  */
217  void scroll_vertical_scrollbar(const scrollbar_base::scroll_mode scroll);
218 
219  /**
220  * Scrolls the horizontal scrollbar.
221  *
222  * @param scroll The position to scroll to.
223  */
224  void scroll_horizontal_scrollbar(const scrollbar_base::scroll_mode scroll);
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  */
272  void set_scrollbar_button_status();
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  */
476  scrollbar_mode vertical_scrollbar_mode_, horizontal_scrollbar_mode_;
477 
478  /** These are valid after finalize_setup(). */
479  grid *vertical_scrollbar_grid_, *horizontal_scrollbar_grid_;
480 
481  /** These are valid after finalize_setup(). */
482  scrollbar_base *vertical_scrollbar_, *horizontal_scrollbar_;
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 
539  void signal_handler_sdl_key_down(
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  {
562  return horizontal_scrollbar_grid_;
563  }
564 
566  {
567  return vertical_scrollbar_grid_;
568  }
569 };
570 
571 } // namespace gui2
scrollbar_base * vertical_scrollbar()
Base class for a scroll bar.
Definition: scrollbar.hpp:41
std::unique_ptr< class walker_base > walker_ptr
Definition: widget.hpp:43
Like AUTO_VISIBLE, but when not needed upon the initial layout phase, the bars are not shown and no s...
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
scrollbar_mode vertical_scrollbar_mode_
The mode of how to show the scrollbar.
Base class for all widgets.
Definition: widget.hpp:53
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.
The listbox class.
Definition: listbox.hpp:45
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
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
An abstract description of a rectangle with integer coordinates.
Definition: rect.hpp:46
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.
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.
scrollbar_base * horizontal_scrollbar()