The Battle for Wesnoth  1.15.1+dev
group.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2018 The Battle for Wesnoth Project https://www.wesnoth.org/
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY.
10 
11  See the COPYING file for more details.
12 */
13 
14 #pragma once
15 
17 #include "gui/core/log.hpp"
20 #include "gui/widgets/widget.hpp"
21 #include "utils/functional.hpp"
22 
23 #include <map>
24 #include <vector>
25 
26 namespace gui2
27 {
28 
29 template<class T>
30 class group
31 {
32  using group_map = std::map<T, selectable_item*>;
33  using order_vector = std::vector<styled_widget*>;
34 
35 public:
36  /**
37  * Adds a widget/value pair to the group map. A callback is set that toggles each members'
38  * state to false when clicked. This happens before individual widget handlers fire, ensuring
39  * that the clicked widget will remain the only one selected.
40  */
41  void add_member(selectable_item* w, const T& value)
42  {
43  bool success;
44  std::tie(std::ignore, success) = members_.emplace(value, w);
45 
46  if(!success) {
47  ERR_GUI_G << "Group member with value " << value << "already exists." << std::endl;
48  return;
49  }
50 
53 
54  member_order_.push_back(dynamic_cast<styled_widget*>(w));
55  }
56 
57  /**
58  * Removes a member from the group map.
59  */
60  void remove_member(const T& value)
61  {
62  members_.erase(value);
63  }
64 
65  /**
66  * Clears the entire group of members.
67  */
68  void clear()
69  {
70  members_.clear();
71  }
72 
73  /**
74  * Group member getters
75  */
77  {
78  return members_;
79  }
80 
81  const group_map& members() const
82  {
83  return members_;
84  }
85 
86  template<typename W>
87  W& member(const T& value)
88  {
89  return dynamic_cast<W&>(*members_.at(value));
90  }
91 
92  /**
93  * Returns the value paired with the currently actively toggled member of the group.
94  */
96  {
97  for(auto& member : members_) {
98  if(member.second->get_value_bool()) {
99  return member.first;
100  }
101  }
102 
103  return T();
104  }
105 
106  /**
107  * Sets the toggle values for all widgets besides the one associated
108  * with the specified value to false.
109  */
110  void set_member_states(const T& value)
111  {
112  for(auto& member : members_) {
113  member.second->set_value(member.first == value);
114  }
115  }
116 
117  /**
118  * Sets a common callback function for all members.
119  */
120  void set_callback_on_value_change(std::function<void(widget&)> func)
121  {
122  // Ensure this callback is only called on the member being activated
123  const auto callback = [func](widget& widget)->void {
124  if(dynamic_cast<selectable_item&>(widget).get_value_bool()) {
125  func(widget);
126  }
127  };
128 
129  for(auto& member : members_) {
130  event::connect_signal_notify_modified(dynamic_cast<widget&>(*member.second), std::bind(callback, _1));
131  }
132  }
133 
134  /**
135  * Wrapper for enabling or disabling member widgets.
136  * Each member widget will be enabled or disabled based on the result of the specified
137  * predicate, which takes its associated value.
138  *
139  * If a selected widget is to be disabled, it is deselected and the first active member
140  * selected instead. The same happens if no members were previously active at all.
141  */
142  void set_members_enabled(std::function<bool(const T&)> predicate)
143  {
144  bool do_reselect = true;
145 
146  for(auto& member : members_) {
147  const bool res = predicate(member.first);
148 
149  selectable_item& w = *member.second;
150  dynamic_cast<styled_widget&>(w).set_active(res);
151 
152  // Only select another member if this was selected
153  if(w.get_value_bool()) {
154  do_reselect = !res;
155 
156  if(do_reselect) {
157  w.set_value_bool(false);
158  }
159  }
160  }
161 
162  if(!do_reselect) {
163  return;
164  }
165 
166  // Look for the first active member to select
167  for(auto& member : member_order_) {
168  if(member->get_active()) {
169  dynamic_cast<selectable_item&>(*member).set_value_bool(true);
170  break;
171  }
172  }
173  }
174 
175 private:
176  /**
177  * Container map for group members, organized by member value, associated widget.
178  */
180 
181  /**
182  * Since iterating over std::map is specified by operator< for it's key values, we can't
183  * guarantee the order would line up with the logical order - ie, that which the widgets
184  * appear in in a specific dialog. Keeping a separate vector here allows iterating over
185  * members in the order which they are added to the group.
186  */
188 
189  /**
190  * The default actions to take when clicking on one of the widgets in the group.
191  */
193  {
194  for(auto& member : members_) {
195  member.second->set_value(false);
196  }
197  }
198 };
199 
200 } // namespace gui2
Define the common log macros for the gui toolkit.
std::map< SCALING_ALGORITHM, selectable_item *> group_map
Definition: group.hpp:32
void set_value_bool(bool value, bool fire_event=false)
Small abstract helper class.
group_map & members()
Group member getters.
Definition: group.hpp:76
const group_map & members() const
Definition: group.hpp:81
T get_active_member_value()
Returns the value paired with the currently actively toggled member of the group. ...
Definition: group.hpp:95
std::vector< styled_widget *> order_vector
Definition: group.hpp:33
Base class for all widgets.
Definition: widget.hpp:47
void set_members_enabled(std::function< bool(const T &)> predicate)
Wrapper for enabling or disabling member widgets.
Definition: group.hpp:142
#define ERR_GUI_G
Definition: log.hpp:43
std::enable_if_t< has_key< set_event, E >::value > connect_signal(const signal_function &signal, const queue_position position=back_child)
Connect a signal for callback in set_event.
Definition: dispatcher.hpp:393
Generic file dialog.
Definition: field-fwd.hpp:22
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification_function &signal)
Connects a signal handler for getting a notification upon modification.
Definition: dispatcher.cpp:248
void clear()
Clears the entire group of members.
Definition: group.hpp:68
group_map members_
Container map for group members, organized by member value, associated widget.
Definition: group.hpp:179
void add_member(selectable_item *w, const T &value)
Adds a widget/value pair to the group map.
Definition: group.hpp:41
int w
Base class for all visible items.
order_vector member_order_
Since iterating over std::map is specified by operator< for it&#39;s key values, we can&#39;t guarantee the o...
Definition: group.hpp:187
W & member(const T &value)
Definition: group.hpp:87
void remove_member(const T &value)
Removes a member from the group map.
Definition: group.hpp:60
A left mouse button click event for a widget.
Definition: handler.hpp:70
void group_operator()
The default actions to take when clicking on one of the widgets in the group.
Definition: group.hpp:192
void set_member_states(const T &value)
Sets the toggle values for all widgets besides the one associated with the specified value to false...
Definition: group.hpp:110
void set_callback_on_value_change(std::function< void(widget &)> func)
Sets a common callback function for all members.
Definition: group.hpp:120