The Battle for Wesnoth  1.15.2+dev
slider_base.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 
20 #include "utils/functional.hpp"
21 
22 namespace gui2
23 {
24 /**
25  * Base class for a scroll bar.
26  *
27  * class will be subclassed for the horizontal and vertical scroll bar.
28  * It might be subclassed for a slider class.
29  *
30  * To make this class generic we talk a lot about offset and length and use
31  * pure virtual functions. The classes implementing us can use the heights or
32  * widths, whichever is applicable.
33  *
34  * The NOTIFY_MODIFIED event is send when the position of slider is changed.
35  *
36  * Common signal handlers:
37  * - connect_signal_notify_modified
38  */
39 class slider_base : public styled_widget
40 {
41 public:
42  slider_base(const implementation::builder_styled_widget& builder, const std::string& control_type);
43 
44  /**
45  * scroll 'step size'.
46  *
47  * When scrolling we always scroll a 'fixed' amount, these are the
48  * parameters for these amounts.
49  */
50  enum scroll_mode {
51  BEGIN, /**< Go to begin position. */
52  ITEM_BACKWARDS, /**< Go one item towards the begin. */
53  HALF_JUMP_BACKWARDS, /**< Go half the visible items towards the begin. */
54  JUMP_BACKWARDS, /**< Go the visible items towards the begin. */
55  END, /**< Go to the end position. */
56  ITEM_FORWARD, /**< Go one item towards the end. */
57  HALF_JUMP_FORWARD, /**< Go half the visible items towards the end. */
58  JUMP_FORWARD /**< Go the visible items towards the end. */
59  };
60 
61  /** Helper container for the slider's current position. */
63  {
64  int offset;
66  };
67 
68  /**
69  * Sets the item position.
70  *
71  * We scroll a predefined step.
72  *
73  * @param scroll 'step size' to scroll.
74  */
75  void scroll(const scroll_mode scroll);
76 
77 protected:
78  /** Is the positioner at the beginning of the slider? */
79  bool at_begin() const
80  {
81  return item_position_ == 0;
82  }
83 
84  /**
85  * Is the positioner at the and of the slider?
86  *
87  * Note both begin and end might be true at the same time.
88  */
89  bool at_end() const
90  {
91  return item_position_ >= item_last_;
92  }
93 
95 
96 public:
97  void finalize_setup();
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  */
121 
122 protected:
123  /***** ***** ***** setters / getters for members ***** ****** *****/
124 
125  void slider_set_item_last(const unsigned item_last)
126  {
127  item_last_ = item_last;
128  recalculate();
129  }
130 
131  unsigned slider_get_item_count() const
132  {
133  return item_last_ + 1;
134  }
135 
136  unsigned slider_get_item_last() const
137  {
138  return item_last_;
139  }
140 
141  /**
142  * Note the position isn't guaranteed to be the wanted position
143  * the step size is honored. The value will be rounded down.
144  */
145  void set_slider_position(int item_position);
146 
147  unsigned get_slider_position() const
148  {
149  return item_position_;
150  }
151 
152  unsigned get_positioner_offset() const
153  {
154  return positioner_offset_;
155  }
156 
157  unsigned get_positioner_length() const
158  {
159  return positioner_length_;
160  }
161 
162  /**
163  * See @ref styled_widget::update_canvas.
164  *
165  * After a recalculation the canvasses also need to be updated.
166  */
167  virtual void update_canvas() override;
168 
169  /**
170  * Callback for subclasses to get notified about positioner movement.
171  *
172  * @todo This is a kind of hack due to the fact there's no simple
173  * callback slot mechanism. See whether we can implement a generic way to
174  * attach callback which would remove quite some extra code.
175  */
177  {
178  }
179 
180  virtual int jump_size() const
181  {
182  return 1;
183  }
184 
185 private:
186  void set_state(const state_t state);
187 
188  /**
189  * Current state of the widget.
190  *
191  * The state of the widget determines what to render and how the widget
192  * reacts to certain 'events'.
193  */
195 
196  /** one less than the number items the slider 'holds'. */
198 
199  /** The item the positioner is at, starts at 0. */
201 
202  /**
203  * The position the mouse was when draggin the slider was started.
204  *
205  * This is used during dragging the positioner.
206  */
208 
209  /**
210  * The offset in pixels the slider was when dragging the positioner was started.
211  */
213 
214  /**
215  * The start offset of the positioner.
216  *
217  * This takes the offset before in consideration.
218  */
220 
221  /** The current length of the positioner. */
223 
224  /** Whether the slider should 'snap' into its supported values or not. */
225  bool snap_;
226 
227  /***** ***** ***** ***** Pure virtual functions ***** ***** ***** *****/
228 
229  /** Get the length of the slider. */
230  virtual unsigned get_length() const = 0;
231 
232  int available_length() const
233  {
234  return get_length() - offset_before() - offset_after();
235  }
236 
237  int max_offset() const
238  {
239  return std::max(0, available_length() - positioner_length());
240  }
241 
242  /**
243  * The number of pixels we can't use since they're used for borders.
244  *
245  * These are the pixels before the widget (left side if horizontal,
246  * top side if vertical).
247  */
248  virtual unsigned offset_before() const = 0;
249 
250  /**
251  * The number of pixels we can't use since they're used for borders.
252  *
253  * These are the pixels after the widget (right side if horizontal,
254  * bottom side if vertical).
255  */
256  virtual unsigned offset_after() const = 0;
257 
258  /**
259  * Is the coordinate on the positioner?
260  *
261  * @param coordinate Coordinate to test whether it's on the
262  * positioner.
263  *
264  * @returns Whether the location on the positioner is.
265  */
266  virtual bool on_positioner(const point& coordinate) const = 0;
267 
268  /**
269  * Is the coordinate on the bar?
270  *
271  * @param coordinate Coordinate to test whether it's on the
272  * bar.
273  *
274  * @returns Whether the location on the bar is.
275  * @retval -1 Coordinate is on the bar before positioner.
276  * @retval 0 Coordinate is not on the bar.
277  * @retval 1 Coordinate is on the bar after the positioner.
278  */
279  virtual int on_bar(const point& coordinate) const = 0;
280 
281  /**
282  * Gets the relevant difference in between the two positions.
283  *
284  * This function is used to determine how much the positioner needs to be
285  * moved.
286  */
287  virtual int get_length_difference(const point& original, const point& current) const = 0;
288 
289  /***** ***** ***** ***** Private functions ***** ***** ***** *****/
290 
291  /**
292  * Updates the slider.
293  *
294  * Needs to be called when something changes eg number of items or available size.
295  * It can only be called once we have a size otherwise we can't calculate a thing.
296  */
297  void recalculate();
298 
299  /**
300  * Updates the positioner.
301  *
302  * This is a helper for recalculate().
303  */
304  virtual int positioner_length() const = 0;
305 
307  {
308  positioner_length_ = positioner_length();
309  }
310 
311  /**
312  * Moves the positioner.
313  *
314  * @param offset The new offset in pixels of the positioner;
315  */
316  void move_positioner(int offset);
317 
318  /***** ***** ***** signal handlers ***** ****** *****/
319 
320  void signal_handler_mouse_enter(const event::ui_event event, bool& handled, bool& halt);
321 
322  void signal_handler_mouse_motion(const event::ui_event event, bool& handled, bool& halt, const point& coordinate);
323 
324  void signal_handler_mouse_leave(const event::ui_event event, bool& handled);
325 
326  void signal_handler_left_button_down(const event::ui_event event, bool& handled);
327 
328  void signal_handler_left_button_up(const event::ui_event event, bool& handled);
329 };
330 
331 } // namespace gui2
int positioner_length_
The current length of the positioner.
Go one item towards the begin.
Definition: slider_base.hpp:52
unsigned slider_get_item_count() const
virtual int on_bar(const point &coordinate) const =0
Is the coordinate on the bar?
Go the visible items towards the begin.
Definition: slider_base.hpp:54
virtual unsigned offset_before() const =0
The number of pixels we can&#39;t use since they&#39;re used for borders.
virtual bool on_positioner(const point &coordinate) const =0
Is the coordinate on the positioner?
virtual bool get_active() const override
See styled_widget::get_active.
Go the visible items towards the end.
Definition: slider_base.hpp:58
bool snap_
Whether the slider should &#39;snap&#39; into its supported values or not.
int item_last_
one less than the number items the slider &#39;holds&#39;.
virtual void child_callback_positioner_moved()
Callback for subclasses to get notified about positioner movement.
void update_slider_position(slider_position_t &pos)
Helper container for the slider&#39;s current position.
Definition: slider_base.hpp:62
void signal_handler_left_button_down(const event::ui_event event, bool &handled)
void set_state(const state_t state)
virtual unsigned get_length() const =0
Get the length of the slider.
unsigned get_positioner_offset() const
unsigned get_slider_position() const
unsigned get_positioner_length() const
void scroll(const scroll_mode scroll)
Sets the item position.
Definition: slider_base.cpp:65
slider_base(const implementation::builder_styled_widget &builder, const std::string &control_type)
Definition: slider_base.cpp:42
state_t state_
Current state of the widget.
Go half the visible items towards the begin.
Definition: slider_base.hpp:53
point drag_initial_mouse_
The position the mouse was when draggin the slider was started.
virtual unsigned offset_after() const =0
The number of pixels we can&#39;t use since they&#39;re used for borders.
virtual unsigned get_state() const override
See styled_widget::get_state.
Generic file dialog.
Definition: field-fwd.hpp:22
void signal_handler_mouse_enter(const event::ui_event event, bool &handled, bool &halt)
int available_length() const
int drag_initial_offset_
The offset in pixels the slider was when dragging the positioner was started.
virtual void set_active(const bool active) override
See styled_widget::set_active.
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
unsigned slider_get_item_last() const
int positioner_offset_
The start offset of the positioner.
void move_positioner(int offset)
Moves the positioner.
Go half the visible items towards the end.
Definition: slider_base.hpp:57
virtual int get_length_difference(const point &original, const point &current) const =0
Gets the relevant difference in between the two positions.
void slider_set_item_last(const unsigned item_last)
void recalculate()
Updates the slider.
void set_slider_position(int item_position)
Note the position isn&#39;t guaranteed to be the wanted position the step size is honored.
void signal_handler_mouse_motion(const event::ui_event event, bool &handled, bool &halt, const point &coordinate)
virtual int jump_size() const
Go one item towards the end.
Definition: slider_base.hpp:56
int max_offset() const
Go to begin position.
Definition: slider_base.hpp:51
bool at_begin() const
Is the positioner at the beginning of the slider?
Definition: slider_base.hpp:79
Holds a 2D point.
Definition: point.hpp:23
Base class for all visible items.
Go to the end position.
Definition: slider_base.hpp:55
virtual void place(const point &origin, const point &size) override
See widget::place.
int item_position_
The item the positioner is at, starts at 0.
state_t
Possible states of the widget.
void recalculate_positioner()
Base class for a scroll bar.
Definition: slider_base.hpp:39
scroll_mode
scroll &#39;step size&#39;.
Definition: slider_base.hpp:50
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
virtual void update_canvas() override
See styled_widget::update_canvas.
virtual int positioner_length() const =0
Updates the positioner.
void signal_handler_left_button_up(const event::ui_event event, bool &handled)
bool at_end() const
Is the positioner at the and of the slider?
Definition: slider_base.hpp:89
ui_event
The event send to the dispatcher.
Definition: handler.hpp:55
void signal_handler_mouse_leave(const event::ui_event event, bool &handled)