The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
group.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2008 - 2025
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"
22
23#include <map>
24#include <vector>
25
26namespace gui2
27{
28
29template<class T>
30class group
31{
32 using group_map = std::map<T, selectable_item*>;
33 using order_vector = std::vector<styled_widget*>;
34
35public:
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 */
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 already exists.";
48 return;
49 }
50
52 [this](auto&&...) { group_operator(); }, event::dispatcher::front_child);
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 */
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 template<typename Func>
121 void on_modified(const Func& func)
122 {
123 // Ensure this callback is only called on the member being activated
124 const auto callback = [func, this](widget& widget, auto&&...) -> void {
125 if(auto& si = dynamic_cast<selectable_item&>(widget); si.get_value_bool()) {
126 for(auto& [v, w] : members_) {
127 if(&si == w) {
128 func(widget, v);
129 return;
130 }
131 }
132
133 throw std::runtime_error("Group value change callback invoked for non-member widget");
134 }
135 };
136
137 for(auto& member : members_) {
138 event::connect_signal_notify_modified(dynamic_cast<widget&>(*member.second), callback);
139 }
140 }
141
142 /**
143 * Wrapper for enabling or disabling member widgets.
144 * Each member widget will be enabled or disabled based on the result of the specified
145 * predicate, which takes its associated value.
146 *
147 * If a selected widget is to be disabled, it is deselected and the first active member
148 * selected instead. The same happens if no members were previously active at all.
149 */
150 template<typename Func>
151 void set_members_enabled(const Func& predicate)
152 {
153 bool do_reselect = true;
154
155 for(auto& member : members_) {
156 const bool res = predicate(member.first);
157
158 selectable_item& w = *member.second;
159 dynamic_cast<styled_widget&>(w).set_active(res);
160
161 // Only select another member if this was selected
162 if(w.get_value_bool()) {
163 do_reselect = !res;
164
165 if(do_reselect) {
166 w.set_value_bool(false);
167 }
168 }
169 }
170
171 if(!do_reselect) {
172 return;
173 }
174
175 // Look for the first active member to select
176 for(auto& member : member_order_) {
177 if(member->get_active()) {
178 dynamic_cast<selectable_item&>(*member).set_value_bool(true);
179 break;
180 }
181 }
182 }
183
184private:
185 /**
186 * Container map for group members, organized by member value, associated widget.
187 */
189
190 /**
191 * Since iterating over std::map is specified by operator< for it's key values, we can't
192 * guarantee the order would line up with the logical order - ie, that which the widgets
193 * appear in in a specific dialog. Keeping a separate vector here allows iterating over
194 * members in the order which they are added to the group.
195 */
197
198 /**
199 * The default actions to take when clicking on one of the widgets in the group.
200 */
202 {
203 for(auto& member : members_) {
204 member.second->set_value(false);
205 }
206 }
207};
208
209} // namespace gui2
void connect_signal(const F &func, const queue_position position=back_child)
Adds a callback to the appropriate queue based on event type.
void group_operator()
The default actions to take when clicking on one of the widgets in the group.
Definition group.hpp:201
void remove_member(const T &value)
Removes a member from the group map.
Definition group.hpp:60
void on_modified(const Func &func)
Sets a common callback function for all members.
Definition group.hpp:121
void add_member(selectable_item *w, const T &value)
Adds a widget/value pair to the group map.
Definition group.hpp:41
void clear()
Clears the entire group of members.
Definition group.hpp:68
W & member(const T &value)
Definition group.hpp:87
void set_members_enabled(const Func &predicate)
Wrapper for enabling or disabling member widgets.
Definition group.hpp:151
std::map< T, selectable_item * > group_map
Definition group.hpp:32
std::vector< styled_widget * > order_vector
Definition group.hpp:33
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
T get_active_member_value() const
Returns the value paired with the currently actively toggled member of the group.
Definition group.hpp:95
order_vector member_order_
Since iterating over std::map is specified by operator< for it's key values, we can't guarantee the o...
Definition group.hpp:196
group_map members_
Container map for group members, organized by member value, associated widget.
Definition group.hpp:188
group_map & members()
Group member getters.
Definition group.hpp:76
const group_map & members() const
Definition group.hpp:81
Small abstract helper class.
void set_value_bool(bool value, bool fire_event=false)
Base class for all widgets.
Definition widget.hpp:55
Define the common log macros for the gui toolkit.
#define ERR_GUI_G
Definition log.hpp:44
@ LEFT_BUTTON_CLICK
Definition handler.hpp:122
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification &signal)
Connects a signal handler for getting a notification upon modification.
Generic file dialog.
int w
Definition pathfind.cpp:188
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139