The Battle for Wesnoth  1.17.12+dev
toggle_panel.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2022
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 
21 #include "gui/widgets/settings.hpp"
22 #include "gui/widgets/window.hpp"
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 
34 namespace gui2
35 {
36 
37 // ------------ WIDGET -----------{
38 
39 REGISTER_WIDGET(toggle_panel)
40 
41 toggle_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 
81 unsigned toggle_panel::num_states() const
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 
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 
121 void toggle_panel::set_active(const bool active)
122 {
123  if(active) {
125  } else {
127  }
128 }
129 
131 {
132  return state_ != DISABLED;
133 }
134 
135 unsigned toggle_panel::get_state() const
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  SDL_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 
163 {
164  selected = selected % num_states();
165  if(selected == get_value()) {
166  return;
167  }
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  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
214 
216  handled = true;
217 }
218 
220  bool& handled)
221 {
222  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
223 
225  handled = true;
226 }
227 
228 void
230 {
231  DBG_GUI_E << get_control_type() << "[" << id() << "]: " << event << ".";
232 
233  set_value(1, true);
234 
235 #if 0
236  /*
237  * Disabled since it causes issues with gamestate inspector (bug #22095).
238  * It was added in b84f2ebff0b53c7e4194da315c43f62a08494c52 for the lobby,
239  * since that code is still experimental, prefer to fix a real issue caused
240  * by it.
241  *
242  * The issue is that the gui2::listbox::add_row code was changed to
243  * increase the content size. Before the list was shown the list was
244  * cleared. The clear operation did not reduce the size (since the widgets
245  * were not shown yet). The add operation afterwards again reserved the
246  * space causing the size of the listbox to be twice the required space.
247  *
248  * 2014.06.09 -- Mordante
249  */
250 
251  fire(event::NOTIFY_MODIFIED, *this, nullptr);
252 #endif
253 }
254 
256  bool& handled)
257 {
258  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
259 
261 
262  set_value(get_value() + 1, true);
263 
264  handled = true;
265 }
266 
268  const event::ui_event event, bool& handled)
269 {
270  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
271 
272  if(retval_) {
273  window* window = get_window();
274  assert(window);
275 
276  window->set_retval(retval_);
277  }
278 
279  handled = true;
280 }
281 
282 // }---------- DEFINITION ---------{
283 
286 {
287  DBG_GUI_P << "Parsing toggle panel " << id;
288 
289  load_resolutions<resolution>(cfg);
290 }
291 
293  : resolution_definition(cfg)
294  , top_border(cfg["top_border"])
295  , bottom_border(cfg["bottom_border"])
296  , left_border(cfg["left_border"])
297  , right_border(cfg["right_border"])
298 {
299  // Note the order should be the same as the enum state_t in toggle_panel.hpp.
300  for(const auto& c : cfg.child_range("state"))
301  {
302  state.emplace_back(c.child("enabled"));
303  state.emplace_back(c.child("disabled"));
304  state.emplace_back(c.child("focused"));
305  }
306 }
307 
308 // }---------- BUILDER -----------{
309 
310 namespace implementation
311 {
312 
313 builder_toggle_panel::builder_toggle_panel(const config& cfg)
314  : builder_styled_widget(cfg)
315  , grid(nullptr)
316  , retval_id_(cfg["return_value_id"])
317  , retval_(cfg["return_value"])
318 {
319  const config& c = cfg.child("grid");
320 
321  VALIDATE(c, _("No grid defined."));
322 
323  grid = std::make_shared<builder_grid>(c);
324 }
325 
326 std::unique_ptr<widget> builder_toggle_panel::build() const
327 {
328  auto widget = std::make_unique<toggle_panel>(*this);
329 
330  widget->set_retval(get_retval(retval_id_, retval_, id));
331 
332  DBG_GUI_G << "Window builder: placed toggle panel '" << id
333  << "' with definition '" << definition << "'.";
334 
335  widget->init_grid(*grid);
336  return widget;
337 }
338 
339 } // namespace implementation
340 
341 // }------------ END --------------
342 
343 } // namespace gui2
Define the common log macros for the gui toolkit.
Base class of a resolution, contains the common keys for a resolution.
#define DBG_GUI_P
Definition: log.hpp:66
Class for a toggle button.
virtual unsigned get_state() const override
See styled_widget::get_state.
virtual void set_value(unsigned selected, bool fire_event=false) override
Inherited from selectable_item.
#define LOG_HEADER
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:402
void set_child_members(const widget_data &data)
Sets the members of the child controls.
std::vector< state_definition > state
unsigned state_num_
Usually 1 for selected and 0 for not selected, can also have higher values in tristate buttons...
widget * find(const std::string &id, const bool must_be_active) override
See widget::find.
virtual void impl_draw_foreground() override
See widget::impl_draw_foreground.
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
virtual bool get_active() const override
See styled_widget::get_active.
A panel is a visible container to hold multiple widgets.
Definition: panel.hpp:58
Add a special kind of assert to validate whether the input from WML doesn&#39;t contain any problems that...
rect get_rectangle() const
Gets the bounding rectangle of the widget on the screen.
Definition: widget.cpp:311
virtual point border_space() const override
See container_base::border_space.
virtual void set_members(const widget_item &data)
Sets the members of the styled_widget.
const std::string & id() const
Definition: widget.cpp:111
This file contains the window object, this object is a top level container which has the event manage...
child_itors child_range(config_key_type key)
Definition: config.cpp:344
Base class for all widgets.
Definition: widget.hpp:53
std::string_view data
Definition: picture.cpp:206
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
virtual const std::string & get_control_type() const override
Inherited from styled_widget, implemented by REGISTER_WIDGET.
static std::string _(const char *str)
Definition: gettext.hpp:93
Generic file dialog.
toggle_panel_definition(const config &cfg)
bool fire_event(const ui_event event, const std::vector< std::pair< widget *, ui_event >> &event_chain, widget *dispatcher, widget *w, F &&... params)
Helper function for fire_event.
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
void signal_handler_pre_left_button_click(const event::ui_event event)
virtual void impl_draw_foreground() override
See widget::impl_draw_foreground.
Base container class.
Definition: grid.hpp:31
void signal_handler_mouse_leave(const event::ui_event event, bool &handled)
std::string definition
Parameters for the styled_widget.
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
This file contains the settings handling of the widget library.
void set_state(const state_t state)
std::string selected
resolution_definition_ptr get_config()
void signal_handler_left_button_click(const event::ui_event event, bool &handled)
virtual unsigned num_states() const override
Inherited from selectable_item.
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
state_t state_
Current state of the widget.
int retval_
The return value of the button.
state_t
Possible states of the widget.
virtual void set_active(const bool active) override
See styled_widget::set_active.
void set_retval(const int retval)
#define DBG_GUI_E
Definition: log.hpp:35
Default, unset return value.
Definition: retval.hpp:32
void queue_redraw()
Indicates that this widget should be redrawn.
Definition: widget.cpp:442
virtual void impl_draw_background() override
See widget::impl_draw_background.
window * get_window()
Get the parent window.
Definition: widget.cpp:118
Holds a 2D point.
Definition: point.hpp:24
void set_retval(const int retval, const bool close_window=true)
Sets there return value of the window.
Definition: window.hpp:358
Base class for all visible items.
std::string sound_toggle_panel_click
Definition: settings.cpp:50
virtual void impl_draw_background() override
See widget::impl_draw_background.
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
virtual std::unique_ptr< widget > build() const override
void play_UI_sound(const std::string &files)
Definition: sound.cpp:1066
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:76
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:193
std::map< std::string, widget_item > widget_data
Definition: widget.hpp:35
retval
Default window/dialog return values.
Definition: retval.hpp:29
void signal_handler_left_button_double_click(const event::ui_event event, bool &handled)
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:60
virtual unsigned get_value() const override
Inherited from selectable_item.
mock_char c
virtual SDL_Rect get_client_rect() const override
See container_base::get_client_rect.
base class of top level items, the only item which needs to store the final canvases to draw on...
Definition: window.hpp:66
#define DBG_GUI_G
Definition: log.hpp:41
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:414
void signal_handler_mouse_enter(const event::ui_event event, bool &handled)