The Battle for Wesnoth  1.15.2+dev
scrollbar.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/notifier.hpp"
19 #include "sdl/rect.hpp"
20 #include "utils/functional.hpp"
21 
22 namespace gui2
23 {
24 
25 /**
26  * Base class for a scroll bar.
27  *
28  * class will be subclassed for the horizontal and vertical scroll bar.
29  * It might be subclassed for a slider class.
30  *
31  * To make this class generic we talk a lot about offset and length and use
32  * pure virtual functions. The classes implementing us can use the heights or
33  * widths, whichever is applicable.
34  *
35  * The NOTIFY_MODIFIED event is send when the position of scrollbar is changed.
36  *
37  * Common signal handlers:
38  * - connect_signal_notify_modified
39  */
41 {
42  /** @todo Abstract the code so this friend is no longer needed. */
43  friend class slider;
44 
45 public:
46  scrollbar_base(const implementation::builder_styled_widget& builder, const std::string& control_type);
47 
48  /**
49  * scroll 'step size'.
50  *
51  * When scrolling we always scroll a 'fixed' amount, these are the
52  * parameters for these amounts.
53  */
54  enum scroll_mode {
55  BEGIN, /**< Go to begin position. */
56  ITEM_BACKWARDS, /**< Go one item towards the begin. */
57  HALF_JUMP_BACKWARDS, /**< Go half the visible items towards the begin.
58  */
59  JUMP_BACKWARDS, /**< Go the visible items towards the begin. */
60  END, /**< Go to the end position. */
61  ITEM_FORWARD, /**< Go one item towards the end. */
62  HALF_JUMP_FORWARD, /**< Go half the visible items towards the end. */
64  }; /**< Go the visible items towards the end. */
65 
66  /**
67  * Sets the item position.
68  *
69  * We scroll a predefined step.
70  *
71  * @param scroll 'step size' to scroll.
72  */
73  void scroll(const scroll_mode scroll);
74 
75  void scroll_by(const int pixels);
76 
77  /** Is the positioner at the beginning of the scrollbar? */
78  bool at_begin() const
79  {
80  return item_position_ == 0;
81  }
82 
83  /**
84  * Is the positioner at the and of the scrollbar?
85  *
86  * Note both begin and end might be true at the same time.
87  */
88  bool at_end() const
89  {
91  }
92 
93  /** Are all items visible? */
94  bool all_items_visible() const
95  {
96  return visible_items_ >= item_count_;
97  }
98 
99  /***** ***** ***** ***** layout functions ***** ***** ***** *****/
100 
101  /** See @ref widget::place. */
102  virtual void place(const point& origin, const point& size) override;
103 
104  /***** ***** ***** ***** Inherited ***** ***** ***** *****/
105 
106  /** See @ref styled_widget::set_active. */
107  virtual void set_active(const bool active) override;
108 
109  /** See @ref styled_widget::get_active. */
110  virtual bool get_active() const override;
111 
112  /** See @ref styled_widget::get_state. */
113  virtual unsigned get_state() const override;
114 
115  /**
116  * Possible states of the widget.
117  *
118  * Note the order of the states must be the same as defined in settings.hpp.
119  */
120  enum state_t {
125  };
126 
127  /***** ***** ***** setters / getters for members ***** ****** *****/
128 
129  void set_item_count(const unsigned item_count)
130  {
131  item_count_ = item_count;
132  recalculate();
133  }
134  unsigned get_item_count() const
135  {
136  return item_count_;
137  }
138 
139  /**
140  * Note the position isn't guaranteed to be the wanted position
141  * the step size is honored. The value will be rouded down.
142  */
143  void set_item_position(const unsigned item_position);
144  unsigned get_item_position() const
145  {
146  return item_position_;
147  }
148 
149  unsigned get_visible_items() const
150  {
151  return visible_items_;
152  }
153 
154  void set_visible_items(const unsigned visible_items)
155  {
156  visible_items_ = visible_items;
157  recalculate();
158  }
159 
160  unsigned get_step_size() const
161  {
162  return step_size_;
163  }
164 
165  void set_step_size(const unsigned step_size)
166  {
167  // Step size can't be 0!
168  if(step_size == 0) {
169  throw std::invalid_argument("GUI2: scrollbar step size cannot be 0");
170  }
171 
172  step_size_ = step_size;
173  recalculate();
174  }
175 
176  float get_pixels_per_step() const
177  {
178  return pixels_per_step_;
179  }
180 
181 protected:
182  void finalize_setup();
183 
184  unsigned get_positioner_offset() const
185  {
186  return positioner_offset_;
187  }
188 
189  unsigned get_positioner_length() const
190  {
191  return positioner_length_;
192  }
193 
195  {
196  return mouse_;
197  }
198 
199  /**
200  * See @ref styled_widget::update_canvas.
201  *
202  * After a recalculation the canvasses also need to be updated.
203  */
204  virtual void update_canvas() override;
205 
206  /**
207  * Callback for subclasses to get notified about positioner movement.
208  *
209  * @todo This is a kind of hack due to the fact there's no simple
210  * callback slot mechanism. See whether we can implement a generic way to
211  * attach callback which would remove quite some extra code.
212  */
214  {
215  }
216 
217 private:
218  void set_state(const state_t state);
219  /**
220  * Current state of the widget.
221  *
222  * The state of the widget determines what to render and how the widget
223  * reacts to certain 'events'.
224  */
226 
227  /** The number of items the scrollbar 'holds'. */
228  unsigned item_count_;
229 
230  /** The item the positioner is at, starts at 0. */
231  unsigned item_position_;
232 
233  /**
234  * The number of items which can be shown at the same time.
235  *
236  * As long as all items are visible we don't need to scroll.
237  */
238  unsigned visible_items_;
239 
240  /**
241  * Number of items moved when scrolling.
242  *
243  * The step size is the minimum number of items we scroll through when we
244  * move. Normally this value is 1, we can move per item. But for example
245  * sliders want for example to move per 5 items.
246  */
247  unsigned step_size_;
248 
249  /**
250  * Number of pixels per step.
251  *
252  * The number of pixels the positioner needs to move to go to the next step.
253  * Note if there is too little space it can happen 1 pixel does more than 1
254  * step.
255  */
257 
258  /**
259  * The position the mouse was at the last movement.
260  *
261  * This is used during dragging the positioner.
262  */
264 
265  /**
266  * The start offset of the positioner.
267  *
268  * This takes the offset before in consideration.
269  */
271 
272  /** The current length of the positioner. */
274 
275  /***** ***** ***** ***** Pure virtual functions ***** ***** ***** *****/
276 
277  /** Get the length of the scrollbar. */
278  virtual unsigned get_length() const = 0;
279 
280  /** The minimum length of the positioner. */
281  virtual unsigned minimum_positioner_length() const = 0;
282 
283  /** The maximum length of the positioner. */
284  virtual unsigned maximum_positioner_length() const = 0;
285 
286  /**
287  * The number of pixels we can't use since they're used for borders.
288  *
289  * These are the pixels before the widget (left side if horizontal,
290  * top side if vertical).
291  */
292  virtual unsigned offset_before() const = 0;
293 
294  /**
295  * The number of pixels we can't use since they're used for borders.
296  *
297  * These are the pixels after the widget (right side if horizontal,
298  * bottom side if vertical).
299  */
300  virtual unsigned offset_after() const = 0;
301 
302  /**
303  * Is the coordinate on the positioner?
304  *
305  * @param coordinate Coordinate to test whether it's on the
306  * positioner.
307  *
308  * @returns Whether the location on the positioner is.
309  */
310  virtual bool on_positioner(const point& coordinate) const = 0;
311 
312  /**
313  * Is the coordinate on the bar?
314  *
315  * @param coordinate Coordinate to test whether it's on the
316  * bar.
317  *
318  * @returns Whether the location on the bar is.
319  * @retval -1 Coordinate is on the bar before positioner.
320  * @retval 0 Coordinate is not on the bar.
321  * @retval 1 Coordinate is on the bar after the positioner.
322  */
323  virtual int on_bar(const point& coordinate) const = 0;
324 
325  /**
326  * Is the coordinate in the bar's orthogonal range?
327  *
328  * @param coordinate Coordinate to test whether it's in-range.
329  *
330  * @returns Whether the location is in the bar's.
331  * orthogonal range.
332  */
333  virtual bool in_orthogonal_range(const point& coordinate) const = 0;
334 
335  /**
336  * Gets the relevant difference in between the two positions.
337  *
338  * This function is used to determine how much the positioner needs to be
339  * moved.
340  */
341  virtual int get_length_difference(const point& original,
342  const point& current) const = 0;
343 
344  /***** ***** ***** ***** Private functions ***** ***** ***** *****/
345 
346  /**
347  * Updates the scrollbar.
348  *
349  * Needs to be called when something changes eg number of items
350  * or available size. It can only be called once we have a size
351  * otherwise we can't calculate a thing.
352  */
353  void recalculate();
354 
355  /**
356  * Updates the positioner.
357  *
358  * This is a helper for recalculate().
359  */
360  void recalculate_positioner();
361 
362  /**
363  * Moves the positioner.
364  *
365  * @param distance The distance moved, negative to begin, positive
366  * to end.
367  */
368  virtual void move_positioner(const int distance);
369 
370  /***** ***** ***** signal handlers ***** ****** *****/
371 
373  bool& handled,
374  bool& halt);
375 
377  bool& handled,
378  bool& halt,
379  const point& coordinate);
380 
381  void signal_handler_mouse_leave(const event::ui_event event, bool& handled);
382 
384  bool& handled);
385 
387  bool& handled);
388 };
389 
390 } // namespace gui2
Base class for a scroll bar.
Definition: scrollbar.hpp:40
Go one item towards the begin.
Definition: scrollbar.hpp:56
unsigned step_size_
Number of items moved when scrolling.
Definition: scrollbar.hpp:247
state_t
Possible states of the widget.
Definition: scrollbar.hpp:120
virtual void set_active(const bool active) override
See styled_widget::set_active.
Definition: scrollbar.cpp:134
void set_visible_items(const unsigned visible_items)
Definition: scrollbar.hpp:154
unsigned get_visible_items() const
Definition: scrollbar.hpp:149
virtual int get_length_difference(const point &original, const point &current) const =0
Gets the relevant difference in between the two positions.
virtual void update_canvas() override
See styled_widget::update_canvas.
Definition: scrollbar.cpp:178
void signal_handler_mouse_leave(const event::ui_event event, bool &handled)
Definition: scrollbar.cpp:390
Go to begin position.
Definition: scrollbar.hpp:55
virtual unsigned offset_before() const =0
The number of pixels we can&#39;t use since they&#39;re used for borders.
virtual unsigned get_length() const =0
Get the length of the scrollbar.
point get_mouse_position_last_move() const
Definition: scrollbar.hpp:194
state_t state_
Current state of the widget.
Definition: scrollbar.hpp:225
void set_item_position(const unsigned item_position)
Note the position isn&#39;t guaranteed to be the wanted position the step size is honored.
Definition: scrollbar.cpp:151
bool all_items_visible() const
Are all items visible?
Definition: scrollbar.hpp:94
void scroll_by(const int pixels)
Definition: scrollbar.cpp:65
float pixels_per_step_
Number of pixels per step.
Definition: scrollbar.hpp:256
virtual int on_bar(const point &coordinate) const =0
Is the coordinate on the bar?
void set_state(const state_t state)
Definition: scrollbar.cpp:188
float get_pixels_per_step() const
Definition: scrollbar.hpp:176
void set_step_size(const unsigned step_size)
Definition: scrollbar.hpp:165
virtual void place(const point &origin, const point &size) override
See widget::place.
Definition: scrollbar.cpp:126
void recalculate()
Updates the scrollbar.
Definition: scrollbar.cpp:196
bool at_end() const
Is the positioner at the and of the scrollbar?
Definition: scrollbar.hpp:88
bool at_begin() const
Is the positioner at the beginning of the scrollbar?
Definition: scrollbar.hpp:78
Go half the visible items towards the end.
Definition: scrollbar.hpp:62
unsigned visible_items_
The number of items which can be shown at the same time.
Definition: scrollbar.hpp:238
Generic file dialog.
Definition: field-fwd.hpp:22
Go to the end position.
Definition: scrollbar.hpp:60
virtual unsigned maximum_positioner_length() const =0
The maximum length of the positioner.
virtual unsigned minimum_positioner_length() const =0
The minimum length of the positioner.
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
virtual void move_positioner(const int distance)
Moves the positioner.
Definition: scrollbar.cpp:282
scrollbar_base(const implementation::builder_styled_widget &builder, const std::string &control_type)
Definition: scrollbar.cpp:30
void scroll(const scroll_mode scroll)
Sets the item position.
Definition: scrollbar.cpp:70
unsigned positioner_length_
The current length of the positioner.
Definition: scrollbar.hpp:273
virtual void child_callback_positioner_moved()
Callback for subclasses to get notified about positioner movement.
Definition: scrollbar.hpp:213
unsigned positioner_offset_
The start offset of the positioner.
Definition: scrollbar.hpp:270
unsigned get_item_position() const
Definition: scrollbar.hpp:144
point mouse_
The position the mouse was at the last movement.
Definition: scrollbar.hpp:263
Go one item towards the end.
Definition: scrollbar.hpp:61
unsigned get_positioner_offset() const
Definition: scrollbar.hpp:184
void signal_handler_left_button_down(const event::ui_event event, bool &handled)
Definition: scrollbar.cpp:402
virtual bool on_positioner(const point &coordinate) const =0
Is the coordinate on the positioner?
unsigned item_position_
The item the positioner is at, starts at 0.
Definition: scrollbar.hpp:231
Go the visible items towards the begin.
Definition: scrollbar.hpp:59
virtual unsigned offset_after() const =0
The number of pixels we can&#39;t use since they&#39;re used for borders.
unsigned get_item_count() const
Definition: scrollbar.hpp:134
Holds a 2D point.
Definition: point.hpp:23
unsigned item_count_
The number of items the scrollbar &#39;holds&#39;.
Definition: scrollbar.hpp:228
scroll_mode
scroll &#39;step size&#39;.
Definition: scrollbar.hpp:54
Base class for all visible items.
Contains the SDL_Rect helper code.
virtual unsigned get_state() const override
See styled_widget::get_state.
Definition: scrollbar.cpp:146
A slider.
Definition: slider.hpp:33
virtual bool get_active() const override
See styled_widget::get_active.
Definition: scrollbar.cpp:141
unsigned get_step_size() const
Definition: scrollbar.hpp:160
Go half the visible items towards the begin.
Definition: scrollbar.hpp:57
virtual bool in_orthogonal_range(const point &coordinate) const =0
Is the coordinate in the bar&#39;s orthogonal range?
void recalculate_positioner()
Updates the positioner.
Definition: scrollbar.cpp:268
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
void set_item_count(const unsigned item_count)
Definition: scrollbar.hpp:129
unsigned get_positioner_length() const
Definition: scrollbar.hpp:189
void signal_handler_mouse_enter(const event::ui_event event, bool &handled, bool &halt)
Definition: scrollbar.cpp:334
void signal_handler_mouse_motion(const event::ui_event event, bool &handled, bool &halt, const point &coordinate)
Definition: scrollbar.cpp:344
ui_event
The event send to the dispatcher.
Definition: handler.hpp:55
void signal_handler_left_button_up(const event::ui_event event, bool &handled)
Definition: scrollbar.cpp:433