The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
slider.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2016 by Mark de Wever <[email protected]>
3  Part of the Battle for Wesnoth Project http://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 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
17 #include "gui/widgets/slider.hpp"
18 
19 #include "formatter.hpp"
20 #include "gui/core/log.hpp"
21 #include "gui/widgets/window.hpp"
23 #include "gui/widgets/settings.hpp"
24 #include "sound.hpp"
25 #include "gettext.hpp"
26 #include "wml_exception.hpp"
27 
28 #include "utils/functional.hpp"
29 
30 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
31 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
32 
33 namespace gui2
34 {
35 
36 // ------------ WIDGET -----------{
37 
38 REGISTER_WIDGET(slider)
39 
41  : tscrollbar_()
42  , best_slider_length_(0)
43  , minimum_value_(0)
44  , minimum_value_label_()
45  , maximum_value_label_()
46  , value_labels_()
47 {
48  connect_signal<event::SDL_KEY_DOWN>(std::bind(
49  &tslider::signal_handler_sdl_key_down, this, _2, _3, _5));
50  connect_signal<event::LEFT_BUTTON_UP>(
51  std::bind(&tslider::signal_handler_left_button_up, this, _2, _3));
52 }
53 
55 {
57 
58  // Inherited.
60  if(best_slider_length_ != 0) {
61 
62  // Override length.
64  = boost::dynamic_pointer_cast<const tslider_definition::
66 
67  assert(conf);
68 
69  result.x = conf->left_offset + best_slider_length_ + conf->right_offset;
70  }
71 
72  DBG_GUI_L << LOG_HEADER << " best_slider_length " << best_slider_length_
73  << " result " << result << ".\n";
74  return result;
75 }
76 
77 void tslider::set_value(const int value)
78 {
79  if(value == get_value()) {
80  return;
81  }
82 
83  if(value < minimum_value_) {
85  } else if(value > get_maximum_value()) {
87  } else {
89  }
90 }
91 
92 void tslider::set_minimum_value(const int minimum_value)
93 {
94  if(minimum_value == minimum_value_) {
95  return;
96  }
97 
98  /** @todo maybe make it a VALIDATE. */
99  assert(minimum_value <= get_maximum_value());
100 
101  const int value = get_value();
102  const int maximum_value = get_maximum_value();
103  minimum_value_ = minimum_value;
104 
105  // The number of items needs to include the begin and end so distance step
106  // size.
107  set_item_count(maximum_value - minimum_value_ + get_step_size());
108 
109  if(value < minimum_value_) {
111  } else {
113  }
114 }
115 
116 void tslider::set_maximum_value(const int maximum_value)
117 {
118  if(maximum_value == get_maximum_value()) {
119  return;
120  }
121 
122  /** @todo maybe make it a VALIDATE. */
123  assert(minimum_value_ <= maximum_value);
124 
125  const int value = get_value();
126 
127  // The number of items needs to include the begin and end so distance + step
128  // size.
129  set_item_count(maximum_value - minimum_value_ + get_step_size());
130 
131  if(value > maximum_value) {
133  } else {
135  }
136 }
137 
139 {
140  if(value_labels_) {
142  } else if(!minimum_value_label_.empty() && get_value()
143  == get_minimum_value()) {
144  return minimum_value_label_;
145  } else if(!maximum_value_label_.empty() && get_value()
146  == get_maximum_value()) {
147  return maximum_value_label_;
148  }
149 
150  return t_string((formatter() << get_value()).str());
151 }
152 
154 {
156 }
157 
159 {
161  conf = boost::dynamic_pointer_cast<const tslider_definition::tresolution>(
162  config());
163  assert(conf);
164  return conf->minimum_positioner_length;
165 }
166 
168 {
170  conf = boost::dynamic_pointer_cast<const tslider_definition::tresolution>(
171  config());
172  assert(conf);
173  return conf->maximum_positioner_length;
174 }
175 
176 unsigned tslider::offset_before() const
177 {
179  conf = boost::dynamic_pointer_cast<const tslider_definition::tresolution>(
180  config());
181  assert(conf);
182  return conf->left_offset;
183 }
184 
185 unsigned tslider::offset_after() const
186 {
188  conf = boost::dynamic_pointer_cast<const tslider_definition::tresolution>(
189  config());
190  assert(conf);
191  return conf->right_offset;
192 }
193 
194 bool tslider::on_positioner(const tpoint& coordinate) const
195 {
196  // Note we assume the positioner is over the entire height of the widget.
197  return coordinate.x >= static_cast<int>(get_positioner_offset())
198  && coordinate.x < static_cast<int>(get_positioner_offset()
200  && coordinate.y > 0 && coordinate.y < static_cast<int>(get_height());
201 }
202 
203 int tslider::on_bar(const tpoint& coordinate) const
204 {
205  const unsigned x = static_cast<size_t>(coordinate.x);
206  const unsigned y = static_cast<size_t>(coordinate.y);
207 
208  // Not on the widget, leave.
209  if(x > get_width() || y > get_height()) {
210  return 0;
211  }
212 
213  // we also assume the bar is over the entire height of the widget.
214  if(x < get_positioner_offset()) {
215  return -1;
216  } else if(x > get_positioner_offset() + get_positioner_length()) {
217  return 1;
218  }
219 
220  return 0;
221 }
222 
223 bool tslider::in_orthogonal_range(const tpoint& coordinate) const
224 {
225  return static_cast<size_t>(coordinate.x) < (get_width() - offset_after());
226 }
227 
229 {
230 
231  // Inherited.
233 
234  for(auto & tmp : canvas())
235  {
236  tmp.set_variable("text", variant(get_value_label()));
237  }
238 }
239 
241 {
242  static const std::string type = "slider";
243  return type;
244 }
245 
246 void tslider::handle_key_decrease(bool& handled)
247 {
248  DBG_GUI_E << LOG_HEADER << '\n';
249 
250  handled = true;
251 
253 }
254 
255 void tslider::handle_key_increase(bool& handled)
256 {
257  DBG_GUI_E << LOG_HEADER << '\n';
258 
259  handled = true;
260 
262 }
263 
265  bool& handled,
266  const SDLKey key)
267 {
268 
269  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
270 
271  if(key == SDLK_DOWN || key == SDLK_LEFT) {
272  handle_key_decrease(handled);
273  } else if(key == SDLK_UP || key == SDLK_RIGHT) {
274  handle_key_increase(handled);
275  } else {
276  // Do nothing. Ignore other keys.
277  }
278 }
279 
281  bool& handled)
282 {
283  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
284 
285  get_window()->keyboard_capture(this);
286 
287  handled = true;
288 }
289 
290 static t_string default_value_label_generator(const std::vector<t_string>& value_labels, int item_position, int max)
291 {
292  assert(int(value_labels.size()) == max);
293  assert(item_position < max && item_position >= 0);
294  return value_labels[item_position];
295 }
296 
297 void tslider::set_value_labels(const std::vector<t_string>& value_labels)
298 {
299  //dont use std::ref becasue we want to store value_labels in the cloasure.
300  set_value_labels(std::bind(&default_value_label_generator, value_labels, _1, _2));
301 }
302 
303 // }---------- DEFINITION ---------{
304 
306  : tcontrol_definition(cfg)
307 {
308  DBG_GUI_P << "Parsing slider " << id << '\n';
309 
310  load_resolutions<tresolution>(cfg);
311 }
312 
313 /*WIKI
314  * @page = GUIWidgetDefinitionWML
315  * @order = 1_slider
316  *
317  * == Slider ==
318  *
319  * @macro = slider_description
320  *
321  * @begin{parent}{name="gui/"}
322  * @begin{tag}{name="slider_definition"}{min=0}{max=-1}{super="generic/widget_definition"}
323  * @begin{tag}{name="resolution"}{min=0}{max=-1}{super="generic/widget_definition/resolution"}
324  * @begin{table}{config}
325  * minimum_positioner_length & unsigned & &
326  * The minimum size the positioner is
327  * allowed to be. The engine needs to know
328  * this in order to calculate the best size
329  * for the positioner. $
330  * maximum_positioner_length & unsigned & 0 &
331  * The maximum size the positioner is
332  * allowed to be. If minimum and maximum are
333  * the same value the positioner is fixed
334  * size. If the maximum is 0 (and the
335  * minimum not) there's no maximum. $
336  * left_offset & unsigned & 0 & The number of pixels at the left side
337  * which can't be used by the positioner. $
338  * right_offset & unsigned & 0 & The number of pixels at the right side
339  * which can't be used by the positioner. $
340  * @end{table}
341  *
342  * The following states exist:
343  * * state_enabled, the slider is enabled.
344  * * state_disabled, the slider is disabled.
345  * * state_pressed, the left mouse button is down on the positioner of the
346  * slider.
347  * * state_focused, the mouse is over the positioner of the slider.
348  * @begin{tag}{name="state_enabled"}{min=0}{max=1}{super="generic/state"}
349  * @end{tag}{name="state_enabled"}
350  * @begin{tag}{name="state_disabled"}{min=0}{max=1}{super="generic/state"}
351  * @end{tag}{name="state_disabled"}
352  * @begin{tag}{name="state_pressed"}{min=0}{max=1}{super="generic/state"}
353  * @end{tag}{name="state_pressed"}
354  * @begin{tag}{name="state_focused"}{min=0}{max=1}{super="generic/state"}
355  * @end{tag}{name="state_focused"}
356  * @end{tag}{name="resolution"}
357  * @end{tag}{name="slider_definition"}
358  * @end{parent}{name="gui/"}
359  */
362  , minimum_positioner_length(cfg["minimum_positioner_length"])
363  , maximum_positioner_length(cfg["maximum_positioner_length"])
364  , left_offset(cfg["left_offset"])
365  , right_offset(cfg["right_offset"])
366 {
368  missing_mandatory_wml_key("resolution",
369  "minimum_positioner_length"));
370 
371  // Note the order should be the same as the enum tstate is slider.hpp.
372  state.push_back(tstate_definition(cfg.child("state_enabled")));
373  state.push_back(tstate_definition(cfg.child("state_disabled")));
374  state.push_back(tstate_definition(cfg.child("state_pressed")));
375  state.push_back(tstate_definition(cfg.child("state_focused")));
376 }
377 
378 // }---------- BUILDER -----------{
379 
380 /*WIKI_MACRO
381  * @begin{macro}{slider_description}
382  * A slider is a control that can select a value by moving a grip on a groove.
383  * @end{macro}
384  */
385 
386 /*WIKI
387  * @page = GUIWidgetInstanceWML
388  * @order = 3_slider
389  * @begin{parent}{name="gui/window/resolution/grid/row/column/"}
390  * @begin{tag}{name="slider"}{min="0"}{max="-1"}{super="generic/widget_instance"}
391  * == Slider ==
392  *
393  * @macro = slider_description
394  *
395  * @begin{table}{config}
396  * best_slider_length & unsigned & 0 &
397  * The best length for the sliding part. $
398  * minimum_value & int & 0 & The minimum value the slider can have. $
399  * maximum_value & int & 0 & The maximum value the slider can have. $
400  *
401  * step_size & unsigned & 0 & The number of items the slider's value
402  * increases with one step. $
403  * value & int & 0 & The value of the slider. $
404  *
405  * minimum_value_label & t_string & "" &
406  * If the minimum value is chosen there
407  * might be the need for a special value
408  * (eg off). When this key has a value
409  * that value will be shown if the minimum
410  * is selected. $
411  * maximum_value_label & t_string & "" &
412  * If the maximum value is chosen there
413  * might be the need for a special value
414  * (eg unlimited)). When this key has a
415  * value that value will be shown if the
416  * maximum is selected. $
417  * value_labels & [] & It might be the labels need to be shown
418  * are not a linear number sequence eg
419  * (0.5, 1, 2, 4) in that case for all
420  * items this section can be filled with
421  * the values, which should be the same
422  * number of items as the items in the
423  * slider. NOTE if this option is used,
424  * 'minimum_value_label' and
425  * 'maximum_value_label' are ignored. $
426  * @end{table}
427  * @end{tag}{name="slider"}
428  * @end{parent}{name="gui/window/resolution/grid/row/column/"}
429  */
430 
431 namespace implementation
432 {
433 
434 tbuilder_slider::tbuilder_slider(const config& cfg)
436  , best_slider_length_(cfg["best_slider_length"])
437  , minimum_value_(cfg["minimum_value"])
438  , maximum_value_(cfg["maximum_value"])
439  , step_size_(cfg["step_size"])
440  , value_(cfg["value"])
441  , minimum_value_label_(cfg["minimum_value_label"].t_str())
442  , maximum_value_label_(cfg["maximum_value_label"].t_str())
443  , value_labels_()
444 {
445  const config& labels = cfg.child("value_labels");
446  if(!labels) {
447  return;
448  }
449 
450  for(const auto & label : labels.child_range("value"))
451  {
452  value_labels_.push_back(label["label"]);
453  }
454 }
455 
457 {
458  tslider* widget = new tslider();
459 
460  init_control(widget);
461 
465  widget->set_step_size(step_size_);
466  widget->set_value(value_);
467 
468  if(!value_labels_.empty()) {
469  VALIDATE(value_labels_.size() == widget->get_item_count(),
470  _("The number of value_labels and values don't match."));
471 
473 
474  } else {
477  }
478 
479  DBG_GUI_G << "Window builder: placed slider '" << id
480  << "' with definition '" << definition << "'.\n";
481 
482  return widget;
483 }
484 
485 } // namespace implementation
486 
487 // }------------ END --------------
488 
489 } // namespace gui2
Define the common log macros for the gui toolkit.
int on_bar(const tpoint &coordinate) const
Inherited from tscrollbar.
Definition: slider.cpp:203
unsigned get_width() const
Definition: widget.cpp:294
void handle_key_increase(bool &handled)
Definition: slider.cpp:255
#define DBG_GUI_P
Definition: log.hpp:69
child_itors child_range(const std::string &key)
Definition: config.cpp:613
t_string maximum_value_label_
When the slider shows the maximum value can show a special text.
Definition: slider.hpp:169
void set_step_size(const unsigned step_size)
Definition: scrollbar.hpp:150
void set_item_count(const unsigned item_count)
Definition: scrollbar.hpp:116
#define DBG_GUI_L
Definition: log.hpp:58
void set_best_slider_length(const unsigned length)
Definition: slider.hpp:74
int minimum_value_
The minimum value the slider holds.
Definition: slider.hpp:120
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1221
tresolution_definition_ptr config()
Definition: control.hpp:299
This file contains the window object, this object is a top level container which has the event manage...
int get_maximum_value() const
Inherited from tinteger_selector_.
Definition: slider.hpp:66
void child_callback_positioner_moved()
Inherited from tscrollbar.
Definition: slider.cpp:153
void set_minimum_value(const int minimum_value)
Inherited from tinteger_selector_.
Definition: slider.cpp:92
lg::log_domain log_gui_layout("gui/layout")
Definition: log.hpp:57
virtual void update_canvas() override
See tcontrol::update_canvas.
Definition: slider.cpp:228
void signal_handler_left_button_up(const event::tevent event, bool &handled)
Definition: slider.cpp:280
Base class for a scroll bar.
Definition: scrollbar.hpp:41
void set_maximum_value(const int maximum_value)
Inherited from tinteger_selector_.
Definition: slider.cpp:116
bool on_positioner(const tpoint &coordinate) const
Inherited from tscrollbar.
Definition: slider.cpp:194
GLint GLint GLint GLint GLint GLint y
Definition: glew.h:1220
void set_value(const int value)
Inherited from tinteger_selector_.
Definition: slider.cpp:77
t_string get_value_label() const
Returns the label shown for the current value.
Definition: slider.cpp:138
Go one item towards the begin.
Definition: scrollbar.hpp:57
#define SDLKey
Definition: compat.hpp:29
std::string sound_slider_adjust
Definition: settings.cpp:61
Base class of a resolution, contains the common keys for a resolution.
tlabel_creator value_labels_
This allows the slider to show custom texts instead of the values.
Definition: slider.hpp:177
std::string missing_mandatory_wml_key(const std::string &section, const std::string &key, const std::string &primary_key, const std::string &primary_value)
Returns a standard message for a missing wml key.
unsigned get_item_count() const
Definition: scrollbar.hpp:121
void set_value_labels(const std::vector< t_string > &value_labels)
Definition: slider.cpp:297
A class inherited from ttext_box that displays its input as stars.
Definition: field-fwd.hpp:23
void init_control(tcontrol *control) const
Definition: control.cpp:675
std::string definition
Parameters for the control.
Definition: control.hpp:530
void handle_key_decrease(bool &handled)
Handlers for keyboard input.
Definition: slider.cpp:246
unsigned minimum_positioner_length() const
Inherited from tscrollbar.
Definition: slider.cpp:158
unsigned offset_after() const
Inherited from tscrollbar.
Definition: slider.cpp:185
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
GLuint64EXT * result
Definition: glew.h:10727
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
This file contains the settings handling of the widget library.
std::ostringstream wrapper.
Definition: formatter.hpp:32
int y
y coordinate.
Definition: point.hpp:34
int get_value() const
Inherited from tinteger_selector_.
Definition: slider.hpp:48
unsigned get_item_position() const
Definition: scrollbar.hpp:131
GLsizei const GLfloat * value
Definition: glew.h:1817
unsigned offset_before() const
Inherited from tscrollbar.
Definition: slider.cpp:176
static t_string default_value_label_generator(const std::vector< t_string > &value_labels, int item_position, int max)
Definition: slider.cpp:290
#define log_scope2(domain, description)
Definition: log.hpp:186
tevent
The event send to the dispatcher.
Definition: handler.hpp:54
std::vector< t_string > value_labels_
Definition: slider.hpp:242
Contains the state info for a resolution.
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
unsigned best_slider_length_
The best size for the slider part itself, if 0 ignored.
Definition: slider.hpp:112
tslider_definition(const config &cfg)
Definition: slider.cpp:305
int x
x coordinate.
Definition: point.hpp:31
virtual const std::string & get_control_type() const override
See tcontrol::get_control_type.
Definition: slider.cpp:240
#define DBG_GUI_E
Definition: log.hpp:35
#define LOG_HEADER
Definition: slider.cpp:31
unsigned maximum_positioner_length() const
Inherited from tscrollbar.
Definition: slider.cpp:167
virtual void update_canvas() override
See tcontrol::update_canvas.
Definition: scrollbar.cpp:149
t_string minimum_value_label_
When the slider shows the minimum value can show a special text.
Definition: slider.hpp:163
void signal_handler_sdl_key_down(const event::tevent event, bool &handled, const SDLKey key)
Signal handlers:
Definition: slider.cpp:264
unsigned get_positioner_offset() const
Definition: scrollbar.hpp:157
unsigned get_height() const
Definition: widget.cpp:299
Holds a 2D point.
Definition: point.hpp:24
GLint GLint GLint GLint GLint x
Definition: glew.h:1220
std::vector< tcanvas > & canvas()
Definition: control.hpp:282
int get_minimum_value() const
Inherited from tinteger_selector_.
Definition: slider.hpp:57
std::vector< tstate_definition > state
void scroll(const tscroll scroll)
Sets the item position.
Definition: scrollbar.cpp:54
virtual tpoint calculate_best_size() const override
See twidget::calculate_best_size.
Definition: slider.cpp:54
cl_event event
Definition: glew.h:3070
#define LOG_SCOPE_HEADER
Definition: slider.cpp:30
config & child(const std::string &key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:658
Base class for all widgets.
Definition: widget.hpp:49
void play_UI_sound(const std::string &files)
Definition: sound.cpp:842
void set_item_position(const unsigned item_position)
Note the position isn't guaranteed to be the wanted position the step size is honored.
Definition: scrollbar.cpp:127
void keyboard_capture(twidget *widget)
Definition: window.cpp:1394
Go one item towards the end.
Definition: scrollbar.hpp:62
twindow * get_window()
Get the parent window.
Definition: widget.cpp:116
A slider.
Definition: slider.hpp:30
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
unsigned get_step_size() const
Definition: scrollbar.hpp:146
#define DBG_GUI_G
Definition: log.hpp:41
bool in_orthogonal_range(const tpoint &coordinate) const
Inherited from tscrollbar.
Definition: slider.cpp:223
GLsizei const GLcharARB ** string
Definition: glew.h:4503
bool empty() const
Definition: tstring.hpp:166
void set_maximum_value_label(const t_string &maximum_value_label)
Definition: slider.hpp:85
Contains the implementation details for lexical_cast and shouldn't be used directly.
void set_minimum_value_label(const t_string &minimum_value_label)
Definition: slider.hpp:80
unsigned get_positioner_length() const
Definition: scrollbar.hpp:162
virtual tpoint calculate_best_size() const override
See twidget::calculate_best_size.
Definition: control.cpp:229