The Battle for Wesnoth  1.15.0-dev
tristate_button.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2013 - 2018 by Fabian Mueller <fabianmueller5@gmx.de>
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 
18 
19 #include "image.hpp"
20 #include "log.hpp"
21 #include "sdl/rect.hpp"
22 #include "sound.hpp"
23 #include "video.hpp"
24 
25 static lg::log_domain log_display("display");
26 #define ERR_DP LOG_STREAM(err, log_display)
27 
28 namespace gui {
29 
32  std::string button_image_name,
33  const bool auto_join) :
34  widget(video, auto_join),
35  baseImage_(nullptr), touchedBaseImage_(nullptr), activeBaseImage_(nullptr),
36  itemImage_(nullptr),
37  pressedDownImage_(nullptr), pressedUpImage_(nullptr), pressedBothImage_(nullptr),
38  pressedBothActiveImage_(nullptr), pressedDownActiveImage_(nullptr), pressedUpActiveImage_(nullptr),
39  touchedDownImage_(nullptr), touchedUpImage_(nullptr), touchedBothImage_(nullptr),
40  textRect_(),
41  state_(NORMAL), pressed_(false),
42  base_height_(0), base_width_(0),
43  palette_(palette), item_id_()
44 {
45 
46  if (button_image_name.empty()) {
47  button_image_name = "buttons/button_selectable/button_selectable_38_";
48  }
49 
51  image::get_image(button_image_name + "base.png"));
53  image::get_image(button_image_name + "base-active.png"));
55  image::get_image(button_image_name + "base-touched.png"));
56 
58  image::get_image(button_image_name + "border-touched-both.png"));
60  image::get_image(button_image_name + "border-touched-up.png"));
62  image::get_image(button_image_name + "border-touched-down.png"));
63 
65  image::get_image(button_image_name + "border-pressed-up.png"));
67  image::get_image(button_image_name + "border-pressed-down.png"));
69  image::get_image(button_image_name + "border-pressed-both.png"));
70 
72  image::get_image(button_image_name + "border-active-pressed-up.png"));
74  image::get_image(button_image_name + "border-active-pressed-down.png"));
76  image::get_image(button_image_name + "border-active-pressed-both.png"));
77 
78  //TODO
79 // if (button_image.null()) {
80 // ERR_DP<< "error initializing button!" << std::endl;
81 // throw error();
82 // }
83 
86 
87 }
88 
90 
92 
93  STATE new_state = state_;
94 
95  switch (new_pressed_state) {
96  case LEFT:
98  break;
99  case RIGHT:
101  break;
102  case BOTH:
104  break;
105  case NONE:
106  new_state = NORMAL;
107  }
108 
109  if (state_ != new_state) {
110  state_ = new_state;
111  set_dirty();
112  }
113 }
114 
115 //TODO
116 //void tristate_button::set_active(bool active) {
117 // if ((state_ == NORMAL) && active) {
118 // state_ = ACTIVE;
119 // set_dirty();
120 // } else if ((state_ == ACTIVE) && !active) {
121 // state_ = NORMAL;
122 // set_dirty();
123 // }
124 //}
125 
127 
128  switch (state_) {
129  case PRESSED_LEFT:
130  case PRESSED_ACTIVE_LEFT:
131  case TOUCHED_BOTH_LEFT:
132  return LEFT;
133  case PRESSED_RIGHT:
135  case TOUCHED_BOTH_RIGHT:
136  return RIGHT;
137  case PRESSED_BOTH:
138  case PRESSED_ACTIVE_BOTH:
139  return BOTH;
140  default:
141  return NONE;
142  }
143 }
144 
145 void tristate_button::enable(bool new_val) {
146  if (new_val != enabled()) {
147  pressed_ = false;
148  // check buttons should keep their state
149  state_ = NORMAL;
150 
151  widget::enable(new_val);
152  }
153 }
154 
156 
157  surface image(nullptr);
158 
159  surface overlay(nullptr);
160  surface base = baseImage_;
161 
162  switch (state_) {
163 
164  case UNINIT:
165  return;
166 
167  case NORMAL:
168  break;
169 
170  case TOUCHED_LEFT:
171  overlay = touchedUpImage_;
172  base = touchedBaseImage_;
173  break;
174  case TOUCHED_RIGHT:
175  overlay = touchedDownImage_;
176  base = touchedBaseImage_;
177  break;
178  case TOUCHED_BOTH_LEFT:
179  case TOUCHED_BOTH_RIGHT:
180  overlay = touchedBothImage_;
181  base = touchedBaseImage_;
182  break;
183  case ACTIVE:
184  // overlay = activeImage_;
185  base = activeBaseImage_;
186  break;
187  case PRESSED_LEFT:
188  base = activeBaseImage_;
189  overlay = pressedUpImage_;
190  break;
191  case PRESSED_RIGHT:
192  base = activeBaseImage_;
193  overlay = pressedDownImage_;
194  break;
195  case PRESSED_BOTH:
196  base = activeBaseImage_;
197  overlay = pressedBothImage_;
198  break;
199  case PRESSED_ACTIVE_LEFT:
200  overlay = pressedUpActiveImage_;
201  base = activeBaseImage_;
202  break;
203  case PRESSED_ACTIVE_BOTH:
204  overlay = pressedBothActiveImage_;
205  base = activeBaseImage_;
206  break;
208  overlay = pressedDownActiveImage_;
209  base = activeBaseImage_;
210  break;
211  }
212 
213  image = base;
214 
215  const SDL_Rect& loc = location();
216 
217  surface scalled_item;
218  scalled_item.assign(scale_surface(itemImage_,
219  36, 36));
220 
221  surface nitem = make_neutral_surface(scalled_item);
222  surface nbase = make_neutral_surface(base);
223 
224  //TODO avoid magic numbers
225  SDL_Rect r {1, 1, 0, 0};
226  sdl_blit(nitem, nullptr, nbase, &r);
227 
228  if (!overlay.null()) {
229  surface noverlay = make_neutral_surface(overlay);
230  sdl_blit(noverlay, nullptr, nbase, nullptr);
231  }
232 
233  bg_restore();
234 
235  image = nbase;
236  UNUSED(loc);
237  UNUSED(image);
238  //video().blit_surface(loc.x, loc.y, image);
239 }
240 
241 //TODO move to widget
242 bool tristate_button::hit(int x, int y) const {
243  return sdl::point_in_rect(x, y, location());
244 }
245 
246 void tristate_button::mouse_motion(const SDL_MouseMotionEvent& event) {
247 
248  if (hit(event.x, event.y))
249  { // the cursor is over the widget
250 
251  switch (state_) {
252 
253  case UNINIT:
254  return;
255 
256  case NORMAL:
257  state_ = ACTIVE;
258  break;
259  case PRESSED_LEFT:
261  break;
262  case PRESSED_RIGHT:
264  break;
265  case PRESSED_BOTH:
267  break;
268  default:
269  //assert(false);
270  break;
271  }
272 
273  } else { // the cursor is not over the widget
274 
275  switch (state_) {
276 
277  case ACTIVE:
278  state_ = NORMAL;
279  break;
280  case TOUCHED_LEFT:
281  case TOUCHED_RIGHT:
282  state_ = ACTIVE;
283  break;
285  case TOUCHED_BOTH_RIGHT:
287  break;
288  case PRESSED_ACTIVE_BOTH:
290  break;
291  case PRESSED_ACTIVE_LEFT:
292  case TOUCHED_BOTH_LEFT:
294  break;
295  default:
296  break;
297  }
298  }
299 }
300 
301 void tristate_button::mouse_down(const SDL_MouseButtonEvent& event) {
302 
303  if (!hit(event.x, event.y))
304  return;
305 
306  if (event.button == SDL_BUTTON_RIGHT) {
307  if (state_ == ACTIVE)
311  }
312 
313  if (event.button == SDL_BUTTON_LEFT) {
314  if (state_ == ACTIVE)
318  }
319 
320 }
321 
323  state_ = NORMAL;
324  draw_contents();
325 }
326 
327 void tristate_button::mouse_up(const SDL_MouseButtonEvent& event) {
328 
329  if (!(hit(event.x, event.y)))
330  return;
331 
332  // the user has stopped pressing the mouse left button while on the widget
333  if (event.button == SDL_BUTTON_LEFT) {
334 
335  if (state_ == TOUCHED_LEFT) {
338  //TODO
339  // palette_->draw(true);
340  pressed_ = true;
341  }
342  if (state_ == TOUCHED_BOTH_RIGHT) {
345  // palette_->select_bg_item(item_id_);
346  // palette_->draw(true);
347  pressed_ = true;
348  }
349  }
350 
351  if (event.button == SDL_BUTTON_RIGHT) {
352 
353  pressed_ = true;
355 
356  if (state_ == TOUCHED_RIGHT) {
358  // palette_->select_bg_item(item_id_);
359  // palette_->draw(true);
360  // pressed_ = true;
361  }
362  if (state_ == TOUCHED_BOTH_LEFT) {
364  // palette_->select_fg_item(item_id_);
365  // palette_->select_bg_item(item_id_);
366  // palette_->draw(true);
367  // pressed_ = true;
368  }
369  }
370 
371  //if (pressed_)
372  //sound::play_UI_sound(game_config::sounds::checkbox_release);
373 }
374 
375 void tristate_button::handle_event(const SDL_Event& event) {
376 
378 
379  if (hidden() || !enabled())
380  return;
381 
382  STATE start_state = state_;
383 
384  if (!mouse_locked()) {
385  switch (event.type) {
386  case SDL_MOUSEBUTTONDOWN:
387  mouse_down(event.button);
388  break;
389  case SDL_MOUSEBUTTONUP:
390  mouse_up(event.button);
391  break;
392  case SDL_MOUSEMOTION:
393  mouse_motion(event.motion);
394  break;
395  default:
396  return;
397  }
398  }
399 
400  if (start_state != state_)
401  set_dirty(true);
402 }
403 
405  const bool res = pressed_;
406  pressed_ = false;
407  return res;
408 }
409 
410 }
surface get_image(const image::locator &i_locator, TYPE type)
function to get the surface corresponding to an image.
Definition: image.cpp:989
virtual void mouse_up(const SDL_MouseButtonEvent &event)
bool enabled() const
Definition: widget.cpp:205
virtual void mouse_down(const SDL_MouseButtonEvent &event)
virtual void enable(bool new_val=true)
Definition: widget.cpp:197
surface scale_surface(const surface &surf, int w, int h)
Scale a surface using alpha-weighted modified bilinear filtering Note: causes artifacts with alpha gr...
Definition: utils.cpp:275
bool hidden() const
Definition: widget.cpp:191
virtual void select_bg_item(const std::string &item_id)=0
std::vector< color_t > palette(const color_range &cr)
Creates a reference color palette from a color range.
Definition: color_range.cpp:83
virtual ~tristate_button()
Default implementation, but defined out-of-line for efficiency reasons.
Definition: video.hpp:36
General purpose widgets.
-file util.hpp
editor::tristate_palette * palette_
bool null() const
Definition: surface.hpp:79
virtual void select_fg_item(const std::string &item_id)=0
void set_pressed(PRESSED_STATE new_pressed_state)
void set_dirty(bool dirty=true)
Definition: widget.cpp:210
virtual void handle_event(const SDL_Event &)
Definition: widget.cpp:315
const SDL_Rect & location() const
Definition: widget.cpp:137
virtual void handle_event(const SDL_Event &event) override
bool point_in_rect(int x, int y, const SDL_Rect &rect)
Tests whether a point is inside a rectangle.
Definition: rect.cpp:22
virtual void mouse_motion(const SDL_MouseMotionEvent &event)
#define UNUSED(x)
Definition: global.hpp:34
surface make_neutral_surface(const surface &surf)
Definition: utils.cpp:73
virtual void draw_contents() override
void sdl_blit(const surface &src, SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:33
void bg_restore() const
Definition: widget.cpp:241
bool mouse_locked() const
Definition: widget.cpp:70
void assign(SDL_Surface *surf)
Definition: surface.hpp:46
Contains the SDL_Rect helper code.
this module manages the cache of images.
Definition: image.cpp:102
Standard logging facilities (interface).
PRESSED_STATE pressed_state() const
virtual void enable(bool new_val=true) override
static lg::log_domain log_display("display")
tristate_button(CVideo &video, editor::tristate_palette *palette, std::string button_image="", const bool auto_join=true)
bool hit(int x, int y) const