The Battle for Wesnoth  1.15.2+dev
scrollbar_container.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2018 by Mark de Wever <koraq@xs4all.nl>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #pragma once
16 
17 #include "gui/core/notifiee.hpp"
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 private:
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  /***** ***** ***** setters / getters for members ***** ****** *****/
141 
142  /** @note shouldn't be called after being shown in a dialog. */
143  void set_vertical_scrollbar_mode(const scrollbar_mode scrollbar_mode);
144 
146  {
147  return vertical_scrollbar_mode_;
148  }
149 
150  /** @note shouldn't be called after being shown in a dialog. */
151  void set_horizontal_scrollbar_mode(const scrollbar_mode scrollbar_mode);
152 
153  scrollbar_mode get_horizontal_scrollbar_mode() const
154  {
155  return horizontal_scrollbar_mode_;
156  }
157 
159  {
160  return content_grid_.get();
161  }
162 
163  const grid* content_grid() const
164  {
165  return content_grid_.get();
166  }
167 
168  const SDL_Rect& content_visible_area() const
169  {
170  return content_visible_area_;
171  }
172 
173  /***** ***** ***** scrollbar helpers ***** ****** *****/
174 
175  /* Returns at_end status of the vertical scrollbar.
176  *
177  */
178  bool vertical_scrollbar_at_end();
179 
180  /**
181  * Returns current position of the vertical scrollbar.
182  *
183  */
184  unsigned get_vertical_scrollbar_item_position() const;
185 
186  /**
187  * Move the vertical scrollbar to a position.
188  *
189  * @param position The position to scroll to.
190  */
191  void set_vertical_scrollbar_item_position(const unsigned position);
192 
193  /**
194  * Returns current position of the horizontal scrollbar.
195  *
196  */
197  unsigned get_horizontal_scrollbar_item_position() const;
198 
199  /**
200  * Move the horizontal scrollbar to a position.
201  *
202  * @param position The position to scroll to.
203  */
204  void set_horizontal_scrollbar_item_position(const unsigned position);
205 
206  /**
207  * Scrolls the vertical scrollbar.
208  *
209  * @param scroll The position to scroll to.
210  */
211  void scroll_vertical_scrollbar(const scrollbar_base::scroll_mode scroll);
212 
213  /**
214  * Scrolls the horizontal scrollbar.
215  *
216  * @param scroll The position to scroll to.
217  */
218  void scroll_horizontal_scrollbar(const scrollbar_base::scroll_mode scroll);
219 
220  /**
221  * Callback when the scrollbar moves (NOTE maybe only one callback needed).
222  * Maybe also make protected or private and add a friend.
223  */
225  {
226  scrollbar_moved();
227  }
228 
230  {
231  scrollbar_moved();
232  }
233 
234 protected:
235  /**
236  * Shows a certain part of the content.
237  *
238  * When the part to be shown is bigger as the visible viewport the top
239  * left of the wanted rect will be the top left of the viewport.
240  *
241  * @param rect The rect which should be visible.
242  */
243  void show_content_rect(const SDL_Rect& rect);
244 
245  /*
246  * The widget contains the following three grids.
247  *
248  * * _vertical_scrollbar_grid containing at least a widget named
249  * _vertical_scrollbar
250  *
251  * * _horizontal_scrollbar_grid containing at least a widget named
252  * _horizontal_scrollbar
253  *
254  * * _content_grid a grid which holds the contents of the area.
255  *
256  * NOTE maybe just hardcode these in the finalize phase...
257  *
258  */
259 
260  /**
261  * Sets the status of the scrollbar buttons.
262  *
263  * This is needed after the scrollbar moves so the status of the buttons
264  * will be active or inactive as needed.
265  */
266  void set_scrollbar_button_status();
267 
268  /**
269  * Notification if the content of a child needs a resize.
270  *
271  * When a resize is required the container first can try to handle it
272  * itself. If it can't honor the request the function will call @ref
273  * window::invalidate_layout().
274  *
275  * @note Calling this function on a widget with size == (0, 0) results
276  * false but doesn't call invalidate_layout, the engine expects to be in
277  * build up phase with the layout already invalidated.
278  *
279  * @param force_sizing If the contents fit do we want to force a
280  * resize? This is needed in the MP lobby since
281  * items might not be properly placed yet.
282  * (The listboxes with the player info need it.)
283  *
284  * @returns True if the resize is handled, false
285  * otherwise.
286  */
287  bool content_resize_request(const bool force_sizing = false);
288 
289  /**
290  * Request from the content to modify the size of the container.
291  *
292  * When the wanted resize fails the function will call @ref
293  * window::invalidate_layout().
294  *
295  *
296  * @note Calling this function on a widget with size == (0, 0) results
297  * false but doesn't call invalidate_layout, the engine expects to be in
298  * build up phase with the layout already invalidated.
299  *
300  * @note If @ref window::get_need_layout() is true the function returns
301  * false and doesn't try to fit the contents since a layout phase will be
302  * triggered anyway.
303  *
304  * @note This function might replace the @ref content_resize_request above.
305  *
306  * @param width_modification The wanted modification to the width:
307  * * negative values reduce width.
308  * * zero leave width as is.
309  * * positive values increase width.
310  * @param height_modification The wanted modification to the height:
311  * * negative values reduce height.
312  * * zero leave height as is.
313  * * positive values increase height.
314  * @param width_modification_pos
315  * The position where the additional content was
316  * inserted/removed, defaults to -1 which means
317  * 'at end'
318  * @param height_modification_pos
319  * The position where the additional content was
320  * inserted/removed, defaults to -1 which means
321  * 'at end'
322  *
323  * @returns True is wanted modification is accepted false
324  * otherwise.
325  */
326  bool content_resize_request(const int width_modification,
327  const int height_modification,
328  const int width_modification_pos = -1,
329  const int height_modification_pos = -1);
330 
331 private:
332  /**
333  * Helper for @ref content_resize_request.
334  *
335  * Handle the width modification.
336  */
337  bool content_resize_width(const int width_modification, const int width_modification_pos);
338 
339  /**
340  * Helper for @ref content_resize_request.
341  *
342  * Handle the height modification.
343  */
344  bool content_resize_height(const int height_modification, const int width_modification_pos);
345 
346 protected:
347  /***** ***** ***** ***** keyboard functions ***** ***** ***** *****/
348 
349  /**
350  * Home key pressed.
351  *
352  * @param modifier The SDL keyboard modifier when the key was
353  * pressed.
354  * @param handled If the function handles the key it should
355  * set handled to true else do not modify it.
356  * This is used in the keyboard event
357  * changing.
358  */
359  virtual void handle_key_home(SDL_Keymod modifier, bool& handled);
360 
361  /**
362  * End key pressed.
363  *
364  * @param modifier The SDL keyboard modifier when the key was
365  * pressed.
366  * @param handled If the function handles the key it should
367  * set handled to true else do not modify it.
368  * This is used in the keyboard event
369  * changing.
370  */
371  virtual void handle_key_end(SDL_Keymod modifier, bool& handled);
372 
373  /**
374  * Page up key pressed.
375  *
376  * @param modifier The SDL keyboard modifier when the key was
377  * pressed.
378  * @param handled If the function handles the key it should
379  * set handled to true else do not modify it.
380  * This is used in the keyboard event
381  * changing.
382  */
383  virtual void handle_key_page_up(SDL_Keymod modifier, bool& handled);
384 
385  /**
386  * Page down key pressed.
387  *
388  * @param modifier The SDL keyboard modifier when the key was
389  * pressed.
390  * @param handled If the function handles the key it should
391  * set handled to true else do not modify it.
392  * This is used in the keyboard event
393  * changing.
394  */
395  virtual void handle_key_page_down(SDL_Keymod modifier, bool& handled);
396 
397  /**
398  * Up arrow key pressed.
399  *
400  * @param modifier The SDL keyboard modifier when the key was
401  * pressed.
402  * @param handled If the function handles the key it should
403  * set handled to true else do not modify it.
404  * This is used in the keyboard event
405  * changing.
406  */
407  virtual void handle_key_up_arrow(SDL_Keymod modifier, bool& handled);
408 
409  /**
410  * Down arrow key pressed.
411  *
412  * @param modifier The SDL keyboard modifier when the key was
413  * pressed.
414  * @param handled If the function handles the key it should
415  * set handled to true else do not modify it.
416  * This is used in the keyboard event
417  * changing.
418  */
419  virtual void handle_key_down_arrow(SDL_Keymod modifier, bool& handled);
420 
421  /**
422  * Left arrow key pressed.
423  *
424  * @param modifier The SDL keyboard modifier when the key was
425  * pressed.
426  * @param handled If the function handles the key it should
427  * set handled to true else do not modify it.
428  * This is used in the keyboard event
429  * changing.
430  */
431  virtual void handle_key_left_arrow(SDL_Keymod modifier, bool& handled);
432 
433  /**
434  * Right arrow key pressed.
435  *
436  * @param modifier The SDL keyboard modifier when the key was
437  * pressed.
438  * @param handled If the function handles the key it should
439  * set handled to true else do not modify it.
440  * This is used in the keyboard event
441  * changing.
442  */
443  virtual void handle_key_right_arrow(SDL_Keymod modifier, bool& handled);
444 
445 private:
446  /**
447  * Possible states of the widget.
448  *
449  * Note the order of the states must be the same as defined in settings.hpp.
450  */
451  enum state_t {
454  };
455 
456  /**
457  * Current state of the widget.
458  *
459  * The state of the widget determines what to render and how the widget
460  * reacts to certain 'events'.
461  */
463 
464  /**
465  * The mode of how to show the scrollbar.
466  *
467  * This value should only be modified before showing, doing it while
468  * showing results in UB.
469  */
470  scrollbar_mode vertical_scrollbar_mode_, horizontal_scrollbar_mode_;
471 
472  /** These are valid after finalize_setup(). */
473  grid *vertical_scrollbar_grid_, *horizontal_scrollbar_grid_;
474 
475  /** These are valid after finalize_setup(). */
476  scrollbar_base *vertical_scrollbar_, *horizontal_scrollbar_;
477 
478  /** The grid that holds the content. */
479  std::unique_ptr<grid> content_grid_;
480 
481  /** Dummy spacer to hold the contents location. */
483 
484  /**
485  * Cache for the visible area for the content.
486  *
487  * The visible area for the content needs to be updated when scrolling.
488  */
490 
491  /** The builder needs to call us so we do our setup. */
492  void finalize_setup(); // FIXME make protected
493 
494  /**
495  * Function for the subclasses to do their setup.
496  *
497  * This function is called at the end of finalize_setup().
498  */
499  virtual void finalize_subclass()
500  {
501  }
502 
503  /** See @ref widget::layout_children. */
504  virtual void layout_children() override;
505 
506  /** See @ref widget::impl_draw_children. */
507  virtual void impl_draw_children(surface& frame_buffer, int x_offset, int y_offset) override;
508 
509  /** See @ref widget::child_populate_dirty_list. */
510  virtual void child_populate_dirty_list(window& caller, const std::vector<widget*>& call_stack) override;
511 
512  /**
513  * Sets the size of the content grid.
514  *
515  * This function normally just updates the content grid but can be
516  * overridden by a subclass.
517  *
518  * @param origin The origin for the content.
519  * @param size The size of the content.
520  */
521  virtual void set_content_size(const point& origin, const point& size);
522 
523  /** Helper function which needs to be called after the scollbar moved. */
524  void scrollbar_moved();
525 
526 public:
527  /** Static type getter that does not rely on the widget being constructed. */
528  static const std::string& type();
529 
530 private:
531  /** See @ref styled_widget::get_control_type. */
532  virtual const std::string& get_control_type() const override;
533 
534  /***** ***** ***** signal handlers ***** ****** *****/
535 
536  void signal_handler_sdl_key_down(
537  const event::ui_event event, bool& handled, const SDL_Keycode key, SDL_Keymod modifier);
538 
539  void signal_handler_sdl_wheel_up(const event::ui_event event, bool& handled);
540  void signal_handler_sdl_wheel_down(const event::ui_event event, bool& handled);
541  void signal_handler_sdl_wheel_left(const event::ui_event event, bool& handled);
542  void signal_handler_sdl_wheel_right(const event::ui_event event, bool& handled);
543  void signal_handler_sdl_touch_motion(const event::ui_event event, bool& handled,
544  const point& position, const point& distance);
545 
546 public:
548  {
549  return horizontal_scrollbar_;
550  }
551 
553  {
554  return vertical_scrollbar_;
555  }
556 
558  {
559  return horizontal_scrollbar_grid_;
560  }
561 
563  {
564  return vertical_scrollbar_grid_;
565  }
566 };
567 
568 } // namespace gui2
scrollbar_base * vertical_scrollbar()
Base class for a scroll bar.
Definition: scrollbar.hpp:40
Like AUTO_VISIBLE, but when not needed upon the initial layout phase, the bars are not shown and no s...
scrollbar_mode vertical_scrollbar_mode_
The mode of how to show the scrollbar.
Base class for all widgets.
Definition: widget.hpp:47
std::unique_ptr< grid > content_grid_
The grid that holds the content.
spacer * content_
Dummy spacer to hold the contents location.
const grid * content_grid() const
state_t state_
Current state of the widget.
virtual void finalize_subclass()
Function for the subclasses to do their setup.
Generic file dialog.
Definition: field-fwd.hpp:22
The listbox class.
Definition: listbox.hpp:40
Base container class.
Definition: grid.hpp:30
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
The scrollbar is shown when the number of items is larger as the visible items.
scrollbar_mode get_horizontal_scrollbar_mode() const
state_t
Possible states of the widget.
void vertical_scrollbar_moved()
Callback when the scrollbar moves (NOTE maybe only one callback needed).
Base class for creating containers with one or two scrollbar(s).
scrollbar_mode get_vertical_scrollbar_mode() const
scrollbar_base * vertical_scrollbar_
These are valid after finalize_setup().
The scrollbar is never shown even notwhen needed.
grid * vertical_scrollbar_grid_
These are valid after finalize_setup().
const SDL_Rect & content_visible_area() const
Holds a 2D point.
Definition: point.hpp:23
Helper to implement private functions without modifying the header.
scroll_mode
scroll &#39;step size&#39;.
Definition: scrollbar.hpp:54
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.
bool find(E event, F functor)
Tests whether an event handler is available.
SDL_Rect content_visible_area_
Cache for the visible area for the content.
An empty widget.
Definition: spacer.hpp:41
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:63
static std::deque< std::string > call_stack
Definition: function.cpp:39
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.
ui_event
The event send to the dispatcher.
Definition: handler.hpp:55
scrollbar_base * horizontal_scrollbar()