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