The Battle for Wesnoth  1.13.10+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 - 2017 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 "font/constants.hpp"
20 #include "font/sdl_ttf.hpp"
21 #include "font/standard_colors.hpp"
22 #include "game_config.hpp"
23 #include "image.hpp"
24 #include "log.hpp"
25 #include "font/marked-up_text.hpp"
26 #include "sdl/rect.hpp"
28 #include "sound.hpp"
29 #include "video.hpp"
30 
31 static lg::log_domain log_display("display");
32 #define ERR_DP LOG_STREAM(err, log_display)
33 
34 namespace gui {
35 
38 
41  std::string button_image_name,
42  const bool auto_join) :
43  widget(video, auto_join),
44  baseImage_(nullptr), touchedBaseImage_(nullptr), activeBaseImage_(nullptr),
45  itemImage_(nullptr),
46  pressedDownImage_(nullptr), pressedUpImage_(nullptr), pressedBothImage_(nullptr),
47  pressedBothActiveImage_(nullptr), pressedDownActiveImage_(nullptr), pressedUpActiveImage_(nullptr),
48  touchedDownImage_(nullptr), touchedUpImage_(nullptr), touchedBothImage_(nullptr),
49  textRect_(),
50  state_(NORMAL), pressed_(false),
51  base_height_(0), base_width_(0),
52  palette_(palette), item_id_()
53 {
54 
55  if (button_image_name.empty()) {
56  button_image_name = "buttons/button_selectable/button_selectable_38_";
57  }
58 
60  image::get_image(button_image_name + "base.png"));
62  image::get_image(button_image_name + "base-active.png"));
64  image::get_image(button_image_name + "base-touched.png"));
65 
67  image::get_image(button_image_name + "border-touched-both.png"));
69  image::get_image(button_image_name + "border-touched-up.png"));
71  image::get_image(button_image_name + "border-touched-down.png"));
72 
74  image::get_image(button_image_name + "border-pressed-up.png"));
76  image::get_image(button_image_name + "border-pressed-down.png"));
78  image::get_image(button_image_name + "border-pressed-both.png"));
79 
81  image::get_image(button_image_name + "border-active-pressed-up.png"));
83  image::get_image(button_image_name + "border-active-pressed-down.png"));
85  image::get_image(button_image_name + "border-active-pressed-both.png"));
86 
87  //TODO
88 // if (button_image.null()) {
89 // ERR_DP<< "error initializing button!" << std::endl;
90 // throw error();
91 // }
92 
95 
96 }
97 
99 
101 
102  STATE new_state = state_;
103 
104  switch (new_pressed_state) {
105  case LEFT:
107  break;
108  case RIGHT:
110  break;
111  case BOTH:
113  break;
114  case NONE:
115  new_state = NORMAL;
116  }
117 
118  if (state_ != new_state) {
119  state_ = new_state;
120  set_dirty();
121  }
122 }
123 
124 //TODO
125 //void tristate_button::set_active(bool active) {
126 // if ((state_ == NORMAL) && active) {
127 // state_ = ACTIVE;
128 // set_dirty();
129 // } else if ((state_ == ACTIVE) && !active) {
130 // state_ = NORMAL;
131 // set_dirty();
132 // }
133 //}
134 
136 
137  switch (state_) {
138  case PRESSED_LEFT:
139  case PRESSED_ACTIVE_LEFT:
140  case TOUCHED_BOTH_LEFT:
141  return LEFT;
142  case PRESSED_RIGHT:
144  case TOUCHED_BOTH_RIGHT:
145  return RIGHT;
146  case PRESSED_BOTH:
147  case PRESSED_ACTIVE_BOTH:
148  return BOTH;
149  default:
150  return NONE;
151  }
152 }
153 
154 void tristate_button::enable(bool new_val) {
155  if (new_val != enabled()) {
156  pressed_ = false;
157  // check buttons should keep their state
158  state_ = NORMAL;
159 
160  widget::enable(new_val);
161  }
162 }
163 
165 
166  surface image(nullptr);
167 
168  surface overlay(nullptr);
169  surface base = baseImage_;
170 
171  int offset = 0;
172  switch (state_) {
173 
174  case UNINIT:
175  return;
176 
177  case NORMAL:
178  break;
179 
180  case TOUCHED_LEFT:
181  overlay = touchedUpImage_;
182  base = touchedBaseImage_;
183  break;
184  case TOUCHED_RIGHT:
185  overlay = touchedDownImage_;
186  base = touchedBaseImage_;
187  break;
188  case TOUCHED_BOTH_LEFT:
189  case TOUCHED_BOTH_RIGHT:
190  overlay = touchedBothImage_;
191  base = touchedBaseImage_;
192  break;
193  case ACTIVE:
194  // overlay = activeImage_;
195  base = activeBaseImage_;
196  break;
197  case PRESSED_LEFT:
198  base = activeBaseImage_;
199  overlay = pressedUpImage_;
200  break;
201  case PRESSED_RIGHT:
202  base = activeBaseImage_;
203  overlay = pressedDownImage_;
204  break;
205  case PRESSED_BOTH:
206  base = activeBaseImage_;
207  overlay = pressedBothImage_;
208  break;
209  case PRESSED_ACTIVE_LEFT:
210  overlay = pressedUpActiveImage_;
211  base = activeBaseImage_;
212  break;
213  case PRESSED_ACTIVE_BOTH:
214  overlay = pressedBothActiveImage_;
215  base = activeBaseImage_;
216  break;
218  overlay = pressedDownActiveImage_;
219  base = activeBaseImage_;
220  break;
221  }
222 
223  image = base;
224 
225  const int image_w = image->w;
226  SDL_Rect const &loc = location();
227  SDL_Rect clipArea = loc;
228  const int texty = loc.y + loc.h / 2 - textRect_.h / 2 + offset;
229  int textx;
230 
231  clipArea.w += image_w + checkbox_horizontal_padding;
232  textx = loc.x + image_w + checkbox_horizontal_padding / 2;
233 
234  color_t button_color = font::BUTTON_COLOR;
235 
236  surface scalled_item;
237  scalled_item.assign(scale_surface(itemImage_,
238  36, 36));
239 
240  surface nitem = make_neutral_surface(scalled_item);
241  surface nbase = make_neutral_surface(base);
242 
243  //TODO avoid magic numbers
244  SDL_Rect r {1, 1, 0, 0};
245  sdl_blit(nitem, nullptr, nbase, &r);
246 
247  if (!overlay.null()) {
248  surface noverlay = make_neutral_surface(overlay);
249  sdl_blit(noverlay, nullptr, nbase, nullptr);
250  }
251 
252  bg_restore();
253 
254  image = nbase;
255  video().blit_surface(loc.x, loc.y, image);
256 
257  clipArea.x += offset;
258  clipArea.y += offset;
259  clipArea.w -= 2 * offset;
260  clipArea.h -= 2 * offset;
261  font::draw_text(&video(), clipArea, font_size, button_color, label_, textx,
262  texty);
263 }
264 
265 //TODO move to widget
266 bool tristate_button::hit(int x, int y) const {
267  return sdl::point_in_rect(x, y, location());
268 }
269 
270 void tristate_button::mouse_motion(SDL_MouseMotionEvent const &event) {
271 
272  if (hit(event.x, event.y))
273  { // the cursor is over the widget
274 
275  switch (state_) {
276 
277  case UNINIT:
278  return;
279 
280  case NORMAL:
281  state_ = ACTIVE;
282  break;
283  case PRESSED_LEFT:
285  break;
286  case PRESSED_RIGHT:
288  break;
289  case PRESSED_BOTH:
291  break;
292  default:
293  //assert(false);
294  break;
295  }
296 
297  } else { // the cursor is not over the widget
298 
299  switch (state_) {
300 
301  case ACTIVE:
302  state_ = NORMAL;
303  break;
304  case TOUCHED_LEFT:
305  case TOUCHED_RIGHT:
306  state_ = ACTIVE;
307  break;
309  case TOUCHED_BOTH_RIGHT:
311  break;
312  case PRESSED_ACTIVE_BOTH:
314  break;
315  case PRESSED_ACTIVE_LEFT:
316  case TOUCHED_BOTH_LEFT:
318  break;
319  default:
320  break;
321  }
322  }
323 }
324 
325 void tristate_button::mouse_down(SDL_MouseButtonEvent const &event) {
326 
327  if (!hit(event.x, event.y))
328  return;
329 
330  if (event.button == SDL_BUTTON_RIGHT) {
331  if (state_ == ACTIVE)
335  }
336 
337  if (event.button == SDL_BUTTON_LEFT) {
338  if (state_ == ACTIVE)
342  }
343 
344 }
345 
347  state_ = NORMAL;
348  draw_contents();
349 }
350 
351 void tristate_button::mouse_up(SDL_MouseButtonEvent const &event) {
352 
353  if (!(hit(event.x, event.y)))
354  return;
355 
356  // the user has stopped pressing the mouse left button while on the widget
357  if (event.button == SDL_BUTTON_LEFT) {
358 
359  if (state_ == TOUCHED_LEFT) {
362  //TODO
363  // palette_->draw(true);
364  pressed_ = true;
365  }
366  if (state_ == TOUCHED_BOTH_RIGHT) {
369  // palette_->select_bg_item(item_id_);
370  // palette_->draw(true);
371  pressed_ = true;
372  }
373  }
374 
375  if (event.button == SDL_BUTTON_RIGHT) {
376 
377  pressed_ = true;
379 
380  if (state_ == TOUCHED_RIGHT) {
382  // palette_->select_bg_item(item_id_);
383  // palette_->draw(true);
384  // pressed_ = true;
385  }
386  if (state_ == TOUCHED_BOTH_LEFT) {
388  // palette_->select_fg_item(item_id_);
389  // palette_->select_bg_item(item_id_);
390  // palette_->draw(true);
391  // pressed_ = true;
392  }
393  }
394 
395  if (pressed_)
397 }
398 
399 void tristate_button::handle_event(const SDL_Event& event) {
400 
402 
403  if (hidden() || !enabled())
404  return;
405 
406  STATE start_state = state_;
407 
408  if (!mouse_locked()) {
409  switch (event.type) {
410  case SDL_MOUSEBUTTONDOWN:
411  mouse_down(event.button);
412  break;
413  case SDL_MOUSEBUTTONUP:
414  mouse_up(event.button);
415  break;
416  case SDL_MOUSEMOTION:
417  mouse_motion(event.motion);
418  break;
419  default:
420  return;
421  }
422  }
423 
424  if (start_state != state_)
425  set_dirty(true);
426 }
427 
429  const bool res = pressed_;
430  pressed_ = false;
431  return res;
432 }
433 
434 }
const color_t BUTTON_COLOR
surface get_image(const image::locator &i_locator, TYPE type)
function to get the surface corresponding to an image.
Definition: image.cpp:926
virtual void mouse_up(const SDL_MouseButtonEvent &event)
bool hit(int x, int y) const
std::vector< char_t > string
virtual void mouse_down(const SDL_MouseButtonEvent &event)
bool enabled() const
Definition: widget.cpp:210
virtual void enable(bool new_val=true)
Definition: widget.cpp:202
bool null() const
Definition: surface.hpp:79
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:85
virtual ~tristate_button()
Default implementation, but defined out-of-line for efficiency reasons.
Definition: video.hpp:31
PRESSED_STATE pressed_state() const
CVideo & video() const
Definition: widget.hpp:84
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:274
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:162
-file util.hpp
editor::tristate_palette * palette_
virtual void select_fg_item(const std::string &item_id)=0
void set_pressed(PRESSED_STATE new_pressed_state)
bool hidden() const
Definition: widget.cpp:196
void set_dirty(bool dirty=true)
Definition: widget.cpp:215
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 assign(SDL_Surface *surf)
Definition: surface.hpp:46
Contains the SDL_Rect helper code.
void bg_restore() const
Definition: widget.cpp:249
SDL_Rect draw_text(surface &dst, const SDL_Rect &area, int size, const color_t &color, const std::string &txt, int x, int y, bool use_tooltips, int style)
Function to draw text on a surface.
surface make_neutral_surface(const surface &surf)
Definition: utils.cpp:72
this module manages the cache of images.
Definition: image.cpp:109
void play_UI_sound(const std::string &files)
Definition: sound.cpp:1020
Standard logging facilities (interface).
bool mouse_locked() const
Definition: widget.cpp:70
virtual void handle_event(SDL_Event const &)
Definition: widget.cpp:338
SDL_Rect const & location() const
Definition: widget.cpp:142
void sdl_blit(const surface &src, SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:33
const int font_size
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)
const int SIZE_SMALL
Definition: constants.cpp:23
const int checkbox_horizontal_padding
const std::string checkbox_release