OpenTTD Source 15.0-beta2
network_gui.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#include "../stdafx.h"
11#include "../strings_func.h"
12#include "../fios.h"
13#include "network_client.h"
14#include "network_gui.h"
15#include "network_gamelist.h"
16#include "network.h"
17#include "network_base.h"
18#include "network_content.h"
19#include "network_server.h"
20#include "network_coordinator.h"
21#include "network_survey.h"
22#include "../gui.h"
23#include "network_udp.h"
24#include "../window_func.h"
25#include "../gfx_func.h"
26#include "../dropdown_type.h"
27#include "../dropdown_func.h"
28#include "../querystring_gui.h"
29#include "../sortlist_type.h"
30#include "../company_func.h"
31#include "../command_func.h"
32#include "../core/geometry_func.hpp"
33#include "../genworld.h"
34#include "../map_type.h"
35#include "../zoom_func.h"
36#include "../sprite.h"
37#include "../settings_internal.h"
38#include "../company_cmd.h"
39#include "../timer/timer.h"
40#include "../timer/timer_window.h"
41#include "../timer/timer_game_calendar.h"
42#include "../textfile_gui.h"
43#include "../stringfilter_type.h"
44
45#include "../widgets/network_widget.h"
46
47#include "table/strings.h"
48#include "../table/sprites.h"
49
50#ifdef __EMSCRIPTEN__
51# include <emscripten.h>
52#endif
53
54#include "../safeguards.h"
55
56static void ShowNetworkStartServerWindow();
57
59static CompanyID _admin_company_id = CompanyID::Invalid();
60
69
70static DropDownList BuildVisibilityDropDownList()
71{
72 DropDownList list;
73
74 list.push_back(MakeDropDownListStringItem(STR_NETWORK_SERVER_VISIBILITY_LOCAL, SERVER_GAME_TYPE_LOCAL));
75 list.push_back(MakeDropDownListStringItem(STR_NETWORK_SERVER_VISIBILITY_INVITE_ONLY, SERVER_GAME_TYPE_INVITE_ONLY));
76 list.push_back(MakeDropDownListStringItem(STR_NETWORK_SERVER_VISIBILITY_PUBLIC, SERVER_GAME_TYPE_PUBLIC));
77
78 return list;
79}
80
82typedef int ServerListPosition;
83static const ServerListPosition SLP_INVALID = -1;
84
87 static const uint MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER = 150;
88public:
90 {
91 auto leaf = std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NAME, WidgetData{.string = STR_NETWORK_SERVER_LIST_GAME_NAME}, STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP);
92 leaf->SetResize(1, 0);
93 leaf->SetFill(1, 0);
94 this->Add(std::move(leaf));
95
96 this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CLIENTS, WidgetData{.string = STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION}, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP));
97 this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_MAPSIZE, WidgetData{.string = STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION}, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP));
98 this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_DATE, WidgetData{.string = STR_NETWORK_SERVER_LIST_DATE_CAPTION}, STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP));
99 this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_YEARS, WidgetData{.string = STR_NETWORK_SERVER_LIST_PLAY_TIME_CAPTION}, STR_NETWORK_SERVER_LIST_PLAY_TIME_CAPTION_TOOLTIP));
100
101 leaf = std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_INFO, WidgetData{.string = STR_EMPTY}, STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP);
102 leaf->SetFill(0, 1);
103 this->Add(std::move(leaf));
104 }
105
106 void SetupSmallestSize(Window *w) override
107 {
108 this->smallest_y = 0; // Biggest child.
109 this->fill_x = 1;
110 this->fill_y = 0;
111 this->resize_x = 1; // We only resize in this direction
112 this->resize_y = 0; // We never resize in this direction
113
114 /* First initialise some variables... */
115 for (const auto &child_wid : this->children) {
116 child_wid->SetupSmallestSize(w);
117 this->smallest_y = std::max(this->smallest_y, child_wid->smallest_y + child_wid->padding.Vertical());
118 }
119
120 /* ... then in a second pass make sure the 'current' sizes are set. Won't change for most widgets. */
121 for (const auto &child_wid : this->children) {
122 child_wid->current_x = child_wid->smallest_x;
123 child_wid->current_y = this->smallest_y;
124 }
125
126 this->smallest_x = this->children.front()->smallest_x + this->children.back()->smallest_x; // First and last are always shown, rest not
127 this->ApplyAspectRatio();
128 }
129
130 void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override
131 {
132 assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
133
134 this->pos_x = x;
135 this->pos_y = y;
136 this->current_x = given_width;
137 this->current_y = given_height;
138
139 given_width -= this->children.back()->smallest_x;
140 /* The first and last widget are always visible, determine which other should be visible */
141 if (this->children.size() > 2) {
142 auto first = std::next(std::begin(this->children));
143 auto last = std::prev(std::end(this->children));
144 for (auto it = first; it != last; ++it) {
145 auto &child_wid = *it;
146 if (given_width > ScaleGUITrad(MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER) + child_wid->smallest_x && (*std::prev(it))->current_x != 0) {
147 given_width -= child_wid->smallest_x;
148 child_wid->current_x = child_wid->smallest_x; /* Make visible. */
149 } else {
150 child_wid->current_x = 0; /* Make invisible. */
151 }
152 }
153 }
154
155 /* All remaining space goes to the first (name) widget */
156 this->children.front()->current_x = given_width;
157
158 /* Now assign the widgets to their rightful place */
159 uint position = 0; // Place to put next child relative to origin of the container.
160 auto assign_position = [&](const std::unique_ptr<NWidgetBase> &child_wid) {
161 if (child_wid->current_x != 0) {
162 child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl);
163 position += child_wid->current_x;
164 }
165 };
166
167 if (rtl) {
168 std::for_each(std::rbegin(this->children), std::rend(this->children), assign_position);
169 } else {
170 std::for_each(std::begin(this->children), std::end(this->children), assign_position);
171 }
172 }
173};
174
175class NetworkGameWindow : public Window {
176protected:
177 /* Runtime saved values */
178 static Listing last_sorting;
179
180 /* Constants for sorting servers */
181 static const std::initializer_list<GUIGameServerList::SortFunction * const> sorter_funcs;
182 static const std::initializer_list<GUIGameServerList::FilterFunction * const> filter_funcs;
183
184 NetworkGame *server = nullptr;
187 ServerListPosition list_pos = SLP_INVALID;
188 Scrollbar *vscroll = nullptr;
191 bool searched_internet = false;
192
193 Dimension lock{};
195
202 {
203 if (!this->servers.NeedRebuild()) return;
204
205 /* Create temporary array of games to use for listing */
206 this->servers.clear();
207
208 bool found_current_server = false;
209 bool found_last_joined = false;
210 for (const auto &ngl : _network_game_list) {
211 this->servers.push_back(ngl.get());
212 if (ngl.get() == this->server) {
213 found_current_server = true;
214 }
215 if (ngl.get() == this->last_joined) {
216 found_last_joined = true;
217 }
218 }
219 /* A refresh can cause the current server to be delete; so unselect. */
220 if (!found_last_joined) {
221 this->last_joined = nullptr;
222 }
223 if (!found_current_server) {
224 this->server = nullptr;
225 this->list_pos = SLP_INVALID;
226 }
227
228 /* Apply the filter condition immediately, if a search string has been provided. */
229 StringFilter sf;
230 sf.SetFilterTerm(this->filter_editbox.text.GetText());
231
232 if (!sf.IsEmpty()) {
233 this->servers.SetFilterState(true);
234 this->servers.Filter(sf);
235 } else {
236 this->servers.SetFilterState(false);
237 }
238
239 this->servers.RebuildDone();
240 this->vscroll->SetCount(this->servers.size());
241
242 /* Sort the list of network games as requested. */
243 this->servers.Sort();
244 this->UpdateListPos();
245 }
246
248 static bool NGameNameSorter(NetworkGame * const &a, NetworkGame * const &b)
249 {
250 int r = StrNaturalCompare(a->info.server_name, b->info.server_name, true); // Sort by name (natural sorting).
251 if (r == 0) r = a->connection_string.compare(b->connection_string);
252
253 return r < 0;
254 }
255
261 static bool NGameClientSorter(NetworkGame * const &a, NetworkGame * const &b)
262 {
263 /* Reverse as per default we are interested in most-clients first */
264 int r = a->info.clients_on - b->info.clients_on;
265
266 if (r == 0) r = a->info.clients_max - b->info.clients_max;
267 if (r == 0) return NGameNameSorter(a, b);
268
269 return r < 0;
270 }
271
273 static bool NGameMapSizeSorter(NetworkGame * const &a, NetworkGame * const &b)
274 {
275 /* Sort by the area of the map. */
276 int r = (a->info.map_height) * (a->info.map_width) - (b->info.map_height) * (b->info.map_width);
277
278 if (r == 0) r = a->info.map_width - b->info.map_width;
279 return (r != 0) ? r < 0 : NGameClientSorter(a, b);
280 }
281
283 static bool NGameCalendarDateSorter(NetworkGame * const &a, NetworkGame * const &b)
284 {
285 auto r = a->info.calendar_date - b->info.calendar_date;
286 return (r != 0) ? r < 0 : NGameClientSorter(a, b);
287 }
288
290 static bool NGameTicksPlayingSorter(NetworkGame * const &a, NetworkGame * const &b)
291 {
292 if (a->info.ticks_playing == b->info.ticks_playing) {
293 return NGameClientSorter(a, b);
294 }
295 return a->info.ticks_playing < b->info.ticks_playing;
296 }
297
302 static bool NGameAllowedSorter(NetworkGame * const &a, NetworkGame * const &b)
303 {
304 /* The servers we do not know anything about (the ones that did not reply) should be at the bottom) */
305 int r = a->info.server_revision.empty() - b->info.server_revision.empty();
306
307 /* Reverse default as we are interested in version-compatible clients first */
308 if (r == 0) r = b->info.version_compatible - a->info.version_compatible;
309 /* The version-compatible ones are then sorted with NewGRF compatible first, incompatible last */
310 if (r == 0) r = b->info.compatible - a->info.compatible;
311 /* Passworded servers should be below unpassworded servers */
312 if (r == 0) r = a->info.use_password - b->info.use_password;
313
314 /* Finally sort on the number of clients of the server in reverse order. */
315 return (r != 0) ? r < 0 : NGameClientSorter(b, a);
316 }
317
320 {
321 if (this->servers.Sort()) this->UpdateListPos();
322 }
323
326 {
327 auto it = std::ranges::find(this->servers, this->server);
328 if (it == std::end(this->servers)) {
329 this->list_pos = SLP_INVALID;
330 } else {
331 this->list_pos = static_cast<ServerListPosition>(std::distance(std::begin(this->servers), it));
332 }
333 }
334
335 static bool NGameSearchFilter(NetworkGame * const *item, StringFilter &sf)
336 {
337 assert(item != nullptr);
338 assert((*item) != nullptr);
339
340 sf.ResetState();
341 sf.AddLine((*item)->info.server_name);
342 return sf.GetState();
343 }
344
351 void DrawServerLine(const NetworkGame *cur_item, int y, bool highlight) const
352 {
353 Rect name = this->GetWidget<NWidgetBase>(WID_NG_NAME)->GetCurrentRect();
354 Rect info = this->GetWidget<NWidgetBase>(WID_NG_INFO)->GetCurrentRect();
355
356 /* show highlighted item with a different colour */
357 if (highlight) {
358 Rect r = {std::min(name.left, info.left), y, std::max(name.right, info.right), y + (int)this->resize.step_height - 1};
360 }
361
362 /* Offset to vertically position text. */
364
365 info = info.Shrink(WidgetDimensions::scaled.framerect);
366 name = name.Shrink(WidgetDimensions::scaled.framerect);
367 DrawString(name.left, name.right, y + text_y_offset, cur_item->info.server_name, TC_BLACK);
368
369 /* only draw details if the server is online */
370 if (cur_item->status == NGLS_ONLINE) {
371 if (const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(WID_NG_CLIENTS); nwid->current_x != 0) {
372 Rect clients = nwid->GetCurrentRect();
373 DrawString(clients.left, clients.right, y + text_y_offset,
374 GetString(STR_NETWORK_SERVER_LIST_GENERAL_ONLINE, cur_item->info.clients_on, cur_item->info.clients_max, cur_item->info.companies_on, cur_item->info.companies_max),
375 TC_FROMSTRING, SA_HOR_CENTER);
376 }
377
378 if (const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(WID_NG_MAPSIZE); nwid->current_x != 0) {
379 /* map size */
380 Rect mapsize = nwid->GetCurrentRect();
381 DrawString(mapsize.left, mapsize.right, y + text_y_offset,
382 GetString(STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT, cur_item->info.map_width, cur_item->info.map_height),
383 TC_FROMSTRING, SA_HOR_CENTER);
384 }
385
386 if (const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(WID_NG_DATE); nwid->current_x != 0) {
387 /* current date */
388 Rect date = nwid->GetCurrentRect();
389 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(cur_item->info.calendar_date);
390 DrawString(date.left, date.right, y + text_y_offset,
391 GetString(STR_JUST_INT, ymd.year),
392 TC_BLACK, SA_HOR_CENTER);
393 }
394
395 if (const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(WID_NG_YEARS); nwid->current_x != 0) {
396 /* play time */
397 Rect years = nwid->GetCurrentRect();
398 const auto play_time = cur_item->info.ticks_playing / Ticks::TICKS_PER_SECOND;
399 DrawString(years.left, years.right, y + text_y_offset,
400 GetString(STR_NETWORK_SERVER_LIST_PLAY_TIME_SHORT, play_time / 60 / 60, (play_time / 60) % 60),
401 TC_BLACK, SA_HOR_CENTER);
402 }
403
404 /* Set top and bottom of info rect to current row. */
405 info.top = y;
406 info.bottom = y + this->resize.step_height - 1;
407
408 bool rtl = _current_text_dir == TD_RTL;
409
410 /* draw a lock if the server is password protected */
411 if (cur_item->info.use_password) DrawSpriteIgnorePadding(SPR_LOCK, PAL_NONE, info.WithWidth(this->lock.width, rtl), SA_CENTER);
412
413 /* draw red or green icon, depending on compatibility with server */
414 PaletteID pal = cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED);
415 DrawSpriteIgnorePadding(SPR_BLOT, pal, info.WithWidth(this->blot.width, !rtl), SA_CENTER);
416 }
417 }
418
427 {
428 if (this->list_pos == SLP_INVALID) return; // no server selected
429 this->vscroll->ScrollTowards(this->list_pos);
430 }
431
432public:
434 {
435 this->CreateNestedTree();
436 this->vscroll = this->GetScrollbar(WID_NG_SCROLLBAR);
438
440 this->name_editbox.text.Assign(_settings_client.network.client_name);
441
443 this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
445
446 /* As the Game Coordinator doesn't support "websocket" servers yet, we
447 * let "os/emscripten/pre.js" hardcode a list of servers people can
448 * join. This means the serverlist is curated for now, but it is the
449 * best we can offer. */
450#ifdef __EMSCRIPTEN__
451 EM_ASM(if (window["openttd_server_list"]) openttd_server_list());
452#endif
453
454 this->last_joined = NetworkAddServer(_settings_client.network.last_joined, false);
455 this->server = this->last_joined;
456
457 this->servers.SetListing(this->last_sorting);
458 this->servers.SetSortFuncs(NetworkGameWindow::sorter_funcs);
459 this->servers.SetFilterFuncs(NetworkGameWindow::filter_funcs);
460 this->servers.ForceRebuild();
461 }
462
464 {
465 this->last_sorting = this->servers.GetListing();
466 }
467
468 void OnInit() override
469 {
470 this->lock = GetScaledSpriteSize(SPR_LOCK);
471 this->blot = GetScaledSpriteSize(SPR_BLOT);
472 }
473
474 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
475 {
476 switch (widget) {
477 case WID_NG_MATRIX:
478 resize.height = std::max(GetSpriteSize(SPR_BLOT).height, (uint)GetCharacterHeight(FS_NORMAL)) + padding.height;
479 fill.height = resize.height;
480 size.height = 12 * resize.height;
481 break;
482
484 size.height = std::max(GetSpriteSize(SPR_BLOT).height, (uint)GetCharacterHeight(FS_NORMAL)) + WidgetDimensions::scaled.matrix.Vertical();
485 break;
486
488 size.width = NWidgetScrollbar::GetVerticalDimension().width;
489 break;
490
491 case WID_NG_NAME:
492 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
493 break;
494
495 case WID_NG_CLIENTS: {
496 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
497 auto max_clients = GetParamMaxValue(MAX_CLIENTS);
498 auto max_companies = GetParamMaxValue(MAX_COMPANIES);
499 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_SERVER_LIST_GENERAL_ONLINE, max_clients, max_clients, max_companies, max_companies)));
500 break;
501 }
502
503 case WID_NG_MAPSIZE: {
504 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
505 auto max_map_size = GetParamMaxValue(0, MAX_MAP_SIZE);
506 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT, max_map_size, max_map_size)));
507 break;
508 }
509
510 case WID_NG_DATE:
511 case WID_NG_YEARS:
512 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
513 size = maxdim(size, GetStringBoundingBox(GetString(STR_JUST_INT, GetParamMaxValue(5))));
514 break;
515
516 case WID_NG_INFO:
517 size.width = this->lock.width + WidgetDimensions::scaled.hsep_normal + this->blot.width + padding.width;
518 size.height = std::max(this->lock.height, this->blot.height) + padding.height;
519 break;
520 }
521 }
522
523 void DrawWidget(const Rect &r, WidgetID widget) const override
524 {
525 switch (widget) {
526 case WID_NG_MATRIX: {
527 uint16_t y = r.top;
528
529 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->servers);
530 for (auto it = first; it != last; ++it) {
531 const NetworkGame *ngl = *it;
532 this->DrawServerLine(ngl, y, ngl == this->server);
533 y += this->resize.step_height;
534 }
535 break;
536 }
537
539 /* Draw the last joined server, if any */
540 if (this->last_joined != nullptr) this->DrawServerLine(this->last_joined, r.top, this->last_joined == this->server);
541 break;
542
543 case WID_NG_DETAILS:
544 this->DrawDetails(r);
545 break;
546
547 case WID_NG_NAME:
548 case WID_NG_CLIENTS:
549 case WID_NG_MAPSIZE:
550 case WID_NG_DATE:
551 case WID_NG_YEARS:
552 case WID_NG_INFO:
553 if (widget - WID_NG_NAME == this->servers.SortType()) this->DrawSortButtonState(widget, this->servers.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
554 break;
555 }
556 }
557
558
559 void OnPaint() override
560 {
561 if (this->servers.NeedRebuild()) {
563 }
564 if (this->servers.NeedResort()) {
565 this->SortNetworkGameList();
566 }
567
568 NetworkGame *sel = this->server;
569 /* 'Refresh' button invisible if no server selected */
570 this->SetWidgetDisabledState(WID_NG_REFRESH, sel == nullptr);
571 /* 'Join' button disabling conditions */
572 this->SetWidgetDisabledState(WID_NG_JOIN, sel == nullptr || // no Selected Server
573 sel->status != NGLS_ONLINE || // Server offline
574 sel->info.clients_on >= sel->info.clients_max || // Server full
575 !sel->info.compatible); // Revision mismatch
576
577 this->SetWidgetLoweredState(WID_NG_REFRESH, sel != nullptr && sel->refreshing);
578
579 /* 'NewGRF Settings' button invisible if no NewGRF is used */
580 bool changed = false;
581 changed |= this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == nullptr || sel->status != NGLS_ONLINE || sel->info.grfconfig.empty() ? SZSP_NONE : 0);
582 changed |= this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_MISSING_SEL)->SetDisplayedPlane(sel == nullptr || sel->status != NGLS_ONLINE || sel->info.grfconfig.empty() || !sel->info.version_compatible || sel->info.compatible ? SZSP_NONE : 0);
583 if (changed) {
584 this->ReInit();
585 return;
586 }
587
588#ifdef __EMSCRIPTEN__
593#endif
594
595 this->DrawWidgets();
596 }
597
598 StringID GetHeaderString() const
599 {
600 if (this->server == nullptr) return STR_NETWORK_SERVER_LIST_GAME_INFO;
601 switch (this->server->status) {
602 case NGLS_OFFLINE: return STR_NETWORK_SERVER_LIST_SERVER_OFFLINE;
603 case NGLS_ONLINE: return STR_NETWORK_SERVER_LIST_GAME_INFO;
604 case NGLS_FULL: return STR_NETWORK_SERVER_LIST_SERVER_FULL;
605 case NGLS_BANNED: return STR_NETWORK_SERVER_LIST_SERVER_BANNED;
606 case NGLS_TOO_OLD: return STR_NETWORK_SERVER_LIST_SERVER_TOO_OLD;
607 default: NOT_REACHED();
608 }
609 }
610
611 void DrawDetails(const Rect &r) const
612 {
613 NetworkGame *sel = this->server;
614
615 Rect tr = r.Shrink(WidgetDimensions::scaled.frametext);
616 StringID header_msg = this->GetHeaderString();
617 int header_height = GetStringHeight(header_msg, tr.Width()) +
618 (sel == nullptr ? 0 : GetStringHeight(sel->info.server_name, tr.Width())) +
619 WidgetDimensions::scaled.frametext.Vertical();
620
621 /* Height for the title banner */
622 Rect hr = r.WithHeight(header_height).Shrink(WidgetDimensions::scaled.frametext);
623 tr.top += header_height;
624
625 /* Draw the right menu */
626 /* Create the nice grayish rectangle at the details top */
628 hr.top = DrawStringMultiLine(hr, header_msg, TC_FROMSTRING, SA_HOR_CENTER);
629 if (sel == nullptr) return;
630
631 hr.top = DrawStringMultiLine(hr, sel->info.server_name, TC_ORANGE, SA_HOR_CENTER); // game name
632 if (sel->status != NGLS_ONLINE) {
633 tr.top = DrawStringMultiLine(tr, header_msg, TC_FROMSTRING, SA_HOR_CENTER);
634 } else { // show game info
635 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_CLIENTS, sel->info.clients_on, sel->info.clients_max, sel->info.companies_on, sel->info.companies_max));
636
637 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_LANDSCAPE, STR_CLIMATE_TEMPERATE_LANDSCAPE + to_underlying(sel->info.landscape))); // landscape
638
639 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_MAP_SIZE, sel->info.map_width, sel->info.map_height)); // map size
640
641 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_SERVER_VERSION, sel->info.server_revision)); // server version
642
643 StringID invite_or_address = sel->connection_string.starts_with("+") ? STR_NETWORK_SERVER_LIST_INVITE_CODE : STR_NETWORK_SERVER_LIST_SERVER_ADDRESS;
644 tr.top = DrawStringMultiLine(tr, GetString(invite_or_address, sel->connection_string)); // server address / invite code
645
646 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_START_DATE, sel->info.calendar_start)); // start date
647
648 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_CURRENT_DATE, sel->info.calendar_date)); // current date
649
650 const auto play_time = sel->info.ticks_playing / Ticks::TICKS_PER_SECOND;
651 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_PLAY_TIME, play_time / 60 / 60, (play_time / 60) % 60)); // play time
652
653 if (sel->info.gamescript_version != -1) {
654 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_GAMESCRIPT, sel->info.gamescript_name, sel->info.gamescript_version)); // gamescript name and version
655 }
656
658
659 if (!sel->info.compatible) {
660 DrawStringMultiLine(tr, sel->info.version_compatible ? STR_NETWORK_SERVER_LIST_GRF_MISMATCH : STR_NETWORK_SERVER_LIST_VERSION_MISMATCH, TC_FROMSTRING, SA_HOR_CENTER); // server mismatch
661 } else if (sel->info.clients_on == sel->info.clients_max) {
662 /* Show: server full, when clients_on == max_clients */
663 DrawStringMultiLine(tr, STR_NETWORK_SERVER_LIST_SERVER_FULL, TC_FROMSTRING, SA_HOR_CENTER); // server full
664 } else if (sel->info.use_password) {
665 DrawStringMultiLine(tr, STR_NETWORK_SERVER_LIST_PASSWORD, TC_FROMSTRING, SA_HOR_CENTER); // password warning
666 }
667 }
668 }
669
670 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
671 {
672 switch (widget) {
673 case WID_NG_CANCEL: // Cancel button
675 break;
676
677 case WID_NG_NAME: // Sort by name
678 case WID_NG_CLIENTS: // Sort by connected clients
679 case WID_NG_MAPSIZE: // Sort by map size
680 case WID_NG_DATE: // Sort by date
681 case WID_NG_YEARS: // Sort by years
682 case WID_NG_INFO: // Connectivity (green dot)
683 if (this->servers.SortType() == widget - WID_NG_NAME) {
684 this->servers.ToggleSortOrder();
685 if (this->list_pos != SLP_INVALID) this->list_pos = (ServerListPosition)this->servers.size() - this->list_pos - 1;
686 } else {
687 this->servers.SetSortType(widget - WID_NG_NAME);
688 this->servers.ForceResort();
689 this->SortNetworkGameList();
690 }
692 this->SetDirty();
693 break;
694
695 case WID_NG_MATRIX: { // Show available network games
696 auto it = this->vscroll->GetScrolledItemFromWidget(this->servers, pt.y, this, WID_NG_MATRIX);
697 this->server = (it != this->servers.end()) ? *it : nullptr;
698 this->list_pos = (server == nullptr) ? SLP_INVALID : it - this->servers.begin();
699 this->SetDirty();
700
701 if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
702 break;
703 }
704
705 case WID_NG_LASTJOINED: {
706 if (this->last_joined != nullptr) {
707 this->server = this->last_joined;
708
709 /* search the position of the newly selected server */
710 this->UpdateListPos();
712 this->SetDirty();
713
714 if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
715 }
716 break;
717 }
718
721 this->searched_internet = true;
722 break;
723
726 break;
727
728 case WID_NG_ADD: // Add a server
731 STR_NETWORK_SERVER_LIST_ENTER_SERVER_ADDRESS,
732 NETWORK_HOSTNAME_PORT_LENGTH, // maximum number of characters including '\0'
734 break;
735
736 case WID_NG_START: // Start server
737 ShowNetworkStartServerWindow();
738 break;
739
740 case WID_NG_JOIN: // Join Game
741 if (this->server != nullptr) {
743 }
744 break;
745
746 case WID_NG_REFRESH: // Refresh
747 if (this->server != nullptr && !this->server->refreshing) NetworkQueryServer(this->server->connection_string);
748 break;
749
750 case WID_NG_NEWGRF: // NewGRF Settings
751 if (this->server != nullptr) ShowNewGRFSettings(false, false, false, this->server->info.grfconfig);
752 break;
753
754 case WID_NG_NEWGRF_MISSING: // Find missing content online
755 if (this->server != nullptr) ShowMissingContentWindow(this->server->info.grfconfig);
756 break;
757 }
758 }
759
765 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
766 {
767 this->servers.ForceRebuild();
768 this->SetDirty();
769 }
770
771 EventState OnKeyPress([[maybe_unused]] char32_t key, uint16_t keycode) override
772 {
774
775 /* handle up, down, pageup, pagedown, home and end */
776 if (this->vscroll->UpdateListPositionOnKeyPress(this->list_pos, keycode) == ES_HANDLED) {
777 if (this->list_pos == SLP_INVALID) return ES_HANDLED;
778
779 this->server = this->servers[this->list_pos];
780
781 /* Scroll to the new server if it is outside the current range. */
783
784 /* redraw window */
785 this->SetDirty();
786 return ES_HANDLED;
787 }
788
789 if (this->server != nullptr) {
790 if (keycode == WKC_DELETE) { // Press 'delete' to remove servers
791 NetworkGameListRemoveItem(this->server);
792 if (this->server == this->last_joined) this->last_joined = nullptr;
793 this->server = nullptr;
794 this->list_pos = SLP_INVALID;
795 }
796 }
797
798 return state;
799 }
800
801 void OnEditboxChanged(WidgetID wid) override
802 {
803 switch (wid) {
804 case WID_NG_FILTER: {
805 this->servers.ForceRebuild();
808 this->SetDirty();
809 break;
810 }
811
812 case WID_NG_CLIENT:
813 /* Validation of the name will happen once the user tries to join or start a game, as getting
814 * error messages while typing (e.g. when you clear the name) defeats the purpose of the check. */
815 _settings_client.network.client_name = this->name_editbox.text.GetText();
816 break;
817 }
818 }
819
820 void OnQueryTextFinished(std::optional<std::string> str) override
821 {
822 if (!str.has_value() || str->empty()) return;
823
824 _settings_client.network.connect_to_ip = std::move(*str);
826 NetworkRebuildHostList();
827 }
828
829 void OnResize() override
830 {
831 this->vscroll->SetCapacityFromWidget(this, WID_NG_MATRIX);
832 }
833
835 IntervalTimer<TimerWindow> refresh_interval = {std::chrono::seconds(30), [this](uint) {
836 if (!this->searched_internet) return;
837
839 }};
840};
841
842Listing NetworkGameWindow::last_sorting = {false, 5};
843const std::initializer_list<GUIGameServerList::SortFunction * const> NetworkGameWindow::sorter_funcs = {
844 &NGameNameSorter,
845 &NGameClientSorter,
846 &NGameMapSizeSorter,
847 &NGameCalendarDateSorter,
848 &NGameTicksPlayingSorter,
849 &NGameAllowedSorter
850};
851
852const std::initializer_list<GUIGameServerList::FilterFunction * const> NetworkGameWindow::filter_funcs = {
853 &NGameSearchFilter
854};
855
856static std::unique_ptr<NWidgetBase> MakeResizableHeader()
857{
858 return std::make_unique<NWidgetServerListHeader>();
859}
860
861static constexpr NWidgetPart _nested_network_game_widgets[] = {
862 /* TOP */
864 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
865 NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetStringTip(STR_NETWORK_SERVER_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
866 NWidget(WWT_DEFSIZEBOX, COLOUR_LIGHT_BLUE),
867 EndContainer(),
868 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_MAIN),
871 /* LEFT SIDE */
874 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NG_FILTER_LABEL), SetStringTip(STR_LIST_FILTER_TITLE),
875 NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_FILTER), SetMinimalSize(251, 0), SetFill(1, 0), SetResize(1, 0),
876 SetStringTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
877 EndContainer(),
880 NWidgetFunction(MakeResizableHeader),
881 NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NG_MATRIX), SetResize(1, 1), SetFill(1, 0),
882 SetMatrixDataTip(1, 0, STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT), SetScrollbar(WID_NG_SCROLLBAR),
883 EndContainer(),
884 NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NG_SCROLLBAR),
885 EndContainer(),
887 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NG_LASTJOINED_LABEL), SetFill(1, 0),
888 SetStringTip(STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER), SetResize(1, 0),
890 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_LASTJOINED), SetFill(1, 0), SetResize(1, 0),
891 SetToolTip(STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST_TOOLTIP),
892 EndContainer(),
893 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NG_LASTJOINED_SPACER), SetFill(0, 0),
894 EndContainer(),
895 EndContainer(),
896 EndContainer(),
897 /* RIGHT SIDE */
900 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NG_CLIENT_LABEL), SetStringTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME),
901 NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_CLIENT), SetMinimalSize(151, 0), SetFill(1, 0), SetResize(1, 0),
902 SetStringTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE, STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP),
903 EndContainer(),
905 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_DETAILS), SetMinimalSize(140, 0), SetMinimalTextLines(15, 0), SetResize(0, 1),
906 EndContainer(),
909 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NEWGRF_MISSING), SetFill(1, 0), SetStringTip(STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON, STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP),
910 EndContainer(),
911 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NG_NEWGRF_SEL),
912 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NEWGRF), SetFill(1, 0), SetStringTip(STR_INTRO_NEWGRF_SETTINGS),
913 EndContainer(),
915 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_JOIN), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_JOIN_GAME),
916 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_REFRESH), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_REFRESH, STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP),
917 EndContainer(),
918 EndContainer(),
919 EndContainer(),
920 EndContainer(),
921 EndContainer(),
922 /* BOTTOM */
924 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_SEARCH_INTERNET), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET, STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP),
925 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_SEARCH_LAN), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN, STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP),
926 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_ADD), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_ADD_SERVER, STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP),
927 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_START), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_START_SERVER, STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP),
928 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CANCEL), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_BUTTON_CANCEL),
929 EndContainer(),
930 EndContainer(),
931 /* Resize button. */
933 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
934 NWidget(WWT_RESIZEBOX, COLOUR_LIGHT_BLUE), SetResizeWidgetTypeTip(RWV_HIDE_BEVEL, STR_TOOLTIP_RESIZE),
935 EndContainer(),
936 EndContainer(),
937};
938
939static WindowDesc _network_game_window_desc(
940 WDP_CENTER, "list_servers", 1000, 730,
942 {},
943 _nested_network_game_widgets
944);
945
946void ShowNetworkGameWindow()
947{
948 static bool first = true;
950
951 /* Only show once */
952 if (first) {
953 first = false;
954 /* Add all servers from the config file to our list. */
955 for (const auto &iter : _network_host_list) {
956 NetworkAddServer(iter);
957 }
958 }
959
960 new NetworkGameWindow(_network_game_window_desc);
961}
962
966
968 {
970
972 this->name_editbox.text.Assign(_settings_client.network.server_name);
973
975 }
976
977 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
978 {
979 switch (widget) {
981 return GetString(STR_NETWORK_SERVER_VISIBILITY_LOCAL + _settings_client.network.server_game_type);
982
984 return GetString(STR_NETWORK_START_SERVER_CLIENTS_SELECT, _settings_client.network.max_clients);
985
987 return GetString(STR_NETWORK_START_SERVER_COMPANIES_SELECT, _settings_client.network.max_companies);
988
989 default:
990 return this->Window::GetWidgetString(widget, stringid);
991 }
992 }
993
994 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
995 {
996 switch (widget) {
998 size = maxdim(maxdim(GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_LOCAL), GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_PUBLIC)), GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_INVITE_ONLY));
999 size.width += padding.width;
1000 size.height += padding.height;
1001 break;
1002 }
1003 }
1004
1005 void DrawWidget(const Rect &r, WidgetID widget) const override
1006 {
1007 switch (widget) {
1008 case WID_NSS_SETPWD:
1009 /* If password is set, draw red '*' next to 'Set password' button. */
1010 if (!_settings_client.network.server_password.empty()) DrawString(r.right + WidgetDimensions::scaled.framerect.left, this->width - WidgetDimensions::scaled.framerect.right, r.top, "*", TC_RED);
1011 }
1012 }
1013
1014 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1015 {
1016 switch (widget) {
1017 case WID_NSS_CANCEL: // Cancel button
1018 ShowNetworkGameWindow();
1019 break;
1020
1021 case WID_NSS_SETPWD: // Set password button
1022 this->widget_id = WID_NSS_SETPWD;
1023 ShowQueryString(_settings_client.network.server_password, STR_NETWORK_START_SERVER_SET_PASSWORD, NETWORK_PASSWORD_LENGTH, this, CS_ALPHANUMERAL, {});
1024 break;
1025
1026 case WID_NSS_CONNTYPE_BTN: // Connection type
1027 ShowDropDownList(this, BuildVisibilityDropDownList(), _settings_client.network.server_game_type, WID_NSS_CONNTYPE_BTN);
1028 break;
1029
1030 case WID_NSS_CLIENTS_BTND: case WID_NSS_CLIENTS_BTNU: // Click on up/down button for number of clients
1031 case WID_NSS_COMPANIES_BTND: case WID_NSS_COMPANIES_BTNU: // Click on up/down button for number of companies
1032 /* Don't allow too fast scrolling. */
1033 if (!this->flags.Test(WindowFlag::Timeout) || this->timeout_timer <= 1) {
1034 this->HandleButtonClick(widget);
1035 this->SetDirty();
1036 switch (widget) {
1037 default: NOT_REACHED();
1040 break;
1043 break;
1044 }
1045 }
1046 _left_button_clicked = false;
1047 break;
1048
1049 case WID_NSS_CLIENTS_TXT: // Click on number of clients
1051 ShowQueryString(GetString(STR_JUST_INT, _settings_client.network.max_clients), STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS, 4, this, CS_NUMERAL, {});
1052 break;
1053
1054 case WID_NSS_COMPANIES_TXT: // Click on number of companies
1056 ShowQueryString(GetString(STR_JUST_INT, _settings_client.network.max_companies), STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES, 3, this, CS_NUMERAL, {});
1057 break;
1058
1059 case WID_NSS_GENERATE_GAME: // Start game
1060 if (!CheckServerName()) return;
1061 _is_network_server = true;
1062 if (_ctrl_pressed) {
1064 } else {
1066 }
1067 break;
1068
1069 case WID_NSS_LOAD_GAME:
1070 if (!CheckServerName()) return;
1071 _is_network_server = true;
1073 break;
1074
1076 if (!CheckServerName()) return;
1077 _is_network_server = true;
1079 break;
1080
1082 if (!CheckServerName()) return;
1083 _is_network_server = true;
1085 break;
1086 }
1087 }
1088
1089 void OnDropdownSelect(WidgetID widget, int index) override
1090 {
1091 switch (widget) {
1094 break;
1095 default:
1096 NOT_REACHED();
1097 }
1098
1099 this->SetDirty();
1100 }
1101
1102 bool CheckServerName()
1103 {
1104 std::string str = this->name_editbox.text.GetText();
1105 if (!NetworkValidateServerName(str)) return false;
1106
1107 SetSettingValue(GetSettingFromName("network.server_name")->AsStringSetting(), std::move(str));
1108 return true;
1109 }
1110
1115
1116 void OnQueryTextFinished(std::optional<std::string> str) override
1117 {
1118 if (!str.has_value()) return;
1119
1120 if (this->widget_id == WID_NSS_SETPWD) {
1121 _settings_client.network.server_password = std::move(*str);
1122 } else {
1123 int32_t value = atoi(str->c_str());
1124 this->SetWidgetDirty(this->widget_id);
1125 switch (this->widget_id) {
1126 default: NOT_REACHED();
1128 case WID_NSS_COMPANIES_TXT: _settings_client.network.max_companies = Clamp(value, 1, MAX_COMPANIES); break;
1129 }
1130 }
1131
1132 this->SetDirty();
1133 }
1134};
1135
1136static constexpr NWidgetPart _nested_network_start_server_window_widgets[] = {
1138 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
1139 NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetStringTip(STR_NETWORK_START_SERVER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1140 EndContainer(),
1141 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NSS_BACKGROUND),
1145 /* Game name widgets */
1146 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NSS_GAMENAME_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME),
1147 NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NSS_GAMENAME), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE, STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP),
1148 EndContainer(),
1149
1152 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NSS_CONNTYPE_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_VISIBILITY_LABEL),
1153 NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_BTN), SetFill(1, 0), SetToolTip(STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP),
1154 EndContainer(),
1156 NWidget(NWID_SPACER), SetFill(1, 1),
1157 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_SETPWD), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_SET_PASSWORD, STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP),
1158 EndContainer(),
1159 EndContainer(),
1160
1163 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NSS_CLIENTS_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS),
1165 NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_BTND), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON), SetFill(0, 1), SetSpriteTip(SPR_ARROW_DOWN, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
1166 NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_TXT), SetFill(1, 0), SetToolTip(STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
1167 NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_BTNU), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON), SetFill(0, 1), SetSpriteTip(SPR_ARROW_UP, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
1168 EndContainer(),
1169 EndContainer(),
1170
1172 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NSS_COMPANIES_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES),
1174 NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_BTND), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON), SetFill(0, 1), SetSpriteTip(SPR_ARROW_DOWN, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
1175 NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_TXT), SetFill(1, 0), SetToolTip(STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
1176 NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_BTNU), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON), SetFill(0, 1), SetSpriteTip(SPR_ARROW_UP, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
1177 EndContainer(),
1178 EndContainer(),
1179 EndContainer(),
1180 EndContainer(),
1181
1183 /* 'generate game' and 'load game' buttons */
1185 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_GENERATE_GAME), SetStringTip(STR_INTRO_NEW_GAME, STR_INTRO_TOOLTIP_NEW_GAME), SetFill(1, 0),
1186 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_LOAD_GAME), SetStringTip(STR_INTRO_LOAD_GAME, STR_INTRO_TOOLTIP_LOAD_GAME), SetFill(1, 0),
1187 EndContainer(),
1188
1189 /* 'play scenario' and 'play heightmap' buttons */
1191 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_PLAY_SCENARIO), SetStringTip(STR_INTRO_PLAY_SCENARIO, STR_INTRO_TOOLTIP_PLAY_SCENARIO), SetFill(1, 0),
1192 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_PLAY_HEIGHTMAP), SetStringTip(STR_INTRO_PLAY_HEIGHTMAP, STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP), SetFill(1, 0),
1193 EndContainer(),
1194 EndContainer(),
1195
1197 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_CANCEL), SetStringTip(STR_BUTTON_CANCEL), SetMinimalSize(128, 12),
1198 EndContainer(),
1199 EndContainer(),
1200 EndContainer(),
1201};
1202
1203static WindowDesc _network_start_server_window_desc(
1204 WDP_CENTER, nullptr, 0, 0,
1206 {},
1207 _nested_network_start_server_window_widgets
1208);
1209
1210static void ShowNetworkStartServerWindow()
1211{
1212 if (!NetworkValidateOurClientName()) return;
1213
1215
1216 new NetworkStartServerWindow(_network_start_server_window_desc);
1217}
1218
1219/* The window below gives information about the connected clients
1220 * and also makes able to kick them (if server) and stuff like that. */
1221
1222extern void DrawCompanyIcon(CompanyID cid, int x, int y);
1223
1224static constexpr NWidgetPart _nested_client_list_widgets[] = {
1226 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1227 NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_NETWORK_CLIENT_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1228 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
1229 NWidget(WWT_STICKYBOX, COLOUR_GREY),
1230 EndContainer(),
1231 NWidget(WWT_PANEL, COLOUR_GREY),
1233 NWidget(WWT_FRAME, COLOUR_GREY), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0),
1235 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_NAME),
1236 NWidget(WWT_TEXT, INVALID_COLOUR, WID_CL_SERVER_NAME), SetFill(1, 0), SetResize(1, 0), SetToolTip(STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1237 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_CL_SERVER_NAME_EDIT), SetAspect(WidgetDimensions::ASPECT_RENAME), SetSpriteTip(SPR_RENAME, STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP),
1238 EndContainer(),
1242 NWidget(WWT_TEXT, INVALID_COLOUR), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY),
1243 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_CL_SERVER_VISIBILITY), SetToolTip(STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP),
1244 EndContainer(),
1246 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_INVITE_CODE),
1247 NWidget(WWT_TEXT, INVALID_COLOUR, WID_CL_SERVER_INVITE_CODE), SetFill(1, 0), SetResize(1, 0), SetToolTip(STR_NETWORK_CLIENT_LIST_SERVER_INVITE_CODE_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1248 EndContainer(),
1250 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE),
1251 NWidget(WWT_TEXT, INVALID_COLOUR, WID_CL_SERVER_CONNECTION_TYPE), SetFill(1, 0), SetResize(1, 0), SetToolTip(STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1252 EndContainer(),
1253 EndContainer(),
1254 EndContainer(),
1255 EndContainer(),
1256 NWidget(WWT_FRAME, COLOUR_GREY), SetStringTip(STR_NETWORK_CLIENT_LIST_PLAYER),
1258 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_NETWORK_CLIENT_LIST_PLAYER_NAME),
1259 NWidget(WWT_TEXT, INVALID_COLOUR, WID_CL_CLIENT_NAME), SetFill(1, 0), SetResize(1, 0), SetToolTip(STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1260 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_CL_CLIENT_NAME_EDIT), SetAspect(WidgetDimensions::ASPECT_RENAME), SetSpriteTip(SPR_RENAME, STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP),
1261 EndContainer(),
1262 EndContainer(),
1263 EndContainer(),
1264 EndContainer(),
1268 EndContainer(),
1270 NWidget(WWT_PANEL, COLOUR_GREY),
1271 NWidget(WWT_TEXT, INVALID_COLOUR, WID_CL_CLIENT_COMPANY_COUNT), SetFill(1, 0), SetResize(1, 0), SetPadding(WidgetDimensions::unscaled.framerect), SetAlignment(SA_CENTER), SetToolTip(STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT_TOOLTIP),
1272 EndContainer(),
1273 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
1274 EndContainer(),
1275};
1276
1277static WindowDesc _client_list_desc(
1278 WDP_AUTO, "list_clients", 220, 300,
1280 {},
1281 _nested_client_list_widgets
1282);
1283
1288enum DropDownAdmin : uint8_t {
1289 DD_CLIENT_ADMIN_KICK,
1290 DD_CLIENT_ADMIN_BAN,
1291 DD_COMPANY_ADMIN_RESET,
1292};
1293
1298static void AdminClientKickCallback(Window *, bool confirmed)
1299{
1300 if (confirmed) NetworkServerKickClient(_admin_client_id, {});
1301}
1302
1307static void AdminClientBanCallback(Window *, bool confirmed)
1308{
1309 if (confirmed) NetworkServerKickOrBanIP(_admin_client_id, true, {});
1310}
1311
1316static void AdminCompanyResetCallback(Window *, bool confirmed)
1317{
1318 if (confirmed) {
1321 }
1322}
1323
1332public:
1335 Colours colour;
1337 uint height;
1338 uint width;
1339
1340 ButtonCommon(SpriteID sprite, StringID tooltip, Colours colour, bool disabled = false) :
1341 sprite(sprite),
1343 colour(colour),
1345 {
1347 this->height = d.height + WidgetDimensions::scaled.framerect.Vertical();
1348 this->width = d.width + WidgetDimensions::scaled.framerect.Horizontal();
1349 }
1350 virtual ~ButtonCommon() = default;
1351
1355 virtual void OnClick(struct NetworkClientListWindow *w, Point pt) = 0;
1356};
1357
1361template <typename T>
1362class Button : public ButtonCommon {
1363private:
1364 typedef void (*ButtonCallback)(struct NetworkClientListWindow *w, Point pt, T id);
1365 T id;
1367
1368public:
1369 Button(SpriteID sprite, StringID tooltip, Colours colour, T id, ButtonCallback proc, bool disabled = false) :
1371 id(id),
1372 proc(proc)
1373 {
1374 assert(proc != nullptr);
1375 }
1376
1377 void OnClick(struct NetworkClientListWindow *w, Point pt) override
1378 {
1379 if (this->disabled) return;
1380
1381 this->proc(w, pt, this->id);
1382 }
1383};
1384
1387
1392private:
1394
1396 CompanyID dd_company_id = CompanyID::Invalid();
1397
1398 Scrollbar *vscroll = nullptr;
1399 uint line_height = 0;
1400 uint line_count = 0;
1401 int hover_index = -1;
1404
1405 std::map<uint, std::vector<std::unique_ptr<ButtonCommon>>> buttons{};
1406
1413 static void OnClickCompanyChat([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, CompanyID company_id)
1414 {
1415 ShowNetworkChatQueryWindow(DESTTYPE_TEAM, company_id.base());
1416 }
1417
1424 static void OnClickCompanyJoin([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, CompanyID company_id)
1425 {
1426 if (_network_server) {
1429 } else {
1430 NetworkClientRequestMove(company_id);
1431 }
1432 }
1433
1439 static void OnClickCompanyNew([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, CompanyID)
1440 {
1442 }
1443
1450 static void OnClickClientAdmin([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, ClientID client_id)
1451 {
1452 DropDownList list;
1453 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK, DD_CLIENT_ADMIN_KICK));
1454 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN, DD_CLIENT_ADMIN_BAN));
1455
1456 Rect wi_rect;
1457 wi_rect.left = pt.x;
1458 wi_rect.right = pt.x;
1459 wi_rect.top = pt.y;
1460 wi_rect.bottom = pt.y;
1461
1462 w->dd_client_id = client_id;
1463 ShowDropDownListAt(w, std::move(list), -1, WID_CL_MATRIX, wi_rect, COLOUR_GREY, true);
1464 }
1465
1472 static void OnClickCompanyAdmin([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, CompanyID company_id)
1473 {
1474 DropDownList list;
1475 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET, DD_COMPANY_ADMIN_RESET, NetworkCompanyHasClients(company_id)));
1476
1477 Rect wi_rect;
1478 wi_rect.left = pt.x;
1479 wi_rect.right = pt.x;
1480 wi_rect.top = pt.y;
1481 wi_rect.bottom = pt.y;
1482
1483 w->dd_company_id = company_id;
1484 ShowDropDownListAt(w, std::move(list), -1, WID_CL_MATRIX, wi_rect, COLOUR_GREY, true);
1485 }
1492 static void OnClickClientChat([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, ClientID client_id)
1493 {
1495 }
1496
1497 static void OnClickClientAuthorize([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, ClientID client_id)
1498 {
1501 }
1502
1509 void RebuildListCompany(CompanyID company_id, CompanyID client_playas, bool can_join_company)
1510 {
1511 ButtonCommon *chat_button = new CompanyButton(SPR_CHAT, company_id == COMPANY_SPECTATOR ? STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP : STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::OnClickCompanyChat);
1512
1513 if (_network_server) this->buttons[line_count].push_back(std::make_unique<CompanyButton>(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP, COLOUR_RED, company_id, &NetworkClientListWindow::OnClickCompanyAdmin, company_id == COMPANY_SPECTATOR));
1514 this->buttons[line_count].emplace_back(chat_button);
1515 if (can_join_company) this->buttons[line_count].push_back(std::make_unique<CompanyButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::OnClickCompanyJoin, company_id != COMPANY_SPECTATOR && Company::Get(company_id)->is_ai));
1516
1517 this->line_count += 1;
1518
1519 bool has_players = false;
1520 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1521 if (ci->client_playas != company_id) continue;
1522 has_players = true;
1523
1524 if (_network_server) this->buttons[line_count].push_back(std::make_unique<ClientButton>(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP, COLOUR_RED, ci->client_id, &NetworkClientListWindow::OnClickClientAdmin, _network_own_client_id == ci->client_id));
1525 if (_network_own_client_id != ci->client_id) this->buttons[line_count].push_back(std::make_unique<ClientButton>(SPR_CHAT, STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP, COLOUR_ORANGE, ci->client_id, &NetworkClientListWindow::OnClickClientChat));
1526 if (_network_own_client_id != ci->client_id && client_playas != COMPANY_SPECTATOR && !ci->CanJoinCompany(client_playas)) this->buttons[line_count].push_back(std::make_unique<ClientButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_COMPANY_AUTHORIZE_TOOLTIP, COLOUR_GREEN, ci->client_id, &NetworkClientListWindow::OnClickClientAuthorize));
1527
1528 if (ci->client_id == _network_own_client_id) {
1529 this->player_self_index = this->line_count;
1530 } else if (ci->client_id == CLIENT_ID_SERVER) {
1531 this->player_host_index = this->line_count;
1532 }
1533
1534 this->line_count += 1;
1535 }
1536
1537 /* Disable the chat button when there are players in this company. */
1538 chat_button->disabled = !has_players;
1539 }
1540
1545 {
1547 CompanyID client_playas = own_ci == nullptr ? COMPANY_SPECTATOR : own_ci->client_playas;
1548
1549 this->buttons.clear();
1550 this->line_count = 0;
1551 this->player_host_index = -1;
1552 this->player_self_index = -1;
1553
1554 /* As spectator, show a line to create a new company. */
1555 if (client_playas == COMPANY_SPECTATOR && !NetworkMaxCompaniesReached()) {
1556 this->buttons[line_count].push_back(std::make_unique<CompanyButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP, COLOUR_ORANGE, COMPANY_SPECTATOR, &NetworkClientListWindow::OnClickCompanyNew));
1557 this->line_count += 1;
1558 }
1559
1560 if (client_playas != COMPANY_SPECTATOR) {
1561 this->RebuildListCompany(client_playas, client_playas, false);
1562 }
1563
1564 /* Companies */
1565 for (const Company *c : Company::Iterate()) {
1566 if (c->index == client_playas) continue;
1567
1568 this->RebuildListCompany(c->index, client_playas, (own_ci != nullptr && c->allow_list.Contains(own_ci->public_key)) || _network_server);
1569 }
1570
1571 /* Spectators */
1572 this->RebuildListCompany(COMPANY_SPECTATOR, client_playas, client_playas != COMPANY_SPECTATOR);
1573
1574 this->vscroll->SetCount(this->line_count);
1575 }
1576
1583 {
1584 uint index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CL_MATRIX);
1585 Rect matrix = this->GetWidget<NWidgetBase>(WID_CL_MATRIX)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
1586
1587 bool rtl = _current_text_dir == TD_RTL;
1588 uint x = rtl ? matrix.left : matrix.right;
1589
1590 /* Find the buttons for this row. */
1591 auto button_find = this->buttons.find(index);
1592 if (button_find == this->buttons.end()) return nullptr;
1593
1594 /* Check if we want to display a tooltip for any of the buttons. */
1595 for (auto &button : button_find->second) {
1596 uint left = rtl ? x : x - button->width;
1597 uint right = rtl ? x + button->width : x;
1598
1599 if (IsInsideMM(pt.x, left, right)) {
1600 return button.get();
1601 }
1602
1603 int width = button->width + WidgetDimensions::scaled.framerect.Horizontal();
1604 x += rtl ? width : -width;
1605 }
1606
1607 return nullptr;
1608 }
1609
1610public:
1612 {
1613 this->CreateNestedTree();
1614 this->vscroll = this->GetScrollbar(WID_CL_SCROLLBAR);
1615 this->OnInvalidateData();
1616 this->FinishInitNested(window_number);
1617 }
1618
1619 void OnInit() override
1620 {
1621 RebuildList();
1622 }
1623
1624 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1625 {
1626 this->RebuildList();
1627
1628 /* Currently server information is not sync'd to clients, so we cannot show it on clients. */
1629 this->GetWidget<NWidgetStacked>(WID_CL_SERVER_SELECTOR)->SetDisplayedPlane(_network_server ? 0 : SZSP_HORIZONTAL);
1631 }
1632
1633 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1634 {
1635 switch (widget) {
1636 case WID_CL_SERVER_NAME:
1637 case WID_CL_CLIENT_NAME: {
1638 std::string str;
1639 if (widget == WID_CL_SERVER_NAME) {
1641 } else {
1643 str = GetString(STR_JUST_RAW_STRING, own_ci != nullptr ? own_ci->client_name : _settings_client.network.client_name);
1644 }
1645 size = GetStringBoundingBox(str);
1646 size.width = std::min(size.width, static_cast<uint>(ScaleGUITrad(200))); // By default, don't open the window too wide.
1647 break;
1648 }
1649
1651 size = maxdim(maxdim(GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_LOCAL), GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_PUBLIC)), GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_INVITE_ONLY));
1652 size.width += padding.width;
1653 size.height += padding.height;
1654 break;
1655
1656 case WID_CL_MATRIX: {
1657 uint height = std::max({GetSpriteSize(SPR_COMPANY_ICON).height, GetSpriteSize(SPR_JOIN).height, GetSpriteSize(SPR_ADMIN).height, GetSpriteSize(SPR_CHAT).height});
1659 this->line_height = std::max(height, (uint)GetCharacterHeight(FS_NORMAL)) + padding.height;
1660
1661 resize.width = 1;
1662 resize.height = this->line_height;
1663 fill.height = this->line_height;
1664 size.height = std::max(size.height, 5 * this->line_height);
1665 break;
1666 }
1667 }
1668 }
1669
1670 void OnResize() override
1671 {
1672 this->vscroll->SetCapacityFromWidget(this, WID_CL_MATRIX);
1673 }
1674
1675 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
1676 {
1677 switch (widget) {
1678 case WID_CL_SERVER_NAME:
1680
1682 return GetString(STR_NETWORK_SERVER_VISIBILITY_LOCAL + _settings_client.network.server_game_type);
1683
1686
1688 return GetString(STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_UNKNOWN + _network_server_connection_type);
1689
1690 case WID_CL_CLIENT_NAME: {
1692 return own_ci != nullptr ? own_ci->client_name : _settings_client.network.client_name;
1693 }
1694
1696 return GetString(STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT, NetworkClientInfo::GetNumItems(), Company::GetNumItems(), NetworkMaxCompaniesAllowed());
1697
1698 default:
1699 return this->Window::GetWidgetString(widget, stringid);
1700 }
1701 }
1702
1703 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1704 {
1705 switch (widget) {
1707 if (!_network_server) break;
1708
1711 break;
1712
1716 ShowQueryString(own_ci != nullptr ? own_ci->client_name : _settings_client.network.client_name, STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION, NETWORK_CLIENT_NAME_LENGTH, this, CS_ALPHANUMERAL, QueryStringFlag::LengthIsInChars);
1717 break;
1718 }
1720 if (!_network_server) break;
1721
1723 break;
1724
1725 case WID_CL_MATRIX: {
1726 ButtonCommon *button = this->GetButtonAtPoint(pt);
1727 if (button == nullptr) break;
1728
1729 button->OnClick(this, pt);
1730 break;
1731 }
1732 }
1733 }
1734
1735 bool OnTooltip([[maybe_unused]] Point pt, WidgetID widget, TooltipCloseCondition close_cond) override
1736 {
1737 switch (widget) {
1738 case WID_CL_MATRIX: {
1739 int index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CL_MATRIX);
1740
1741 bool rtl = _current_text_dir == TD_RTL;
1742 Rect matrix = this->GetWidget<NWidgetBase>(WID_CL_MATRIX)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
1743
1744 Dimension d = GetSpriteSize(SPR_COMPANY_ICON);
1745 uint text_left = matrix.left + (rtl ? 0 : d.width + WidgetDimensions::scaled.hsep_wide);
1746 uint text_right = matrix.right - (rtl ? d.width + WidgetDimensions::scaled.hsep_wide : 0);
1747
1748 Dimension d2 = GetSpriteSize(SPR_PLAYER_SELF);
1749 uint offset_x = WidgetDimensions::scaled.hsep_indent - d2.width - ScaleGUITrad(3);
1750
1751 uint player_icon_x = rtl ? text_right - offset_x - d2.width : text_left + offset_x;
1752
1753 if (IsInsideMM(pt.x, player_icon_x, player_icon_x + d2.width)) {
1754 if (index == this->player_self_index) {
1755 GuiShowTooltips(this, GetEncodedString(STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP), close_cond);
1756 return true;
1757 } else if (index == this->player_host_index) {
1758 GuiShowTooltips(this, GetEncodedString(STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP), close_cond);
1759 return true;
1760 }
1761 }
1762
1763 ButtonCommon *button = this->GetButtonAtPoint(pt);
1764 if (button == nullptr) return false;
1765
1766 GuiShowTooltips(this, GetEncodedString(button->tooltip), close_cond);
1767 return true;
1768 };
1769 }
1770
1771 return false;
1772 }
1773
1774 void OnDropdownClose(Point pt, WidgetID widget, int index, bool instant_close) override
1775 {
1776 /* If you close the dropdown outside the list, don't take any action. */
1777 if (widget == WID_CL_MATRIX) return;
1778
1779 Window::OnDropdownClose(pt, widget, index, instant_close);
1780 }
1781
1782 void OnDropdownSelect(WidgetID widget, int index) override
1783 {
1784 switch (widget) {
1786 if (!_network_server) break;
1787
1790 break;
1791
1792 case WID_CL_MATRIX: {
1793 QueryCallbackProc *callback = nullptr;
1794
1795 EncodedString text;
1796 switch (index) {
1797 case DD_CLIENT_ADMIN_KICK:
1799 callback = AdminClientKickCallback;
1800 text = GetEncodedString(STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK, NetworkClientInfo::GetByClientID(_admin_client_id)->client_name);
1801 break;
1802
1803 case DD_CLIENT_ADMIN_BAN:
1805 callback = AdminClientBanCallback;
1806 text = GetEncodedString(STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN, NetworkClientInfo::GetByClientID(_admin_client_id)->client_name);
1807 break;
1808
1809 case DD_COMPANY_ADMIN_RESET:
1811 callback = AdminCompanyResetCallback;
1812 text = GetEncodedString(STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET, _admin_company_id);
1813 break;
1814
1815 default:
1816 NOT_REACHED();
1817 }
1818
1819 assert(callback != nullptr);
1820
1821 /* Always ask confirmation for all admin actions. */
1822 ShowQuery(
1823 GetEncodedString(STR_NETWORK_CLIENT_LIST_ASK_CAPTION),
1824 std::move(text),
1825 this, callback);
1826
1827 break;
1828 }
1829
1830 default:
1831 NOT_REACHED();
1832 }
1833
1834 this->SetDirty();
1835 }
1836
1837 void OnQueryTextFinished(std::optional<std::string> str) override
1838 {
1839 if (!str.has_value()) return;
1840
1841 switch (this->query_widget) {
1842 default: NOT_REACHED();
1843
1845 if (!_network_server) break;
1846
1847 SetSettingValue(GetSettingFromName("network.server_name")->AsStringSetting(), *str);
1848 this->InvalidateData();
1849 break;
1850 }
1851
1853 SetSettingValue(GetSettingFromName("network.client_name")->AsStringSetting(), *str);
1854 this->InvalidateData();
1855 break;
1856 }
1857 }
1858 }
1859
1870 void DrawButtons(int &x, uint y, const std::vector<std::unique_ptr<ButtonCommon>> &buttons) const
1871 {
1872 Rect r;
1873
1874 for (auto &button : buttons) {
1875 bool rtl = _current_text_dir == TD_RTL;
1876
1877 int offset = (this->line_height - button->height) / 2;
1878 r.left = rtl ? x : x - button->width + 1;
1879 r.right = rtl ? x + button->width - 1 : x;
1880 r.top = y + offset;
1881 r.bottom = r.top + button->height - 1;
1882
1883 DrawFrameRect(r, button->colour, {});
1884 DrawSprite(button->sprite, PAL_NONE, r.left + WidgetDimensions::scaled.framerect.left, r.top + WidgetDimensions::scaled.framerect.top);
1885 if (button->disabled) {
1887 }
1888
1889 int width = button->width + WidgetDimensions::scaled.hsep_normal;
1890 x += rtl ? width : -width;
1891 }
1892 }
1893
1900 void DrawCompany(CompanyID company_id, const Rect &r, uint &line) const
1901 {
1902 bool rtl = _current_text_dir == TD_RTL;
1903 int text_y_offset = CenterBounds(0, this->line_height, GetCharacterHeight(FS_NORMAL));
1904
1905 Dimension d = GetSpriteSize(SPR_COMPANY_ICON);
1906 int offset = CenterBounds(0, this->line_height, d.height);
1907
1908 uint line_start = this->vscroll->GetPosition();
1909 uint line_end = line_start + this->vscroll->GetCapacity();
1910
1911 uint y = r.top + (this->line_height * (line - line_start));
1912
1913 /* Draw the company line (if in range of scrollbar). */
1914 if (IsInsideMM(line, line_start, line_end)) {
1915 int icon_left = r.WithWidth(d.width, rtl).left;
1916 Rect tr = r.Indent(d.width + WidgetDimensions::scaled.hsep_normal, rtl);
1917 int &x = rtl ? tr.left : tr.right;
1918
1919 /* If there are buttons for this company, draw them. */
1920 auto button_find = this->buttons.find(line);
1921 if (button_find != this->buttons.end()) {
1922 this->DrawButtons(x, y, button_find->second);
1923 }
1924
1925 if (company_id == COMPANY_SPECTATOR) {
1926 DrawSprite(SPR_COMPANY_ICON, PALETTE_TO_GREY, icon_left, y + offset);
1927 DrawString(tr.left, tr.right, y + text_y_offset, STR_NETWORK_CLIENT_LIST_SPECTATORS, TC_SILVER);
1928 } else if (company_id == COMPANY_NEW_COMPANY) {
1929 DrawSprite(SPR_COMPANY_ICON, PALETTE_TO_GREY, icon_left, y + offset);
1930 DrawString(tr.left, tr.right, y + text_y_offset, STR_NETWORK_CLIENT_LIST_NEW_COMPANY, TC_WHITE);
1931 } else {
1932 DrawCompanyIcon(company_id, icon_left, y + offset);
1933
1934 DrawString(tr.left, tr.right, y + text_y_offset, GetString(STR_COMPANY_NAME, company_id, company_id), TC_SILVER);
1935 }
1936 }
1937
1938 y += this->line_height;
1939 line++;
1940
1941 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1942 if (ci->client_playas != company_id) continue;
1943
1944 /* Draw the player line (if in range of scrollbar). */
1945 if (IsInsideMM(line, line_start, line_end)) {
1946 Rect tr = r.Indent(WidgetDimensions::scaled.hsep_indent, rtl);
1947
1948 /* If there are buttons for this client, draw them. */
1949 auto button_find = this->buttons.find(line);
1950 if (button_find != this->buttons.end()) {
1951 int &x = rtl ? tr.left : tr.right;
1952 this->DrawButtons(x, y, button_find->second);
1953 }
1954
1955 SpriteID player_icon = 0;
1956 if (ci->client_id == _network_own_client_id) {
1957 player_icon = SPR_PLAYER_SELF;
1958 } else if (ci->client_id == CLIENT_ID_SERVER) {
1959 player_icon = SPR_PLAYER_HOST;
1960 }
1961
1962 if (player_icon != 0) {
1963 Dimension d2 = GetSpriteSize(player_icon);
1964 int offset_y = CenterBounds(0, this->line_height, d2.height);
1965 DrawSprite(player_icon, PALETTE_TO_GREY, rtl ? tr.right - d2.width : tr.left, y + offset_y);
1966 tr = tr.Indent(d2.width + WidgetDimensions::scaled.hsep_normal, rtl);
1967 }
1968
1969 DrawString(tr.left, tr.right, y + text_y_offset, GetString(STR_JUST_RAW_STRING, ci->client_name), TC_BLACK);
1970 }
1971
1972 y += this->line_height;
1973 line++;
1974 }
1975 }
1976
1977 void DrawWidget(const Rect &r, WidgetID widget) const override
1978 {
1979 switch (widget) {
1980 case WID_CL_MATRIX: {
1981 Rect ir = r.Shrink(WidgetDimensions::scaled.framerect, RectPadding::zero);
1982 uint line = 0;
1983
1984 if (this->hover_index >= 0) {
1985 Rect br = r.WithHeight(this->line_height).Translate(0, this->hover_index * this->line_height);
1987 }
1988
1990 CompanyID client_playas = own_ci == nullptr ? COMPANY_SPECTATOR : own_ci->client_playas;
1991
1992 if (client_playas == COMPANY_SPECTATOR && !NetworkMaxCompaniesReached()) {
1993 this->DrawCompany(COMPANY_NEW_COMPANY, ir, line);
1994 }
1995
1996 if (client_playas != COMPANY_SPECTATOR) {
1997 this->DrawCompany(client_playas, ir, line);
1998 }
1999
2000 for (const Company *c : Company::Iterate()) {
2001 if (client_playas == c->index) continue;
2002 this->DrawCompany(c->index, ir, line);
2003 }
2004
2005 /* Spectators */
2006 this->DrawCompany(COMPANY_SPECTATOR, ir, line);
2007
2008 break;
2009 }
2010 }
2011 }
2012
2013 void OnMouseOver([[maybe_unused]] Point pt, WidgetID widget) override
2014 {
2015 if (widget != WID_CL_MATRIX) {
2016 if (this->hover_index != -1) {
2017 this->hover_index = -1;
2019 }
2020 } else {
2021 int index = this->GetRowFromWidget(pt.y, widget, 0, -1);
2022 if (index != this->hover_index) {
2023 this->hover_index = index;
2025 }
2026 }
2027 }
2028};
2029
2030void ShowClientList()
2031{
2032 AllocateWindowDescFront<NetworkClientListWindow>(_client_list_desc, 0);
2033}
2034
2039
2041 std::shared_ptr<NetworkAuthenticationPasswordRequest> request{};
2042
2044 {
2047 }
2048
2049 void DrawWidget(const Rect &r, WidgetID widget) const override
2050 {
2051 switch (widget) {
2052 case WID_NJS_PROGRESS_BAR: {
2053 /* Draw the % complete with a bar and a text */
2055 Rect ir = r.Shrink(WidgetDimensions::scaled.bevel);
2056 uint8_t progress; // used for progress bar
2057 switch (_network_join_status) {
2058 case NETWORK_JOIN_STATUS_CONNECTING:
2059 case NETWORK_JOIN_STATUS_AUTHORIZING:
2060 case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
2061 progress = 10; // first two stages 10%
2062 break;
2063 case NETWORK_JOIN_STATUS_WAITING:
2064 progress = 15; // third stage is 15%
2065 break;
2066 case NETWORK_JOIN_STATUS_DOWNLOADING:
2067 if (_network_join_bytes_total == 0) {
2068 progress = 15; // We don't have the final size yet; the server is still compressing!
2069 break;
2070 }
2071 [[fallthrough]];
2072
2073 default: // Waiting is 15%, so the resting receivement of map is maximum 70%
2074 progress = 15 + _network_join_bytes * (100 - 15) / _network_join_bytes_total;
2075 break;
2076 }
2077 DrawFrameRect(ir.WithWidth(ir.Width() * progress / 100, _current_text_dir == TD_RTL), COLOUR_MAUVE, {});
2078 DrawString(ir.left, ir.right, CenterBounds(ir.top, ir.bottom, GetCharacterHeight(FS_NORMAL)), STR_NETWORK_CONNECTING_1 + _network_join_status, TC_FROMSTRING, SA_HOR_CENTER);
2079 break;
2080 }
2081
2083 switch (_network_join_status) {
2084 case NETWORK_JOIN_STATUS_WAITING:
2085 DrawStringMultiLine(r, GetString(STR_NETWORK_CONNECTING_WAITING, _network_join_waiting), TC_FROMSTRING, SA_CENTER);
2086 break;
2087
2088 case NETWORK_JOIN_STATUS_DOWNLOADING:
2089 if (_network_join_bytes_total == 0) {
2090 DrawStringMultiLine(r, GetString(STR_NETWORK_CONNECTING_DOWNLOADING_1, _network_join_bytes), TC_FROMSTRING, SA_CENTER);
2091 } else {
2092 DrawStringMultiLine(r, GetString(STR_NETWORK_CONNECTING_DOWNLOADING_2, _network_join_bytes, _network_join_bytes_total), TC_FROMSTRING, SA_CENTER);
2093 }
2094 break;
2095
2096 default:
2097 break;
2098 }
2099 break;
2100 }
2101 }
2102
2103 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2104 {
2105 switch (widget) {
2107 /* Account for the statuses */
2108 for (uint i = 0; i < NETWORK_JOIN_STATUS_END; i++) {
2109 size = maxdim(size, GetStringBoundingBox(STR_NETWORK_CONNECTING_1 + i));
2110 }
2111 /* For the number of waiting (other) players */
2112 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_CONNECTING_WAITING, GetParamMaxValue(MAX_CLIENTS))));
2113 /* We need some spacing for the 'border' */
2116 break;
2117
2118 case WID_NJS_PROGRESS_TEXT: {
2119 /* Account for downloading ~ 10 MiB */
2120 uint64_t max_digits = GetParamMaxDigits(8);
2121 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_CONNECTING_DOWNLOADING_1, max_digits, max_digits)));
2122 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_CONNECTING_DOWNLOADING_1, max_digits, max_digits)));
2123 break;
2124 }
2125 }
2126 }
2127
2128 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2129 {
2130 if (widget == WID_NJS_CANCELOK) { // Disconnect button
2132 SwitchToMode(SM_MENU);
2133 ShowNetworkGameWindow();
2134 }
2135 }
2136
2137 void OnQueryTextFinished(std::optional<std::string> str) override
2138 {
2139 if (!str.has_value() || str->empty() || this->request == nullptr) {
2141 return;
2142 }
2143
2144 this->request->Reply(*str);
2145 }
2146};
2147
2148static constexpr NWidgetPart _nested_network_join_status_window_widgets[] = {
2149 NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_NETWORK_CONNECTING_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2150 NWidget(WWT_PANEL, COLOUR_GREY),
2152 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NJS_PROGRESS_BAR), SetFill(1, 0),
2153 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NJS_PROGRESS_TEXT), SetFill(1, 0), SetMinimalSize(350, 0),
2154 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NJS_CANCELOK), SetMinimalSize(101, 12), SetStringTip(STR_NETWORK_CONNECTION_DISCONNECT), SetFill(1, 0),
2155 EndContainer(),
2156 EndContainer(),
2157};
2158
2159static WindowDesc _network_join_status_window_desc(
2160 WDP_CENTER, nullptr, 0, 0,
2163 _nested_network_join_status_window_widgets
2164);
2165
2166void ShowJoinStatusWindow()
2167{
2169 new NetworkJoinStatusWindow(_network_join_status_window_desc);
2170}
2171
2172void ShowNetworkNeedPassword(std::shared_ptr<NetworkAuthenticationPasswordRequest> request)
2173{
2175 if (w == nullptr) return;
2176 w->request = std::move(request);
2177
2178 ShowQueryString({}, STR_NETWORK_NEED_GAME_PASSWORD_CAPTION, NETWORK_PASSWORD_LENGTH, w, CS_ALPHANUMERAL, {});
2179}
2180
2187 std::string token{};
2188
2189 NetworkAskRelayWindow(WindowDesc &desc, Window *parent, const std::string &server_connection_string, const std::string &relay_connection_string, const std::string &token) :
2190 Window(desc),
2193 token(token)
2194 {
2195 this->parent = parent;
2196 this->InitNested(0);
2197 }
2198
2199 void Close(int data = 0) override
2200 {
2202 this->Window::Close();
2203 }
2204
2205 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2206 {
2207 if (widget == WID_NAR_TEXT) {
2208 size = GetStringBoundingBox(GetString(STR_NETWORK_ASK_RELAY_TEXT, this->server_connection_string, this->relay_connection_string));
2209 }
2210 }
2211
2212 void DrawWidget(const Rect &r, WidgetID widget) const override
2213 {
2214 if (widget == WID_NAR_TEXT) {
2215 DrawStringMultiLine(r, GetString(STR_NETWORK_ASK_RELAY_TEXT, this->server_connection_string, this->relay_connection_string), TC_FROMSTRING, SA_CENTER);
2216 }
2217 }
2218
2219 void FindWindowPlacementAndResize([[maybe_unused]] int def_width, [[maybe_unused]] int def_height) override
2220 {
2221 /* Position query window over the calling window, ensuring it's within screen bounds. */
2222 this->left = Clamp(parent->left + (parent->width / 2) - (this->width / 2), 0, _screen.width - this->width);
2223 this->top = Clamp(parent->top + (parent->height / 2) - (this->height / 2), 0, _screen.height - this->height);
2224 this->SetDirty();
2225 }
2226
2227 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2228 {
2229 switch (widget) {
2230 case WID_NAR_NO:
2232 this->Close(NRWCD_HANDLED);
2233 break;
2234
2235 case WID_NAR_YES_ONCE:
2236 _network_coordinator_client.StartTurnConnection(this->token);
2237 this->Close(NRWCD_HANDLED);
2238 break;
2239
2240 case WID_NAR_YES_ALWAYS:
2242 _network_coordinator_client.StartTurnConnection(this->token);
2243 this->Close(NRWCD_HANDLED);
2244 break;
2245 }
2246 }
2247};
2248
2249static constexpr NWidgetPart _nested_network_ask_relay_widgets[] = {
2251 NWidget(WWT_CLOSEBOX, COLOUR_RED),
2252 NWidget(WWT_CAPTION, COLOUR_RED, WID_NAR_CAPTION), SetStringTip(STR_NETWORK_ASK_RELAY_CAPTION),
2253 EndContainer(),
2254 NWidget(WWT_PANEL, COLOUR_RED),
2258 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NAR_NO), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_RELAY_NO),
2259 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NAR_YES_ONCE), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_RELAY_YES_ONCE),
2260 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NAR_YES_ALWAYS), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_RELAY_YES_ALWAYS),
2261 EndContainer(),
2262 EndContainer(),
2263 EndContainer(),
2264};
2265
2266static WindowDesc _network_ask_relay_desc(
2267 WDP_CENTER, nullptr, 0, 0,
2270 _nested_network_ask_relay_widgets
2271);
2272
2279void ShowNetworkAskRelay(const std::string &server_connection_string, const std::string &relay_connection_string, const std::string &token)
2280{
2282
2283 Window *parent = GetMainWindow();
2284 new NetworkAskRelayWindow(_network_ask_relay_desc, parent, server_connection_string, relay_connection_string, token);
2285}
2286
2292 Window(desc)
2293 {
2294 this->parent = parent;
2295 this->InitNested(0);
2296 }
2297
2298 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2299 {
2300 if (widget == WID_NAS_TEXT) {
2301 size = GetStringBoundingBox(STR_NETWORK_ASK_SURVEY_TEXT);
2302 }
2303 }
2304
2305 void DrawWidget(const Rect &r, WidgetID widget) const override
2306 {
2307 if (widget == WID_NAS_TEXT) {
2308 DrawStringMultiLine(r, STR_NETWORK_ASK_SURVEY_TEXT, TC_BLACK, SA_CENTER);
2309 }
2310 }
2311
2312 void FindWindowPlacementAndResize([[maybe_unused]] int def_width, [[maybe_unused]] int def_height) override
2313 {
2314 /* Position query window over the calling window, ensuring it's within screen bounds. */
2315 this->left = Clamp(parent->left + (parent->width / 2) - (this->width / 2), 0, _screen.width - this->width);
2316 this->top = Clamp(parent->top + (parent->height / 2) - (this->height / 2), 0, _screen.height - this->height);
2317 this->SetDirty();
2318 }
2319
2320 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2321 {
2322 switch (widget) {
2323 case WID_NAS_PREVIEW:
2324 ShowSurveyResultTextfileWindow();
2325 break;
2326
2327 case WID_NAS_LINK:
2328 OpenBrowser(NETWORK_SURVEY_DETAILS_LINK);
2329 break;
2330
2331 case WID_NAS_NO:
2333 this->Close();
2334 break;
2335
2336 case WID_NAS_YES:
2338 this->Close();
2339 break;
2340 }
2341 }
2342};
2343
2344static constexpr NWidgetPart _nested_network_ask_survey_widgets[] = {
2346 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
2347 NWidget(WWT_CAPTION, COLOUR_GREY, WID_NAS_CAPTION), SetStringTip(STR_NETWORK_ASK_SURVEY_CAPTION),
2348 EndContainer(),
2349 NWidget(WWT_PANEL, COLOUR_GREY),
2353 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NAS_PREVIEW), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_SURVEY_PREVIEW),
2354 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NAS_LINK), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_SURVEY_LINK),
2355 EndContainer(),
2357 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NAS_NO), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_SURVEY_NO),
2358 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NAS_YES), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_SURVEY_YES),
2359 EndContainer(),
2360 EndContainer(),
2361 EndContainer(),
2362};
2363
2364static WindowDesc _network_ask_survey_desc(
2365 WDP_CENTER, nullptr, 0, 0,
2368 _nested_network_ask_survey_widgets
2369);
2370
2375{
2376 /* If we can't send a survey, don't ask the question. */
2377 if constexpr (!NetworkSurveyHandler::IsSurveyPossible()) return;
2378
2380
2381 Window *parent = GetMainWindow();
2382 new NetworkAskSurveyWindow(_network_ask_survey_desc, parent);
2383}
2384
2388
2390 {
2391 this->ConstructWindow();
2392
2393 auto result = _survey.CreatePayload(NetworkSurveyHandler::Reason::PREVIEW, true);
2394 this->LoadText(result);
2395 this->InvalidateData();
2396 }
2397};
2398
2399void ShowSurveyResultTextfileWindow()
2400{
2403}
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Button shown for either a company or client in the client-list.
Colours colour
The colour of the button.
bool disabled
Is the button disabled?
uint width
Calculated width of the button.
virtual void OnClick(struct NetworkClientListWindow *w, Point pt)=0
OnClick handler for when the button is pressed.
SpriteID sprite
The sprite to use on the button.
uint height
Calculated height of the button.
StringID tooltip
The tooltip of the button.
Template version of Button, with callback support.
T id
ID this button belongs to.
void OnClick(struct NetworkClientListWindow *w, Point pt) override
OnClick handler for when the button is pressed.
ButtonCallback proc
Callback proc to call when button is pressed.
void(* ButtonCallback)(struct NetworkClientListWindow *w, Point pt, T id)
Callback function to call on click.
void ConnectFailure(const std::string &token, uint8_t tracking_number)
Callback from a Connecter to let the Game Coordinator know the connection failed.
void GetListing()
Request a listing of all public servers.
Container for an encoded string, created by GetEncodedString.
List template of 'things' T to sort in a GUI.
bool Filter(FilterFunction *decide, F filter_data)
Filter the list.
void RebuildDone()
Notify the sortlist that the rebuild is done.
void SetListing(Listing l)
Import sort conditions.
void SetFilterState(bool state)
Enable or disable the filter.
bool IsDescSortOrder() const
Check if the sort order is descending.
void ToggleSortOrder()
Toggle the sort order Since that is the worst condition for the sort function reverse the list here.
void SetFilterFuncs(std::span< FilterFunction *const > n_funcs)
Hand the filter function pointers to the GUIList.
bool NeedRebuild() const
Check if a rebuild is needed.
void ForceRebuild()
Force that a rebuild is needed.
bool Sort(Comp compare)
Sort the list.
void ForceResort()
Force a resort next Sort call Reset the resort timer if used too.
uint8_t SortType() const
Get the sorttype of the list.
Listing GetListing() const
Export current sort conditions.
void SetSortFuncs(std::span< SortFunction *const > n_funcs)
Hand the sort function pointers to the GUIList.
bool NeedResort()
Check if a resort is needed next loop If used the resort timer will decrease every call till 0.
void SetSortType(uint8_t n_type)
Set the sorttype of the list.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
Baseclass for nested widgets.
uint resize_x
Horizontal resize step (0 means not resizable).
uint fill_x
Horizontal fill stepsize (from initial size, 0 means not resizable).
uint smallest_x
Smallest horizontal size of the widget in a filled window.
uint current_x
Current horizontal size (after resizing).
int pos_y
Vertical position of top-left corner of the widget in the window.
int pos_x
Horizontal position of top-left corner of the widget in the window.
uint smallest_y
Smallest vertical size of the widget in a filled window.
uint fill_y
Vertical fill stepsize (from initial size, 0 means not resizable).
uint resize_y
Vertical resize step (0 means not resizable).
uint current_y
Current vertical size (after resizing).
Baseclass for container widgets.
void Add(std::unique_ptr< NWidgetBase > &&wid)
Append widget wid to container.
Definition widget.cpp:1280
std::vector< std::unique_ptr< NWidgetBase > > children
Child widgets in container.
Full blown container to make it behave exactly as we want :)
static const uint MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER
Minimum width before adding a new header.
void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override
Assign size and position to the widget.
void SetupSmallestSize(Window *w) override
Compute smallest size needed by the widget.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
void OnPaint() override
The window must be repainted.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
QueryString filter_editbox
Editbox for filter on servers.
Scrollbar * vscroll
Vertical scrollbar of the list of servers.
void BuildGUINetworkGameList()
Dimension of compatibility icon.
static bool NGameNameSorter(NetworkGame *const &a, NetworkGame *const &b)
Sort servers by name.
static bool NGameTicksPlayingSorter(NetworkGame *const &a, NetworkGame *const &b)
Sort servers by the number of ticks the game is running.
void UpdateListPos()
Set this->list_pos to match this->server.
IntervalTimer< TimerWindow > refresh_interval
Refresh the online servers on a regular interval.
void OnInit() override
Notification that the nested widget tree gets initialized.
static bool NGameAllowedSorter(NetworkGame *const &a, NetworkGame *const &b)
Sort servers by joinability.
NetworkGame * server
Selected server.
NetworkGame * last_joined
The last joined server.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void DrawServerLine(const NetworkGame *cur_item, int y, bool highlight) const
Draw a single server line.
void OnResize() override
Called after the window got resized.
static bool NGameCalendarDateSorter(NetworkGame *const &a, NetworkGame *const &b)
Sort servers by calendar date.
void ScrollToSelectedServer()
Scroll the list up or down to the currently selected server.
void OnEditboxChanged(WidgetID wid) override
The text in an editbox has been edited.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
ServerListPosition list_pos
Position of the selected server.
static bool NGameClientSorter(NetworkGame *const &a, NetworkGame *const &b)
Sort servers by the amount of clients online on a server.
void SortNetworkGameList()
Sort the server list.
Dimension blot
Dimension of lock icon.
static bool NGameMapSizeSorter(NetworkGame *const &a, NetworkGame *const &b)
Sort servers by map size.
GUIGameServerList servers
List with game servers.
bool searched_internet
Did we ever press "Search Internet" button?
QueryString name_editbox
Client name editbox.
EventState OnKeyPress(char32_t key, uint16_t keycode) override
A key has been pressed.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
@ PREVIEW
User is previewing the survey result.
Scrollbar data structure.
size_type GetCapacity() const
Gets the number of visible elements of the scrollbar.
void SetCount(size_t num)
Sets the number of elements in the list.
auto GetScrolledItemFromWidget(Tcontainer &container, int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Return an iterator pointing to the element of a scrolled widget that a user clicked in.
size_type GetScrolledRowFromWidget(int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Compute the row of a scrolled widget that a user clicked in.
Definition widget.cpp:2449
void SetCapacityFromWidget(Window *w, WidgetID widget, int padding=0)
Set capacity of visible elements from the size and resize properties of a widget.
Definition widget.cpp:2523
EventState UpdateListPositionOnKeyPress(int &list_position, uint16_t keycode) const
Update the given list position as if it were on this scroll bar when the given keycode was pressed.
Definition widget.cpp:2470
void ScrollTowards(size_type position)
Scroll towards the given position; if the item is visible nothing happens, otherwise it will be shown...
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
size_type GetPosition() const
Gets the position of the first visible element in the list.
static constexpr TimerGameTick::Ticks TICKS_PER_SECOND
Estimation of how many ticks fit in a single second.
static YearMonthDay ConvertDateToYMD(Date date)
Converts a Date to a Year, Month & Day.
RectPadding framerect
Standard padding inside many panels.
Definition window_gui.h:40
RectPadding frametext
Padding inside frame with text.
Definition window_gui.h:41
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:29
int vsep_wide
Wide vertical spacing.
Definition window_gui.h:60
int hsep_wide
Wide horizontal spacing.
Definition window_gui.h:62
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:94
RectPadding matrix
Padding of WWT_MATRIX items.
Definition window_gui.h:42
int hsep_normal
Normal horizontal spacing.
Definition window_gui.h:61
RectPadding bevel
Bevel thickness, affected by "scaled bevels" game option.
Definition window_gui.h:38
int hsep_indent
Width of indentation for tree layouts.
Definition window_gui.h:63
CompanyID _current_company
Company currently doing an action.
@ CCA_DELETE
Delete a company.
@ CCA_NEW
Create a new company.
static constexpr CompanyID COMPANY_SPECTATOR
The client is spectating.
@ CALCA_ADD
Create a public key.
static constexpr CompanyID COMPANY_NEW_COMPANY
The client wants a new company.
@ CRR_NONE
Dummy reason for actions that don't need one.
@ CRR_MANUAL
The company is manually removed.
static const uint NETWORK_CLIENT_NAME_LENGTH
The maximum length of a client's name, in bytes including '\0'.
Definition config.h:58
static const uint NETWORK_HOSTNAME_PORT_LENGTH
The maximum length of the host name + port, in bytes including '\0'. The extra six is ":" + port numb...
Definition config.h:55
static const uint NETWORK_NAME_LENGTH
The maximum length of the server name and map name, in bytes including '\0'.
Definition config.h:53
static const std::string NETWORK_SURVEY_DETAILS_LINK
Link with more details & privacy statement of the survey.
Definition config.h:30
static const uint NETWORK_PASSWORD_LENGTH
The maximum length of the password, in bytes including '\0'.
Definition config.h:57
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, bool instant_close, bool persist)
Show a drop down list.
Definition dropdown.cpp:407
void ShowDropDownListAt(Window *w, DropDownList &&list, int selected, WidgetID button, Rect wi_rect, Colours wi_colour, bool instant_close, bool persist)
Show a drop down list.
Definition dropdown.cpp:389
std::vector< std::unique_ptr< const DropDownListItem > > DropDownList
A drop down list is a collection of drop down list items.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
@ SLO_LOAD
File is being loaded.
Definition fileio_type.h:55
@ FT_SCENARIO
old or new scenario
Definition fileio_type.h:19
@ FT_HEIGHTMAP
heightmap file
Definition fileio_type.h:20
@ FT_SAVEGAME
old or new savegame
Definition fileio_type.h:18
void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fop)
Launch save/load dialog in the given mode.
Definition fios_gui.cpp:984
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:77
static const uint32_t GENERATE_NEW_SEED
Create a new random seed.
Definition genworld.h:25
void StartNewGameWithoutGUI(uint32_t seed)
Start a normal game without the GUI.
void ShowGenerateLandscape()
Start with a normal game.
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
int GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition gfx.cpp:705
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition gfx.cpp:923
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:852
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition gfx.cpp:658
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:38
bool _left_button_clicked
Is left mouse button clicked?
Definition gfx.cpp:42
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
Definition gfx.cpp:115
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition gfx.cpp:989
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition gfx.cpp:775
Dimension GetScaledSpriteSize(SpriteID sprid)
Scale sprite size for GUI.
Definition widget.cpp:67
int CenterBounds(int min, int max, int size)
Determine where to draw a centred object inside a widget.
Definition gfx_func.h:166
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:245
@ SA_RIGHT
Right align the text (must be a single bit).
Definition gfx_type.h:379
@ SA_HOR_CENTER
Horizontally center the text.
Definition gfx_type.h:378
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:387
@ SA_VERT_CENTER
Vertically center the text.
Definition gfx_type.h:383
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
@ FILLRECT_CHECKER
Draw only every second pixel, used for greying-out.
Definition gfx_type.h:335
constexpr NWidgetPart SetMatrixDataTip(uint32_t cols, uint32_t rows, StringID tip={})
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
constexpr NWidgetPart NWidgetFunction(NWidgetFunctionType *func_ptr)
Obtain a nested widget (sub)tree from an external source.
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
constexpr NWidgetPart SetSpriteTip(SpriteID sprite, StringID tip={})
Widget part function for setting the sprite and tooltip.
constexpr NWidgetPart SetPIP(uint8_t pre, uint8_t inter, uint8_t post)
Widget part function for setting a pre/inter/post spaces.
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
constexpr NWidgetPart SetPadding(uint8_t top, uint8_t right, uint8_t bottom, uint8_t left)
Widget part function for setting additional space around a widget.
constexpr NWidgetPart SetStringTip(StringID string, StringID tip={})
Widget part function for setting the string and tooltip.
constexpr NWidgetPart SetAspect(float ratio, AspectFlags flags=AspectFlag::ResizeX)
Widget part function for setting the aspect ratio.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
constexpr NWidgetPart SetResizeWidgetTypeTip(ResizeWidgetValues widget_type, StringID tip)
Widget part function for setting the resize widget type and tooltip.
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetToolTip(StringID tip)
Widget part function for setting tooltip and clearing the widget data.
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart SetMinimalTextLines(uint8_t lines, uint8_t spacing, FontSize size=FS_NORMAL)
Widget part function for setting the minimal text lines.
constexpr NWidgetPart SetAlignment(StringAlignment align)
Widget part function for setting the alignment of text/images.
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
constexpr NWidgetPart SetPIPRatio(uint8_t ratio_pre, uint8_t ratio_inter, uint8_t ratio_post)
Widget part function for setting a pre/inter/post ratio.
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition window.cpp:945
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1500
static const uint MAX_MAP_SIZE
Maximal map size = 4096.
Definition map_type.h:40
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
void GuiShowTooltips(Window *parent, EncodedString &&text, TooltipCloseCondition close_tooltip)
Shows a tooltip.
Definition misc_gui.cpp:688
void ShowQuery(EncodedString &&caption, EncodedString &&message, Window *parent, QueryCallbackProc *callback, bool focus)
Show a confirmation window with standard 'yes' and 'no' buttons The window is aligned to the centre o...
void ShowQueryString(std::string_view str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
Show a query popup window with a textbox in it.
bool _is_network_server
Does this client wants to be a network-server?
Definition network.cpp:70
StringList _network_host_list
The servers we know.
Definition network.cpp:75
void NetworkQueryServer(const std::string &connection_string)
Query a server to fetch the game-info.
Definition network.cpp:670
void NetworkDisconnect(bool close_admins)
We want to disconnect from the host/clients.
Definition network.cpp:999
bool _network_server
network-server is active
Definition network.cpp:67
ClientID _network_own_client_id
Our client identifier.
Definition network.cpp:71
bool NetworkClientConnectGame(const std::string &connection_string, CompanyID default_company, const std::string &join_server_password)
Join a client to the server at with the given connection string.
Definition network.cpp:785
NetworkGame * NetworkAddServer(const std::string &connection_string, bool manually, bool never_expire)
Validates an address entered as a string and adds the server to the list.
Definition network.cpp:692
void NetworkUpdateServerGameType()
The setting server_game_type was updated; possibly we need to take some action.
Definition network.cpp:1027
bool NetworkValidateServerName(std::string &server_name)
Trim the given server name in place, i.e.
Definition network.cpp:858
Basic functions/variables used all over the place.
Base core network types and some helper functions to access them.
void ShowNetworkChatQueryWindow(DestType type, int dest)
Show the chat window.
bool NetworkValidateOurClientName()
Convenience method for NetworkValidateClientName on _settings_client.network.client_name.
bool NetworkMaxCompaniesReached()
Check if max_companies has been reached on the server (local check only).
uint NetworkMaxCompaniesAllowed()
Get the maximum number of companies that are allowed by the server.
std::string _network_server_name
The current name of the server you are on.
void NetworkClientRequestMove(CompanyID company_id)
Notify the server of this client wanting to be moved to another company.
Client part of the network protocol.
Part of the network protocol handling content distribution.
void ShowMissingContentWindow(const GRFConfigList &list)
Show the content list window with all missing grfs from the given list.
ConnectionType _network_server_connection_type
What type of connection the Game Coordinator detected we are on.
ClientNetworkCoordinatorSocketHandler _network_coordinator_client
The connection to the Game Coordinator.
std::string _network_server_invite_code
Our invite code as indicated by the Game Coordinator.
Part of the network protocol handling Game Coordinator requests.
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, const std::string &reason)
Ban, or kick, everyone joined from the given client's IP.
void NetworkServerKickClient(ClientID client_id, const std::string &reason)
Kick a single client.
void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
Handle the tid-bits of moving a client from one company to another.
bool NetworkCompanyHasClients(CompanyID company)
Check whether a particular company has clients.
void NetworkGameListRemoveItem(NetworkGame *remove)
Remove an item from the gamelist linked list.
std::vector< std::unique_ptr< NetworkGame > > _network_game_list
Game list of this client.
Handling of the list of games.
@ NGLS_ONLINE
Server is online.
@ NGLS_FULL
Server is full and cannot be queried.
@ NGLS_TOO_OLD
Server is too old to query.
@ NGLS_OFFLINE
Server is offline (or cannot be queried).
@ NGLS_BANNED
You are banned from this server.
void ShowNetworkAskRelay(const std::string &server_connection_string, const std::string &relay_connection_string, const std::string &token)
Show a modal confirmation window with "no" / "yes, once" / "yes, always" buttons.
static void AdminCompanyResetCallback(Window *, bool confirmed)
Callback function for admin command to reset company.
NetworkJoinStatus _network_join_status
The status of joining.
static void AdminClientKickCallback(Window *, bool confirmed)
Callback function for admin command to kick client.
void UpdateNetworkGameWindow()
Update the network new window because a new server is found on the network.
uint8_t _network_join_waiting
The number of clients waiting in front of us.
DropDownAdmin
The possibly entries in a DropDown for an admin.
static void AdminClientBanCallback(Window *, bool confirmed)
Callback function for admin command to ban client.
void DrawCompanyIcon(CompanyID cid, int x, int y)
Draw the icon of a company.
uint32_t _network_join_bytes_total
The total number of bytes to download.
uint32_t _network_join_bytes
The number of bytes we already downloaded.
void ShowNetworkAskSurvey()
Show a modal confirmation window with "no" / "preview" / "yes" buttons.
static CompanyID _admin_company_id
For what company a confirmation window is open.
static ClientID _admin_client_id
For what client a confirmation window is open.
GUIs related to networking.
@ NRWCD_UNHANDLED
Relay request is unhandled.
Definition network_gui.h:42
@ NRWCD_HANDLED
Relay request is handled, either by user or by timeout.
Definition network_gui.h:43
NetworkJoinStatus
Status of the clients during joining.
Server part of the network protocol.
Part of the network protocol handling opt-in survey.
@ DESTTYPE_CLIENT
Send message/notice to only a certain client (Private)
@ DESTTYPE_TEAM
Send message/notice to everyone playing the same company (Team)
static const uint MAX_CLIENTS
How many clients can we have.
ClientID
'Unique' identifier to be given to clients
@ INVALID_CLIENT_ID
Client is not part of anything.
@ CLIENT_ID_SERVER
Servers always have this ID.
ServerGameType
Game type the server can be using.
void NetworkUDPSearchGame()
Find all servers.
Sending and receiving UDP messages.
@ WID_NJS_PROGRESS_BAR
Simple progress bar.
@ WID_NJS_PROGRESS_TEXT
Text explaining what is happening.
@ WID_NJS_CANCELOK
Cancel / OK button.
@ WID_NG_CLIENT
Panel with editbox to set client name.
@ WID_NG_CLIENTS
'Clients' button.
@ WID_NG_SCROLLBAR
Scrollbar of matrix.
@ WID_NG_YEARS
'Years' button.
@ WID_NG_FILTER_LABEL
Label in front of the filter/search edit box.
@ WID_NG_NEWGRF_MISSING_SEL
Selection widget for the above button.
@ WID_NG_SEARCH_INTERNET
'Search internet server' button.
@ WID_NG_NEWGRF_MISSING
'Find missing NewGRF online' button.
@ WID_NG_LASTJOINED_SPACER
Spacer after last joined server panel.
@ WID_NG_DATE
'Date' button.
@ WID_NG_LASTJOINED
Info about the last joined server.
@ WID_NG_MATRIX
Panel with list of games.
@ WID_NG_CLIENT_LABEL
Label in front of client name edit box.
@ WID_NG_NEWGRF_SEL
Selection 'widget' to hide the NewGRF settings.
@ WID_NG_JOIN
'Join game' button.
@ WID_NG_SEARCH_LAN
'Search LAN server' button.
@ WID_NG_MAPSIZE
'Map size' button.
@ WID_NG_START
'Start server' button.
@ WID_NG_DETAILS
Panel with game details.
@ WID_NG_INFO
Third button in the game list panel.
@ WID_NG_NAME
'Name' button.
@ WID_NG_CANCEL
'Cancel' button.
@ WID_NG_ADD
'Add server' button.
@ WID_NG_MAIN
Main panel.
@ WID_NG_REFRESH
'Refresh server' button.
@ WID_NG_FILTER
Panel with the edit box to enter the search text.
@ WID_NG_LASTJOINED_LABEL
Label "Last joined server:".
@ WID_NG_NEWGRF
'NewGRF Settings' button.
ClientListWidgets
Widgets of the NetworkClientListWindow class.
@ WID_CL_CLIENT_NAME_EDIT
Edit button for client name.
@ WID_CL_SERVER_NAME
Server name.
@ WID_CL_SERVER_INVITE_CODE
Invite code for this server.
@ WID_CL_SERVER_NAME_EDIT
Edit button for server name.
@ WID_CL_CLIENT_NAME
Client name.
@ WID_CL_SERVER_SELECTOR
Selector to hide the server frame.
@ WID_CL_SCROLLBAR
Scrollbar for company/client list.
@ WID_CL_CLIENT_COMPANY_COUNT
Count of clients and companies.
@ WID_CL_SERVER_CONNECTION_TYPE
The type of connection the Game Coordinator detected for this server.
@ WID_CL_SERVER_VISIBILITY
Server visibility.
@ WID_CL_MATRIX
Company/client list.
@ WID_NSS_COMPANIES_BTNU
'Max companies' uparrow.
@ WID_NSS_COMPANIES_LABEL
Label for 'max companies'.
@ WID_NSS_CLIENTS_LABEL
Label for 'max clients'.
@ WID_NSS_CLIENTS_TXT
'Max clients' text.
@ WID_NSS_CLIENTS_BTND
'Max clients' downarrow.
@ WID_NSS_GAMENAME
Background for editbox to set game name.
@ WID_NSS_CANCEL
'Cancel' button.
@ WID_NSS_PLAY_HEIGHTMAP
Play heightmap button.
@ WID_NSS_GAMENAME_LABEL
Label for the game name.
@ WID_NSS_LOAD_GAME
Load game button.
@ WID_NSS_GENERATE_GAME
New game button.
@ WID_NSS_CONNTYPE_LABEL
Label for 'connection type'.
@ WID_NSS_CONNTYPE_BTN
'Connection type' droplist button.
@ WID_NSS_COMPANIES_BTND
'Max companies' downarrow.
@ WID_NSS_SETPWD
'Set password' button.
@ WID_NSS_CLIENTS_BTNU
'Max clients' uparrow.
@ WID_NSS_COMPANIES_TXT
'Max companies' text.
@ WID_NSS_BACKGROUND
Background of the window.
@ WID_NSS_PLAY_SCENARIO
Play scenario button.
@ WID_NAR_YES_ALWAYS
"Yes, always" button.
@ WID_NAR_TEXT
Text in the window.
@ WID_NAR_YES_ONCE
"Yes, once" button.
@ WID_NAR_NO
"No" button.
@ WID_NAR_CAPTION
Caption of the window.
@ WID_NAS_YES
"Yes" button.
@ WID_NAS_LINK
"Details & Privacy" button.
@ WID_NAS_TEXT
Text in the window.
@ WID_NAS_CAPTION
Caption of the window.
@ WID_NAS_NO
"No" button.
@ WID_NAS_PREVIEW
"Preview" button.
void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfigList &config)
Setup the NewGRF gui.
@ SM_MENU
Switch to game intro menu.
Definition openttd.h:33
uint8_t GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
Definition palette.cpp:387
static const uint8_t PC_GREY
Grey palette colour.
static const uint8_t PC_DARK_BLUE
Dark blue palette colour.
#define GREY_SCALE(level)
Return the colour for a particular greyscale level.
bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame)
Top function to save the new value of an element of the Settings struct.
static const SettingDesc * GetSettingFromName(const std::string_view name, const SettingTable &settings)
Given a name of setting, return a setting description from the table.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:58
int StrNaturalCompare(std::string_view s1, std::string_view s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
Definition string.cpp:514
@ CS_NUMERAL
Only numeric ones.
Definition string_type.h:26
@ CS_ALPHANUMERAL
Both numeric and alphabetic and spaces and stuff.
Definition string_type.h:25
uint64_t GetParamMaxValue(uint64_t max_value, uint min_count, FontSize size)
Get some number that is suitable for string size computations.
Definition strings.cpp:246
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:91
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:57
uint64_t GetParamMaxDigits(uint count, FontSize size)
Get some number that is suitable for string size computations.
Definition strings.cpp:228
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
@ TD_RTL
Text is written right-to-left by default.
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
NetworkSettings network
settings related to the network
Dimensions (a width and height) of a rectangle in 2D.
Information about GRF, used in the game and (part of it) in savegames.
Data structure describing how to show the list (what sort direction and criteria).
Partial widget specification to allow NWidgets to be written nested.
Window used for asking the user if he is okay using a relay server.
void FindWindowPlacementAndResize(int def_width, int def_height) override
Resize window towards the default size.
std::string relay_connection_string
The relay server we want to connect to.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
std::string token
The token for this connection.
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
std::string server_connection_string
The game server we want to connect to.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
Window used for asking if the user wants to participate in the automated survey.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
void FindWindowPlacementAndResize(int def_width, int def_height) override
Resize window towards the default size.
Container for all information known about a client.
static NetworkClientInfo * GetByClientID(ClientID client_id)
Return the CI given it's client-identifier.
Definition network.cpp:117
CompanyID client_playas
As which company is this client playing (CompanyID)
std::string client_name
Name of the client.
std::string public_key
The public key of the client.
Main handle for clientlist.
Scrollbar * vscroll
Vertical scrollbar of this window.
void OnResize() override
Called after the window got resized.
uint line_count
Amount of lines in the matrix.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
std::map< uint, std::vector< std::unique_ptr< ButtonCommon > > > buttons
Per line which buttons are available.
void DrawButtons(int &x, uint y, const std::vector< std::unique_ptr< ButtonCommon > > &buttons) const
Draw the buttons for a single line in the matrix.
ClientListWidgets query_widget
During a query this tracks what widget caused the query.
void OnDropdownSelect(WidgetID widget, int index) override
A dropdown option associated to this window has been selected.
CompanyID dd_company_id
During admin dropdown, track which company this was for.
void OnMouseOver(Point pt, WidgetID widget) override
The mouse is currently moving over the window or has just moved outside of the window.
int hover_index
Index of the current line we are hovering over, or -1 if none.
bool OnTooltip(Point pt, WidgetID widget, TooltipCloseCondition close_cond) override
Event to display a custom tooltip.
static void OnClickCompanyNew(NetworkClientListWindow *w, Point pt, CompanyID)
Crete new company button is clicked.
void OnDropdownClose(Point pt, WidgetID widget, int index, bool instant_close) override
A dropdown window associated to this window has been closed.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
uint line_height
Current lineheight of each entry in the matrix.
void OnInit() override
Notification that the nested widget tree gets initialized.
static void OnClickCompanyAdmin(NetworkClientListWindow *w, Point pt, CompanyID company_id)
Admin button on a Company is clicked.
static void OnClickCompanyChat(NetworkClientListWindow *w, Point pt, CompanyID company_id)
Chat button on a Company is clicked.
ClientID dd_client_id
During admin dropdown, track which client this was for.
static void OnClickClientChat(NetworkClientListWindow *w, Point pt, ClientID client_id)
Chat button on a Client is clicked.
void RebuildListCompany(CompanyID company_id, CompanyID client_playas, bool can_join_company)
Part of RebuildList() to create the information for a single company.
int player_self_index
The line the current player is on.
void DrawCompany(CompanyID company_id, const Rect &r, uint &line) const
Draw a company and its clients on the matrix.
int player_host_index
The line the host is on.
static void OnClickClientAdmin(NetworkClientListWindow *w, Point pt, ClientID client_id)
Admin button on a Client is clicked.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
ButtonCommon * GetButtonAtPoint(Point pt)
Get the button at a specific point on the WID_CL_MATRIX.
static void OnClickCompanyJoin(NetworkClientListWindow *w, Point pt, CompanyID company_id)
Join button on a Company is clicked.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void RebuildList()
Rebuild the list, meaning: calculate the lines needed and what buttons go on which line.
bool version_compatible
Can we connect to this server or not? (based on server_revision)
bool compatible
Can we connect to this server or not? (based on server_revision and grf_match.
Structure with information shown in the game list (GUI)
bool refreshing
Whether this server is being queried.
std::string connection_string
Address of the server.
NetworkGameInfo info
The game information of this server.
NetworkGameStatus status
Stats of the server.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
TimerGameCalendar::Date calendar_start
When the game started.
std::string server_revision
The version number the server is using (e.g.: 'r304' or 0.5.0)
bool use_password
Is this server passworded?
uint8_t clients_max
Max clients allowed on server.
GRFConfigList grfconfig
List of NewGRF files used.
uint16_t map_height
Map height.
std::string server_name
Server name.
uint16_t map_width
Map width.
TimerGameTick::TickCounter ticks_playing
Amount of ticks the game has been running unpaused.
LandscapeType landscape
The used landscape.
uint8_t companies_max
Max companies allowed on server.
std::string gamescript_name
Name of the gamescript.
TimerGameCalendar::Date calendar_date
Current calendar date.
int gamescript_version
Version of the gamescript.
uint8_t companies_on
How many started companies do we have.
uint8_t clients_on
Current count of clients on server.
uint8_t max_clients
maximum amount of clients
uint8_t max_companies
maximum amount of companies
std::string client_name
name of the player (as client)
ServerGameType server_game_type
Server type: local / public / invite-only.
UseRelayService use_relay_service
Use relay service?
std::string connect_to_ip
default for the "Add server" query
std::string last_joined
Last joined server.
std::string server_name
name of the server
std::string server_password
password for joining this server
ParticipateSurvey participate_survey
Participate in the automated survey.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
WidgetID widget_id
The widget that has the pop-up input menu.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnDropdownSelect(WidgetID widget, int index) override
A dropdown option associated to this window has been selected.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
QueryString name_editbox
Server name editbox.
void OnTimeout() override
Called when this window's timeout has been reached.
Coordinates of a point in 2D.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * Get(auto index)
Returns Titem with given index.
static size_t GetNumItems()
Returns number of valid items in the pool.
Data stored about a string that can be modified in the GUI.
int cancel_button
Widget button of parent window to simulate when pressing CANCEL in OSK.
static const int ACTION_CLEAR
Clear editbox.
constexpr uint Horizontal() const
Get total horizontal padding of RectPadding.
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Specification of a rectangle with absolute coordinates of all edges.
Rect WithWidth(int width, bool end) const
Copy Rect and set its width.
int Width() const
Get width of Rect.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Rect WithHeight(int height, bool end=false) const
Copy Rect and set its height.
Rect Indent(int indent, bool end) const
Copy Rect and indent it from its position.
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
uint step_height
Step-size of height resize changes.
Definition window_gui.h:213
String filter and state.
bool IsEmpty() const
Check whether any filter words were entered.
void SetFilterTerm(std::string_view str)
Set the term to filter on.
void ResetState()
Reset the matching state to process a new item.
bool GetState() const
Get the matching state of the current item.
Window for displaying the textfile of a survey result.
const GRFConfig * grf_config
View the textfile of this GRFConfig.
void Assign(const std::string_view text)
Copy a string into the textbuffer.
Definition textbuf.cpp:420
const char * GetText() const
Get the current text.
Definition textbuf.cpp:284
Window for displaying a textfile.
void LoadText(std::string_view buf)
Load a text into the textfile viewer.
TextfileType file_type
Type of textfile to view.
Container with the data associated to a single widget.
High level window description.
Definition window_gui.h:168
Number to differentiate different windows of the same class.
Data structure for an opened window.
Definition window_gui.h:274
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition window.cpp:957
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1052
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition widget.cpp:793
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1736
std::map< WidgetID, QueryString * > querystrings
QueryString associated to WWT_EDITBOX widgets.
Definition window_gui.h:321
void DrawWidgets() const
Paint all widgets of a window.
Definition widget.cpp:744
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition window.cpp:3164
Window * parent
Parent window.
Definition window_gui.h:329
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:556
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:504
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
Definition widget.cpp:776
ResizeInfo resize
Resize information.
Definition window_gui.h:315
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1726
bool SetFocusedWidget(WidgetID widget_index)
Set focus within this window to the given widget.
Definition window.cpp:485
virtual void OnDropdownClose(Point pt, WidgetID widget, int index, bool instant_close)
A dropdown window associated to this window has been closed.
Definition window.cpp:286
bool IsWidgetDisabled(WidgetID widget_index) const
Gets the enabled/disabled status of a widget.
Definition window_gui.h:411
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition window_gui.h:442
int left
x position of left edge of the window
Definition window_gui.h:310
void RaiseWidgetsWhenLowered(Args... widgets)
Raises the widgets and sets widgets dirty that are lowered.
Definition window_gui.h:537
int top
y position of top edge of the window
Definition window_gui.h:311
int GetRowFromWidget(int clickpos, WidgetID widget, int padding, int line_height=-1) const
Compute the row of a widget that a user clicked in.
Definition window.cpp:212
void HandleButtonClick(WidgetID widget)
Do all things to make a button look clicked and mark it to be unclicked in a few ticks.
Definition window.cpp:595
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1749
WindowFlags flags
Window flags.
Definition window_gui.h:301
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:313
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:382
int height
Height of the window (number of pixels down in y direction)
Definition window_gui.h:313
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:312
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:303
@ CONNECTION_TYPE_UNKNOWN
The Game Coordinator hasn't informed us yet what type of connection we have.
@ AcceptUnchanged
return success even when the text didn't change
@ LengthIsInChars
the length of the string is counted in characters
void QueryCallbackProc(Window *, bool)
Callback procedure for the ShowQuery method.
Definition textbuf_gui.h:27
TextfileType
Additional text files accompanying Tar archives.
@ TFT_SURVEY_RESULT
Survey result (preview)
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition widget.cpp:296
static RectPadding ScaleGUITrad(const RectPadding &r)
Scale a RectPadding to GUI zoom level.
Definition widget.cpp:48
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ WWT_IMGBTN
(Toggle) Button with image
Definition widget_type.h:42
@ WWT_PUSHIMGBTN
Normal push-button (no toggle button) with image caption.
@ NWID_SPACER
Invisible widget that takes some space.
Definition widget_type.h:69
@ WWT_EDITBOX
a textbox for typing
Definition widget_type.h:61
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:65
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:40
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition widget_type.h:56
@ WWT_MATRIX
Grid of rows and columns.
Definition widget_type.h:49
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:51
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:75
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:67
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:59
@ WWT_FRAME
Frame.
Definition widget_type.h:50
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:38
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:58
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:55
@ WWT_DROPDOWN
Drop down list.
Definition widget_type.h:60
@ WWT_TEXT
Pure simple text.
Definition widget_type.h:48
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition widget_type.h:70
@ SZSP_HORIZONTAL
Display plane with zero size vertically, and filling and resizing horizontally.
@ SZSP_NONE
Display plane with zero size in both directions (none filling and resizing).
@ EqualSize
Containers should keep all their (resizing) children equally large.
SizingType
Different forms of sizing nested widgets, using NWidgetBase::AssignSizePosition()
@ RWV_HIDE_BEVEL
Bevel of resize box is hidden.
Definition widget_type.h:30
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition window.cpp:1143
Window * GetMainWindow()
Get the main window, i.e.
Definition window.cpp:1130
void CloseWindowByClass(WindowClass cls, int data)
Close all windows of a given class.
Definition window.cpp:1155
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
Definition window.cpp:3224
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1101
@ Modal
The window is a modal child of some other window, meaning the parent is 'inactive'.
@ BorderOnly
Draw border only, no background.
@ Lowered
If set the frame is lowered and the background colour brighter (ie. buttons when pressed)
@ Timeout
Window timeout counter.
@ SBS_DOWN
Sort ascending.
Definition window_gui.h:219
@ SBS_UP
Sort descending.
Definition window_gui.h:220
@ WDP_CENTER
Center the window.
Definition window_gui.h:146
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:145
int WidgetID
Widget ID.
Definition window_type.h:20
@ WN_NETWORK_STATUS_WINDOW_JOIN
Network join status.
Definition window_type.h:41
@ WN_NETWORK_WINDOW_GAME
Network game window.
Definition window_type.h:37
@ WN_NETWORK_WINDOW_START
Network start server.
Definition window_type.h:39
EventState
State of handling an event.
@ ES_HANDLED
The passed event is handled.
@ ES_NOT_HANDLED
The passed event is not handled.
@ WC_NETWORK_ASK_RELAY
Network ask relay window; Window numbers:
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:47
@ WC_CLIENT_LIST
Client list; Window numbers:
@ WC_NETWORK_WINDOW
Network window; Window numbers:
@ WC_TEXTFILE
textfile; Window numbers:
@ WC_NETWORK_STATUS_WINDOW
Network status window; Window numbers:
@ WC_NETWORK_ASK_SURVEY
Network ask survey window; Window numbers: