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