The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
toggle_panel.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2016 by Mark de Wever <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
18 
20 #include "gui/widgets/settings.hpp"
21 #include "gui/widgets/window.hpp"
22 #include "gui/core/log.hpp"
24 #include "gettext.hpp"
25 #include "sound.hpp"
26 #include "wml_exception.hpp"
27 
28 #include "utils/functional.hpp"
29 
30 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
31 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
32 
33 namespace gui2
34 {
35 
36 // ------------ WIDGET -----------{
37 
38 REGISTER_WIDGET(toggle_panel)
39 
41  : tpanel(COUNT)
42  , state_(ENABLED)
43  , state_num_(0)
44  , retval_(0)
45  , callback_state_change_(nullptr)
46  , callback_mouse_left_double_click_()
47 {
48  set_wants_mouse_left_double_click();
49 
50  connect_signal<event::MOUSE_ENTER>(std::bind(
52  connect_signal<event::MOUSE_LEAVE>(std::bind(
54 #if 0
55  connect_signal<event::LEFT_BUTTON_CLICK>(
57  this,
58  _2),
60 #endif
61  connect_signal<event::LEFT_BUTTON_CLICK>(std::bind(
63  connect_signal<event::LEFT_BUTTON_CLICK>(
65  this,
66  _2,
67  _3),
69  connect_signal<event::LEFT_BUTTON_DOUBLE_CLICK>(
71  this,
72  _2,
73  _3));
74  connect_signal<event::LEFT_BUTTON_DOUBLE_CLICK>(
76  this,
77  _2,
78  _3),
80 }
81 
82 unsigned ttoggle_panel::num_states() const
83 {
84  std::div_t res = std::div(this->config()->state.size(), COUNT);
85  assert(res.rem == 0);
86  assert(res.quot > 0);
87  return res.quot;
88 }
89 
91  const std::map<std::string /* widget id */, string_map>& data)
92 {
93  for(const auto & item : data)
94  {
95  tcontrol* control = dynamic_cast<tcontrol*>(find(item.first, false));
96  if(control) {
97  control->set_members(item.second);
98  }
99  }
100 }
102  const bool must_be_active)
103 {
104  /**
105  * @todo since there is no mouse event nesting (or event nesting at all)
106  * we need to capture all events. This means items on the panel will
107  * never receive an event, which gives problems with for example the
108  * intended button on the addon panel. So we need to chain mouse events
109  * as well and also add a handled flag for them.
110  */
111 
112  twidget* result = tcontainer_::find_at(coordinate, must_be_active);
113  return result ? result : tcontrol::find_at(coordinate, must_be_active);
114 }
115 
116 const twidget* ttoggle_panel::find_at(const tpoint& coordinate,
117  const bool must_be_active) const
118 {
119  const twidget* result = tcontainer_::find_at(coordinate, must_be_active);
120  return result ? result : tcontrol::find_at(coordinate, must_be_active);
121 }
122 
123 void ttoggle_panel::set_active(const bool active)
124 {
125  if(active) {
127  } else {
129  }
130 }
131 
133 {
134  return state_ != DISABLED;
135 }
136 
137 unsigned ttoggle_panel::get_state() const
138 {
139  return state_ + COUNT * state_num_;
140 }
141 
143 {
145  = boost::dynamic_pointer_cast<const ttoggle_panel_definition::
146  tresolution>(config());
147  assert(conf);
148 
149  SDL_Rect result = get_rectangle();
150  result.x += conf->left_border;
151  result.y += conf->top_border;
152  result.w -= conf->left_border + conf->right_border;
153  result.h -= conf->top_border + conf->bottom_border;
154 
155  return result;
156 }
157 
159 {
161  = boost::dynamic_pointer_cast<const ttoggle_panel_definition::
162  tresolution>(config());
163  assert(conf);
164 
165  return tpoint(conf->left_border + conf->right_border,
166  conf->top_border + conf->bottom_border);
167 }
168 
169 void ttoggle_panel::set_value(const unsigned selected)
170 {
171  if(selected == get_value()) {
172  return;
173  }
174  state_num_ = selected % num_states();
175  set_is_dirty(true);
176 }
177 
178 void ttoggle_panel::set_retval(const int retval)
179 {
180  retval_ = retval;
181 }
182 
184 {
185  if(state == state_) {
186  return;
187  }
188 
189  state_ = state;
190  set_is_dirty(true);
191 
193  = boost::dynamic_pointer_cast<const ttoggle_panel_definition::
194  tresolution>(config());
195  assert(conf);
196 }
197 
199  int x_offset,
200  int y_offset)
201 {
202  // We don't have a fore and background and need to draw depending on
203  // our state, like a control. So we use the controls drawing method.
204  tcontrol::impl_draw_background(frame_buffer, x_offset, y_offset);
205 }
206 
208  int x_offset,
209  int y_offset)
210 {
211  // We don't have a fore and background and need to draw depending on
212  // our state, like a control. So we use the controls drawing method.
213  tcontrol::impl_draw_foreground(frame_buffer, x_offset, y_offset);
214 }
215 
217 {
218  static const std::string type = "toggle_panel";
219  return type;
220 }
221 
223  bool& handled)
224 {
225  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
226 
228  handled = true;
229 }
230 
232  bool& handled)
233 {
234  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
235 
237  handled = true;
238 }
239 
240 void
242 {
243  DBG_GUI_E << get_control_type() << "[" << id() << "]: " << event << ".\n";
244 
245  set_value(1);
246 
247 #if 0
248  /*
249  * Disabled since it causes issues with gamestate inspector (bug #22095).
250  * It was added in b84f2ebff0b53c7e4194da315c43f62a08494c52 for the lobby,
251  * since that code is still experimental, prefer to fix a real issue caused
252  * by it.
253  *
254  * The issue is that the gui2::tlistbox::add_row code was changed to
255  * increase the content size. Before the list was shown the list was
256  * cleared. The clear operation did not reduce the size (since the widgets
257  * were not shown yet). The add operation afterwards again reserved the
258  * space causing the size of the listbox to be twice the required space.
259  *
260  * 2014.06.09 -- Mordante
261  */
263  callback_state_change_(*this);
264  }
265 #endif
266 }
267 
269  bool& handled)
270 {
271  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
272 
274 
275  set_value(get_value() + 1);
276 
278  callback_state_change_(*this);
279  }
280  handled = true;
281 }
282 
284  const event::tevent event, bool& handled)
285 {
286  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
287 
288  if(retval_) {
289  twindow* window = get_window();
290  assert(window);
291 
292  window->set_retval(retval_);
293  }
294 
297  }
298  handled = true;
299 }
300 
301 // }---------- DEFINITION ---------{
302 
304  : tcontrol_definition(cfg)
305 {
306  DBG_GUI_P << "Parsing toggle panel " << id << '\n';
307 
308  load_resolutions<tresolution>(cfg);
309 }
310 
311 /*WIKI
312  * @page = GUIWidgetDefinitionWML
313  * @order = 1_toggle_panel
314  *
315  * == Toggle panel ==
316  *
317  * @begin{parent}{name="gui/"}
318  * @begin{tag}{name="toggle_panel_definition"}{min=0}{max=-1}{super="generic/widget_definition"}
319  * The definition of a toggle panel. A toggle panel is like a toggle button, but
320  * instead of being a button it's a panel. This means it can hold multiple child
321  * items.
322  *
323  * @begin{tag}{name="resolution"}{min=0}{max=-1}{super=generic/widget_definition/resolution}
324  * The resolution for a toggle panel also contains the following keys:
325  * @begin{table}{config}
326  * top_border & unsigned & 0 & The size which isn't used for the client
327  * area. $
328  * bottom_border & unsigned & 0 & The size which isn't used for the client
329  * area. $
330  * left_border & unsigned & 0 & The size which isn't used for the client
331  * area. $
332  * right_border & unsigned & 0 & The size which isn't used for the client
333  * area. $
334  * @end{table}
335  *
336  * The following states exist:
337  * * state_enabled, the panel is enabled and not selected.
338  * * state_disabled, the panel is disabled and not selected.
339  * * state_focused, the mouse is over the panel and not selected.
340  *
341  * * state_enabled_selected, the panel is enabled and selected.
342  * * state_disabled_selected, the panel is disabled and selected.
343  * * state_focused_selected, the mouse is over the panel and selected.
344  * @begin{tag}{name="state_enabled"}{min=0}{max=1}{super="generic/state"}
345  * @end{tag}{name="state_enabled"}
346  * @begin{tag}{name="state_disabled"}{min=0}{max=1}{super="generic/state"}
347  * @end{tag}{name="state_disabled"}
348  * @begin{tag}{name="state_focused"}{min=0}{max=1}{super="generic/state"}
349  * @end{tag}{name="state_focused"}
350  * @begin{tag}{name="state_enabled_selected"}{min=0}{max=1}{super="generic/state"}
351  * @end{tag}{name="state_enabled_selected"}
352  * @begin{tag}{name="state_disabled_selected"}{min=0}{max=1}{super="generic/state"}
353  * @end{tag}{name="state_disabled_selected"}
354  * @begin{tag}{name="state_focused_selected"}{min=0}{max=1}{super="generic/state"}
355  * @end{tag}{name="state_focused_selected"}
356  * @end{tag}{name="resolution"}
357  * @end{tag}{name="toggle_panel_definition"}
358  * @end{parent}{name="gui/"}
359  */
362  , top_border(cfg["top_border"])
363  , bottom_border(cfg["bottom_border"])
364  , left_border(cfg["left_border"])
365  , right_border(cfg["right_border"])
366 {
367  // Note the order should be the same as the enum tstate in toggle_panel.hpp.
368  for(const auto& c : cfg.child_range("state"))
369  {
370  state.push_back(tstate_definition(c.child("enabled")));
371  state.push_back(tstate_definition(c.child("disabled")));
372  state.push_back(tstate_definition(c.child("focused")));
373  }
374 }
375 
376 // }---------- BUILDER -----------{
377 
378 /*WIKI
379  * @page = GUIWidgetInstanceWML
380  * @order = 2_toggle_panel
381  * @begin{parent}{name="gui/window/resolution/grid/row/column/"}
382  * @begin{tag}{name="toggle_panel"}{min=0}{max=-1}{super="generic/widget_instance"}
383  * == Toggle panel ==
384  *
385  * A toggle panel is an item which can hold other items. The difference between
386  * a grid and a panel is that it's possible to define how a panel looks. A grid
387  * in an invisible container to just hold the items. The toggle panel is a
388  * combination of the panel and a toggle button, it allows a toggle button with
389  * its own grid.
390  *
391  * @begin{table}{config}
392  * grid & grid & & Defines the grid with the widgets to
393  * place on the panel. $
394  * return_value_id & string & "" & The return value id, see
395  * [[GUIToolkitWML#Button]] for more
396  * information. $
397  * return_value & int & 0 & The return value, see
398  * [[GUIToolkitWML#Button]] for more
399  * information. $
400  * @end{table}
401  * @allow{link}{name="gui/window/resolution/grid"}
402  * @end{tag}{name="toggle_panel"}
403  * @end{parent}{name="gui/window/resolution/grid/row/column/"}
404  */
405 
406 namespace implementation
407 {
408 
409 tbuilder_toggle_panel::tbuilder_toggle_panel(const config& cfg)
410  : tbuilder_control(cfg)
411  , grid(nullptr)
412  , retval_id_(cfg["return_value_id"])
413  , retval_(cfg["return_value"])
414 {
415  const config& c = cfg.child("grid");
416 
417  VALIDATE(c, _("No grid defined."));
418 
419  grid = new tbuilder_grid(c);
420 }
421 
423 {
424  ttoggle_panel* widget = new ttoggle_panel();
425 
426  init_control(widget);
427 
428  widget->set_retval(get_retval(retval_id_, retval_, id));
429 
430  DBG_GUI_G << "Window builder: placed toggle panel '" << id
431  << "' with definition '" << definition << "'.\n";
432 
433  widget->init_grid(grid);
434  return widget;
435 }
436 
437 } // namespace implementation
438 
439 // }------------ END --------------
440 
441 } // namespace gui2
Define the common log macros for the gui toolkit.
void signal_handler_mouse_enter(const event::tevent event, bool &handled)
#define DBG_GUI_P
Definition: log.hpp:69
virtual void impl_draw_background(surface &frame_buffer, int x_offset, int y_offset) override
See twidget::impl_draw_background.
Definition: control.cpp:403
child_itors child_range(const std::string &key)
Definition: config.cpp:613
#define LOG_HEADER
virtual void impl_draw_foreground(surface &frame_buffer, int x_offset, int y_offset) override
See twidget::impl_draw_foreground.
Definition: control.cpp:414
void signal_handler_left_button_click(const event::tevent event, bool &handled)
void signal_handler_pre_left_button_click(const event::tevent event)
virtual unsigned get_state() const override
See tcontrol::get_state.
const GLfloat * c
Definition: glew.h:12741
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
tstate state_
Current state of the widget.
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1221
tresolution_definition_ptr config()
Definition: control.hpp:299
This file contains the window object, this object is a top level container which has the event manage...
twidget * find(const std::string &id, const bool must_be_active) override
See twidget::find.
Definition: container.cpp:175
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:131
void set_state(const tstate state)
virtual void impl_draw_foreground(surface &frame_buffer, int x_offset, int y_offset) override
See twidget::impl_draw_foreground.
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
Definition: glew.h:1347
void set_is_dirty(const bool is_dirty)
Definition: widget.cpp:435
Base class of a resolution, contains the common keys for a resolution.
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:62
A class inherited from ttext_box that displays its input as stars.
Definition: field-fwd.hpp:23
void init_control(tcontrol *control) const
Definition: control.cpp:675
std::string definition
Parameters for the control.
Definition: control.hpp:530
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
tstate
Possible states of the widget.
GLuint64EXT * result
Definition: glew.h:10727
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
This file contains the settings handling of the widget library.
void signal_handler_mouse_leave(const event::tevent event, bool &handled)
std::string selected
Definition: game_config.cpp:84
void set_retval(const int retval, const bool close_window=true)
Sets there return value of the window.
Definition: window.hpp:422
void init_grid(const boost::intrusive_ptr< tbuilder_grid > &grid_builder)
Initializes and builds the grid.
Definition: container.cpp:209
tevent
The event send to the dispatcher.
Definition: handler.hpp:54
void set_retval(const int retval)
Visible container to hold multiple widgets.
Definition: panel.hpp:34
Contains the state info for a resolution.
int retval_
The return value of the button.
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
GLuint res
Definition: glew.h:9258
virtual tpoint border_space() const override
See tcontainer_::border_space.
unsigned state_num_
Usually 1 for selected and 0 for not selected, can also have higher values in tristate buttons...
#define DBG_GUI_E
Definition: log.hpp:35
const std::string & id() const
Definition: widget.cpp:109
Holds a 2D point.
Definition: point.hpp:24
void set_value(const unsigned selected)
Inherited from tselectable_.
virtual twidget * find_at(const tpoint &coordinate, const bool must_be_active) override
See twidget::find_at.
Definition: container.cpp:163
virtual void impl_draw_background(surface &frame_buffer, int x_offset, int y_offset) override
See twidget::impl_draw_background.
std::string sound_toggle_panel_click
Definition: settings.cpp:60
unsigned get_value() const override
Inherited from tselectable_.
Base class for all visible items.
Definition: control.hpp:34
void set_child_members(const std::map< std::string, string_map > &data)
Sets the members of the child controls.
unsigned num_states() const override
Inherited from tselectable_.
std::vector< tstate_definition > state
cl_event event
Definition: glew.h:3070
virtual void set_members(const string_map &data)
Sets the members of the control.
Definition: control.cpp:99
config & child(const std::string &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:658
virtual twidget * find_at(const tpoint &coordinate, const bool must_be_active) override
See twidget::find_at.
Definition: control.cpp:284
Base class for all widgets.
Definition: widget.hpp:49
void play_UI_sound(const std::string &files)
Definition: sound.cpp:842
virtual twidget * find_at(const tpoint &coordinate, const bool must_be_active) override
See twidget::find_at.
twindow * get_window()
Get the parent window.
Definition: widget.cpp:116
Class for a toggle button.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
SDL_Rect get_rectangle() const
Gets the bounding rectangle of the widget on the screen.
Definition: widget.cpp:279
virtual void set_active(const bool active) override
See tcontrol::set_active.
virtual bool get_active() const override
See tcontrol::get_active.
#define DBG_GUI_G
Definition: log.hpp:41
virtual SDL_Rect get_client_rect() const override
See tcontainer_::get_client_rect.
void signal_handler_left_button_double_click(const event::tevent event, bool &handled)
GLsizei const GLcharARB ** string
Definition: glew.h:4503
ttoggle_panel_definition(const config &cfg)
Contains the implementation details for lexical_cast and shouldn't be used directly.
virtual const std::string & get_control_type() const override
See tcontrol::get_control_type.
std::function< void(twidget &)> callback_mouse_left_double_click_
Mouse left double click callback.
std::function< void(twidget &)> callback_state_change_
See tselectable_::set_callback_state_change.