The Battle for Wesnoth  1.15.2+dev
menu_button.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2018 by Mark de Wever <koraq@xs4all.nl>
3  Part of the Battle for Wesnoth Project https://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 
19 #include "gui/core/log.hpp"
24 #include "gui/widgets/settings.hpp"
25 #include "gui/widgets/window.hpp"
26 #include "sound.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(menu_button)
39 
40 menu_button::menu_button(const implementation::builder_menu_button& builder)
41  : styled_widget(builder, type())
42  , selectable_item()
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, _2, _3));
52 
53  connect_signal<event::MOUSE_LEAVE>(
54  std::bind(&menu_button::signal_handler_mouse_leave, this, _2, _3));
55 
56  connect_signal<event::LEFT_BUTTON_DOWN>(
57  std::bind(&menu_button::signal_handler_left_button_down, this, _2, _3));
58 
59  connect_signal<event::LEFT_BUTTON_UP>(
60  std::bind(&menu_button::signal_handler_left_button_up, this, _2, _3));
61 
62  connect_signal<event::LEFT_BUTTON_CLICK>(
63  std::bind(&menu_button::signal_handler_left_button_click, this, _2, _3));
64 
65  connect_signal<event::SDL_WHEEL_UP>(
66  std::bind(&menu_button::signal_handler_sdl_wheel_up, this, _2, _3),
68 
69  connect_signal<event::SDL_WHEEL_DOWN>(
70  std::bind(&menu_button::signal_handler_sdl_wheel_down, this, _2, _3),
72 }
73 
74 void 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 
86 unsigned menu_button::get_state() const
87 {
88  return state_;
89 }
90 
92 {
93  if(state != state_) {
94  state_ = state;
95  set_is_dirty(true);
96  }
97 }
98 
100 {
101  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
102 
104  handled = true;
105 }
106 
108 {
109  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
110 
112  handled = true;
113 }
114 
116 {
117  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
118 
119  window* window = get_window();
120  if(window) {
121  window->mouse_capture();
122  }
123 
125  handled = true;
126 }
127 
129 {
130  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
131 
133  handled = true;
134 }
135 
137 {
138  assert(get_window());
139  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
140 
142 
143  // If a button has a retval do the default handling.
144  dialogs::drop_down_menu droplist(this->get_rectangle(), this->values_, this->selected_, this->get_use_markup(), this->keep_open_,
145  nullptr);
146 
147  if(droplist.show()) {
148  const int selected = droplist.selected_item();
149 
150  // Safety check. If the user clicks a selection in the dropdown and moves their mouse away too
151  // quickly, selected_ could be set to -1. This returns in that case, preventing crashes.
152  if(selected < 0) {
153  return;
154  }
155 
156  set_selected(selected, true);
157  }
158 
159  handled = true;
160 }
161 
163 {
164  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
165 
166  // TODO: should values wrap?
167  if(selected_ > 0) {
168  set_selected(selected_ - 1);
169  }
170 
171  handled = true;
172 }
173 
175 {
176  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
177 
178  // TODO: should values wrap?
179  if(selected_ < values_.size() - 1) {
180  set_selected(selected_ + 1);
181  }
182 
183  handled = true;
184 }
185 
186 void menu_button::set_values(const std::vector<::config>& values, unsigned selected)
187 {
188  assert(selected < values.size());
189  assert(selected_ < values_.size());
190 
191  if(values[selected]["label"] != values_[selected_]["label"]) {
192  set_is_dirty(true);
193  }
194 
195  values_ = values;
196  selected_ = selected;
197 
198  set_label(values_[selected_]["label"]);
199 }
200 
202 {
203  assert(selected < values_.size());
204  assert(selected_ < values_.size());
205 
206  if(selected != selected_) {
207  set_is_dirty(true);
208  }
209 
211 
212  set_label(values_[selected_]["label"]);
213  if (fire_event) {
214  fire(event::NOTIFY_MODIFIED, *this, nullptr);
215  }
216 }
217 
218 // }---------- DEFINITION ---------{
219 
222 {
223  DBG_GUI_P << "Parsing menu_button " << id << '\n';
224 
225  load_resolutions<resolution>(cfg);
226 }
227 
228 /*WIKI
229  * @page = GUIWidgetDefinitionWML
230  * @order = 1_menu_button
231  *
232  * == menu_button ==
233  *
234  * @macro = menu_button_description
235  *
236  * The following states exist:
237  * * state_enabled, the menu_button is enabled.
238  * * state_disabled, the menu_button is disabled.
239  * * state_pressed, the left mouse menu_button is down.
240  * * state_focused, the mouse is over the menu_button.
241  * @begin{parent}{name="gui/"}
242  * @begin{tag}{name="menu_button_definition"}{min=0}{max=-1}{super="generic/widget_definition"}
243  * @begin{tag}{name="resolution"}{min=0}{max=-1}{super="generic/widget_definition/resolution"}
244  * @begin{tag}{name="state_enabled"}{min=0}{max=1}{super="generic/state"}
245  * @end{tag}{name="state_enabled"}
246  * @begin{tag}{name="state_disabled"}{min=0}{max=1}{super="generic/state"}
247  * @end{tag}{name="state_disabled"}
248  * @begin{tag}{name="state_pressed"}{min=0}{max=1}{super="generic/state"}
249  * @end{tag}{name="state_pressed"}
250  * @begin{tag}{name="state_focused"}{min=0}{max=1}{super="generic/state"}
251  * @end{tag}{name="state_focused"}
252  * @end{tag}{name="resolution"}
253  * @end{tag}{name="menu_button_definition"}
254  * @end{parent}{name="gui/"}
255  */
257  : resolution_definition(cfg)
258 {
259  // Note the order should be the same as the enum state_t in menu_button.hpp.
260  state.emplace_back(cfg.child("state_enabled"));
261  state.emplace_back(cfg.child("state_disabled"));
262  state.emplace_back(cfg.child("state_pressed"));
263  state.emplace_back(cfg.child("state_focused"));
264 }
265 
266 // }---------- BUILDER -----------{
267 
268 /*WIKI_MACRO
269  * @begin{macro}{menu_button_description}
270  *
271  * A menu_button is a styled_widget to choose an element from a list of elements.
272  * @end{macro}
273  */
274 
275 /*WIKI
276  * @page = GUIWidgetInstanceWML
277  * @order = 2_menu_button
278  * @begin{parent}{name="gui/window/resolution/grid/row/column/"}
279  * @begin{tag}{name="menu_button"}{min=0}{max=-1}{super="generic/widget_instance"}
280  * == menu_button ==
281  *
282  * @macro = menu_button_description
283  *
284  * Instance of a menu_button. When a menu_button has a return value it sets the
285  * return value for the window. Normally this closes the window and returns
286  * this value to the caller. The return value can either be defined by the
287  * user or determined from the id of the menu_button. The return value has a
288  * higher precedence as the one defined by the id. (Of course it's weird to
289  * give a menu_button an id and then override its return value.)
290  *
291  * When the menu_button doesn't have a standard id, but you still want to use the
292  * return value of that id, use return_value_id instead. This has a higher
293  * precedence as return_value.
294  *
295  * List with the menu_button specific variables:
296  * @begin{table}{config}
297  * return_value_id & string & "" & The return value id. $
298  * return_value & int & 0 & The return value. $
299  *
300  * @end{table}
301  * @end{tag}{name="menu_button"}
302  * @end{parent}{name="gui/window/resolution/grid/row/column/"}
303  */
304 
305 namespace implementation
306 {
307 
308 builder_menu_button::builder_menu_button(const config& cfg)
309  : builder_styled_widget(cfg)
310  , options_()
311 {
312  for(const auto& option : cfg.child_range("option")) {
313  options_.push_back(option);
314  }
315 }
316 
318 {
319  menu_button* widget = new menu_button(*this);
320 
321  if(!options_.empty()) {
322  widget->set_values(options_);
323  }
324 
325  DBG_GUI_G << "Window builder: placed menu_button '" << id
326  << "' with definition '" << definition << "'.\n";
327 
328  return widget;
329 }
330 
331 } // namespace implementation
332 
333 // }------------ END --------------
334 
335 } // 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:68
Small abstract helper class.
void set_selected(unsigned selected, bool fire_event=true)
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:420
void set_state(const state_t state)
Definition: menu_button.cpp:91
std::vector< state_definition > state
Simple push button.
Definition: menu_button.hpp:41
menu_button_definition(const config &cfg)
bool get_use_markup() const
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:362
SDL_Rect get_rectangle() const
Gets the bounding rectangle of the widget on the screen.
Definition: widget.cpp:307
Base class for all widgets.
Definition: widget.hpp:47
std::string sound_button_click
Definition: settings.cpp:39
void signal_handler_left_button_click(const event::ui_event event, bool &handled)
bool show(const unsigned auto_close_time=0)
Shows the window.
void signal_handler_left_button_up(const event::ui_event event, bool &handled)
void signal_handler_left_button_down(const event::ui_event event, bool &handled)
void signal_handler_sdl_wheel_up(const event::ui_event event, bool &handled)
Generic file dialog.
Definition: field-fwd.hpp:22
Sent by a widget to notify others its contents or state are modified.
Definition: handler.hpp:96
virtual void set_label(const t_string &label)
std::string definition
Parameters for the styled_widget.
void signal_handler_mouse_leave(const event::ui_event event, bool &handled)
This file contains the settings handling of the widget library.
void set_is_dirty(const bool is_dirty)
Definition: widget.cpp:463
Used by the menu_button widget.
std::string selected
state_t
Possible states of the widget.
Definition: menu_button.hpp:95
void set_values(const std::vector<::config > &values, unsigned selected=0)
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
state_t state_
Current state of the widget.
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.
#define DBG_GUI_E
Definition: log.hpp:34
virtual unsigned get_state() const override
See styled_widget::get_state.
Definition: menu_button.cpp:86
window * get_window()
Get the parent window.
Definition: widget.cpp:114
std::vector<::config > values_
Base class for all visible items.
void signal_handler_mouse_enter(const event::ui_event event, bool &handled)
Definition: menu_button.cpp:99
void mouse_capture(const bool capture=true)
Definition: window.cpp:1275
void play_UI_sound(const std::string &files)
Definition: sound.cpp:1019
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:130
void signal_handler_sdl_wheel_down(const event::ui_event event, bool &handled)
virtual void set_active(const bool active) override
See styled_widget::set_active.
Definition: menu_button.cpp:74
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:62
#define DBG_GUI_G
Definition: log.hpp:40
virtual bool get_active() const override
See styled_widget::get_active.
Definition: menu_button.cpp:81
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:55