The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
menu_button.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2008 - 2025
3 by Mark de Wever <koraq@xs4all.nl>
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 "gui/core/log.hpp"
25#include "sound.hpp"
26#include "wml_exception.hpp"
27
28#include <functional>
29
30#define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
31#define LOG_HEADER LOG_SCOPE_HEADER + ':'
32
33namespace gui2
34{
35
36// ------------ WIDGET -----------{
37
38REGISTER_WIDGET(menu_button)
39
40menu_button::menu_button(const implementation::builder_menu_button& builder)
41 : styled_widget(builder, type())
43 , state_(ENABLED)
44 , values_()
45 , selected_(0)
46 , keep_open_(false)
47{
48 values_.emplace_back("label", this->get_label());
49
50 connect_signal<event::MOUSE_ENTER>(
51 std::bind(&menu_button::signal_handler_mouse_enter, this, std::placeholders::_2, std::placeholders::_3));
52
53 connect_signal<event::MOUSE_LEAVE>(
54 std::bind(&menu_button::signal_handler_mouse_leave, this, std::placeholders::_2, std::placeholders::_3));
55
56 connect_signal<event::LEFT_BUTTON_DOWN>(
57 std::bind(&menu_button::signal_handler_left_button_down, this, std::placeholders::_2, std::placeholders::_3));
58
59 connect_signal<event::LEFT_BUTTON_UP>(
60 std::bind(&menu_button::signal_handler_left_button_up, this, std::placeholders::_2, std::placeholders::_3));
61
62 connect_signal<event::LEFT_BUTTON_CLICK>(
63 std::bind(&menu_button::signal_handler_left_button_click, this, std::placeholders::_2, std::placeholders::_3));
64
65 connect_signal<event::SDL_WHEEL_UP>(
66 std::bind(&menu_button::signal_handler_sdl_wheel_up, this, std::placeholders::_2, std::placeholders::_3),
68
69 connect_signal<event::SDL_WHEEL_DOWN>(
70 std::bind(&menu_button::signal_handler_sdl_wheel_down, this, std::placeholders::_2, std::placeholders::_3),
72}
73
74void menu_button::set_active(const bool active)
75{
76 if(get_active() != active) {
77 set_state(active ? ENABLED : DISABLED);
78 }
79}
80
82{
83 return state_ != DISABLED;
84}
85
86unsigned menu_button::get_state() const
87{
88 return state_;
89}
90
92{
93 if(state != state_) {
94 state_ = state;
96 }
97}
98
100{
101 DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
102
104 handled = true;
105}
106
108{
109 DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
110
112 handled = true;
113}
114
116{
117 DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
118
120 if(window) {
122 }
123
125 handled = true;
126}
127
129{
130 DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
131
133 handled = true;
134}
135
137{
138 assert(get_window());
139 DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
140
142
143 // If a button has a retval do the default handling.
145
146 if(droplist.show()) {
147 const int selected = droplist.selected_item();
148
149 // Safety check. If the user clicks a selection in the dropdown and moves their mouse away too
150 // quickly, selected_ could be set to -1. This returns in that case, preventing crashes.
151 if(selected < 0) {
152 return;
153 }
154
155 set_selected(selected, true);
156 }
157
158 handled = true;
159}
160
162{
163 DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
164
165 // TODO: should values wrap?
166 if(selected_ > 0) {
168 }
169
170 handled = true;
171}
172
174{
175 DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
176
177 // TODO: should values wrap?
178 if(selected_ < values_.size() - 1) {
180 }
181
182 handled = true;
183}
184
185void menu_button::set_values(const std::vector<::config>& values, unsigned selected)
186{
187 assert(selected < values.size());
188 assert(selected_ < values_.size());
189
190 if(values[selected]["label"] != values_[selected_]["label"]) {
191 queue_redraw();
192 }
193
194 values_ = values;
195 selected_ = selected;
196
197 set_label(values_[selected_]["label"].t_str());
198}
199
200void menu_button::set_selected(unsigned selected, bool fire_event)
201{
202 assert(selected < values_.size());
203 assert(selected_ < values_.size());
204
205 if(selected != selected_) {
206 queue_redraw();
207 }
208
209 selected_ = selected;
210
211 set_label(values_[selected_]["label"].t_str());
212 if (fire_event) {
213 fire(event::NOTIFY_MODIFIED, *this, nullptr);
214 }
215}
216
217// }---------- DEFINITION ---------{
218
221{
222 DBG_GUI_P << "Parsing menu_button " << id;
223
224 load_resolutions<resolution>(cfg);
225}
226
229{
230 // Note the order should be the same as the enum state_t in menu_button.hpp.
231 state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_enabled", missing_mandatory_wml_tag("menu_button_definition][resolution", "state_enabled")));
232 state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_disabled", missing_mandatory_wml_tag("menu_button_definition][resolution", "state_disabled")));
233 state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_pressed", missing_mandatory_wml_tag("menu_button_definition][resolution", "state_pressed")));
234 state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_focused", missing_mandatory_wml_tag("menu_button_definition][resolution", "state_focused")));
235}
236
237// }---------- BUILDER -----------{
238
239namespace implementation
240{
241
242builder_menu_button::builder_menu_button(const config& cfg)
244 , options_()
245{
246 for(const auto& option : cfg.child_range("option")) {
247 options_.push_back(option);
248 }
249}
250
251std::unique_ptr<widget> builder_menu_button::build() const
252{
253 auto widget = std::make_unique<menu_button>(*this);
254
255 if(!options_.empty()) {
256 widget->set_values(options_);
257 }
258
259 DBG_GUI_G << "Window builder: placed menu_button '" << id
260 << "' with definition '" << definition << "'.";
261
262 return widget;
263}
264
265} // namespace implementation
266
267// }------------ END --------------
268
269} // namespace gui2
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
child_itors child_range(std::string_view key)
Definition config.cpp:268
Used by the menu_button widget.
bool show(const unsigned auto_close_time=0)
Shows the window.
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
void set_state(const state_t state)
void signal_handler_left_button_click(const event::ui_event event, bool &handled)
state_t state_
Current state of the widget.
void set_selected(unsigned selected, bool fire_event=true)
void signal_handler_left_button_down(const event::ui_event event, bool &handled)
void signal_handler_mouse_leave(const event::ui_event event, bool &handled)
void signal_handler_left_button_up(const event::ui_event event, bool &handled)
void set_values(const std::vector<::config > &values, unsigned selected=0)
void signal_handler_mouse_enter(const event::ui_event event, bool &handled)
virtual unsigned get_state() const override
See styled_widget::get_state.
virtual void set_active(const bool active) override
See styled_widget::set_active.
void signal_handler_sdl_wheel_up(const event::ui_event event, bool &handled)
void signal_handler_sdl_wheel_down(const event::ui_event event, bool &handled)
state_t
Possible states of the widget.
virtual bool get_active() const override
See styled_widget::get_active.
std::vector<::config > values_
Small abstract helper class.
virtual void set_label(const t_string &text)
Base class for all widgets.
Definition widget.hpp:55
void queue_redraw()
Indicates that this widget should be redrawn.
Definition widget.cpp:464
window * get_window()
Get the parent window.
Definition widget.cpp:117
base class of top level items, the only item which needs to store the final canvases to draw on.
Definition window.hpp:59
void mouse_capture(const bool capture=true)
Definition window.cpp:1191
#define LOG_HEADER
const config * cfg
Define the common log macros for the gui toolkit.
#define DBG_GUI_G
Definition log.hpp:41
#define DBG_GUI_P
Definition log.hpp:66
#define DBG_GUI_E
Definition log.hpp:35
This file contains the window object, this object is a top level container which has the event manage...
ui_event
The event sent to the dispatcher.
Definition handler.hpp:115
std::string sound_button_click
Definition settings.cpp:50
Generic file dialog.
Contains the implementation details for lexical_cast and shouldn't be used directly.
void play_UI_sound(const std::string &files)
Definition sound.cpp:1006
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
This file contains the settings handling of the widget library.
virtual std::unique_ptr< widget > build() const override
std::string definition
Parameters for the styled_widget.
menu_button_definition(const config &cfg)
std::vector< state_definition > state
std::string missing_mandatory_wml_tag(const std::string &section, const std::string &tag)
Returns a standard message for a missing wml child (tag).
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
#define VALIDATE_WML_CHILD(cfg, key, message)