The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
tristate_button.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2013 - 2016 by Fabian Mueller <[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 "tristate_button.hpp"
20 
21 #include "font.hpp"
22 #include "game_config.hpp"
23 #include "image.hpp"
24 #include "log.hpp"
25 #include "marked-up_text.hpp"
27 #include "sdl/alpha.hpp"
28 #include "sound.hpp"
29 #include "video.hpp"
30 #include "wml_separators.hpp"
31 
32 static lg::log_domain log_display("display");
33 #define ERR_DP LOG_STREAM(err, log_display)
34 
35 namespace gui {
36 
39 
42  std::string button_image_name,
43  const bool auto_join) :
44  widget(video, auto_join),
45  baseImage_(nullptr), touchedBaseImage_(nullptr), activeBaseImage_(nullptr),
46  itemImage_(nullptr),
47  pressedDownImage_(nullptr), pressedUpImage_(nullptr), pressedBothImage_(nullptr),
48  pressedBothActiveImage_(nullptr), pressedDownActiveImage_(nullptr), pressedUpActiveImage_(nullptr),
49  touchedDownImage_(nullptr), touchedUpImage_(nullptr), touchedBothImage_(nullptr),
50  textRect_(),
51  state_(NORMAL), pressed_(false),
52  base_height_(0), base_width_(0),
53  palette_(palette), item_id_()
54 {
55 
56  if (button_image_name.empty()) {
57  button_image_name = "buttons/button_selectable/button_selectable_38_";
58  }
59 
61  image::get_image(button_image_name + "base.png"));
63  image::get_image(button_image_name + "base-active.png"));
65  image::get_image(button_image_name + "base-touched.png"));
66 
68  image::get_image(button_image_name + "border-touched-both.png"));
70  image::get_image(button_image_name + "border-touched-up.png"));
72  image::get_image(button_image_name + "border-touched-down.png"));
73 
75  image::get_image(button_image_name + "border-pressed-up.png"));
77  image::get_image(button_image_name + "border-pressed-down.png"));
79  image::get_image(button_image_name + "border-pressed-both.png"));
80 
82  image::get_image(button_image_name + "border-active-pressed-up.png"));
84  image::get_image(button_image_name + "border-active-pressed-down.png"));
86  image::get_image(button_image_name + "border-active-pressed-both.png"));
87 
88  //TODO
89 // if (button_image.null()) {
90 // ERR_DP<< "error initializing button!" << std::endl;
91 // throw error();
92 // }
93 
96 
97 }
98 
100 
102 
103  STATE new_state = state_;
104 
105  switch (new_pressed_state) {
106  case LEFT:
108  break;
109  case RIGHT:
111  break;
112  case BOTH:
114  break;
115  case NONE:
116  new_state = NORMAL;
117  }
118 
119  if (state_ != new_state) {
120  state_ = new_state;
121  set_dirty();
122  }
123 }
124 
125 //TODO
126 //void tristate_button::set_active(bool active) {
127 // if ((state_ == NORMAL) && active) {
128 // state_ = ACTIVE;
129 // set_dirty();
130 // } else if ((state_ == ACTIVE) && !active) {
131 // state_ = NORMAL;
132 // set_dirty();
133 // }
134 //}
135 
137 
138  switch (state_) {
139  case PRESSED_LEFT:
140  case PRESSED_ACTIVE_LEFT:
141  case TOUCHED_BOTH_LEFT:
142  return LEFT;
143  case PRESSED_RIGHT:
145  case TOUCHED_BOTH_RIGHT:
146  return RIGHT;
147  case PRESSED_BOTH:
148  case PRESSED_ACTIVE_BOTH:
149  return BOTH;
150  default:
151  return NONE;
152  }
153 }
154 
155 void tristate_button::enable(bool new_val) {
156  if (new_val != enabled()) {
157  pressed_ = false;
158  // check buttons should keep their state
159  state_ = NORMAL;
160 
161  widget::enable(new_val);
162  }
163 }
164 
166 
167  surface image(nullptr);
168 
169  surface overlay(nullptr);
170  surface base = baseImage_;
171 
172  int offset = 0;
173  switch (state_) {
174 
175  case UNINIT:
176  return;
177 
178  case NORMAL:
179  break;
180 
181  case TOUCHED_LEFT:
182  overlay = touchedUpImage_;
183  base = touchedBaseImage_;
184  break;
185  case TOUCHED_RIGHT:
186  overlay = touchedDownImage_;
187  base = touchedBaseImage_;
188  break;
189  case TOUCHED_BOTH_LEFT:
190  case TOUCHED_BOTH_RIGHT:
191  overlay = touchedBothImage_;
192  base = touchedBaseImage_;
193  break;
194  case ACTIVE:
195  // overlay = activeImage_;
196  base = activeBaseImage_;
197  break;
198  case PRESSED_LEFT:
199  base = activeBaseImage_;
200  overlay = pressedUpImage_;
201  break;
202  case PRESSED_RIGHT:
203  base = activeBaseImage_;
204  overlay = pressedDownImage_;
205  break;
206  case PRESSED_BOTH:
207  base = activeBaseImage_;
208  overlay = pressedBothImage_;
209  break;
210  case PRESSED_ACTIVE_LEFT:
211  overlay = pressedUpActiveImage_;
212  base = activeBaseImage_;
213  break;
214  case PRESSED_ACTIVE_BOTH:
215  overlay = pressedBothActiveImage_;
216  base = activeBaseImage_;
217  break;
219  overlay = pressedDownActiveImage_;
220  base = activeBaseImage_;
221  break;
222  }
223 
224  image = base;
225 
226  const int image_w = image->w;
227  SDL_Rect const &loc = location();
228  SDL_Rect clipArea = loc;
229  const int texty = loc.y + loc.h / 2 - textRect_.h / 2 + offset;
230  int textx;
231 
232  clipArea.w += image_w + checkbox_horizontal_padding;
233  textx = loc.x + image_w + checkbox_horizontal_padding / 2;
234 
235  SDL_Color button_color = font::BUTTON_COLOR;
236 
237  surface scalled_item;
238  scalled_item.assign(scale_surface(itemImage_,
239  36, 36));
240 
241  // blit_surface want neutral surfaces
242  surface nitem = make_neutral_surface(scalled_item);
243  surface nbase = make_neutral_surface(base);
244 
245  //TODO avoid magic numbers
246  SDL_Rect r = sdl::create_rect(1, 1, 0, 0);
247  blit_surface(nitem, nullptr, nbase, &r);
248 
249  if (!overlay.null()) {
250  surface noverlay = make_neutral_surface(overlay);
251  blit_surface(noverlay, nullptr, nbase, nullptr);
252  }
253 
254 // TODO for later reference
255 // SDL_SetAlpha(nbase, SDL_SRCALPHA, SDL_ALPHA_OPAQUE);
256 // SDL_SetAlpha(image, 0, 0);
257 //
258 // TODO might be needed.
259  bg_restore();
260 
261  image = nbase;
262  video().blit_surface(loc.x, loc.y, image);
263 
264  clipArea.x += offset;
265  clipArea.y += offset;
266  clipArea.w -= 2 * offset;
267  clipArea.h -= 2 * offset;
268  font::draw_text(&video(), clipArea, font_size, button_color, label_, textx,
269  texty);
270 
271  update_rect(loc);
272 }
273 
274 //TODO move to widget
275 bool tristate_button::hit(int x, int y) const {
276  return sdl::point_in_rect(x, y, location());
277 }
278 
279 void tristate_button::mouse_motion(SDL_MouseMotionEvent const &event) {
280 
281  if (hit(event.x, event.y))
282  { // the cursor is over the widget
283 
284  switch (state_) {
285 
286  case UNINIT:
287  return;
288 
289  case NORMAL:
290  state_ = ACTIVE;
291  break;
292  case PRESSED_LEFT:
294  break;
295  case PRESSED_RIGHT:
297  break;
298  case PRESSED_BOTH:
300  break;
301  default:
302  //assert(false);
303  break;
304  }
305 
306  } else { // the cursor is not over the widget
307 
308  switch (state_) {
309 
310  case ACTIVE:
311  state_ = NORMAL;
312  break;
313  case TOUCHED_LEFT:
314  case TOUCHED_RIGHT:
315  state_ = ACTIVE;
316  break;
318  case TOUCHED_BOTH_RIGHT:
320  break;
321  case PRESSED_ACTIVE_BOTH:
323  break;
324  case PRESSED_ACTIVE_LEFT:
325  case TOUCHED_BOTH_LEFT:
327  break;
328  default:
329  break;
330  }
331  }
332 }
333 
334 void tristate_button::mouse_down(SDL_MouseButtonEvent const &event) {
335 
336  if (!hit(event.x, event.y))
337  return;
338 
339  if (event.button == SDL_BUTTON_RIGHT) {
340  if (state_ == ACTIVE)
344  }
345 
346  if (event.button == SDL_BUTTON_LEFT) {
347  if (state_ == ACTIVE)
351  }
352 
353 }
354 
356  state_ = NORMAL;
357  draw_contents();
358 }
359 
360 void tristate_button::mouse_up(SDL_MouseButtonEvent const &event) {
361 
362  if (!(hit(event.x, event.y)))
363  return;
364 
365  // the user has stopped pressing the mouse left button while on the widget
366  if (event.button == SDL_BUTTON_LEFT) {
367 
368  if (state_ == TOUCHED_LEFT) {
371  //TODO
372  // palette_->draw(true);
373  pressed_ = true;
374  }
375  if (state_ == TOUCHED_BOTH_RIGHT) {
378  // palette_->select_bg_item(item_id_);
379  // palette_->draw(true);
380  pressed_ = true;
381  }
382  }
383 
384  if (event.button == SDL_BUTTON_RIGHT) {
385 
386  pressed_ = true;
388 
389  if (state_ == TOUCHED_RIGHT) {
391  // palette_->select_bg_item(item_id_);
392  // palette_->draw(true);
393  // pressed_ = true;
394  }
395  if (state_ == TOUCHED_BOTH_LEFT) {
397  // palette_->select_fg_item(item_id_);
398  // palette_->select_bg_item(item_id_);
399  // palette_->draw(true);
400  // pressed_ = true;
401  }
402  }
403 
404  if (pressed_)
406 }
407 
408 void tristate_button::handle_event(const SDL_Event& event) {
409 
411 
412  if (hidden() || !enabled())
413  return;
414 
415  STATE start_state = state_;
416 
417  if (!mouse_locked()) {
418  switch (event.type) {
419  case SDL_MOUSEBUTTONDOWN:
420  mouse_down(event.button);
421  break;
422  case SDL_MOUSEBUTTONUP:
423  mouse_up(event.button);
424  break;
425  case SDL_MOUSEMOTION:
426  mouse_motion(event.motion);
427  break;
428  default:
429  return;
430  }
431  }
432 
433  if (start_state != state_)
434  set_dirty(true);
435 }
436 
438  const bool res = pressed_;
439  pressed_ = false;
440  return res;
441 }
442 
443 }
const SDL_Color BUTTON_COLOR
Definition: font.cpp:571
surface get_image(const image::locator &i_locator, TYPE type)
function to get the surface corresponding to an image.
Definition: image.cpp:878
virtual void mouse_up(const SDL_MouseButtonEvent &event)
bool null() const
Definition: utils.hpp:104
bool hit(int x, int y) const
virtual void mouse_down(const SDL_MouseButtonEvent &event)
bool enabled() const
Definition: widget.cpp:212
virtual void enable(bool new_val=true)
Definition: widget.cpp:204
virtual void select_bg_item(const std::string &item_id)=0
virtual ~tristate_button()
Default implementation, but defined out-of-line for efficiency reasons.
Definition: video.hpp:58
PRESSED_STATE pressed_state() const
CVideo & video() const
Definition: widget.hpp:83
General purpose widgets.
GLenum GLsizei GLenum GLenum const GLvoid * image
Definition: glew.h:3783
virtual void enable(bool new_val=true)
GLint GLint GLint GLint GLint GLint y
Definition: glew.h:1220
surface scale_surface(const surface &surf, int w, int h)
Definition: utils.cpp:443
void blit_surface(int x, int y, surface surf, SDL_Rect *srcrect=nullptr, SDL_Rect *clip_rect=nullptr)
Definition: video.cpp:290
-file util.hpp
editor::tristate_palette * palette_
virtual void select_fg_item(const std::string &item_id)=0
void blit_surface(const surface &surf, const SDL_Rect *srcrect, surface &dst, const SDL_Rect *dstrect)
Replacement for sdl_blit.
Definition: utils.cpp:2185
void set_pressed(PRESSED_STATE new_pressed_state)
GLintptr offset
Definition: glew.h:1650
bool hidden() const
Definition: widget.cpp:198
void set_dirty(bool dirty=true)
Definition: widget.cpp:217
bool point_in_rect(int x, int y, const SDL_Rect &rect)
Tests whether a point is inside a rectangle.
Definition: rect.cpp:47
virtual void mouse_motion(const SDL_MouseMotionEvent &event)
SDL_Rect draw_text(surface &dst, const SDL_Rect &area, int size, const SDL_Color &color, const std::string &txt, int x, int y, bool use_tooltips, int style)
Function to draw text on a surface.
GLuint res
Definition: glew.h:9258
virtual void handle_event(const SDL_Event &event)
GLint GLint GLint GLint GLint x
Definition: glew.h:1220
GLdouble GLdouble GLdouble r
Definition: glew.h:1374
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
void bg_restore() const
Definition: widget.cpp:251
cl_event event
Definition: glew.h:3070
virtual void draw_contents()
surface make_neutral_surface(const surface &surf)
Definition: utils.cpp:135
void play_UI_sound(const std::string &files)
Definition: sound.cpp:842
Standard logging facilities (interface).
bool mouse_locked() const
Definition: widget.cpp:72
void assign(const surface &o)
Definition: utils.hpp:83
virtual void handle_event(SDL_Event const &)
Definition: widget.cpp:345
SDL_Rect const & location() const
Definition: widget.cpp:144
Compatibility layer for using SDL 1.2 and 2.0.
const int font_size
void update_rect(const SDL_Rect &)
Definition: dummy_video.cpp:27
std::vector< Uint32 > palette(color_range cr)
Creates a reference color palette from a color range.
GLsizei const GLcharARB ** string
Definition: glew.h:4503
static lg::log_domain log_display("display")
tristate_button(CVideo &video, editor::tristate_palette *palette, std::string button_image="", const bool auto_join=true)
const int SIZE_SMALL
Definition: font.hpp:62
const int checkbox_horizontal_padding
const std::string checkbox_release