The Battle for Wesnoth  1.17.17+dev
mp_connect.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2023
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"
21 #include "preferences/game.hpp"
22 #include "gui/auxiliary/field.hpp"
25 #include "gui/widgets/button.hpp"
26 #include "gui/widgets/listbox.hpp"
27 #include "gui/widgets/settings.hpp"
28 
29 #include "log.hpp"
30 
31 #include <functional>
32 
33 #include <boost/algorithm/string/trim.hpp>
34 
35 static lg::log_domain log_mpconnect{"gui/dialogs/mp_connect"};
36 #define ERR_DLG LOG_STREAM(err, log_mpconnect)
37 #define WRN_DLG LOG_STREAM(warn, log_mpconnect)
38 #define LOG_DLG LOG_STREAM(info, log_mpconnect)
39 #define DBG_DLG LOG_STREAM(debug, log_mpconnect)
40 
41 namespace gui2
42 {
43 
44 namespace
45 {
46 
47 // NOTE: See mp_connect::select_first_match() below
48 #if 0
49 void clear_listbox_selection(listbox& listbox)
50 {
51  const auto selection = listbox.get_selected_row();
52  if(selection >= 0) {
53  listbox.select_row(selection, false);
54  }
55 }
56 #endif
57 
58 }
59 
60 namespace dialogs
61 {
62 
63 REGISTER_DIALOG(mp_connect)
64 
66  : modal_dialog(window_id())
67  , host_name_(register_text("host_name",
68  true,
71  true))
72  , builtin_servers_(preferences::builtin_servers_list())
73  , user_servers_(preferences::user_servers_list())
74 {
75 }
76 
77 std::array<mp_connect::server_list*, 2> mp_connect::server_lists()
78 {
79  return {{ &builtin_servers_, &user_servers_ }};
80 }
81 
83 {
84  text_box& hostname_box = find_widget<text_box>(&win, "host_name", false);
85  listbox& server_list = find_widget<listbox>(&win, "server_list", false);
86  button& button_add = find_widget<button>(&win, "server_add", false);
87  button& button_del = find_widget<button>(&win, "server_delete", false);
88 
89  for(const auto* servers : server_lists()) {
90  for(const auto& server : *servers) {
92  }
93  }
94 
96 
97  connect_signal_notify_modified(hostname_box, std::bind(&mp_connect::on_address_change, this));
99  connect_signal_mouse_left_click(button_add, std::bind(&mp_connect::on_server_add, this));
100  connect_signal_mouse_left_click(button_del, std::bind(&mp_connect::on_server_delete, this));
101 }
102 
104 {
105  const widget_data& entry{
106  { "name", widget_item{{"label", srv.name}} },
107  { "address", widget_item{{"label", srv.address}} },
108  };
109 
110  listbox.add_row(entry, pos);
111 }
112 
114 {
115  window* window = get_window();
116 
117  text_box& hostname_box = find_widget<text_box>(window, "host_name", false);
118  listbox& server_list = find_widget<listbox>(window, "server_list", false);
119  button& button_add = find_widget<button>(window, "server_add", false);
120  button& button_del = find_widget<button>(window, "server_delete", false);
121 
122  const auto& address = boost::trim_copy(hostname_box.get_value());
123 
124  std::size_t row = 0;
125 
126  for(const auto* servers : server_lists()) {
127  for(const auto& server : *servers) {
128  if(server.address == address) {
129  server_list.select_row(row);
130  // Can't Add what's already there or Delete built-in servers
131  button_add.set_active(false);
132  button_del.set_active(servers == &user_servers_);
133  return;
134  }
135 
136  ++row;
137  }
138  }
139 
140  // NOTE: Do not use this in production. It requires the listbox to be
141  // defined with has_minimum=false in WML, and makes some UI interactions
142  // awkward. In particular it means we would need to keep track of where
143  // the selection was last at every time we clear the selection so that
144  // the Add button can add under it instead of appending to the very end
145  // of the list (currently it just bails out if there's no selection).
146 #if 0
147  // The user wrote a brand new hostname in so there's no matches, clear the
148  // selection accordingly
149  clear_listbox_selection(server_list);
150  button_del.set_active(false);
151 #endif
152  button_add.set_active(!address.empty());
153 }
154 
156 {
157  // Select the first matching list entry or clear the current selection
159 }
160 
162 {
163  window* window = get_window();
164 
165  text_box& hostname_box = find_widget<text_box>(window, "host_name", false);
166  listbox& server_list = find_widget<listbox>(window, "server_list", false);
167 
168  const auto& address = boost::trim_copy(hostname_box.get_value());
169  const auto& selection = current_selection();
170 
171  if(address.empty() || !selection.valid()) {
172  // We're not supposed to be here
173  return;
174  }
175 
176  // We insert under the selection. If a built-in server is selected or the
177  // user-defined list is empty, we insert at the start of the user-defined
178  // list instead.
179 
180  const std::size_t mem_pos = selection.user_defined() && !user_servers_.empty()
181  ? 1 + selection.relative_index() : 0;
182  const unsigned int ui_pos = selection.user_defined() ? 1 + selection.row() : builtin_servers_.size();
183 
184  std::string name;
185 
186  if(!gui2::dialogs::edit_text::execute(_("Add Server"), _("Name:"), name, true) || name.empty()) {
187  return;
188  }
189 
191  info.name = name;
192  info.address = address;
193 
194  user_servers_.insert(user_servers_.begin() + mem_pos, info);
196 
199 }
200 
202 {
203  window* window = get_window();
204 
205  listbox& server_list = find_widget<listbox>(window, "server_list", false);
206 
207  auto selection = current_selection();
208 
209  if(!selection.valid() || !selection.user_defined()) {
210  // We're not supposed to be here
211  return;
212  }
213 
216 
217  server_list.remove_row(selection.row());
219 }
220 
222 {
223  window* window = get_window();
224 
225  text_box& hostname_box = find_widget<text_box>(window, "host_name", false);
226  button& button_add = find_widget<button>(window, "server_add", false);
227  button& button_del = find_widget<button>(window, "server_delete", false);
228 
229  auto selection = current_selection();
230 
231  if(!selection.valid()) {
232  // The user cleared the selection. We can't delete what isn't selected
233  // and the Add button's status was already set to a value that makes
234  // sense by another signal handler, so just disable Delete.
235  button_del.set_active(false);
236  return;
237  }
238 
239  hostname_box.set_value(selection.get().address);
240 
241  // Can't Add what's already there
242  button_add.set_active(false);
243  // Can only Delete user-defined servers
244  button_del.set_active(selection.user_defined());
245 }
246 
248 {
249  listbox& server_list = find_widget<listbox>(get_window(), "server_list", false);
250  return { this, server_list.get_selected_row() };
251 }
252 
254 {
255  must_be_valid();
256  return parent_list().at(relative_index());
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:37
virtual void set_active(const bool active) override
See styled_widget::set_active.
Definition: button.cpp:65
Abstract base class for all modal dialogs.
window * get_window()
Returns a pointer to the dialog's window.
server_list & parent_list() const
Definition: mp_connect.cpp:271
This shows the dialog to the MP server to connect to.
Definition: mp_connect.hpp:43
void insert_into_server_listbox(listbox &listbox, const server_info &srv, int pos=-1)
Definition: mp_connect.cpp:103
std::vector< server_info > server_list
Definition: mp_connect.hpp:68
std::array< server_list *, 2 > server_lists()
Definition: mp_connect.cpp:77
virtual void pre_show(window &window) override
Actions to be taken before showing the window.
Definition: mp_connect.cpp:82
The listbox class.
Definition: listbox.hpp:46
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:62
std::string get_value() const
virtual void set_value(const std::string &text)
The set_value is virtual for the password_box class.
Class for a single line text area.
Definition: text_box.hpp:142
base class of top level items, the only item which needs to store the final canvases to draw on.
Definition: window.hpp:67
dialogs::modal_dialog * owner_
The dialog that owns the window.
Definition: window.hpp:448
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:93
Standard logging facilities (interface).
#define REGISTER_DIALOG(window_id)
Wrapper for REGISTER_DIALOG2.
static lg::log_domain log_mpconnect
Definition: mp_connect.cpp:35
Various uncategorised dialogs.
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification &signal)
Connects a signal handler for getting a notification upon modification.
Definition: dispatcher.cpp:205
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal &signal)
Connects a signal handler for a left mouse button click.
Definition: dispatcher.cpp:179
Generic file dialog.
std::map< std::string, widget_item > widget_data
Definition: widget.hpp:35
std::map< std::string, t_string > widget_item
Definition: widget.hpp:32
logger & info()
Definition: log.cpp:232
Modify, read and display user preferences.
void set_user_servers_list(const std::vector< game_config::server_info > &value)
Definition: game.cpp:375
std::string network_host()
Definition: game.cpp:387
std::vector< game_config::server_info > user_servers_list()
Definition: game.cpp:362
void set_network_host(const std::string &host)
Definition: game.cpp:397
const std::vector< game_config::server_info > & builtin_servers_list()
Definition: game.cpp:356
This file contains the settings handling of the widget library.
std::string address
may include ':' followed by port number
Definition: game_config.hpp:72