The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
mp_connect.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2008 - 2025
3 by Mark de Wever <koraq@xs4all.nl>
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
19
20#include "gettext.hpp"
27
28#include "log.hpp"
29
30#include <functional>
31
32#include <boost/algorithm/string/trim.hpp>
33
34static lg::log_domain log_mpconnect{"gui/dialogs/mp_connect"};
35#define ERR_DLG LOG_STREAM(err, log_mpconnect)
36#define WRN_DLG LOG_STREAM(warn, log_mpconnect)
37#define LOG_DLG LOG_STREAM(info, log_mpconnect)
38#define DBG_DLG LOG_STREAM(debug, log_mpconnect)
39
40namespace gui2
41{
42
43namespace
44{
45
46// NOTE: See mp_connect::select_first_match() below
47#if 0
48void clear_listbox_selection(listbox& listbox)
49{
50 const auto selection = listbox.get_selected_row();
51 if(selection >= 0) {
52 listbox.select_row(selection, false);
53 }
54}
55#endif
56
57}
58
59namespace dialogs
60{
61
62REGISTER_DIALOG(mp_connect)
63
65 : modal_dialog(window_id())
66 , host_name_(register_text("host_name",
67 true,
68 []() {return prefs::get().network_host();},
69 [](const std::string& v) {prefs::get().set_network_host(v);},
70 true))
71 , builtin_servers_(prefs::get().builtin_servers_list())
72 , user_servers_(prefs::get().user_servers_list())
73{
74}
75
76std::array<mp_connect::server_list*, 2> mp_connect::server_lists()
77{
78 return {{ &builtin_servers_, &user_servers_ }};
79}
80
82{
83 text_box& hostname_box = find_widget<text_box>("host_name");
84 listbox& server_list = find_widget<listbox>("server_list");
85 button& button_add = find_widget<button>("server_add");
86 button& button_del = find_widget<button>("server_delete");
87
88 for(const auto* servers : server_lists()) {
89 for(const auto& server : *servers) {
91 }
92 }
93
95
96 connect_signal_notify_modified(hostname_box, std::bind(&mp_connect::on_address_change, this));
97 connect_signal_notify_modified(server_list, std::bind(&mp_connect::on_server_select, this));
98 connect_signal_mouse_left_click(button_add, std::bind(&mp_connect::on_server_add, this));
99 connect_signal_mouse_left_click(button_del, std::bind(&mp_connect::on_server_delete, this));
100}
101
103{
105 { "name", {
106 { "label", srv.name }
107 }},
108 { "address", {
109 { "label", srv.address }
110 }},
111 }, pos);
112}
113
115{
116 text_box& hostname_box = find_widget<text_box>("host_name");
117 listbox& server_list = find_widget<listbox>("server_list");
118 button& button_add = find_widget<button>("server_add");
119 button& button_del = find_widget<button>("server_delete");
120
121 const auto& address = boost::trim_copy(hostname_box.get_value());
122
123 std::size_t row = 0;
124
125 for(const auto* servers : server_lists()) {
126 for(const auto& server : *servers) {
127 if(server.address == address) {
128 server_list.select_row(row);
129 // Can't Add what's already there or Delete built-in servers
130 button_add.set_active(false);
131 button_del.set_active(servers == &user_servers_);
132 return;
133 }
134
135 ++row;
136 }
137 }
138
139 // NOTE: Do not use this in production. It requires the listbox to be
140 // defined with has_minimum=false in WML, and makes some UI interactions
141 // awkward. In particular it means we would need to keep track of where
142 // the selection was last at every time we clear the selection so that
143 // the Add button can add under it instead of appending to the very end
144 // of the list (currently it just bails out if there's no selection).
145#if 0
146 // The user wrote a brand new hostname in so there's no matches, clear the
147 // selection accordingly
148 clear_listbox_selection(server_list);
149 button_del.set_active(false);
150#endif
151 button_add.set_active(!address.empty());
152}
153
155{
156 // Select the first matching list entry or clear the current selection
158}
159
161{
162 text_box& hostname_box = find_widget<text_box>("host_name");
163 listbox& server_list = find_widget<listbox>("server_list");
164
165 const auto& address = boost::trim_copy(hostname_box.get_value());
166 const auto& selection = current_selection();
167
168 if(address.empty() || !selection.valid()) {
169 // We're not supposed to be here
170 return;
171 }
172
173 // We insert under the selection. If a built-in server is selected or the
174 // user-defined list is empty, we insert at the start of the user-defined
175 // list instead.
176
177 const std::size_t mem_pos = selection.user_defined() && !user_servers_.empty()
178 ? 1 + selection.relative_index() : 0;
179 const unsigned int ui_pos = selection.user_defined() ? 1 + selection.row() : builtin_servers_.size();
180
181 std::string name;
182
183 if(!gui2::dialogs::edit_text::execute(_("Add Server"), _("Name:"), name, true) || name.empty()) {
184 return;
185 }
186
187 server_info info;
188 info.name = name;
189 info.address = address;
190
191 user_servers_.insert(user_servers_.begin() + mem_pos, info);
193
196}
197
199{
200 listbox& server_list = find_widget<listbox>("server_list");
201
203
205 // We're not supposed to be here
206 return;
207 }
208
211
212 server_list.remove_row(selection.row());
214}
215
217{
218 text_box& hostname_box = find_widget<text_box>("host_name");
219 button& button_add = find_widget<button>("server_add");
220 button& button_del = find_widget<button>("server_delete");
221
223
224 if(!selection.valid()) {
225 // The user cleared the selection. We can't delete what isn't selected
226 // and the Add button's status was already set to a value that makes
227 // sense by another signal handler, so just disable Delete.
228 button_del.set_active(false);
229 return;
230 }
231
232 hostname_box.set_value(selection.get().address);
233
234 // Can't Add what's already there
235 button_add.set_active(false);
236 // Can only Delete user-defined servers
237 button_del.set_active(selection.user_defined());
238}
239
241{
242 listbox& server_list = find_widget<listbox>("server_list");
243 return { this, server_list.get_selected_row() };
244}
245
251
253{
254 // An invalid selection is the same as one from the read-only list of
255 // built-in servers for interaction purposes since it can't be written to.
256 return valid() && std::size_t(row_) >= owner_->builtin_servers_.size();
257}
258
260{
261 must_be_valid();
262 return unsigned(row_);
263}
264
266{
267 must_be_valid();
268 return user_defined() ? row() - owner_->builtin_servers_.size() : row();
269}
270
272{
273 must_be_valid();
274 return user_defined() ? owner_->user_servers_ : owner_->builtin_servers_;
275}
276
277} // namespace dialogs
278} // namespace gui2
Simple push button.
Definition button.hpp:36
virtual void set_active(const bool active) override
See styled_widget::set_active.
Definition button.cpp:64
Abstract base class for all modal dialogs.
void insert_into_server_listbox(listbox &listbox, const server_info &srv, int pos=-1)
std::vector< server_info > server_list
std::array< server_list *, 2 > server_lists()
virtual void pre_show() override
Actions to be taken before showing the window.
The listbox class.
Definition listbox.hpp:41
grid & add_row(const widget_item &item, const int index=-1)
When an item in the list is selected by the user we need to update the state.
Definition listbox.cpp:92
std::string get_value() const
virtual void set_value(const std::string &text)
The set_value is virtual for the password_box class.
A widget that allows the user to input text in single line.
Definition text_box.hpp:125
void set_network_host(const std::string &host)
static prefs & get()
std::string network_host()
void set_user_servers_list(const std::vector< game_config::server_info > &value)
Implements some helper classes to ease adding fields to a dialog and hide the synchronization needed.
static std::string _(const char *str)
Definition gettext.hpp:100
Standard logging facilities (interface).
#define REGISTER_DIALOG(window_id)
Wrapper for REGISTER_DIALOG2.
static lg::log_domain log_mpconnect
Various uncategorised dialogs.
Generic file dialog.
std::map< std::string, widget_item > widget_data
Definition widget.hpp:36
std::string address
may include ':' followed by port number