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) 2003 - 2016 by David White <[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 "global.hpp"
18 
19 #include "widgets/slider.hpp"
20 #include "game_config.hpp"
21 #include "font.hpp"
22 #include "image.hpp"
23 #include "sdl/rect.hpp"
24 #include "sound.hpp"
25 #include "video.hpp"
26 
27 
28 #include <boost/math/special_functions/sign.hpp>
29 
30 
31 namespace {
32  const std::string slider_image = ".png";
33  const std::string disabled_image = ".png~GS()";
34  const std::string pressed_image = "-pressed.png";
35  const std::string active_image = "-active.png";
36 }
37 
38 namespace gui {
39 
40 slider::slider(CVideo &video, const std::string& image, bool black)
41  : widget(video), image_(image::get_image(image + slider_image)),
42  pressedImage_(image::get_image(image + pressed_image)),
43  activeImage_(image::get_image(image + active_image)),
44  disabledImage_(image::get_image(image + disabled_image)),
45  line_color_(black ? font::BLACK_COLOR : font::NORMAL_COLOR),
46  min_(-100000), max_(100000), value_(0),
47  increment_(1), value_change_(false), state_(NORMAL)
48 {
49 }
50 
51 void slider::enable(bool new_val)
52 {
53  if(new_val != enabled())
54  {
55  state_ = NORMAL;
56  widget::enable(new_val);
57  }
58 }
59 
60 void slider::set_location(SDL_Rect const &rect)
61 {
62  SDL_Rect r = rect;
63  r.h = image_->h;
65 }
66 
68 {
69  min_ = value;
70  if (value_ < min_) {
71  value_ = min_;
72  value_change_ = true;
73  }
74  set_dirty(true);
75 }
76 
78 {
79  max_ = value;
80  if (value_ > max_) {
81  value_ = max_;
82  value_change_ = true;
83  }
84  set_dirty(true);
85 }
86 
88 {
89  if (value > max_)
90  value = max_;
91  if (value < min_)
92  value = min_;
93 
94  if (increment_ > 1) {
95  int hi = boost::math::sign(value) * increment_ / 2;
96  value = ((value + hi) / increment_) * increment_;
97  }
98 
99  if (value == value_)
100  return;
101 
102  value_ = value;
103  value_change_ = true;
104  set_dirty(true);
105 }
106 
107 void slider::set_increment(int increment)
108 {
109  increment_ = increment;
110 }
111 
112 int slider::value() const
113 {
114  return value_;
115 }
116 
117 int slider::max_value() const
118 {
119  return max_;
120 }
121 
123 {
124  if (value_change_) {
125  value_change_ = false;
126  return true;
127  }
128  return false;
129 }
130 
131 SDL_Rect slider::slider_area() const
132 {
133  static const SDL_Rect default_value = {0,0,0,0};
134  SDL_Rect const &loc = location();
135  if (image_.null() || image_->w >= loc.w)
136  return default_value;
137 
138  int xpos = loc.x + (value_ - min_) * (loc.w - image_->w) / (max_ - min_);
139  return sdl::create_rect(xpos, loc.y, image_->w, image_->h);
140 }
141 
143 {
144  surface image;
145 
146  switch (state_) {
147  case NORMAL:
148  image.assign(image_);
149  break;
150  case ACTIVE:
151  image.assign(activeImage_);
152  break;
153  default:
154  image.assign(pressedImage_);
155  break;
156  }
157 
158  assert(image != nullptr);
159 
160  SDL_Color line_color = line_color_;
161  if (!enabled()) {
162  image.assign(disabledImage_);
163  line_color = font::DISABLED_COLOR;
164  }
165 
166  SDL_Rect const &loc = location();
167  if (image->w >= loc.w)
168  return;
169 
171 
172  SDL_Rect line_rect = sdl::create_rect(loc.x + image->w / 2
173  , loc.y + loc.h / 2
174  , loc.w - image->w
175  , 1);
176 
177  sdl::fill_rect(screen, &line_rect, SDL_MapRGB(screen->format,
178  line_color.r, line_color.g, line_color.b));
179 
180  SDL_Rect const &slider = slider_area();
181  video().blit_surface(slider.x, slider.y, image);
182 }
183 
185 {
186  SDL_Rect const &loc = location();
187  int tmp = x - loc.x - image_->w / 2;
188  if (tmp < 0)
189  tmp = 0;
190  if (tmp > loc.w - image_->w)
191  tmp = loc.w - image_->w;
192 
193  set_value(tmp * (max_ - min_) / (loc.w - image_->w) + min_);
194 }
195 
196 void slider::mouse_motion(const SDL_MouseMotionEvent& event)
197 {
198  if (state_ == NORMAL || state_ == ACTIVE) {
199  bool on = sdl::point_in_rect(event.x, event.y, location());
200  state_ = on ? ACTIVE : NORMAL;
201  } else if (state_ == CLICKED || state_ == DRAGGED) {
202  state_ = DRAGGED;
203  bool prev_change = value_change_;
204  value_change_ = false;
205  set_slider_position(event.x);
206  if(value_change_) {
208  } else {
209  value_change_ = prev_change;
210  }
211  }
212 }
213 
214 void slider::mouse_down(const SDL_MouseButtonEvent& event)
215 {
216  bool prev_change = value_change_;
217 
218  if (!sdl::point_in_rect(event.x, event.y, location()))
219  return;
220 
221 
222  if (event.button != SDL_BUTTON_LEFT)
223  return;
224 
225  state_ = CLICKED;
226  set_focus(true);
227  if (sdl::point_in_rect(event.x, event.y, slider_area())) {
229  } else {
230  value_change_ = false;
231  set_slider_position(event.x);
232  if(value_change_) {
234  } else {
235  value_change_ = prev_change;
236  }
237  }
238 }
239 
240 void slider::mouse_wheel(const SDL_MouseWheelEvent& event) {
241  bool prev_change = value_change_;
242  int x, y;
243  SDL_GetMouseState(&x, &y);
244 
245  if (!sdl::point_in_rect(x, y, location()))
246  return;
247 
248  if (event.y > 0 || event.x > 0) {
249  value_change_ = false;
250  set_focus(true);
252  if(value_change_) {
254  } else {
255  value_change_ = prev_change;
256  }
257  }
258  if (event.y < 0 || event.x < 0) {
259  value_change_ = false;
260  set_focus(true);
262  if(value_change_) {
264  } else {
265  value_change_ = prev_change;
266  }
267  }
268 }
269 
270 bool slider::requires_event_focus(const SDL_Event* event) const
271 {
272  if(!focus_ || !enabled() || hidden()) {
273  return false;
274  }
275  if(event == nullptr) {
276  //when event is not specified, signal that focus may be desired later
277  return true;
278  }
279 
280  if(event->type == SDL_KEYDOWN) {
281  SDLKey key = event->key.keysym.sym;
282  switch(key) {
283  case SDLK_LEFT:
284  case SDLK_RIGHT:
285  return true;
286  default:
287  break;
288  }
289  }
290  //mouse events are processed regardless of focus
291  return false;
292 }
293 
294 void slider::handle_event(const SDL_Event& event)
295 {
297 
298  if (!enabled() || hidden())
299  return;
300 
301  STATE start_state = state_;
302 
303  switch(event.type) {
304  case SDL_MOUSEBUTTONUP:
305  if (!mouse_locked()) {
306  bool on = sdl::point_in_rect(event.button.x, event.button.y, slider_area());
307  state_ = on ? ACTIVE : NORMAL;
308  }
309  break;
310  case SDL_MOUSEBUTTONDOWN:
311  if (!mouse_locked())
312  mouse_down(event.button);
313  break;
314  case SDL_MOUSEMOTION:
315  if (!mouse_locked())
316  mouse_motion(event.motion);
317  break;
318  case SDL_KEYDOWN:
319  if(focus(&event) && allow_key_events()) { //allow_key_events is used by zoom_sliders to disable left-right key press, which is buggy for them
320  const SDL_keysym& key = reinterpret_cast<const SDL_KeyboardEvent&>(event).keysym;
321  const int c = key.sym;
322  if(c == SDLK_LEFT) {
325  } else if(c == SDLK_RIGHT) {
328  }
329  }
330  break;
331  case SDL_MOUSEWHEEL:
332  if (!mouse_locked())
333  mouse_wheel(event.wheel);
334  break;
335  default:
336  return;
337  }
338  if (start_state != state_)
339  set_dirty(true);
340 }
341 
342 template<typename T>
344  slider(video)
345 {
346  set_min(0);
347  set_increment(1);
349 }
350 
351 template<typename T>
352 list_slider<T>::list_slider(CVideo &video, const std::vector<T> &items) :
353  slider(video),
354  items_(items)
355 {
356  set_min(0);
357  set_increment(1);
358  if(items.size() > 0)
359  {
360  set_max(items.size() - 1);
361  }
363 }
364 
365 template<typename T>
367 {
368  return items_[value()];
369 }
370 
371 template<typename T>
372 bool list_slider<T>::select_item(const T& item)
373 {
374  for(unsigned i = 0, nb = items_.size(); i < nb; ++i)
375  {
376  if(item == items_[i])
377  {
379  return true;
380  }
381  }
382  return false;
383 }
384 
385 template<typename T>
386 void list_slider<T>::set_items(const std::vector<T> &items)
387 {
388  items_ = items;
389  if(items.size() > 0)
390  {
391  set_max(items.size() - 1);
392  }
394 }
395 
396 // Force compilation of the following template instantiations
397 template class list_slider< double >;
398 template class list_slider< int >;
399 template class list_slider< std::string >;
400 
401 /***
402 *
403 * Zoom Slider
404 *
405 ***/
406 
408  : slider(video, image, black)
409 {
410 }
411 
412 } //end namespace gui
surface get_image(const image::locator &i_locator, TYPE type)
function to get the surface corresponding to an image.
Definition: image.cpp:878
#define SDL_keysym
Definition: compat.hpp:31
bool value_change_
Definition: slider.hpp:70
bool null() const
Definition: utils.hpp:104
int value_
Definition: slider.hpp:67
void fill_rect(surface &dst, SDL_Rect *dst_rect, const Uint32 color)
Fill a rectangle on a given surface.
Definition: rect.hpp:143
void mouse_down(const SDL_MouseButtonEvent &event)
Definition: slider.cpp:214
bool enabled() const
Definition: widget.cpp:212
virtual void enable(bool new_val=true)
Definition: widget.cpp:204
Graphical text output.
const SDL_Color BLACK_COLOR
Definition: font.cpp:569
const GLfloat * c
Definition: glew.h:12741
void set_value(int value)
Definition: slider.cpp:87
int value() const
Definition: slider.cpp:112
void set_max(int value)
Definition: slider.cpp:77
Definition: video.hpp:58
game_display * screen
Definition: resources.cpp:27
slider(CVideo &video, const std::string &image="buttons/sliders/slider", bool black=false)
Definition: slider.cpp:40
CVideo & video() const
Definition: widget.hpp:83
General purpose widgets.
surface image_
The image is cached in this surface.
Definition: canvas.cpp:961
const std::string slider_adjust
GLenum GLsizei GLenum GLenum const GLvoid * image
Definition: glew.h:3783
void set_increment(int increment)
Definition: slider.cpp:107
void set_focus(bool focus)
Definition: widget.cpp:149
surface disabledImage_
Definition: slider.hpp:62
GLint GLint GLint GLint GLint GLint y
Definition: glew.h:1220
const std::vector< std::string > items
void blit_surface(int x, int y, surface surf, SDL_Rect *srcrect=nullptr, SDL_Rect *clip_rect=nullptr)
Definition: video.cpp:290
surface activeImage_
Definition: slider.hpp:62
bool requires_event_focus(const SDL_Event *event=nullptr) const
Definition: slider.cpp:270
const SDL_Color NORMAL_COLOR
Definition: font.cpp:564
void set_location(int x, int y)
Definition: slider.hpp:47
-file util.hpp
#define SDLKey
Definition: compat.hpp:29
surface & getSurface()
Definition: dummy_video.cpp:22
STATE state_
Definition: slider.hpp:73
bool hidden() const
Definition: widget.cpp:198
const SDL_Color DISABLED_COLOR
Definition: font.cpp:576
void set_dirty(bool dirty=true)
Definition: widget.cpp:217
virtual bool allow_key_events()
Definition: slider.hpp:54
surface pressedImage_
Definition: slider.hpp:62
int max_value() const
Definition: slider.cpp:117
const std::string sign
sign "-" - hyphen-minus used to set sign of signed integer
int max_
Definition: slider.hpp:66
bool focus(const SDL_Event *event)
Definition: widget.cpp:157
void mouse_wheel(const SDL_MouseWheelEvent &event)
Definition: slider.cpp:240
GLsizei const GLfloat * value
Definition: glew.h:1817
list_slider(CVideo &video)
Definition: slider.cpp:343
void set_items(const std::vector< T > &items)
Definition: slider.cpp:386
virtual void enable(bool new_val=true)
Definition: slider.cpp:51
bool select_item(const T &item)
Definition: slider.cpp:372
virtual void handle_event(const SDL_Event &event)
Definition: slider.cpp:294
bool point_in_rect(int x, int y, const SDL_Rect &rect)
Tests whether a point is inside a rectangle.
Definition: rect.cpp:47
Encapsulates the map of the game.
Definition: location.hpp:38
zoom_slider(CVideo &video, const std::string &image="buttons/sliders/slider", bool black=false)
Definition: slider.cpp:407
int min_
Definition: slider.hpp:65
const T & item_selected() const
Definition: slider.cpp:366
void mouse_motion(const SDL_MouseMotionEvent &event)
Definition: slider.cpp:196
virtual void draw_contents()
Definition: slider.cpp:142
bool focus_
Definition: widget.hpp:94
size_t i
Definition: function.cpp:1057
GLint GLint GLint GLint GLint x
Definition: glew.h:1220
GLdouble GLdouble GLdouble r
Definition: glew.h:1374
int increment_
Definition: slider.hpp:68
std::vector< expression_ptr > items_
Definition: formula.cpp:119
bool value_change()
Definition: slider.cpp:122
surface image_
Definition: slider.hpp:62
const std::string button_press
SDL_Rect create_rect(const int x, const int y, const int w, const int h)
Creates an empty SDL_Rect.
Definition: rect.cpp:28
Contains the SDL_Rect helper code.
cl_event event
Definition: glew.h:3070
this module manages the cache of images.
Definition: image.cpp:75
void play_UI_sound(const std::string &files)
Definition: sound.cpp:842
bool mouse_locked() const
Definition: widget.cpp:72
void assign(const surface &o)
Definition: utils.hpp:83
void set_min(int value)
Definition: slider.cpp:67
virtual void set_location(SDL_Rect const &rect)
Definition: widget.cpp:85
virtual void handle_event(SDL_Event const &)
Definition: widget.cpp:345
SDL_Rect const & location() const
Definition: widget.cpp:144
void set_slider_position(int x)
Definition: slider.cpp:184
GLsizei const GLcharARB ** string
Definition: glew.h:4503
SDL_Color line_color_
Definition: slider.hpp:63
SDL_Rect slider_area() const
Definition: slider.cpp:131