The Battle for Wesnoth  1.17.0-dev
toggle_panel.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2021
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->config()->state.size(), COUNT);
84  assert(res.rem == 0);
85  assert(res.quot > 0);
86  return res.quot;
87 }
88 
90  const std::map<std::string /* widget id */, string_map>& data)
91 {
92  for(const auto & item : data)
93  {
94  styled_widget* control = dynamic_cast<styled_widget*>(find(item.first, false));
95  if(control) {
96  control->set_members(item.second);
97  }
98  }
99 }
101  const bool must_be_active)
102 {
103  /**
104  * @todo since there is no mouse event nesting (or event nesting at all)
105  * we need to capture all events. This means items on the panel will
106  * never receive an event, which gives problems with for example the
107  * intended button on the addon panel. So we need to chain mouse events
108  * as well and also add a handled flag for them.
109  */
110 
111  widget* result = container_base::find_at(coordinate, must_be_active);
112  return result ? result : styled_widget::find_at(coordinate, must_be_active);
113 }
114 
116  const bool must_be_active) const
117 {
118  const widget* result = container_base::find_at(coordinate, must_be_active);
119  return result ? result : styled_widget::find_at(coordinate, must_be_active);
120 }
121 
122 void toggle_panel::set_active(const bool active)
123 {
124  if(active) {
126  } else {
128  }
129 }
130 
132 {
133  return state_ != DISABLED;
134 }
135 
136 unsigned toggle_panel::get_state() const
137 {
138  return state_ + COUNT * state_num_;
139 }
140 
142 {
143  const auto conf = cast_config_to<toggle_panel_definition>();
144  assert(conf);
145 
146  SDL_Rect result = get_rectangle();
147  result.x += conf->left_border;
148  result.y += conf->top_border;
149  result.w -= conf->left_border + conf->right_border;
150  result.h -= conf->top_border + conf->bottom_border;
151 
152  return result;
153 }
154 
156 {
157  const auto conf = cast_config_to<toggle_panel_definition>();
158  assert(conf);
159 
160  return point(conf->left_border + conf->right_border, conf->top_border + conf->bottom_border);
161 }
162 
164 {
165  selected = selected % num_states();
166  if(selected == get_value()) {
167  return;
168  }
170  set_is_dirty(true);
171 
172  // Check for get_window() is here to prevent the callback from
173  // being called when the initial value is set.
174  if(get_window() && fire_event) {
175  fire(event::NOTIFY_MODIFIED, *this, nullptr);
176  }
177 }
178 
180 {
181  retval_ = retval;
182 }
183 
185 {
186  if(state == state_) {
187  return;
188  }
189 
190  state_ = state;
191  set_is_dirty(true);
192 
193  const auto conf = cast_config_to<toggle_panel_definition>();
194  assert(conf);
195 }
196 
198  int x_offset,
199  int y_offset)
200 {
201  // We don't have a fore and background and need to draw depending on
202  // our state, like a styled_widget. So we use the styled_widget's drawing method.
203  styled_widget::impl_draw_background(frame_buffer, x_offset, y_offset);
204 }
205 
207  int x_offset,
208  int y_offset)
209 {
210  // We don't have a fore and background and need to draw depending on
211  // our state, like a styled_widget. So we use the styled_widget's drawing method.
212  styled_widget::impl_draw_foreground(frame_buffer, x_offset, y_offset);
213 }
214 
216  bool& handled)
217 {
218  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
219 
221  handled = true;
222 }
223 
225  bool& handled)
226 {
227  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
228 
230  handled = true;
231 }
232 
233 void
235 {
236  DBG_GUI_E << get_control_type() << "[" << id() << "]: " << event << ".\n";
237 
238  set_value(1, true);
239 
240 #if 0
241  /*
242  * Disabled since it causes issues with gamestate inspector (bug #22095).
243  * It was added in b84f2ebff0b53c7e4194da315c43f62a08494c52 for the lobby,
244  * since that code is still experimental, prefer to fix a real issue caused
245  * by it.
246  *
247  * The issue is that the gui2::listbox::add_row code was changed to
248  * increase the content size. Before the list was shown the list was
249  * cleared. The clear operation did not reduce the size (since the widgets
250  * were not shown yet). The add operation afterwards again reserved the
251  * space causing the size of the listbox to be twice the required space.
252  *
253  * 2014.06.09 -- Mordante
254  */
255 
256  fire(event::NOTIFY_MODIFIED, *this, nullptr);
257 #endif
258 }
259 
261  bool& handled)
262 {
263  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
264 
266 
267  set_value(get_value() + 1, true);
268 
269  handled = true;
270 }
271 
273  const event::ui_event event, bool& handled)
274 {
275  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
276 
277  if(retval_) {
278  window* window = get_window();
279  assert(window);
280 
281  window->set_retval(retval_);
282  }
283 
284  handled = true;
285 }
286 
287 // }---------- DEFINITION ---------{
288 
291 {
292  DBG_GUI_P << "Parsing toggle panel " << id << '\n';
293 
294  load_resolutions<resolution>(cfg);
295 }
296 
298  : resolution_definition(cfg)
299  , top_border(cfg["top_border"])
300  , bottom_border(cfg["bottom_border"])
301  , left_border(cfg["left_border"])
302  , right_border(cfg["right_border"])
303 {
304  // Note the order should be the same as the enum state_t in toggle_panel.hpp.
305  for(const auto& c : cfg.child_range("state"))
306  {
307  state.emplace_back(c.child("enabled"));
308  state.emplace_back(c.child("disabled"));
309  state.emplace_back(c.child("focused"));
310  }
311 }
312 
313 // }---------- BUILDER -----------{
314 
315 namespace implementation
316 {
317 
318 builder_toggle_panel::builder_toggle_panel(const config& cfg)
319  : builder_styled_widget(cfg)
320  , grid(nullptr)
321  , retval_id_(cfg["return_value_id"])
322  , retval_(cfg["return_value"])
323 {
324  const config& c = cfg.child("grid");
325 
326  VALIDATE(c, _("No grid defined."));
327 
328  grid = std::make_shared<builder_grid>(c);
329 }
330 
332 {
333  toggle_panel* widget = new toggle_panel(*this);
334 
335  widget->set_retval(get_retval(retval_id_, retval_, id));
336 
337  DBG_GUI_G << "Window builder: placed toggle panel '" << id
338  << "' with definition '" << definition << "'.\n";
339 
340  widget->init_grid(*grid);
341  return widget;
342 }
343 
344 } // namespace implementation
345 
346 // }------------ END --------------
347 
348 } // 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
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 bool get_active() const override
See styled_widget::get_active.
void set_child_members(const std::map< std::string, string_map > &data)
Sets the members of the child controls.
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...
virtual point border_space() const override
See container_base::border_space.
virtual void set_members(const string_map &data)
Sets the members of the styled_widget.
const std::string & id() const
Definition: widget.cpp:110
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
SDL_Rect get_rectangle() const
Gets the bounding rectangle of the widget on the screen.
Definition: widget.cpp:310
Base class for all widgets.
Definition: widget.hpp:49
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.
Definition: field-fwd.hpp:23
toggle_panel_definition(const config &cfg)
Sent by a widget to notify others its contents or state are modified.
Definition: handler.hpp:89
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)
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.
virtual widget * build() const override
#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_is_dirty(const bool is_dirty)
Definition: widget.cpp:466
void set_state(const state_t state)
virtual void impl_draw_foreground(surface &frame_buffer, int x_offset, int y_offset) override
See widget::impl_draw_foreground.
std::string selected
void init_grid(const builder_grid &grid_builder)
Initializes and builds the grid.
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.
virtual void impl_draw_foreground(surface &frame_buffer, int x_offset, int y_offset) override
See widget::impl_draw_foreground.
resolution_definition_ptr config()
state_t state_
Current state of the widget.
virtual void impl_draw_background(surface &frame_buffer, int x_offset, int y_offset) override
See widget::impl_draw_background.
int retval_
The return value of the button.
bool fire_event(const ui_event event, std::vector< std::pair< widget *, ui_event >> &event_chain, widget *dispatcher, widget *w, F &&... params)
Helper function for fire_event.
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
window * get_window()
Get the parent window.
Definition: widget.cpp:117
virtual void impl_draw_background(surface &frame_buffer, int x_offset, int y_offset) override
See widget::impl_draw_background.
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:45
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
void play_UI_sound(const std::string &files)
Definition: sound.cpp:1052
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:69
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:61
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:65
#define DBG_GUI_G
Definition: log.hpp:41
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.
ui_event
The event send to the dispatcher.
Definition: handler.hpp:48
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:410
void signal_handler_mouse_enter(const event::ui_event event, bool &handled)