The Battle for Wesnoth  1.15.11+dev
multimenu_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 "formula/string_utils.hpp"
29 #include <functional>
30 #include "gettext.hpp"
31 
32 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
33 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
34 
35 namespace gui2
36 {
37 
38 // ------------ WIDGET -----------{
39 
40 REGISTER_WIDGET(multimenu_button)
41 
42 multimenu_button::multimenu_button(const implementation::builder_multimenu_button& builder)
43  : styled_widget(builder, type())
44  , state_(ENABLED)
45  , max_shown_(1)
46  , values_()
47  , toggle_states_()
48  , droplist_(nullptr)
49 {
50  values_.emplace_back("label", this->get_label());
51 
52  connect_signal<event::MOUSE_ENTER>(
53  std::bind(&multimenu_button::signal_handler_mouse_enter, this, std::placeholders::_2, std::placeholders::_3));
54  connect_signal<event::MOUSE_LEAVE>(
55  std::bind(&multimenu_button::signal_handler_mouse_leave, this, std::placeholders::_2, std::placeholders::_3));
56 
57  connect_signal<event::LEFT_BUTTON_DOWN>(
58  std::bind(&multimenu_button::signal_handler_left_button_down, this, std::placeholders::_2, std::placeholders::_3));
59  connect_signal<event::LEFT_BUTTON_UP>(
60  std::bind(&multimenu_button::signal_handler_left_button_up, this, std::placeholders::_2, std::placeholders::_3));
61  connect_signal<event::LEFT_BUTTON_CLICK>(
62  std::bind(&multimenu_button::signal_handler_left_button_click, this, std::placeholders::_2, std::placeholders::_3));
63 
64  // TODO: might need to position this differently in the queue if it's called after
65  // dialog-specific callbacks.
66  connect_signal<event::NOTIFY_MODIFIED>(
68 }
69 
70 void multimenu_button::set_active(const bool active)
71 {
72  if(get_active() != active) {
73  set_state(active ? ENABLED : DISABLED);
74  }
75 }
76 
78 {
79  return state_ != DISABLED;
80 }
81 
83 {
84  return state_;
85 }
86 
88 {
89  if(state != state_) {
90  state_ = state;
91  set_is_dirty(true);
92  }
93 }
94 
96 {
97  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
98 
100  handled = true;
101 }
102 
104 {
105  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
106 
108  handled = true;
109 }
110 
112 {
113  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
114 
115  window* window = get_window();
116  if(window) {
117  window->mouse_capture();
118  }
119 
121  handled = true;
122 }
123 
125 {
126  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
127 
129  handled = true;
130 }
131 
133 {
134  assert(get_window());
135  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
136 
138 
139  // If a button has a retval do the default handling.
140  dialogs::drop_down_menu droplist(this, values_, -1, true);
141 
142  droplist_ = &droplist;
143  droplist.show();
144  droplist_ = nullptr;
145 
146  /* In order to allow toggle button states to be specified by various dialogs in the values config, we write the state
147  * bools to the values_ config here, but only if a checkbox= key was already provided. The value of the checkbox= key
148  * is handled by the drop_down_menu widget.
149  *
150  * Passing the dynamic_bitset directly to the drop_down_menu ctor would mean bool values would need to be passed to this
151  * class independently of the values config by dialogs that use this widget. However, the bool states are also saved
152  * in a dynamic_bitset class member which can be fetched for other uses if necessary.
153  */
155 
156  handled = true;
157 }
158 
160 {
161  std::vector<t_string> selected;
162  for(std::size_t i = 0; i < toggle_states_.size() && i < values_.size(); i++) {
163  if(!toggle_states_[i]) {
164  continue;
165  }
166 
167  selected.push_back(values_[i]["label"]);
168  }
169 
170  if(selected.size() == values_.size()) {
171  set_label(_("multimenu^All Selected"));
172  } else {
173  if(selected.size() > max_shown_) {
174  const unsigned excess = selected.size() - max_shown_;
175  selected.resize(max_shown_ + 1);
176  selected.back() = VNGETTEXT("multimenu^$excess other", "$excess others", excess, {{"excess", std::to_string(excess)}});
177  }
178  set_label(utils::format_conjunct_list(_("multimenu^None Selected"), selected));
179  }
180 }
181 
183 {
184  for(unsigned i = 0; i < values_.size(); i++) {
185  ::config& c = values_[i];
186 
187  c["checkbox"] = toggle_states_[i];
188  }
189 }
190 
192 {
193  toggle_states_.reset();
195  update_label();
196 }
197 
199 {
200  assert(droplist_ != nullptr);
201 
203  update_label();
204 }
205 
206 void multimenu_button::select_option(const unsigned option, const bool selected)
207 {
208  assert(option < values_.size());
209 
210  if(option < toggle_states_.size()) {
211  toggle_states_.resize(option + 1);
212  }
213  toggle_states_[option] = selected;
215  update_label();
216 }
217 
218 void multimenu_button::select_options(boost::dynamic_bitset<> states)
219 {
220  assert(states.size() == values_.size());
221  toggle_states_ = states;
223  update_label();
224 }
225 
226 void multimenu_button::set_values(const std::vector<::config>& values)
227 {
228  set_is_dirty(true);
229 
230  values_ = values;
231  toggle_states_.resize(values_.size(), false);
232  toggle_states_.reset();
233 
234  set_label(_("multimenu^None Selected"));
235 }
236 
237 // }---------- DEFINITION ---------{
238 
241 {
242  DBG_GUI_P << "Parsing multimenu_button " << id << '\n';
243 
244  load_resolutions<resolution>(cfg);
245 }
246 
248  : resolution_definition(cfg)
249 {
250  // Note the order should be the same as the enum state_t in multimenu_button.hpp.
251  state.emplace_back(cfg.child("state_enabled"));
252  state.emplace_back(cfg.child("state_disabled"));
253  state.emplace_back(cfg.child("state_pressed"));
254  state.emplace_back(cfg.child("state_focused"));
255 }
256 
257 // }---------- BUILDER -----------{
258 
259 namespace implementation
260 {
261 
262 builder_multimenu_button::builder_multimenu_button(const config& cfg)
263  : builder_styled_widget(cfg)
264  , max_shown_(cfg["maximum_shown"].to_unsigned(1))
265  , options_()
266 {
267  for(const auto& option : cfg.child_range("option")) {
268  options_.push_back(option);
269  }
270 }
271 
273 {
275 
276  widget->set_max_shown(max_shown_);
277  if(!options_.empty()) {
278  widget->set_values(options_);
279  }
280 
281  DBG_GUI_G << "Window builder: placed multimenu_button '" << id
282  << "' with definition '" << definition << "'.\n";
283 
284  return widget;
285 }
286 
287 } // namespace implementation
288 
289 // }------------ END --------------
290 
291 } // namespace gui2
Define the common log macros for the gui toolkit.
void signal_handler_left_button_up(const event::ui_event event, bool &handled)
Base class of a resolution, contains the common keys for a resolution.
#define DBG_GUI_P
Definition: log.hpp:65
void set_max_shown(const unsigned max)
Sets the maximum number of selected elements shown on the label.
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:414
std::string format_conjunct_list(const t_string &empty, const std::vector< t_string > &elems)
Format a conjunctive list.
dialogs::drop_down_menu * droplist_
std::vector< state_definition > state
void set_state(const state_t state)
void signal_handler_mouse_enter(const event::ui_event event, bool &handled)
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:356
Base class for all widgets.
Definition: widget.hpp:49
std::string sound_button_click
Definition: settings.cpp:42
#define VNGETTEXT(msgid, msgid_plural, count,...)
A multimenu_button is a styled_widget to choose an element from a list of elements.
static std::string _(const char *str)
Definition: gettext.hpp:92
bool show(const unsigned auto_close_time=0)
Shows the window.
Generic file dialog.
Definition: field-fwd.hpp:22
virtual void set_label(const t_string &label)
virtual unsigned get_state() const override
See styled_widget::get_state.
virtual bool get_active() const override
See styled_widget::get_active.
void signal_handler_left_button_click(const event::ui_event event, bool &handled)
std::string definition
Parameters for the styled_widget.
state_t state_
Current state of the widget.
state_t
Possible states of the widget.
unsigned max_shown_
The maximum number of selected states to list in the label.
This file contains the settings handling of the widget library.
void signal_handler_mouse_leave(const event::ui_event event, bool &handled)
void set_is_dirty(const bool is_dirty)
Definition: widget.cpp:465
Used by the menu_button widget.
std::string selected
boost::dynamic_bitset toggle_states_
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
virtual void set_active(const bool active) override
See styled_widget::set_active.
std::size_t i
Definition: function.cpp:940
boost::dynamic_bitset get_toggle_states() const
If a toggle button widget is present, returns the toggled state of each row&#39;s button.
#define DBG_GUI_E
Definition: log.hpp:34
window * get_window()
Get the parent window.
Definition: widget.cpp:116
#define LOG_HEADER
Base class for all visible items.
void mouse_capture(const bool capture=true)
Definition: window.cpp:1267
void select_options(boost::dynamic_bitset<> states)
Set the options selected in the menu.
void play_UI_sound(const std::string &files)
Definition: sound.cpp:1051
multimenu_button_definition(const config &cfg)
void select_option(const unsigned option, const bool selected=true)
Select an option in the menu.
void signal_handler_left_button_down(const event::ui_event event, bool &handled)
void set_values(const std::vector<::config > &values)
Set the available menu options.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:59
mock_char c
base class of top level items, the only item which needs to store the final canvases to draw on...
Definition: window.hpp:64
#define DBG_GUI_G
Definition: log.hpp:40
std::vector<::config > values_
void reset_toggle_states()
Deselect all the menu options.
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:47