The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
tristate_button.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2013 - 2025
3 by Fabian Mueller <fabianmueller5@gmx.de>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16#define GETTEXT_DOMAIN "wesnoth-lib"
17
19
20#include "draw.hpp"
21#include "game_config.hpp"
22#include "picture.hpp"
23#include "log.hpp"
24#include "sdl/rect.hpp"
25#include "sound.hpp"
26
27static lg::log_domain log_display("display");
28#define ERR_DP LOG_STREAM(err, log_display)
29
30namespace gui {
31
34 std::string button_image_name,
35 const bool auto_join)
36 : widget(auto_join)
37 , baseImage_()
38 , touchedBaseImage_()
39 , activeBaseImage_()
40 , itemBaseImage_()
41 , itemOverlayImage_()
42 , pressedDownImage_()
43 , pressedUpImage_()
44 , pressedBothImage_()
45 , pressedBothActiveImage_()
46 , pressedDownActiveImage_()
47 , pressedUpActiveImage_()
48 , touchedDownImage_()
49 , touchedUpImage_()
50 , touchedBothImage_()
51 , textRect_()
52 , state_(NORMAL)
53 , pressed_(false)
54 , base_height_(0)
55 , base_width_(0)
56 , palette_(palette)
57 , item_id_()
58{
59 // TODO: highdpi - there seem to be higher-quality 74-px versions of these available, but as that's not actually an integer multiple of 38... this is not a straight swap
60
61 if (button_image_name.empty()) {
62 button_image_name = "buttons/button_selectable/button_selectable_38_";
63 }
64
66 image::get_texture(button_image_name + "base.png");
68 image::get_texture(button_image_name + "base-active.png");
70 image::get_texture(button_image_name + "base-touched.png");
71
73 image::get_texture(button_image_name + "border-touched-both.png");
75 image::get_texture(button_image_name + "border-touched-up.png");
77 image::get_texture(button_image_name + "border-touched-down.png");
78
80 image::get_texture(button_image_name + "border-pressed-up.png");
82 image::get_texture(button_image_name + "border-pressed-down.png");
84 image::get_texture(button_image_name + "border-pressed-both.png");
85
87 image::get_texture(button_image_name + "border-active-pressed-up.png");
89 image::get_texture(button_image_name + "border-active-pressed-down.png");
91 image::get_texture(button_image_name + "border-active-pressed-both.png");
92
93 //TODO
94// if (button_image.null()) {
95// ERR_DP<< "error initializing button!";
96// throw error();
97// }
98
99 // TODO: highdpi - set this some better way
102
103}
104
106
108
109 STATE new_state = state_;
110
111 switch (new_pressed_state) {
112 case LEFT:
114 break;
115 case RIGHT:
117 break;
118 case BOTH:
120 break;
121 case NONE:
122 new_state = NORMAL;
123 }
124
125 if (state_ != new_state) {
126 state_ = new_state;
127 set_dirty();
128 }
129}
130
131//TODO
132//void tristate_button::set_active(bool active) {
133// if ((state_ == NORMAL) && active) {
134// state_ = ACTIVE;
135// set_dirty();
136// } else if ((state_ == ACTIVE) && !active) {
137// state_ = NORMAL;
138// set_dirty();
139// }
140//}
141
143
144 switch (state_) {
145 case PRESSED_LEFT:
148 return LEFT;
149 case PRESSED_RIGHT:
152 return RIGHT;
153 case PRESSED_BOTH:
155 return BOTH;
156 default:
157 return NONE;
158 }
159}
160
161void tristate_button::enable(bool new_val) {
162 if (new_val != enabled()) {
163 pressed_ = false;
164 // check buttons should keep their state
165 state_ = NORMAL;
166
167 widget::enable(new_val);
168 }
169}
170
172{
174 texture base = baseImage_;
175
176 switch (state_) {
177
178 case UNINIT:
179 return;
180
181 case NORMAL:
182 break;
183
184 case TOUCHED_LEFT:
186 base = touchedBaseImage_;
187 break;
188 case TOUCHED_RIGHT:
190 base = touchedBaseImage_;
191 break;
195 base = touchedBaseImage_;
196 break;
197 case ACTIVE:
198 // overlay = activeImage_;
199 base = activeBaseImage_;
200 break;
201 case PRESSED_LEFT:
202 base = activeBaseImage_;
204 break;
205 case PRESSED_RIGHT:
206 base = activeBaseImage_;
208 break;
209 case PRESSED_BOTH:
210 base = activeBaseImage_;
212 break;
215 base = activeBaseImage_;
216 break;
219 base = activeBaseImage_;
220 break;
223 base = activeBaseImage_;
224 break;
225 }
226
227 // Draw the button base.
228 const rect& loc = location();
229 draw::blit(base, loc);
230
231 // Draw the item.
232 // TODO: don't hardcode an implicit reliance on 38 pixel buttons
233 rect magic{loc.x + 1, loc.y + 1, 36, 36};
235 if (itemOverlayImage_) {
237 }
238
239 // Draw the button overlay, if any.
240 if (overlay) {
242 }
243}
244
245//TODO move to widget
246bool tristate_button::hit(int x, int y) const {
247 return location().contains(x, y);
248}
249
250void tristate_button::mouse_motion(const SDL_MouseMotionEvent& event) {
251
252 if (hit(event.x, event.y))
253 { // the cursor is over the widget
254
255 switch (state_) {
256
257 case UNINIT:
258 return;
259
260 case NORMAL:
261 state_ = ACTIVE;
262 break;
263 case PRESSED_LEFT:
265 break;
266 case PRESSED_RIGHT:
268 break;
269 case PRESSED_BOTH:
271 break;
272 default:
273 //assert(false);
274 break;
275 }
276
277 } else { // the cursor is not over the widget
278
279 switch (state_) {
280
281 case ACTIVE:
282 state_ = NORMAL;
283 break;
284 case TOUCHED_LEFT:
285 case TOUCHED_RIGHT:
286 state_ = ACTIVE;
287 break;
291 break;
294 break;
298 break;
299 default:
300 break;
301 }
302 }
303}
304
305void tristate_button::mouse_down(const SDL_MouseButtonEvent& event) {
306
307 if (!hit(event.x, event.y))
308 return;
309
310 //The widget is expected to be in one of the "active" states when the mouse cursor is hovering over it, but that currently doesn't happen if the widget is moved under the cursor by scrolling the palette.
311 if (event.button == SDL_BUTTON_RIGHT) {
312 if (state_ == ACTIVE || state_ == NORMAL)
316 }
317
318 if (event.button == SDL_BUTTON_LEFT) {
319 if (state_ == ACTIVE || state_ == NORMAL)
323 }
324
325}
326
331
332void tristate_button::mouse_up(const SDL_MouseButtonEvent& event) {
333
334 if (!(hit(event.x, event.y)))
335 return;
336
337 // the user has stopped pressing the mouse left button while on the widget
338 if (event.button == SDL_BUTTON_LEFT) {
339
340 if (state_ == TOUCHED_LEFT) {
343 //TODO
344 // palette_->draw(true);
345 pressed_ = true;
346 }
347 if (state_ == TOUCHED_BOTH_RIGHT) {
350 // palette_->select_bg_item(item_id_);
351 // palette_->draw(true);
352 pressed_ = true;
353 }
354 }
355
356 if (event.button == SDL_BUTTON_RIGHT) {
357
358 pressed_ = true;
360
361 if (state_ == TOUCHED_RIGHT) {
363 // palette_->select_bg_item(item_id_);
364 // palette_->draw(true);
365 // pressed_ = true;
366 }
367 if (state_ == TOUCHED_BOTH_LEFT) {
369 // palette_->select_fg_item(item_id_);
370 // palette_->select_bg_item(item_id_);
371 // palette_->draw(true);
372 // pressed_ = true;
373 }
374 }
375
376 if (pressed_)
378}
379
380void tristate_button::handle_event(const SDL_Event& event) {
381
383
384 if (hidden() || !enabled())
385 return;
386
387 STATE start_state = state_;
388
389 if (!mouse_locked()) {
390 switch (event.type) {
391 case SDL_EVENT_MOUSE_BUTTON_DOWN:
392 mouse_down(event.button);
393 break;
394 case SDL_EVENT_MOUSE_BUTTON_UP:
395 mouse_up(event.button);
396 break;
397 case SDL_EVENT_MOUSE_MOTION:
398 mouse_motion(event.motion);
399 break;
400 default:
401 return;
402 }
403 }
404
405 if (start_state != state_)
406 set_dirty(true);
407}
408
410 const bool res = pressed_;
411 pressed_ = false;
412 return res;
413}
414
415}
map_location loc
Definition move.cpp:172
virtual void select_bg_item(const std::string &item_id)=0
virtual void select_fg_item(const std::string &item_id)=0
virtual void draw_contents() override
bool hit(int x, int y) const
void set_pressed(PRESSED_STATE new_pressed_state)
virtual ~tristate_button()
Default implementation, but defined out-of-line for efficiency reasons.
editor::tristate_palette * palette_
virtual void handle_event(const SDL_Event &event) override
virtual void mouse_up(const SDL_MouseButtonEvent &event)
PRESSED_STATE pressed_state() const
virtual void enable(bool new_val=true) override
virtual void mouse_down(const SDL_MouseButtonEvent &event)
virtual void mouse_motion(const SDL_MouseMotionEvent &event)
tristate_button(editor::tristate_palette *palette, std::string button_image="", const bool auto_join=true)
virtual void enable(bool new_val=true)
Definition widget.cpp:167
void set_dirty(bool dirty=true)
Definition widget.cpp:180
virtual void handle_event(const SDL_Event &) override
Definition widget.hpp:90
const rect & location() const
Definition widget.cpp:123
bool enabled() const
Definition widget.cpp:175
bool hidden() const
Definition widget.cpp:161
bool mouse_locked() const
Definition widget.cpp:64
Wrapper class to encapsulate creation and management of an SDL_Texture.
Definition texture.hpp:33
int w() const
The draw-space width of the texture, in pixels.
Definition texture.hpp:103
int h() const
The draw-space height of the texture, in pixels.
Definition texture.hpp:112
Drawing functions, for drawing things on the screen.
Standard logging facilities (interface).
void blit(const texture &tex, const ::rect &dst)
Draws a texture, or part of a texture, at the given location.
Definition draw.cpp:409
const std::string checkbox_release
General purpose widgets.
texture get_texture(const image::locator &i_locator, TYPE type, bool skip_cache)
Returns an image texture suitable for hardware-accelerated rendering.
Definition picture.cpp:955
void play_UI_sound(const std::string &files)
Definition sound.cpp:1009
Contains the SDL_Rect helper code.
An abstract description of a rectangle with integer coordinates.
Definition rect.hpp:49
bool contains(int x, int y) const
Whether the given point lies within the rectangle.
Definition rect.cpp:54
static lg::log_domain log_display("display")