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 https://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 "game_config.hpp"
20 #include "picture.hpp"
21 #include "log.hpp"
22 #include "sdl/rect.hpp"
23 #include "sound.hpp"
24 #include "video.hpp"
25 
26 static lg::log_domain log_display("display");
27 #define ERR_DP LOG_STREAM(err, log_display)
28 
29 namespace gui {
30 
33  std::string button_image_name,
34  const bool auto_join) :
35  widget(video, auto_join),
36  baseImage_(nullptr), touchedBaseImage_(nullptr), activeBaseImage_(nullptr),
37  itemImage_(nullptr),
38  pressedDownImage_(nullptr), pressedUpImage_(nullptr), pressedBothImage_(nullptr),
39  pressedBothActiveImage_(nullptr), pressedDownActiveImage_(nullptr), pressedUpActiveImage_(nullptr),
40  touchedDownImage_(nullptr), touchedUpImage_(nullptr), touchedBothImage_(nullptr),
41  textRect_(),
42  state_(NORMAL), pressed_(false),
43  base_height_(0), base_width_(0),
44  palette_(palette), item_id_()
45 {
46 
47  if (button_image_name.empty()) {
48  button_image_name = "buttons/button_selectable/button_selectable_38_";
49  }
50 
51  baseImage_ =
52  image::get_image(button_image_name + "base.png");
54  image::get_image(button_image_name + "base-active.png");
56  image::get_image(button_image_name + "base-touched.png");
57 
59  image::get_image(button_image_name + "border-touched-both.png");
61  image::get_image(button_image_name + "border-touched-up.png");
63  image::get_image(button_image_name + "border-touched-down.png");
64 
66  image::get_image(button_image_name + "border-pressed-up.png");
68  image::get_image(button_image_name + "border-pressed-down.png");
70  image::get_image(button_image_name + "border-pressed-both.png");
71 
73  image::get_image(button_image_name + "border-active-pressed-up.png");
75  image::get_image(button_image_name + "border-active-pressed-down.png");
77  image::get_image(button_image_name + "border-active-pressed-both.png");
78 
79  //TODO
80 // if (button_image.null()) {
81 // ERR_DP<< "error initializing button!" << std::endl;
82 // throw error();
83 // }
84 
87 
88 }
89 
91 
93 
94  STATE new_state = state_;
95 
96  switch (new_pressed_state) {
97  case LEFT:
99  break;
100  case RIGHT:
102  break;
103  case BOTH:
105  break;
106  case NONE:
107  new_state = NORMAL;
108  }
109 
110  if (state_ != new_state) {
111  state_ = new_state;
112  set_dirty();
113  }
114 }
115 
116 //TODO
117 //void tristate_button::set_active(bool active) {
118 // if ((state_ == NORMAL) && active) {
119 // state_ = ACTIVE;
120 // set_dirty();
121 // } else if ((state_ == ACTIVE) && !active) {
122 // state_ = NORMAL;
123 // set_dirty();
124 // }
125 //}
126 
128 
129  switch (state_) {
130  case PRESSED_LEFT:
131  case PRESSED_ACTIVE_LEFT:
132  case TOUCHED_BOTH_LEFT:
133  return LEFT;
134  case PRESSED_RIGHT:
136  case TOUCHED_BOTH_RIGHT:
137  return RIGHT;
138  case PRESSED_BOTH:
139  case PRESSED_ACTIVE_BOTH:
140  return BOTH;
141  default:
142  return NONE;
143  }
144 }
145 
146 void tristate_button::enable(bool new_val) {
147  if (new_val != enabled()) {
148  pressed_ = false;
149  // check buttons should keep their state
150  state_ = NORMAL;
151 
152  widget::enable(new_val);
153  }
154 }
155 
157 
158  surface image(nullptr);
159 
160  surface overlay(nullptr);
161  surface base = baseImage_;
162 
163  switch (state_) {
164 
165  case UNINIT:
166  return;
167 
168  case NORMAL:
169  break;
170 
171  case TOUCHED_LEFT:
172  overlay = touchedUpImage_;
173  base = touchedBaseImage_;
174  break;
175  case TOUCHED_RIGHT:
176  overlay = touchedDownImage_;
177  base = touchedBaseImage_;
178  break;
179  case TOUCHED_BOTH_LEFT:
180  case TOUCHED_BOTH_RIGHT:
181  overlay = touchedBothImage_;
182  base = touchedBaseImage_;
183  break;
184  case ACTIVE:
185  // overlay = activeImage_;
186  base = activeBaseImage_;
187  break;
188  case PRESSED_LEFT:
189  base = activeBaseImage_;
190  overlay = pressedUpImage_;
191  break;
192  case PRESSED_RIGHT:
193  base = activeBaseImage_;
194  overlay = pressedDownImage_;
195  break;
196  case PRESSED_BOTH:
197  base = activeBaseImage_;
198  overlay = pressedBothImage_;
199  break;
200  case PRESSED_ACTIVE_LEFT:
201  overlay = pressedUpActiveImage_;
202  base = activeBaseImage_;
203  break;
204  case PRESSED_ACTIVE_BOTH:
205  overlay = pressedBothActiveImage_;
206  base = activeBaseImage_;
207  break;
209  overlay = pressedDownActiveImage_;
210  base = activeBaseImage_;
211  break;
212  }
213 
214  image = base;
215 
216  const SDL_Rect& loc = location();
217 
218  surface scaled_item = scale_surface(itemImage_, 36, 36);
219 
220  surface nbase = base.clone();
221 
222  //TODO avoid magic numbers
223  SDL_Rect r {1, 1, 0, 0};
224  sdl_blit(scaled_item, nullptr, nbase, &r);
225 
226  if (overlay) {
227  sdl_blit(overlay, nullptr, nbase, nullptr);
228  }
229 
230  bg_restore();
231 
232  image = nbase;
233  video().blit_surface(loc.x, loc.y, image);
234 }
235 
236 //TODO move to widget
237 bool tristate_button::hit(int x, int y) const {
238  return sdl::point_in_rect(x, y, location());
239 }
240 
241 void tristate_button::mouse_motion(const SDL_MouseMotionEvent& event) {
242 
243  if (hit(event.x, event.y))
244  { // the cursor is over the widget
245 
246  switch (state_) {
247 
248  case UNINIT:
249  return;
250 
251  case NORMAL:
252  state_ = ACTIVE;
253  break;
254  case PRESSED_LEFT:
256  break;
257  case PRESSED_RIGHT:
259  break;
260  case PRESSED_BOTH:
262  break;
263  default:
264  //assert(false);
265  break;
266  }
267 
268  } else { // the cursor is not over the widget
269 
270  switch (state_) {
271 
272  case ACTIVE:
273  state_ = NORMAL;
274  break;
275  case TOUCHED_LEFT:
276  case TOUCHED_RIGHT:
277  state_ = ACTIVE;
278  break;
280  case TOUCHED_BOTH_RIGHT:
282  break;
283  case PRESSED_ACTIVE_BOTH:
285  break;
286  case PRESSED_ACTIVE_LEFT:
287  case TOUCHED_BOTH_LEFT:
289  break;
290  default:
291  break;
292  }
293  }
294 }
295 
296 void tristate_button::mouse_down(const SDL_MouseButtonEvent& event) {
297 
298  if (!hit(event.x, event.y))
299  return;
300 
301  if (event.button == SDL_BUTTON_RIGHT) {
302  if (state_ == ACTIVE)
306  }
307 
308  if (event.button == SDL_BUTTON_LEFT) {
309  if (state_ == ACTIVE)
313  }
314 
315 }
316 
318  state_ = NORMAL;
319  draw_contents();
320 }
321 
322 void tristate_button::mouse_up(const SDL_MouseButtonEvent& event) {
323 
324  if (!(hit(event.x, event.y)))
325  return;
326 
327  // the user has stopped pressing the mouse left button while on the widget
328  if (event.button == SDL_BUTTON_LEFT) {
329 
330  if (state_ == TOUCHED_LEFT) {
333  //TODO
334  // palette_->draw(true);
335  pressed_ = true;
336  }
337  if (state_ == TOUCHED_BOTH_RIGHT) {
340  // palette_->select_bg_item(item_id_);
341  // palette_->draw(true);
342  pressed_ = true;
343  }
344  }
345 
346  if (event.button == SDL_BUTTON_RIGHT) {
347 
348  pressed_ = true;
350 
351  if (state_ == TOUCHED_RIGHT) {
353  // palette_->select_bg_item(item_id_);
354  // palette_->draw(true);
355  // pressed_ = true;
356  }
357  if (state_ == TOUCHED_BOTH_LEFT) {
359  // palette_->select_fg_item(item_id_);
360  // palette_->select_bg_item(item_id_);
361  // palette_->draw(true);
362  // pressed_ = true;
363  }
364  }
365 
366  if (pressed_)
368 }
369 
370 void tristate_button::handle_event(const SDL_Event& event) {
371 
373 
374  if (hidden() || !enabled())
375  return;
376 
377  STATE start_state = state_;
378 
379  if (!mouse_locked()) {
380  switch (event.type) {
381  case SDL_MOUSEBUTTONDOWN:
382  mouse_down(event.button);
383  break;
384  case SDL_MOUSEBUTTONUP:
385  mouse_up(event.button);
386  break;
387  case SDL_MOUSEMOTION:
388  mouse_motion(event.motion);
389  break;
390  default:
391  return;
392  }
393  }
394 
395  if (start_state != state_)
396  set_dirty(true);
397 }
398 
400  const bool res = pressed_;
401  pressed_ = false;
402  return res;
403 }
404 
405 }
surface get_image(const image::locator &i_locator, TYPE type)
function to get the surface corresponding to an image.
Definition: picture.cpp:875
virtual void mouse_up(const SDL_MouseButtonEvent &event)
bool enabled() const
Definition: widget.cpp:202
virtual void mouse_down(const SDL_MouseButtonEvent &event)
virtual void enable(bool new_val=true)
Definition: widget.cpp:194
bool hidden() const
Definition: widget.cpp:188
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:31
General purpose widgets.
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:196
void blit_surface(int x, int y, surface surf, SDL_Rect *srcrect=nullptr, SDL_Rect *clip_rect=nullptr)
Draws a surface directly onto the screen framebuffer.
Definition: video.cpp:163
-file util.hpp
surface clone() const
Makes a copy of this surface.
Definition: surface.cpp:75
editor::tristate_palette * palette_
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:207
virtual void handle_event(const SDL_Event &)
Definition: widget.cpp:330
const SDL_Rect & location() const
Definition: widget.cpp:134
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)
virtual void draw_contents() override
void bg_restore() const
Definition: widget.cpp:241
bool mouse_locked() const
Definition: widget.cpp:62
CVideo & video() const
Definition: widget.hpp:83
Contains the SDL_Rect helper code.
this module manages the cache of images.
void play_UI_sound(const std::string &files)
Definition: sound.cpp:1019
Standard logging facilities (interface).
PRESSED_STATE pressed_state() const
void sdl_blit(const surface &src, SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:33
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
const std::string checkbox_release