OpenTTD Source 20260218-master-g2123fca5ea
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
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"
33#include "../genworld.h"
34#include "../map_type.h"
35#include "../zoom_func.h"
36#include "../sprite.h"
38#include "../company_cmd.h"
39#include "../timer/timer.h"
42#include "../textfile_gui.h"
45
47
48#include "table/strings.h"
49#include "../table/sprites.h"
50
51#ifdef __EMSCRIPTEN__
52# include <emscripten.h>
53#endif
54
55#include "../safeguards.h"
56
57static void ShowNetworkStartServerWindow();
58
60static CompanyID _admin_company_id = CompanyID::Invalid();
61
70
71static DropDownList BuildVisibilityDropDownList()
72{
73 DropDownList list;
74
75 list.push_back(MakeDropDownListStringItem(STR_NETWORK_SERVER_VISIBILITY_LOCAL, SERVER_GAME_TYPE_LOCAL));
76 list.push_back(MakeDropDownListStringItem(STR_NETWORK_SERVER_VISIBILITY_INVITE_ONLY, SERVER_GAME_TYPE_INVITE_ONLY));
77 list.push_back(MakeDropDownListStringItem(STR_NETWORK_SERVER_VISIBILITY_PUBLIC, SERVER_GAME_TYPE_PUBLIC));
78
79 return list;
80}
81
83typedef int ServerListPosition;
84static const ServerListPosition SLP_INVALID = -1;
85
87class NWidgetServerListHeader : public NWidgetContainer {
88 static const uint MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER = 150;
89public:
90 NWidgetServerListHeader() : NWidgetContainer(NWID_HORIZONTAL)
91 {
92 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);
93 leaf->SetResize(1, 0);
94 leaf->SetFill(1, 0);
95 this->Add(std::move(leaf));
96
97 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));
98 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));
99 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));
100 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));
101
102 leaf = std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_INFO, WidgetData{.string = STR_EMPTY}, STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP);
103 leaf->SetFill(0, 1);
104 this->Add(std::move(leaf));
105 }
106
107 void SetupSmallestSize(Window *w) override
108 {
109 this->smallest_y = 0; // Biggest child.
110 this->fill_x = 1;
111 this->fill_y = 0;
112 this->resize_x = 1; // We only resize in this direction
113 this->resize_y = 0; // We never resize in this direction
114
115 /* First initialise some variables... */
116 for (const auto &child_wid : this->children) {
117 child_wid->SetupSmallestSize(w);
118 this->smallest_y = std::max(this->smallest_y, child_wid->smallest_y + child_wid->padding.Vertical());
119 }
120
121 /* ... then in a second pass make sure the 'current' sizes are set. Won't change for most widgets. */
122 for (const auto &child_wid : this->children) {
123 child_wid->current_x = child_wid->smallest_x;
124 child_wid->current_y = this->smallest_y;
125 }
126
127 this->smallest_x = this->children.front()->smallest_x + this->children.back()->smallest_x; // First and last are always shown, rest not
128 this->ApplyAspectRatio();
129 }
130
131 void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override
132 {
133 assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
134
135 this->pos_x = x;
136 this->pos_y = y;
137 this->current_x = given_width;
138 this->current_y = given_height;
139
140 given_width -= this->children.back()->smallest_x;
141 /* The first and last widget are always visible, determine which other should be visible */
142 if (this->children.size() > 2) {
143 auto first = std::next(std::begin(this->children));
144 auto last = std::prev(std::end(this->children));
145 for (auto it = first; it != last; ++it) {
146 auto &child_wid = *it;
147 if (given_width > ScaleGUITrad(MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER) + child_wid->smallest_x && (*std::prev(it))->current_x != 0) {
148 given_width -= child_wid->smallest_x;
149 child_wid->current_x = child_wid->smallest_x; /* Make visible. */
150 } else {
151 child_wid->current_x = 0; /* Make invisible. */
152 }
153 }
154 }
155
156 /* All remaining space goes to the first (name) widget */
157 this->children.front()->current_x = given_width;
158
159 /* Now assign the widgets to their rightful place */
160 uint position = 0; // Place to put next child relative to origin of the container.
161 auto assign_position = [&](const std::unique_ptr<NWidgetBase> &child_wid) {
162 if (child_wid->current_x != 0) {
163 child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl);
164 position += child_wid->current_x;
165 }
166 };
167
168 if (rtl) {
169 std::for_each(std::rbegin(this->children), std::rend(this->children), assign_position);
170 } else {
171 std::for_each(std::begin(this->children), std::end(this->children), assign_position);
172 }
173 }
174};
175
176class NetworkGameWindow : public Window {
177protected:
178 /* Runtime saved values */
179 static Listing last_sorting;
180
181 /* Constants for sorting servers */
182 static const std::initializer_list<GUIGameServerList::SortFunction * const> sorter_funcs;
183 static const std::initializer_list<GUIGameServerList::FilterFunction * const> filter_funcs;
184
185 NetworkGame *server = nullptr;
187 GUIGameServerList servers{};
188 ServerListPosition list_pos = SLP_INVALID;
189 Scrollbar *vscroll = nullptr;
192 bool searched_internet = false;
193
194 Dimension lock{};
196
203 {
204 if (!this->servers.NeedRebuild()) return;
205
206 /* Create temporary array of games to use for listing */
207 this->servers.clear();
208
209 bool found_current_server = false;
210 bool found_last_joined = false;
211 for (const auto &ngl : _network_game_list) {
212 this->servers.push_back(ngl.get());
213 if (ngl.get() == this->server) {
214 found_current_server = true;
215 }
216 if (ngl.get() == this->last_joined) {
217 found_last_joined = true;
218 }
219 }
220 /* A refresh can cause the current server to be delete; so unselect. */
221 if (!found_last_joined) {
222 this->last_joined = nullptr;
223 }
224 if (!found_current_server) {
225 this->server = nullptr;
226 this->list_pos = SLP_INVALID;
227 }
228
229 /* Apply the filter condition immediately, if a search string has been provided. */
230 StringFilter sf;
231 sf.SetFilterTerm(this->filter_editbox.text.GetText());
232
233 if (!sf.IsEmpty()) {
234 this->servers.SetFilterState(true);
235 this->servers.Filter(sf);
236 } else {
237 this->servers.SetFilterState(false);
238 }
239
240 this->servers.RebuildDone();
241 this->vscroll->SetCount(this->servers.size());
242
243 /* Sort the list of network games as requested. */
244 this->servers.Sort();
245 this->UpdateListPos();
246 }
247
249 static bool NGameNameSorter(NetworkGame * const &a, NetworkGame * const &b)
250 {
251 int r = StrNaturalCompare(a->info.server_name, b->info.server_name, true); // Sort by name (natural sorting).
252 if (r == 0) r = a->connection_string.compare(b->connection_string);
253
254 return r < 0;
255 }
256
263 static bool NGameClientSorter(NetworkGame * const &a, NetworkGame * const &b)
264 {
265 /* Reverse as per default we are interested in most-clients first */
266 int r = a->info.clients_on - b->info.clients_on;
267
268 if (r == 0) r = a->info.clients_max - b->info.clients_max;
269 if (r == 0) return NGameNameSorter(a, b);
270
271 return r < 0;
272 }
273
275 static bool NGameMapSizeSorter(NetworkGame * const &a, NetworkGame * const &b)
276 {
277 /* Sort by the area of the map. */
278 int r = (a->info.map_height) * (a->info.map_width) - (b->info.map_height) * (b->info.map_width);
279
280 if (r == 0) r = a->info.map_width - b->info.map_width;
281 return (r != 0) ? r < 0 : NGameClientSorter(a, b);
282 }
283
285 static bool NGameCalendarDateSorter(NetworkGame * const &a, NetworkGame * const &b)
286 {
287 auto r = a->info.calendar_date - b->info.calendar_date;
288 return (r != 0) ? r < 0 : NGameClientSorter(a, b);
289 }
290
292 static bool NGameTicksPlayingSorter(NetworkGame * const &a, NetworkGame * const &b)
293 {
294 if (a->info.ticks_playing == b->info.ticks_playing) {
295 return NGameClientSorter(a, b);
296 }
297 return a->info.ticks_playing < b->info.ticks_playing;
298 }
299
305 static bool NGameAllowedSorter(NetworkGame * const &a, NetworkGame * const &b)
306 {
307 /* The servers we do not know anything about (the ones that did not reply) should be at the bottom) */
308 int r = a->info.server_revision.empty() - b->info.server_revision.empty();
309
310 /* Reverse default as we are interested in version-compatible clients first */
311 if (r == 0) r = b->info.version_compatible - a->info.version_compatible;
312 /* The version-compatible ones are then sorted with NewGRF compatible first, incompatible last */
313 if (r == 0) r = b->info.compatible - a->info.compatible;
314 /* Passworded servers should be below unpassworded servers */
315 if (r == 0) r = a->info.use_password - b->info.use_password;
316
317 /* Finally sort on the number of clients of the server in reverse order. */
318 return (r != 0) ? r < 0 : NGameClientSorter(b, a);
319 }
320
323 {
324 if (this->servers.Sort()) this->UpdateListPos();
325 }
326
329 {
330 auto it = std::ranges::find(this->servers, this->server);
331 if (it == std::end(this->servers)) {
332 this->list_pos = SLP_INVALID;
333 } else {
334 this->list_pos = static_cast<ServerListPosition>(std::distance(std::begin(this->servers), it));
335 }
336 }
337
338 static bool NGameSearchFilter(NetworkGame * const *item, StringFilter &sf)
339 {
340 assert(item != nullptr);
341 assert((*item) != nullptr);
342
343 sf.ResetState();
344 sf.AddLine((*item)->info.server_name);
345 return sf.GetState();
346 }
347
354 void DrawServerLine(const NetworkGame *cur_item, int y, bool highlight) const
355 {
356 Rect name = this->GetWidget<NWidgetBase>(WID_NG_NAME)->GetCurrentRect();
357 Rect info = this->GetWidget<NWidgetBase>(WID_NG_INFO)->GetCurrentRect();
358
359 /* show highlighted item with a different colour */
360 if (highlight) {
361 Rect r = {std::min(name.left, info.left), y, std::max(name.right, info.right), y + (int)this->resize.step_height - 1};
363 }
364
365 /* Offset to vertically position text. */
366 int text_y_offset = WidgetDimensions::scaled.matrix.top + (this->resize.step_height - WidgetDimensions::scaled.matrix.Vertical() - GetCharacterHeight(FS_NORMAL)) / 2;
367
368 info = info.Shrink(WidgetDimensions::scaled.framerect);
369 name = name.Shrink(WidgetDimensions::scaled.framerect);
370 DrawString(name.left, name.right, y + text_y_offset, cur_item->info.server_name, TC_BLACK);
371
372 /* only draw details if the server is online */
373 if (cur_item->status == NGLS_ONLINE) {
374 if (const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(WID_NG_CLIENTS); nwid->current_x != 0) {
375 Rect clients = nwid->GetCurrentRect();
376 DrawString(clients.left, clients.right, y + text_y_offset,
377 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),
378 TC_FROMSTRING, SA_HOR_CENTER);
379 }
380
381 if (const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(WID_NG_MAPSIZE); nwid->current_x != 0) {
382 /* map size */
383 Rect mapsize = nwid->GetCurrentRect();
384 DrawString(mapsize.left, mapsize.right, y + text_y_offset,
385 GetString(STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT, cur_item->info.map_width, cur_item->info.map_height),
386 TC_FROMSTRING, SA_HOR_CENTER);
387 }
388
389 if (const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(WID_NG_DATE); nwid->current_x != 0) {
390 /* current date */
391 Rect date = nwid->GetCurrentRect();
392 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(cur_item->info.calendar_date);
393 DrawString(date.left, date.right, y + text_y_offset,
394 GetString(STR_JUST_INT, ymd.year),
395 TC_BLACK, SA_HOR_CENTER);
396 }
397
398 if (const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(WID_NG_YEARS); nwid->current_x != 0) {
399 /* play time */
400 Rect years = nwid->GetCurrentRect();
401 const auto play_time = cur_item->info.ticks_playing / Ticks::TICKS_PER_SECOND;
402 DrawString(years.left, years.right, y + text_y_offset,
403 GetString(STR_NETWORK_SERVER_LIST_PLAY_TIME_SHORT, play_time / 60 / 60, (play_time / 60) % 60),
404 TC_BLACK, SA_HOR_CENTER);
405 }
406
407 /* Set top and bottom of info rect to current row. */
408 info.top = y;
409 info.bottom = y + this->resize.step_height - 1;
410
411 bool rtl = _current_text_dir == TD_RTL;
412
413 /* draw a lock if the server is password protected */
414 if (cur_item->info.use_password) DrawSpriteIgnorePadding(SPR_LOCK, PAL_NONE, info.WithWidth(this->lock.width, rtl), SA_CENTER);
415
416 /* draw red or green icon, depending on compatibility with server */
417 PaletteID pal = cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED);
418 DrawSpriteIgnorePadding(SPR_BLOT, pal, info.WithWidth(this->blot.width, !rtl), SA_CENTER);
419 }
420 }
421
430 {
431 if (this->list_pos == SLP_INVALID) return; // no server selected
432 this->vscroll->ScrollTowards(this->list_pos);
433 }
434
435public:
437 {
438 this->CreateNestedTree();
439 this->vscroll = this->GetScrollbar(WID_NG_SCROLLBAR);
441
442 this->querystrings[WID_NG_CLIENT] = &this->name_editbox;
443 this->name_editbox.text.Assign(_settings_client.network.client_name);
444
445 this->querystrings[WID_NG_FILTER] = &this->filter_editbox;
446 this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
448
449 /* As the Game Coordinator doesn't support "websocket" servers yet, we
450 * let "os/emscripten/pre.js" hardcode a list of servers people can
451 * join. This means the serverlist is curated for now, but it is the
452 * best we can offer. */
453#ifdef __EMSCRIPTEN__
454 EM_ASM(if (window["openttd_server_list"]) openttd_server_list());
455#endif
456
457 this->last_joined = NetworkAddServer(_settings_client.network.last_joined, false);
458 this->server = this->last_joined;
459
460 this->servers.SetListing(this->last_sorting);
461 this->servers.SetSortFuncs(NetworkGameWindow::sorter_funcs);
462 this->servers.SetFilterFuncs(NetworkGameWindow::filter_funcs);
463 this->servers.ForceRebuild();
464 }
465
466 ~NetworkGameWindow() override
467 {
468 this->last_sorting = this->servers.GetListing();
469 }
470
471 void OnInit() override
472 {
473 this->lock = GetScaledSpriteSize(SPR_LOCK);
474 this->blot = GetScaledSpriteSize(SPR_BLOT);
475 }
476
477 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
478 {
479 switch (widget) {
480 case WID_NG_MATRIX:
481 fill.height = resize.height = std::max<uint>(this->blot.height, GetCharacterHeight(FS_NORMAL)) + padding.height;
482 size.height = 12 * resize.height;
483 break;
484
486 size.height = std::max<uint>(this->blot.height, GetCharacterHeight(FS_NORMAL)) + WidgetDimensions::scaled.matrix.Vertical();
487 break;
488
490 size.width = NWidgetScrollbar::GetVerticalDimension().width;
491 break;
492
493 case WID_NG_NAME:
494 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
495 break;
496
497 case WID_NG_CLIENTS: {
498 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
499 auto max_clients = GetParamMaxValue(MAX_CLIENTS);
500 auto max_companies = GetParamMaxValue(MAX_COMPANIES);
501 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_SERVER_LIST_GENERAL_ONLINE, max_clients, max_clients, max_companies, max_companies)));
502 break;
503 }
504
505 case WID_NG_MAPSIZE: {
506 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
507 auto max_map_size = GetParamMaxValue(MAX_MAP_SIZE);
508 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT, max_map_size, max_map_size)));
509 break;
510 }
511
512 case WID_NG_DATE:
513 case WID_NG_YEARS:
514 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
515 size = maxdim(size, GetStringBoundingBox(GetString(STR_JUST_INT, GetParamMaxValue(5))));
516 break;
517
518 case WID_NG_INFO:
519 size.width = this->lock.width + WidgetDimensions::scaled.hsep_normal + this->blot.width + padding.width;
520 size.height = std::max(this->lock.height, this->blot.height) + padding.height;
521 break;
522 }
523 }
524
525 void DrawWidget(const Rect &r, WidgetID widget) const override
526 {
527 switch (widget) {
528 case WID_NG_MATRIX: {
529 uint16_t y = r.top;
530
531 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->servers);
532 for (auto it = first; it != last; ++it) {
533 const NetworkGame *ngl = *it;
534 this->DrawServerLine(ngl, y, ngl == this->server);
535 y += this->resize.step_height;
536 }
537 break;
538 }
539
541 /* Draw the last joined server, if any */
542 if (this->last_joined != nullptr) this->DrawServerLine(this->last_joined, r.top, this->last_joined == this->server);
543 break;
544
545 case WID_NG_DETAILS:
546 this->DrawDetails(r);
547 break;
548
549 case WID_NG_NAME:
550 case WID_NG_CLIENTS:
551 case WID_NG_MAPSIZE:
552 case WID_NG_DATE:
553 case WID_NG_YEARS:
554 case WID_NG_INFO:
555 if (widget - WID_NG_NAME == this->servers.SortType()) this->DrawSortButtonState(widget, this->servers.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
556 break;
557 }
558 }
559
560
561 void OnPaint() override
562 {
563 if (this->servers.NeedRebuild()) {
565 }
566 if (this->servers.NeedResort()) {
567 this->SortNetworkGameList();
568 }
569
570 NetworkGame *sel = this->server;
571 /* 'Refresh' button invisible if no server selected */
572 this->SetWidgetDisabledState(WID_NG_REFRESH, sel == nullptr);
573 /* 'Join' button disabling conditions */
574 this->SetWidgetDisabledState(WID_NG_JOIN, sel == nullptr || // no Selected Server
575 sel->status != NGLS_ONLINE || // Server offline
576 sel->info.clients_on >= sel->info.clients_max || // Server full
577 !sel->info.compatible); // Revision mismatch
578
579 this->SetWidgetLoweredState(WID_NG_REFRESH, sel != nullptr && sel->refreshing);
580
581 /* 'NewGRF Settings' button invisible if no NewGRF is used */
582 bool changed = false;
583 changed |= this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == nullptr || sel->status != NGLS_ONLINE || sel->info.grfconfig.empty() ? SZSP_NONE : 0);
584 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);
585 if (changed) {
586 this->ReInit();
587 return;
588 }
589
590#ifdef __EMSCRIPTEN__
595#endif
596
597 this->DrawWidgets();
598 }
599
600 StringID GetHeaderString() const
601 {
602 if (this->server == nullptr) return STR_NETWORK_SERVER_LIST_GAME_INFO;
603 switch (this->server->status) {
604 case NGLS_OFFLINE: return STR_NETWORK_SERVER_LIST_SERVER_OFFLINE;
605 case NGLS_ONLINE: return STR_NETWORK_SERVER_LIST_GAME_INFO;
606 case NGLS_FULL: return STR_NETWORK_SERVER_LIST_SERVER_FULL;
607 case NGLS_BANNED: return STR_NETWORK_SERVER_LIST_SERVER_BANNED;
608 case NGLS_TOO_OLD: return STR_NETWORK_SERVER_LIST_SERVER_TOO_OLD;
609 default: NOT_REACHED();
610 }
611 }
612
613 void DrawDetails(const Rect &r) const
614 {
615 NetworkGame *sel = this->server;
616
617 Rect tr = r.Shrink(WidgetDimensions::scaled.frametext);
618 StringID header_msg = this->GetHeaderString();
619 int header_height = GetStringHeight(header_msg, tr.Width()) +
620 (sel == nullptr ? 0 : GetStringHeight(sel->info.server_name, tr.Width())) +
621 WidgetDimensions::scaled.frametext.Vertical();
622
623 /* Height for the title banner */
624 Rect hr = r.WithHeight(header_height).Shrink(WidgetDimensions::scaled.frametext);
625 tr.top += header_height;
626
627 /* Draw the right menu */
628 /* Create the nice darker rectangle at the details top */
629 GfxFillRect(r.WithHeight(header_height).Shrink(WidgetDimensions::scaled.bevel), GetColourGradient(COLOUR_LIGHT_BLUE, SHADE_NORMAL));
630 hr.top = DrawStringMultiLine(hr, header_msg, TC_FROMSTRING, SA_HOR_CENTER);
631 if (sel == nullptr) return;
632
633 hr.top = DrawStringMultiLine(hr, sel->info.server_name, TC_ORANGE, SA_HOR_CENTER); // game name
634 if (sel->status != NGLS_ONLINE) {
635 tr.top = DrawStringMultiLine(tr, header_msg, TC_FROMSTRING, SA_HOR_CENTER);
636 } else { // show game info
637 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));
638
639 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_LANDSCAPE, STR_CLIMATE_TEMPERATE_LANDSCAPE + to_underlying(sel->info.landscape))); // landscape
640
641 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_MAP_SIZE, sel->info.map_width, sel->info.map_height)); // map size
642
643 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_SERVER_VERSION, sel->info.server_revision)); // server version
644
645 StringID invite_or_address = sel->connection_string.starts_with("+") ? STR_NETWORK_SERVER_LIST_INVITE_CODE : STR_NETWORK_SERVER_LIST_SERVER_ADDRESS;
646 tr.top = DrawStringMultiLine(tr, GetString(invite_or_address, sel->connection_string)); // server address / invite code
647
648 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_START_DATE, sel->info.calendar_start)); // start date
649
650 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_CURRENT_DATE, sel->info.calendar_date)); // current date
651
652 const auto play_time = sel->info.ticks_playing / Ticks::TICKS_PER_SECOND;
653 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_PLAY_TIME, play_time / 60 / 60, (play_time / 60) % 60)); // play time
654
655 if (sel->info.gamescript_version != -1) {
656 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_GAMESCRIPT, sel->info.gamescript_name, sel->info.gamescript_version)); // gamescript name and version
657 }
658
660
661 if (!sel->info.compatible) {
662 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
663 } else if (sel->info.clients_on == sel->info.clients_max) {
664 /* Show: server full, when clients_on == max_clients */
665 DrawStringMultiLine(tr, STR_NETWORK_SERVER_LIST_SERVER_FULL, TC_FROMSTRING, SA_HOR_CENTER); // server full
666 } else if (sel->info.use_password) {
667 DrawStringMultiLine(tr, STR_NETWORK_SERVER_LIST_PASSWORD, TC_FROMSTRING, SA_HOR_CENTER); // password warning
668 }
669 }
670 }
671
672 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
673 {
674 switch (widget) {
675 case WID_NG_NAME: // Sort by name
676 case WID_NG_CLIENTS: // Sort by connected clients
677 case WID_NG_MAPSIZE: // Sort by map size
678 case WID_NG_DATE: // Sort by date
679 case WID_NG_YEARS: // Sort by years
680 case WID_NG_INFO: // Connectivity (green dot)
681 if (this->servers.SortType() == widget - WID_NG_NAME) {
682 this->servers.ToggleSortOrder();
683 if (this->list_pos != SLP_INVALID) this->list_pos = (ServerListPosition)this->servers.size() - this->list_pos - 1;
684 } else {
685 this->servers.SetSortType(widget - WID_NG_NAME);
686 this->servers.ForceResort();
687 this->SortNetworkGameList();
688 }
690 this->SetDirty();
691 break;
692
693 case WID_NG_MATRIX: { // Show available network games
694 auto it = this->vscroll->GetScrolledItemFromWidget(this->servers, pt.y, this, WID_NG_MATRIX);
695 this->server = (it != this->servers.end()) ? *it : nullptr;
696 this->list_pos = (server == nullptr) ? SLP_INVALID : it - this->servers.begin();
697 this->SetDirty();
698
699 if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
700 break;
701 }
702
703 case WID_NG_LASTJOINED: {
704 if (this->last_joined != nullptr) {
705 this->server = this->last_joined;
706
707 /* search the position of the newly selected server */
708 this->UpdateListPos();
710 this->SetDirty();
711
712 if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
713 }
714 break;
715 }
716
718 _network_coordinator_client.GetListing();
719 this->searched_internet = true;
720 break;
721
724 break;
725
726 case WID_NG_ADD: // Add a server
728 _settings_client.network.connect_to_ip,
729 STR_NETWORK_SERVER_LIST_ENTER_SERVER_ADDRESS,
730 NETWORK_HOSTNAME_PORT_LENGTH, // maximum number of characters including '\0'
732 break;
733
734 case WID_NG_START: // Start server
735 ShowNetworkStartServerWindow();
736 break;
737
738 case WID_NG_JOIN: // Join Game
739 if (this->server != nullptr) {
741 }
742 break;
743
744 case WID_NG_REFRESH: // Refresh
745 if (this->server != nullptr && !this->server->refreshing) NetworkQueryServer(this->server->connection_string);
746 break;
747
748 case WID_NG_NEWGRF: // NewGRF Settings
749 if (this->server != nullptr) ShowNewGRFSettings(false, false, false, this->server->info.grfconfig);
750 break;
751
752 case WID_NG_NEWGRF_MISSING: // Find missing content online
753 if (this->server != nullptr) ShowMissingContentWindow(this->server->info.grfconfig);
754 break;
755 }
756 }
757
763 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
764 {
765 this->servers.ForceRebuild();
766 this->SetDirty();
767 }
768
769 EventState OnKeyPress([[maybe_unused]] char32_t key, uint16_t keycode) override
770 {
772
773 /* handle up, down, pageup, pagedown, home and end */
774 if (this->vscroll->UpdateListPositionOnKeyPress(this->list_pos, keycode) == ES_HANDLED) {
775 if (this->list_pos == SLP_INVALID) return ES_HANDLED;
776
777 this->server = this->servers[this->list_pos];
778
779 /* Scroll to the new server if it is outside the current range. */
781
782 /* redraw window */
783 this->SetDirty();
784 return ES_HANDLED;
785 }
786
787 if (this->server != nullptr) {
788 if (keycode == WKC_DELETE) { // Press 'delete' to remove servers
789 NetworkGameListRemoveItem(this->server);
790 if (this->server == this->last_joined) this->last_joined = nullptr;
791 this->server = nullptr;
792 this->list_pos = SLP_INVALID;
793 }
794 }
795
796 return state;
797 }
798
799 void OnEditboxChanged(WidgetID wid) override
800 {
801 switch (wid) {
802 case WID_NG_FILTER: {
803 this->servers.ForceRebuild();
806 this->SetDirty();
807 break;
808 }
809
810 case WID_NG_CLIENT:
811 /* Validation of the name will happen once the user tries to join or start a game, as getting
812 * error messages while typing (e.g. when you clear the name) defeats the purpose of the check. */
813 _settings_client.network.client_name = this->name_editbox.text.GetText();
814 break;
815 }
816 }
817
818 void OnQueryTextFinished(std::optional<std::string> str) override
819 {
820 if (!str.has_value() || str->empty()) return;
821
822 _settings_client.network.connect_to_ip = std::move(*str);
823 NetworkAddServer(_settings_client.network.connect_to_ip);
824 NetworkRebuildHostList();
825 }
826
827 void OnResize() override
828 {
829 this->vscroll->SetCapacityFromWidget(this, WID_NG_MATRIX);
830 }
831
833 const IntervalTimer<TimerWindow> refresh_interval = {std::chrono::seconds(30), [this](uint) {
834 if (!this->searched_internet) return;
835
836 _network_coordinator_client.GetListing();
837 }};
838};
839
840Listing NetworkGameWindow::last_sorting = {false, 5};
841const std::initializer_list<GUIGameServerList::SortFunction * const> NetworkGameWindow::sorter_funcs = {
842 &NGameNameSorter,
843 &NGameClientSorter,
844 &NGameMapSizeSorter,
845 &NGameCalendarDateSorter,
846 &NGameTicksPlayingSorter,
847 &NGameAllowedSorter
848};
849
850const std::initializer_list<GUIGameServerList::FilterFunction * const> NetworkGameWindow::filter_funcs = {
851 &NGameSearchFilter
852};
853
854static std::unique_ptr<NWidgetBase> MakeResizableHeader()
855{
856 return std::make_unique<NWidgetServerListHeader>();
857}
858
859static constexpr std::initializer_list<NWidgetPart> _nested_network_game_widgets = {
860 /* TOP */
862 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
863 NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetStringTip(STR_NETWORK_SERVER_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
864 NWidget(WWT_DEFSIZEBOX, COLOUR_LIGHT_BLUE),
865 EndContainer(),
866 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_MAIN),
869 /* LEFT SIDE */
872 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NG_FILTER_LABEL), SetStringTip(STR_LIST_FILTER_TITLE),
873 NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_FILTER), SetMinimalSize(251, 0), SetFill(1, 0), SetResize(1, 0),
874 SetStringTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
875 EndContainer(),
878 NWidgetFunction(MakeResizableHeader),
879 NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NG_MATRIX), SetResize(1, 1), SetFill(1, 0),
880 SetMatrixDataTip(1, 0, STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT), SetScrollbar(WID_NG_SCROLLBAR),
881 EndContainer(),
882 NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NG_SCROLLBAR),
883 EndContainer(),
885 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NG_LASTJOINED_LABEL), SetFill(1, 0),
886 SetStringTip(STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER), SetResize(1, 0),
888 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_LASTJOINED), SetFill(1, 0), SetResize(1, 0),
889 SetToolTip(STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST_TOOLTIP),
890 EndContainer(),
891 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NG_LASTJOINED_SPACER), SetFill(0, 0),
892 EndContainer(),
893 EndContainer(),
894 EndContainer(),
895 /* RIGHT SIDE */
898 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NG_CLIENT_LABEL), SetStringTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME),
899 NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_CLIENT), SetMinimalSize(151, 0), SetFill(1, 0), SetResize(1, 0),
900 SetStringTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE, STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP),
901 EndContainer(),
903 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_DETAILS), SetMinimalSize(140, 0), SetMinimalTextLines(15, 0), SetResize(0, 1),
904 EndContainer(),
907 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),
908 EndContainer(),
909 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NG_NEWGRF_SEL),
910 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NEWGRF), SetFill(1, 0), SetStringTip(STR_MAPGEN_NEWGRF_SETTINGS, STR_MAPGEN_NEWGRF_SETTINGS_TOOLTIP),
911 EndContainer(),
913 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_JOIN), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_JOIN_GAME),
914 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_REFRESH), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_REFRESH, STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP),
915 EndContainer(),
916 EndContainer(),
917 EndContainer(),
918 EndContainer(),
919 EndContainer(),
920 /* BOTTOM */
922 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),
923 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),
924 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),
925 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),
926 EndContainer(),
927 EndContainer(),
928 /* Resize button. */
930 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
931 NWidget(WWT_RESIZEBOX, COLOUR_LIGHT_BLUE), SetResizeWidgetTypeTip(RWV_HIDE_BEVEL, STR_TOOLTIP_RESIZE),
932 EndContainer(),
933 EndContainer(),
934};
935
936static WindowDesc _network_game_window_desc(
937 WDP_CENTER, "list_servers", 1000, 730,
939 {},
940 _nested_network_game_widgets
941);
942
943void ShowNetworkGameWindow()
944{
945 static bool first = true;
947
948 /* Only show once */
949 if (first) {
950 first = false;
951 /* Add all servers from the config file to our list. */
952 for (const auto &iter : _network_host_list) {
953 NetworkAddServer(iter);
954 }
955 }
956
957 new NetworkGameWindow(_network_game_window_desc);
958}
959
960struct NetworkStartServerWindow : public Window {
963
964 NetworkStartServerWindow(WindowDesc &desc) : Window(desc), name_editbox(NETWORK_NAME_LENGTH)
965 {
967
968 this->querystrings[WID_NSS_GAMENAME] = &this->name_editbox;
969 this->name_editbox.text.Assign(_settings_client.network.server_name);
970
972 }
973
974 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
975 {
976 switch (widget) {
978 return GetString(STR_NETWORK_SERVER_VISIBILITY_LOCAL + _settings_client.network.server_game_type);
979
981 return GetString(STR_NETWORK_START_SERVER_CLIENTS_SELECT, _settings_client.network.max_clients);
982
984 return GetString(STR_NETWORK_START_SERVER_COMPANIES_SELECT, _settings_client.network.max_companies);
985
986 default:
987 return this->Window::GetWidgetString(widget, stringid);
988 }
989 }
990
991 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
992 {
993 switch (widget) {
995 size = maxdim(maxdim(GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_LOCAL), GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_PUBLIC)), GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_INVITE_ONLY));
996 size.width += padding.width;
997 size.height += padding.height;
998 break;
999 }
1000 }
1001
1002 void DrawWidget(const Rect &r, WidgetID widget) const override
1003 {
1004 switch (widget) {
1005 case WID_NSS_SETPWD:
1006 /* If password is set, draw red '*' next to 'Set password' button. */
1007 if (!_settings_client.network.server_password.empty()) DrawString(r.right + WidgetDimensions::scaled.framerect.left, this->width - WidgetDimensions::scaled.framerect.right, r.top, "*", TC_RED);
1008 }
1009 }
1010
1011 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1012 {
1013 switch (widget) {
1014 case WID_NSS_CANCEL: // Cancel button
1015 ShowNetworkGameWindow();
1016 break;
1017
1018 case WID_NSS_SETPWD: // Set password button
1019 this->widget_id = WID_NSS_SETPWD;
1020 ShowQueryString(_settings_client.network.server_password, STR_NETWORK_START_SERVER_SET_PASSWORD, NETWORK_PASSWORD_LENGTH, this, CS_ALPHANUMERAL, {});
1021 break;
1022
1023 case WID_NSS_CONNTYPE_BTN: // Connection type
1024 ShowDropDownList(this, BuildVisibilityDropDownList(), _settings_client.network.server_game_type, WID_NSS_CONNTYPE_BTN);
1025 break;
1026
1027 case WID_NSS_CLIENTS_BTND: case WID_NSS_CLIENTS_BTNU: // Click on up/down button for number of clients
1028 case WID_NSS_COMPANIES_BTND: case WID_NSS_COMPANIES_BTNU: // Click on up/down button for number of companies
1029 /* Don't allow too fast scrolling. */
1030 if (!this->flags.Test(WindowFlag::Timeout) || this->timeout_timer <= 1) {
1031 this->HandleButtonClick(widget);
1032 this->SetDirty();
1033 switch (widget) {
1034 default: NOT_REACHED();
1036 _settings_client.network.max_clients = Clamp(_settings_client.network.max_clients + widget - WID_NSS_CLIENTS_TXT, 2, MAX_CLIENTS);
1037 break;
1039 _settings_client.network.max_companies = Clamp(_settings_client.network.max_companies + widget - WID_NSS_COMPANIES_TXT, 1, MAX_COMPANIES);
1040 break;
1041 }
1042 }
1043 _left_button_clicked = false;
1044 break;
1045
1046 case WID_NSS_CLIENTS_TXT: // Click on number of clients
1047 this->widget_id = WID_NSS_CLIENTS_TXT;
1048 ShowQueryString(GetString(STR_JUST_INT, _settings_client.network.max_clients), STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS, 4, this, CS_NUMERAL, {});
1049 break;
1050
1051 case WID_NSS_COMPANIES_TXT: // Click on number of companies
1052 this->widget_id = WID_NSS_COMPANIES_TXT;
1053 ShowQueryString(GetString(STR_JUST_INT, _settings_client.network.max_companies), STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES, 3, this, CS_NUMERAL, {});
1054 break;
1055
1056 case WID_NSS_GENERATE_GAME: // Start game
1057 if (!CheckServerName()) return;
1058 _is_network_server = true;
1059 if (_ctrl_pressed) {
1061 } else {
1063 }
1064 break;
1065
1066 case WID_NSS_LOAD_GAME:
1067 if (!CheckServerName()) return;
1068 _is_network_server = true;
1070 break;
1071
1073 if (!CheckServerName()) return;
1074 _is_network_server = true;
1076 break;
1077
1079 if (!CheckServerName()) return;
1080 _is_network_server = true;
1082 break;
1083 }
1084 }
1085
1086 void OnDropdownSelect(WidgetID widget, int index, int) override
1087 {
1088 switch (widget) {
1090 _settings_client.network.server_game_type = (ServerGameType)index;
1091 break;
1092 default:
1093 NOT_REACHED();
1094 }
1095
1096 this->SetDirty();
1097 }
1098
1099 bool CheckServerName()
1100 {
1101 std::string str{this->name_editbox.text.GetText()};
1102 if (!NetworkValidateServerName(str)) return false;
1103
1104 SetSettingValue(GetSettingFromName("network.server_name")->AsStringSetting(), std::move(str));
1105 return true;
1106 }
1107
1112
1113 void OnQueryTextFinished(std::optional<std::string> str) override
1114 {
1115 if (!str.has_value()) return;
1116
1117 if (this->widget_id == WID_NSS_SETPWD) {
1118 _settings_client.network.server_password = std::move(*str);
1119 } else {
1120 auto value = ParseInteger<int32_t>(*str, 10, true);
1121 if (!value.has_value()) return;
1122 this->SetWidgetDirty(this->widget_id);
1123 switch (this->widget_id) {
1124 default: NOT_REACHED();
1125 case WID_NSS_CLIENTS_TXT: _settings_client.network.max_clients = Clamp(*value, 2, MAX_CLIENTS); break;
1126 case WID_NSS_COMPANIES_TXT: _settings_client.network.max_companies = Clamp(*value, 1, MAX_COMPANIES); break;
1127 }
1128 }
1129
1130 this->SetDirty();
1131 }
1132};
1133
1134static constexpr std::initializer_list<NWidgetPart> _nested_network_start_server_window_widgets = {
1136 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
1137 NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetStringTip(STR_NETWORK_START_SERVER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1138 EndContainer(),
1139 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NSS_BACKGROUND),
1143 /* Game name widgets */
1144 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NSS_GAMENAME_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME),
1145 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),
1146 EndContainer(),
1147
1150 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NSS_CONNTYPE_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_VISIBILITY_LABEL),
1151 NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_BTN), SetFill(1, 0), SetToolTip(STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP),
1152 EndContainer(),
1154 NWidget(NWID_SPACER), SetFill(1, 1),
1155 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_SETPWD), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_SET_PASSWORD, STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP),
1156 EndContainer(),
1157 EndContainer(),
1158
1161 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NSS_CLIENTS_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS),
1163 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),
1164 NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_TXT), SetFill(1, 0), SetToolTip(STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
1165 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),
1166 EndContainer(),
1167 EndContainer(),
1168
1170 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NSS_COMPANIES_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES),
1172 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),
1173 NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_TXT), SetFill(1, 0), SetToolTip(STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
1174 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),
1175 EndContainer(),
1176 EndContainer(),
1177 EndContainer(),
1178 EndContainer(),
1179
1181 /* 'generate game' and 'load game' buttons */
1183 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_GENERATE_GAME), SetStringTip(STR_INTRO_NEW_GAME, STR_INTRO_TOOLTIP_NEW_GAME), SetFill(1, 0),
1184 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_LOAD_GAME), SetStringTip(STR_INTRO_LOAD_GAME, STR_INTRO_TOOLTIP_LOAD_GAME), SetFill(1, 0),
1185 EndContainer(),
1186
1187 /* 'play scenario' and 'play heightmap' buttons */
1189 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_PLAY_SCENARIO), SetStringTip(STR_INTRO_PLAY_SCENARIO, STR_INTRO_TOOLTIP_PLAY_SCENARIO), SetFill(1, 0),
1190 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_PLAY_HEIGHTMAP), SetStringTip(STR_INTRO_PLAY_HEIGHTMAP, STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP), SetFill(1, 0),
1191 EndContainer(),
1192 EndContainer(),
1193
1195 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_CANCEL), SetStringTip(STR_BUTTON_CANCEL), SetMinimalSize(128, 12),
1196 EndContainer(),
1197 EndContainer(),
1198 EndContainer(),
1199};
1200
1201static WindowDesc _network_start_server_window_desc(
1202 WDP_CENTER, {}, 0, 0,
1204 {},
1205 _nested_network_start_server_window_widgets
1206);
1207
1208static void ShowNetworkStartServerWindow()
1209{
1210 if (!NetworkValidateOurClientName()) return;
1211
1213
1214 new NetworkStartServerWindow(_network_start_server_window_desc);
1215}
1216
1217/* The window below gives information about the connected clients
1218 * and also makes able to kick them (if server) and stuff like that. */
1219
1220extern void DrawCompanyIcon(CompanyID cid, int x, int y);
1221
1222static constexpr std::initializer_list<NWidgetPart> _nested_client_list_widgets = {
1224 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1225 NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_NETWORK_CLIENT_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1226 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
1227 NWidget(WWT_STICKYBOX, COLOUR_GREY),
1228 EndContainer(),
1229 NWidget(WWT_PANEL, COLOUR_GREY),
1231 NWidget(WWT_FRAME, COLOUR_GREY), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0),
1233 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_NAME),
1234 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),
1235 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),
1236 EndContainer(),
1240 NWidget(WWT_TEXT, INVALID_COLOUR), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY),
1241 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_CL_SERVER_VISIBILITY), SetToolTip(STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP),
1242 EndContainer(),
1244 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_INVITE_CODE),
1245 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),
1246 EndContainer(),
1248 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE),
1249 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),
1250 EndContainer(),
1251 EndContainer(),
1252 EndContainer(),
1253 EndContainer(),
1254 NWidget(WWT_FRAME, COLOUR_GREY), SetStringTip(STR_NETWORK_CLIENT_LIST_PLAYER),
1256 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_NETWORK_CLIENT_LIST_PLAYER_NAME),
1257 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),
1258 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),
1259 EndContainer(),
1260 EndContainer(),
1261 EndContainer(),
1262 EndContainer(),
1266 EndContainer(),
1268 NWidget(WWT_PANEL, COLOUR_GREY),
1269 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),
1270 EndContainer(),
1271 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
1272 EndContainer(),
1273};
1274
1275static WindowDesc _client_list_desc(
1276 WDP_AUTO, "list_clients", 220, 300,
1278 {},
1279 _nested_client_list_widgets
1280);
1281
1286static void AdminClientKickCallback(Window *, bool confirmed)
1287{
1288 if (confirmed) NetworkServerKickClient(_admin_client_id, {});
1289}
1290
1295static void AdminClientBanCallback(Window *, bool confirmed)
1296{
1297 if (confirmed) NetworkServerKickOrBanIP(_admin_client_id, true, {});
1298}
1299
1304static void AdminCompanyResetCallback(Window *, bool confirmed)
1305{
1306 if (confirmed) {
1309 }
1310}
1311
1319class ButtonCommon {
1320public:
1323 Colours colour;
1325 uint height;
1326 uint width;
1327
1328 ButtonCommon(SpriteID sprite, StringID tooltip, Colours colour, bool disabled = false) :
1329 sprite(sprite),
1331 colour(colour),
1333 {
1335 this->height = d.height + WidgetDimensions::scaled.framerect.Vertical();
1336 this->width = d.width + WidgetDimensions::scaled.framerect.Horizontal();
1337 }
1338 virtual ~ButtonCommon() = default;
1339
1345 virtual void OnClick(struct NetworkClientListWindow *w, Point pt) = 0;
1346};
1347
1351template <typename T>
1352class Button : public ButtonCommon {
1353private:
1354 typedef void (*ButtonCallback)(struct NetworkClientListWindow *w, Point pt, T id);
1355 T id;
1357
1358public:
1359 Button(SpriteID sprite, StringID tooltip, Colours colour, T id, ButtonCallback proc, bool disabled = false) :
1360 ButtonCommon(sprite, tooltip, colour, disabled),
1361 id(id),
1362 proc(proc)
1363 {
1364 assert(proc != nullptr);
1365 }
1366
1367 void OnClick(struct NetworkClientListWindow *w, Point pt) override
1368 {
1369 if (this->disabled) return;
1370
1371 this->proc(w, pt, this->id);
1372 }
1373};
1374
1375using CompanyButton = Button<CompanyID>;
1376using ClientButton = Button<ClientID>;
1377
1382public:
1383 std::vector<std::unique_ptr<ButtonCommon>> buttons{};
1384
1385 virtual ~ButtonLine() = default;
1386
1391 virtual void Draw(Rect r) const = 0;
1392
1393 template <typename T, typename...TArgs>
1394 T &AddButton(TArgs &&... args)
1395 {
1396 auto &button = this->buttons.emplace_back(std::make_unique<T>(std::forward<TArgs &&>(args)...));
1397 return static_cast<T &>(*button);
1398 }
1399
1406 ButtonCommon *GetButton(Rect r, const Point &pt) const
1407 {
1408 bool rtl = _current_text_dir == TD_RTL;
1409 for (auto &button : this->buttons) {
1410 if (r.WithWidth(button->width, !rtl).Contains(pt)) return button.get();
1411 r = r.Indent(button->width + WidgetDimensions::scaled.hsep_normal, !rtl);
1412 }
1413 return nullptr;
1414 }
1415
1422 virtual std::optional<EncodedString> GetTooltip(Rect r, const Point &pt) const
1423 {
1424 ButtonCommon *button = this->GetButton(r, pt);
1425 if (button == nullptr) return {};
1426 return GetEncodedString(button->tooltip);
1427 }
1428
1429protected:
1436 {
1437 bool rtl = _current_text_dir == TD_RTL;
1438 for (auto &button : buttons) {
1439 Rect br = r.CentreToHeight(button->height).WithWidth(button->width, !rtl);
1440 DrawFrameRect(br, button->colour, {});
1441 DrawSpriteIgnorePadding(button->sprite, PAL_NONE, br, SA_CENTER);
1442 if (button->disabled) {
1443 GfxFillRect(br.Shrink(WidgetDimensions::scaled.bevel), GetColourGradient(button->colour, SHADE_DARKER), FILLRECT_CHECKER);
1444 }
1445 r = r.Indent(button->width + WidgetDimensions::scaled.hsep_normal, !rtl);
1446 }
1447 return r;
1448 }
1449};
1450
1451class CompanyButtonLine : public ButtonLine {
1452public:
1453 CompanyButtonLine(CompanyID company_id) : company_id(company_id) {}
1454
1455 void Draw(Rect r) const override
1456 {
1457 bool rtl = _current_text_dir == TD_RTL;
1458 r = this->DrawButtons(r);
1459
1460 Dimension d = GetScaledSpriteSize(SPR_COMPANY_ICON);
1461 PaletteID pal = Company::IsValidID(this->company_id) ? GetCompanyPalette(this->company_id) : PALETTE_TO_GREY;
1462 DrawSpriteIgnorePadding(SPR_COMPANY_ICON, pal, r.WithWidth(d.width, rtl), SA_CENTER);
1463
1465 if (this->company_id == COMPANY_SPECTATOR) {
1466 DrawString(tr, STR_NETWORK_CLIENT_LIST_SPECTATORS, TC_SILVER);
1467 } else if (this->company_id == COMPANY_NEW_COMPANY) {
1468 DrawString(tr, STR_NETWORK_CLIENT_LIST_NEW_COMPANY, TC_WHITE);
1469 } else {
1470 DrawString(tr, GetString(STR_COMPANY_NAME, this->company_id, this->company_id), TC_SILVER);
1471 }
1472 };
1473
1474private:
1475 CompanyID company_id;
1476};
1477
1478class ClientButtonLine : public ButtonLine {
1479public:
1480 ClientButtonLine(ClientPoolID client_pool_id) : client_pool_id(client_pool_id) {}
1481
1482 void Draw(Rect r) const override
1483 {
1484 const NetworkClientInfo *ci = NetworkClientInfo::GetIfValid(this->client_pool_id);
1485 if (ci == nullptr) return;
1486
1487 bool rtl = _current_text_dir == TD_RTL;
1488 r = this->DrawButtons(r);
1489
1491
1492 SpriteID player_icon = 0;
1493 if (ci->client_id == _network_own_client_id) {
1494 player_icon = SPR_PLAYER_SELF;
1495 } else if (ci->client_id == CLIENT_ID_SERVER) {
1496 player_icon = SPR_PLAYER_HOST;
1497 }
1498
1499 if (player_icon != 0) {
1500 Dimension d = GetScaledSpriteSize(player_icon);
1501 DrawSpriteIgnorePadding(player_icon, PALETTE_TO_GREY, r.WithWidth(d.width, rtl), SA_CENTER);
1502 tr = tr.Indent(d.width + WidgetDimensions::scaled.hsep_normal, rtl);
1503 }
1504
1505 DrawString(tr, GetString(STR_JUST_RAW_STRING, ci->client_name), TC_BLACK);
1506 }
1507
1508 std::optional<EncodedString> GetTooltip(Rect r, const Point &pt) const override
1509 {
1510 bool rtl = _current_text_dir == TD_RTL;
1511 Dimension d = GetScaledSpriteSize(SPR_PLAYER_SELF);
1512
1513 if (r.WithWidth(d.width, rtl).Contains(pt)) {
1514 const NetworkClientInfo *ci = NetworkClientInfo::GetIfValid(this->client_pool_id);
1515 if (ci != nullptr) {
1516 if (ci->client_id == _network_own_client_id) {
1517 return GetEncodedString(STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP);
1518 } else if (ci->client_id == CLIENT_ID_SERVER) {
1519 return GetEncodedString(STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP);
1520 }
1521 }
1522 }
1523
1524 return this->ButtonLine::GetTooltip(r, pt);
1525 }
1526
1527private:
1528 ClientPoolID client_pool_id;
1529};
1530
1534struct NetworkClientListWindow : Window {
1535private:
1547
1549
1551 CompanyID dd_company_id = CompanyID::Invalid();
1552
1553 Scrollbar *vscroll = nullptr;
1554 uint line_height = 0;
1555 int hover_index = -1;
1556
1557 std::vector<std::unique_ptr<ButtonLine>> buttons{};
1558
1565 static void OnClickCompanyChat([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, CompanyID company_id)
1566 {
1567 ShowNetworkChatQueryWindow(DESTTYPE_TEAM, company_id.base());
1568 }
1569
1576 static void OnClickCompanyJoin([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, CompanyID company_id)
1577 {
1578 if (_network_server) {
1581 } else {
1582 NetworkClientRequestMove(company_id);
1583 }
1584 }
1585
1591 static void OnClickCompanyNew([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, CompanyID)
1592 {
1593 Command<Commands::CompanyControl>::Post(CompanyCtrlAction::New, CompanyID::Invalid(), CompanyRemoveReason::None, _network_own_client_id);
1594 }
1595
1602 static void OnClickClientAdmin([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, ClientID client_id)
1603 {
1604 DropDownList list;
1605 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK, to_underlying(DropDownAction::AdminKickClient)));
1606 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN, to_underlying(DropDownAction::AdminBanClient)));
1607
1608 Rect wi_rect;
1609 wi_rect.left = pt.x;
1610 wi_rect.right = pt.x;
1611 wi_rect.top = pt.y;
1612 wi_rect.bottom = pt.y;
1613
1614 w->dd_client_id = client_id;
1615 ShowDropDownListAt(w, std::move(list), -1, WID_CL_MATRIX, wi_rect, COLOUR_GREY, DropDownOption::InstantClose);
1616 }
1617
1624 static void OnClickCompanyAdmin([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, CompanyID company_id)
1625 {
1626 DropDownList list;
1627 if (_network_server) list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET, to_underlying(DropDownAction::AdminResetCompany), NetworkCompanyHasClients(company_id)));
1628 if (const Company *c = Company::GetIfValid(company_id); c != nullptr) {
1629 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_ALLOW_ANY, to_underlying(DropDownAction::CompanyAllowAny), c->allow_any));
1630 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_ALLOW_LISTED, to_underlying(DropDownAction::CompanyAllowListed), !c->allow_any));
1631 }
1632
1633 Rect wi_rect;
1634 wi_rect.left = pt.x;
1635 wi_rect.right = pt.x;
1636 wi_rect.top = pt.y;
1637 wi_rect.bottom = pt.y;
1638
1639 w->dd_company_id = company_id;
1640 ShowDropDownListAt(w, std::move(list), -1, WID_CL_MATRIX, wi_rect, COLOUR_GREY, DropDownOption::InstantClose);
1641 }
1642
1649 static void OnClickClientChat([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, ClientID client_id)
1650 {
1652 }
1653
1654 static void OnClickClientAuthorize([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, ClientID client_id)
1655 {
1657 Command<Commands::CompanyAllowListControl>::Post(CompanyAllowListCtrlAction::AddKey, NetworkClientInfo::GetByClientID(client_id)->public_key);
1658 }
1659
1666 void RebuildListCompany(CompanyID company_id, CompanyID client_playas, bool can_join_company)
1667 {
1668 ButtonLine &company_line = *this->buttons.emplace_back(std::make_unique<CompanyButtonLine>(company_id));
1669 if (_network_server || company_id == _local_company) {
1670 company_line.AddButton<CompanyButton>(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP, COLOUR_RED, company_id, &NetworkClientListWindow::OnClickCompanyAdmin, company_id == COMPANY_SPECTATOR);
1671 }
1672 ButtonCommon &chat_button = company_line.AddButton<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);
1673 if (can_join_company) company_line.AddButton<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);
1674
1675 bool has_players = false;
1676 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1677 if (ci->client_playas != company_id) continue;
1678 has_players = true;
1679
1680 ButtonLine &line = *this->buttons.emplace_back(std::make_unique<ClientButtonLine>(ci->index));
1681 if (_network_server) line.AddButton<ClientButton>(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP, COLOUR_RED, ci->client_id, &NetworkClientListWindow::OnClickClientAdmin, _network_own_client_id == ci->client_id);
1682 if (_network_own_client_id != ci->client_id) line.AddButton<ClientButton>(SPR_CHAT, STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP, COLOUR_ORANGE, ci->client_id, &NetworkClientListWindow::OnClickClientChat);
1683 if (_network_own_client_id != ci->client_id && client_playas != COMPANY_SPECTATOR && !ci->CanJoinCompany(client_playas)) line.AddButton<ClientButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_COMPANY_AUTHORIZE_TOOLTIP, COLOUR_GREEN, ci->client_id, &NetworkClientListWindow::OnClickClientAuthorize);
1684 }
1685
1686 /* Disable the chat button when there are players in this company. */
1687 chat_button.disabled = !has_players;
1688 }
1689
1694 {
1696 CompanyID client_playas = own_ci == nullptr ? COMPANY_SPECTATOR : own_ci->client_playas;
1697
1698 this->buttons.clear();
1699
1700 /* As spectator, show a line to create a new company. */
1701 if (client_playas == COMPANY_SPECTATOR && !NetworkMaxCompaniesReached()) {
1702 ButtonLine &line = *this->buttons.emplace_back(std::make_unique<CompanyButtonLine>(COMPANY_NEW_COMPANY));
1703 line.AddButton<CompanyButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP, COLOUR_ORANGE, COMPANY_SPECTATOR, &NetworkClientListWindow::OnClickCompanyNew);
1704 }
1705
1706 if (client_playas != COMPANY_SPECTATOR) {
1707 this->RebuildListCompany(client_playas, client_playas, false);
1708 }
1709
1710 /* Companies */
1711 for (const Company *c : Company::Iterate()) {
1712 if (c->index == client_playas) continue;
1713
1714 this->RebuildListCompany(c->index, client_playas, _network_server || c->allow_any || (own_ci != nullptr && c->allow_list.Contains(own_ci->public_key)));
1715 }
1716
1717 /* Spectators */
1718 this->RebuildListCompany(COMPANY_SPECTATOR, client_playas, client_playas != COMPANY_SPECTATOR);
1719
1720 this->vscroll->SetCount(this->buttons.size());
1721 }
1722
1723public:
1725 {
1726 this->CreateNestedTree();
1727 this->vscroll = this->GetScrollbar(WID_CL_SCROLLBAR);
1728 this->OnInvalidateData();
1729 this->FinishInitNested(window_number);
1730 }
1731
1732 void OnInit() override
1733 {
1734 this->RebuildList();
1735 }
1736
1737 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1738 {
1739 this->RebuildList();
1740
1741 /* Currently server information is not synced to clients, so we cannot show it on clients. */
1744 }
1745
1746 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1747 {
1748 switch (widget) {
1749 case WID_CL_SERVER_NAME:
1750 case WID_CL_CLIENT_NAME: {
1751 std::string str;
1752 if (widget == WID_CL_SERVER_NAME) {
1753 str = GetString(STR_JUST_RAW_STRING, _network_server ? _settings_client.network.server_name : _network_server_name);
1754 } else {
1756 str = GetString(STR_JUST_RAW_STRING, own_ci != nullptr ? own_ci->client_name : _settings_client.network.client_name);
1757 }
1758 size = GetStringBoundingBox(str);
1759 size.width = std::min(size.width, static_cast<uint>(ScaleGUITrad(200))); // By default, don't open the window too wide.
1760 break;
1761 }
1762
1764 size = maxdim(maxdim(GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_LOCAL), GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_PUBLIC)), GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_INVITE_ONLY));
1765 size.width += padding.width;
1766 size.height += padding.height;
1767 break;
1768
1769 case WID_CL_MATRIX: {
1770 uint height = std::max({GetScaledSpriteSize(SPR_COMPANY_ICON).height, GetScaledSpriteSize(SPR_JOIN).height, GetScaledSpriteSize(SPR_ADMIN).height, GetScaledSpriteSize(SPR_CHAT).height});
1771 height += WidgetDimensions::scaled.framerect.Vertical();
1772 this->line_height = std::max(height, (uint)GetCharacterHeight(FS_NORMAL)) + padding.height;
1773
1774 resize.width = 1;
1775 fill.height = resize.height = this->line_height;
1776 size.height = std::max(size.height, 5 * this->line_height);
1777 break;
1778 }
1779 }
1780 }
1781
1782 void OnResize() override
1783 {
1784 this->vscroll->SetCapacityFromWidget(this, WID_CL_MATRIX);
1785 }
1786
1787 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
1788 {
1789 switch (widget) {
1790 case WID_CL_SERVER_NAME:
1791 return _network_server ? _settings_client.network.server_name : _network_server_name;
1792
1794 return GetString(STR_NETWORK_SERVER_VISIBILITY_LOCAL + _settings_client.network.server_game_type);
1795
1798
1800 return GetString(STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_UNKNOWN + _network_server_connection_type);
1801
1802 case WID_CL_CLIENT_NAME: {
1804 return own_ci != nullptr ? own_ci->client_name : _settings_client.network.client_name;
1805 }
1806
1808 return GetString(STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT, NetworkClientInfo::GetNumItems(), Company::GetNumItems(), NetworkMaxCompaniesAllowed());
1809
1810 default:
1811 return this->Window::GetWidgetString(widget, stringid);
1812 }
1813 }
1814
1815 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1816 {
1817 switch (widget) {
1819 if (!_network_server) break;
1820
1821 this->query_widget = WID_CL_SERVER_NAME_EDIT;
1822 ShowQueryString(_settings_client.network.server_name, STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION, NETWORK_NAME_LENGTH, this, CS_ALPHANUMERAL, QueryStringFlag::LengthIsInChars);
1823 break;
1824
1827 this->query_widget = WID_CL_CLIENT_NAME_EDIT;
1828 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);
1829 break;
1830 }
1832 if (!_network_server) break;
1833
1834 ShowDropDownList(this, BuildVisibilityDropDownList(), _settings_client.network.server_game_type, WID_CL_SERVER_VISIBILITY);
1835 break;
1836
1837 case WID_CL_MATRIX: {
1838 auto it = this->vscroll->GetScrolledItemFromWidget(this->buttons, pt.y, this, WID_CL_MATRIX);
1839 if (it == std::end(this->buttons)) break;
1840
1841 Rect r = this->GetWidget<NWidgetBase>(WID_CL_MATRIX)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
1842 ButtonCommon *button = (*it)->GetButton(r, pt);
1843 if (button == nullptr) break;
1844
1845 button->OnClick(this, pt);
1846 break;
1847 }
1848 }
1849 }
1850
1851 bool OnTooltip([[maybe_unused]] Point pt, WidgetID widget, TooltipCloseCondition close_cond) override
1852 {
1853 switch (widget) {
1854 case WID_CL_MATRIX: {
1855 auto it = this->vscroll->GetScrolledItemFromWidget(this->buttons, pt.y, this, WID_CL_MATRIX);
1856 if (it == std::end(this->buttons)) break;
1857
1858 Rect r = this->GetWidget<NWidgetBase>(WID_CL_MATRIX)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
1859 auto tooltip = (*it)->GetTooltip(r, pt);
1860 if (!tooltip.has_value()) break;
1861
1862 GuiShowTooltips(this, std::move(*tooltip), close_cond);
1863 return true;
1864 };
1865 }
1866
1867 return false;
1868 }
1869
1870 void OnDropdownClose(Point pt, WidgetID widget, int index, int click_result, bool instant_close) override
1871 {
1872 /* If you close the dropdown outside the list, don't take any action. */
1873 if (widget == WID_CL_MATRIX) return;
1874
1875 Window::OnDropdownClose(pt, widget, index, click_result, instant_close);
1876 }
1877
1878 void OnDropdownSelect(WidgetID widget, int index, int) override
1879 {
1880 switch (widget) {
1882 if (!_network_server) break;
1883
1884 _settings_client.network.server_game_type = (ServerGameType)index;
1886 break;
1887
1888 case WID_CL_MATRIX: {
1889 QueryCallbackProc *callback = nullptr;
1890
1891 EncodedString text;
1892 switch (static_cast<DropDownAction>(index)) {
1894 _admin_client_id = this->dd_client_id;
1895 callback = AdminClientKickCallback;
1896 text = GetEncodedString(STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK, NetworkClientInfo::GetByClientID(_admin_client_id)->client_name);
1897 break;
1898
1900 _admin_client_id = this->dd_client_id;
1901 callback = AdminClientBanCallback;
1902 text = GetEncodedString(STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN, NetworkClientInfo::GetByClientID(_admin_client_id)->client_name);
1903 break;
1904
1906 _admin_company_id = this->dd_company_id;
1907 callback = AdminCompanyResetCallback;
1908 text = GetEncodedString(STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET, _admin_company_id);
1909 break;
1910
1912 AutoRestoreBackup cur_company(_current_company, this->dd_company_id);
1913 Command<Commands::CompanyAllowListControl>::Post(CompanyAllowListCtrlAction::AllowAny, {});
1914 return;
1915 }
1916
1918 AutoRestoreBackup cur_company(_current_company, this->dd_company_id);
1919 Command<Commands::CompanyAllowListControl>::Post(CompanyAllowListCtrlAction::AllowListed, {});
1920 return;
1921 }
1922
1923 default:
1924 NOT_REACHED();
1925 }
1926
1927 assert(callback != nullptr);
1928
1929 /* Always ask confirmation for all admin actions. */
1930 ShowQuery(
1931 GetEncodedString(STR_NETWORK_CLIENT_LIST_ASK_CAPTION),
1932 std::move(text),
1933 this, callback);
1934
1935 break;
1936 }
1937
1938 default:
1939 NOT_REACHED();
1940 }
1941
1942 this->SetDirty();
1943 }
1944
1945 void OnQueryTextFinished(std::optional<std::string> str) override
1946 {
1947 if (!str.has_value()) return;
1948
1949 switch (this->query_widget) {
1950 default: NOT_REACHED();
1951
1953 if (!_network_server) break;
1954
1955 SetSettingValue(GetSettingFromName("network.server_name")->AsStringSetting(), *str);
1956 this->InvalidateData();
1957 break;
1958 }
1959
1961 SetSettingValue(GetSettingFromName("network.client_name")->AsStringSetting(), *str);
1962 this->InvalidateData();
1963 break;
1964 }
1965 }
1966 }
1967
1968 void DrawWidget(const Rect &r, WidgetID widget) const override
1969 {
1970 switch (widget) {
1971 case WID_CL_MATRIX: {
1972 Rect ir = r.WithHeight(this->line_height).Shrink(WidgetDimensions::scaled.framerect, RectPadding::zero);
1973
1974 if (this->hover_index >= 0) {
1975 Rect br = r.WithHeight(this->line_height).Translate(0, this->hover_index * this->line_height);
1977 }
1978
1979 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->buttons);
1980 for (auto it = first; it != last; ++it) {
1981 (*it)->Draw(ir);
1982 ir = ir.Translate(0, this->line_height);
1983 }
1984
1985 break;
1986 }
1987 }
1988 }
1989
1990 void OnMouseOver([[maybe_unused]] Point pt, WidgetID widget) override
1991 {
1992 if (widget != WID_CL_MATRIX) {
1993 if (this->hover_index != -1) {
1994 this->hover_index = -1;
1996 }
1997 } else {
1998 int index = this->GetRowFromWidget(pt.y, widget, 0, -1);
1999 if (index != this->hover_index) {
2000 this->hover_index = index;
2002 }
2003 }
2004 }
2005};
2006
2007void ShowClientList()
2008{
2010}
2011
2016
2017struct NetworkJoinStatusWindow : Window {
2018 std::shared_ptr<NetworkAuthenticationPasswordRequest> request{};
2019
2020 NetworkJoinStatusWindow(WindowDesc &desc) : Window(desc)
2021 {
2024 }
2025
2026 void DrawWidget(const Rect &r, WidgetID widget) const override
2027 {
2028 switch (widget) {
2029 case WID_NJS_PROGRESS_BAR: {
2030 /* Draw the % complete with a bar and a text */
2032 Rect ir = r.Shrink(WidgetDimensions::scaled.bevel);
2033 uint8_t progress; // used for progress bar
2034 switch (_network_join_status) {
2035 case NETWORK_JOIN_STATUS_CONNECTING:
2036 case NETWORK_JOIN_STATUS_AUTHORIZING:
2037 case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
2038 progress = 10; // first two stages 10%
2039 break;
2040 case NETWORK_JOIN_STATUS_WAITING:
2041 progress = 15; // third stage is 15%
2042 break;
2043 case NETWORK_JOIN_STATUS_DOWNLOADING:
2044 if (_network_join_bytes_total == 0) {
2045 progress = 15; // We don't have the final size yet; the server is still compressing!
2046 break;
2047 }
2048 [[fallthrough]];
2049
2050 default: // Waiting is 15%, so the remaining downloading of the map is maximum 70%
2051 progress = 15 + _network_join_bytes * (100 - 15) / _network_join_bytes_total;
2052 break;
2053 }
2054 DrawFrameRect(ir.WithWidth(ir.Width() * progress / 100, _current_text_dir == TD_RTL), COLOUR_MAUVE, {});
2055 DrawString(ir.left, ir.right, CentreBounds(ir.top, ir.bottom, GetCharacterHeight(FS_NORMAL)), STR_NETWORK_CONNECTING_1 + _network_join_status, TC_FROMSTRING, SA_HOR_CENTER);
2056 break;
2057 }
2058
2060 switch (_network_join_status) {
2061 case NETWORK_JOIN_STATUS_WAITING:
2062 DrawStringMultiLine(r, GetString(STR_NETWORK_CONNECTING_WAITING, _network_join_waiting), TC_FROMSTRING, SA_CENTER);
2063 break;
2064
2065 case NETWORK_JOIN_STATUS_DOWNLOADING:
2066 if (_network_join_bytes_total == 0) {
2067 DrawStringMultiLine(r, GetString(STR_NETWORK_CONNECTING_DOWNLOADING_1, _network_join_bytes), TC_FROMSTRING, SA_CENTER);
2068 } else {
2069 DrawStringMultiLine(r, GetString(STR_NETWORK_CONNECTING_DOWNLOADING_2, _network_join_bytes, _network_join_bytes_total), TC_FROMSTRING, SA_CENTER);
2070 }
2071 break;
2072
2073 default:
2074 break;
2075 }
2076 break;
2077 }
2078 }
2079
2080 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2081 {
2082 switch (widget) {
2084 /* Account for the statuses */
2085 for (uint i = 0; i < NETWORK_JOIN_STATUS_END; i++) {
2086 size = maxdim(size, GetStringBoundingBox(STR_NETWORK_CONNECTING_1 + i));
2087 }
2088 /* For the number of waiting (other) players */
2089 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_CONNECTING_WAITING, GetParamMaxValue(MAX_CLIENTS))));
2090 /* We need some spacing for the 'border' */
2091 size.height += WidgetDimensions::scaled.frametext.Horizontal();
2092 size.width += WidgetDimensions::scaled.frametext.Vertical();
2093 break;
2094
2095 case WID_NJS_PROGRESS_TEXT: {
2096 /* Account for downloading ~ 10 MiB */
2097 uint64_t max_digits = GetParamMaxDigits(8);
2098 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_CONNECTING_DOWNLOADING_1, max_digits, max_digits)));
2099 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_CONNECTING_DOWNLOADING_1, max_digits, max_digits)));
2100 break;
2101 }
2102 }
2103 }
2104
2105 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2106 {
2107 if (widget == WID_NJS_CANCELOK) { // Disconnect button
2109 SwitchToMode(SM_MENU);
2110 ShowNetworkGameWindow();
2111 }
2112 }
2113
2114 void OnQueryTextFinished(std::optional<std::string> str) override
2115 {
2116 if (!str.has_value() || str->empty() || this->request == nullptr) {
2118 return;
2119 }
2120
2121 this->request->Reply(*str);
2122 }
2123};
2124
2125static constexpr std::initializer_list<NWidgetPart> _nested_network_join_status_window_widgets = {
2126 NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_NETWORK_CONNECTING_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2127 NWidget(WWT_PANEL, COLOUR_GREY),
2129 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NJS_PROGRESS_BAR), SetFill(1, 0),
2130 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NJS_PROGRESS_TEXT), SetFill(1, 0), SetMinimalSize(350, 0),
2131 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NJS_CANCELOK), SetMinimalSize(101, 12), SetStringTip(STR_NETWORK_CONNECTION_DISCONNECT), SetFill(1, 0),
2132 EndContainer(),
2133 EndContainer(),
2134};
2135
2136static WindowDesc _network_join_status_window_desc(
2137 WDP_CENTER, {}, 0, 0,
2140 _nested_network_join_status_window_widgets
2141);
2142
2143void ShowJoinStatusWindow()
2144{
2146 new NetworkJoinStatusWindow(_network_join_status_window_desc);
2147}
2148
2149void ShowNetworkNeedPassword(std::shared_ptr<NetworkAuthenticationPasswordRequest> request)
2150{
2152 if (w == nullptr) return;
2153 w->request = std::move(request);
2154
2155 ShowQueryString({}, STR_NETWORK_NEED_GAME_PASSWORD_CAPTION, NETWORK_PASSWORD_LENGTH, w, CS_ALPHANUMERAL, {});
2156}
2157
2161struct NetworkAskRelayWindow : public Window {
2164 std::string token{};
2165
2166 NetworkAskRelayWindow(WindowDesc &desc, Window *parent, std::string_view server_connection_string, std::string &&relay_connection_string, std::string &&token) :
2167 Window(desc),
2170 token(std::move(token))
2171 {
2172 this->parent = parent;
2173 this->InitNested(0);
2174 }
2175
2176 void Close(int data = 0) override
2177 {
2178 if (data == NRWCD_UNHANDLED) _network_coordinator_client.ConnectFailure(this->token, 0);
2179 this->Window::Close();
2180 }
2181
2182 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2183 {
2184 if (widget == WID_NAR_TEXT) {
2185 size = GetStringBoundingBox(GetString(STR_NETWORK_ASK_RELAY_TEXT, this->server_connection_string, this->relay_connection_string));
2186 }
2187 }
2188
2189 void DrawWidget(const Rect &r, WidgetID widget) const override
2190 {
2191 if (widget == WID_NAR_TEXT) {
2192 DrawStringMultiLine(r, GetString(STR_NETWORK_ASK_RELAY_TEXT, this->server_connection_string, this->relay_connection_string), TC_FROMSTRING, SA_CENTER);
2193 }
2194 }
2195
2196 void FindWindowPlacementAndResize(int, int, bool) override
2197 {
2198 /* Position query window over the calling window, ensuring it's within screen bounds. */
2199 this->left = Clamp(parent->left + (parent->width / 2) - (this->width / 2), 0, _screen.width - this->width);
2200 this->top = Clamp(parent->top + (parent->height / 2) - (this->height / 2), 0, _screen.height - this->height);
2201 this->SetDirty();
2202 }
2203
2204 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2205 {
2206 switch (widget) {
2207 case WID_NAR_NO:
2208 _network_coordinator_client.ConnectFailure(this->token, 0);
2209 this->Close(NRWCD_HANDLED);
2210 break;
2211
2212 case WID_NAR_YES_ONCE:
2213 _network_coordinator_client.StartTurnConnection(this->token);
2214 this->Close(NRWCD_HANDLED);
2215 break;
2216
2217 case WID_NAR_YES_ALWAYS:
2218 _settings_client.network.use_relay_service = UseRelayService::Allow;
2219 _network_coordinator_client.StartTurnConnection(this->token);
2220 this->Close(NRWCD_HANDLED);
2221 break;
2222 }
2223 }
2224};
2225
2226static constexpr std::initializer_list<NWidgetPart> _nested_network_ask_relay_widgets = {
2228 NWidget(WWT_CLOSEBOX, COLOUR_RED),
2229 NWidget(WWT_CAPTION, COLOUR_RED, WID_NAR_CAPTION), SetStringTip(STR_NETWORK_ASK_RELAY_CAPTION),
2230 EndContainer(),
2231 NWidget(WWT_PANEL, COLOUR_RED),
2235 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NAR_NO), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_RELAY_NO),
2236 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NAR_YES_ONCE), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_RELAY_YES_ONCE),
2237 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NAR_YES_ALWAYS), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_RELAY_YES_ALWAYS),
2238 EndContainer(),
2239 EndContainer(),
2240 EndContainer(),
2241};
2242
2243static WindowDesc _network_ask_relay_desc(
2244 WDP_CENTER, {}, 0, 0,
2247 _nested_network_ask_relay_widgets
2248);
2249
2256void ShowNetworkAskRelay(std::string_view server_connection_string, std::string &&relay_connection_string, std::string &&token)
2257{
2259
2260 Window *parent = GetMainWindow();
2261 new NetworkAskRelayWindow(_network_ask_relay_desc, parent, server_connection_string, std::move(relay_connection_string), std::move(token));
2262}
2263
2267struct NetworkAskSurveyWindow : public Window {
2268 NetworkAskSurveyWindow(WindowDesc &desc, Window *parent) :
2269 Window(desc)
2270 {
2271 this->parent = parent;
2272 this->InitNested(0);
2273 }
2274
2275 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2276 {
2277 if (widget == WID_NAS_TEXT) {
2278 size = GetStringBoundingBox(STR_NETWORK_ASK_SURVEY_TEXT);
2279 }
2280 }
2281
2282 void DrawWidget(const Rect &r, WidgetID widget) const override
2283 {
2284 if (widget == WID_NAS_TEXT) {
2285 DrawStringMultiLine(r, STR_NETWORK_ASK_SURVEY_TEXT, TC_BLACK, SA_CENTER);
2286 }
2287 }
2288
2289 void FindWindowPlacementAndResize(int, int, bool) override
2290 {
2291 /* Position query window over the calling window, ensuring it's within screen bounds. */
2292 this->left = Clamp(parent->left + (parent->width / 2) - (this->width / 2), 0, _screen.width - this->width);
2293 this->top = Clamp(parent->top + (parent->height / 2) - (this->height / 2), 0, _screen.height - this->height);
2294 this->SetDirty();
2295 }
2296
2297 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2298 {
2299 switch (widget) {
2300 case WID_NAS_PREVIEW:
2301 ShowSurveyResultTextfileWindow(this);
2302 break;
2303
2304 case WID_NAS_LINK:
2305 OpenBrowser(NETWORK_SURVEY_DETAILS_LINK);
2306 break;
2307
2308 case WID_NAS_NO:
2309 _settings_client.network.participate_survey = ParticipateSurvey::No;
2310 this->Close();
2311 break;
2312
2313 case WID_NAS_YES:
2314 _settings_client.network.participate_survey = ParticipateSurvey::Yes;
2315 this->Close();
2316 break;
2317 }
2318 }
2319};
2320
2321static constexpr std::initializer_list<NWidgetPart> _nested_network_ask_survey_widgets = {
2323 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
2324 NWidget(WWT_CAPTION, COLOUR_GREY, WID_NAS_CAPTION), SetStringTip(STR_NETWORK_ASK_SURVEY_CAPTION),
2325 EndContainer(),
2326 NWidget(WWT_PANEL, COLOUR_GREY),
2330 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NAS_PREVIEW), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_SURVEY_PREVIEW),
2331 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NAS_LINK), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_SURVEY_LINK),
2332 EndContainer(),
2334 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NAS_NO), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_SURVEY_NO),
2335 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NAS_YES), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_SURVEY_YES),
2336 EndContainer(),
2337 EndContainer(),
2338 EndContainer(),
2339};
2340
2341static WindowDesc _network_ask_survey_desc(
2342 WDP_CENTER, {}, 0, 0,
2345 _nested_network_ask_survey_widgets
2346);
2347
2352{
2353 /* If we can't send a survey, don't ask the question. */
2354 if constexpr (!NetworkSurveyHandler::IsSurveyPossible()) return;
2355
2357
2358 Window *parent = GetMainWindow();
2359 new NetworkAskSurveyWindow(_network_ask_survey_desc, parent);
2360}
2361
2363struct SurveyResultTextfileWindow : public TextfileWindow {
2365
2366 SurveyResultTextfileWindow(Window *parent, TextfileType file_type) : TextfileWindow(parent, file_type)
2367 {
2368 this->ConstructWindow();
2369
2370 auto result = _survey.CreatePayload(NetworkSurveyHandler::Reason::Preview, true);
2371 this->LoadText(result);
2372 this->InvalidateData();
2373 }
2374};
2375
2376void ShowSurveyResultTextfileWindow(Window *parent)
2377{
2380}
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.
Base interface for a network client list line.
virtual std::optional< EncodedString > GetTooltip(Rect r, const Point &pt) const
Get tooptip for a given point on the line.
Rect DrawButtons(Rect r) const
Draw the buttons for this line.
std::vector< std::unique_ptr< ButtonCommon > > buttons
Buttons for this line.
ButtonCommon * GetButton(Rect r, const Point &pt) const
Get the button at a given point on the line.
virtual void Draw(Rect r) const =0
Draw the button line.
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
void(* ButtonCallback)(struct NetworkClientListWindow *w, Point pt, T id)
Callback function to call on click.
void Draw(Rect r) const override
Draw the button line.
std::optional< EncodedString > GetTooltip(Rect r, const Point &pt) const override
Get tooptip for a given point on the line.
void Draw(Rect r) const override
Draw the button line.
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.
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).
void Add(std::unique_ptr< NWidgetBase > &&wid)
Append widget wid to container.
Definition widget.cpp:1293
std::vector< std::unique_ptr< NWidgetBase > > children
Child widgets in container.
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.
void OnInit() override
Notification that the nested widget tree gets initialized.
const IntervalTimer< TimerWindow > refresh_interval
Refresh the online servers on a regular interval.
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.
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.
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:2500
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:2447
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.
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.
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:30
int vsep_wide
Wide vertical spacing.
Definition window_gui.h:60
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:93
RectPadding bevel
Bevel thickness, affected by "scaled bevels" game option.
Definition window_gui.h:38
Functions related to commands.
PaletteID GetCompanyPalette(CompanyID company)
Get the palette for recolouring with a company colour.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
CompanyID _current_company
Company currently doing an action.
Command definitions related to companies.
Functions related to companies.
@ New
Create a new company.
@ Delete
Delete a company.
static constexpr CompanyID COMPANY_SPECTATOR
The client is spectating.
@ AddKey
Create a public key.
@ AllowListed
Allow only listed keys to join the company.
@ AllowAny
Allow joining the company without a key.
static constexpr CompanyID COMPANY_NEW_COMPANY
The client wants a new company.
@ None
Dummy reason for actions that don't need one.
@ 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:56
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:53
static const uint NETWORK_NAME_LENGTH
The maximum length of the server name and map name, in bytes including '\0'.
Definition config.h:51
static const std::string NETWORK_SURVEY_DETAILS_LINK
Link with more details & privacy statement of the survey.
Definition config.h:28
static const uint NETWORK_PASSWORD_LENGTH
The maximum length of the password, in bytes including '\0'.
Definition config.h:55
void ShowDropDownListAt(Window *w, DropDownList &&list, int selected, WidgetID button, Rect wi_rect, Colours wi_colour, DropDownOptions options)
Show a drop down list.
Definition dropdown.cpp:403
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, DropDownOptions options)
Show a drop down list.
Definition dropdown.cpp:419
Functions related to the drop down widget.
Types related to the drop down widget.
std::vector< std::unique_ptr< const DropDownListItem > > DropDownList
A drop down list is a collection of drop down list items.
@ InstantClose
Set if releasing mouse button should close the list regardless of where the cursor is.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:21
@ SLO_LOAD
File is being loaded.
Definition fileio_type.h:54
@ FT_SCENARIO
old or new scenario
Definition fileio_type.h:20
@ FT_HEIGHTMAP
heightmap file
Definition fileio_type.h:21
@ FT_SAVEGAME
old or new savegame
Definition fileio_type.h:19
Declarations for savegames operations.
void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fop)
Launch save/load dialog in the given mode.
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:87
Functions related to world/map generation.
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.
Geometry functions.
int CentreBounds(int min, int max, int size)
Determine where to position a centred object.
int GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition gfx.cpp:717
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:900
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:669
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:39
bool _left_button_clicked
Is left mouse button clicked?
Definition gfx.cpp:43
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:788
void GfxFillRect(int left, int top, int right, int bottom, const std::variant< PixelColour, PaletteID > &colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
Definition gfx.cpp:116
Functions related to the gfx engine.
Dimension GetScaledSpriteSize(SpriteID sprid)
Scale sprite size for GUI.
Definition widget.cpp:68
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:249
@ SA_RIGHT
Right align the text (must be a single bit).
Definition gfx_type.h:390
@ SA_HOR_CENTER
Horizontally center the text.
Definition gfx_type.h:389
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:398
@ SA_VERT_CENTER
Vertically center the text.
Definition gfx_type.h:394
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:346
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 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 NWidget(WidgetType tp, Colours col, WidgetID idx=INVALID_WIDGET)
Widget part function for starting a new 'real' widget.
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:967
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1554
GUI functions that shouldn't be here.
#define Rect
Macro that prevents name conflicts between included headers.
#define Point
Macro that prevents name conflicts between included headers.
Types related to maps.
static const uint MAX_MAP_SIZE
Maximal map size = 4096.
Definition map_type.h:40
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:695
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(std::string_view 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
NetworkGame * NetworkAddServer(std::string_view 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
bool NetworkClientConnectGame(std::string_view 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
ClientID _network_own_client_id
Our client identifier.
Definition network.cpp:71
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.
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 NetworkServerKickClient(ClientID client_id, std::string_view reason)
Kick a single client.
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, std::string_view reason)
Ban, or kick, everyone joined from the given client's IP.
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.
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.
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.
void ShowNetworkAskRelay(std::string_view server_connection_string, std::string &&relay_connection_string, std::string &&token)
Show a modal confirmation window with "no" / "yes, once" / "yes, always" buttons.
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.
PoolID< uint16_t, struct ClientPoolIDTag, MAX_CLIENTS+1, 0xFFFF > ClientPoolID
Indices into the client related pools.
void NetworkUDPSearchGame()
Find all servers.
Sending and receiving UDP messages.
Types related to the network widgets.
@ 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_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
PixelColour GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
Definition palette.cpp:388
constexpr PixelColour GREY_SCALE(uint8_t level)
Return the colour for a particular greyscale level.
static constexpr PixelColour PC_GREY
Grey palette colour.
Base for the GUIs that have an edit box in them.
A number of safeguards to prevent using unsafe methods.
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(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:60
Functions and types used internally for the settings configurations.
Base types for having sorted lists in GUIs.
Base for drawing complex sprites.
This file contains all sprite-related enums and defines.
Definition of base types and functions in a cross-platform compatible way.
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:427
Parse strings.
static std::optional< T > ParseInteger(std::string_view arg, int base=10, bool clamp=false)
Change a string into its number representation.
@ 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
Searching and filtering using a stringterm.
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:236
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
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:56
uint64_t GetParamMaxDigits(uint count, FontSize size)
Get some number that is suitable for string size computations.
Definition strings.cpp:218
Functions related to OTTD's strings.
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...
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).
Window used for asking the user if he is okay using a relay server.
void FindWindowPlacementAndResize(int, int, bool) 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, int, bool) 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).
ClientID client_id
Client identifier (same as ClientState->client_id).
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.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
ClientListWidgets query_widget
During a query this tracks what widget caused the query.
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.
std::vector< std::unique_ptr< ButtonLine > > buttons
Per line which buttons are available.
static void OnClickCompanyNew(NetworkClientListWindow *w, Point pt, CompanyID)
Create new company button is clicked.
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.
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.
DropDownAction
The possible entries in a DropDown for an admin action.
@ CompanyAllowListed
Allow only listed clients.
void OnDropdownClose(Point pt, WidgetID widget, int index, int click_result, bool instant_close) override
A dropdown window associated to this window has been closed.
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.
void OnDropdownSelect(WidgetID widget, int index, int) override
A dropdown option associated to this window has been selected.
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.
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.
void OnDropdownSelect(WidgetID widget, int index, int) override
A dropdown option associated to this window has been selected.
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 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.
static Pool::IterateWrapper< NetworkClientInfo > Iterate(size_t from=0)
static Company * Get(auto index)
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.
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 CentreToHeight(int height) const
Centre a vertical dimension within this Rect.
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
bool Contains(const Point &pt) const
Test if a point falls inside this Rect.
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.
std::string_view GetText() const
Get the current text.
Definition textbuf.cpp:284
void Assign(std::string_view text)
Copy a string into the textbuffer.
Definition textbuf.cpp:420
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:979
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1104
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition widget.cpp:815
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1809
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:766
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing).
Definition window.cpp:3247
Window * parent
Parent window.
Definition window_gui.h:329
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:557
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:505
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
Definition widget.cpp:798
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:1799
void CloseChildWindowById(WindowClass wc, WindowNumber number) const
Close all children a window might have in a head-recursive manner.
Definition window.cpp:1091
bool SetFocusedWidget(WidgetID widget_index)
Set focus within this window to the given widget.
Definition window.cpp:486
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
virtual void OnDropdownClose(Point pt, WidgetID widget, int index, int click_result, bool instant_close)
A dropdown window associated to this window has been closed.
Definition window.cpp:285
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
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition window.cpp:1832
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:210
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:986
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:596
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1822
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:314
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
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
Definition textbuf_gui.h:19
@ LengthIsInChars
the length of the string is counted in characters
Definition textbuf_gui.h:21
void QueryCallbackProc(Window *, bool)
Callback procedure for the ShowQuery method.
Definition textbuf_gui.h:28
GUI functions related to textfiles.
TextfileType
Additional text files accompanying Tar archives.
@ TFT_SURVEY_RESULT
Survey result (preview).
Definition of Interval and OneShot timers.
Definition of the game-calendar-timer.
Definition of the Window system.
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition widget.cpp:289
static RectPadding ScaleGUITrad(const RectPadding &r)
Scale a RectPadding to GUI zoom level.
Definition widget.cpp:49
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ WWT_IMGBTN
(Toggle) Button with image
Definition widget_type.h:41
@ WWT_PUSHIMGBTN
Normal push-button (no toggle button) with image caption.
@ NWID_SPACER
Invisible widget that takes some space.
Definition widget_type.h:70
@ WWT_EDITBOX
a textbox for typing
Definition widget_type.h:62
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:66
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:39
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX).
Definition widget_type.h:57
@ WWT_MATRIX
Grid of rows and columns.
Definition widget_type.h:50
@ WWT_CAPTION
Window caption (window title between closebox and stickybox).
Definition widget_type.h:52
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:76
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:68
@ WWT_CLOSEBOX
Close box (at top-left of a window).
Definition widget_type.h:60
@ WWT_FRAME
Frame.
Definition widget_type.h:51
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:37
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window).
Definition widget_type.h:59
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX).
Definition widget_type.h:56
@ WWT_DROPDOWN
Drop down list.
Definition widget_type.h:61
@ WWT_TEXT
Pure simple text.
Definition widget_type.h:49
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition widget_type.h:71
@ 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:29
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:1196
Window * GetMainWindow()
Get the main window, i.e.
Definition window.cpp:1182
void CloseWindowByClass(WindowClass cls, int data)
Close all windows of a given class.
Definition window.cpp:1209
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:3307
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1153
Window functions not directly related to making/drawing windows.
@ Modal
The window is a modal child of some other window, meaning the parent is 'inactive'.
Definition window_gui.h:154
@ BorderOnly
Draw border only, no background.
Definition window_gui.h:26
@ Lowered
If set the frame is lowered and the background colour brighter (ie. buttons when pressed).
Definition window_gui.h:27
Twindow * AllocateWindowDescFront(WindowDesc &desc, WindowNumber window_number, Targs... extra_arguments)
Open a new window.
@ Timeout
Window timeout counter.
Definition window_gui.h:227
@ 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:145
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:144
int WidgetID
Widget ID.
Definition window_type.h:20
@ WN_NETWORK_STATUS_WINDOW_JOIN
Network join status.
Definition window_type.h:44
@ WN_NETWORK_WINDOW_GAME
Network game window.
Definition window_type.h:40
@ WN_NETWORK_WINDOW_START
Network start server.
Definition window_type.h:42
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:50
@ 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:
Functions related to zooming.