The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
toggle_panel.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
23#include "gui/core/log.hpp"
25#include "gettext.hpp"
26#include "sound.hpp"
27#include "wml_exception.hpp"
28
29#include <functional>
30
31#define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
32#define LOG_HEADER LOG_SCOPE_HEADER + ':'
33
34namespace gui2
35{
36
37// ------------ WIDGET -----------{
38
39REGISTER_WIDGET(toggle_panel)
40
41toggle_panel::toggle_panel(const implementation::builder_toggle_panel& builder)
42 : panel(builder, type())
43 , state_(ENABLED)
44 , state_num_(0)
45 , retval_(retval::NONE)
46{
47 set_wants_mouse_left_double_click();
48
49 connect_signal<event::MOUSE_ENTER>(std::bind(
50 &toggle_panel::signal_handler_mouse_enter, this, std::placeholders::_2, std::placeholders::_3));
51 connect_signal<event::MOUSE_LEAVE>(std::bind(
52 &toggle_panel::signal_handler_mouse_leave, this, std::placeholders::_2, std::placeholders::_3));
53#if 0
54 connect_signal<event::LEFT_BUTTON_CLICK>(
56 this,
57 std::placeholders::_2),
59#endif
60 connect_signal<event::LEFT_BUTTON_CLICK>(std::bind(
61 &toggle_panel::signal_handler_left_button_click, this, std::placeholders::_2, std::placeholders::_3));
62 connect_signal<event::LEFT_BUTTON_CLICK>(
64 this,
65 std::placeholders::_2,
66 std::placeholders::_3),
68 connect_signal<event::LEFT_BUTTON_DOUBLE_CLICK>(
70 this,
71 std::placeholders::_2,
72 std::placeholders::_3));
73 connect_signal<event::LEFT_BUTTON_DOUBLE_CLICK>(
75 this,
76 std::placeholders::_2,
77 std::placeholders::_3),
79}
80
82{
83 std::div_t res = std::div(this->get_config()->state.size(), COUNT);
84 assert(res.rem == 0);
85 assert(res.quot > 0);
86 return res.quot;
87}
88
90{
91 for(const auto & item : data)
92 {
93 styled_widget* control = dynamic_cast<styled_widget*>(find(item.first, false));
94 if(control) {
95 control->set_members(item.second);
96 }
97 }
98}
100 const bool must_be_active)
101{
102 /**
103 * @todo since there is no mouse event nesting (or event nesting at all)
104 * we need to capture all events. This means items on the panel will
105 * never receive an event, which gives problems with for example the
106 * intended button on the addon panel. So we need to chain mouse events
107 * as well and also add a handled flag for them.
108 */
109
110 widget* result = container_base::find_at(coordinate, must_be_active);
111 return result ? result : styled_widget::find_at(coordinate, must_be_active);
112}
113
114const widget* toggle_panel::find_at(const point& coordinate,
115 const bool must_be_active) const
116{
117 const widget* result = container_base::find_at(coordinate, must_be_active);
118 return result ? result : styled_widget::find_at(coordinate, must_be_active);
119}
120
121void toggle_panel::set_active(const bool active)
122{
123 if(active) {
125 } else {
127 }
128}
129
131{
132 return state_ != DISABLED;
133}
134
136{
137 return state_ + COUNT * state_num_;
138}
139
141{
142 const auto conf = cast_config_to<toggle_panel_definition>();
143 assert(conf);
144
145 rect result = get_rectangle();
146 result.x += conf->left_border;
147 result.y += conf->top_border;
148 result.w -= conf->left_border + conf->right_border;
149 result.h -= conf->top_border + conf->bottom_border;
150
151 return result;
152}
153
155{
156 const auto conf = cast_config_to<toggle_panel_definition>();
157 assert(conf);
158
159 return point(conf->left_border + conf->right_border, conf->top_border + conf->bottom_border);
160}
161
162void toggle_panel::set_value(unsigned selected, bool fire_event)
163{
164 selected = selected % num_states();
165 if(selected == get_value()) {
166 return;
167 }
168 state_num_ = selected;
169 queue_redraw();
170
171 // Check for get_window() is here to prevent the callback from
172 // being called when the initial value is set.
173 if(get_window() && fire_event) {
174 fire(event::NOTIFY_MODIFIED, *this, nullptr);
175 }
176}
177
179{
180 retval_ = retval;
181}
182
184{
185 if(state == state_) {
186 return;
187 }
188
189 state_ = state;
190 queue_redraw();
191
192 const auto conf = cast_config_to<toggle_panel_definition>();
193 assert(conf);
194}
195
197{
198 // We don't have a fore and background and need to draw depending on
199 // our state, like a styled_widget. So we use the styled_widget's drawing method.
201}
202
204{
205 // We don't have a fore and background and need to draw depending on
206 // our state, like a styled_widget. So we use the styled_widget's drawing method.
208}
209
211 bool& handled)
212{
213#ifndef __ANDROID__
214 DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
215
217 handled = true;
218#endif
219}
220
222 bool& handled)
223{
224#ifndef __ANDROID__
225 DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
226
228 handled = true;
229#endif
230}
231
232void
234{
235 DBG_GUI_E << get_control_type() << "[" << id() << "]: " << event << ".";
236
237 set_value(1, true);
238
239#if 0
240 /*
241 * Disabled since it causes issues with gamestate inspector (bug #22095).
242 * It was added in b84f2ebff0b53c7e4194da315c43f62a08494c52 for the lobby,
243 * since that code is still experimental, prefer to fix a real issue caused
244 * by it.
245 *
246 * The issue is that the gui2::listbox::add_row code was changed to
247 * increase the content size. Before the list was shown the list was
248 * cleared. The clear operation did not reduce the size (since the widgets
249 * were not shown yet). The add operation afterwards again reserved the
250 * space causing the size of the listbox to be twice the required space.
251 *
252 * 2014.06.09 -- Mordante
253 */
254
255 fire(event::NOTIFY_MODIFIED, *this, nullptr);
256#endif
257}
258
260 bool& handled)
261{
262 DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
263
265
266 set_value(get_value() + 1, true);
267
268 handled = true;
269}
270
272 const event::ui_event event, bool& handled)
273{
274 DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
275
276 if(retval_) {
278 assert(window);
279
281 }
282
283 handled = true;
284}
285
286// }---------- DEFINITION ---------{
287
290{
291 DBG_GUI_P << "Parsing toggle panel " << id;
292
293 load_resolutions<resolution>(cfg);
294}
295
298 , top_border(cfg["top_border"].to_unsigned())
299 , bottom_border(cfg["bottom_border"].to_unsigned())
300 , left_border(cfg["left_border"].to_unsigned())
301 , right_border(cfg["right_border"].to_unsigned())
302{
303 // Note the order should be the same as the enum state_t in toggle_panel.hpp.
304 for(const auto& c : cfg.child_range("state"))
305 {
306 state.emplace_back(VALIDATE_WML_CHILD(c, "enabled", missing_mandatory_wml_tag("toggle_panel_definition][resolution][state", "enabled")));
307 state.emplace_back(VALIDATE_WML_CHILD(c, "disabled", missing_mandatory_wml_tag("toggle_panel_definition][resolution][state", "disabled")));
308 state.emplace_back(VALIDATE_WML_CHILD(c, "focused", missing_mandatory_wml_tag("toggle_panel_definition][resolution][state", "focused")));
309 }
310}
311
312// }---------- BUILDER -----------{
313
314namespace implementation
315{
316
317builder_toggle_panel::builder_toggle_panel(const config& cfg)
319 , grid(nullptr)
320 , retval_id_(cfg["return_value_id"])
321 , retval_(cfg["return_value"].to_int())
322{
323 auto c = cfg.optional_child("grid");
324
325 VALIDATE(c, _("No grid defined."));
326
327 grid = std::make_shared<builder_grid>(*c);
328}
329
330std::unique_ptr<widget> builder_toggle_panel::build() const
331{
332 auto widget = std::make_unique<toggle_panel>(*this);
333
334 widget->set_retval(get_retval(retval_id_, retval_, id));
335
336 DBG_GUI_G << "Window builder: placed toggle panel '" << id
337 << "' with definition '" << definition << "'.";
338
339 widget->init_grid(*grid);
340 return widget;
341}
342
343} // namespace implementation
344
345// }------------ END --------------
346
347} // namespace gui2
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
optional_config_impl< config > optional_child(std::string_view key, int n=0)
Equivalent to mandatory_child, but returns an empty optional if the nth child was not found.
Definition config.cpp:380
child_itors child_range(std::string_view key)
Definition config.cpp:268
widget * find(const std::string_view id, const bool must_be_active) override
See widget::find.
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Base container class.
Definition grid.hpp:32
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
virtual void set_members(const widget_item &data)
Sets the members of the styled_widget.
virtual bool impl_draw_background() override
See widget::impl_draw_background.
virtual bool impl_draw_foreground() override
See widget::impl_draw_foreground.
resolution_definition_ptr get_config()
void signal_handler_left_button_double_click(const event::ui_event event, bool &handled)
unsigned state_num_
Usually 1 for selected and 0 for not selected, can also have higher values in tristate buttons.
virtual bool impl_draw_foreground() override
See widget::impl_draw_foreground.
virtual bool impl_draw_background() override
See widget::impl_draw_background.
void signal_handler_mouse_enter(const event::ui_event event, bool &handled)
void set_state(const state_t state)
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
void set_child_members(const widget_data &data)
Sets the members of the child controls.
virtual unsigned get_state() const override
See styled_widget::get_state.
virtual void set_active(const bool active) override
See styled_widget::set_active.
int retval_
The return value of the button.
void set_retval(const int retval)
virtual unsigned get_value() const override
Inherited from selectable_item.
void signal_handler_left_button_click(const event::ui_event event, bool &handled)
virtual point border_space() const override
See container_base::border_space.
virtual rect get_client_rect() const override
See container_base::get_client_rect.
virtual bool get_active() const override
See styled_widget::get_active.
virtual const std::string & get_control_type() const override
Inherited from styled_widget, implemented by REGISTER_WIDGET.
virtual void set_value(unsigned selected, bool fire_event=false) override
Inherited from selectable_item.
void signal_handler_mouse_leave(const event::ui_event event, bool &handled)
state_t state_
Current state of the widget.
virtual unsigned num_states() const override
Inherited from selectable_item.
void signal_handler_pre_left_button_click(const event::ui_event event)
state_t
Possible states of the widget.
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
rect get_rectangle() const
Gets the bounding rectangle of the widget on the screen.
Definition widget.cpp:321
base class of top level items, the only item which needs to store the final canvases to draw on.
Definition window.hpp:59
void set_retval(const int retval, const bool close_window=true)
Sets there return value of the window.
Definition window.hpp:387
#define LOG_HEADER
const config * cfg
static std::string _(const char *str)
Definition gettext.hpp:100
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
std::string id
Text to match against addon_info.tags()
Definition manager.cpp:199
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
int get_retval(const std::string &retval_id, const int retval, const std::string &id)
Returns the return value for a widget.
Definition helper.cpp:137
std::string sound_toggle_panel_click
Definition settings.cpp:52
Generic file dialog.
std::map< std::string, widget_item > widget_data
Definition widget.hpp:36
retval
Default window/dialog return values.
Definition retval.hpp:30
@ NONE
Default, unset return value.
Definition retval.hpp:32
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
std::string_view data
Definition picture.cpp:188
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
This file contains the settings handling of the widget library.
std::string definition
Parameters for the styled_widget.
virtual std::unique_ptr< widget > build() const override
std::vector< state_definition > state
toggle_panel_definition(const config &cfg)
Holds a 2D point.
Definition point.hpp:25
An abstract description of a rectangle with integer coordinates.
Definition rect.hpp:49
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)
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
#define c