OpenTTD Source 20241222-master-gc72542431a
network_gui.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#include "../stdafx.h"
11#include "../strings_func.h"
12#include "../fios.h"
13#include "network_client.h"
14#include "network_gui.h"
15#include "network_gamelist.h"
16#include "network.h"
17#include "network_base.h"
18#include "network_content.h"
19#include "network_server.h"
20#include "network_coordinator.h"
21#include "network_survey.h"
22#include "../gui.h"
23#include "network_udp.h"
24#include "../window_func.h"
25#include "../gfx_func.h"
26#include "../dropdown_type.h"
27#include "../dropdown_func.h"
28#include "../querystring_gui.h"
29#include "../sortlist_type.h"
30#include "../company_func.h"
31#include "../command_func.h"
32#include "../core/geometry_func.hpp"
33#include "../genworld.h"
34#include "../map_type.h"
35#include "../zoom_func.h"
36#include "../sprite.h"
37#include "../settings_internal.h"
38#include "../company_cmd.h"
39#include "../timer/timer.h"
40#include "../timer/timer_window.h"
41#include "../timer/timer_game_calendar.h"
42#include "../textfile_gui.h"
43
44#include "../widgets/network_widget.h"
45
46#include "table/strings.h"
47#include "../table/sprites.h"
48
49#include "../stringfilter_type.h"
50
51#ifdef __EMSCRIPTEN__
52# include <emscripten.h>
53#endif
54
55#include "../safeguards.h"
56
57static void ShowNetworkStartServerWindow();
58
61
70
71static DropDownList BuildVisibilityDropDownList()
72{
73 DropDownList list;
74
75 list.push_back(MakeDropDownListStringItem(STR_NETWORK_SERVER_VISIBILITY_LOCAL, SERVER_GAME_TYPE_LOCAL));
76 list.push_back(MakeDropDownListStringItem(STR_NETWORK_SERVER_VISIBILITY_INVITE_ONLY, SERVER_GAME_TYPE_INVITE_ONLY));
77 list.push_back(MakeDropDownListStringItem(STR_NETWORK_SERVER_VISIBILITY_PUBLIC, SERVER_GAME_TYPE_PUBLIC));
78
79 return list;
80}
81
83typedef int ServerListPosition;
84static const ServerListPosition SLP_INVALID = -1;
85
88 static const uint MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER = 150;
89public:
91 {
92 auto leaf = std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NAME, STR_NETWORK_SERVER_LIST_GAME_NAME, STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP);
93 leaf->SetResize(1, 0);
94 leaf->SetFill(1, 0);
95 this->Add(std::move(leaf));
96
97 this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CLIENTS, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP));
98 this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_MAPSIZE, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP));
99 this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_DATE, STR_NETWORK_SERVER_LIST_DATE_CAPTION, STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP));
100 this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_YEARS, STR_NETWORK_SERVER_LIST_PLAY_TIME_CAPTION, STR_NETWORK_SERVER_LIST_PLAY_TIME_CAPTION_TOOLTIP));
101
102 leaf = std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_INFO, STR_EMPTY, STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP);
103 leaf->SetFill(0, 1);
104 this->Add(std::move(leaf));
105 }
106
107 void SetupSmallestSize(Window *w) override
108 {
109 this->smallest_y = 0; // Biggest child.
110 this->fill_x = 1;
111 this->fill_y = 0;
112 this->resize_x = 1; // We only resize in this direction
113 this->resize_y = 0; // We never resize in this direction
114
115 /* First initialise some variables... */
116 for (const auto &child_wid : this->children) {
117 child_wid->SetupSmallestSize(w);
118 this->smallest_y = std::max(this->smallest_y, child_wid->smallest_y + child_wid->padding.Vertical());
119 }
120
121 /* ... then in a second pass make sure the 'current' sizes are set. Won't change for most widgets. */
122 for (const auto &child_wid : this->children) {
123 child_wid->current_x = child_wid->smallest_x;
124 child_wid->current_y = this->smallest_y;
125 }
126
127 this->smallest_x = this->children.front()->smallest_x + this->children.back()->smallest_x; // First and last are always shown, rest not
128 this->ApplyAspectRatio();
129 }
130
131 void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override
132 {
133 assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
134
135 this->pos_x = x;
136 this->pos_y = y;
137 this->current_x = given_width;
138 this->current_y = given_height;
139
140 given_width -= this->children.back()->smallest_x;
141 /* The first and last widget are always visible, determine which other should be visible */
142 if (this->children.size() > 2) {
143 auto first = std::next(std::begin(this->children));
144 auto last = std::prev(std::end(this->children));
145 for (auto it = first; it != last; ++it) {
146 auto &child_wid = *it;
147 if (given_width > ScaleGUITrad(MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER) + child_wid->smallest_x && (*std::prev(it))->current_x != 0) {
148 given_width -= child_wid->smallest_x;
149 child_wid->current_x = child_wid->smallest_x; /* Make visible. */
150 } else {
151 child_wid->current_x = 0; /* Make invisible. */
152 }
153 }
154 }
155
156 /* All remaining space goes to the first (name) widget */
157 this->children.front()->current_x = given_width;
158
159 /* Now assign the widgets to their rightful place */
160 uint position = 0; // Place to put next child relative to origin of the container.
161 auto assign_position = [&](const std::unique_ptr<NWidgetBase> &child_wid) {
162 if (child_wid->current_x != 0) {
163 child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl);
164 position += child_wid->current_x;
165 }
166 };
167
168 if (rtl) {
169 std::for_each(std::rbegin(this->children), std::rend(this->children), assign_position);
170 } else {
171 std::for_each(std::begin(this->children), std::end(this->children), assign_position);
172 }
173 }
174};
175
176class NetworkGameWindow : public Window {
177protected:
178 /* Runtime saved values */
179 static Listing last_sorting;
180
181 /* Constants for sorting servers */
182 static const std::initializer_list<GUIGameServerList::SortFunction * const> sorter_funcs;
183 static const std::initializer_list<GUIGameServerList::FilterFunction * const> filter_funcs;
184
188 ServerListPosition list_pos;
192 bool searched_internet = false;
193
194 Dimension lock;
196
203 {
204 if (!this->servers.NeedRebuild()) return;
205
206 /* Create temporary array of games to use for listing */
207 this->servers.clear();
208
209 bool found_current_server = false;
210 bool found_last_joined = false;
211 for (NetworkGameList *ngl = _network_game_list; ngl != nullptr; ngl = ngl->next) {
212 this->servers.push_back(ngl);
213 if (ngl == this->server) {
215 }
216 if (ngl == this->last_joined) {
217 found_last_joined = true;
218 }
219 }
220 /* A refresh can cause the current server to be delete; so unselect. */
221 if (!found_last_joined) {
222 this->last_joined = nullptr;
223 }
225 this->server = nullptr;
226 this->list_pos = SLP_INVALID;
227 }
228
229 /* Apply the filter condition immediately, if a search string has been provided. */
230 StringFilter sf;
231 sf.SetFilterTerm(this->filter_editbox.text.buf);
232
233 if (!sf.IsEmpty()) {
234 this->servers.SetFilterState(true);
235 this->servers.Filter(sf);
236 } else {
237 this->servers.SetFilterState(false);
238 }
239
240 this->servers.RebuildDone();
241 this->vscroll->SetCount(this->servers.size());
242
243 /* Sort the list of network games as requested. */
244 this->servers.Sort();
245 this->UpdateListPos();
246 }
247
249 static bool NGameNameSorter(NetworkGameList * const &a, NetworkGameList * const &b)
250 {
251 int r = StrNaturalCompare(a->info.server_name, b->info.server_name, true); // Sort by name (natural sorting).
252 if (r == 0) r = a->connection_string.compare(b->connection_string);
253
254 return r < 0;
255 }
256
262 static bool NGameClientSorter(NetworkGameList * const &a, NetworkGameList * const &b)
263 {
264 /* Reverse as per default we are interested in most-clients first */
265 int r = a->info.clients_on - b->info.clients_on;
266
267 if (r == 0) r = a->info.clients_max - b->info.clients_max;
268 if (r == 0) return NGameNameSorter(a, b);
269
270 return r < 0;
271 }
272
274 static bool NGameMapSizeSorter(NetworkGameList * const &a, NetworkGameList * const &b)
275 {
276 /* Sort by the area of the map. */
277 int r = (a->info.map_height) * (a->info.map_width) - (b->info.map_height) * (b->info.map_width);
278
279 if (r == 0) r = a->info.map_width - b->info.map_width;
280 return (r != 0) ? r < 0 : NGameClientSorter(a, b);
281 }
282
284 static bool NGameCalendarDateSorter(NetworkGameList * const &a, NetworkGameList * const &b)
285 {
286 auto r = a->info.calendar_date - b->info.calendar_date;
287 return (r != 0) ? r < 0 : NGameClientSorter(a, b);
288 }
289
291 static bool NGameTicksPlayingSorter(NetworkGameList * const &a, NetworkGameList * const &b)
292 {
293 if (a->info.ticks_playing == b->info.ticks_playing) {
294 return NGameClientSorter(a, b);
295 }
296 return a->info.ticks_playing < b->info.ticks_playing;
297 }
298
303 static bool NGameAllowedSorter(NetworkGameList * const &a, NetworkGameList * const &b)
304 {
305 /* The servers we do not know anything about (the ones that did not reply) should be at the bottom) */
306 int r = a->info.server_revision.empty() - b->info.server_revision.empty();
307
308 /* Reverse default as we are interested in version-compatible clients first */
309 if (r == 0) r = b->info.version_compatible - a->info.version_compatible;
310 /* The version-compatible ones are then sorted with NewGRF compatible first, incompatible last */
311 if (r == 0) r = b->info.compatible - a->info.compatible;
312 /* Passworded servers should be below unpassworded servers */
313 if (r == 0) r = a->info.use_password - b->info.use_password;
314
315 /* Finally sort on the number of clients of the server in reverse order. */
316 return (r != 0) ? r < 0 : NGameClientSorter(b, a);
317 }
318
321 {
322 if (this->servers.Sort()) this->UpdateListPos();
323 }
324
327 {
328 this->list_pos = SLP_INVALID;
329 for (uint i = 0; i != this->servers.size(); i++) {
330 if (this->servers[i] == this->server) {
331 this->list_pos = i;
332 break;
333 }
334 }
335 }
336
337 static bool NGameSearchFilter(NetworkGameList * const *item, StringFilter &sf)
338 {
339 assert(item != nullptr);
340 assert((*item) != nullptr);
341
342 sf.ResetState();
343 sf.AddLine((*item)->info.server_name);
344 return sf.GetState();
345 }
346
353 void DrawServerLine(const NetworkGameList *cur_item, int y, bool highlight) const
354 {
355 Rect name = this->GetWidget<NWidgetBase>(WID_NG_NAME)->GetCurrentRect();
356 Rect info = this->GetWidget<NWidgetBase>(WID_NG_INFO)->GetCurrentRect();
357
358 /* show highlighted item with a different colour */
359 if (highlight) {
360 Rect r = {std::min(name.left, info.left), y, std::max(name.right, info.right), y + (int)this->resize.step_height - 1};
362 }
363
364 /* Offset to vertically position text. */
366
367 info = info.Shrink(WidgetDimensions::scaled.framerect);
368 name = name.Shrink(WidgetDimensions::scaled.framerect);
369 DrawString(name.left, name.right, y + text_y_offset, cur_item->info.server_name, TC_BLACK);
370
371 /* only draw details if the server is online */
372 if (cur_item->status == NGLS_ONLINE) {
374 Rect clients = nwid->GetCurrentRect();
375 SetDParam(0, cur_item->info.clients_on);
376 SetDParam(1, cur_item->info.clients_max);
377 SetDParam(2, cur_item->info.companies_on);
378 SetDParam(3, cur_item->info.companies_max);
379 DrawString(clients.left, clients.right, y + text_y_offset, STR_NETWORK_SERVER_LIST_GENERAL_ONLINE, TC_FROMSTRING, SA_HOR_CENTER);
380 }
381
383 /* map size */
384 Rect mapsize = nwid->GetCurrentRect();
385 SetDParam(0, cur_item->info.map_width);
386 SetDParam(1, cur_item->info.map_height);
388 }
389
391 /* current date */
392 Rect date = nwid->GetCurrentRect();
393 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(cur_item->info.calendar_date);
394 SetDParam(0, ymd.year);
395 DrawString(date.left, date.right, y + text_y_offset, STR_JUST_INT, TC_BLACK, SA_HOR_CENTER);
396 }
397
399 /* play time */
400 Rect years = nwid->GetCurrentRect();
401 const auto play_time = cur_item->info.ticks_playing / Ticks::TICKS_PER_SECOND;
402 SetDParam(0, play_time / 60 / 60);
403 SetDParam(1, (play_time / 60) % 60);
405 }
406
407 /* Set top and bottom of info rect to current row. */
408 info.top = y;
409 info.bottom = y + this->resize.step_height - 1;
410
411 bool rtl = _current_text_dir == TD_RTL;
412
413 /* draw a lock if the server is password protected */
414 if (cur_item->info.use_password) DrawSpriteIgnorePadding(SPR_LOCK, PAL_NONE, info.WithWidth(this->lock.width, rtl), SA_CENTER);
415
416 /* draw red or green icon, depending on compatibility with server */
417 PaletteID pal = cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED);
418 DrawSpriteIgnorePadding(SPR_BLOT, pal, info.WithWidth(this->blot.width, !rtl), SA_CENTER);
419 }
420 }
421
430 {
431 if (this->list_pos == SLP_INVALID) return; // no server selected
432 this->vscroll->ScrollTowards(this->list_pos);
433 }
434
435public:
437 {
438 this->list_pos = SLP_INVALID;
439 this->server = nullptr;
440
441 this->CreateNestedTree();
442 this->vscroll = this->GetScrollbar(WID_NG_SCROLLBAR);
444
446 this->name_editbox.text.Assign(_settings_client.network.client_name);
447
449 this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
451
452 /* As the Game Coordinator doesn't support "websocket" servers yet, we
453 * let "os/emscripten/pre.js" hardcode a list of servers people can
454 * join. This means the serverlist is curated for now, but it is the
455 * best we can offer. */
456#ifdef __EMSCRIPTEN__
457 EM_ASM(if (window["openttd_server_list"]) openttd_server_list());
458#endif
459
460 this->last_joined = NetworkAddServer(_settings_client.network.last_joined, false);
461 this->server = this->last_joined;
462
463 this->servers.SetListing(this->last_sorting);
464 this->servers.SetSortFuncs(NetworkGameWindow::sorter_funcs);
465 this->servers.SetFilterFuncs(NetworkGameWindow::filter_funcs);
466 this->servers.ForceRebuild();
467 }
468
470 {
471 this->last_sorting = this->servers.GetListing();
472 }
473
474 void OnInit() override
475 {
476 this->lock = GetScaledSpriteSize(SPR_LOCK);
477 this->blot = GetScaledSpriteSize(SPR_BLOT);
478 }
479
481 {
482 switch (widget) {
483 case WID_NG_MATRIX:
484 resize.height = std::max(GetSpriteSize(SPR_BLOT).height, (uint)GetCharacterHeight(FS_NORMAL)) + padding.height;
485 fill.height = resize.height;
486 size.height = 12 * resize.height;
487 break;
488
490 size.height = std::max(GetSpriteSize(SPR_BLOT).height, (uint)GetCharacterHeight(FS_NORMAL)) + WidgetDimensions::scaled.matrix.Vertical();
491 break;
492
494 size.width = NWidgetScrollbar::GetVerticalDimension().width;
495 break;
496
497 case WID_NG_NAME:
498 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
499 break;
500
501 case WID_NG_CLIENTS:
502 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
508 break;
509
510 case WID_NG_MAPSIZE:
511 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
515 break;
516
517 case WID_NG_DATE:
518 case WID_NG_YEARS:
519 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
520 SetDParamMaxValue(0, 5);
522 break;
523
524 case WID_NG_INFO:
525 size.width = this->lock.width + WidgetDimensions::scaled.hsep_normal + this->blot.width + padding.width;
526 size.height = std::max(this->lock.height, this->blot.height) + padding.height;
527 break;
528 }
529 }
530
531 void DrawWidget(const Rect &r, WidgetID widget) const override
532 {
533 switch (widget) {
534 case WID_NG_MATRIX: {
535 uint16_t y = r.top;
536
537 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->servers);
538 for (auto it = first; it != last; ++it) {
539 const NetworkGameList *ngl = *it;
540 this->DrawServerLine(ngl, y, ngl == this->server);
541 y += this->resize.step_height;
542 }
543 break;
544 }
545
547 /* Draw the last joined server, if any */
548 if (this->last_joined != nullptr) this->DrawServerLine(this->last_joined, r.top, this->last_joined == this->server);
549 break;
550
551 case WID_NG_DETAILS:
552 this->DrawDetails(r);
553 break;
554
555 case WID_NG_NAME:
556 case WID_NG_CLIENTS:
557 case WID_NG_MAPSIZE:
558 case WID_NG_DATE:
559 case WID_NG_YEARS:
560 case WID_NG_INFO:
561 if (widget - WID_NG_NAME == this->servers.SortType()) this->DrawSortButtonState(widget, this->servers.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
562 break;
563 }
564 }
565
566
567 void OnPaint() override
568 {
569 if (this->servers.NeedRebuild()) {
571 }
572 if (this->servers.NeedResort()) {
573 this->SortNetworkGameList();
574 }
575
576 NetworkGameList *sel = this->server;
577 /* 'Refresh' button invisible if no server selected */
578 this->SetWidgetDisabledState(WID_NG_REFRESH, sel == nullptr);
579 /* 'Join' button disabling conditions */
580 this->SetWidgetDisabledState(WID_NG_JOIN, sel == nullptr || // no Selected Server
581 sel->status != NGLS_ONLINE || // Server offline
582 sel->info.clients_on >= sel->info.clients_max || // Server full
583 !sel->info.compatible); // Revision mismatch
584
585 this->SetWidgetLoweredState(WID_NG_REFRESH, sel != nullptr && sel->refreshing);
586
587 /* 'NewGRF Settings' button invisible if no NewGRF is used */
588 bool changed = false;
589 changed |= this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == nullptr || sel->status != NGLS_ONLINE || sel->info.grfconfig == nullptr ? SZSP_NONE : 0);
590 changed |= this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_MISSING_SEL)->SetDisplayedPlane(sel == nullptr || sel->status != NGLS_ONLINE || sel->info.grfconfig == nullptr || !sel->info.version_compatible || sel->info.compatible ? SZSP_NONE : 0);
591 if (changed) {
592 this->ReInit();
593 return;
594 }
595
596#ifdef __EMSCRIPTEN__
601#endif
602
603 this->DrawWidgets();
604 }
605
606 StringID GetHeaderString() const
607 {
608 if (this->server == nullptr) return STR_NETWORK_SERVER_LIST_GAME_INFO;
609 switch (this->server->status) {
615 default: NOT_REACHED();
616 }
617 }
618
619 void DrawDetails(const Rect &r) const
620 {
621 NetworkGameList *sel = this->server;
622
623 Rect tr = r.Shrink(WidgetDimensions::scaled.frametext);
624 StringID header_msg = this->GetHeaderString();
625 int header_height = GetStringHeight(header_msg, tr.Width()) +
626 (sel == nullptr ? 0 : GetStringHeight(sel->info.server_name, tr.Width())) +
627 WidgetDimensions::scaled.frametext.Vertical();
628
629 /* Height for the title banner */
630 Rect hr = r.WithHeight(header_height).Shrink(WidgetDimensions::scaled.frametext);
631 tr.top += header_height;
632
633 /* Draw the right menu */
634 /* Create the nice grayish rectangle at the details top */
636 hr.top = DrawStringMultiLine(hr, header_msg, TC_FROMSTRING, SA_HOR_CENTER);
637 if (sel == nullptr) return;
638
639 hr.top = DrawStringMultiLine(hr, sel->info.server_name, TC_ORANGE, SA_HOR_CENTER); // game name
640 if (sel->status != NGLS_ONLINE) {
641 tr.top = DrawStringMultiLine(tr, header_msg, TC_FROMSTRING, SA_HOR_CENTER);
642 } else { // show game info
643 SetDParam(0, sel->info.clients_on);
644 SetDParam(1, sel->info.clients_max);
645 SetDParam(2, sel->info.companies_on);
648
651
652 SetDParam(0, sel->info.map_width);
653 SetDParam(1, sel->info.map_height);
655
658
661 tr.top = DrawStringMultiLine(tr, invite_or_address); // server address / invite code
662
665
668
670 SetDParam(0, play_time / 60 / 60);
671 SetDParam(1, (play_time / 60) % 60);
673
674 if (sel->info.gamescript_version != -1) {
677 tr.top = DrawStringMultiLine(tr, STR_NETWORK_SERVER_LIST_GAMESCRIPT); // gamescript name and version
678 }
679
681
682 if (!sel->info.compatible) {
684 } else if (sel->info.clients_on == sel->info.clients_max) {
685 /* Show: server full, when clients_on == max_clients */
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_CANCEL: // Cancel button
698 break;
699
700 case WID_NG_NAME: // Sort by name
701 case WID_NG_CLIENTS: // Sort by connected clients
702 case WID_NG_MAPSIZE: // Sort by map size
703 case WID_NG_DATE: // Sort by date
704 case WID_NG_YEARS: // Sort by years
705 case WID_NG_INFO: // Connectivity (green dot)
706 if (this->servers.SortType() == widget - WID_NG_NAME) {
707 this->servers.ToggleSortOrder();
708 if (this->list_pos != SLP_INVALID) this->list_pos = (ServerListPosition)this->servers.size() - this->list_pos - 1;
709 } else {
710 this->servers.SetSortType(widget - WID_NG_NAME);
711 this->servers.ForceResort();
712 this->SortNetworkGameList();
713 }
715 this->SetDirty();
716 break;
717
718 case WID_NG_MATRIX: { // Show available network games
719 auto it = this->vscroll->GetScrolledItemFromWidget(this->servers, pt.y, this, WID_NG_MATRIX);
720 this->server = (it != this->servers.end()) ? *it : nullptr;
721 this->list_pos = (server == nullptr) ? SLP_INVALID : it - this->servers.begin();
722 this->SetDirty();
723
724 /* FIXME the disabling should go into some InvalidateData, which is called instead of the SetDirty */
725 if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
726 break;
727 }
728
729 case WID_NG_LASTJOINED: {
730 if (this->last_joined != nullptr) {
731 this->server = this->last_joined;
732
733 /* search the position of the newly selected server */
734 this->UpdateListPos();
736 this->SetDirty();
737
738 /* FIXME the disabling should go into some InvalidateData, which is called instead of the SetDirty */
739 if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
740 }
741 break;
742 }
743
746 this->searched_internet = true;
747 break;
748
751 break;
752
753 case WID_NG_ADD: // Add a server
758 NETWORK_HOSTNAME_PORT_LENGTH, // maximum number of characters including '\0'
760 break;
761
762 case WID_NG_START: // Start server
763 ShowNetworkStartServerWindow();
764 break;
765
766 case WID_NG_JOIN: // Join Game
767 if (this->server != nullptr) {
769 }
770 break;
771
772 case WID_NG_REFRESH: // Refresh
773 if (this->server != nullptr && !this->server->refreshing) NetworkQueryServer(this->server->connection_string);
774 break;
775
776 case WID_NG_NEWGRF: // NewGRF Settings
777 if (this->server != nullptr) ShowNewGRFSettings(false, false, false, &this->server->info.grfconfig);
778 break;
779
780 case WID_NG_NEWGRF_MISSING: // Find missing content online
781 if (this->server != nullptr) ShowMissingContentWindow(this->server->info.grfconfig);
782 break;
783 }
784 }
785
791 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
792 {
793 this->servers.ForceRebuild();
794 this->SetDirty();
795 }
796
797 EventState OnKeyPress([[maybe_unused]] char32_t key, uint16_t keycode) override
798 {
800
801 /* handle up, down, pageup, pagedown, home and end */
802 if (this->vscroll->UpdateListPositionOnKeyPress(this->list_pos, keycode) == ES_HANDLED) {
803 if (this->list_pos == SLP_INVALID) return ES_HANDLED;
804
805 this->server = this->servers[this->list_pos];
806
807 /* Scroll to the new server if it is outside the current range. */
809
810 /* redraw window */
811 this->SetDirty();
812 return ES_HANDLED;
813 }
814
815 if (this->server != nullptr) {
816 if (keycode == WKC_DELETE) { // Press 'delete' to remove servers
817 NetworkGameListRemoveItem(this->server);
818 if (this->server == this->last_joined) this->last_joined = nullptr;
819 this->server = nullptr;
820 this->list_pos = SLP_INVALID;
821 }
822 }
823
824 return state;
825 }
826
828 {
829 switch (wid) {
830 case WID_NG_FILTER: {
831 this->servers.ForceRebuild();
834 this->SetDirty();
835 break;
836 }
837
838 case WID_NG_CLIENT:
839 /* Validation of the name will happen once the user tries to join or start a game, as getting
840 * error messages while typing (e.g. when you clear the name) defeats the purpose of the check. */
841 _settings_client.network.client_name = this->name_editbox.text.buf;
842 break;
843 }
844 }
845
846 void OnQueryTextFinished(std::optional<std::string> str) override
847 {
848 if (!str.has_value() || str->empty()) return;
849
850 _settings_client.network.connect_to_ip = std::move(*str);
852 NetworkRebuildHostList();
853 }
854
855 void OnResize() override
856 {
857 this->vscroll->SetCapacityFromWidget(this, WID_NG_MATRIX);
858 }
859
861 IntervalTimer<TimerWindow> refresh_interval = {std::chrono::seconds(30), [this](uint) {
862 if (!this->searched_internet) return;
863
865 }};
866};
867
868Listing NetworkGameWindow::last_sorting = {false, 5};
869const std::initializer_list<GUIGameServerList::SortFunction * const> NetworkGameWindow::sorter_funcs = {
870 &NGameNameSorter,
871 &NGameClientSorter,
872 &NGameMapSizeSorter,
873 &NGameCalendarDateSorter,
874 &NGameTicksPlayingSorter,
875 &NGameAllowedSorter
876};
877
878const std::initializer_list<GUIGameServerList::FilterFunction * const> NetworkGameWindow::filter_funcs = {
879 &NGameSearchFilter
880};
881
882static std::unique_ptr<NWidgetBase> MakeResizableHeader()
883{
884 return std::make_unique<NWidgetServerListHeader>();
885}
886
887static constexpr NWidgetPart _nested_network_game_widgets[] = {
888 /* TOP */
890 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
891 NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_SERVER_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
892 NWidget(WWT_DEFSIZEBOX, COLOUR_LIGHT_BLUE),
893 EndContainer(),
894 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_MAIN),
897 /* LEFT SIDE */
900 NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_FILTER_LABEL), SetDataTip(STR_LIST_FILTER_TITLE, STR_NULL),
901 NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_FILTER), SetMinimalSize(251, 0), SetFill(1, 0), SetResize(1, 0),
902 SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
903 EndContainer(),
906 NWidgetFunction(MakeResizableHeader),
907 NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NG_MATRIX), SetResize(1, 1), SetFill(1, 0),
908 SetMatrixDataTip(1, 0, STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT), SetScrollbar(WID_NG_SCROLLBAR),
909 EndContainer(),
910 NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NG_SCROLLBAR),
911 EndContainer(),
913 NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_LASTJOINED_LABEL), SetFill(1, 0),
914 SetDataTip(STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER, STR_NULL), SetResize(1, 0),
916 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_LASTJOINED), SetFill(1, 0), SetResize(1, 0),
917 SetDataTip(0x0, STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST),
918 EndContainer(),
919 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NG_LASTJOINED_SPACER), SetFill(0, 0),
920 EndContainer(),
921 EndContainer(),
922 EndContainer(),
923 /* RIGHT SIDE */
926 NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_CLIENT_LABEL), SetDataTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME, STR_NULL),
927 NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_CLIENT), SetMinimalSize(151, 0), SetFill(1, 0), SetResize(1, 0),
928 SetDataTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE, STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP),
929 EndContainer(),
931 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_DETAILS), SetMinimalSize(140, 0), SetMinimalTextLines(15, 0), SetResize(0, 1),
932 EndContainer(),
935 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NEWGRF_MISSING), SetFill(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON, STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP),
936 EndContainer(),
937 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NG_NEWGRF_SEL),
938 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NEWGRF), SetFill(1, 0), SetDataTip(STR_INTRO_NEWGRF_SETTINGS, STR_NULL),
939 EndContainer(),
941 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_JOIN), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_JOIN_GAME, STR_NULL),
942 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_REFRESH), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_REFRESH, STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP),
943 EndContainer(),
944 EndContainer(),
945 EndContainer(),
946 EndContainer(),
947 EndContainer(),
948 /* BOTTOM */
950 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_SEARCH_INTERNET), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET, STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP),
951 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_SEARCH_LAN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN, STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP),
952 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_ADD), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_ADD_SERVER, STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP),
953 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_START), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_START_SERVER, STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP),
954 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CANCEL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
955 EndContainer(),
956 EndContainer(),
957 /* Resize button. */
959 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
960 NWidget(WWT_RESIZEBOX, COLOUR_LIGHT_BLUE), SetDataTip(RWV_HIDE_BEVEL, STR_TOOLTIP_RESIZE),
961 EndContainer(),
962 EndContainer(),
963};
964
965static WindowDesc _network_game_window_desc(
966 WDP_CENTER, "list_servers", 1000, 730,
968 0,
969 _nested_network_game_widgets
970);
971
972void ShowNetworkGameWindow()
973{
974 static bool first = true;
976
977 /* Only show once */
978 if (first) {
979 first = false;
980 /* Add all servers from the config file to our list. */
981 for (const auto &iter : _network_host_list) {
982 NetworkAddServer(iter);
983 }
984 }
985
986 new NetworkGameWindow(_network_game_window_desc);
987}
988
992
994 {
996
998 this->name_editbox.text.Assign(_settings_client.network.server_name);
999
1001 }
1002
1003 void SetStringParameters(WidgetID widget) const override
1004 {
1005 switch (widget) {
1008 break;
1009
1012 break;
1013
1016 break;
1017 }
1018 }
1019
1021 {
1022 switch (widget) {
1025 size.width += padding.width;
1026 size.height += padding.height;
1027 break;
1028 }
1029 }
1030
1031 void DrawWidget(const Rect &r, WidgetID widget) const override
1032 {
1033 switch (widget) {
1034 case WID_NSS_SETPWD:
1035 /* If password is set, draw red '*' next to 'Set password' button. */
1036 if (!_settings_client.network.server_password.empty()) DrawString(r.right + WidgetDimensions::scaled.framerect.left, this->width - WidgetDimensions::scaled.framerect.right, r.top, "*", TC_RED);
1037 }
1038 }
1039
1040 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1041 {
1042 switch (widget) {
1043 case WID_NSS_CANCEL: // Cancel button
1044 ShowNetworkGameWindow();
1045 break;
1046
1047 case WID_NSS_SETPWD: // Set password button
1048 this->widget_id = WID_NSS_SETPWD;
1051 break;
1052
1053 case WID_NSS_CONNTYPE_BTN: // Connection type
1054 ShowDropDownList(this, BuildVisibilityDropDownList(), _settings_client.network.server_game_type, WID_NSS_CONNTYPE_BTN);
1055 break;
1056
1057 case WID_NSS_CLIENTS_BTND: case WID_NSS_CLIENTS_BTNU: // Click on up/down button for number of clients
1058 case WID_NSS_COMPANIES_BTND: case WID_NSS_COMPANIES_BTNU: // Click on up/down button for number of companies
1059 /* Don't allow too fast scrolling. */
1060 if (!(this->flags & WF_TIMEOUT) || this->timeout_timer <= 1) {
1061 this->HandleButtonClick(widget);
1062 this->SetDirty();
1063 switch (widget) {
1064 default: NOT_REACHED();
1067 break;
1070 break;
1071 }
1072 }
1073 _left_button_clicked = false;
1074 break;
1075
1076 case WID_NSS_CLIENTS_TXT: // Click on number of clients
1077 this->widget_id = WID_NSS_CLIENTS_TXT;
1080 break;
1081
1082 case WID_NSS_COMPANIES_TXT: // Click on number of companies
1083 this->widget_id = WID_NSS_COMPANIES_TXT;
1086 break;
1087
1088 case WID_NSS_GENERATE_GAME: // Start game
1089 if (!CheckServerName()) return;
1090 _is_network_server = true;
1091 if (_ctrl_pressed) {
1093 } else {
1095 }
1096 break;
1097
1098 case WID_NSS_LOAD_GAME:
1099 if (!CheckServerName()) return;
1100 _is_network_server = true;
1102 break;
1103
1105 if (!CheckServerName()) return;
1106 _is_network_server = true;
1108 break;
1109
1111 if (!CheckServerName()) return;
1112 _is_network_server = true;
1114 break;
1115 }
1116 }
1117
1118 void OnDropdownSelect(WidgetID widget, int index) override
1119 {
1120 switch (widget) {
1123 break;
1124 default:
1125 NOT_REACHED();
1126 }
1127
1128 this->SetDirty();
1129 }
1130
1131 bool CheckServerName()
1132 {
1133 std::string str = this->name_editbox.text.buf;
1134 if (!NetworkValidateServerName(str)) return false;
1135
1136 SetSettingValue(GetSettingFromName("network.server_name")->AsStringSetting(), str);
1137 return true;
1138 }
1139
1144
1145 void OnQueryTextFinished(std::optional<std::string> str) override
1146 {
1147 if (!str.has_value()) return;
1148
1149 if (this->widget_id == WID_NSS_SETPWD) {
1150 _settings_client.network.server_password = std::move(*str);
1151 } else {
1152 int32_t value = atoi(str->c_str());
1153 this->SetWidgetDirty(this->widget_id);
1154 switch (this->widget_id) {
1155 default: NOT_REACHED();
1158 }
1159 }
1160
1161 this->SetDirty();
1162 }
1163};
1164
1165static constexpr NWidgetPart _nested_network_start_server_window_widgets[] = {
1167 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
1168 NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_START_SERVER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1169 EndContainer(),
1170 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NSS_BACKGROUND),
1174 /* Game name widgets */
1175 NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_GAMENAME_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME, STR_NULL),
1176 NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NSS_GAMENAME), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE, STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP),
1177 EndContainer(),
1178
1181 NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_VISIBILITY_LABEL, STR_NULL),
1182 NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_BTN), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP),
1183 EndContainer(),
1185 NWidget(NWID_SPACER), SetFill(1, 1),
1186 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_SETPWD), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_SET_PASSWORD, STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP),
1187 EndContainer(),
1188 EndContainer(),
1189
1192 NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS, STR_NULL),
1194 NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_BTND), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON), SetFill(0, 1), SetDataTip(SPR_ARROW_DOWN, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
1195 NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_TXT), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_CLIENTS_SELECT, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
1196 NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_BTNU), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON), SetFill(0, 1), SetDataTip(SPR_ARROW_UP, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
1197 EndContainer(),
1198 EndContainer(),
1199
1201 NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES, STR_NULL),
1203 NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_BTND), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON), SetFill(0, 1), SetDataTip(SPR_ARROW_DOWN, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
1204 NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_TXT), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_COMPANIES_SELECT, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
1205 NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_BTNU), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON), SetFill(0, 1), SetDataTip(SPR_ARROW_UP, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
1206 EndContainer(),
1207 EndContainer(),
1208 EndContainer(),
1209 EndContainer(),
1210
1212 /* 'generate game' and 'load game' buttons */
1214 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_GENERATE_GAME), SetDataTip(STR_INTRO_NEW_GAME, STR_INTRO_TOOLTIP_NEW_GAME), SetFill(1, 0),
1215 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_LOAD_GAME), SetDataTip(STR_INTRO_LOAD_GAME, STR_INTRO_TOOLTIP_LOAD_GAME), SetFill(1, 0),
1216 EndContainer(),
1217
1218 /* 'play scenario' and 'play heightmap' buttons */
1220 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_PLAY_SCENARIO), SetDataTip(STR_INTRO_PLAY_SCENARIO, STR_INTRO_TOOLTIP_PLAY_SCENARIO), SetFill(1, 0),
1221 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_PLAY_HEIGHTMAP), SetDataTip(STR_INTRO_PLAY_HEIGHTMAP, STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP), SetFill(1, 0),
1222 EndContainer(),
1223 EndContainer(),
1224
1226 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_CANCEL), SetDataTip(STR_BUTTON_CANCEL, STR_NULL), SetMinimalSize(128, 12),
1227 EndContainer(),
1228 EndContainer(),
1229 EndContainer(),
1230};
1231
1232static WindowDesc _network_start_server_window_desc(
1233 WDP_CENTER, nullptr, 0, 0,
1235 0,
1236 _nested_network_start_server_window_widgets
1237);
1238
1239static void ShowNetworkStartServerWindow()
1240{
1241 if (!NetworkValidateOurClientName()) return;
1242
1244
1245 new NetworkStartServerWindow(_network_start_server_window_desc);
1246}
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
1253static constexpr NWidgetPart _nested_client_list_widgets[] = {
1255 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1256 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_CLIENT_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1257 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
1258 NWidget(WWT_STICKYBOX, COLOUR_GREY),
1259 EndContainer(),
1260 NWidget(WWT_PANEL, COLOUR_GREY),
1262 NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_NETWORK_CLIENT_LIST_SERVER, STR_NULL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0),
1264 NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_NETWORK_CLIENT_LIST_SERVER_NAME, STR_NULL),
1265 NWidget(WWT_TEXT, COLOUR_GREY, WID_CL_SERVER_NAME), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_JUST_RAW_STRING, STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1266 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_CL_SERVER_NAME_EDIT), SetAspect(WidgetDimensions::ASPECT_RENAME), SetDataTip(SPR_RENAME, STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP),
1267 EndContainer(),
1271 NWidget(WWT_TEXT, COLOUR_GREY), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY, STR_NULL),
1272 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_CL_SERVER_VISIBILITY), SetDataTip(STR_JUST_STRING, STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP),
1273 EndContainer(),
1275 NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_NETWORK_CLIENT_LIST_SERVER_INVITE_CODE, STR_NULL),
1276 NWidget(WWT_TEXT, COLOUR_GREY, WID_CL_SERVER_INVITE_CODE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_JUST_RAW_STRING, STR_NETWORK_CLIENT_LIST_SERVER_INVITE_CODE_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1277 EndContainer(),
1279 NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE, STR_NULL),
1280 NWidget(WWT_TEXT, COLOUR_GREY, WID_CL_SERVER_CONNECTION_TYPE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_JUST_STRING, STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1281 EndContainer(),
1282 EndContainer(),
1283 EndContainer(),
1284 EndContainer(),
1285 NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_NETWORK_CLIENT_LIST_PLAYER, STR_NULL),
1287 NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_NETWORK_CLIENT_LIST_PLAYER_NAME, STR_NULL),
1288 NWidget(WWT_TEXT, COLOUR_GREY, WID_CL_CLIENT_NAME), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_JUST_RAW_STRING, STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1289 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_CL_CLIENT_NAME_EDIT), SetAspect(WidgetDimensions::ASPECT_RENAME), SetDataTip(SPR_RENAME, STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP),
1290 EndContainer(),
1291 EndContainer(),
1292 EndContainer(),
1293 EndContainer(),
1295 NWidget(WWT_MATRIX, COLOUR_GREY, WID_CL_MATRIX), SetMinimalSize(180, 0), SetResize(1, 1), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_CL_SCROLLBAR),
1297 EndContainer(),
1299 NWidget(WWT_PANEL, COLOUR_GREY),
1300 NWidget(WWT_TEXT, COLOUR_GREY, WID_CL_CLIENT_COMPANY_COUNT), SetFill(1, 0), SetResize(1, 0), SetPadding(WidgetDimensions::unscaled.framerect), SetAlignment(SA_CENTER), SetDataTip(STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT, STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT_TOOLTIP),
1301 EndContainer(),
1302 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
1303 EndContainer(),
1304};
1305
1306static WindowDesc _client_list_desc(
1307 WDP_AUTO, "list_clients", 220, 300,
1309 0,
1310 _nested_client_list_widgets
1311);
1312
1318 DD_CLIENT_ADMIN_KICK,
1319 DD_CLIENT_ADMIN_BAN,
1320 DD_COMPANY_ADMIN_RESET,
1321};
1322
1327static void AdminClientKickCallback(Window *, bool confirmed)
1328{
1329 if (confirmed) NetworkServerKickClient(_admin_client_id, {});
1330}
1331
1336static void AdminClientBanCallback(Window *, bool confirmed)
1337{
1338 if (confirmed) NetworkServerKickOrBanIP(_admin_client_id, true, {});
1339}
1340
1345static void AdminCompanyResetCallback(Window *, bool confirmed)
1346{
1347 if (confirmed) {
1350 }
1351}
1352
1361public:
1364 Colours colour;
1366 uint height;
1367 uint width;
1368
1369 ButtonCommon(SpriteID sprite, StringID tooltip, Colours colour, bool disabled = false) :
1370 sprite(sprite),
1372 colour(colour),
1374 {
1376 this->height = d.height + WidgetDimensions::scaled.framerect.Vertical();
1377 this->width = d.width + WidgetDimensions::scaled.framerect.Horizontal();
1378 }
1379 virtual ~ButtonCommon() = default;
1380
1384 virtual void OnClick(struct NetworkClientListWindow *w, Point pt) = 0;
1385};
1386
1390template<typename T>
1391class Button : public ButtonCommon {
1392private:
1393 typedef void (*ButtonCallback)(struct NetworkClientListWindow *w, Point pt, T id);
1394 T id;
1396
1397public:
1398 Button(SpriteID sprite, StringID tooltip, Colours colour, T id, ButtonCallback proc, bool disabled = false) :
1400 id(id),
1401 proc(proc)
1402 {
1403 assert(proc != nullptr);
1404 }
1405
1406 void OnClick(struct NetworkClientListWindow *w, Point pt) override
1407 {
1408 if (this->disabled) return;
1409
1410 this->proc(w, pt, this->id);
1411 }
1412};
1413
1416
1421private:
1423
1426
1433
1434 std::map<uint, std::vector<std::unique_ptr<ButtonCommon>>> buttons;
1435
1446
1462
1472
1480 {
1481 DropDownList list;
1482 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK, DD_CLIENT_ADMIN_KICK));
1483 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN, DD_CLIENT_ADMIN_BAN));
1484
1485 Rect wi_rect;
1486 wi_rect.left = pt.x;
1487 wi_rect.right = pt.x;
1488 wi_rect.top = pt.y;
1489 wi_rect.bottom = pt.y;
1490
1491 w->dd_client_id = client_id;
1492 ShowDropDownListAt(w, std::move(list), -1, WID_CL_MATRIX, wi_rect, COLOUR_GREY, true);
1493 }
1494
1502 {
1503 DropDownList list;
1504 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET, DD_COMPANY_ADMIN_RESET, NetworkCompanyHasClients(company_id)));
1505
1506 Rect wi_rect;
1507 wi_rect.left = pt.x;
1508 wi_rect.right = pt.x;
1509 wi_rect.top = pt.y;
1510 wi_rect.bottom = pt.y;
1511
1512 w->dd_company_id = company_id;
1513 ShowDropDownListAt(w, std::move(list), -1, WID_CL_MATRIX, wi_rect, COLOUR_GREY, true);
1514 }
1525
1526 static void OnClickClientAuthorize([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, ClientID client_id)
1527 {
1530 }
1531
1539 {
1541
1542 if (_network_server) this->buttons[line_count].push_back(std::make_unique<CompanyButton>(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP, COLOUR_RED, company_id, &NetworkClientListWindow::OnClickCompanyAdmin, company_id == COMPANY_SPECTATOR));
1543 this->buttons[line_count].emplace_back(chat_button);
1544 if (can_join_company) this->buttons[line_count].push_back(std::make_unique<CompanyButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::OnClickCompanyJoin, company_id != COMPANY_SPECTATOR && Company::Get(company_id)->is_ai));
1545
1546 this->line_count += 1;
1547
1548 bool has_players = false;
1549 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1550 if (ci->client_playas != company_id) continue;
1551 has_players = true;
1552
1553 if (_network_server) this->buttons[line_count].push_back(std::make_unique<ClientButton>(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP, COLOUR_RED, ci->client_id, &NetworkClientListWindow::OnClickClientAdmin, _network_own_client_id == ci->client_id));
1554 if (_network_own_client_id != ci->client_id) this->buttons[line_count].push_back(std::make_unique<ClientButton>(SPR_CHAT, STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP, COLOUR_ORANGE, ci->client_id, &NetworkClientListWindow::OnClickClientChat));
1555 if (_network_own_client_id != ci->client_id && client_playas != COMPANY_SPECTATOR && !ci->CanJoinCompany(client_playas)) this->buttons[line_count].push_back(std::make_unique<ClientButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_COMPANY_AUTHORIZE_TOOLTIP, COLOUR_GREEN, ci->client_id, &NetworkClientListWindow::OnClickClientAuthorize));
1556
1557 if (ci->client_id == _network_own_client_id) {
1558 this->player_self_index = this->line_count;
1559 } else if (ci->client_id == CLIENT_ID_SERVER) {
1560 this->player_host_index = this->line_count;
1561 }
1562
1563 this->line_count += 1;
1564 }
1565
1566 /* Disable the chat button when there are players in this company. */
1568 }
1569
1574 {
1576 CompanyID client_playas = own_ci == nullptr ? COMPANY_SPECTATOR : own_ci->client_playas;
1577
1578 this->buttons.clear();
1579 this->line_count = 0;
1580 this->player_host_index = -1;
1581 this->player_self_index = -1;
1582
1583 /* As spectator, show a line to create a new company. */
1584 if (client_playas == COMPANY_SPECTATOR && !NetworkMaxCompaniesReached()) {
1585 this->buttons[line_count].push_back(std::make_unique<CompanyButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP, COLOUR_ORANGE, COMPANY_SPECTATOR, &NetworkClientListWindow::OnClickCompanyNew));
1586 this->line_count += 1;
1587 }
1588
1589 if (client_playas != COMPANY_SPECTATOR) {
1590 this->RebuildListCompany(client_playas, client_playas, false);
1591 }
1592
1593 /* Companies */
1594 for (const Company *c : Company::Iterate()) {
1595 if (c->index == client_playas) continue;
1596
1597 this->RebuildListCompany(c->index, client_playas, (own_ci != nullptr && c->allow_list.Contains(own_ci->public_key)) || _network_server);
1598 }
1599
1600 /* Spectators */
1601 this->RebuildListCompany(COMPANY_SPECTATOR, client_playas, client_playas != COMPANY_SPECTATOR);
1602
1603 this->vscroll->SetCount(this->line_count);
1604 }
1605
1612 {
1613 uint index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CL_MATRIX);
1614 Rect matrix = this->GetWidget<NWidgetBase>(WID_CL_MATRIX)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
1615
1616 bool rtl = _current_text_dir == TD_RTL;
1617 uint x = rtl ? matrix.left : matrix.right;
1618
1619 /* Find the buttons for this row. */
1620 auto button_find = this->buttons.find(index);
1621 if (button_find == this->buttons.end()) return nullptr;
1622
1623 /* Check if we want to display a tooltip for any of the buttons. */
1624 for (auto &button : button_find->second) {
1625 uint left = rtl ? x : x - button->width;
1626 uint right = rtl ? x + button->width : x;
1627
1628 if (IsInsideMM(pt.x, left, right)) {
1629 return button.get();
1630 }
1631
1632 int width = button->width + WidgetDimensions::scaled.framerect.Horizontal();
1633 x += rtl ? width : -width;
1634 }
1635
1636 return nullptr;
1637 }
1638
1639public:
1641 Window(desc),
1642 hover_index(-1),
1645 {
1646 this->CreateNestedTree();
1647 this->vscroll = this->GetScrollbar(WID_CL_SCROLLBAR);
1648 this->OnInvalidateData();
1649 this->FinishInitNested(window_number);
1650 }
1651
1652 void OnInit() override
1653 {
1654 RebuildList();
1655 }
1656
1657 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1658 {
1659 this->RebuildList();
1660
1661 /* Currently server information is not sync'd to clients, so we cannot show it on clients. */
1664 }
1665
1667 {
1668 switch (widget) {
1669 case WID_CL_SERVER_NAME:
1670 case WID_CL_CLIENT_NAME:
1671 if (widget == WID_CL_SERVER_NAME) {
1673 } else {
1675 SetDParamStr(0, own_ci != nullptr ? own_ci->client_name : _settings_client.network.client_name);
1676 }
1678 size.width = std::min(size.width, static_cast<uint>(ScaleGUITrad(200))); // By default, don't open the window too wide.
1679 break;
1680
1683 size.width += padding.width;
1684 size.height += padding.height;
1685 break;
1686
1687 case WID_CL_MATRIX: {
1688 uint height = std::max({GetSpriteSize(SPR_COMPANY_ICON).height, GetSpriteSize(SPR_JOIN).height, GetSpriteSize(SPR_ADMIN).height, GetSpriteSize(SPR_CHAT).height});
1690 this->line_height = std::max(height, (uint)GetCharacterHeight(FS_NORMAL)) + padding.height;
1691
1692 resize.width = 1;
1693 resize.height = this->line_height;
1694 fill.height = this->line_height;
1695 size.height = std::max(size.height, 5 * this->line_height);
1696 break;
1697 }
1698 }
1699 }
1700
1701 void OnResize() override
1702 {
1703 this->vscroll->SetCapacityFromWidget(this, WID_CL_MATRIX);
1704 }
1705
1740
1741 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1742 {
1743 switch (widget) {
1745 if (!_network_server) break;
1746
1747 this->query_widget = WID_CL_SERVER_NAME_EDIT;
1750 break;
1751
1754 this->query_widget = WID_CL_CLIENT_NAME_EDIT;
1755 SetDParamStr(0, own_ci != nullptr ? own_ci->client_name : _settings_client.network.client_name);
1757 break;
1758 }
1760 if (!_network_server) break;
1761
1763 break;
1764
1765 case WID_CL_MATRIX: {
1766 ButtonCommon *button = this->GetButtonAtPoint(pt);
1767 if (button == nullptr) break;
1768
1769 button->OnClick(this, pt);
1770 break;
1771 }
1772 }
1773 }
1774
1775 bool OnTooltip([[maybe_unused]] Point pt, WidgetID widget, TooltipCloseCondition close_cond) override
1776 {
1777 switch (widget) {
1778 case WID_CL_MATRIX: {
1779 int index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CL_MATRIX);
1780
1781 bool rtl = _current_text_dir == TD_RTL;
1782 Rect matrix = this->GetWidget<NWidgetBase>(WID_CL_MATRIX)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
1783
1784 Dimension d = GetSpriteSize(SPR_COMPANY_ICON);
1785 uint text_left = matrix.left + (rtl ? 0 : d.width + WidgetDimensions::scaled.hsep_wide);
1786 uint text_right = matrix.right - (rtl ? d.width + WidgetDimensions::scaled.hsep_wide : 0);
1787
1788 Dimension d2 = GetSpriteSize(SPR_PLAYER_SELF);
1790
1791 uint player_icon_x = rtl ? text_right - offset_x - d2.width : text_left + offset_x;
1792
1793 if (IsInsideMM(pt.x, player_icon_x, player_icon_x + d2.width)) {
1794 if (index == this->player_self_index) {
1796 return true;
1797 } else if (index == this->player_host_index) {
1799 return true;
1800 }
1801 }
1802
1803 ButtonCommon *button = this->GetButtonAtPoint(pt);
1804 if (button == nullptr) return false;
1805
1806 GuiShowTooltips(this, button->tooltip, close_cond);
1807 return true;
1808 };
1809 }
1810
1811 return false;
1812 }
1813
1814 void OnDropdownClose(Point pt, WidgetID widget, int index, bool instant_close) override
1815 {
1816 /* If you close the dropdown outside the list, don't take any action. */
1817 if (widget == WID_CL_MATRIX) return;
1818
1819 Window::OnDropdownClose(pt, widget, index, instant_close);
1820 }
1821
1822 void OnDropdownSelect(WidgetID widget, int index) override
1823 {
1824 switch (widget) {
1826 if (!_network_server) break;
1827
1830 break;
1831
1832 case WID_CL_MATRIX: {
1833 StringID text = STR_NULL;
1834 QueryCallbackProc *callback = nullptr;
1835
1836 switch (index) {
1837 case DD_CLIENT_ADMIN_KICK:
1840 callback = AdminClientKickCallback;
1842 break;
1843
1844 case DD_CLIENT_ADMIN_BAN:
1847 callback = AdminClientBanCallback;
1849 break;
1850
1851 case DD_COMPANY_ADMIN_RESET:
1854 callback = AdminCompanyResetCallback;
1856 break;
1857
1858 default:
1859 NOT_REACHED();
1860 }
1861
1862 assert(text != STR_NULL);
1863 assert(callback != nullptr);
1864
1865 /* Always ask confirmation for all admin actions. */
1866 ShowQuery(STR_NETWORK_CLIENT_LIST_ASK_CAPTION, text, this, callback);
1867
1868 break;
1869 }
1870
1871 default:
1872 NOT_REACHED();
1873 }
1874
1875 this->SetDirty();
1876 }
1877
1878 void OnQueryTextFinished(std::optional<std::string> str) override
1879 {
1880 if (!str.has_value()) return;
1881
1882 switch (this->query_widget) {
1883 default: NOT_REACHED();
1884
1886 if (!_network_server) break;
1887
1888 SetSettingValue(GetSettingFromName("network.server_name")->AsStringSetting(), *str);
1889 this->InvalidateData();
1890 break;
1891 }
1892
1894 SetSettingValue(GetSettingFromName("network.client_name")->AsStringSetting(), *str);
1895 this->InvalidateData();
1896 break;
1897 }
1898 }
1899 }
1900
1911 void DrawButtons(int &x, uint y, const std::vector<std::unique_ptr<ButtonCommon>> &buttons) const
1912 {
1913 Rect r;
1914
1915 for (auto &button : buttons) {
1916 bool rtl = _current_text_dir == TD_RTL;
1917
1918 int offset = (this->line_height - button->height) / 2;
1919 r.left = rtl ? x : x - button->width + 1;
1920 r.right = rtl ? x + button->width - 1 : x;
1921 r.top = y + offset;
1922 r.bottom = r.top + button->height - 1;
1923
1924 DrawFrameRect(r, button->colour, FR_NONE);
1925 DrawSprite(button->sprite, PAL_NONE, r.left + WidgetDimensions::scaled.framerect.left, r.top + WidgetDimensions::scaled.framerect.top);
1926 if (button->disabled) {
1928 }
1929
1930 int width = button->width + WidgetDimensions::scaled.hsep_normal;
1931 x += rtl ? width : -width;
1932 }
1933 }
1934
1941 void DrawCompany(CompanyID company_id, const Rect &r, uint &line) const
1942 {
1943 bool rtl = _current_text_dir == TD_RTL;
1944 int text_y_offset = CenterBounds(0, this->line_height, GetCharacterHeight(FS_NORMAL));
1945
1946 Dimension d = GetSpriteSize(SPR_COMPANY_ICON);
1947 int offset = CenterBounds(0, this->line_height, d.height);
1948
1949 uint line_start = this->vscroll->GetPosition();
1950 uint line_end = line_start + this->vscroll->GetCapacity();
1951
1952 uint y = r.top + (this->line_height * (line - line_start));
1953
1954 /* Draw the company line (if in range of scrollbar). */
1955 if (IsInsideMM(line, line_start, line_end)) {
1956 int icon_left = r.WithWidth(d.width, rtl).left;
1958 int &x = rtl ? tr.left : tr.right;
1959
1960 /* If there are buttons for this company, draw them. */
1961 auto button_find = this->buttons.find(line);
1962 if (button_find != this->buttons.end()) {
1963 this->DrawButtons(x, y, button_find->second);
1964 }
1965
1967 DrawSprite(SPR_COMPANY_ICON, PALETTE_TO_GREY, icon_left, y + offset);
1968 DrawString(tr.left, tr.right, y + text_y_offset, STR_NETWORK_CLIENT_LIST_SPECTATORS, TC_SILVER);
1969 } else if (company_id == COMPANY_NEW_COMPANY) {
1970 DrawSprite(SPR_COMPANY_ICON, PALETTE_TO_GREY, icon_left, y + offset);
1972 } else {
1973 DrawCompanyIcon(company_id, icon_left, y + offset);
1974
1977 DrawString(tr.left, tr.right, y + text_y_offset, STR_COMPANY_NAME, TC_SILVER);
1978 }
1979 }
1980
1981 y += this->line_height;
1982 line++;
1983
1984 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1985 if (ci->client_playas != company_id) continue;
1986
1987 /* Draw the player line (if in range of scrollbar). */
1988 if (IsInsideMM(line, line_start, line_end)) {
1989 Rect tr = r.Indent(WidgetDimensions::scaled.hsep_indent, rtl);
1990
1991 /* If there are buttons for this client, draw them. */
1992 auto button_find = this->buttons.find(line);
1993 if (button_find != this->buttons.end()) {
1994 int &x = rtl ? tr.left : tr.right;
1995 this->DrawButtons(x, y, button_find->second);
1996 }
1997
1999 if (ci->client_id == _network_own_client_id) {
2000 player_icon = SPR_PLAYER_SELF;
2001 } else if (ci->client_id == CLIENT_ID_SERVER) {
2002 player_icon = SPR_PLAYER_HOST;
2003 }
2004
2005 if (player_icon != 0) {
2007 int offset_y = CenterBounds(0, this->line_height, d2.height);
2008 DrawSprite(player_icon, PALETTE_TO_GREY, rtl ? tr.right - d2.width : tr.left, y + offset_y);
2009 tr = tr.Indent(d2.width + WidgetDimensions::scaled.hsep_normal, rtl);
2010 }
2011
2012 SetDParamStr(0, ci->client_name);
2013 DrawString(tr.left, tr.right, y + text_y_offset, STR_JUST_RAW_STRING, TC_BLACK);
2014 }
2015
2016 y += this->line_height;
2017 line++;
2018 }
2019 }
2020
2021 void DrawWidget(const Rect &r, WidgetID widget) const override
2022 {
2023 switch (widget) {
2024 case WID_CL_MATRIX: {
2025 Rect ir = r.Shrink(WidgetDimensions::scaled.framerect, RectPadding::zero);
2026 uint line = 0;
2027
2028 if (this->hover_index >= 0) {
2029 Rect br = r.WithHeight(this->line_height).Translate(0, this->hover_index * this->line_height);
2031 }
2032
2034 CompanyID client_playas = own_ci == nullptr ? COMPANY_SPECTATOR : own_ci->client_playas;
2035
2036 if (client_playas == COMPANY_SPECTATOR && !NetworkMaxCompaniesReached()) {
2037 this->DrawCompany(COMPANY_NEW_COMPANY, ir, line);
2038 }
2039
2040 if (client_playas != COMPANY_SPECTATOR) {
2041 this->DrawCompany(client_playas, ir, line);
2042 }
2043
2044 for (const Company *c : Company::Iterate()) {
2045 if (client_playas == c->index) continue;
2046 this->DrawCompany(c->index, ir, line);
2047 }
2048
2049 /* Spectators */
2050 this->DrawCompany(COMPANY_SPECTATOR, ir, line);
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
2074void ShowClientList()
2075{
2076 AllocateWindowDescFront<NetworkClientListWindow>(_client_list_desc, 0);
2077}
2078
2083
2085 std::shared_ptr<NetworkAuthenticationPasswordRequest> request;
2086
2088 {
2091 }
2092
2093 void DrawWidget(const Rect &r, WidgetID widget) const override
2094 {
2095 switch (widget) {
2096 case WID_NJS_PROGRESS_BAR: {
2097 /* Draw the % complete with a bar and a text */
2098 DrawFrameRect(r, COLOUR_GREY, FR_BORDERONLY | FR_LOWERED);
2100 uint8_t progress; // used for progress bar
2101 switch (_network_join_status) {
2102 case NETWORK_JOIN_STATUS_CONNECTING:
2103 case NETWORK_JOIN_STATUS_AUTHORIZING:
2104 case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
2105 progress = 10; // first two stages 10%
2106 break;
2107 case NETWORK_JOIN_STATUS_WAITING:
2108 progress = 15; // third stage is 15%
2109 break;
2110 case NETWORK_JOIN_STATUS_DOWNLOADING:
2111 if (_network_join_bytes_total == 0) {
2112 progress = 15; // We don't have the final size yet; the server is still compressing!
2113 break;
2114 }
2115 [[fallthrough]];
2116
2117 default: // Waiting is 15%, so the resting receivement of map is maximum 70%
2118 progress = 15 + _network_join_bytes * (100 - 15) / _network_join_bytes_total;
2119 break;
2120 }
2121 DrawFrameRect(ir.WithWidth(ir.Width() * progress / 100, _current_text_dir == TD_RTL), COLOUR_MAUVE, FR_NONE);
2123 break;
2124 }
2125
2127 switch (_network_join_status) {
2128 case NETWORK_JOIN_STATUS_WAITING:
2131 break;
2132 case NETWORK_JOIN_STATUS_DOWNLOADING:
2136 break;
2137 default:
2138 break;
2139 }
2140 break;
2141 }
2142 }
2143
2145 {
2146 switch (widget) {
2148 /* Account for the statuses */
2149 for (uint i = 0; i < NETWORK_JOIN_STATUS_END; i++) {
2151 }
2152 /* For the number of waiting (other) players */
2155 /* We need some spacing for the 'border' */
2158 break;
2159
2161 /* Account for downloading ~ 10 MiB */
2162 SetDParamMaxDigits(0, 8);
2163 SetDParamMaxDigits(1, 8);
2166 break;
2167 }
2168 }
2169
2170 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2171 {
2172 if (widget == WID_NJS_CANCELOK) { // Disconnect button
2174 SwitchToMode(SM_MENU);
2175 ShowNetworkGameWindow();
2176 }
2177 }
2178
2179 void OnQueryTextFinished(std::optional<std::string> str) override
2180 {
2181 if (!str.has_value() || str->empty() || this->request == nullptr) {
2183 return;
2184 }
2185
2186 this->request->Reply(*str);
2187 }
2188};
2189
2190static constexpr NWidgetPart _nested_network_join_status_window_widgets[] = {
2191 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_CONNECTING_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2192 NWidget(WWT_PANEL, COLOUR_GREY),
2194 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NJS_PROGRESS_BAR), SetFill(1, 0),
2195 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NJS_PROGRESS_TEXT), SetFill(1, 0), SetMinimalSize(350, 0),
2196 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NJS_CANCELOK), SetMinimalSize(101, 12), SetDataTip(STR_NETWORK_CONNECTION_DISCONNECT, STR_NULL), SetFill(1, 0),
2197 EndContainer(),
2198 EndContainer(),
2199};
2200
2201static WindowDesc _network_join_status_window_desc(
2202 WDP_CENTER, nullptr, 0, 0,
2204 WDF_MODAL,
2205 _nested_network_join_status_window_widgets
2206);
2207
2208void ShowJoinStatusWindow()
2209{
2211 new NetworkJoinStatusWindow(_network_join_status_window_desc);
2212}
2213
2214void ShowNetworkNeedPassword(std::shared_ptr<NetworkAuthenticationPasswordRequest> request)
2215{
2217 if (w == nullptr) return;
2218 w->request = request;
2219
2220 ShowQueryString(STR_EMPTY, STR_NETWORK_NEED_GAME_PASSWORD_CAPTION, NETWORK_PASSWORD_LENGTH, w, CS_ALPHANUMERAL, QSF_NONE);
2221}
2222
2229 std::string token;
2230
2231 NetworkAskRelayWindow(WindowDesc &desc, Window *parent, const std::string &server_connection_string, const std::string &relay_connection_string, const std::string &token) :
2232 Window(desc),
2235 token(token)
2236 {
2237 this->parent = parent;
2238 this->InitNested(0);
2239 }
2240
2241 void Close(int data = 0) override
2242 {
2243 if (data == NRWCD_UNHANDLED) _network_coordinator_client.ConnectFailure(this->token, 0);
2244 this->Window::Close();
2245 }
2246
2248 {
2249 if (widget == WID_NAR_TEXT) {
2251 }
2252 }
2253
2254 void DrawWidget(const Rect &r, WidgetID widget) const override
2255 {
2256 if (widget == WID_NAR_TEXT) {
2258 }
2259 }
2260
2262 {
2263 /* Position query window over the calling window, ensuring it's within screen bounds. */
2264 this->left = Clamp(parent->left + (parent->width / 2) - (this->width / 2), 0, _screen.width - this->width);
2265 this->top = Clamp(parent->top + (parent->height / 2) - (this->height / 2), 0, _screen.height - this->height);
2266 this->SetDirty();
2267 }
2268
2269 void SetStringParameters(WidgetID widget) const override
2270 {
2271 switch (widget) {
2272 case WID_NAR_TEXT:
2273 SetDParamStr(0, this->server_connection_string);
2274 SetDParamStr(1, this->relay_connection_string);
2275 break;
2276 }
2277 }
2278
2279 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2280 {
2281 switch (widget) {
2282 case WID_NAR_NO:
2284 this->Close(NRWCD_HANDLED);
2285 break;
2286
2287 case WID_NAR_YES_ONCE:
2288 _network_coordinator_client.StartTurnConnection(this->token);
2289 this->Close(NRWCD_HANDLED);
2290 break;
2291
2292 case WID_NAR_YES_ALWAYS:
2294 _network_coordinator_client.StartTurnConnection(this->token);
2295 this->Close(NRWCD_HANDLED);
2296 break;
2297 }
2298 }
2299};
2300
2301static constexpr NWidgetPart _nested_network_ask_relay_widgets[] = {
2303 NWidget(WWT_CLOSEBOX, COLOUR_RED),
2304 NWidget(WWT_CAPTION, COLOUR_RED, WID_NAR_CAPTION), SetDataTip(STR_NETWORK_ASK_RELAY_CAPTION, STR_NULL),
2305 EndContainer(),
2306 NWidget(WWT_PANEL, COLOUR_RED),
2310 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NAR_NO), SetMinimalSize(71, 12), SetFill(1, 1), SetDataTip(STR_NETWORK_ASK_RELAY_NO, STR_NULL),
2311 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NAR_YES_ONCE), SetMinimalSize(71, 12), SetFill(1, 1), SetDataTip(STR_NETWORK_ASK_RELAY_YES_ONCE, STR_NULL),
2312 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NAR_YES_ALWAYS), SetMinimalSize(71, 12), SetFill(1, 1), SetDataTip(STR_NETWORK_ASK_RELAY_YES_ALWAYS, STR_NULL),
2313 EndContainer(),
2314 EndContainer(),
2315 EndContainer(),
2316};
2317
2318static WindowDesc _network_ask_relay_desc(
2319 WDP_CENTER, nullptr, 0, 0,
2321 WDF_MODAL,
2322 _nested_network_ask_relay_widgets
2323);
2324
2331void ShowNetworkAskRelay(const std::string &server_connection_string, const std::string &relay_connection_string, const std::string &token)
2332{
2334
2335 Window *parent = GetMainWindow();
2336 new NetworkAskRelayWindow(_network_ask_relay_desc, parent, server_connection_string, relay_connection_string, token);
2337}
2338
2344 Window(desc)
2345 {
2346 this->parent = parent;
2347 this->InitNested(0);
2348 }
2349
2351 {
2352 if (widget == WID_NAS_TEXT) {
2354 }
2355 }
2356
2357 void DrawWidget(const Rect &r, WidgetID widget) const override
2358 {
2359 if (widget == WID_NAS_TEXT) {
2361 }
2362 }
2363
2365 {
2366 /* Position query window over the calling window, ensuring it's within screen bounds. */
2367 this->left = Clamp(parent->left + (parent->width / 2) - (this->width / 2), 0, _screen.width - this->width);
2368 this->top = Clamp(parent->top + (parent->height / 2) - (this->height / 2), 0, _screen.height - this->height);
2369 this->SetDirty();
2370 }
2371
2372 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2373 {
2374 switch (widget) {
2375 case WID_NAS_PREVIEW:
2376 ShowSurveyResultTextfileWindow();
2377 break;
2378
2379 case WID_NAS_LINK:
2380 OpenBrowser(NETWORK_SURVEY_DETAILS_LINK);
2381 break;
2382
2383 case WID_NAS_NO:
2385 this->Close();
2386 break;
2387
2388 case WID_NAS_YES:
2390 this->Close();
2391 break;
2392 }
2393 }
2394};
2395
2396static constexpr NWidgetPart _nested_network_ask_survey_widgets[] = {
2398 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
2399 NWidget(WWT_CAPTION, COLOUR_GREY, WID_NAS_CAPTION), SetDataTip(STR_NETWORK_ASK_SURVEY_CAPTION, STR_NULL),
2400 EndContainer(),
2401 NWidget(WWT_PANEL, COLOUR_GREY),
2405 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NAS_PREVIEW), SetMinimalSize(71, 12), SetFill(1, 1), SetDataTip(STR_NETWORK_ASK_SURVEY_PREVIEW, STR_NULL),
2406 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NAS_LINK), SetMinimalSize(71, 12), SetFill(1, 1), SetDataTip(STR_NETWORK_ASK_SURVEY_LINK, STR_NULL),
2407 EndContainer(),
2409 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NAS_NO), SetMinimalSize(71, 12), SetFill(1, 1), SetDataTip(STR_NETWORK_ASK_SURVEY_NO, STR_NULL),
2410 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NAS_YES), SetMinimalSize(71, 12), SetFill(1, 1), SetDataTip(STR_NETWORK_ASK_SURVEY_YES, STR_NULL),
2411 EndContainer(),
2412 EndContainer(),
2413 EndContainer(),
2414};
2415
2416static WindowDesc _network_ask_survey_desc(
2417 WDP_CENTER, nullptr, 0, 0,
2419 WDF_MODAL,
2420 _nested_network_ask_survey_widgets
2421);
2422
2427{
2428 /* If we can't send a survey, don't ask the question. */
2429 if constexpr (!NetworkSurveyHandler::IsSurveyPossible()) return;
2430
2432
2433 Window *parent = GetMainWindow();
2434 new NetworkAskSurveyWindow(_network_ask_survey_desc, parent);
2435}
2436
2440
2442 {
2443 this->ConstructWindow();
2444
2445 auto result = _survey.CreatePayload(NetworkSurveyHandler::Reason::PREVIEW, true);
2446 this->LoadText(result);
2447 this->InvalidateData();
2448 }
2449};
2450
2451void ShowSurveyResultTextfileWindow()
2452{
2455}
Button shown for either a company or client in the client-list.
Colours colour
The colour of the button.
bool disabled
Is the button disabled?
uint width
Calculated width of the button.
virtual void OnClick(struct NetworkClientListWindow *w, Point pt)=0
OnClick handler for when the button is pressed.
SpriteID sprite
The sprite to use on the button.
uint height
Calculated height of the button.
StringID tooltip
The tooltip of the button.
Template version of Button, with callback support.
T id
ID this button belongs to.
void OnClick(struct NetworkClientListWindow *w, Point pt) override
OnClick handler for when the button is pressed.
ButtonCallback proc
Callback proc to call when button is pressed.
void(* ButtonCallback)(struct NetworkClientListWindow *w, Point pt, T id)
Callback function to call on click.
void ConnectFailure(const std::string &token, uint8_t tracking_number)
Callback from a Connecter to let the Game Coordinator know the connection failed.
void GetListing()
Request a listing of all public servers.
List template of 'things' T to sort in a GUI.
bool Filter(FilterFunction *decide, F filter_data)
Filter the list.
void RebuildDone()
Notify the sortlist that the rebuild is done.
void SetListing(Listing l)
Import sort conditions.
void SetFilterState(bool state)
Enable or disable the filter.
bool IsDescSortOrder() const
Check if the sort order is descending.
void ToggleSortOrder()
Toggle the sort order Since that is the worst condition for the sort function reverse the list here.
void SetFilterFuncs(std::span< FilterFunction *const > n_funcs)
Hand the filter function pointers to the GUIList.
bool NeedRebuild() const
Check if a rebuild is needed.
void ForceRebuild()
Force that a rebuild is needed.
bool Sort(Comp compare)
Sort the list.
void ForceResort()
Force a resort next Sort call Reset the resort timer if used too.
uint8_t SortType() const
Get the sorttype of the list.
Listing GetListing() const
Export current sort conditions.
void SetSortFuncs(std::span< SortFunction *const > n_funcs)
Hand the sort function pointers to the GUIList.
bool NeedResort()
Check if a resort is needed next loop If used the resort timer will decrease every call till 0.
void SetSortType(uint8_t n_type)
Set the sorttype of the list.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
Baseclass for nested widgets.
uint resize_x
Horizontal resize step (0 means not resizable).
uint fill_x
Horizontal fill stepsize (from initial size, 0 means not resizable).
uint smallest_x
Smallest horizontal size of the widget in a filled window.
uint current_x
Current horizontal size (after resizing).
int pos_y
Vertical position of top-left corner of the widget in the window.
int pos_x
Horizontal position of top-left corner of the widget in the window.
uint smallest_y
Smallest vertical size of the widget in a filled window.
uint fill_y
Vertical fill stepsize (from initial size, 0 means not resizable).
uint resize_y
Vertical resize step (0 means not resizable).
uint current_y
Current vertical size (after resizing).
Baseclass for container widgets.
void Add(std::unique_ptr< NWidgetBase > &&wid)
Append widget wid to container.
Definition widget.cpp:1198
std::vector< std::unique_ptr< NWidgetBase > > children
Child widgets in contaier.
Full blown container to make it behave exactly as we want :)
static const uint MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER
Minimum width before adding a new header.
void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override
Assign size and position to the widget.
void SetupSmallestSize(Window *w) override
Compute smallest size needed by the widget.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
void OnPaint() override
The window must be repainted.
static bool NGameClientSorter(NetworkGameList *const &a, NetworkGameList *const &b)
Sort servers by the amount of clients online on a server.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
static bool NGameMapSizeSorter(NetworkGameList *const &a, NetworkGameList *const &b)
Sort servers by map size.
QueryString filter_editbox
Editbox for filter on servers.
Scrollbar * vscroll
Vertical scrollbar of the list of servers.
NetworkGameList * last_joined
The last joined server.
static bool NGameAllowedSorter(NetworkGameList *const &a, NetworkGameList *const &b)
Sort servers by joinability.
NetworkGameList * server
Selected server.
void BuildGUINetworkGameList()
Dimension of compatibility icon.
void UpdateListPos()
Set this->list_pos to match this->server.
IntervalTimer< TimerWindow > refresh_interval
Refresh the online servers on a regular interval.
void OnInit() override
Notification that the nested widget tree gets initialized.
static bool NGameNameSorter(NetworkGameList *const &a, NetworkGameList *const &b)
Sort servers by name.
void DrawServerLine(const NetworkGameList *cur_item, int y, bool highlight) const
Draw a single server line.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
static bool NGameCalendarDateSorter(NetworkGameList *const &a, NetworkGameList *const &b)
Sort servers by calendar date.
void OnResize() override
Called after the window got resized.
void ScrollToSelectedServer()
Scroll the list up or down to the currently selected server.
void OnEditboxChanged(WidgetID wid) override
The text in an editbox has been edited.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
ServerListPosition list_pos
Position of the selected server.
static bool NGameTicksPlayingSorter(NetworkGameList *const &a, NetworkGameList *const &b)
Sort servers by the number of ticks the game is running.
void SortNetworkGameList()
Sort the server list.
Dimension blot
Dimension of lock icon.
GUIGameServerList servers
List with game servers.
bool searched_internet
Did we ever press "Search Internet" button?
QueryString name_editbox
Client name editbox.
EventState OnKeyPress(char32_t key, uint16_t keycode) override
A key has been pressed.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
@ PREVIEW
User is previewing the survey result.
Scrollbar data structure.
size_type GetCapacity() const
Gets the number of visible elements of the scrollbar.
void SetCount(size_t num)
Sets the number of elements in the list.
auto GetScrolledItemFromWidget(Tcontainer &container, int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Return an iterator pointing to the element of a scrolled widget that a user clicked in.
size_type GetScrolledRowFromWidget(int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Compute the row of a scrolled widget that a user clicked in.
Definition widget.cpp:2377
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:2451
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:2398
void ScrollTowards(size_type position)
Scroll towards the given position; if the item is visible nothing happens, otherwise it will be shown...
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
size_type GetPosition() const
Gets the position of the first visible element in the list.
static constexpr TimerGameTick::Ticks TICKS_PER_SECOND
Estimation of how many ticks fit in a single second.
static YearMonthDay ConvertDateToYMD(Date date)
Converts a Date to a Year, Month & Day.
RectPadding framerect
Standard padding inside many panels.
Definition window_gui.h:42
RectPadding frametext
Padding inside frame with text.
Definition window_gui.h:43
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:28
int vsep_wide
Wide vertical spacing.
Definition window_gui.h:62
int hsep_wide
Wide horizontal spacing.
Definition window_gui.h:64
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:96
RectPadding matrix
Padding of WWT_MATRIX items.
Definition window_gui.h:44
int hsep_normal
Normal horizontal spacing.
Definition window_gui.h:63
RectPadding bevel
Bevel thickness, affected by "scaled bevels" game option.
Definition window_gui.h:40
int hsep_indent
Width of identation for tree layouts.
Definition window_gui.h:65
CompanyID _current_company
Company currently doing an action.
@ CCA_DELETE
Delete a company.
@ CCA_NEW
Create a new company.
@ CALCA_ADD
Create a public key.
Owner
Enum for all companies/owners.
@ INVALID_COMPANY
An invalid company.
@ COMPANY_SPECTATOR
The client is spectating.
@ COMPANY_NEW_COMPANY
The client wants a new company.
@ MAX_COMPANIES
Maximum number of companies.
@ CRR_NONE
Dummy reason for actions that don't need one.
@ CRR_MANUAL
The company is manually removed.
static const uint NETWORK_CLIENT_NAME_LENGTH
The maximum length of a client's name, in bytes including '\0'.
Definition config.h:58
static const uint NETWORK_HOSTNAME_PORT_LENGTH
The maximum length of the host name + port, in bytes including '\0'. The extra six is ":" + port numb...
Definition config.h:55
static const uint NETWORK_NAME_LENGTH
The maximum length of the server name and map name, in bytes including '\0'.
Definition config.h:53
static const std::string NETWORK_SURVEY_DETAILS_LINK
Link with more details & privacy statement of the survey.
Definition config.h:30
static const uint NETWORK_PASSWORD_LENGTH
The maximum length of the password, in bytes including '\0'.
Definition config.h:57
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, bool instant_close, bool persist)
Show a drop down list.
Definition dropdown.cpp:404
void ShowDropDownListAt(Window *w, DropDownList &&list, int selected, WidgetID button, Rect wi_rect, Colours wi_colour, bool instant_close, bool persist)
Show a drop down list.
Definition dropdown.cpp:386
std::vector< std::unique_ptr< const DropDownListItem > > DropDownList
A drop down list is a collection of drop down list items.
@ FT_SCENARIO
old or new scenario
Definition fileio_type.h:19
@ FT_HEIGHTMAP
heightmap file
Definition fileio_type.h:20
@ FT_SAVEGAME
old or new savegame
Definition fileio_type.h:18
@ SLO_LOAD
File is being loaded.
Definition fileio_type.h:55
void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fop)
Launch save/load dialog in the given mode.
Definition fios_gui.cpp:986
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:77
static const uint32_t GENERATE_NEW_SEED
Create a new random seed.
Definition genworld.h:24
void StartNewGameWithoutGUI(uint32_t seed)
Start a normal game without the GUI.
void ShowGenerateLandscape()
Start with a normal game.
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
int GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition gfx.cpp:704
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition gfx.cpp:922
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:851
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:657
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:38
bool _left_button_clicked
Is left mouse button clicked?
Definition gfx.cpp:42
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
Definition gfx.cpp:114
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition gfx.cpp:988
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:774
Dimension GetScaledSpriteSize(SpriteID sprid)
Scale sprite size for GUI.
Definition widget.cpp:54
int CenterBounds(int min, int max, int size)
Determine where to draw a centred object inside a widget.
Definition gfx_func.h:166
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:18
@ SA_RIGHT
Right align the text (must be a single bit).
Definition gfx_type.h:345
@ SA_HOR_CENTER
Horizontally center the text.
Definition gfx_type.h:344
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:353
@ SA_VERT_CENTER
Vertically center the text.
Definition gfx_type.h:349
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:209
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:19
@ FILLRECT_CHECKER
Draw only every second pixel, used for greying-out.
Definition gfx_type.h:299
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 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 SetDataTip(uint32_t data, StringID tip)
Widget part function for setting the data and tooltip.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetMatrixDataTip(uint8_t cols, uint8_t rows, StringID tip)
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart SetMinimalTextLines(uint8_t lines, uint8_t spacing, FontSize size=FS_NORMAL)
Widget part function for setting the minimal text lines.
constexpr NWidgetPart SetAlignment(StringAlignment align)
Widget part function for setting the alignment of text/images.
constexpr NWidgetPart SetAspect(float ratio, AspectFlags flags=AspectFlags::ResizeX)
Widget part function for setting the aspect ratio.
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:940
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1529
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
constexpr bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
void GuiShowTooltips(Window *parent, StringID str, TooltipCloseCondition close_tooltip, uint paramcount)
Shows a tooltip.
Definition misc_gui.cpp:740
void ShowQuery(StringID caption, StringID 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(StringID 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:69
StringList _network_host_list
The servers we know.
Definition network.cpp:74
void NetworkQueryServer(const std::string &connection_string)
Query a server to fetch the game-info.
Definition network.cpp:670
NetworkGameList * NetworkAddServer(const std::string &connection_string, bool manually, bool never_expire)
Validates an address entered as a string and adds the server to the list.
Definition network.cpp:692
void NetworkDisconnect(bool close_admins)
We want to disconnect from the host/clients.
Definition network.cpp:999
bool _network_server
network-server is active
Definition network.cpp:66
ClientID _network_own_client_id
Our client identifier.
Definition network.cpp:70
bool NetworkClientConnectGame(const std::string &connection_string, CompanyID default_company, const std::string &join_server_password)
Join a client to the server at with the given connection string.
Definition network.cpp:785
void NetworkUpdateServerGameType()
The setting server_game_type was updated; possibly we need to take some action.
Definition network.cpp:1027
bool NetworkValidateServerName(std::string &server_name)
Trim the given server name in place, i.e.
Definition network.cpp:858
Basic functions/variables used all over the place.
Base core network types and some helper functions to access them.
void ShowNetworkChatQueryWindow(DestType type, int dest)
Show the chat window.
bool NetworkValidateOurClientName()
Convenience method for NetworkValidateClientName on _settings_client.network.client_name.
bool NetworkMaxCompaniesReached()
Check if max_companies has been reached on the server (local check only).
uint NetworkMaxCompaniesAllowed()
Get the maximum number of companies that are allowed by the server.
std::string _network_server_name
The current name of the server you are on.
void NetworkClientRequestMove(CompanyID company_id)
Notify the server of this client wanting to be moved to another company.
Client part of the network protocol.
Part of the network protocol handling content distribution.
ConnectionType _network_server_connection_type
What type of connection the Game Coordinator detected we are on.
ClientNetworkCoordinatorSocketHandler _network_coordinator_client
The connection to the Game Coordinator.
std::string _network_server_invite_code
Our invite code as indicated by the Game Coordinator.
Part of the network protocol handling Game Coordinator requests.
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, const std::string &reason)
Ban, or kick, everyone joined from the given client's IP.
void NetworkServerKickClient(ClientID client_id, const std::string &reason)
Kick a single client.
void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
Handle the tid-bits of moving a client from one company to another.
bool NetworkCompanyHasClients(CompanyID company)
Check whether a particular company has clients.
void NetworkGameListRemoveItem(NetworkGameList *remove)
Remove an item from the gamelist linked list.
NetworkGameList * _network_game_list
Game list of this client.
Handling of the list of games.
@ NGLS_ONLINE
Server is online.
@ NGLS_FULL
Server is full and cannot be queried.
@ NGLS_TOO_OLD
Server is too old to query.
@ NGLS_OFFLINE
Server is offline (or cannot be queried).
@ NGLS_BANNED
You are banned from this server.
void ShowNetworkAskRelay(const std::string &server_connection_string, const std::string &relay_connection_string, const std::string &token)
Show a modal confirmation window with "no" / "yes, once" / "yes, always" buttons.
static void AdminCompanyResetCallback(Window *, bool confirmed)
Callback function for admin command to reset company.
NetworkJoinStatus _network_join_status
The status of joining.
static void AdminClientKickCallback(Window *, bool confirmed)
Callback function for admin command to kick client.
void UpdateNetworkGameWindow()
Update the network new window because a new server is found on the network.
uint8_t _network_join_waiting
The number of clients waiting in front of us.
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.
DropDownAdmin
The possibly entries in a DropDown for an admin.
uint32_t _network_join_bytes_total
The total number of bytes to download.
uint32_t _network_join_bytes
The number of bytes we already downloaded.
void ShowNetworkAskSurvey()
Show a modal confirmation window with "no" / "preview" / "yes" buttons.
static CompanyID _admin_company_id
For what company a confirmation window is open.
static ClientID _admin_client_id
For what client a confirmation window is open.
GUIs related to networking.
@ NRWCD_UNHANDLED
Relay request is unhandled.
Definition network_gui.h:42
@ NRWCD_HANDLED
Relay request is handled, either by user or by timeout.
Definition network_gui.h:43
NetworkJoinStatus
Status of the clients during joining.
Server part of the network protocol.
Part of the network protocol handling opt-in survey.
@ DESTTYPE_CLIENT
Send message/notice to only a certain client (Private)
@ DESTTYPE_TEAM
Send message/notice to everyone playing the same company (Team)
static const uint MAX_CLIENTS
How many clients can we have.
ClientID
'Unique' identifier to be given to clients
@ INVALID_CLIENT_ID
Client is not part of anything.
@ CLIENT_ID_SERVER
Servers always have this ID.
ServerGameType
Game type the server can be using.
void NetworkUDPSearchGame()
Find all servers.
Sending and receiving UDP messages.
@ WID_NJS_PROGRESS_BAR
Simple progress bar.
@ WID_NJS_PROGRESS_TEXT
Text explaining what is happening.
@ WID_NJS_CANCELOK
Cancel / OK button.
@ WID_NG_CLIENT
Panel with editbox to set client name.
@ WID_NG_CLIENTS
'Clients' button.
@ WID_NG_SCROLLBAR
Scrollbar of matrix.
@ WID_NG_YEARS
'Years' button.
@ WID_NG_FILTER_LABEL
Label in front of the filter/search edit box.
@ WID_NG_NEWGRF_MISSING_SEL
Selection widget for the above button.
@ WID_NG_SEARCH_INTERNET
'Search internet server' button.
@ WID_NG_NEWGRF_MISSING
'Find missing NewGRF online' button.
@ WID_NG_LASTJOINED_SPACER
Spacer after last joined server panel.
@ WID_NG_DATE
'Date' button.
@ WID_NG_LASTJOINED
Info about the last joined server.
@ WID_NG_MATRIX
Panel with list of games.
@ WID_NG_CLIENT_LABEL
Label in front of client name edit box.
@ WID_NG_NEWGRF_SEL
Selection 'widget' to hide the NewGRF settings.
@ WID_NG_JOIN
'Join game' button.
@ WID_NG_SEARCH_LAN
'Search LAN server' button.
@ WID_NG_MAPSIZE
'Map size' button.
@ WID_NG_START
'Start server' button.
@ WID_NG_DETAILS
Panel with game details.
@ WID_NG_INFO
Third button in the game list panel.
@ WID_NG_NAME
'Name' button.
@ WID_NG_CANCEL
'Cancel' button.
@ WID_NG_ADD
'Add server' button.
@ WID_NG_MAIN
Main panel.
@ WID_NG_REFRESH
'Refresh server' button.
@ WID_NG_FILTER
Panel with the edit box to enter the search text.
@ WID_NG_LASTJOINED_LABEL
Label "Last joined server:".
@ WID_NG_NEWGRF
'NewGRF Settings' button.
ClientListWidgets
Widgets of the NetworkClientListWindow class.
@ WID_CL_CLIENT_NAME_EDIT
Edit button for client name.
@ WID_CL_SERVER_NAME
Server name.
@ WID_CL_SERVER_INVITE_CODE
Invite code for this server.
@ WID_CL_SERVER_NAME_EDIT
Edit button for server name.
@ WID_CL_CLIENT_NAME
Client name.
@ WID_CL_SERVER_SELECTOR
Selector to hide the server frame.
@ WID_CL_SCROLLBAR
Scrollbar for company/client list.
@ WID_CL_CLIENT_COMPANY_COUNT
Count of clients and companies.
@ WID_CL_SERVER_CONNECTION_TYPE
The type of connection the Game Coordinator detected for this server.
@ WID_CL_SERVER_VISIBILITY
Server visibility.
@ WID_CL_MATRIX
Company/client list.
@ WID_NSS_COMPANIES_BTNU
'Max companies' uparrow.
@ WID_NSS_COMPANIES_LABEL
Label for 'max companies'.
@ WID_NSS_CLIENTS_LABEL
Label for 'max clients'.
@ WID_NSS_CLIENTS_TXT
'Max clients' text.
@ WID_NSS_CLIENTS_BTND
'Max clients' downarrow.
@ WID_NSS_GAMENAME
Background for editbox to set game name.
@ WID_NSS_CANCEL
'Cancel' button.
@ WID_NSS_PLAY_HEIGHTMAP
Play heightmap button.
@ WID_NSS_GAMENAME_LABEL
Label for the game name.
@ WID_NSS_LOAD_GAME
Load game button.
@ WID_NSS_GENERATE_GAME
New game button.
@ WID_NSS_CONNTYPE_LABEL
Label for 'connection type'.
@ WID_NSS_CONNTYPE_BTN
'Connection type' droplist button.
@ WID_NSS_COMPANIES_BTND
'Max companies' downarrow.
@ WID_NSS_SETPWD
'Set password' button.
@ WID_NSS_CLIENTS_BTNU
'Max clients' uparrow.
@ WID_NSS_COMPANIES_TXT
'Max companies' text.
@ WID_NSS_BACKGROUND
Background of the window.
@ WID_NSS_PLAY_SCENARIO
Play scenario button.
@ WID_NAR_YES_ALWAYS
"Yes, always" button.
@ WID_NAR_TEXT
Text in the window.
@ WID_NAR_YES_ONCE
"Yes, once" button.
@ WID_NAR_NO
"No" button.
@ WID_NAR_CAPTION
Caption of the window.
@ WID_NAS_YES
"Yes" button.
@ WID_NAS_LINK
"Details & Privacy" button.
@ WID_NAS_TEXT
Text in the window.
@ WID_NAS_CAPTION
Caption of the window.
@ WID_NAS_NO
"No" button.
@ WID_NAS_PREVIEW
"Preview" button.
void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config)
Setup the NewGRF gui.
@ SM_MENU
Switch to game intro menu.
Definition openttd.h:33
uint8_t GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
Definition palette.cpp:314
static const uint8_t PC_GREY
Grey palette colour.
static const uint8_t PC_DARK_BLUE
Dark blue palette colour.
#define GREY_SCALE(level)
Return the colour for a particular greyscale level.
bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame)
Top function to save the new value of an element of the Settings struct.
static const SettingDesc * GetSettingFromName(const std::string_view name, const SettingTable &settings)
Given a name of setting, return a setting description from the table.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:56
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:589
@ 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
void SetDParamMaxValue(size_t n, uint64_t max_value, uint min_count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition strings.cpp:127
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition strings.cpp:104
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:56
void SetDParamStr(size_t n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition strings.cpp:371
void SetDParamMaxDigits(size_t n, uint count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition strings.cpp:143
@ TD_RTL
Text is written right-to-left by default.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
NetworkSettings network
settings related to the network
Dimensions (a width and height) of a rectangle in 2D.
Information about GRF, used in the game and (part of it) in savegames.
Data structure describing how to show the list (what sort direction and criteria).
Partial widget specification to allow NWidgets to be written nested.
Window used for asking the user if he is okay using a relay server.
void FindWindowPlacementAndResize(int def_width, int def_height) override
Resize window towards the default size.
void SetStringParameters(WidgetID widget) const override
Initialize string parameters for a widget.
std::string relay_connection_string
The relay server we want to connect to.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
std::string token
The token for this connection.
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
std::string server_connection_string
The game server we want to connect to.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
Window used for asking if the user wants to participate in the automated survey.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
void FindWindowPlacementAndResize(int def_width, int def_height) override
Resize window towards the default size.
Container for all information known about a client.
static NetworkClientInfo * GetByClientID(ClientID client_id)
Return the CI given it's client-identifier.
Definition network.cpp:116
Main handle for clientlist.
Scrollbar * vscroll
Vertical scrollbar of this window.
void OnResize() override
Called after the window got resized.
uint line_count
Amount of lines in the matrix.
std::map< uint, std::vector< std::unique_ptr< ButtonCommon > > > buttons
Per line which buttons are available.
void DrawButtons(int &x, uint y, const std::vector< std::unique_ptr< ButtonCommon > > &buttons) const
Draw the buttons for a single line in the matrix.
ClientListWidgets query_widget
During a query this tracks what widget caused the query.
void SetStringParameters(WidgetID widget) const override
Initialize string parameters for a widget.
void OnDropdownSelect(WidgetID widget, int index) override
A dropdown option associated to this window has been selected.
CompanyID dd_company_id
During admin dropdown, track which company this was for.
void OnMouseOver(Point pt, WidgetID widget) override
The mouse is currently moving over the window or has just moved outside of the window.
int hover_index
Index of the current line we are hovering over, or -1 if none.
bool OnTooltip(Point pt, WidgetID widget, TooltipCloseCondition close_cond) override
Event to display a custom tooltip.
static void OnClickCompanyNew(NetworkClientListWindow *w, Point pt, CompanyID)
Crete new company button is clicked.
void OnDropdownClose(Point pt, WidgetID widget, int index, bool instant_close) override
A dropdown window associated to this window has been closed.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
uint line_height
Current lineheight of each entry in the matrix.
void OnInit() override
Notification that the nested widget tree gets initialized.
static void OnClickCompanyAdmin(NetworkClientListWindow *w, Point pt, CompanyID company_id)
Admin button on a Company is clicked.
static void OnClickCompanyChat(NetworkClientListWindow *w, Point pt, CompanyID company_id)
Chat button on a Company is clicked.
ClientID dd_client_id
During admin dropdown, track which client this was for.
static void OnClickClientChat(NetworkClientListWindow *w, Point pt, ClientID client_id)
Chat button on a Client is clicked.
void RebuildListCompany(CompanyID company_id, CompanyID client_playas, bool can_join_company)
Part of RebuildList() to create the information for a single company.
int player_self_index
The line the current player is on.
void DrawCompany(CompanyID company_id, const Rect &r, uint &line) const
Draw a company and its clients on the matrix.
int player_host_index
The line the host is on.
static void OnClickClientAdmin(NetworkClientListWindow *w, Point pt, ClientID client_id)
Admin button on a Client is clicked.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
ButtonCommon * GetButtonAtPoint(Point pt)
Get the button at a specific point on the WID_CL_MATRIX.
static void OnClickCompanyJoin(NetworkClientListWindow *w, Point pt, CompanyID company_id)
Join button on a Company is clicked.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void RebuildList()
Rebuild the list, meaning: calculate the lines needed and what buttons go on which line.
bool version_compatible
Can we connect to this server or not? (based on server_revision)
bool compatible
Can we connect to this server or not? (based on server_revision and grf_match.
Structure with information shown in the game list (GUI)
std::string connection_string
Address of the server.
bool refreshing
Whether this server is being queried.
NetworkGameList * next
Next pointer to make a linked game list.
NetworkGameListStatus status
Stats of the server.
NetworkGameInfo info
The game information of this server.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
TimerGameCalendar::Date calendar_start
When the game started.
std::string server_revision
The version number the server is using (e.g.: 'r304' or 0.5.0)
bool use_password
Is this server passworded?
uint8_t clients_max
Max clients allowed on server.
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.
GRFConfig * grfconfig
List of NewGRF files used.
uint8_t landscape
The used landscape.
uint8_t companies_max
Max companies allowed on server.
std::string gamescript_name
Name of the gamescript.
TimerGameCalendar::Date calendar_date
Current calendar date.
int gamescript_version
Version of the gamescript.
uint8_t companies_on
How many started companies do we have.
uint8_t clients_on
Current count of clients on server.
uint8_t max_clients
maximum amount of clients
uint8_t max_companies
maximum amount of companies
std::string client_name
name of the player (as client)
ServerGameType server_game_type
Server type: local / public / invite-only.
UseRelayService use_relay_service
Use relay service?
std::string connect_to_ip
default for the "Add server" query
std::string last_joined
Last joined server.
std::string server_name
name of the server
std::string server_password
password for joining this server
ParticipateSurvey participate_survey
Participate in the automated survey.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
WidgetID widget_id
The widget that has the pop-up input menu.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnDropdownSelect(WidgetID widget, int index) override
A dropdown option associated to this window has been selected.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
void SetStringParameters(WidgetID widget) const override
Initialize string parameters for a widget.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
QueryString name_editbox
Server name editbox.
void OnTimeout() override
Called when this window's timeout has been reached.
Coordinates of a point in 2D.
static size_t GetNumItems()
Returns number of valid items in the pool.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * Get(size_t index)
Returns Titem with given 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.
constexpr uint Horizontal() const
Get total horizontal padding of RectPadding.
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Specification of a rectangle with absolute coordinates of all edges.
Rect WithWidth(int width, bool end) const
Copy Rect and set its width.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Rect WithHeight(int height, bool end=false) const
Copy Rect and set its height.
Rect Indent(int indent, bool end) const
Copy Rect and indent it from its position.
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
uint step_height
Step-size of height resize changes.
Definition window_gui.h:214
String filter and state.
bool IsEmpty() const
Check whether any filter words were entered.
void SetFilterTerm(const char *str)
Set the term to filter on.
void ResetState()
Reset the matching state to process a new item.
void AddLine(const char *str)
Pass another text line from the current item to the filter.
bool GetState() const
Get the matching state of the current item.
Window for displaying the textfile of a survey result.
const GRFConfig * grf_config
View the textfile of this GRFConfig.
void Assign(StringID string)
Render a string into the textbuffer.
Definition textbuf.cpp:431
char *const buf
buffer in which text is saved
Window for displaying a textfile.
void LoadText(std::string_view buf)
Load a text into the textfile viewer.
TextfileType file_type
Type of textfile to view.
High level window description.
Definition window_gui.h:159
Data structure for an opened window.
Definition window_gui.h:273
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition window.cpp:952
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1047
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition widget.cpp:781
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1733
std::map< WidgetID, QueryString * > querystrings
QueryString associated to WWT_EDITBOX widgets.
Definition window_gui.h:320
void DrawWidgets() const
Paint all widgets of a window.
Definition widget.cpp:732
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition window.cpp:3159
Window * parent
Parent window.
Definition window_gui.h:328
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:551
uint8_t timeout_timer
Timer value of the WF_TIMEOUT for flags.
Definition window_gui.h:306
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
Definition widget.cpp:764
ResizeInfo resize
Resize information.
Definition window_gui.h:314
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1723
bool SetFocusedWidget(WidgetID widget_index)
Set focus within this window to the given widget.
Definition window.cpp:486
virtual void OnDropdownClose(Point pt, WidgetID widget, int index, bool instant_close)
A dropdown window associated to this window has been closed.
Definition window.cpp:287
bool IsWidgetDisabled(WidgetID widget_index) const
Gets the enabled/disabled status of a widget.
Definition window_gui.h:416
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition window_gui.h:447
int left
x position of left edge of the window
Definition window_gui.h:309
void RaiseWidgetsWhenLowered(Args... widgets)
Raises the widgets and sets widgets dirty that are lowered.
Definition window_gui.h:542
int top
y position of top edge of the window
Definition window_gui.h:310
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:213
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:977
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:590
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1746
WindowFlags flags
Window flags.
Definition window_gui.h:300
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:314
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:387
int height
Height of the window (number of pixels down in y direction)
Definition window_gui.h:312
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:311
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:302
@ CONNECTION_TYPE_UNKNOWN
The Game Coordinator hasn't informed us yet what type of connection we have.
void QueryCallbackProc(Window *, bool)
Callback procedure for the ShowQuery method.
Definition textbuf_gui.h:28
@ QSF_ACCEPT_UNCHANGED
return success even when the text didn't change
Definition textbuf_gui.h:20
@ QSF_LEN_IN_CHARS
the length of the string is counted in characters
Definition textbuf_gui.h:22
TextfileType
Additional text files accompanying Tar archives.
@ TFT_SURVEY_RESULT
Survey result (preview)
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition widget.cpp:283
static RectPadding ScaleGUITrad(const RectPadding &r)
Scale a RectPadding to GUI zoom level.
Definition widget.cpp:35
@ 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).
@ NC_EQUALSIZE
Value of the NCB_EQUALSIZE flag.
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ WWT_IMGBTN
(Toggle) Button with image
Definition widget_type.h:52
@ WWT_PUSHIMGBTN
Normal push-button (no toggle button) with image caption.
@ NWID_SPACER
Invisible widget that takes some space.
Definition widget_type.h:79
@ WWT_EDITBOX
a textbox for typing
Definition widget_type.h:71
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:75
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:50
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition widget_type.h:66
@ WWT_MATRIX
Grid of rows and columns.
Definition widget_type.h:59
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:61
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:85
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:77
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:69
@ WWT_FRAME
Frame.
Definition widget_type.h:60
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:48
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:68
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:65
@ WWT_DROPDOWN
Drop down list.
Definition widget_type.h:70
@ WWT_TEXT
Pure simple text.
Definition widget_type.h:58
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition widget_type.h:80
SizingType
Different forms of sizing nested widgets, using NWidgetBase::AssignSizePosition()
@ RWV_HIDE_BEVEL
Bevel of resize box is hidden.
Definition widget_type.h:40
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:1140
Window * GetMainWindow()
Get the main window, i.e.
Definition window.cpp:1127
void CloseWindowByClass(WindowClass cls, int data)
Close all windows of a given class.
Definition window.cpp:1152
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:3219
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1098
@ SBS_DOWN
Sort ascending.
Definition window_gui.h:220
@ SBS_UP
Sort descending.
Definition window_gui.h:221
@ WF_TIMEOUT
Window timeout counter.
Definition window_gui.h:228
@ FR_BORDERONLY
Draw border only, no background.
Definition window_gui.h:27
@ FR_LOWERED
If set the frame is lowered and the background colour brighter (ie. buttons when pressed)
Definition window_gui.h:28
@ WDF_MODAL
The window is a modal child of some other window, meaning the parent is 'inactive'.
Definition window_gui.h:204
@ WDP_CENTER
Center the window.
Definition window_gui.h:148
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:147
int WidgetID
Widget ID.
Definition window_type.h:18
@ WN_NETWORK_STATUS_WINDOW_JOIN
Network join status.
Definition window_type.h:39
@ WN_NETWORK_WINDOW_GAME
Network game window.
Definition window_type.h:35
@ WN_NETWORK_WINDOW_START
Network start server.
Definition window_type.h:37
int32_t WindowNumber
Number to differentiate different windows of the same class.
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:45
@ 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: