The Battle for Wesnoth  1.17.0-dev
menu_button.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 
20 #include "gui/core/log.hpp"
25 #include "gui/widgets/settings.hpp"
26 #include "gui/widgets/window.hpp"
27 #include "sound.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(menu_button)
40 
41 menu_button::menu_button(const implementation::builder_menu_button& builder)
42  : styled_widget(builder, type())
43  , selectable_item()
44  , state_(ENABLED)
45  , values_()
46  , selected_(0)
47  , keep_open_(false)
48 {
49  values_.emplace_back("label", this->get_label());
50 
51  connect_signal<event::MOUSE_ENTER>(
52  std::bind(&menu_button::signal_handler_mouse_enter, this, std::placeholders::_2, std::placeholders::_3));
53 
54  connect_signal<event::MOUSE_LEAVE>(
55  std::bind(&menu_button::signal_handler_mouse_leave, this, std::placeholders::_2, std::placeholders::_3));
56 
57  connect_signal<event::LEFT_BUTTON_DOWN>(
58  std::bind(&menu_button::signal_handler_left_button_down, this, std::placeholders::_2, std::placeholders::_3));
59 
60  connect_signal<event::LEFT_BUTTON_UP>(
61  std::bind(&menu_button::signal_handler_left_button_up, this, std::placeholders::_2, std::placeholders::_3));
62 
63  connect_signal<event::LEFT_BUTTON_CLICK>(
64  std::bind(&menu_button::signal_handler_left_button_click, this, std::placeholders::_2, std::placeholders::_3));
65 
66  connect_signal<event::SDL_WHEEL_UP>(
67  std::bind(&menu_button::signal_handler_sdl_wheel_up, this, std::placeholders::_2, std::placeholders::_3),
69 
70  connect_signal<event::SDL_WHEEL_DOWN>(
71  std::bind(&menu_button::signal_handler_sdl_wheel_down, this, std::placeholders::_2, std::placeholders::_3),
73 }
74 
75 void menu_button::set_active(const bool active)
76 {
77  if(get_active() != active) {
78  set_state(active ? ENABLED : DISABLED);
79  }
80 }
81 
83 {
84  return state_ != DISABLED;
85 }
86 
87 unsigned menu_button::get_state() const
88 {
89  return state_;
90 }
91 
93 {
94  if(state != state_) {
95  state_ = state;
96  set_is_dirty(true);
97  }
98 }
99 
101 {
102  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
103 
105  handled = true;
106 }
107 
109 {
110  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
111 
113  handled = true;
114 }
115 
117 {
118  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
119 
120  window* window = get_window();
121  if(window) {
122  window->mouse_capture();
123  }
124 
126  handled = true;
127 }
128 
130 {
131  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
132 
134  handled = true;
135 }
136 
138 {
139  assert(get_window());
140  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
141 
143 
144  // If a button has a retval do the default handling.
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 
229  : resolution_definition(cfg)
230 {
231  // Note the order should be the same as the enum state_t in menu_button.hpp.
232  state.emplace_back(cfg.child("state_enabled"));
233  state.emplace_back(cfg.child("state_disabled"));
234  state.emplace_back(cfg.child("state_pressed"));
235  state.emplace_back(cfg.child("state_focused"));
236 }
237 
238 // }---------- BUILDER -----------{
239 
240 namespace implementation
241 {
242 
243 builder_menu_button::builder_menu_button(const config& cfg)
244  : builder_styled_widget(cfg)
245  , options_()
246 {
247  for(const auto& option : cfg.child_range("option")) {
248  options_.push_back(option);
249  }
250 }
251 
253 {
254  menu_button* widget = new menu_button(*this);
255 
256  if(!options_.empty()) {
257  widget->set_values(options_);
258  }
259 
260  DBG_GUI_G << "Window builder: placed menu_button '" << id
261  << "' with definition '" << definition << "'.\n";
262 
263  return widget;
264 }
265 
266 } // namespace implementation
267 
268 // }------------ END --------------
269 
270 } // 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
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:402
void set_state(const state_t state)
Definition: menu_button.cpp:92
std::vector< state_definition > state
A menu_button is a styled_widget to choose an element from a list of elements.
Definition: menu_button.hpp:61
menu_button_definition(const config &cfg)
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:49
std::string sound_button_click
Definition: settings.cpp:43
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:23
Sent by a widget to notify others its contents or state are modified.
Definition: handler.hpp:89
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:466
Used by the menu_button widget.
std::string selected
state_t
Possible states of the widget.
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:35
virtual unsigned get_state() const override
See styled_widget::get_state.
Definition: menu_button.cpp:87
window * get_window()
Get the parent window.
Definition: widget.cpp:117
std::vector<::config > values_
Base class for all visible items.
virtual widget * build() const override
void signal_handler_mouse_enter(const event::ui_event event, bool &handled)
void mouse_capture(const bool capture=true)
Definition: window.cpp:1270
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
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:75
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
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
virtual bool get_active() const override
See styled_widget::get_active.
Definition: menu_button.cpp:82
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