OpenTTD Source 20260421-master-gc2fbc6fdeb
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
58
60static CompanyID _admin_company_id = CompanyID::Invalid();
61
70
76{
77 DropDownList list;
78
79 list.push_back(MakeDropDownListStringItem(STR_NETWORK_SERVER_VISIBILITY_LOCAL, to_underlying(ServerGameType::Local)));
80 list.push_back(MakeDropDownListStringItem(STR_NETWORK_SERVER_VISIBILITY_INVITE_ONLY, to_underlying(ServerGameType::InviteOnly)));
81 list.push_back(MakeDropDownListStringItem(STR_NETWORK_SERVER_VISIBILITY_PUBLIC, to_underlying(ServerGameType::Public)));
82
83 return list;
84}
85
87using ServerListPosition = int;
89
91class NWidgetServerListHeader : public NWidgetContainer {
92 static const uint MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER = 150;
93public:
96 {
97 auto leaf = std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, Colours::White, WID_NG_NAME, WidgetData{.string = STR_NETWORK_SERVER_LIST_GAME_NAME}, STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP);
98 leaf->SetResize(1, 0);
99 leaf->SetFill(1, 0);
100 this->Add(std::move(leaf));
101
102 this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, Colours::White, WID_NG_CLIENTS, WidgetData{.string = STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION}, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP));
103 this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, Colours::White, WID_NG_MAPSIZE, WidgetData{.string = STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION}, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP));
104 this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, Colours::White, WID_NG_DATE, WidgetData{.string = STR_NETWORK_SERVER_LIST_DATE_CAPTION}, STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP));
105 this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, Colours::White, WID_NG_YEARS, WidgetData{.string = STR_NETWORK_SERVER_LIST_PLAY_TIME_CAPTION}, STR_NETWORK_SERVER_LIST_PLAY_TIME_CAPTION_TOOLTIP));
106
107 leaf = std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, Colours::White, WID_NG_INFO, WidgetData{.string = STR_EMPTY}, STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP);
108 leaf->SetFill(0, 1);
109 this->Add(std::move(leaf));
110 }
111
112 void SetupSmallestSize(Window *w) override
113 {
114 this->smallest_y = 0; // Biggest child.
115 this->fill_x = 1;
116 this->fill_y = 0;
117 this->resize_x = 1; // We only resize in this direction
118 this->resize_y = 0; // We never resize in this direction
119
120 /* First initialise some variables... */
121 for (const auto &child_wid : this->children) {
122 child_wid->SetupSmallestSize(w);
123 this->smallest_y = std::max(this->smallest_y, child_wid->smallest_y + child_wid->padding.Vertical());
124 }
125
126 /* ... then in a second pass make sure the 'current' sizes are set. Won't change for most widgets. */
127 for (const auto &child_wid : this->children) {
128 child_wid->current_x = child_wid->smallest_x;
129 child_wid->current_y = this->smallest_y;
130 }
131
132 this->smallest_x = this->children.front()->smallest_x + this->children.back()->smallest_x; // First and last are always shown, rest not
133 this->ApplyAspectRatio();
134 }
135
136 void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override
137 {
138 assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
139
140 this->pos_x = x;
141 this->pos_y = y;
142 this->current_x = given_width;
143 this->current_y = given_height;
144
145 given_width -= this->children.back()->smallest_x;
146 /* The first and last widget are always visible, determine which other should be visible */
147 if (this->children.size() > 2) {
148 auto first = std::next(std::begin(this->children));
149 auto last = std::prev(std::end(this->children));
150 for (auto it = first; it != last; ++it) {
151 auto &child_wid = *it;
152 if (given_width > ScaleGUITrad(MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER) + child_wid->smallest_x && (*std::prev(it))->current_x != 0) {
153 given_width -= child_wid->smallest_x;
154 child_wid->current_x = child_wid->smallest_x; /* Make visible. */
155 } else {
156 child_wid->current_x = 0; /* Make invisible. */
157 }
158 }
159 }
160
161 /* All remaining space goes to the first (name) widget */
162 this->children.front()->current_x = given_width;
163
164 /* Now assign the widgets to their rightful place */
165 uint position = 0; // Place to put next child relative to origin of the container.
166 auto assign_position = [&](const std::unique_ptr<NWidgetBase> &child_wid) {
167 if (child_wid->current_x != 0) {
168 child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl);
169 position += child_wid->current_x;
170 }
171 };
172
173 if (rtl) {
174 std::for_each(std::rbegin(this->children), std::rend(this->children), assign_position);
175 } else {
176 std::for_each(std::begin(this->children), std::end(this->children), assign_position);
177 }
178 }
179};
180
182class NetworkGameWindow : public Window {
183protected:
185 static Listing last_sorting;
186
188 static const std::initializer_list<GUIGameServerList::SortFunction * const> sorter_funcs;
190 static const std::initializer_list<GUIGameServerList::FilterFunction * const> filter_funcs;
191
192 NetworkGame *server = nullptr;
196 Scrollbar *vscroll = nullptr;
199 bool searched_internet = false;
200
203
210 {
211 if (!this->servers.NeedRebuild()) return;
212
213 /* Create temporary array of games to use for listing */
214 this->servers.clear();
215
216 bool found_current_server = false;
217 bool found_last_joined = false;
218 for (const auto &ngl : _network_game_list) {
219 this->servers.push_back(ngl.get());
220 if (ngl.get() == this->server) {
221 found_current_server = true;
222 }
223 if (ngl.get() == this->last_joined) {
224 found_last_joined = true;
225 }
226 }
227 /* A refresh can cause the current server to be delete; so unselect. */
228 if (!found_last_joined) {
229 this->last_joined = nullptr;
230 }
231 if (!found_current_server) {
232 this->server = nullptr;
233 this->list_pos = SLP_INVALID;
234 }
235
236 /* Apply the filter condition immediately, if a search string has been provided. */
237 StringFilter sf;
238 sf.SetFilterTerm(this->filter_editbox.text.GetText());
239
240 if (!sf.IsEmpty()) {
241 this->servers.SetFilterState(true);
242 this->servers.Filter(sf);
243 } else {
244 this->servers.SetFilterState(false);
245 }
246
247 this->servers.RebuildDone();
248 this->vscroll->SetCount(this->servers.size());
249
250 /* Sort the list of network games as requested. */
251 this->servers.Sort();
252 this->UpdateListPos();
253 }
254
256 static bool NGameNameSorter(NetworkGame * const &a, NetworkGame * const &b)
257 {
258 int r = StrNaturalCompare(a->info.server_name, b->info.server_name, true); // Sort by name (natural sorting).
259 if (r == 0) r = a->connection_string.compare(b->connection_string);
260
261 return r < 0;
262 }
263
270 static bool NGameClientSorter(NetworkGame * const &a, NetworkGame * const &b)
271 {
272 /* Reverse as per default we are interested in most-clients first */
273 int r = a->info.clients_on - b->info.clients_on;
274
275 if (r == 0) r = a->info.clients_max - b->info.clients_max;
276 if (r == 0) return NGameNameSorter(a, b);
277
278 return r < 0;
279 }
280
282 static bool NGameMapSizeSorter(NetworkGame * const &a, NetworkGame * const &b)
283 {
284 /* Sort by the area of the map. */
285 int r = (a->info.map_height) * (a->info.map_width) - (b->info.map_height) * (b->info.map_width);
286
287 if (r == 0) r = a->info.map_width - b->info.map_width;
288 return (r != 0) ? r < 0 : NGameClientSorter(a, b);
289 }
290
292 static bool NGameCalendarDateSorter(NetworkGame * const &a, NetworkGame * const &b)
293 {
294 auto r = a->info.calendar_date - b->info.calendar_date;
295 return (r != 0) ? r < 0 : NGameClientSorter(a, b);
296 }
297
299 static bool NGameTicksPlayingSorter(NetworkGame * const &a, NetworkGame * const &b)
300 {
301 if (a->info.ticks_playing == b->info.ticks_playing) {
302 return NGameClientSorter(a, b);
303 }
304 return a->info.ticks_playing < b->info.ticks_playing;
305 }
306
312 static bool NGameAllowedSorter(NetworkGame * const &a, NetworkGame * const &b)
313 {
314 /* The servers we do not know anything about (the ones that did not reply) should be at the bottom) */
315 int r = a->info.server_revision.empty() - b->info.server_revision.empty();
316
317 /* Reverse default as we are interested in version-compatible clients first */
318 if (r == 0) r = b->info.version_compatible - a->info.version_compatible;
319 /* The version-compatible ones are then sorted with NewGRF compatible first, incompatible last */
320 if (r == 0) r = b->info.compatible - a->info.compatible;
321 /* Passworded servers should be below unpassworded servers */
322 if (r == 0) r = a->info.use_password - b->info.use_password;
323
324 /* Finally sort on the number of clients of the server in reverse order. */
325 return (r != 0) ? r < 0 : NGameClientSorter(b, a);
326 }
327
330 {
331 if (this->servers.Sort()) this->UpdateListPos();
332 }
333
336 {
337 auto it = std::ranges::find(this->servers, this->server);
338 if (it == std::end(this->servers)) {
339 this->list_pos = SLP_INVALID;
340 } else {
341 this->list_pos = static_cast<ServerListPosition>(std::distance(std::begin(this->servers), it));
342 }
343 }
344
346 static bool NGameSearchFilter(NetworkGame * const *item, StringFilter &filter)
347 {
348 assert(item != nullptr);
349 assert((*item) != nullptr);
350
351 filter.ResetState();
352 filter.AddLine((*item)->info.server_name);
353 return filter.GetState();
354 }
355
362 void DrawServerLine(const NetworkGame *cur_item, int y, bool highlight) const
363 {
364 Rect name = this->GetWidget<NWidgetBase>(WID_NG_NAME)->GetCurrentRect();
365 Rect info = this->GetWidget<NWidgetBase>(WID_NG_INFO)->GetCurrentRect();
366
367 /* show highlighted item with a different colour */
368 if (highlight) {
369 Rect r = {std::min(name.left, info.left), y, std::max(name.right, info.right), y + (int)this->resize.step_height - 1};
371 }
372
373 /* Offset to vertically position text. */
374 int text_y_offset = WidgetDimensions::scaled.matrix.top + (this->resize.step_height - WidgetDimensions::scaled.matrix.Vertical() - GetCharacterHeight(FontSize::Normal)) / 2;
375
376 info = info.Shrink(WidgetDimensions::scaled.framerect);
377 name = name.Shrink(WidgetDimensions::scaled.framerect);
378 DrawString(name.left, name.right, y + text_y_offset, cur_item->info.server_name, TC_BLACK);
379
380 /* only draw details if the server is online */
381 if (cur_item->status == NGLS_ONLINE) {
382 if (const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(WID_NG_CLIENTS); nwid->current_x != 0) {
383 Rect clients = nwid->GetCurrentRect();
384 DrawString(clients.left, clients.right, y + text_y_offset,
385 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),
386 TC_FROMSTRING, SA_HOR_CENTER);
387 }
388
389 if (const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(WID_NG_MAPSIZE); nwid->current_x != 0) {
390 /* map size */
391 Rect mapsize = nwid->GetCurrentRect();
392 DrawString(mapsize.left, mapsize.right, y + text_y_offset,
393 GetString(STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT, cur_item->info.map_width, cur_item->info.map_height),
394 TC_FROMSTRING, SA_HOR_CENTER);
395 }
396
397 if (const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(WID_NG_DATE); nwid->current_x != 0) {
398 /* current date */
399 Rect date = nwid->GetCurrentRect();
400 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(cur_item->info.calendar_date);
401 DrawString(date.left, date.right, y + text_y_offset,
402 GetString(STR_JUST_INT, ymd.year),
403 TC_BLACK, SA_HOR_CENTER);
404 }
405
406 if (const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(WID_NG_YEARS); nwid->current_x != 0) {
407 /* play time */
408 Rect years = nwid->GetCurrentRect();
409 const auto play_time = cur_item->info.ticks_playing / Ticks::TICKS_PER_SECOND;
410 DrawString(years.left, years.right, y + text_y_offset,
411 GetString(STR_NETWORK_SERVER_LIST_PLAY_TIME_SHORT, play_time / 60 / 60, (play_time / 60) % 60),
412 TC_BLACK, SA_HOR_CENTER);
413 }
414
415 /* Set top and bottom of info rect to current row. */
416 info.top = y;
417 info.bottom = y + this->resize.step_height - 1;
418
419 bool rtl = _current_text_dir == TD_RTL;
420
421 /* draw a lock if the server is password protected */
422 if (cur_item->info.use_password) DrawSpriteIgnorePadding(SPR_LOCK, PAL_NONE, info.WithWidth(this->lock.width, rtl), SA_CENTER);
423
424 /* draw red or green icon, depending on compatibility with server */
425 PaletteID pal = cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED);
426 DrawSpriteIgnorePadding(SPR_BLOT, pal, info.WithWidth(this->blot.width, !rtl), SA_CENTER);
427 }
428 }
429
438 {
439 if (this->list_pos == SLP_INVALID) return; // no server selected
440 this->vscroll->ScrollTowards(this->list_pos);
441 }
442
443public:
449 {
450 this->CreateNestedTree();
451 this->vscroll = this->GetScrollbar(WID_NG_SCROLLBAR);
453
454 this->querystrings[WID_NG_CLIENT] = &this->name_editbox;
455 this->name_editbox.text.Assign(_settings_client.network.client_name);
456
457 this->querystrings[WID_NG_FILTER] = &this->filter_editbox;
458 this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
460
461 /* As the Game Coordinator doesn't support "websocket" servers yet, we
462 * let "os/emscripten/pre.js" hardcode a list of servers people can
463 * join. This means the serverlist is curated for now, but it is the
464 * best we can offer. */
465#ifdef __EMSCRIPTEN__
466 EM_ASM(if (window["openttd_server_list"]) openttd_server_list());
467#endif
468
469 this->last_joined = NetworkAddServer(_settings_client.network.last_joined, false);
470 this->server = this->last_joined;
471
472 this->servers.SetListing(this->last_sorting);
475 this->servers.ForceRebuild();
476 }
477
480 {
481 this->last_sorting = this->servers.GetListing();
482 }
483
484 void OnInit() override
485 {
486 this->lock = GetScaledSpriteSize(SPR_LOCK);
487 this->blot = GetScaledSpriteSize(SPR_BLOT);
488 }
489
490 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
491 {
492 switch (widget) {
493 case WID_NG_MATRIX:
494 fill.height = resize.height = std::max<uint>(this->blot.height, GetCharacterHeight(FontSize::Normal)) + padding.height;
495 size.height = 12 * resize.height;
496 break;
497
499 size.height = std::max<uint>(this->blot.height, GetCharacterHeight(FontSize::Normal)) + WidgetDimensions::scaled.matrix.Vertical();
500 break;
501
503 size.width = NWidgetScrollbar::GetVerticalDimension().width;
504 break;
505
506 case WID_NG_NAME:
507 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
508 break;
509
510 case WID_NG_CLIENTS: {
511 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
512 auto max_clients = GetParamMaxValue(MAX_CLIENTS);
513 auto max_companies = GetParamMaxValue(MAX_COMPANIES);
514 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_SERVER_LIST_GENERAL_ONLINE, max_clients, max_clients, max_companies, max_companies)));
515 break;
516 }
517
518 case WID_NG_MAPSIZE: {
519 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
520 auto max_map_size = GetParamMaxValue(MAX_MAP_SIZE);
521 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT, max_map_size, max_map_size)));
522 break;
523 }
524
525 case WID_NG_DATE:
526 case WID_NG_YEARS:
527 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
528 size = maxdim(size, GetStringBoundingBox(GetString(STR_JUST_INT, GetParamMaxValue(5))));
529 break;
530
531 case WID_NG_INFO:
532 size.width = this->lock.width + WidgetDimensions::scaled.hsep_normal + this->blot.width + padding.width;
533 size.height = std::max(this->lock.height, this->blot.height) + padding.height;
534 break;
535 }
536 }
537
538 void DrawWidget(const Rect &r, WidgetID widget) const override
539 {
540 switch (widget) {
541 case WID_NG_MATRIX: {
542 uint16_t y = r.top;
543
544 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->servers);
545 for (auto it = first; it != last; ++it) {
546 const NetworkGame *ngl = *it;
547 this->DrawServerLine(ngl, y, ngl == this->server);
548 y += this->resize.step_height;
549 }
550 break;
551 }
552
554 /* Draw the last joined server, if any */
555 if (this->last_joined != nullptr) this->DrawServerLine(this->last_joined, r.top, this->last_joined == this->server);
556 break;
557
558 case WID_NG_DETAILS:
559 this->DrawDetails(r);
560 break;
561
562 case WID_NG_NAME:
563 case WID_NG_CLIENTS:
564 case WID_NG_MAPSIZE:
565 case WID_NG_DATE:
566 case WID_NG_YEARS:
567 case WID_NG_INFO:
568 if (widget - WID_NG_NAME == this->servers.SortType()) this->DrawSortButtonState(widget, this->servers.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
569 break;
570 }
571 }
572
573
574 void OnPaint() override
575 {
576 if (this->servers.NeedRebuild()) {
578 }
579 if (this->servers.NeedResort()) {
580 this->SortNetworkGameList();
581 }
582
583 NetworkGame *sel = this->server;
584 /* 'Refresh' button invisible if no server selected */
585 this->SetWidgetDisabledState(WID_NG_REFRESH, sel == nullptr);
586 /* 'Join' button disabling conditions */
587 this->SetWidgetDisabledState(WID_NG_JOIN, sel == nullptr || // no Selected Server
588 sel->status != NGLS_ONLINE || // Server offline
589 sel->info.clients_on >= sel->info.clients_max || // Server full
590 !sel->info.compatible); // Revision mismatch
591
592 this->SetWidgetLoweredState(WID_NG_REFRESH, sel != nullptr && sel->refreshing);
593
594 /* 'NewGRF Settings' button invisible if no NewGRF is used */
595 bool changed = false;
596 changed |= this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == nullptr || sel->status != NGLS_ONLINE || sel->info.grfconfig.empty() ? SZSP_NONE : 0);
597 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);
598 if (changed) {
599 this->ReInit();
600 return;
601 }
602
603#ifdef __EMSCRIPTEN__
608#endif
609
610 this->DrawWidgets();
611 }
612
618 {
619 if (this->server == nullptr) return STR_NETWORK_SERVER_LIST_GAME_INFO;
620 switch (this->server->status) {
621 case NGLS_OFFLINE: return STR_NETWORK_SERVER_LIST_SERVER_OFFLINE;
622 case NGLS_ONLINE: return STR_NETWORK_SERVER_LIST_GAME_INFO;
623 case NGLS_FULL: return STR_NETWORK_SERVER_LIST_SERVER_FULL;
624 case NGLS_BANNED: return STR_NETWORK_SERVER_LIST_SERVER_BANNED;
625 case NGLS_TOO_OLD: return STR_NETWORK_SERVER_LIST_SERVER_TOO_OLD;
626 default: NOT_REACHED();
627 }
628 }
629
634 void DrawDetails(const Rect &r) const
635 {
636 NetworkGame *sel = this->server;
637
638 Rect tr = r.Shrink(WidgetDimensions::scaled.frametext);
639 StringID header_msg = this->GetHeaderString();
640 int header_height = GetStringHeight(header_msg, tr.Width()) +
641 (sel == nullptr ? 0 : GetStringHeight(sel->info.server_name, tr.Width())) +
642 WidgetDimensions::scaled.frametext.Vertical();
643
644 /* Height for the title banner */
645 Rect hr = r.WithHeight(header_height).Shrink(WidgetDimensions::scaled.frametext);
646 tr.top += header_height;
647
648 /* Draw the right menu */
649 /* Create the nice darker rectangle at the details top */
651 hr.top = DrawStringMultiLine(hr, header_msg, TC_FROMSTRING, SA_HOR_CENTER);
652 if (sel == nullptr) return;
653
654 hr.top = DrawStringMultiLine(hr, sel->info.server_name, TC_ORANGE, SA_HOR_CENTER); // game name
655 if (sel->status != NGLS_ONLINE) {
656 tr.top = DrawStringMultiLine(tr, header_msg, TC_FROMSTRING, SA_HOR_CENTER);
657 } else { // show game info
658 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));
659
660 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_LANDSCAPE, STR_CLIMATE_TEMPERATE_LANDSCAPE + to_underlying(sel->info.landscape))); // landscape
661
662 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_MAP_SIZE, sel->info.map_width, sel->info.map_height)); // map size
663
664 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_SERVER_VERSION, sel->info.server_revision)); // server version
665
666 StringID invite_or_address = sel->connection_string.starts_with("+") ? STR_NETWORK_SERVER_LIST_INVITE_CODE : STR_NETWORK_SERVER_LIST_SERVER_ADDRESS;
667 tr.top = DrawStringMultiLine(tr, GetString(invite_or_address, sel->connection_string)); // server address / invite code
668
669 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_START_DATE, sel->info.calendar_start)); // start date
670
671 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_CURRENT_DATE, sel->info.calendar_date)); // current date
672
673 const auto play_time = sel->info.ticks_playing / Ticks::TICKS_PER_SECOND;
674 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_PLAY_TIME, play_time / 60 / 60, (play_time / 60) % 60)); // play time
675
676 if (sel->info.gamescript_version != -1) {
677 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_GAMESCRIPT, sel->info.gamescript_name, sel->info.gamescript_version)); // gamescript name and version
678 }
679
680 tr.top += WidgetDimensions::scaled.vsep_wide;
681
682 if (!sel->info.compatible) {
683 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
684 } else if (sel->info.clients_on == sel->info.clients_max) {
685 /* Show: server full, when clients_on == max_clients */
686 DrawStringMultiLine(tr, STR_NETWORK_SERVER_LIST_SERVER_FULL, TC_FROMSTRING, SA_HOR_CENTER); // server full
687 } else if (sel->info.use_password) {
688 DrawStringMultiLine(tr, STR_NETWORK_SERVER_LIST_PASSWORD, TC_FROMSTRING, SA_HOR_CENTER); // password warning
689 }
690 }
691 }
692
693 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
694 {
695 switch (widget) {
696 case WID_NG_NAME: // Sort by name
697 case WID_NG_CLIENTS: // Sort by connected clients
698 case WID_NG_MAPSIZE: // Sort by map size
699 case WID_NG_DATE: // Sort by date
700 case WID_NG_YEARS: // Sort by years
701 case WID_NG_INFO: // Connectivity (green dot)
702 if (this->servers.SortType() == widget - WID_NG_NAME) {
703 this->servers.ToggleSortOrder();
704 if (this->list_pos != SLP_INVALID) this->list_pos = (ServerListPosition)this->servers.size() - this->list_pos - 1;
705 } else {
706 this->servers.SetSortType(widget - WID_NG_NAME);
707 this->servers.ForceResort();
708 this->SortNetworkGameList();
709 }
711 this->SetDirty();
712 break;
713
714 case WID_NG_MATRIX: { // Show available network games
715 auto it = this->vscroll->GetScrolledItemFromWidget(this->servers, pt.y, this, WID_NG_MATRIX);
716 this->server = (it != this->servers.end()) ? *it : nullptr;
717 this->list_pos = (server == nullptr) ? SLP_INVALID : it - this->servers.begin();
718 this->SetDirty();
719
720 if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
721 break;
722 }
723
724 case WID_NG_LASTJOINED: {
725 if (this->last_joined != nullptr) {
726 this->server = this->last_joined;
727
728 /* search the position of the newly selected server */
729 this->UpdateListPos();
731 this->SetDirty();
732
733 if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
734 }
735 break;
736 }
737
739 _network_coordinator_client.GetListing();
740 this->searched_internet = true;
741 break;
742
745 break;
746
747 case WID_NG_ADD: // Add a server
749 _settings_client.network.connect_to_ip,
750 STR_NETWORK_SERVER_LIST_ENTER_SERVER_ADDRESS,
751 NETWORK_HOSTNAME_PORT_LENGTH, // maximum number of characters including '\0'
753 break;
754
755 case WID_NG_START: // Start server
757 break;
758
759 case WID_NG_JOIN: // Join Game
760 if (this->server != nullptr) {
762 }
763 break;
764
765 case WID_NG_REFRESH: // Refresh
766 if (this->server != nullptr && !this->server->refreshing) NetworkQueryServer(this->server->connection_string);
767 break;
768
769 case WID_NG_NEWGRF: // NewGRF Settings
770 if (this->server != nullptr) ShowNewGRFSettings(false, false, false, this->server->info.grfconfig);
771 break;
772
773 case WID_NG_NEWGRF_MISSING: // Find missing content online
774 if (this->server != nullptr) ShowMissingContentWindow(this->server->info.grfconfig);
775 break;
776 }
777 }
778
784 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
785 {
786 this->servers.ForceRebuild();
787 this->SetDirty();
788 }
789
790 EventState OnKeyPress([[maybe_unused]] char32_t key, uint16_t keycode) override
791 {
793
794 /* handle up, down, pageup, pagedown, home and end */
795 if (this->vscroll->UpdateListPositionOnKeyPress(this->list_pos, keycode) == ES_HANDLED) {
796 if (this->list_pos == SLP_INVALID) return ES_HANDLED;
797
798 this->server = this->servers[this->list_pos];
799
800 /* Scroll to the new server if it is outside the current range. */
802
803 /* redraw window */
804 this->SetDirty();
805 return ES_HANDLED;
806 }
807
808 if (this->server != nullptr) {
809 if (keycode == WKC_DELETE) { // Press 'delete' to remove servers
810 NetworkGameListRemoveItem(this->server);
811 if (this->server == this->last_joined) this->last_joined = nullptr;
812 this->server = nullptr;
813 this->list_pos = SLP_INVALID;
814 }
815 }
816
817 return state;
818 }
819
820 void OnEditboxChanged(WidgetID wid) override
821 {
822 switch (wid) {
823 case WID_NG_FILTER: {
824 this->servers.ForceRebuild();
827 this->SetDirty();
828 break;
829 }
830
831 case WID_NG_CLIENT:
832 /* Validation of the name will happen once the user tries to join or start a game, as getting
833 * error messages while typing (e.g. when you clear the name) defeats the purpose of the check. */
834 _settings_client.network.client_name = this->name_editbox.text.GetText();
835 break;
836 }
837 }
838
839 void OnQueryTextFinished(std::optional<std::string> str) override
840 {
841 if (!str.has_value() || str->empty()) return;
842
843 _settings_client.network.connect_to_ip = std::move(*str);
844 NetworkAddServer(_settings_client.network.connect_to_ip);
846 }
847
848 void OnResize() override
849 {
850 this->vscroll->SetCapacityFromWidget(this, WID_NG_MATRIX);
851 }
852
854 const IntervalTimer<TimerWindow> refresh_interval = {std::chrono::seconds(30), [this](uint) {
855 if (!this->searched_internet) return;
856
857 _network_coordinator_client.GetListing();
858 }};
859};
860
862const std::initializer_list<GUIGameServerList::SortFunction * const> NetworkGameWindow::sorter_funcs = {
869};
870
871const std::initializer_list<GUIGameServerList::FilterFunction * const> NetworkGameWindow::filter_funcs = {
873};
874
876static constexpr std::initializer_list<NWidgetPart> _nested_network_game_widgets = {
877 /* TOP */
880 NWidget(WWT_CAPTION, Colours::LightBlue), SetStringTip(STR_NETWORK_SERVER_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
882 EndContainer(),
886 /* LEFT SIDE */
891 SetStringTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
892 EndContainer(),
895 NWidgetFunction([]() -> std::unique_ptr<NWidgetBase> { return std::make_unique<NWidgetServerListHeader>(); }),
897 SetMatrixDataTip(1, 0, STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT), SetScrollbar(WID_NG_SCROLLBAR),
898 EndContainer(),
900 EndContainer(),
903 SetStringTip(STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER), SetResize(1, 0),
906 SetToolTip(STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST_TOOLTIP),
907 EndContainer(),
909 EndContainer(),
910 EndContainer(),
911 EndContainer(),
912 /* RIGHT SIDE */
915 NWidget(WWT_TEXT, Colours::Invalid, WID_NG_CLIENT_LABEL), SetStringTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME),
917 SetStringTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE, STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP),
918 EndContainer(),
921 EndContainer(),
924 NWidget(WWT_PUSHTXTBTN, Colours::White, WID_NG_NEWGRF_MISSING), SetFill(1, 0), SetStringTip(STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON, STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP),
925 EndContainer(),
927 NWidget(WWT_PUSHTXTBTN, Colours::White, WID_NG_NEWGRF), SetFill(1, 0), SetStringTip(STR_MAPGEN_NEWGRF_SETTINGS, STR_MAPGEN_NEWGRF_SETTINGS_TOOLTIP),
928 EndContainer(),
930 NWidget(WWT_PUSHTXTBTN, Colours::White, WID_NG_JOIN), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_JOIN_GAME),
931 NWidget(WWT_PUSHTXTBTN, Colours::White, WID_NG_REFRESH), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_REFRESH, STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP),
932 EndContainer(),
933 EndContainer(),
934 EndContainer(),
935 EndContainer(),
936 EndContainer(),
937 /* BOTTOM */
939 NWidget(WWT_PUSHTXTBTN, Colours::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),
940 NWidget(WWT_PUSHTXTBTN, Colours::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),
941 NWidget(WWT_PUSHTXTBTN, Colours::White, WID_NG_ADD), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_ADD_SERVER, STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP),
942 NWidget(WWT_PUSHTXTBTN, Colours::White, WID_NG_START), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_START_SERVER, STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP),
943 EndContainer(),
944 EndContainer(),
945 /* Resize button. */
947 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
949 EndContainer(),
950 EndContainer(),
951};
952
955 WDP_CENTER, "list_servers", 1000, 730,
957 {},
959);
960
963{
964 static bool first = true;
966
967 /* Only show once */
968 if (first) {
969 first = false;
970 /* Add all servers from the config file to our list. */
971 for (const auto &iter : _network_host_list) {
972 NetworkAddServer(iter);
973 }
974 }
975
977}
978
983
989 {
991
992 this->querystrings[WID_NSS_GAMENAME] = &this->name_editbox;
993 this->name_editbox.text.Assign(_settings_client.network.server_name);
994
996 }
997
998 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
999 {
1000 switch (widget) {
1002 return GetString(STR_NETWORK_SERVER_VISIBILITY_LOCAL + to_underlying(_settings_client.network.server_game_type));
1003
1005 return GetString(STR_NETWORK_START_SERVER_CLIENTS_SELECT, _settings_client.network.max_clients);
1006
1008 return GetString(STR_NETWORK_START_SERVER_COMPANIES_SELECT, _settings_client.network.max_companies);
1009
1010 default:
1011 return this->Window::GetWidgetString(widget, stringid);
1012 }
1013 }
1014
1015 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1016 {
1017 switch (widget) {
1019 size = maxdim(maxdim(GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_LOCAL), GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_PUBLIC)), GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_INVITE_ONLY));
1020 size.width += padding.width;
1021 size.height += padding.height;
1022 break;
1023 }
1024 }
1025
1026 void DrawWidget(const Rect &r, WidgetID widget) const override
1027 {
1028 switch (widget) {
1029 case WID_NSS_SETPWD:
1030 /* If password is set, draw red '*' next to 'Set password' button. */
1031 if (!_settings_client.network.server_password.empty()) DrawString(r.right + WidgetDimensions::scaled.framerect.left, this->width - WidgetDimensions::scaled.framerect.right, r.top, "*", TC_RED);
1032 }
1033 }
1034
1035 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1036 {
1037 switch (widget) {
1038 case WID_NSS_CANCEL: // Cancel button
1040 break;
1041
1042 case WID_NSS_SETPWD: // Set password button
1043 this->widget_id = WID_NSS_SETPWD;
1044 ShowQueryString(_settings_client.network.server_password, STR_NETWORK_START_SERVER_SET_PASSWORD, NETWORK_PASSWORD_LENGTH, this, CS_ALPHANUMERAL, {});
1045 break;
1046
1047 case WID_NSS_CONNTYPE_BTN: // Connection type
1049 break;
1050
1051 case WID_NSS_CLIENTS_BTND: case WID_NSS_CLIENTS_BTNU: // Click on up/down button for number of clients
1052 case WID_NSS_COMPANIES_BTND: case WID_NSS_COMPANIES_BTNU: // Click on up/down button for number of companies
1053 /* Don't allow too fast scrolling. */
1054 if (!this->flags.Test(WindowFlag::Timeout) || this->timeout_timer <= 1) {
1055 this->HandleButtonClick(widget);
1056 this->SetDirty();
1057 switch (widget) {
1058 default: NOT_REACHED();
1060 _settings_client.network.max_clients = Clamp(_settings_client.network.max_clients + widget - WID_NSS_CLIENTS_TXT, 2, MAX_CLIENTS);
1061 break;
1063 _settings_client.network.max_companies = Clamp(_settings_client.network.max_companies + widget - WID_NSS_COMPANIES_TXT, 1, MAX_COMPANIES);
1064 break;
1065 }
1066 }
1067 _left_button_clicked = false;
1068 break;
1069
1070 case WID_NSS_CLIENTS_TXT: // Click on number of clients
1071 this->widget_id = WID_NSS_CLIENTS_TXT;
1072 ShowQueryString(GetString(STR_JUST_INT, _settings_client.network.max_clients), STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS, 4, this, CS_NUMERAL, {});
1073 break;
1074
1075 case WID_NSS_COMPANIES_TXT: // Click on number of companies
1076 this->widget_id = WID_NSS_COMPANIES_TXT;
1077 ShowQueryString(GetString(STR_JUST_INT, _settings_client.network.max_companies), STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES, 3, this, CS_NUMERAL, {});
1078 break;
1079
1080 case WID_NSS_GENERATE_GAME: // Start game
1081 if (!CheckServerName()) return;
1082 _is_network_server = true;
1083 if (_ctrl_pressed) {
1085 } else {
1087 }
1088 break;
1089
1090 case WID_NSS_LOAD_GAME:
1091 if (!CheckServerName()) return;
1092 _is_network_server = true;
1094 break;
1095
1097 if (!CheckServerName()) return;
1098 _is_network_server = true;
1100 break;
1101
1103 if (!CheckServerName()) return;
1104 _is_network_server = true;
1106 break;
1107 }
1108 }
1109
1110 void OnDropdownSelect(WidgetID widget, int index, int) override
1111 {
1112 switch (widget) {
1114 _settings_client.network.server_game_type = (ServerGameType)index;
1115 break;
1116 default:
1117 NOT_REACHED();
1118 }
1119
1120 this->SetDirty();
1121 }
1122
1128 {
1129 std::string str{this->name_editbox.text.GetText()};
1130 if (!NetworkValidateServerName(str)) return false;
1131
1132 SetSettingValue(GetSettingFromName("network.server_name")->AsStringSetting(), std::move(str));
1133 return true;
1134 }
1135
1140
1141 void OnQueryTextFinished(std::optional<std::string> str) override
1142 {
1143 if (!str.has_value()) return;
1144
1145 if (this->widget_id == WID_NSS_SETPWD) {
1146 _settings_client.network.server_password = std::move(*str);
1147 } else {
1148 auto value = ParseInteger<int32_t>(*str, 10, true);
1149 if (!value.has_value()) return;
1150 this->SetWidgetDirty(this->widget_id);
1151 switch (this->widget_id) {
1152 default: NOT_REACHED();
1153 case WID_NSS_CLIENTS_TXT: _settings_client.network.max_clients = Clamp(*value, 2, MAX_CLIENTS); break;
1154 case WID_NSS_COMPANIES_TXT: _settings_client.network.max_companies = Clamp(*value, 1, MAX_COMPANIES); break;
1155 }
1156 }
1157
1158 this->SetDirty();
1159 }
1160};
1161
1163static constexpr std::initializer_list<NWidgetPart> _nested_network_start_server_window_widgets = {
1166 NWidget(WWT_CAPTION, Colours::LightBlue), SetStringTip(STR_NETWORK_START_SERVER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1167 EndContainer(),
1172 /* Game name widgets */
1173 NWidget(WWT_TEXT, Colours::Invalid, WID_NSS_GAMENAME_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME),
1174 NWidget(WWT_EDITBOX, Colours::LightBlue, WID_NSS_GAMENAME), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE, STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP),
1175 EndContainer(),
1176
1179 NWidget(WWT_TEXT, Colours::Invalid, WID_NSS_CONNTYPE_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_VISIBILITY_LABEL),
1180 NWidget(WWT_DROPDOWN, Colours::LightBlue, WID_NSS_CONNTYPE_BTN), SetFill(1, 0), SetToolTip(STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP),
1181 EndContainer(),
1183 NWidget(NWID_SPACER), SetFill(1, 1),
1184 NWidget(WWT_PUSHTXTBTN, Colours::White, WID_NSS_SETPWD), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_SET_PASSWORD, STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP),
1185 EndContainer(),
1186 EndContainer(),
1187
1190 NWidget(WWT_TEXT, Colours::Invalid, WID_NSS_CLIENTS_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS),
1192 NWidget(WWT_IMGBTN, Colours::LightBlue, 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),
1193 NWidget(WWT_PUSHTXTBTN, Colours::LightBlue, WID_NSS_CLIENTS_TXT), SetFill(1, 0), SetToolTip(STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
1194 NWidget(WWT_IMGBTN, Colours::LightBlue, 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),
1195 EndContainer(),
1196 EndContainer(),
1197
1199 NWidget(WWT_TEXT, Colours::Invalid, WID_NSS_COMPANIES_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES),
1201 NWidget(WWT_IMGBTN, Colours::LightBlue, 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),
1202 NWidget(WWT_PUSHTXTBTN, Colours::LightBlue, WID_NSS_COMPANIES_TXT), SetFill(1, 0), SetToolTip(STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
1203 NWidget(WWT_IMGBTN, Colours::LightBlue, 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),
1204 EndContainer(),
1205 EndContainer(),
1206 EndContainer(),
1207 EndContainer(),
1208
1210 /* 'generate game' and 'load game' buttons */
1212 NWidget(WWT_PUSHTXTBTN, Colours::White, WID_NSS_GENERATE_GAME), SetStringTip(STR_INTRO_NEW_GAME, STR_INTRO_TOOLTIP_NEW_GAME), SetFill(1, 0),
1213 NWidget(WWT_PUSHTXTBTN, Colours::White, WID_NSS_LOAD_GAME), SetStringTip(STR_INTRO_LOAD_GAME, STR_INTRO_TOOLTIP_LOAD_GAME), SetFill(1, 0),
1214 EndContainer(),
1215
1216 /* 'play scenario' and 'play heightmap' buttons */
1218 NWidget(WWT_PUSHTXTBTN, Colours::White, WID_NSS_PLAY_SCENARIO), SetStringTip(STR_INTRO_PLAY_SCENARIO, STR_INTRO_TOOLTIP_PLAY_SCENARIO), SetFill(1, 0),
1219 NWidget(WWT_PUSHTXTBTN, Colours::White, WID_NSS_PLAY_HEIGHTMAP), SetStringTip(STR_INTRO_PLAY_HEIGHTMAP, STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP), SetFill(1, 0),
1220 EndContainer(),
1221 EndContainer(),
1222
1225 EndContainer(),
1226 EndContainer(),
1227 EndContainer(),
1228};
1229
1232 WDP_CENTER, {}, 0, 0,
1234 {},
1236);
1237
1247
1248/* The window below gives information about the connected clients
1249 * and also makes able to kick them (if server) and stuff like that. */
1250
1251extern void DrawCompanyIcon(CompanyID cid, int x, int y);
1252
1254static constexpr std::initializer_list<NWidgetPart> _nested_client_list_widgets = {
1257 NWidget(WWT_CAPTION, Colours::Grey), SetStringTip(STR_NETWORK_CLIENT_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1260 EndContainer(),
1263 NWidget(WWT_FRAME, Colours::Grey), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0),
1265 NWidget(WWT_TEXT, Colours::Invalid), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_NAME),
1266 NWidget(WWT_TEXT, Colours::Invalid, WID_CL_SERVER_NAME), SetFill(1, 0), SetResize(1, 0), SetToolTip(STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1267 NWidget(WWT_PUSHIMGBTN, Colours::Grey, WID_CL_SERVER_NAME_EDIT), SetAspect(WidgetDimensions::ASPECT_RENAME), SetSpriteTip(SPR_RENAME, STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP),
1268 EndContainer(),
1272 NWidget(WWT_TEXT, Colours::Invalid), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY),
1273 NWidget(WWT_DROPDOWN, Colours::Grey, WID_CL_SERVER_VISIBILITY), SetToolTip(STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP),
1274 EndContainer(),
1276 NWidget(WWT_TEXT, Colours::Invalid), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_INVITE_CODE),
1277 NWidget(WWT_TEXT, Colours::Invalid, 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),
1278 EndContainer(),
1280 NWidget(WWT_TEXT, Colours::Invalid), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE),
1281 NWidget(WWT_TEXT, Colours::Invalid, 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),
1282 EndContainer(),
1283 EndContainer(),
1284 EndContainer(),
1285 EndContainer(),
1286 NWidget(WWT_FRAME, Colours::Grey), SetStringTip(STR_NETWORK_CLIENT_LIST_PLAYER),
1288 NWidget(WWT_TEXT, Colours::Invalid), SetStringTip(STR_NETWORK_CLIENT_LIST_PLAYER_NAME),
1289 NWidget(WWT_TEXT, Colours::Invalid, WID_CL_CLIENT_NAME), SetFill(1, 0), SetResize(1, 0), SetToolTip(STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1290 NWidget(WWT_PUSHIMGBTN, Colours::Grey, WID_CL_CLIENT_NAME_EDIT), SetAspect(WidgetDimensions::ASPECT_RENAME), SetSpriteTip(SPR_RENAME, STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP),
1291 EndContainer(),
1292 EndContainer(),
1293 EndContainer(),
1294 EndContainer(),
1298 EndContainer(),
1301 NWidget(WWT_TEXT, Colours::Invalid, 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),
1302 EndContainer(),
1304 EndContainer(),
1305};
1306
1309 WDP_AUTO, "list_clients", 220, 300,
1311 {},
1313);
1314
1319static void AdminClientKickCallback(Window *, bool confirmed)
1320{
1321 if (confirmed) NetworkServerKickClient(_admin_client_id, {});
1322}
1323
1328static void AdminClientBanCallback(Window *, bool confirmed)
1329{
1330 if (confirmed) NetworkServerKickOrBanIP(_admin_client_id, true, {});
1331}
1332
1337static void AdminCompanyResetCallback(Window *, bool confirmed)
1338{
1339 if (confirmed) {
1342 }
1343}
1344
1353public:
1358 uint height;
1359 uint width;
1360
1369 sprite(sprite),
1371 colour(colour),
1373 {
1375 this->height = d.height + WidgetDimensions::scaled.framerect.Vertical();
1376 this->width = d.width + WidgetDimensions::scaled.framerect.Horizontal();
1377 }
1378
1379 virtual ~ButtonCommon() = default;
1380
1386 virtual void OnClick(struct NetworkClientListWindow *w, Point pt) = 0;
1387};
1388
1392template <typename T>
1393class Button : public ButtonCommon {
1394private:
1395 typedef void (*ButtonCallback)(struct NetworkClientListWindow *w, Point pt, T id);
1398
1399public:
1411 id(id),
1412 proc(proc)
1413 {
1414 assert(proc != nullptr);
1415 }
1416
1417 void OnClick(struct NetworkClientListWindow *w, Point pt) override
1418 {
1419 if (this->disabled) return;
1420
1421 this->proc(w, pt, this->id);
1422 }
1423};
1424
1427
1432public:
1433 std::vector<std::unique_ptr<ButtonCommon>> buttons{};
1434
1436 virtual ~ButtonLine() = default;
1437
1442 virtual void Draw(Rect r) const = 0;
1443
1449 template <typename T, typename...TArgs>
1450 T &AddButton(TArgs &&... args)
1451 {
1452 auto &button = this->buttons.emplace_back(std::make_unique<T>(std::forward<TArgs &&>(args)...));
1453 return static_cast<T &>(*button);
1454 }
1455
1462 ButtonCommon *GetButton(Rect r, const Point &pt) const
1463 {
1464 bool rtl = _current_text_dir == TD_RTL;
1465 for (auto &button : this->buttons) {
1466 if (r.WithWidth(button->width, !rtl).Contains(pt)) return button.get();
1467 r = r.Indent(button->width + WidgetDimensions::scaled.hsep_normal, !rtl);
1468 }
1469 return nullptr;
1470 }
1471
1478 virtual std::optional<EncodedString> GetTooltip(Rect r, const Point &pt) const
1479 {
1480 ButtonCommon *button = this->GetButton(r, pt);
1481 if (button == nullptr) return {};
1482 return GetEncodedString(button->tooltip);
1483 }
1484
1485protected:
1492 {
1493 bool rtl = _current_text_dir == TD_RTL;
1494 for (auto &button : buttons) {
1495 Rect br = r.CentreToHeight(button->height).WithWidth(button->width, !rtl);
1496 DrawFrameRect(br, button->colour, {});
1497 DrawSpriteIgnorePadding(button->sprite, PAL_NONE, br, SA_CENTER);
1498 if (button->disabled) {
1499 GfxFillRect(br.Shrink(WidgetDimensions::scaled.bevel), GetColourGradient(button->colour, SHADE_DARKER), FILLRECT_CHECKER);
1500 }
1501 r = r.Indent(button->width + WidgetDimensions::scaled.hsep_normal, !rtl);
1502 }
1503 return r;
1504 }
1505};
1506
1509public:
1515
1516 void Draw(Rect r) const override
1517 {
1518 bool rtl = _current_text_dir == TD_RTL;
1519 r = this->DrawButtons(r);
1520
1521 Dimension d = GetScaledSpriteSize(SPR_COMPANY_ICON);
1522 PaletteID pal = Company::IsValidID(this->company_id) ? GetCompanyPalette(this->company_id) : PALETTE_TO_GREY;
1523 DrawSpriteIgnorePadding(SPR_COMPANY_ICON, pal, r.WithWidth(d.width, rtl), SA_CENTER);
1524
1526 if (this->company_id == COMPANY_SPECTATOR) {
1527 DrawString(tr, STR_NETWORK_CLIENT_LIST_SPECTATORS, TC_SILVER);
1528 } else if (this->company_id == COMPANY_NEW_COMPANY) {
1529 DrawString(tr, STR_NETWORK_CLIENT_LIST_NEW_COMPANY, TC_WHITE);
1530 } else {
1531 DrawString(tr, GetString(STR_COMPANY_NAME, this->company_id, this->company_id), TC_SILVER);
1532 }
1533 };
1534
1535private:
1536 CompanyID company_id;
1537};
1538
1541public:
1547
1548 void Draw(Rect r) const override
1549 {
1551 if (ci == nullptr) return;
1552
1553 bool rtl = _current_text_dir == TD_RTL;
1554 r = this->DrawButtons(r);
1555
1557
1558 SpriteID player_icon = 0;
1559 if (ci->client_id == _network_own_client_id) {
1560 player_icon = SPR_PLAYER_SELF;
1561 } else if (ci->client_id == CLIENT_ID_SERVER) {
1562 player_icon = SPR_PLAYER_HOST;
1563 }
1564
1565 if (player_icon != 0) {
1566 Dimension d = GetScaledSpriteSize(player_icon);
1567 DrawSpriteIgnorePadding(player_icon, PALETTE_TO_GREY, r.WithWidth(d.width, rtl), SA_CENTER);
1568 tr = tr.Indent(d.width + WidgetDimensions::scaled.hsep_normal, rtl);
1569 }
1570
1571 DrawString(tr, GetString(STR_JUST_RAW_STRING, ci->client_name), TC_BLACK);
1572 }
1573
1574 std::optional<EncodedString> GetTooltip(Rect r, const Point &pt) const override
1575 {
1576 bool rtl = _current_text_dir == TD_RTL;
1577 Dimension d = GetScaledSpriteSize(SPR_PLAYER_SELF);
1578
1579 if (r.WithWidth(d.width, rtl).Contains(pt)) {
1581 if (ci != nullptr) {
1582 if (ci->client_id == _network_own_client_id) {
1583 return GetEncodedString(STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP);
1584 } else if (ci->client_id == CLIENT_ID_SERVER) {
1585 return GetEncodedString(STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP);
1586 }
1587 }
1588 }
1589
1590 return this->ButtonLine::GetTooltip(r, pt);
1591 }
1592
1593private:
1595};
1596
1601private:
1613
1615
1617 CompanyID dd_company_id = CompanyID::Invalid();
1618
1619 Scrollbar *vscroll = nullptr;
1620 uint line_height = 0;
1621 int hover_index = -1;
1622
1623 std::vector<std::unique_ptr<ButtonLine>> buttons{};
1624
1629 static void OnClickCompanyChat(NetworkClientListWindow *, Point, CompanyID company_id)
1630 {
1632 }
1633
1638 static void OnClickCompanyJoin(NetworkClientListWindow *, Point, CompanyID company_id)
1639 {
1640 if (_network_server) {
1643 } else {
1644 NetworkClientRequestMove(company_id);
1645 }
1646 }
1647
1652 {
1653 Command<Commands::CompanyControl>::Post(CompanyCtrlAction::New, CompanyID::Invalid(), CompanyRemoveReason::None, _network_own_client_id);
1654 }
1655
1663 {
1664 DropDownList list;
1665 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK, to_underlying(DropDownAction::AdminKickClient)));
1666 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN, to_underlying(DropDownAction::AdminBanClient)));
1667
1668 Rect wi_rect;
1669 wi_rect.left = pt.x;
1670 wi_rect.right = pt.x;
1671 wi_rect.top = pt.y;
1672 wi_rect.bottom = pt.y;
1673
1674 w->dd_client_id = client_id;
1676 }
1677
1684 static void OnClickCompanyAdmin(NetworkClientListWindow *w, Point pt, CompanyID company_id)
1685 {
1686 DropDownList list;
1687 if (_network_server) list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET, to_underlying(DropDownAction::AdminResetCompany), NetworkCompanyHasClients(company_id)));
1688 if (const Company *c = Company::GetIfValid(company_id); c != nullptr) {
1689 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_ALLOW_ANY, to_underlying(DropDownAction::CompanyAllowAny), c->allow_any));
1690 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_ALLOW_LISTED, to_underlying(DropDownAction::CompanyAllowListed), !c->allow_any));
1691 }
1692
1693 Rect wi_rect;
1694 wi_rect.left = pt.x;
1695 wi_rect.right = pt.x;
1696 wi_rect.top = pt.y;
1697 wi_rect.bottom = pt.y;
1698
1699 w->dd_company_id = company_id;
1701 }
1702
1711
1717 {
1719 Command<Commands::CompanyAllowListControl>::Post(CompanyAllowListCtrlAction::AddKey, NetworkClientInfo::GetByClientID(client_id)->public_key);
1720 }
1721
1728 void RebuildListCompany(CompanyID company_id, CompanyID client_playas, bool can_join_company)
1729 {
1730 ButtonLine &company_line = *this->buttons.emplace_back(std::make_unique<CompanyButtonLine>(company_id));
1731 if (_network_server || company_id == _local_company) {
1732 company_line.AddButton<CompanyButton>(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP, Colours::Red, company_id, &NetworkClientListWindow::OnClickCompanyAdmin, company_id == COMPANY_SPECTATOR);
1733 }
1734 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, Colours::Orange, company_id, &NetworkClientListWindow::OnClickCompanyChat);
1735 if (can_join_company) company_line.AddButton<CompanyButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP, Colours::Orange, company_id, &NetworkClientListWindow::OnClickCompanyJoin, company_id != COMPANY_SPECTATOR && Company::Get(company_id)->is_ai);
1736
1737 bool has_players = false;
1738 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1739 if (ci->client_playas != company_id) continue;
1740 has_players = true;
1741
1742 ButtonLine &line = *this->buttons.emplace_back(std::make_unique<ClientButtonLine>(ci->index));
1743 if (_network_server) line.AddButton<ClientButton>(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP, Colours::Red, ci->client_id, &NetworkClientListWindow::OnClickClientAdmin, _network_own_client_id == ci->client_id);
1744 if (_network_own_client_id != ci->client_id) line.AddButton<ClientButton>(SPR_CHAT, STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP, Colours::Orange, ci->client_id, &NetworkClientListWindow::OnClickClientChat);
1745 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, Colours::Green, ci->client_id, &NetworkClientListWindow::OnClickClientAuthorize);
1746 }
1747
1748 /* Disable the chat button when there are players in this company. */
1749 chat_button.disabled = !has_players;
1750 }
1751
1756 {
1758 CompanyID client_playas = own_ci == nullptr ? COMPANY_SPECTATOR : own_ci->client_playas;
1759
1760 this->buttons.clear();
1761
1762 /* As spectator, show a line to create a new company. */
1763 if (client_playas == COMPANY_SPECTATOR && !NetworkMaxCompaniesReached()) {
1764 ButtonLine &line = *this->buttons.emplace_back(std::make_unique<CompanyButtonLine>(COMPANY_NEW_COMPANY));
1765 line.AddButton<CompanyButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP, Colours::Orange, COMPANY_SPECTATOR, &NetworkClientListWindow::OnClickCompanyNew);
1766 }
1767
1768 if (client_playas != COMPANY_SPECTATOR) {
1769 this->RebuildListCompany(client_playas, client_playas, false);
1770 }
1771
1772 /* Companies */
1773 for (const Company *c : Company::Iterate()) {
1774 if (c->index == client_playas) continue;
1775
1776 this->RebuildListCompany(c->index, client_playas, _network_server || c->allow_any || (own_ci != nullptr && c->allow_list.Contains(own_ci->public_key)));
1777 }
1778
1779 /* Spectators */
1780 this->RebuildListCompany(COMPANY_SPECTATOR, client_playas, client_playas != COMPANY_SPECTATOR);
1781
1782 this->vscroll->SetCount(this->buttons.size());
1783 }
1784
1785public:
1792 {
1793 this->CreateNestedTree();
1794 this->vscroll = this->GetScrollbar(WID_CL_SCROLLBAR);
1795 this->OnInvalidateData();
1796 this->FinishInitNested(window_number);
1797 }
1798
1799 void OnInit() override
1800 {
1801 this->RebuildList();
1802 }
1803
1804 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1805 {
1806 this->RebuildList();
1807
1808 /* Currently server information is not synced to clients, so we cannot show it on clients. */
1811 }
1812
1813 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1814 {
1815 switch (widget) {
1816 case WID_CL_SERVER_NAME:
1817 case WID_CL_CLIENT_NAME: {
1818 std::string str;
1819 if (widget == WID_CL_SERVER_NAME) {
1820 str = GetString(STR_JUST_RAW_STRING, _network_server ? _settings_client.network.server_name : _network_server_name);
1821 } else {
1823 str = GetString(STR_JUST_RAW_STRING, own_ci != nullptr ? own_ci->client_name : _settings_client.network.client_name);
1824 }
1825 size = GetStringBoundingBox(str);
1826 size.width = std::min(size.width, static_cast<uint>(ScaleGUITrad(200))); // By default, don't open the window too wide.
1827 break;
1828 }
1829
1831 size = maxdim(maxdim(GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_LOCAL), GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_PUBLIC)), GetStringBoundingBox(STR_NETWORK_SERVER_VISIBILITY_INVITE_ONLY));
1832 size.width += padding.width;
1833 size.height += padding.height;
1834 break;
1835
1836 case WID_CL_MATRIX: {
1837 uint height = std::max({GetScaledSpriteSize(SPR_COMPANY_ICON).height, GetScaledSpriteSize(SPR_JOIN).height, GetScaledSpriteSize(SPR_ADMIN).height, GetScaledSpriteSize(SPR_CHAT).height});
1838 height += WidgetDimensions::scaled.framerect.Vertical();
1839 this->line_height = std::max(height, (uint)GetCharacterHeight(FontSize::Normal)) + padding.height;
1840
1841 resize.width = 1;
1842 fill.height = resize.height = this->line_height;
1843 size.height = std::max(size.height, 5 * this->line_height);
1844 break;
1845 }
1846 }
1847 }
1848
1849 void OnResize() override
1850 {
1851 this->vscroll->SetCapacityFromWidget(this, WID_CL_MATRIX);
1852 }
1853
1854 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
1855 {
1856 switch (widget) {
1857 case WID_CL_SERVER_NAME:
1858 return _network_server ? _settings_client.network.server_name : _network_server_name;
1859
1861 return GetString(STR_NETWORK_SERVER_VISIBILITY_LOCAL + to_underlying(_settings_client.network.server_game_type));
1862
1865
1867 return GetString(STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_UNKNOWN + _network_server_connection_type);
1868
1869 case WID_CL_CLIENT_NAME: {
1871 return own_ci != nullptr ? own_ci->client_name : _settings_client.network.client_name;
1872 }
1873
1875 return GetString(STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT, NetworkClientInfo::GetNumItems(), Company::GetNumItems(), NetworkMaxCompaniesAllowed());
1876
1877 default:
1878 return this->Window::GetWidgetString(widget, stringid);
1879 }
1880 }
1881
1882 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1883 {
1884 switch (widget) {
1886 if (!_network_server) break;
1887
1888 this->query_widget = WID_CL_SERVER_NAME_EDIT;
1889 ShowQueryString(_settings_client.network.server_name, STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION, NETWORK_NAME_LENGTH, this, CS_ALPHANUMERAL, QueryStringFlag::LengthIsInChars);
1890 break;
1891
1894 this->query_widget = WID_CL_CLIENT_NAME_EDIT;
1895 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);
1896 break;
1897 }
1899 if (!_network_server) break;
1900
1902 break;
1903
1904 case WID_CL_MATRIX: {
1905 auto it = this->vscroll->GetScrolledItemFromWidget(this->buttons, pt.y, this, WID_CL_MATRIX);
1906 if (it == std::end(this->buttons)) break;
1907
1908 Rect r = this->GetWidget<NWidgetBase>(WID_CL_MATRIX)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
1909 ButtonCommon *button = (*it)->GetButton(r, pt);
1910 if (button == nullptr) break;
1911
1912 button->OnClick(this, pt);
1913 break;
1914 }
1915 }
1916 }
1917
1918 bool OnTooltip([[maybe_unused]] Point pt, WidgetID widget, TooltipCloseCondition close_cond) override
1919 {
1920 switch (widget) {
1921 case WID_CL_MATRIX: {
1922 auto it = this->vscroll->GetScrolledItemFromWidget(this->buttons, pt.y, this, WID_CL_MATRIX);
1923 if (it == std::end(this->buttons)) break;
1924
1925 Rect r = this->GetWidget<NWidgetBase>(WID_CL_MATRIX)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
1926 auto tooltip = (*it)->GetTooltip(r, pt);
1927 if (!tooltip.has_value()) break;
1928
1929 GuiShowTooltips(this, std::move(*tooltip), close_cond);
1930 return true;
1931 };
1932 }
1933
1934 return false;
1935 }
1936
1937 void OnDropdownClose(Point pt, WidgetID widget, int index, int click_result, bool instant_close) override
1938 {
1939 /* If you close the dropdown outside the list, don't take any action. */
1940 if (widget == WID_CL_MATRIX) return;
1941
1942 Window::OnDropdownClose(pt, widget, index, click_result, instant_close);
1943 }
1944
1945 void OnDropdownSelect(WidgetID widget, int index, int) override
1946 {
1947 switch (widget) {
1949 if (!_network_server) break;
1950
1951 _settings_client.network.server_game_type = (ServerGameType)index;
1953 break;
1954
1955 case WID_CL_MATRIX: {
1956 QueryCallbackProc *callback = nullptr;
1957
1958 EncodedString text;
1959 switch (static_cast<DropDownAction>(index)) {
1961 _admin_client_id = this->dd_client_id;
1962 callback = AdminClientKickCallback;
1963 text = GetEncodedString(STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK, NetworkClientInfo::GetByClientID(_admin_client_id)->client_name);
1964 break;
1965
1967 _admin_client_id = this->dd_client_id;
1968 callback = AdminClientBanCallback;
1969 text = GetEncodedString(STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN, NetworkClientInfo::GetByClientID(_admin_client_id)->client_name);
1970 break;
1971
1973 _admin_company_id = this->dd_company_id;
1974 callback = AdminCompanyResetCallback;
1975 text = GetEncodedString(STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET, _admin_company_id);
1976 break;
1977
1979 AutoRestoreBackup cur_company(_current_company, this->dd_company_id);
1980 Command<Commands::CompanyAllowListControl>::Post(CompanyAllowListCtrlAction::AllowAny, {});
1981 return;
1982 }
1983
1985 AutoRestoreBackup cur_company(_current_company, this->dd_company_id);
1986 Command<Commands::CompanyAllowListControl>::Post(CompanyAllowListCtrlAction::AllowListed, {});
1987 return;
1988 }
1989
1990 default:
1991 NOT_REACHED();
1992 }
1993
1994 assert(callback != nullptr);
1995
1996 /* Always ask confirmation for all admin actions. */
1997 ShowQuery(
1998 GetEncodedString(STR_NETWORK_CLIENT_LIST_ASK_CAPTION),
1999 std::move(text),
2000 this, callback);
2001
2002 break;
2003 }
2004
2005 default:
2006 NOT_REACHED();
2007 }
2008
2009 this->SetDirty();
2010 }
2011
2012 void OnQueryTextFinished(std::optional<std::string> str) override
2013 {
2014 if (!str.has_value()) return;
2015
2016 switch (this->query_widget) {
2017 default: NOT_REACHED();
2018
2020 if (!_network_server) break;
2021
2022 SetSettingValue(GetSettingFromName("network.server_name")->AsStringSetting(), *str);
2023 this->InvalidateData();
2024 break;
2025 }
2026
2028 SetSettingValue(GetSettingFromName("network.client_name")->AsStringSetting(), *str);
2029 this->InvalidateData();
2030 break;
2031 }
2032 }
2033 }
2034
2035 void DrawWidget(const Rect &r, WidgetID widget) const override
2036 {
2037 switch (widget) {
2038 case WID_CL_MATRIX: {
2039 Rect ir = r.WithHeight(this->line_height).Shrink(WidgetDimensions::scaled.framerect, RectPadding::zero);
2040
2041 if (this->hover_index >= 0) {
2042 Rect br = r.WithHeight(this->line_height).Translate(0, this->hover_index * this->line_height);
2044 }
2045
2046 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->buttons);
2047 for (auto it = first; it != last; ++it) {
2048 (*it)->Draw(ir);
2049 ir = ir.Translate(0, this->line_height);
2050 }
2051
2052 break;
2053 }
2054 }
2055 }
2056
2057 void OnMouseOver([[maybe_unused]] Point pt, WidgetID widget) override
2058 {
2059 if (widget != WID_CL_MATRIX) {
2060 if (this->hover_index != -1) {
2061 this->hover_index = -1;
2063 }
2064 } else {
2065 int index = this->GetRowFromWidget(pt.y, widget, 0, -1);
2066 if (index != this->hover_index) {
2067 this->hover_index = index;
2069 }
2070 }
2071 }
2072};
2073
2079
2084
2087 std::shared_ptr<NetworkAuthenticationPasswordRequest> request{};
2088
2098
2099 void DrawWidget(const Rect &r, WidgetID widget) const override
2100 {
2101 switch (widget) {
2102 case WID_NJS_PROGRESS_BAR: {
2103 /* Draw the % complete with a bar and a text */
2105 Rect ir = r.Shrink(WidgetDimensions::scaled.bevel);
2106 uint8_t progress; // used for progress bar
2107 switch (_network_join_status) {
2110 progress = 10; // first two stages 10%
2111 break;
2113 progress = 15; // third stage is 15%
2114 break;
2116 if (_network_join_bytes_total == 0) {
2117 progress = 15; // We don't have the final size yet; the server is still compressing!
2118 break;
2119 }
2120 [[fallthrough]];
2121
2122 default: // Waiting is 15%, so the remaining downloading of the map is maximum 70%
2123 progress = 15 + _network_join_bytes * (100 - 15) / _network_join_bytes_total;
2124 break;
2125 }
2126 DrawFrameRect(ir.WithWidth(ir.Width() * progress / 100, _current_text_dir == TD_RTL), Colours::Mauve, {});
2127 DrawString(ir.left, ir.right, CentreBounds(ir.top, ir.bottom, GetCharacterHeight(FontSize::Normal)), STR_NETWORK_CONNECTING_1 + to_underlying(_network_join_status), TC_FROMSTRING, SA_HOR_CENTER);
2128 break;
2129 }
2130
2132 switch (_network_join_status) {
2134 DrawStringMultiLine(r, GetString(STR_NETWORK_CONNECTING_WAITING, _network_join_waiting), TC_FROMSTRING, SA_CENTER);
2135 break;
2136
2138 if (_network_join_bytes_total == 0) {
2139 DrawStringMultiLine(r, GetString(STR_NETWORK_CONNECTING_DOWNLOADING_1, _network_join_bytes), TC_FROMSTRING, SA_CENTER);
2140 } else {
2141 DrawStringMultiLine(r, GetString(STR_NETWORK_CONNECTING_DOWNLOADING_2, _network_join_bytes, _network_join_bytes_total), TC_FROMSTRING, SA_CENTER);
2142 }
2143 break;
2144
2145 default:
2146 break;
2147 }
2148 break;
2149 }
2150 }
2151
2152 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2153 {
2154 switch (widget) {
2156 /* Account for the statuses */
2157 for (uint i = 0; i < to_underlying(NetworkJoinStatus::End); i++) {
2158 size = maxdim(size, GetStringBoundingBox(STR_NETWORK_CONNECTING_1 + i));
2159 }
2160 /* For the number of waiting (other) players */
2161 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_CONNECTING_WAITING, GetParamMaxValue(MAX_CLIENTS))));
2162 /* We need some spacing for the 'border' */
2163 size.height += WidgetDimensions::scaled.frametext.Horizontal();
2164 size.width += WidgetDimensions::scaled.frametext.Vertical();
2165 break;
2166
2167 case WID_NJS_PROGRESS_TEXT: {
2168 /* Account for downloading ~ 10 MiB */
2169 uint64_t max_digits = GetParamMaxDigits(8);
2170 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_CONNECTING_DOWNLOADING_1, max_digits, max_digits)));
2171 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_CONNECTING_DOWNLOADING_1, max_digits, max_digits)));
2172 break;
2173 }
2174 }
2175 }
2176
2177 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2178 {
2179 if (widget == WID_NJS_CANCELOK) { // Disconnect button
2181 SwitchToMode(SM_MENU);
2183 }
2184 }
2185
2186 void OnQueryTextFinished(std::optional<std::string> str) override
2187 {
2188 if (!str.has_value() || str->empty() || this->request == nullptr) {
2190 return;
2191 }
2192
2193 this->request->Reply(*str);
2194 }
2195};
2196
2198static constexpr std::initializer_list<NWidgetPart> _nested_network_join_status_window_widgets = {
2199 NWidget(WWT_CAPTION, Colours::Grey), SetStringTip(STR_NETWORK_CONNECTING_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2204 NWidget(WWT_PUSHTXTBTN, Colours::White, WID_NJS_CANCELOK), SetMinimalSize(101, 12), SetStringTip(STR_NETWORK_CONNECTION_DISCONNECT), SetFill(1, 0),
2205 EndContainer(),
2206 EndContainer(),
2207};
2208
2211 WDP_CENTER, {}, 0, 0,
2215);
2216
2223
2228void ShowNetworkNeedPassword(std::shared_ptr<NetworkAuthenticationPasswordRequest> request)
2229{
2231 if (w == nullptr) return;
2232 w->request = std::move(request);
2233
2234 ShowQueryString({}, STR_NETWORK_NEED_GAME_PASSWORD_CAPTION, NETWORK_PASSWORD_LENGTH, w, CS_ALPHANUMERAL, {});
2235}
2236
2243 std::string token{};
2244
2254 Window(desc),
2257 token(std::move(token))
2258 {
2259 this->parent = parent;
2260 this->InitNested(0);
2261 }
2262
2263 void Close(int data = 0) override
2264 {
2265 if (data == NRWCD_UNHANDLED) _network_coordinator_client.ConnectFailure(this->token, 0);
2266 this->Window::Close();
2267 }
2268
2269 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2270 {
2271 if (widget == WID_NAR_TEXT) {
2272 size = GetStringBoundingBox(GetString(STR_NETWORK_ASK_RELAY_TEXT, this->server_connection_string, this->relay_connection_string));
2273 }
2274 }
2275
2276 void DrawWidget(const Rect &r, WidgetID widget) const override
2277 {
2278 if (widget == WID_NAR_TEXT) {
2279 DrawStringMultiLine(r, GetString(STR_NETWORK_ASK_RELAY_TEXT, this->server_connection_string, this->relay_connection_string), TC_FROMSTRING, SA_CENTER);
2280 }
2281 }
2282
2283 void FindWindowPlacementAndResize(int, int, bool) override
2284 {
2285 /* Position query window over the calling window, ensuring it's within screen bounds. */
2286 this->left = Clamp(parent->left + (parent->width / 2) - (this->width / 2), 0, _screen.width - this->width);
2287 this->top = Clamp(parent->top + (parent->height / 2) - (this->height / 2), 0, _screen.height - this->height);
2288 this->SetDirty();
2289 }
2290
2291 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2292 {
2293 switch (widget) {
2294 case WID_NAR_NO:
2295 _network_coordinator_client.ConnectFailure(this->token, 0);
2296 this->Close(NRWCD_HANDLED);
2297 break;
2298
2299 case WID_NAR_YES_ONCE:
2300 _network_coordinator_client.StartTurnConnection(this->token);
2301 this->Close(NRWCD_HANDLED);
2302 break;
2303
2304 case WID_NAR_YES_ALWAYS:
2305 _settings_client.network.use_relay_service = UseRelayService::Allow;
2306 _network_coordinator_client.StartTurnConnection(this->token);
2307 this->Close(NRWCD_HANDLED);
2308 break;
2309 }
2310 }
2311};
2312
2330
2333 WDP_CENTER, {}, 0, 0,
2337);
2338
2345void ShowNetworkAskRelay(std::string_view server_connection_string, std::string &&relay_connection_string, std::string &&token)
2346{
2348
2349 Window *parent = GetMainWindow();
2350 new NetworkAskRelayWindow(_network_ask_relay_desc, parent, server_connection_string, std::move(relay_connection_string), std::move(token));
2351}
2352
2363 Window(desc)
2364 {
2365 this->parent = parent;
2366 this->InitNested(0);
2367 }
2368
2369 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2370 {
2371 if (widget == WID_NAS_TEXT) {
2372 size = GetStringBoundingBox(STR_NETWORK_ASK_SURVEY_TEXT);
2373 }
2374 }
2375
2376 void DrawWidget(const Rect &r, WidgetID widget) const override
2377 {
2378 if (widget == WID_NAS_TEXT) {
2379 DrawStringMultiLine(r, STR_NETWORK_ASK_SURVEY_TEXT, TC_BLACK, SA_CENTER);
2380 }
2381 }
2382
2383 void FindWindowPlacementAndResize(int, int, bool) override
2384 {
2385 /* Position query window over the calling window, ensuring it's within screen bounds. */
2386 this->left = Clamp(parent->left + (parent->width / 2) - (this->width / 2), 0, _screen.width - this->width);
2387 this->top = Clamp(parent->top + (parent->height / 2) - (this->height / 2), 0, _screen.height - this->height);
2388 this->SetDirty();
2389 }
2390
2391 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2392 {
2393 switch (widget) {
2394 case WID_NAS_PREVIEW:
2396 break;
2397
2398 case WID_NAS_LINK:
2399 OpenBrowser(NETWORK_SURVEY_DETAILS_LINK);
2400 break;
2401
2402 case WID_NAS_NO:
2403 _settings_client.network.participate_survey = ParticipateSurvey::No;
2404 this->Close();
2405 break;
2406
2407 case WID_NAS_YES:
2408 _settings_client.network.participate_survey = ParticipateSurvey::Yes;
2409 this->Close();
2410 break;
2411 }
2412 }
2413};
2414
2435
2438 WDP_CENTER, {}, 0, 0,
2442);
2443
2448{
2449 /* If we can't send a survey, don't ask the question. */
2450 if constexpr (!NetworkSurveyHandler::IsSurveyPossible()) return;
2451
2453
2454 Window *parent = GetMainWindow();
2456}
2457
2459struct SurveyResultTextfileWindow : public TextfileWindow {
2461
2468 {
2469 this->ConstructWindow();
2470
2471 auto result = _survey.CreatePayload(NetworkSurveyHandler::Reason::Preview, true);
2472 this->LoadText(result);
2473 this->InvalidateData();
2474 }
2475};
2476
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.
ButtonCommon(SpriteID sprite, StringID tooltip, Colours colour, bool disabled=false)
Create 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.
T & AddButton(TArgs &&... args)
Construct a button and add it.
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
Button(SpriteID sprite, StringID tooltip, Colours colour, T id, ButtonCallback proc, bool disabled=false)
Create the button.
void(* ButtonCallback)(struct NetworkClientListWindow *w, Point pt, T id)
Callback function to call on click.
ClientPoolID client_pool_id
The client to show on this line.
ClientButtonLine(ClientPoolID client_pool_id)
Create the line.
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.
CompanyButtonLine(CompanyID company_id)
Create the line.
CompanyID company_id
The company to show on the 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:1323
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.
NWidgetServerListHeader()
Create the header.
Window with the list of game servers.
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.
void DrawDetails(const Rect &r) const
Draw the details about the selected server.
QueryString filter_editbox
Editbox for filter on servers.
Scrollbar * vscroll
Vertical scrollbar of the list of servers.
StringID GetHeaderString() const
Get the string for the header of the 'selected server' subpanel.
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.
NetworkGameWindow(WindowDesc &desc)
Create the window.
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.
static constexpr bool IsSurveyPossible()
Check whether a survey is possible.
@ 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:2532
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:2479
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
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:93
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:570
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:587
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
@ Load
File is being loaded.
Definition fileio_type.h:54
@ Savegame
old or new savegame
Definition fileio_type.h:19
@ Scenario
old or new scenario
Definition fileio_type.h:20
@ Heightmap
heightmap file
Definition fileio_type.h:21
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:88
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
@ 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
Colours
One of 16 base colours used for companies and windows/widgets.
Definition gfx_type.h:283
@ White
White.
Definition gfx_type.h:300
@ Mauve
Mauve.
Definition gfx_type.h:295
@ Invalid
Invalid marker.
Definition gfx_type.h:302
@ LightBlue
Light blue.
Definition gfx_type.h:290
@ Yellow
Yellow.
Definition gfx_type.h:288
@ Orange
Orange.
Definition gfx_type.h:297
@ Grey
Grey.
Definition gfx_type.h:299
@ Green
Green.
Definition gfx_type.h:291
@ Red
Red.
Definition gfx_type.h:289
@ 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 SetResizeWidgetTypeTip(ResizeWidgetType widget_type, StringID tip)
Widget part function for setting the resize widget type 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 SetMinimalTextLines(uint8_t lines, uint8_t spacing, FontSize size=FontSize::Normal)
Widget part function for setting the minimal text lines.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
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 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 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:687
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:689
void NetworkDisconnect(bool close_admins)
We want to disconnect from the host/clients.
Definition network.cpp:1035
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:711
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:809
void NetworkRebuildHostList()
Generates the list of manually added hosts from NetworkGame and dumps them into the array _network_ho...
Definition network.cpp:753
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:1063
bool NetworkValidateServerName(std::string &server_name)
Trim the given server name in place, i.e.
Definition network.cpp:887
Basic functions/variables used all over the place.
Base core network types and some helper functions to access them.
void ShowNetworkChatQueryWindow(NetworkChatDestinationType 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.
int ServerListPosition
A location within the server list.
static void AdminCompanyResetCallback(Window *, bool confirmed)
Callback function for admin command to reset company.
static WindowDesc _network_start_server_window_desc(WDP_CENTER, {}, 0, 0, WC_NETWORK_WINDOW, WC_NONE, {}, _nested_network_start_server_window_widgets)
Description of the NetworkStartServerWindow.
void ShowNetworkGameWindow()
Show the server list window.
static constexpr std::initializer_list< NWidgetPart > _nested_network_start_server_window_widgets
Widgets and the structure of the NetworkStartServerWindow.
static WindowDesc _client_list_desc(WDP_AUTO, "list_clients", 220, 300, WC_CLIENT_LIST, WC_NONE, {}, _nested_client_list_widgets)
Description of the NetworkClientListWindow.
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.
void ShowJoinStatusWindow()
Open the window showing the status of joining the server.
static constexpr std::initializer_list< NWidgetPart > _nested_network_join_status_window_widgets
Widgets and the structure of the NetworkJoinStatusWindow.
static WindowDesc _network_game_window_desc(WDP_CENTER, "list_servers", 1000, 730, WC_NETWORK_WINDOW, WC_NONE, {}, _nested_network_game_widgets)
Description of the NetworkGameWindow.
Button< CompanyID > CompanyButton
Button linked to a company.
static WindowDesc _network_join_status_window_desc(WDP_CENTER, {}, 0, 0, WC_NETWORK_STATUS_WINDOW, WC_NONE, WindowDefaultFlag::Modal, _nested_network_join_status_window_widgets)
Description of the NetworkJoinStatusWindow.
static const ServerListPosition SLP_INVALID
Sentinel for an invalid location in the server list.
void ShowSurveyResultTextfileWindow(Window *parent)
Show the surver results as a text file.
static constexpr std::initializer_list< NWidgetPart > _nested_network_ask_relay_widgets
Widgets and the structure of the NetworkAskRelayWindow.
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.
static constexpr std::initializer_list< NWidgetPart > _nested_client_list_widgets
Widgets and the structure of the NetworkClientListWindow.
static DropDownList BuildVisibilityDropDownList()
Create the dropdown with visibility options for the server.
static WindowDesc _network_ask_relay_desc(WDP_CENTER, {}, 0, 0, WC_NETWORK_ASK_RELAY, WC_NONE, WindowDefaultFlag::Modal, _nested_network_ask_relay_widgets)
Description of the NetworkAskRelayWindow.
GUIList< NetworkGame *, std::nullptr_t, StringFilter & > GUIGameServerList
The list of servers with sorting/filtering.
static constexpr std::initializer_list< NWidgetPart > _nested_network_ask_survey_widgets
Widgets and the structure of the NetworkAskSurveyWindow.
static WindowDesc _network_ask_survey_desc(WDP_CENTER, {}, 0, 0, WC_NETWORK_ASK_SURVEY, WC_NONE, WindowDefaultFlag::Modal, _nested_network_ask_survey_widgets)
Description of the NetworkAskSurveyWindow.
void ShowClientList()
Open the client list window.
static constexpr std::initializer_list< NWidgetPart > _nested_network_game_widgets
Widgets and the structure of the NetworkGameWindow.
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.
Button< ClientID > ClientButton
Button linked to a client.
void ShowNetworkAskSurvey()
Show a modal confirmation window with "no" / "preview" / "yes" buttons.
void ShowNetworkNeedPassword(std::shared_ptr< NetworkAuthenticationPasswordRequest > request)
Update the NetworkJoinStatusWindow to start requesting the server password.
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.
static void ShowNetworkStartServerWindow()
Show the window to configure and start your server with.
GUIs related to networking.
@ NRWCD_UNHANDLED
Relay request is unhandled.
Definition network_gui.h:44
@ NRWCD_HANDLED
Relay request is handled, either by user or by timeout.
Definition network_gui.h:45
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.
NetworkSurveyHandler _survey
The handler for sending surveys for statistics.
Part of the network protocol handling opt-in survey.
static const uint MAX_CLIENTS
How many clients can we have.
@ Client
Send message/notice to only a certain client (Private).
@ Team
Send message/notice to everyone playing the same company (Team).
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...
T y
Y coordinate.
T x
X coordinate.
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.
NetworkAskRelayWindow(WindowDesc &desc, Window *parent, std::string_view server_connection_string, std::string &&relay_connection_string, std::string &&token)
Create 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.
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.
NetworkAskSurveyWindow(WindowDesc &desc, Window *parent)
Create the window.
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.
static void OnClickCompanyNew(NetworkClientListWindow *, Point, CompanyID)
Create new company button is clicked.
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.
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 OnClickClientChat(NetworkClientListWindow *, Point, ClientID client_id)
Chat button on a Client is clicked.
ClientID dd_client_id
During admin dropdown, track which client this was for.
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 OnClickClientAuthorize(NetworkClientListWindow *, Point, ClientID client_id)
Authorize button on a Client is clicked.
static void OnClickClientAdmin(NetworkClientListWindow *w, Point pt, ClientID client_id)
Admin button on a Client is clicked.
static void OnClickCompanyChat(NetworkClientListWindow *, Point, CompanyID company_id)
Chat button on a Company 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.
static void OnClickCompanyJoin(NetworkClientListWindow *, Point, CompanyID company_id)
Join button on a Company is clicked.
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.
NetworkClientListWindow(WindowDesc &desc, WindowNumber window_number)
Create the window.
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.
Window showing the progress during joining.
NetworkJoinStatusWindow(WindowDesc &desc)
Create the window.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
std::shared_ptr< NetworkAuthenticationPasswordRequest > request
Callback to send the password request result to.
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.
Window to configure and start your server with.
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.
NetworkStartServerWindow(WindowDesc &desc)
Create 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.
bool CheckServerName()
Check whether the currently entered server name is valid, and if so update the server_name setting.
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.
SurveyResultTextfileWindow(Window *parent, TextfileType file_type)
Create the window.
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:835
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:786
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing).
Definition window.cpp:3262
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:818
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:1846
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:1836
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:309
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().
@ HideBevel
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:3322
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:21
@ WN_NETWORK_STATUS_WINDOW_JOIN
Network join status.
Definition window_type.h:45
@ WN_NETWORK_WINDOW_GAME
Network game window.
Definition window_type.h:41
@ WN_NETWORK_WINDOW_START
Network start server.
Definition window_type.h:43
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:51
@ 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.