1 /*
2 Copyright (C) 2011 - 2018 by Lukasz Dobrogowski
3 <lukasz.dobrogowski@gmail.com>
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
18 #include "gui/dialogs/multiplayer/mp_change_control.hpp"
19
20 #include "font/text_formatting.hpp"
21 #include "formatter.hpp"
22 #include "formula/string_utils.hpp"
23 #include "game_board.hpp"
24 #include "game_display.hpp"
25 #include "preferences/credentials.hpp"
26 #include "gui/auxiliary/find_widget.hpp"
27 #include "gui/widgets/label.hpp"
28 #include "gui/widgets/listbox.hpp"
29 #include "gui/widgets/settings.hpp"
30 #include "gui/widgets/window.hpp"
31 #include "log.hpp"
32 #include "menu_events.hpp"
33 #include "team.hpp"
34
35 #include "utils/functional.hpp"
36
37 static lg::log_domain log_gui("gui/dialogs/mp_change_control");
38 #define ERR_GUI LOG_STREAM(err, log_gui)
39 #define WRN_GUI LOG_STREAM(warn, log_gui)
40 #define LOG_GUI LOG_STREAM(info, log_gui)
41 #define DBG_GUI LOG_STREAM(debug, log_gui)
42
43 namespace gui2
44 {
45 namespace dialogs
46 {
47
48 /*WIKI
49 * @page = GUIWindowDefinitionWML
50 * @order = 2_mp_change_control
51 *
52 * == Change control dialog ==
53 *
54 * This shows the multiplayer change control dialog.
55 *
56 * @begin{table}{dialog_widgets}
57 * sides_list & & listbox & m &
58 * List of sides participating in the MP game. $
59 *
60 * nicks_list & & listbox & m &
61 * List of nicks of all clients playing or observing the MP game. $
62 *
63 * @end{table}
64 *
65 */
66
REGISTER_DIALOG(mp_change_control)67 REGISTER_DIALOG(mp_change_control)
68
69 mp_change_control::mp_change_control(events::menu_handler& mh)
70 : menu_handler_(mh)
71 , selected_side_(0)
72 , selected_nick_(0)
73 , sides_()
74 , nicks_()
75 {
76 }
77
pre_show(window & window)78 void mp_change_control::pre_show(window& window)
79 {
80 listbox& sides_list = find_widget<listbox>(&window, "sides_list", false);
81 listbox& nicks_list = find_widget<listbox>(&window, "nicks_list", false);
82
83 connect_signal_notify_modified(sides_list,
84 std::bind(&mp_change_control::handle_sides_list_item_clicked, this, std::ref(window)));
85
86 connect_signal_notify_modified(nicks_list,
87 std::bind(&mp_change_control::handle_nicks_list_item_clicked, this, std::ref(window)));
88
89 //
90 // Initialize sides list
91 //
92 const unsigned int num_sides = menu_handler_.board().teams().size();
93
94 for(unsigned int side = 1; side <= num_sides; ++side) {
95 if(menu_handler_.board().get_team(side).hidden()) {
96 continue;
97 }
98
99 sides_.push_back(side);
100
101 std::map<std::string, string_map> data;
102 string_map item;
103
104 std::string side_str = VGETTEXT("Side $side", {{"side", std::to_string(side)}});
105 side_str = font::span_color(team::get_side_color(side)) + side_str + "</span>";
106
107 item["id"] = (formatter() << "side_" << side).str();
108 item["label"] = side_str;
109 item["use_markup"] = "true";
110 data.emplace("side", item);
111
112 sides_list.add_row(data);
113 }
114
115 //
116 // Prepare set of available nicknames
117 //
118 std::set<std::string> temp_nicks;
119 for(const auto& team : menu_handler_.board().teams()) {
120 if(!team.is_local_ai() && !team.is_network_ai() && !team.is_idle()
121 && !team.is_empty() && !team.current_player().empty())
122 {
123 temp_nicks.insert(team.current_player());
124 }
125 }
126
127 const std::set<std::string>& observers = game_display::get_singleton()->observers();
128 temp_nicks.insert(observers.begin(), observers.end());
129
130 // In case we are an observer, it isn't in the observers set and has to be added manually.
131 temp_nicks.insert(preferences::login());
132
133 //
134 // Initialize nick list
135 //
136 for(const std::string& nick : temp_nicks) {
137 nicks_.push_back(nick);
138
139 std::map<std::string, string_map> data;
140 string_map item;
141
142 item["id"] = nick;
143 item["label"] = nick;
144 item["use_markup"] = "true";
145 data.emplace("nick", item);
146
147 nicks_list.add_row(data);
148 }
149
150 handle_sides_list_item_clicked(window);
151 handle_nicks_list_item_clicked(window);
152 }
153
handle_sides_list_item_clicked(window & window)154 void mp_change_control::handle_sides_list_item_clicked(window& window)
155 {
156 selected_side_ = find_widget<listbox>(&window, "sides_list", false).get_selected_row();
157
158 highlight_side_nick(window);
159 }
160
handle_nicks_list_item_clicked(window & window)161 void mp_change_control::handle_nicks_list_item_clicked(window& window)
162 {
163 selected_nick_ = find_widget<listbox>(&window, "nicks_list", false).get_selected_row();
164 }
165
highlight_side_nick(window & window)166 void mp_change_control::highlight_side_nick(window& window)
167 {
168 listbox& nicks_list = find_widget<listbox>(&window, "nicks_list", false);
169 const auto& teams = menu_handler_.board().teams();
170
171 int i = 0;
172 for(const std::string& nick : nicks_) {
173 std::string label_str = "";
174
175 if(selected_side_ <= static_cast<unsigned int>(teams.size()) && teams.at(selected_side_).current_player() == nick) {
176 label_str = formatter() << "<b>" << nick << "</b>";
177 } else {
178 label_str = nick;
179 }
180
181 grid* row_grid = nicks_list.get_row_grid(i);
182 find_widget<label>(row_grid, nick, false).set_label(label_str);
183
184 ++i;
185 }
186 }
187
post_show(window & window)188 void mp_change_control::post_show(window& window)
189 {
190 if(window.get_retval() == retval::OK) {
191 DBG_GUI << "Main: changing control of side "
192 << sides_[selected_side_] << " to nick "
193 << nicks_[selected_nick_] << std::endl;
194
195 menu_handler_.request_control_change(
196 sides_[selected_side_],
197 nicks_[selected_nick_]
198 );
199 }
200 }
201
202 } // namespace dialogs
203 } // namespace gui2
204