OpenTTD Source 20260311-master-g511d3794ce
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, to_underlying(ServerGameType::Local)));
76 list.push_back(MakeDropDownListStringItem(STR_NETWORK_SERVER_VISIBILITY_INVITE_ONLY, to_underlying(ServerGameType::InviteOnly)));
77 list.push_back(MakeDropDownListStringItem(STR_NETWORK_SERVER_VISIBILITY_PUBLIC, to_underlying(ServerGameType::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:
179 static Listing last_sorting;
180
182 static const std::initializer_list<GUIGameServerList::SortFunction * const> sorter_funcs;
184 static const std::initializer_list<GUIGameServerList::FilterFunction * const> filter_funcs;
185
186 NetworkGame *server = nullptr;
188 GUIGameServerList servers{};
189 ServerListPosition list_pos = SLP_INVALID;
190 Scrollbar *vscroll = nullptr;
193 bool searched_internet = false;
194
197
204 {
205 if (!this->servers.NeedRebuild()) return;
206
207 /* Create temporary array of games to use for listing */
208 this->servers.clear();
209
210 bool found_current_server = false;
211 bool found_last_joined = false;
212 for (const auto &ngl : _network_game_list) {
213 this->servers.push_back(ngl.get());
214 if (ngl.get() == this->server) {
215 found_current_server = true;
216 }
217 if (ngl.get() == this->last_joined) {
218 found_last_joined = true;
219 }
220 }
221 /* A refresh can cause the current server to be delete; so unselect. */
222 if (!found_last_joined) {
223 this->last_joined = nullptr;
224 }
225 if (!found_current_server) {
226 this->server = nullptr;
227 this->list_pos = SLP_INVALID;
228 }
229
230 /* Apply the filter condition immediately, if a search string has been provided. */
231 StringFilter sf;
232 sf.SetFilterTerm(this->filter_editbox.text.GetText());
233
234 if (!sf.IsEmpty()) {
235 this->servers.SetFilterState(true);
236 this->servers.Filter(sf);
237 } else {
238 this->servers.SetFilterState(false);
239 }
240
241 this->servers.RebuildDone();
242 this->vscroll->SetCount(this->servers.size());
243
244 /* Sort the list of network games as requested. */
245 this->servers.Sort();
246 this->UpdateListPos();
247 }
248
250 static bool NGameNameSorter(NetworkGame * const &a, NetworkGame * const &b)
251 {
252 int r = StrNaturalCompare(a->info.server_name, b->info.server_name, true); // Sort by name (natural sorting).
253 if (r == 0) r = a->connection_string.compare(b->connection_string);
254
255 return r < 0;
256 }
257
264 static bool NGameClientSorter(NetworkGame * const &a, NetworkGame * const &b)
265 {
266 /* Reverse as per default we are interested in most-clients first */
267 int r = a->info.clients_on - b->info.clients_on;
268
269 if (r == 0) r = a->info.clients_max - b->info.clients_max;
270 if (r == 0) return NGameNameSorter(a, b);
271
272 return r < 0;
273 }
274
276 static bool NGameMapSizeSorter(NetworkGame * const &a, NetworkGame * const &b)
277 {
278 /* Sort by the area of the map. */
279 int r = (a->info.map_height) * (a->info.map_width) - (b->info.map_height) * (b->info.map_width);
280
281 if (r == 0) r = a->info.map_width - b->info.map_width;
282 return (r != 0) ? r < 0 : NGameClientSorter(a, b);
283 }
284
286 static bool NGameCalendarDateSorter(NetworkGame * const &a, NetworkGame * const &b)
287 {
288 auto r = a->info.calendar_date - b->info.calendar_date;
289 return (r != 0) ? r < 0 : NGameClientSorter(a, b);
290 }
291
293 static bool NGameTicksPlayingSorter(NetworkGame * const &a, NetworkGame * const &b)
294 {
295 if (a->info.ticks_playing == b->info.ticks_playing) {
296 return NGameClientSorter(a, b);
297 }
298 return a->info.ticks_playing < b->info.ticks_playing;
299 }
300
306 static bool NGameAllowedSorter(NetworkGame * const &a, NetworkGame * const &b)
307 {
308 /* The servers we do not know anything about (the ones that did not reply) should be at the bottom) */
309 int r = a->info.server_revision.empty() - b->info.server_revision.empty();
310
311 /* Reverse default as we are interested in version-compatible clients first */
312 if (r == 0) r = b->info.version_compatible - a->info.version_compatible;
313 /* The version-compatible ones are then sorted with NewGRF compatible first, incompatible last */
314 if (r == 0) r = b->info.compatible - a->info.compatible;
315 /* Passworded servers should be below unpassworded servers */
316 if (r == 0) r = a->info.use_password - b->info.use_password;
317
318 /* Finally sort on the number of clients of the server in reverse order. */
319 return (r != 0) ? r < 0 : NGameClientSorter(b, a);
320 }
321
324 {
325 if (this->servers.Sort()) this->UpdateListPos();
326 }
327
330 {
331 auto it = std::ranges::find(this->servers, this->server);
332 if (it == std::end(this->servers)) {
333 this->list_pos = SLP_INVALID;
334 } else {
335 this->list_pos = static_cast<ServerListPosition>(std::distance(std::begin(this->servers), it));
336 }
337 }
338
340 static bool NGameSearchFilter(NetworkGame * const *item, StringFilter &filter)
341 {
342 assert(item != nullptr);
343 assert((*item) != nullptr);
344
345 filter.ResetState();
346 filter.AddLine((*item)->info.server_name);
347 return filter.GetState();
348 }
349
356 void DrawServerLine(const NetworkGame *cur_item, int y, bool highlight) const
357 {
358 Rect name = this->GetWidget<NWidgetBase>(WID_NG_NAME)->GetCurrentRect();
359 Rect info = this->GetWidget<NWidgetBase>(WID_NG_INFO)->GetCurrentRect();
360
361 /* show highlighted item with a different colour */
362 if (highlight) {
363 Rect r = {std::min(name.left, info.left), y, std::max(name.right, info.right), y + (int)this->resize.step_height - 1};
365 }
366
367 /* Offset to vertically position text. */
368 int text_y_offset = WidgetDimensions::scaled.matrix.top + (this->resize.step_height - WidgetDimensions::scaled.matrix.Vertical() - GetCharacterHeight(FS_NORMAL)) / 2;
369
370 info = info.Shrink(WidgetDimensions::scaled.framerect);
371 name = name.Shrink(WidgetDimensions::scaled.framerect);
372 DrawString(name.left, name.right, y + text_y_offset, cur_item->info.server_name, TC_BLACK);
373
374 /* only draw details if the server is online */
375 if (cur_item->status == NGLS_ONLINE) {
376 if (const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(WID_NG_CLIENTS); nwid->current_x != 0) {
377 Rect clients = nwid->GetCurrentRect();
378 DrawString(clients.left, clients.right, y + text_y_offset,
379 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),
380 TC_FROMSTRING, SA_HOR_CENTER);
381 }
382
383 if (const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(WID_NG_MAPSIZE); nwid->current_x != 0) {
384 /* map size */
385 Rect mapsize = nwid->GetCurrentRect();
386 DrawString(mapsize.left, mapsize.right, y + text_y_offset,
387 GetString(STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT, cur_item->info.map_width, cur_item->info.map_height),
388 TC_FROMSTRING, SA_HOR_CENTER);
389 }
390
391 if (const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(WID_NG_DATE); nwid->current_x != 0) {
392 /* current date */
393 Rect date = nwid->GetCurrentRect();
394 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(cur_item->info.calendar_date);
395 DrawString(date.left, date.right, y + text_y_offset,
396 GetString(STR_JUST_INT, ymd.year),
397 TC_BLACK, SA_HOR_CENTER);
398 }
399
400 if (const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(WID_NG_YEARS); nwid->current_x != 0) {
401 /* play time */
402 Rect years = nwid->GetCurrentRect();
403 const auto play_time = cur_item->info.ticks_playing / Ticks::TICKS_PER_SECOND;
404 DrawString(years.left, years.right, y + text_y_offset,
405 GetString(STR_NETWORK_SERVER_LIST_PLAY_TIME_SHORT, play_time / 60 / 60, (play_time / 60) % 60),
406 TC_BLACK, SA_HOR_CENTER);
407 }
408
409 /* Set top and bottom of info rect to current row. */
410 info.top = y;
411 info.bottom = y + this->resize.step_height - 1;
412
413 bool rtl = _current_text_dir == TD_RTL;
414
415 /* draw a lock if the server is password protected */
416 if (cur_item->info.use_password) DrawSpriteIgnorePadding(SPR_LOCK, PAL_NONE, info.WithWidth(this->lock.width, rtl), SA_CENTER);
417
418 /* draw red or green icon, depending on compatibility with server */
419 PaletteID pal = cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED);
420 DrawSpriteIgnorePadding(SPR_BLOT, pal, info.WithWidth(this->blot.width, !rtl), SA_CENTER);
421 }
422 }
423
432 {
433 if (this->list_pos == SLP_INVALID) return; // no server selected
434 this->vscroll->ScrollTowards(this->list_pos);
435 }
436
437public:
439 {
440 this->CreateNestedTree();
441 this->vscroll = this->GetScrollbar(WID_NG_SCROLLBAR);
443
444 this->querystrings[WID_NG_CLIENT] = &this->name_editbox;
445 this->name_editbox.text.Assign(_settings_client.network.client_name);
446
447 this->querystrings[WID_NG_FILTER] = &this->filter_editbox;
448 this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
450
451 /* As the Game Coordinator doesn't support "websocket" servers yet, we
452 * let "os/emscripten/pre.js" hardcode a list of servers people can
453 * join. This means the serverlist is curated for now, but it is the
454 * best we can offer. */
455#ifdef __EMSCRIPTEN__
456 EM_ASM(if (window["openttd_server_list"]) openttd_server_list());
457#endif
458
459 this->last_joined = NetworkAddServer(_settings_client.network.last_joined, false);
460 this->server = this->last_joined;
461
462 this->servers.SetListing(this->last_sorting);
465 this->servers.ForceRebuild();
466 }
467
470 {
471 this->last_sorting = this->servers.GetListing();
472 }
473
474 void OnInit() override
475 {
476 this->lock = GetScaledSpriteSize(SPR_LOCK);
477 this->blot = GetScaledSpriteSize(SPR_BLOT);
478 }
479
480 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
481 {
482 switch (widget) {
483 case WID_NG_MATRIX:
484 fill.height = resize.height = std::max<uint>(this->blot.height, GetCharacterHeight(FS_NORMAL)) + padding.height;
485 size.height = 12 * resize.height;
486 break;
487
489 size.height = std::max<uint>(this->blot.height, GetCharacterHeight(FS_NORMAL)) + WidgetDimensions::scaled.matrix.Vertical();
490 break;
491
493 size.width = NWidgetScrollbar::GetVerticalDimension().width;
494 break;
495
496 case WID_NG_NAME:
497 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
498 break;
499
500 case WID_NG_CLIENTS: {
501 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
502 auto max_clients = GetParamMaxValue(MAX_CLIENTS);
503 auto max_companies = GetParamMaxValue(MAX_COMPANIES);
504 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_SERVER_LIST_GENERAL_ONLINE, max_clients, max_clients, max_companies, max_companies)));
505 break;
506 }
507
508 case WID_NG_MAPSIZE: {
509 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
510 auto max_map_size = GetParamMaxValue(MAX_MAP_SIZE);
511 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT, max_map_size, max_map_size)));
512 break;
513 }
514
515 case WID_NG_DATE:
516 case WID_NG_YEARS:
517 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
518 size = maxdim(size, GetStringBoundingBox(GetString(STR_JUST_INT, GetParamMaxValue(5))));
519 break;
520
521 case WID_NG_INFO:
522 size.width = this->lock.width + WidgetDimensions::scaled.hsep_normal + this->blot.width + padding.width;
523 size.height = std::max(this->lock.height, this->blot.height) + padding.height;
524 break;
525 }
526 }
527
528 void DrawWidget(const Rect &r, WidgetID widget) const override
529 {
530 switch (widget) {
531 case WID_NG_MATRIX: {
532 uint16_t y = r.top;
533
534 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->servers);
535 for (auto it = first; it != last; ++it) {
536 const NetworkGame *ngl = *it;
537 this->DrawServerLine(ngl, y, ngl == this->server);
538 y += this->resize.step_height;
539 }
540 break;
541 }
542
544 /* Draw the last joined server, if any */
545 if (this->last_joined != nullptr) this->DrawServerLine(this->last_joined, r.top, this->last_joined == this->server);
546 break;
547
548 case WID_NG_DETAILS:
549 this->DrawDetails(r);
550 break;
551
552 case WID_NG_NAME:
553 case WID_NG_CLIENTS:
554 case WID_NG_MAPSIZE:
555 case WID_NG_DATE:
556 case WID_NG_YEARS:
557 case WID_NG_INFO:
558 if (widget - WID_NG_NAME == this->servers.SortType()) this->DrawSortButtonState(widget, this->servers.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
559 break;
560 }
561 }
562
563
564 void OnPaint() override
565 {
566 if (this->servers.NeedRebuild()) {
568 }
569 if (this->servers.NeedResort()) {
570 this->SortNetworkGameList();
571 }
572
573 NetworkGame *sel = this->server;
574 /* 'Refresh' button invisible if no server selected */
575 this->SetWidgetDisabledState(WID_NG_REFRESH, sel == nullptr);
576 /* 'Join' button disabling conditions */
577 this->SetWidgetDisabledState(WID_NG_JOIN, sel == nullptr || // no Selected Server
578 sel->status != NGLS_ONLINE || // Server offline
579 sel->info.clients_on >= sel->info.clients_max || // Server full
580 !sel->info.compatible); // Revision mismatch
581
582 this->SetWidgetLoweredState(WID_NG_REFRESH, sel != nullptr && sel->refreshing);
583
584 /* 'NewGRF Settings' button invisible if no NewGRF is used */
585 bool changed = false;
586 changed |= this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == nullptr || sel->status != NGLS_ONLINE || sel->info.grfconfig.empty() ? SZSP_NONE : 0);
587 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);
588 if (changed) {
589 this->ReInit();
590 return;
591 }
592
593#ifdef __EMSCRIPTEN__
598#endif
599
600 this->DrawWidgets();
601 }
602
603 StringID GetHeaderString() const
604 {
605 if (this->server == nullptr) return STR_NETWORK_SERVER_LIST_GAME_INFO;
606 switch (this->server->status) {
607 case NGLS_OFFLINE: return STR_NETWORK_SERVER_LIST_SERVER_OFFLINE;
608 case NGLS_ONLINE: return STR_NETWORK_SERVER_LIST_GAME_INFO;
609 case NGLS_FULL: return STR_NETWORK_SERVER_LIST_SERVER_FULL;
610 case NGLS_BANNED: return STR_NETWORK_SERVER_LIST_SERVER_BANNED;
611 case NGLS_TOO_OLD: return STR_NETWORK_SERVER_LIST_SERVER_TOO_OLD;
612 default: NOT_REACHED();
613 }
614 }
615
616 void DrawDetails(const Rect &r) const
617 {
618 NetworkGame *sel = this->server;
619
620 Rect tr = r.Shrink(WidgetDimensions::scaled.frametext);
621 StringID header_msg = this->GetHeaderString();
622 int header_height = GetStringHeight(header_msg, tr.Width()) +
623 (sel == nullptr ? 0 : GetStringHeight(sel->info.server_name, tr.Width())) +
624 WidgetDimensions::scaled.frametext.Vertical();
625
626 /* Height for the title banner */
627 Rect hr = r.WithHeight(header_height).Shrink(WidgetDimensions::scaled.frametext);
628 tr.top += header_height;
629
630 /* Draw the right menu */
631 /* Create the nice darker rectangle at the details top */
632 GfxFillRect(r.WithHeight(header_height).Shrink(WidgetDimensions::scaled.bevel), GetColourGradient(COLOUR_LIGHT_BLUE, SHADE_NORMAL));
633 hr.top = DrawStringMultiLine(hr, header_msg, TC_FROMSTRING, SA_HOR_CENTER);
634 if (sel == nullptr) return;
635
636 hr.top = DrawStringMultiLine(hr, sel->info.server_name, TC_ORANGE, SA_HOR_CENTER); // game name
637 if (sel->status != NGLS_ONLINE) {
638 tr.top = DrawStringMultiLine(tr, header_msg, TC_FROMSTRING, SA_HOR_CENTER);
639 } else { // show game info
640 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));
641
642 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_LANDSCAPE, STR_CLIMATE_TEMPERATE_LANDSCAPE + to_underlying(sel->info.landscape))); // landscape
643
644 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_MAP_SIZE, sel->info.map_width, sel->info.map_height)); // map size
645
646 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_SERVER_VERSION, sel->info.server_revision)); // server version
647
648 StringID invite_or_address = sel->connection_string.starts_with("+") ? STR_NETWORK_SERVER_LIST_INVITE_CODE : STR_NETWORK_SERVER_LIST_SERVER_ADDRESS;
649 tr.top = DrawStringMultiLine(tr, GetString(invite_or_address, sel->connection_string)); // server address / invite code
650
651 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_START_DATE, sel->info.calendar_start)); // start date
652
653 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_CURRENT_DATE, sel->info.calendar_date)); // current date
654
655 const auto play_time = sel->info.ticks_playing / Ticks::TICKS_PER_SECOND;
656 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_PLAY_TIME, play_time / 60 / 60, (play_time / 60) % 60)); // play time
657
658 if (sel->info.gamescript_version != -1) {
659 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_GAMESCRIPT, sel->info.gamescript_name, sel->info.gamescript_version)); // gamescript name and version
660 }
661
663
664 if (!sel->info.compatible) {
665 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
666 } else if (sel->info.clients_on == sel->info.clients_max) {
667 /* Show: server full, when clients_on == max_clients */
668 DrawStringMultiLine(tr, STR_NETWORK_SERVER_LIST_SERVER_FULL, TC_FROMSTRING, SA_HOR_CENTER); // server full
669 } else if (sel->info.use_password) {
670 DrawStringMultiLine(tr, STR_NETWORK_SERVER_LIST_PASSWORD, TC_FROMSTRING, SA_HOR_CENTER); // password warning
671 }
672 }
673 }
674
675 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
676 {
677 switch (widget) {
678 case WID_NG_NAME: // Sort by name
679 case WID_NG_CLIENTS: // Sort by connected clients
680 case WID_NG_MAPSIZE: // Sort by map size
681 case WID_NG_DATE: // Sort by date
682 case WID_NG_YEARS: // Sort by years
683 case WID_NG_INFO: // Connectivity (green dot)
684 if (this->servers.SortType() == widget - WID_NG_NAME) {
685 this->servers.ToggleSortOrder();
686 if (this->list_pos != SLP_INVALID) this->list_pos = (ServerListPosition)this->servers.size() - this->list_pos - 1;
687 } else {
688 this->servers.SetSortType(widget - WID_NG_NAME);
689 this->servers.ForceResort();
690 this->SortNetworkGameList();
691 }
693 this->SetDirty();
694 break;
695
696 case WID_NG_MATRIX: { // Show available network games
697 auto it = this->vscroll->GetScrolledItemFromWidget(this->servers, pt.y, this, WID_NG_MATRIX);
698 this->server = (it != this->servers.end()) ? *it : nullptr;
699 this->list_pos = (server == nullptr) ? SLP_INVALID : it - this->servers.begin();
700 this->SetDirty();
701
702 if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
703 break;
704 }
705
706 case WID_NG_LASTJOINED: {
707 if (this->last_joined != nullptr) {
708 this->server = this->last_joined;
709
710 /* search the position of the newly selected server */
711 this->UpdateListPos();
713 this->SetDirty();
714
715 if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
716 }
717 break;
718 }
719
721 _network_coordinator_client.GetListing();
722 this->searched_internet = true;
723 break;
724
727 break;
728
729 case WID_NG_ADD: // Add a server
731 _settings_client.network.connect_to_ip,
732 STR_NETWORK_SERVER_LIST_ENTER_SERVER_ADDRESS,
733 NETWORK_HOSTNAME_PORT_LENGTH, // maximum number of characters including '\0'
735 break;
736
737 case WID_NG_START: // Start server
738 ShowNetworkStartServerWindow();
739 break;
740
741 case WID_NG_JOIN: // Join Game
742 if (this->server != nullptr) {
744 }
745 break;
746
747 case WID_NG_REFRESH: // Refresh
748 if (this->server != nullptr && !this->server->refreshing) NetworkQueryServer(this->server->connection_string);
749 break;
750
751 case WID_NG_NEWGRF: // NewGRF Settings
752 if (this->server != nullptr) ShowNewGRFSettings(false, false, false, this->server->info.grfconfig);
753 break;
754
755 case WID_NG_NEWGRF_MISSING: // Find missing content online
756 if (this->server != nullptr) ShowMissingContentWindow(this->server->info.grfconfig);
757 break;
758 }
759 }
760
766 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
767 {
768 this->servers.ForceRebuild();
769 this->SetDirty();
770 }
771
772 EventState OnKeyPress([[maybe_unused]] char32_t key, uint16_t keycode) override
773 {
775
776 /* handle up, down, pageup, pagedown, home and end */
777 if (this->vscroll->UpdateListPositionOnKeyPress(this->list_pos, keycode) == ES_HANDLED) {
778 if (this->list_pos == SLP_INVALID) return ES_HANDLED;
779
780 this->server = this->servers[this->list_pos];
781
782 /* Scroll to the new server if it is outside the current range. */
784
785 /* redraw window */
786 this->SetDirty();
787 return ES_HANDLED;
788 }
789
790 if (this->server != nullptr) {
791 if (keycode == WKC_DELETE) { // Press 'delete' to remove servers
792 NetworkGameListRemoveItem(this->server);
793 if (this->server == this->last_joined) this->last_joined = nullptr;
794 this->server = nullptr;
795 this->list_pos = SLP_INVALID;
796 }
797 }
798
799 return state;
800 }
801
802 void OnEditboxChanged(WidgetID wid) override
803 {
804 switch (wid) {
805 case WID_NG_FILTER: {
806 this->servers.ForceRebuild();
809 this->SetDirty();
810 break;
811 }
812
813 case WID_NG_CLIENT:
814 /* Validation of the name will happen once the user tries to join or start a game, as getting
815 * error messages while typing (e.g. when you clear the name) defeats the purpose of the check. */
816 _settings_client.network.client_name = this->name_editbox.text.GetText();
817 break;
818 }
819 }
820
821 void OnQueryTextFinished(std::optional<std::string> str) override
822 {
823 if (!str.has_value() || str->empty()) return;
824
825 _settings_client.network.connect_to_ip = std::move(*str);
826 NetworkAddServer(_settings_client.network.connect_to_ip);
828 }
829
830 void OnResize() override
831 {
832 this->vscroll->SetCapacityFromWidget(this, WID_NG_MATRIX);
833 }
834
836 const IntervalTimer<TimerWindow> refresh_interval = {std::chrono::seconds(30), [this](uint) {
837 if (!this->searched_internet) return;
838
839 _network_coordinator_client.GetListing();
840 }};
841};
842
844const std::initializer_list<GUIGameServerList::SortFunction * const> NetworkGameWindow::sorter_funcs = {
851};
852
853const std::initializer_list<GUIGameServerList::FilterFunction * const> NetworkGameWindow::filter_funcs = {
855};
856
857static std::unique_ptr<NWidgetBase> MakeResizableHeader()
858{
859 return std::make_unique<NWidgetServerListHeader>();
860}
861
862static constexpr std::initializer_list<NWidgetPart> _nested_network_game_widgets = {
863 /* TOP */
865 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
866 NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetStringTip(STR_NETWORK_SERVER_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
867 NWidget(WWT_DEFSIZEBOX, COLOUR_LIGHT_BLUE),
868 EndContainer(),
869 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_MAIN),
872 /* LEFT SIDE */
875 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NG_FILTER_LABEL), SetStringTip(STR_LIST_FILTER_TITLE),
876 NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_FILTER), SetMinimalSize(251, 0), SetFill(1, 0), SetResize(1, 0),
877 SetStringTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
878 EndContainer(),
881 NWidgetFunction(MakeResizableHeader),
882 NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NG_MATRIX), SetResize(1, 1), SetFill(1, 0),
883 SetMatrixDataTip(1, 0, STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT), SetScrollbar(WID_NG_SCROLLBAR),
884 EndContainer(),
885 NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NG_SCROLLBAR),
886 EndContainer(),
888 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NG_LASTJOINED_LABEL), SetFill(1, 0),
889 SetStringTip(STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER), SetResize(1, 0),
891 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_LASTJOINED), SetFill(1, 0), SetResize(1, 0),
892 SetToolTip(STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST_TOOLTIP),
893 EndContainer(),
894 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NG_LASTJOINED_SPACER), SetFill(0, 0),
895 EndContainer(),
896 EndContainer(),
897 EndContainer(),
898 /* RIGHT SIDE */
901 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NG_CLIENT_LABEL), SetStringTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME),
902 NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_CLIENT), SetMinimalSize(151, 0), SetFill(1, 0), SetResize(1, 0),
903 SetStringTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE, STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP),
904 EndContainer(),
906 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_DETAILS), SetMinimalSize(140, 0), SetMinimalTextLines(15, 0), SetResize(0, 1),
907 EndContainer(),
910 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),
911 EndContainer(),
912 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NG_NEWGRF_SEL),
913 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NEWGRF), SetFill(1, 0), SetStringTip(STR_MAPGEN_NEWGRF_SETTINGS, STR_MAPGEN_NEWGRF_SETTINGS_TOOLTIP),
914 EndContainer(),
916 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_JOIN), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_JOIN_GAME),
917 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_REFRESH), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_REFRESH, STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP),
918 EndContainer(),
919 EndContainer(),
920 EndContainer(),
921 EndContainer(),
922 EndContainer(),
923 /* BOTTOM */
925 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),
926 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),
927 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),
928 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),
929 EndContainer(),
930 EndContainer(),
931 /* Resize button. */
933 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
934 NWidget(WWT_RESIZEBOX, COLOUR_LIGHT_BLUE), SetResizeWidgetTypeTip(RWV_HIDE_BEVEL, STR_TOOLTIP_RESIZE),
935 EndContainer(),
936 EndContainer(),
937};
938
939static WindowDesc _network_game_window_desc(
940 WDP_CENTER, "list_servers", 1000, 730,
942 {},
943 _nested_network_game_widgets
944);
945
946void ShowNetworkGameWindow()
947{
948 static bool first = true;
950
951 /* Only show once */
952 if (first) {
953 first = false;
954 /* Add all servers from the config file to our list. */
955 for (const auto &iter : _network_host_list) {
956 NetworkAddServer(iter);
957 }
958 }
959
960 new NetworkGameWindow(_network_game_window_desc);
961}
962
963struct NetworkStartServerWindow : public Window {
966
967 NetworkStartServerWindow(WindowDesc &desc) : Window(desc), name_editbox(NETWORK_NAME_LENGTH)
968 {
970
971 this->querystrings[WID_NSS_GAMENAME] = &this->name_editbox;
972 this->name_editbox.text.Assign(_settings_client.network.server_name);
973
975 }
976
977 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
978 {
979 switch (widget) {
981 return GetString(STR_NETWORK_SERVER_VISIBILITY_LOCAL + to_underlying(_settings_client.network.server_game_type));
982
984 return GetString(STR_NETWORK_START_SERVER_CLIENTS_SELECT, _settings_client.network.max_clients);
985
987 return GetString(STR_NETWORK_START_SERVER_COMPANIES_SELECT, _settings_client.network.max_companies);
988
989 default:
990 return this->Window::GetWidgetString(widget, stringid);
991 }
992 }
993
994 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
995 {
996 switch (widget) {
998 size = maxdim(maxdim(GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_LOCAL), GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_PUBLIC)), GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_INVITE_ONLY));
999 size.width += padding.width;
1000 size.height += padding.height;
1001 break;
1002 }
1003 }
1004
1005 void DrawWidget(const Rect &r, WidgetID widget) const override
1006 {
1007 switch (widget) {
1008 case WID_NSS_SETPWD:
1009 /* If password is set, draw red '*' next to 'Set password' button. */
1010 if (!_settings_client.network.server_password.empty()) DrawString(r.right + WidgetDimensions::scaled.framerect.left, this->width - WidgetDimensions::scaled.framerect.right, r.top, "*", TC_RED);
1011 }
1012 }
1013
1014 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1015 {
1016 switch (widget) {
1017 case WID_NSS_CANCEL: // Cancel button
1018 ShowNetworkGameWindow();
1019 break;
1020
1021 case WID_NSS_SETPWD: // Set password button
1022 this->widget_id = WID_NSS_SETPWD;
1023 ShowQueryString(_settings_client.network.server_password, STR_NETWORK_START_SERVER_SET_PASSWORD, NETWORK_PASSWORD_LENGTH, this, CS_ALPHANUMERAL, {});
1024 break;
1025
1026 case WID_NSS_CONNTYPE_BTN: // Connection type
1027 ShowDropDownList(this, BuildVisibilityDropDownList(), to_underlying(_settings_client.network.server_game_type), WID_NSS_CONNTYPE_BTN);
1028 break;
1029
1030 case WID_NSS_CLIENTS_BTND: case WID_NSS_CLIENTS_BTNU: // Click on up/down button for number of clients
1031 case WID_NSS_COMPANIES_BTND: case WID_NSS_COMPANIES_BTNU: // Click on up/down button for number of companies
1032 /* Don't allow too fast scrolling. */
1033 if (!this->flags.Test(WindowFlag::Timeout) || this->timeout_timer <= 1) {
1034 this->HandleButtonClick(widget);
1035 this->SetDirty();
1036 switch (widget) {
1037 default: NOT_REACHED();
1039 _settings_client.network.max_clients = Clamp(_settings_client.network.max_clients + widget - WID_NSS_CLIENTS_TXT, 2, MAX_CLIENTS);
1040 break;
1042 _settings_client.network.max_companies = Clamp(_settings_client.network.max_companies + widget - WID_NSS_COMPANIES_TXT, 1, MAX_COMPANIES);
1043 break;
1044 }
1045 }
1046 _left_button_clicked = false;
1047 break;
1048
1049 case WID_NSS_CLIENTS_TXT: // Click on number of clients
1050 this->widget_id = WID_NSS_CLIENTS_TXT;
1051 ShowQueryString(GetString(STR_JUST_INT, _settings_client.network.max_clients), STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS, 4, this, CS_NUMERAL, {});
1052 break;
1053
1054 case WID_NSS_COMPANIES_TXT: // Click on number of companies
1055 this->widget_id = WID_NSS_COMPANIES_TXT;
1056 ShowQueryString(GetString(STR_JUST_INT, _settings_client.network.max_companies), STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES, 3, this, CS_NUMERAL, {});
1057 break;
1058
1059 case WID_NSS_GENERATE_GAME: // Start game
1060 if (!CheckServerName()) return;
1061 _is_network_server = true;
1062 if (_ctrl_pressed) {
1064 } else {
1066 }
1067 break;
1068
1069 case WID_NSS_LOAD_GAME:
1070 if (!CheckServerName()) return;
1071 _is_network_server = true;
1073 break;
1074
1076 if (!CheckServerName()) return;
1077 _is_network_server = true;
1079 break;
1080
1082 if (!CheckServerName()) return;
1083 _is_network_server = true;
1085 break;
1086 }
1087 }
1088
1089 void OnDropdownSelect(WidgetID widget, int index, int) override
1090 {
1091 switch (widget) {
1093 _settings_client.network.server_game_type = (ServerGameType)index;
1094 break;
1095 default:
1096 NOT_REACHED();
1097 }
1098
1099 this->SetDirty();
1100 }
1101
1102 bool CheckServerName()
1103 {
1104 std::string str{this->name_editbox.text.GetText()};
1105 if (!NetworkValidateServerName(str)) return false;
1106
1107 SetSettingValue(GetSettingFromName("network.server_name")->AsStringSetting(), std::move(str));
1108 return true;
1109 }
1110
1115
1116 void OnQueryTextFinished(std::optional<std::string> str) override
1117 {
1118 if (!str.has_value()) return;
1119
1120 if (this->widget_id == WID_NSS_SETPWD) {
1121 _settings_client.network.server_password = std::move(*str);
1122 } else {
1123 auto value = ParseInteger<int32_t>(*str, 10, true);
1124 if (!value.has_value()) return;
1125 this->SetWidgetDirty(this->widget_id);
1126 switch (this->widget_id) {
1127 default: NOT_REACHED();
1128 case WID_NSS_CLIENTS_TXT: _settings_client.network.max_clients = Clamp(*value, 2, MAX_CLIENTS); break;
1129 case WID_NSS_COMPANIES_TXT: _settings_client.network.max_companies = Clamp(*value, 1, MAX_COMPANIES); break;
1130 }
1131 }
1132
1133 this->SetDirty();
1134 }
1135};
1136
1137static constexpr std::initializer_list<NWidgetPart> _nested_network_start_server_window_widgets = {
1139 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
1140 NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetStringTip(STR_NETWORK_START_SERVER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1141 EndContainer(),
1142 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NSS_BACKGROUND),
1146 /* Game name widgets */
1147 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NSS_GAMENAME_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME),
1148 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),
1149 EndContainer(),
1150
1153 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NSS_CONNTYPE_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_VISIBILITY_LABEL),
1154 NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_BTN), SetFill(1, 0), SetToolTip(STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP),
1155 EndContainer(),
1157 NWidget(NWID_SPACER), SetFill(1, 1),
1158 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_SETPWD), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_SET_PASSWORD, STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP),
1159 EndContainer(),
1160 EndContainer(),
1161
1164 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NSS_CLIENTS_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS),
1166 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),
1167 NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_TXT), SetFill(1, 0), SetToolTip(STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
1168 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),
1169 EndContainer(),
1170 EndContainer(),
1171
1173 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NSS_COMPANIES_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES),
1175 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),
1176 NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_TXT), SetFill(1, 0), SetToolTip(STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
1177 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),
1178 EndContainer(),
1179 EndContainer(),
1180 EndContainer(),
1181 EndContainer(),
1182
1184 /* 'generate game' and 'load game' buttons */
1186 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_GENERATE_GAME), SetStringTip(STR_INTRO_NEW_GAME, STR_INTRO_TOOLTIP_NEW_GAME), SetFill(1, 0),
1187 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_LOAD_GAME), SetStringTip(STR_INTRO_LOAD_GAME, STR_INTRO_TOOLTIP_LOAD_GAME), SetFill(1, 0),
1188 EndContainer(),
1189
1190 /* 'play scenario' and 'play heightmap' buttons */
1192 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_PLAY_SCENARIO), SetStringTip(STR_INTRO_PLAY_SCENARIO, STR_INTRO_TOOLTIP_PLAY_SCENARIO), SetFill(1, 0),
1193 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_PLAY_HEIGHTMAP), SetStringTip(STR_INTRO_PLAY_HEIGHTMAP, STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP), SetFill(1, 0),
1194 EndContainer(),
1195 EndContainer(),
1196
1198 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_CANCEL), SetStringTip(STR_BUTTON_CANCEL), SetMinimalSize(128, 12),
1199 EndContainer(),
1200 EndContainer(),
1201 EndContainer(),
1202};
1203
1204static WindowDesc _network_start_server_window_desc(
1205 WDP_CENTER, {}, 0, 0,
1207 {},
1208 _nested_network_start_server_window_widgets
1209);
1210
1211static void ShowNetworkStartServerWindow()
1212{
1213 if (!NetworkValidateOurClientName()) return;
1214
1216
1217 new NetworkStartServerWindow(_network_start_server_window_desc);
1218}
1219
1220/* The window below gives information about the connected clients
1221 * and also makes able to kick them (if server) and stuff like that. */
1222
1223extern void DrawCompanyIcon(CompanyID cid, int x, int y);
1224
1225static constexpr std::initializer_list<NWidgetPart> _nested_client_list_widgets = {
1227 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1228 NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_NETWORK_CLIENT_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1229 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
1230 NWidget(WWT_STICKYBOX, COLOUR_GREY),
1231 EndContainer(),
1232 NWidget(WWT_PANEL, COLOUR_GREY),
1234 NWidget(WWT_FRAME, COLOUR_GREY), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0),
1236 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_NAME),
1237 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),
1238 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),
1239 EndContainer(),
1243 NWidget(WWT_TEXT, INVALID_COLOUR), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY),
1244 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_CL_SERVER_VISIBILITY), SetToolTip(STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP),
1245 EndContainer(),
1247 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_INVITE_CODE),
1248 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),
1249 EndContainer(),
1251 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE),
1252 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),
1253 EndContainer(),
1254 EndContainer(),
1255 EndContainer(),
1256 EndContainer(),
1257 NWidget(WWT_FRAME, COLOUR_GREY), SetStringTip(STR_NETWORK_CLIENT_LIST_PLAYER),
1259 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_NETWORK_CLIENT_LIST_PLAYER_NAME),
1260 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),
1261 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),
1262 EndContainer(),
1263 EndContainer(),
1264 EndContainer(),
1265 EndContainer(),
1269 EndContainer(),
1271 NWidget(WWT_PANEL, COLOUR_GREY),
1272 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),
1273 EndContainer(),
1274 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
1275 EndContainer(),
1276};
1277
1278static WindowDesc _client_list_desc(
1279 WDP_AUTO, "list_clients", 220, 300,
1281 {},
1282 _nested_client_list_widgets
1283);
1284
1289static void AdminClientKickCallback(Window *, bool confirmed)
1290{
1291 if (confirmed) NetworkServerKickClient(_admin_client_id, {});
1292}
1293
1298static void AdminClientBanCallback(Window *, bool confirmed)
1299{
1300 if (confirmed) NetworkServerKickOrBanIP(_admin_client_id, true, {});
1301}
1302
1307static void AdminCompanyResetCallback(Window *, bool confirmed)
1308{
1309 if (confirmed) {
1312 }
1313}
1314
1322class ButtonCommon {
1323public:
1326 Colours colour;
1328 uint height;
1329 uint width;
1330
1331 ButtonCommon(SpriteID sprite, StringID tooltip, Colours colour, bool disabled = false) :
1332 sprite(sprite),
1334 colour(colour),
1336 {
1338 this->height = d.height + WidgetDimensions::scaled.framerect.Vertical();
1339 this->width = d.width + WidgetDimensions::scaled.framerect.Horizontal();
1340 }
1342 virtual ~ButtonCommon() = default;
1343
1349 virtual void OnClick(struct NetworkClientListWindow *w, Point pt) = 0;
1350};
1351
1355template <typename T>
1356class Button : public ButtonCommon {
1357private:
1358 typedef void (*ButtonCallback)(struct NetworkClientListWindow *w, Point pt, T id);
1361
1362public:
1363 Button(SpriteID sprite, StringID tooltip, Colours colour, T id, ButtonCallback proc, bool disabled = false) :
1364 ButtonCommon(sprite, tooltip, colour, disabled),
1365 id(id),
1366 proc(proc)
1367 {
1368 assert(proc != nullptr);
1369 }
1370
1371 void OnClick(struct NetworkClientListWindow *w, Point pt) override
1372 {
1373 if (this->disabled) return;
1374
1375 this->proc(w, pt, this->id);
1376 }
1377};
1378
1379using CompanyButton = Button<CompanyID>;
1380using ClientButton = Button<ClientID>;
1381
1386public:
1387 std::vector<std::unique_ptr<ButtonCommon>> buttons{};
1388
1390 virtual ~ButtonLine() = default;
1391
1396 virtual void Draw(Rect r) const = 0;
1397
1398 template <typename T, typename...TArgs>
1399 T &AddButton(TArgs &&... args)
1400 {
1401 auto &button = this->buttons.emplace_back(std::make_unique<T>(std::forward<TArgs &&>(args)...));
1402 return static_cast<T &>(*button);
1403 }
1404
1411 ButtonCommon *GetButton(Rect r, const Point &pt) const
1412 {
1413 bool rtl = _current_text_dir == TD_RTL;
1414 for (auto &button : this->buttons) {
1415 if (r.WithWidth(button->width, !rtl).Contains(pt)) return button.get();
1416 r = r.Indent(button->width + WidgetDimensions::scaled.hsep_normal, !rtl);
1417 }
1418 return nullptr;
1419 }
1420
1427 virtual std::optional<EncodedString> GetTooltip(Rect r, const Point &pt) const
1428 {
1429 ButtonCommon *button = this->GetButton(r, pt);
1430 if (button == nullptr) return {};
1431 return GetEncodedString(button->tooltip);
1432 }
1433
1434protected:
1441 {
1442 bool rtl = _current_text_dir == TD_RTL;
1443 for (auto &button : buttons) {
1444 Rect br = r.CentreToHeight(button->height).WithWidth(button->width, !rtl);
1445 DrawFrameRect(br, button->colour, {});
1446 DrawSpriteIgnorePadding(button->sprite, PAL_NONE, br, SA_CENTER);
1447 if (button->disabled) {
1448 GfxFillRect(br.Shrink(WidgetDimensions::scaled.bevel), GetColourGradient(button->colour, SHADE_DARKER), FILLRECT_CHECKER);
1449 }
1450 r = r.Indent(button->width + WidgetDimensions::scaled.hsep_normal, !rtl);
1451 }
1452 return r;
1453 }
1454};
1455
1456class CompanyButtonLine : public ButtonLine {
1457public:
1458 CompanyButtonLine(CompanyID company_id) : company_id(company_id) {}
1459
1460 void Draw(Rect r) const override
1461 {
1462 bool rtl = _current_text_dir == TD_RTL;
1463 r = this->DrawButtons(r);
1464
1465 Dimension d = GetScaledSpriteSize(SPR_COMPANY_ICON);
1466 PaletteID pal = Company::IsValidID(this->company_id) ? GetCompanyPalette(this->company_id) : PALETTE_TO_GREY;
1467 DrawSpriteIgnorePadding(SPR_COMPANY_ICON, pal, r.WithWidth(d.width, rtl), SA_CENTER);
1468
1470 if (this->company_id == COMPANY_SPECTATOR) {
1471 DrawString(tr, STR_NETWORK_CLIENT_LIST_SPECTATORS, TC_SILVER);
1472 } else if (this->company_id == COMPANY_NEW_COMPANY) {
1473 DrawString(tr, STR_NETWORK_CLIENT_LIST_NEW_COMPANY, TC_WHITE);
1474 } else {
1475 DrawString(tr, GetString(STR_COMPANY_NAME, this->company_id, this->company_id), TC_SILVER);
1476 }
1477 };
1478
1479private:
1480 CompanyID company_id;
1481};
1482
1483class ClientButtonLine : public ButtonLine {
1484public:
1485 ClientButtonLine(ClientPoolID client_pool_id) : client_pool_id(client_pool_id) {}
1486
1487 void Draw(Rect r) const override
1488 {
1489 const NetworkClientInfo *ci = NetworkClientInfo::GetIfValid(this->client_pool_id);
1490 if (ci == nullptr) return;
1491
1492 bool rtl = _current_text_dir == TD_RTL;
1493 r = this->DrawButtons(r);
1494
1496
1497 SpriteID player_icon = 0;
1498 if (ci->client_id == _network_own_client_id) {
1499 player_icon = SPR_PLAYER_SELF;
1500 } else if (ci->client_id == CLIENT_ID_SERVER) {
1501 player_icon = SPR_PLAYER_HOST;
1502 }
1503
1504 if (player_icon != 0) {
1505 Dimension d = GetScaledSpriteSize(player_icon);
1506 DrawSpriteIgnorePadding(player_icon, PALETTE_TO_GREY, r.WithWidth(d.width, rtl), SA_CENTER);
1507 tr = tr.Indent(d.width + WidgetDimensions::scaled.hsep_normal, rtl);
1508 }
1509
1510 DrawString(tr, GetString(STR_JUST_RAW_STRING, ci->client_name), TC_BLACK);
1511 }
1512
1513 std::optional<EncodedString> GetTooltip(Rect r, const Point &pt) const override
1514 {
1515 bool rtl = _current_text_dir == TD_RTL;
1516 Dimension d = GetScaledSpriteSize(SPR_PLAYER_SELF);
1517
1518 if (r.WithWidth(d.width, rtl).Contains(pt)) {
1519 const NetworkClientInfo *ci = NetworkClientInfo::GetIfValid(this->client_pool_id);
1520 if (ci != nullptr) {
1521 if (ci->client_id == _network_own_client_id) {
1522 return GetEncodedString(STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP);
1523 } else if (ci->client_id == CLIENT_ID_SERVER) {
1524 return GetEncodedString(STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP);
1525 }
1526 }
1527 }
1528
1529 return this->ButtonLine::GetTooltip(r, pt);
1530 }
1531
1532private:
1533 ClientPoolID client_pool_id;
1534};
1535
1539struct NetworkClientListWindow : Window {
1540private:
1552
1554
1556 CompanyID dd_company_id = CompanyID::Invalid();
1557
1558 Scrollbar *vscroll = nullptr;
1559 uint line_height = 0;
1560 int hover_index = -1;
1561
1562 std::vector<std::unique_ptr<ButtonLine>> buttons{};
1563
1570 static void OnClickCompanyChat([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, CompanyID company_id)
1571 {
1572 ShowNetworkChatQueryWindow(DESTTYPE_TEAM, company_id.base());
1573 }
1574
1581 static void OnClickCompanyJoin([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, CompanyID company_id)
1582 {
1583 if (_network_server) {
1586 } else {
1587 NetworkClientRequestMove(company_id);
1588 }
1589 }
1590
1596 static void OnClickCompanyNew([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, CompanyID)
1597 {
1598 Command<Commands::CompanyControl>::Post(CompanyCtrlAction::New, CompanyID::Invalid(), CompanyRemoveReason::None, _network_own_client_id);
1599 }
1600
1607 static void OnClickClientAdmin([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, ClientID client_id)
1608 {
1609 DropDownList list;
1610 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK, to_underlying(DropDownAction::AdminKickClient)));
1611 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN, to_underlying(DropDownAction::AdminBanClient)));
1612
1613 Rect wi_rect;
1614 wi_rect.left = pt.x;
1615 wi_rect.right = pt.x;
1616 wi_rect.top = pt.y;
1617 wi_rect.bottom = pt.y;
1618
1619 w->dd_client_id = client_id;
1620 ShowDropDownListAt(w, std::move(list), -1, WID_CL_MATRIX, wi_rect, COLOUR_GREY, DropDownOption::InstantClose);
1621 }
1622
1629 static void OnClickCompanyAdmin([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, CompanyID company_id)
1630 {
1631 DropDownList list;
1632 if (_network_server) list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET, to_underlying(DropDownAction::AdminResetCompany), NetworkCompanyHasClients(company_id)));
1633 if (const Company *c = Company::GetIfValid(company_id); c != nullptr) {
1634 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_ALLOW_ANY, to_underlying(DropDownAction::CompanyAllowAny), c->allow_any));
1635 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_ALLOW_LISTED, to_underlying(DropDownAction::CompanyAllowListed), !c->allow_any));
1636 }
1637
1638 Rect wi_rect;
1639 wi_rect.left = pt.x;
1640 wi_rect.right = pt.x;
1641 wi_rect.top = pt.y;
1642 wi_rect.bottom = pt.y;
1643
1644 w->dd_company_id = company_id;
1645 ShowDropDownListAt(w, std::move(list), -1, WID_CL_MATRIX, wi_rect, COLOUR_GREY, DropDownOption::InstantClose);
1646 }
1647
1654 static void OnClickClientChat([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, ClientID client_id)
1655 {
1657 }
1658
1659 static void OnClickClientAuthorize([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, ClientID client_id)
1660 {
1662 Command<Commands::CompanyAllowListControl>::Post(CompanyAllowListCtrlAction::AddKey, NetworkClientInfo::GetByClientID(client_id)->public_key);
1663 }
1664
1671 void RebuildListCompany(CompanyID company_id, CompanyID client_playas, bool can_join_company)
1672 {
1673 ButtonLine &company_line = *this->buttons.emplace_back(std::make_unique<CompanyButtonLine>(company_id));
1674 if (_network_server || company_id == _local_company) {
1675 company_line.AddButton<CompanyButton>(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP, COLOUR_RED, company_id, &NetworkClientListWindow::OnClickCompanyAdmin, company_id == COMPANY_SPECTATOR);
1676 }
1677 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);
1678 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);
1679
1680 bool has_players = false;
1681 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1682 if (ci->client_playas != company_id) continue;
1683 has_players = true;
1684
1685 ButtonLine &line = *this->buttons.emplace_back(std::make_unique<ClientButtonLine>(ci->index));
1686 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);
1687 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);
1688 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);
1689 }
1690
1691 /* Disable the chat button when there are players in this company. */
1692 chat_button.disabled = !has_players;
1693 }
1694
1699 {
1701 CompanyID client_playas = own_ci == nullptr ? COMPANY_SPECTATOR : own_ci->client_playas;
1702
1703 this->buttons.clear();
1704
1705 /* As spectator, show a line to create a new company. */
1706 if (client_playas == COMPANY_SPECTATOR && !NetworkMaxCompaniesReached()) {
1707 ButtonLine &line = *this->buttons.emplace_back(std::make_unique<CompanyButtonLine>(COMPANY_NEW_COMPANY));
1708 line.AddButton<CompanyButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP, COLOUR_ORANGE, COMPANY_SPECTATOR, &NetworkClientListWindow::OnClickCompanyNew);
1709 }
1710
1711 if (client_playas != COMPANY_SPECTATOR) {
1712 this->RebuildListCompany(client_playas, client_playas, false);
1713 }
1714
1715 /* Companies */
1716 for (const Company *c : Company::Iterate()) {
1717 if (c->index == client_playas) continue;
1718
1719 this->RebuildListCompany(c->index, client_playas, _network_server || c->allow_any || (own_ci != nullptr && c->allow_list.Contains(own_ci->public_key)));
1720 }
1721
1722 /* Spectators */
1723 this->RebuildListCompany(COMPANY_SPECTATOR, client_playas, client_playas != COMPANY_SPECTATOR);
1724
1725 this->vscroll->SetCount(this->buttons.size());
1726 }
1727
1728public:
1730 {
1731 this->CreateNestedTree();
1732 this->vscroll = this->GetScrollbar(WID_CL_SCROLLBAR);
1733 this->OnInvalidateData();
1734 this->FinishInitNested(window_number);
1735 }
1736
1737 void OnInit() override
1738 {
1739 this->RebuildList();
1740 }
1741
1742 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1743 {
1744 this->RebuildList();
1745
1746 /* Currently server information is not synced to clients, so we cannot show it on clients. */
1749 }
1750
1751 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1752 {
1753 switch (widget) {
1754 case WID_CL_SERVER_NAME:
1755 case WID_CL_CLIENT_NAME: {
1756 std::string str;
1757 if (widget == WID_CL_SERVER_NAME) {
1758 str = GetString(STR_JUST_RAW_STRING, _network_server ? _settings_client.network.server_name : _network_server_name);
1759 } else {
1761 str = GetString(STR_JUST_RAW_STRING, own_ci != nullptr ? own_ci->client_name : _settings_client.network.client_name);
1762 }
1763 size = GetStringBoundingBox(str);
1764 size.width = std::min(size.width, static_cast<uint>(ScaleGUITrad(200))); // By default, don't open the window too wide.
1765 break;
1766 }
1767
1769 size = maxdim(maxdim(GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_LOCAL), GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_PUBLIC)), GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_INVITE_ONLY));
1770 size.width += padding.width;
1771 size.height += padding.height;
1772 break;
1773
1774 case WID_CL_MATRIX: {
1775 uint height = std::max({GetScaledSpriteSize(SPR_COMPANY_ICON).height, GetScaledSpriteSize(SPR_JOIN).height, GetScaledSpriteSize(SPR_ADMIN).height, GetScaledSpriteSize(SPR_CHAT).height});
1776 height += WidgetDimensions::scaled.framerect.Vertical();
1777 this->line_height = std::max(height, (uint)GetCharacterHeight(FS_NORMAL)) + padding.height;
1778
1779 resize.width = 1;
1780 fill.height = resize.height = this->line_height;
1781 size.height = std::max(size.height, 5 * this->line_height);
1782 break;
1783 }
1784 }
1785 }
1786
1787 void OnResize() override
1788 {
1789 this->vscroll->SetCapacityFromWidget(this, WID_CL_MATRIX);
1790 }
1791
1792 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
1793 {
1794 switch (widget) {
1795 case WID_CL_SERVER_NAME:
1796 return _network_server ? _settings_client.network.server_name : _network_server_name;
1797
1799 return GetString(STR_NETWORK_SERVER_VISIBILITY_LOCAL + to_underlying(_settings_client.network.server_game_type));
1800
1803
1805 return GetString(STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_UNKNOWN + _network_server_connection_type);
1806
1807 case WID_CL_CLIENT_NAME: {
1809 return own_ci != nullptr ? own_ci->client_name : _settings_client.network.client_name;
1810 }
1811
1813 return GetString(STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT, NetworkClientInfo::GetNumItems(), Company::GetNumItems(), NetworkMaxCompaniesAllowed());
1814
1815 default:
1816 return this->Window::GetWidgetString(widget, stringid);
1817 }
1818 }
1819
1820 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1821 {
1822 switch (widget) {
1824 if (!_network_server) break;
1825
1826 this->query_widget = WID_CL_SERVER_NAME_EDIT;
1827 ShowQueryString(_settings_client.network.server_name, STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION, NETWORK_NAME_LENGTH, this, CS_ALPHANUMERAL, QueryStringFlag::LengthIsInChars);
1828 break;
1829
1832 this->query_widget = WID_CL_CLIENT_NAME_EDIT;
1833 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);
1834 break;
1835 }
1837 if (!_network_server) break;
1838
1839 ShowDropDownList(this, BuildVisibilityDropDownList(), to_underlying(_settings_client.network.server_game_type), WID_CL_SERVER_VISIBILITY);
1840 break;
1841
1842 case WID_CL_MATRIX: {
1843 auto it = this->vscroll->GetScrolledItemFromWidget(this->buttons, pt.y, this, WID_CL_MATRIX);
1844 if (it == std::end(this->buttons)) break;
1845
1846 Rect r = this->GetWidget<NWidgetBase>(WID_CL_MATRIX)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
1847 ButtonCommon *button = (*it)->GetButton(r, pt);
1848 if (button == nullptr) break;
1849
1850 button->OnClick(this, pt);
1851 break;
1852 }
1853 }
1854 }
1855
1856 bool OnTooltip([[maybe_unused]] Point pt, WidgetID widget, TooltipCloseCondition close_cond) override
1857 {
1858 switch (widget) {
1859 case WID_CL_MATRIX: {
1860 auto it = this->vscroll->GetScrolledItemFromWidget(this->buttons, pt.y, this, WID_CL_MATRIX);
1861 if (it == std::end(this->buttons)) break;
1862
1863 Rect r = this->GetWidget<NWidgetBase>(WID_CL_MATRIX)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
1864 auto tooltip = (*it)->GetTooltip(r, pt);
1865 if (!tooltip.has_value()) break;
1866
1867 GuiShowTooltips(this, std::move(*tooltip), close_cond);
1868 return true;
1869 };
1870 }
1871
1872 return false;
1873 }
1874
1875 void OnDropdownClose(Point pt, WidgetID widget, int index, int click_result, bool instant_close) override
1876 {
1877 /* If you close the dropdown outside the list, don't take any action. */
1878 if (widget == WID_CL_MATRIX) return;
1879
1880 Window::OnDropdownClose(pt, widget, index, click_result, instant_close);
1881 }
1882
1883 void OnDropdownSelect(WidgetID widget, int index, int) override
1884 {
1885 switch (widget) {
1887 if (!_network_server) break;
1888
1889 _settings_client.network.server_game_type = (ServerGameType)index;
1891 break;
1892
1893 case WID_CL_MATRIX: {
1894 QueryCallbackProc *callback = nullptr;
1895
1896 EncodedString text;
1897 switch (static_cast<DropDownAction>(index)) {
1899 _admin_client_id = this->dd_client_id;
1900 callback = AdminClientKickCallback;
1901 text = GetEncodedString(STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK, NetworkClientInfo::GetByClientID(_admin_client_id)->client_name);
1902 break;
1903
1905 _admin_client_id = this->dd_client_id;
1906 callback = AdminClientBanCallback;
1907 text = GetEncodedString(STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN, NetworkClientInfo::GetByClientID(_admin_client_id)->client_name);
1908 break;
1909
1911 _admin_company_id = this->dd_company_id;
1912 callback = AdminCompanyResetCallback;
1913 text = GetEncodedString(STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET, _admin_company_id);
1914 break;
1915
1917 AutoRestoreBackup cur_company(_current_company, this->dd_company_id);
1918 Command<Commands::CompanyAllowListControl>::Post(CompanyAllowListCtrlAction::AllowAny, {});
1919 return;
1920 }
1921
1923 AutoRestoreBackup cur_company(_current_company, this->dd_company_id);
1924 Command<Commands::CompanyAllowListControl>::Post(CompanyAllowListCtrlAction::AllowListed, {});
1925 return;
1926 }
1927
1928 default:
1929 NOT_REACHED();
1930 }
1931
1932 assert(callback != nullptr);
1933
1934 /* Always ask confirmation for all admin actions. */
1935 ShowQuery(
1936 GetEncodedString(STR_NETWORK_CLIENT_LIST_ASK_CAPTION),
1937 std::move(text),
1938 this, callback);
1939
1940 break;
1941 }
1942
1943 default:
1944 NOT_REACHED();
1945 }
1946
1947 this->SetDirty();
1948 }
1949
1950 void OnQueryTextFinished(std::optional<std::string> str) override
1951 {
1952 if (!str.has_value()) return;
1953
1954 switch (this->query_widget) {
1955 default: NOT_REACHED();
1956
1958 if (!_network_server) break;
1959
1960 SetSettingValue(GetSettingFromName("network.server_name")->AsStringSetting(), *str);
1961 this->InvalidateData();
1962 break;
1963 }
1964
1966 SetSettingValue(GetSettingFromName("network.client_name")->AsStringSetting(), *str);
1967 this->InvalidateData();
1968 break;
1969 }
1970 }
1971 }
1972
1973 void DrawWidget(const Rect &r, WidgetID widget) const override
1974 {
1975 switch (widget) {
1976 case WID_CL_MATRIX: {
1977 Rect ir = r.WithHeight(this->line_height).Shrink(WidgetDimensions::scaled.framerect, RectPadding::zero);
1978
1979 if (this->hover_index >= 0) {
1980 Rect br = r.WithHeight(this->line_height).Translate(0, this->hover_index * this->line_height);
1982 }
1983
1984 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->buttons);
1985 for (auto it = first; it != last; ++it) {
1986 (*it)->Draw(ir);
1987 ir = ir.Translate(0, this->line_height);
1988 }
1989
1990 break;
1991 }
1992 }
1993 }
1994
1995 void OnMouseOver([[maybe_unused]] Point pt, WidgetID widget) override
1996 {
1997 if (widget != WID_CL_MATRIX) {
1998 if (this->hover_index != -1) {
1999 this->hover_index = -1;
2001 }
2002 } else {
2003 int index = this->GetRowFromWidget(pt.y, widget, 0, -1);
2004 if (index != this->hover_index) {
2005 this->hover_index = index;
2007 }
2008 }
2009 }
2010};
2011
2012void ShowClientList()
2013{
2015}
2016
2021
2022struct NetworkJoinStatusWindow : Window {
2023 std::shared_ptr<NetworkAuthenticationPasswordRequest> request{};
2024
2025 NetworkJoinStatusWindow(WindowDesc &desc) : Window(desc)
2026 {
2029 }
2030
2031 void DrawWidget(const Rect &r, WidgetID widget) const override
2032 {
2033 switch (widget) {
2034 case WID_NJS_PROGRESS_BAR: {
2035 /* Draw the % complete with a bar and a text */
2037 Rect ir = r.Shrink(WidgetDimensions::scaled.bevel);
2038 uint8_t progress; // used for progress bar
2039 switch (_network_join_status) {
2042 progress = 10; // first two stages 10%
2043 break;
2045 progress = 15; // third stage is 15%
2046 break;
2048 if (_network_join_bytes_total == 0) {
2049 progress = 15; // We don't have the final size yet; the server is still compressing!
2050 break;
2051 }
2052 [[fallthrough]];
2053
2054 default: // Waiting is 15%, so the remaining downloading of the map is maximum 70%
2055 progress = 15 + _network_join_bytes * (100 - 15) / _network_join_bytes_total;
2056 break;
2057 }
2058 DrawFrameRect(ir.WithWidth(ir.Width() * progress / 100, _current_text_dir == TD_RTL), COLOUR_MAUVE, {});
2059 DrawString(ir.left, ir.right, CentreBounds(ir.top, ir.bottom, GetCharacterHeight(FS_NORMAL)), STR_NETWORK_CONNECTING_1 + to_underlying(_network_join_status), TC_FROMSTRING, SA_HOR_CENTER);
2060 break;
2061 }
2062
2064 switch (_network_join_status) {
2066 DrawStringMultiLine(r, GetString(STR_NETWORK_CONNECTING_WAITING, _network_join_waiting), TC_FROMSTRING, SA_CENTER);
2067 break;
2068
2070 if (_network_join_bytes_total == 0) {
2071 DrawStringMultiLine(r, GetString(STR_NETWORK_CONNECTING_DOWNLOADING_1, _network_join_bytes), TC_FROMSTRING, SA_CENTER);
2072 } else {
2073 DrawStringMultiLine(r, GetString(STR_NETWORK_CONNECTING_DOWNLOADING_2, _network_join_bytes, _network_join_bytes_total), TC_FROMSTRING, SA_CENTER);
2074 }
2075 break;
2076
2077 default:
2078 break;
2079 }
2080 break;
2081 }
2082 }
2083
2084 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2085 {
2086 switch (widget) {
2088 /* Account for the statuses */
2089 for (uint i = 0; i < to_underlying(NetworkJoinStatus::End); i++) {
2090 size = maxdim(size, GetStringBoundingBox(STR_NETWORK_CONNECTING_1 + i));
2091 }
2092 /* For the number of waiting (other) players */
2093 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_CONNECTING_WAITING, GetParamMaxValue(MAX_CLIENTS))));
2094 /* We need some spacing for the 'border' */
2095 size.height += WidgetDimensions::scaled.frametext.Horizontal();
2096 size.width += WidgetDimensions::scaled.frametext.Vertical();
2097 break;
2098
2099 case WID_NJS_PROGRESS_TEXT: {
2100 /* Account for downloading ~ 10 MiB */
2101 uint64_t max_digits = GetParamMaxDigits(8);
2102 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_CONNECTING_DOWNLOADING_1, max_digits, max_digits)));
2103 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_CONNECTING_DOWNLOADING_1, max_digits, max_digits)));
2104 break;
2105 }
2106 }
2107 }
2108
2109 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2110 {
2111 if (widget == WID_NJS_CANCELOK) { // Disconnect button
2113 SwitchToMode(SM_MENU);
2114 ShowNetworkGameWindow();
2115 }
2116 }
2117
2118 void OnQueryTextFinished(std::optional<std::string> str) override
2119 {
2120 if (!str.has_value() || str->empty() || this->request == nullptr) {
2122 return;
2123 }
2124
2125 this->request->Reply(*str);
2126 }
2127};
2128
2129static constexpr std::initializer_list<NWidgetPart> _nested_network_join_status_window_widgets = {
2130 NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_NETWORK_CONNECTING_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2131 NWidget(WWT_PANEL, COLOUR_GREY),
2133 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NJS_PROGRESS_BAR), SetFill(1, 0),
2134 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NJS_PROGRESS_TEXT), SetFill(1, 0), SetMinimalSize(350, 0),
2135 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NJS_CANCELOK), SetMinimalSize(101, 12), SetStringTip(STR_NETWORK_CONNECTION_DISCONNECT), SetFill(1, 0),
2136 EndContainer(),
2137 EndContainer(),
2138};
2139
2140static WindowDesc _network_join_status_window_desc(
2141 WDP_CENTER, {}, 0, 0,
2144 _nested_network_join_status_window_widgets
2145);
2146
2147void ShowJoinStatusWindow()
2148{
2150 new NetworkJoinStatusWindow(_network_join_status_window_desc);
2151}
2152
2153void ShowNetworkNeedPassword(std::shared_ptr<NetworkAuthenticationPasswordRequest> request)
2154{
2156 if (w == nullptr) return;
2157 w->request = std::move(request);
2158
2159 ShowQueryString({}, STR_NETWORK_NEED_GAME_PASSWORD_CAPTION, NETWORK_PASSWORD_LENGTH, w, CS_ALPHANUMERAL, {});
2160}
2161
2165struct NetworkAskRelayWindow : public Window {
2168 std::string token{};
2169
2170 NetworkAskRelayWindow(WindowDesc &desc, Window *parent, std::string_view server_connection_string, std::string &&relay_connection_string, std::string &&token) :
2171 Window(desc),
2174 token(std::move(token))
2175 {
2176 this->parent = parent;
2177 this->InitNested(0);
2178 }
2179
2180 void Close(int data = 0) override
2181 {
2182 if (data == NRWCD_UNHANDLED) _network_coordinator_client.ConnectFailure(this->token, 0);
2183 this->Window::Close();
2184 }
2185
2186 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2187 {
2188 if (widget == WID_NAR_TEXT) {
2189 size = GetStringBoundingBox(GetString(STR_NETWORK_ASK_RELAY_TEXT, this->server_connection_string, this->relay_connection_string));
2190 }
2191 }
2192
2193 void DrawWidget(const Rect &r, WidgetID widget) const override
2194 {
2195 if (widget == WID_NAR_TEXT) {
2196 DrawStringMultiLine(r, GetString(STR_NETWORK_ASK_RELAY_TEXT, this->server_connection_string, this->relay_connection_string), TC_FROMSTRING, SA_CENTER);
2197 }
2198 }
2199
2200 void FindWindowPlacementAndResize(int, int, bool) override
2201 {
2202 /* Position query window over the calling window, ensuring it's within screen bounds. */
2203 this->left = Clamp(parent->left + (parent->width / 2) - (this->width / 2), 0, _screen.width - this->width);
2204 this->top = Clamp(parent->top + (parent->height / 2) - (this->height / 2), 0, _screen.height - this->height);
2205 this->SetDirty();
2206 }
2207
2208 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2209 {
2210 switch (widget) {
2211 case WID_NAR_NO:
2212 _network_coordinator_client.ConnectFailure(this->token, 0);
2213 this->Close(NRWCD_HANDLED);
2214 break;
2215
2216 case WID_NAR_YES_ONCE:
2217 _network_coordinator_client.StartTurnConnection(this->token);
2218 this->Close(NRWCD_HANDLED);
2219 break;
2220
2221 case WID_NAR_YES_ALWAYS:
2222 _settings_client.network.use_relay_service = UseRelayService::Allow;
2223 _network_coordinator_client.StartTurnConnection(this->token);
2224 this->Close(NRWCD_HANDLED);
2225 break;
2226 }
2227 }
2228};
2229
2230static constexpr std::initializer_list<NWidgetPart> _nested_network_ask_relay_widgets = {
2232 NWidget(WWT_CLOSEBOX, COLOUR_RED),
2233 NWidget(WWT_CAPTION, COLOUR_RED, WID_NAR_CAPTION), SetStringTip(STR_NETWORK_ASK_RELAY_CAPTION),
2234 EndContainer(),
2235 NWidget(WWT_PANEL, COLOUR_RED),
2239 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NAR_NO), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_RELAY_NO),
2240 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NAR_YES_ONCE), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_RELAY_YES_ONCE),
2241 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NAR_YES_ALWAYS), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_RELAY_YES_ALWAYS),
2242 EndContainer(),
2243 EndContainer(),
2244 EndContainer(),
2245};
2246
2247static WindowDesc _network_ask_relay_desc(
2248 WDP_CENTER, {}, 0, 0,
2251 _nested_network_ask_relay_widgets
2252);
2253
2260void ShowNetworkAskRelay(std::string_view server_connection_string, std::string &&relay_connection_string, std::string &&token)
2261{
2263
2264 Window *parent = GetMainWindow();
2265 new NetworkAskRelayWindow(_network_ask_relay_desc, parent, server_connection_string, std::move(relay_connection_string), std::move(token));
2266}
2267
2271struct NetworkAskSurveyWindow : public Window {
2272 NetworkAskSurveyWindow(WindowDesc &desc, Window *parent) :
2273 Window(desc)
2274 {
2275 this->parent = parent;
2276 this->InitNested(0);
2277 }
2278
2279 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2280 {
2281 if (widget == WID_NAS_TEXT) {
2282 size = GetStringBoundingBox(STR_NETWORK_ASK_SURVEY_TEXT);
2283 }
2284 }
2285
2286 void DrawWidget(const Rect &r, WidgetID widget) const override
2287 {
2288 if (widget == WID_NAS_TEXT) {
2289 DrawStringMultiLine(r, STR_NETWORK_ASK_SURVEY_TEXT, TC_BLACK, SA_CENTER);
2290 }
2291 }
2292
2293 void FindWindowPlacementAndResize(int, int, bool) override
2294 {
2295 /* Position query window over the calling window, ensuring it's within screen bounds. */
2296 this->left = Clamp(parent->left + (parent->width / 2) - (this->width / 2), 0, _screen.width - this->width);
2297 this->top = Clamp(parent->top + (parent->height / 2) - (this->height / 2), 0, _screen.height - this->height);
2298 this->SetDirty();
2299 }
2300
2301 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2302 {
2303 switch (widget) {
2304 case WID_NAS_PREVIEW:
2305 ShowSurveyResultTextfileWindow(this);
2306 break;
2307
2308 case WID_NAS_LINK:
2309 OpenBrowser(NETWORK_SURVEY_DETAILS_LINK);
2310 break;
2311
2312 case WID_NAS_NO:
2313 _settings_client.network.participate_survey = ParticipateSurvey::No;
2314 this->Close();
2315 break;
2316
2317 case WID_NAS_YES:
2318 _settings_client.network.participate_survey = ParticipateSurvey::Yes;
2319 this->Close();
2320 break;
2321 }
2322 }
2323};
2324
2325static constexpr std::initializer_list<NWidgetPart> _nested_network_ask_survey_widgets = {
2327 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
2328 NWidget(WWT_CAPTION, COLOUR_GREY, WID_NAS_CAPTION), SetStringTip(STR_NETWORK_ASK_SURVEY_CAPTION),
2329 EndContainer(),
2330 NWidget(WWT_PANEL, COLOUR_GREY),
2334 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NAS_PREVIEW), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_SURVEY_PREVIEW),
2335 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NAS_LINK), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_SURVEY_LINK),
2336 EndContainer(),
2338 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NAS_NO), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_SURVEY_NO),
2339 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NAS_YES), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_SURVEY_YES),
2340 EndContainer(),
2341 EndContainer(),
2342 EndContainer(),
2343};
2344
2345static WindowDesc _network_ask_survey_desc(
2346 WDP_CENTER, {}, 0, 0,
2349 _nested_network_ask_survey_widgets
2350);
2351
2356{
2357 /* If we can't send a survey, don't ask the question. */
2358 if constexpr (!NetworkSurveyHandler::IsSurveyPossible()) return;
2359
2361
2362 Window *parent = GetMainWindow();
2363 new NetworkAskSurveyWindow(_network_ask_survey_desc, parent);
2364}
2365
2367struct SurveyResultTextfileWindow : public TextfileWindow {
2369
2370 SurveyResultTextfileWindow(Window *parent, TextfileType file_type) : TextfileWindow(parent, file_type)
2371 {
2372 this->ConstructWindow();
2373
2374 auto result = _survey.CreatePayload(NetworkSurveyHandler::Reason::Preview, true);
2375 this->LoadText(result);
2376 this->InvalidateData();
2377 }
2378};
2379
2380void ShowSurveyResultTextfileWindow(Window *parent)
2381{
2384}
Button shown for either a company or client in the client-list.
Colours colour
The colour of the button.
virtual ~ButtonCommon()=default
Ensure the destructor of the sub classes are called as well.
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.
virtual ~ButtonLine()=default
Ensure the destructor of the sub classes are called as well.
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.
Listing GetListing() const
Export current sort conditions.
void SetSortFuncs(std::span< SortFunction *const > n_funcs)
Hand the sort function pointers to the GUIList.
bool NeedResort()
Check if a resort is needed next loop If used the resort timer will decrease every call till 0.
void SetSortType(uint8_t n_type)
Set the sorttype of the list.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
Baseclass for nested widgets.
uint resize_x
Horizontal resize step (0 means not resizable).
uint fill_x
Horizontal fill stepsize (from initial size, 0 means not resizable).
uint smallest_x
Smallest horizontal size of the widget in a filled window.
uint current_x
Current horizontal size (after resizing).
int pos_y
Vertical position of top-left corner of the widget in the window.
int pos_x
Horizontal position of top-left corner of the widget in the window.
uint smallest_y
Smallest vertical size of the widget in a filled window.
uint fill_y
Vertical fill stepsize (from initial size, 0 means not resizable).
uint resize_y
Vertical resize step (0 means not resizable).
uint current_y
Current vertical size (after resizing).
void Add(std::unique_ptr< NWidgetBase > &&wid)
Append widget wid to container.
Definition widget.cpp:1295
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()
(Re)build the GUI network game list (a.k.a.
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.
~NetworkGameWindow() override
Save the last sorting state.
static const std::initializer_list< GUIGameServerList::SortFunction *const > sorter_funcs
Functions for sorting servers.
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 compatibility icon.
static bool NGameSearchFilter(NetworkGame *const *item, StringFilter &filter)
Filter the servers by the server name.
static Listing last_sorting
Runtime saved values.
static bool NGameMapSizeSorter(NetworkGame *const &a, NetworkGame *const &b)
Sort servers by map size.
static const std::initializer_list< GUIGameServerList::FilterFunction *const > filter_funcs
Functions for filtering servers.
GUIGameServerList servers
List with game servers.
bool searched_internet
Did we ever press "Search Internet" button?
Dimension lock
Dimension of lock icon.
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:2504
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:2451
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, std::string *const persistent_filter_text)
Show a drop down list.
Definition dropdown.cpp:568
std::unique_ptr< DropDownListItem > MakeDropDownListStringItem(StringID str, int value, bool masked, bool shaded)
Creates new DropDownListStringItem.
Definition dropdown.cpp:49
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, DropDownOptions options, std::string *const persistent_filter_text)
Show a drop down list.
Definition dropdown.cpp:585
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.
#define T
Climate temperate.
Definition engines.h:91
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:70
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:980
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:71
StringList _network_host_list
The servers we know.
Definition network.cpp:76
void NetworkQueryServer(std::string_view connection_string)
Query a server to fetch the game-info.
Definition network.cpp:666
void NetworkDisconnect(bool close_admins)
We want to disconnect from the host/clients.
Definition network.cpp:998
bool _network_server
network-server is active
Definition network.cpp:68
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:688
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:782
void NetworkRebuildHostList()
Generates the list of manually added hosts from NetworkGame and dumps them into the array _network_ho...
Definition network.cpp:730
ClientID _network_own_client_id
Our client identifier.
Definition network.cpp:72
void NetworkUpdateServerGameType()
The setting server_game_type was updated; possibly we need to take some action.
Definition network.cpp:1026
bool NetworkValidateServerName(std::string &server_name)
Trim the given server name in place, i.e.
Definition network.cpp:855
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.
@ Waiting
Waiting for other clients to finish downloading the map.
@ End
Sentinel for end-of-enumeration.
@ Authorizing
Starting authorizing the client to join the game and optionally company.
@ Downloading
Downloading the map from the server.
@ Connecting
Opening the connection to the server.
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.
@ Public
The game is publicly accessible.
@ Local
Do not communicate with the game coordinator.
@ InviteOnly
The game can be accessed if you know the invite code.
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:393
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:429
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:118
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:992
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1117
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition widget.cpp:817
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1822
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:768
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing).
Definition window.cpp:3261
Window * parent
Parent window.
Definition window_gui.h:329
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:570
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:518
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
Definition widget.cpp:800
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:1812
void CloseChildWindowById(WindowClass wc, WindowNumber number) const
Close all children a window might have in a head-recursive manner.
Definition window.cpp:1104
bool SetFocusedWidget(WidgetID widget_index)
Set focus within this window to the given widget.
Definition window.cpp:499
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:298
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:1845
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:223
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:990
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:609
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1835
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:327
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:291
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:1209
Window * GetMainWindow()
Get the main window, i.e.
Definition window.cpp:1195
void CloseWindowByClass(WindowClass cls, int data)
Close all windows of a given class.
Definition window.cpp:1222
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:3321
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1166
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.