OpenTTD Source 20250312-master-gcdcc6b491d
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
60static CompanyID _admin_company_id = CompanyID::Invalid();
61
70
71static DropDownList BuildVisibilityDropDownList()
72{
73 DropDownList list;
74
75 list.push_back(MakeDropDownListStringItem(STR_NETWORK_SERVER_VISIBILITY_LOCAL, SERVER_GAME_TYPE_LOCAL));
76 list.push_back(MakeDropDownListStringItem(STR_NETWORK_SERVER_VISIBILITY_INVITE_ONLY, SERVER_GAME_TYPE_INVITE_ONLY));
77 list.push_back(MakeDropDownListStringItem(STR_NETWORK_SERVER_VISIBILITY_PUBLIC, SERVER_GAME_TYPE_PUBLIC));
78
79 return list;
80}
81
83typedef int ServerListPosition;
84static const ServerListPosition SLP_INVALID = -1;
85
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, WidgetData{.string = STR_NETWORK_SERVER_LIST_GAME_NAME}, STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP);
93 leaf->SetResize(1, 0);
94 leaf->SetFill(1, 0);
95 this->Add(std::move(leaf));
96
97 this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CLIENTS, WidgetData{.string = STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION}, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP));
98 this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_MAPSIZE, WidgetData{.string = STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION}, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP));
99 this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_DATE, WidgetData{.string = STR_NETWORK_SERVER_LIST_DATE_CAPTION}, STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP));
100 this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_YEARS, WidgetData{.string = STR_NETWORK_SERVER_LIST_PLAY_TIME_CAPTION}, STR_NETWORK_SERVER_LIST_PLAY_TIME_CAPTION_TOOLTIP));
101
102 leaf = std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_INFO, WidgetData{.string = STR_EMPTY}, STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP);
103 leaf->SetFill(0, 1);
104 this->Add(std::move(leaf));
105 }
106
107 void SetupSmallestSize(Window *w) override
108 {
109 this->smallest_y = 0; // Biggest child.
110 this->fill_x = 1;
111 this->fill_y = 0;
112 this->resize_x = 1; // We only resize in this direction
113 this->resize_y = 0; // We never resize in this direction
114
115 /* First initialise some variables... */
116 for (const auto &child_wid : this->children) {
117 child_wid->SetupSmallestSize(w);
118 this->smallest_y = std::max(this->smallest_y, child_wid->smallest_y + child_wid->padding.Vertical());
119 }
120
121 /* ... then in a second pass make sure the 'current' sizes are set. Won't change for most widgets. */
122 for (const auto &child_wid : this->children) {
123 child_wid->current_x = child_wid->smallest_x;
124 child_wid->current_y = this->smallest_y;
125 }
126
127 this->smallest_x = this->children.front()->smallest_x + this->children.back()->smallest_x; // First and last are always shown, rest not
128 this->ApplyAspectRatio();
129 }
130
131 void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override
132 {
133 assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
134
135 this->pos_x = x;
136 this->pos_y = y;
137 this->current_x = given_width;
138 this->current_y = given_height;
139
140 given_width -= this->children.back()->smallest_x;
141 /* The first and last widget are always visible, determine which other should be visible */
142 if (this->children.size() > 2) {
143 auto first = std::next(std::begin(this->children));
144 auto last = std::prev(std::end(this->children));
145 for (auto it = first; it != last; ++it) {
146 auto &child_wid = *it;
147 if (given_width > ScaleGUITrad(MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER) + child_wid->smallest_x && (*std::prev(it))->current_x != 0) {
148 given_width -= child_wid->smallest_x;
149 child_wid->current_x = child_wid->smallest_x; /* Make visible. */
150 } else {
151 child_wid->current_x = 0; /* Make invisible. */
152 }
153 }
154 }
155
156 /* All remaining space goes to the first (name) widget */
157 this->children.front()->current_x = given_width;
158
159 /* Now assign the widgets to their rightful place */
160 uint position = 0; // Place to put next child relative to origin of the container.
161 auto assign_position = [&](const std::unique_ptr<NWidgetBase> &child_wid) {
162 if (child_wid->current_x != 0) {
163 child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl);
164 position += child_wid->current_x;
165 }
166 };
167
168 if (rtl) {
169 std::for_each(std::rbegin(this->children), std::rend(this->children), assign_position);
170 } else {
171 std::for_each(std::begin(this->children), std::end(this->children), assign_position);
172 }
173 }
174};
175
176class NetworkGameWindow : public Window {
177protected:
178 /* Runtime saved values */
179 static Listing last_sorting;
180
181 /* Constants for sorting servers */
182 static const std::initializer_list<GUIGameServerList::SortFunction * const> sorter_funcs;
183 static const std::initializer_list<GUIGameServerList::FilterFunction * const> filter_funcs;
184
188 ServerListPosition list_pos = SLP_INVALID;
189 Scrollbar *vscroll = nullptr;
192 bool searched_internet = false;
193
194 Dimension lock{};
196
203 {
204 if (!this->servers.NeedRebuild()) return;
205
206 /* Create temporary array of games to use for listing */
207 this->servers.clear();
208
209 bool found_current_server = false;
210 bool found_last_joined = false;
211 for (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.GetText());
232
233 if (!sf.IsEmpty()) {
234 this->servers.SetFilterState(true);
235 this->servers.Filter(sf);
236 } else {
237 this->servers.SetFilterState(false);
238 }
239
240 this->servers.RebuildDone();
241 this->vscroll->SetCount(this->servers.size());
242
243 /* Sort the list of network games as requested. */
244 this->servers.Sort();
245 this->UpdateListPos();
246 }
247
249 static bool NGameNameSorter(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 auto it = std::ranges::find(this->servers, this->server);
329 if (it == std::end(this->servers)) {
330 this->list_pos = SLP_INVALID;
331 } else {
332 this->list_pos = static_cast<ServerListPosition>(std::distance(std::begin(this->servers), it));
333 }
334 }
335
336 static bool NGameSearchFilter(NetworkGameList * const *item, StringFilter &sf)
337 {
338 assert(item != nullptr);
339 assert((*item) != nullptr);
340
341 sf.ResetState();
342 sf.AddLine((*item)->info.server_name);
343 return sf.GetState();
344 }
345
352 void DrawServerLine(const NetworkGameList *cur_item, int y, bool highlight) const
353 {
354 Rect name = this->GetWidget<NWidgetBase>(WID_NG_NAME)->GetCurrentRect();
355 Rect info = this->GetWidget<NWidgetBase>(WID_NG_INFO)->GetCurrentRect();
356
357 /* show highlighted item with a different colour */
358 if (highlight) {
359 Rect r = {std::min(name.left, info.left), y, std::max(name.right, info.right), y + (int)this->resize.step_height - 1};
361 }
362
363 /* Offset to vertically position text. */
365
366 info = info.Shrink(WidgetDimensions::scaled.framerect);
367 name = name.Shrink(WidgetDimensions::scaled.framerect);
368 DrawString(name.left, name.right, y + text_y_offset, cur_item->info.server_name, TC_BLACK);
369
370 /* only draw details if the server is online */
371 if (cur_item->status == NGLS_ONLINE) {
373 Rect clients = nwid->GetCurrentRect();
374 DrawString(clients.left, clients.right, y + text_y_offset,
375 GetString(STR_NETWORK_SERVER_LIST_GENERAL_ONLINE, cur_item->info.clients_on, cur_item->info.clients_max, cur_item->info.companies_on, cur_item->info.companies_max),
376 TC_FROMSTRING, SA_HOR_CENTER);
377 }
378
380 /* map size */
381 Rect mapsize = nwid->GetCurrentRect();
382 DrawString(mapsize.left, mapsize.right, y + text_y_offset,
383 GetString(STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT, cur_item->info.map_width, cur_item->info.map_height),
384 TC_FROMSTRING, SA_HOR_CENTER);
385 }
386
388 /* current date */
389 Rect date = nwid->GetCurrentRect();
390 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(cur_item->info.calendar_date);
391 DrawString(date.left, date.right, y + text_y_offset,
393 TC_BLACK, SA_HOR_CENTER);
394 }
395
397 /* play time */
398 Rect years = nwid->GetCurrentRect();
399 const auto play_time = cur_item->info.ticks_playing / Ticks::TICKS_PER_SECOND;
400 DrawString(years.left, years.right, y + text_y_offset,
402 TC_BLACK, SA_HOR_CENTER);
403 }
404
405 /* Set top and bottom of info rect to current row. */
406 info.top = y;
407 info.bottom = y + this->resize.step_height - 1;
408
409 bool rtl = _current_text_dir == TD_RTL;
410
411 /* draw a lock if the server is password protected */
412 if (cur_item->info.use_password) DrawSpriteIgnorePadding(SPR_LOCK, PAL_NONE, info.WithWidth(this->lock.width, rtl), SA_CENTER);
413
414 /* draw red or green icon, depending on compatibility with server */
415 PaletteID pal = cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED);
416 DrawSpriteIgnorePadding(SPR_BLOT, pal, info.WithWidth(this->blot.width, !rtl), SA_CENTER);
417 }
418 }
419
428 {
429 if (this->list_pos == SLP_INVALID) return; // no server selected
430 this->vscroll->ScrollTowards(this->list_pos);
431 }
432
433public:
435 {
436 this->CreateNestedTree();
437 this->vscroll = this->GetScrollbar(WID_NG_SCROLLBAR);
439
441 this->name_editbox.text.Assign(_settings_client.network.client_name);
442
444 this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
446
447 /* As the Game Coordinator doesn't support "websocket" servers yet, we
448 * let "os/emscripten/pre.js" hardcode a list of servers people can
449 * join. This means the serverlist is curated for now, but it is the
450 * best we can offer. */
451#ifdef __EMSCRIPTEN__
452 EM_ASM(if (window["openttd_server_list"]) openttd_server_list());
453#endif
454
455 this->last_joined = NetworkAddServer(_settings_client.network.last_joined, false);
456 this->server = this->last_joined;
457
458 this->servers.SetListing(this->last_sorting);
459 this->servers.SetSortFuncs(NetworkGameWindow::sorter_funcs);
460 this->servers.SetFilterFuncs(NetworkGameWindow::filter_funcs);
461 this->servers.ForceRebuild();
462 }
463
465 {
466 this->last_sorting = this->servers.GetListing();
467 }
468
469 void OnInit() override
470 {
471 this->lock = GetScaledSpriteSize(SPR_LOCK);
472 this->blot = GetScaledSpriteSize(SPR_BLOT);
473 }
474
476 {
477 switch (widget) {
478 case WID_NG_MATRIX:
479 resize.height = std::max(GetSpriteSize(SPR_BLOT).height, (uint)GetCharacterHeight(FS_NORMAL)) + padding.height;
480 fill.height = resize.height;
481 size.height = 12 * resize.height;
482 break;
483
485 size.height = std::max(GetSpriteSize(SPR_BLOT).height, (uint)GetCharacterHeight(FS_NORMAL)) + WidgetDimensions::scaled.matrix.Vertical();
486 break;
487
489 size.width = NWidgetScrollbar::GetVerticalDimension().width;
490 break;
491
492 case WID_NG_NAME:
493 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
494 break;
495
496 case WID_NG_CLIENTS: {
497 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
498 auto max_clients = GetParamMaxValue(MAX_CLIENTS);
499 auto max_companies = GetParamMaxValue(MAX_COMPANIES);
500 size = maxdim(size, GetStringBoundingBox(GetString(STR_NETWORK_SERVER_LIST_GENERAL_ONLINE, max_clients, max_clients, max_companies, max_companies)));
501 break;
502 }
503
504 case WID_NG_MAPSIZE: {
505 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
508 break;
509 }
510
511 case WID_NG_DATE:
512 case WID_NG_YEARS:
513 size.width += 2 * Window::SortButtonWidth(); // Make space for the arrow
515 break;
516
517 case WID_NG_INFO:
518 size.width = this->lock.width + WidgetDimensions::scaled.hsep_normal + this->blot.width + padding.width;
519 size.height = std::max(this->lock.height, this->blot.height) + padding.height;
520 break;
521 }
522 }
523
524 void DrawWidget(const Rect &r, WidgetID widget) const override
525 {
526 switch (widget) {
527 case WID_NG_MATRIX: {
528 uint16_t y = r.top;
529
530 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->servers);
531 for (auto it = first; it != last; ++it) {
532 const NetworkGameList *ngl = *it;
533 this->DrawServerLine(ngl, y, ngl == this->server);
534 y += this->resize.step_height;
535 }
536 break;
537 }
538
540 /* Draw the last joined server, if any */
541 if (this->last_joined != nullptr) this->DrawServerLine(this->last_joined, r.top, this->last_joined == this->server);
542 break;
543
544 case WID_NG_DETAILS:
545 this->DrawDetails(r);
546 break;
547
548 case WID_NG_NAME:
549 case WID_NG_CLIENTS:
550 case WID_NG_MAPSIZE:
551 case WID_NG_DATE:
552 case WID_NG_YEARS:
553 case WID_NG_INFO:
554 if (widget - WID_NG_NAME == this->servers.SortType()) this->DrawSortButtonState(widget, this->servers.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
555 break;
556 }
557 }
558
559
560 void OnPaint() override
561 {
562 if (this->servers.NeedRebuild()) {
564 }
565 if (this->servers.NeedResort()) {
566 this->SortNetworkGameList();
567 }
568
569 NetworkGameList *sel = this->server;
570 /* 'Refresh' button invisible if no server selected */
571 this->SetWidgetDisabledState(WID_NG_REFRESH, sel == nullptr);
572 /* 'Join' button disabling conditions */
573 this->SetWidgetDisabledState(WID_NG_JOIN, sel == nullptr || // no Selected Server
574 sel->status != NGLS_ONLINE || // Server offline
575 sel->info.clients_on >= sel->info.clients_max || // Server full
576 !sel->info.compatible); // Revision mismatch
577
578 this->SetWidgetLoweredState(WID_NG_REFRESH, sel != nullptr && sel->refreshing);
579
580 /* 'NewGRF Settings' button invisible if no NewGRF is used */
581 bool changed = false;
582 changed |= this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == nullptr || sel->status != NGLS_ONLINE || sel->info.grfconfig.empty() ? SZSP_NONE : 0);
583 changed |= this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_MISSING_SEL)->SetDisplayedPlane(sel == nullptr || sel->status != NGLS_ONLINE || sel->info.grfconfig.empty() || !sel->info.version_compatible || sel->info.compatible ? SZSP_NONE : 0);
584 if (changed) {
585 this->ReInit();
586 return;
587 }
588
589#ifdef __EMSCRIPTEN__
594#endif
595
596 this->DrawWidgets();
597 }
598
599 StringID GetHeaderString() const
600 {
601 if (this->server == nullptr) return STR_NETWORK_SERVER_LIST_GAME_INFO;
602 switch (this->server->status) {
608 default: NOT_REACHED();
609 }
610 }
611
612 void DrawDetails(const Rect &r) const
613 {
614 NetworkGameList *sel = this->server;
615
616 Rect tr = r.Shrink(WidgetDimensions::scaled.frametext);
617 StringID header_msg = this->GetHeaderString();
618 int header_height = GetStringHeight(header_msg, tr.Width()) +
619 (sel == nullptr ? 0 : GetStringHeight(sel->info.server_name, tr.Width())) +
620 WidgetDimensions::scaled.frametext.Vertical();
621
622 /* Height for the title banner */
623 Rect hr = r.WithHeight(header_height).Shrink(WidgetDimensions::scaled.frametext);
624 tr.top += header_height;
625
626 /* Draw the right menu */
627 /* Create the nice grayish rectangle at the details top */
629 hr.top = DrawStringMultiLine(hr, header_msg, TC_FROMSTRING, SA_HOR_CENTER);
630 if (sel == nullptr) return;
631
632 hr.top = DrawStringMultiLine(hr, sel->info.server_name, TC_ORANGE, SA_HOR_CENTER); // game name
633 if (sel->status != NGLS_ONLINE) {
634 tr.top = DrawStringMultiLine(tr, header_msg, TC_FROMSTRING, SA_HOR_CENTER);
635 } else { // show game info
637
639
641
643
645 tr.top = DrawStringMultiLine(tr, GetString(invite_or_address, sel->connection_string)); // server address / invite code
646
648
650
652 tr.top = DrawStringMultiLine(tr, GetString(STR_NETWORK_SERVER_LIST_PLAY_TIME, play_time / 60 / 60, (play_time / 60) % 60)); // play time
653
654 if (sel->info.gamescript_version != -1) {
656 }
657
659
660 if (!sel->info.compatible) {
662 } else if (sel->info.clients_on == sel->info.clients_max) {
663 /* Show: server full, when clients_on == max_clients */
665 } else if (sel->info.use_password) {
666 DrawStringMultiLine(tr, STR_NETWORK_SERVER_LIST_PASSWORD, TC_FROMSTRING, SA_HOR_CENTER); // password warning
667 }
668 }
669 }
670
671 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
672 {
673 switch (widget) {
674 case WID_NG_CANCEL: // Cancel button
676 break;
677
678 case WID_NG_NAME: // Sort by name
679 case WID_NG_CLIENTS: // Sort by connected clients
680 case WID_NG_MAPSIZE: // Sort by map size
681 case WID_NG_DATE: // Sort by date
682 case WID_NG_YEARS: // Sort by years
683 case WID_NG_INFO: // Connectivity (green dot)
684 if (this->servers.SortType() == widget - WID_NG_NAME) {
685 this->servers.ToggleSortOrder();
686 if (this->list_pos != SLP_INVALID) this->list_pos = (ServerListPosition)this->servers.size() - this->list_pos - 1;
687 } else {
688 this->servers.SetSortType(widget - WID_NG_NAME);
689 this->servers.ForceResort();
690 this->SortNetworkGameList();
691 }
693 this->SetDirty();
694 break;
695
696 case WID_NG_MATRIX: { // Show available network games
697 auto it = this->vscroll->GetScrolledItemFromWidget(this->servers, pt.y, this, WID_NG_MATRIX);
698 this->server = (it != this->servers.end()) ? *it : nullptr;
699 this->list_pos = (server == nullptr) ? SLP_INVALID : it - this->servers.begin();
700 this->SetDirty();
701
702 /* FIXME the disabling should go into some InvalidateData, which is called instead of the SetDirty */
703 if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
704 break;
705 }
706
707 case WID_NG_LASTJOINED: {
708 if (this->last_joined != nullptr) {
709 this->server = this->last_joined;
710
711 /* search the position of the newly selected server */
712 this->UpdateListPos();
714 this->SetDirty();
715
716 /* FIXME the disabling should go into some InvalidateData, which is called instead of the SetDirty */
717 if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
718 }
719 break;
720 }
721
724 this->searched_internet = true;
725 break;
726
729 break;
730
731 case WID_NG_ADD: // Add a server
735 NETWORK_HOSTNAME_PORT_LENGTH, // maximum number of characters including '\0'
737 break;
738
739 case WID_NG_START: // Start server
740 ShowNetworkStartServerWindow();
741 break;
742
743 case WID_NG_JOIN: // Join Game
744 if (this->server != nullptr) {
746 }
747 break;
748
749 case WID_NG_REFRESH: // Refresh
750 if (this->server != nullptr && !this->server->refreshing) NetworkQueryServer(this->server->connection_string);
751 break;
752
753 case WID_NG_NEWGRF: // NewGRF Settings
754 if (this->server != nullptr) ShowNewGRFSettings(false, false, false, this->server->info.grfconfig);
755 break;
756
757 case WID_NG_NEWGRF_MISSING: // Find missing content online
758 if (this->server != nullptr) ShowMissingContentWindow(this->server->info.grfconfig);
759 break;
760 }
761 }
762
768 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
769 {
770 this->servers.ForceRebuild();
771 this->SetDirty();
772 }
773
774 EventState OnKeyPress([[maybe_unused]] char32_t key, uint16_t keycode) override
775 {
777
778 /* handle up, down, pageup, pagedown, home and end */
779 if (this->vscroll->UpdateListPositionOnKeyPress(this->list_pos, keycode) == ES_HANDLED) {
780 if (this->list_pos == SLP_INVALID) return ES_HANDLED;
781
782 this->server = this->servers[this->list_pos];
783
784 /* Scroll to the new server if it is outside the current range. */
786
787 /* redraw window */
788 this->SetDirty();
789 return ES_HANDLED;
790 }
791
792 if (this->server != nullptr) {
793 if (keycode == WKC_DELETE) { // Press 'delete' to remove servers
794 NetworkGameListRemoveItem(this->server);
795 if (this->server == this->last_joined) this->last_joined = nullptr;
796 this->server = nullptr;
797 this->list_pos = SLP_INVALID;
798 }
799 }
800
801 return state;
802 }
803
805 {
806 switch (wid) {
807 case WID_NG_FILTER: {
808 this->servers.ForceRebuild();
811 this->SetDirty();
812 break;
813 }
814
815 case WID_NG_CLIENT:
816 /* Validation of the name will happen once the user tries to join or start a game, as getting
817 * error messages while typing (e.g. when you clear the name) defeats the purpose of the check. */
818 _settings_client.network.client_name = this->name_editbox.text.GetText();
819 break;
820 }
821 }
822
823 void OnQueryTextFinished(std::optional<std::string> str) override
824 {
825 if (!str.has_value() || str->empty()) return;
826
827 _settings_client.network.connect_to_ip = std::move(*str);
829 NetworkRebuildHostList();
830 }
831
832 void OnResize() override
833 {
834 this->vscroll->SetCapacityFromWidget(this, WID_NG_MATRIX);
835 }
836
838 IntervalTimer<TimerWindow> refresh_interval = {std::chrono::seconds(30), [this](uint) {
839 if (!this->searched_internet) return;
840
842 }};
843};
844
845Listing NetworkGameWindow::last_sorting = {false, 5};
846const std::initializer_list<GUIGameServerList::SortFunction * const> NetworkGameWindow::sorter_funcs = {
847 &NGameNameSorter,
848 &NGameClientSorter,
849 &NGameMapSizeSorter,
850 &NGameCalendarDateSorter,
851 &NGameTicksPlayingSorter,
852 &NGameAllowedSorter
853};
854
855const std::initializer_list<GUIGameServerList::FilterFunction * const> NetworkGameWindow::filter_funcs = {
856 &NGameSearchFilter
857};
858
859static std::unique_ptr<NWidgetBase> MakeResizableHeader()
860{
861 return std::make_unique<NWidgetServerListHeader>();
862}
863
864static constexpr NWidgetPart _nested_network_game_widgets[] = {
865 /* TOP */
867 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
868 NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetStringTip(STR_NETWORK_SERVER_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
869 NWidget(WWT_DEFSIZEBOX, COLOUR_LIGHT_BLUE),
870 EndContainer(),
871 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_MAIN),
874 /* LEFT SIDE */
877 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NG_FILTER_LABEL), SetStringTip(STR_LIST_FILTER_TITLE),
878 NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_FILTER), SetMinimalSize(251, 0), SetFill(1, 0), SetResize(1, 0),
879 SetStringTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
880 EndContainer(),
883 NWidgetFunction(MakeResizableHeader),
884 NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NG_MATRIX), SetResize(1, 1), SetFill(1, 0),
885 SetMatrixDataTip(1, 0, STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT), SetScrollbar(WID_NG_SCROLLBAR),
886 EndContainer(),
887 NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NG_SCROLLBAR),
888 EndContainer(),
890 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NG_LASTJOINED_LABEL), SetFill(1, 0),
891 SetStringTip(STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER), SetResize(1, 0),
893 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_LASTJOINED), SetFill(1, 0), SetResize(1, 0),
894 SetToolTip(STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST_TOOLTIP),
895 EndContainer(),
896 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NG_LASTJOINED_SPACER), SetFill(0, 0),
897 EndContainer(),
898 EndContainer(),
899 EndContainer(),
900 /* RIGHT SIDE */
903 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NG_CLIENT_LABEL), SetStringTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME),
904 NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_CLIENT), SetMinimalSize(151, 0), SetFill(1, 0), SetResize(1, 0),
905 SetStringTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE, STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP),
906 EndContainer(),
908 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_DETAILS), SetMinimalSize(140, 0), SetMinimalTextLines(15, 0), SetResize(0, 1),
909 EndContainer(),
912 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NEWGRF_MISSING), SetFill(1, 0), SetStringTip(STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON, STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP),
913 EndContainer(),
914 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NG_NEWGRF_SEL),
915 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NEWGRF), SetFill(1, 0), SetStringTip(STR_INTRO_NEWGRF_SETTINGS),
916 EndContainer(),
918 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_JOIN), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_JOIN_GAME),
919 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_REFRESH), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_REFRESH, STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP),
920 EndContainer(),
921 EndContainer(),
922 EndContainer(),
923 EndContainer(),
924 EndContainer(),
925 /* BOTTOM */
927 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_SEARCH_INTERNET), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET, STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP),
928 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_SEARCH_LAN), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN, STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP),
929 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_ADD), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_ADD_SERVER, STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP),
930 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_START), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_NETWORK_SERVER_LIST_START_SERVER, STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP),
931 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CANCEL), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_BUTTON_CANCEL),
932 EndContainer(),
933 EndContainer(),
934 /* Resize button. */
936 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
937 NWidget(WWT_RESIZEBOX, COLOUR_LIGHT_BLUE), SetResizeWidgetTypeTip(RWV_HIDE_BEVEL, STR_TOOLTIP_RESIZE),
938 EndContainer(),
939 EndContainer(),
940};
941
942static WindowDesc _network_game_window_desc(
943 WDP_CENTER, "list_servers", 1000, 730,
945 {},
946 _nested_network_game_widgets
947);
948
949void ShowNetworkGameWindow()
950{
951 static bool first = true;
953
954 /* Only show once */
955 if (first) {
956 first = false;
957 /* Add all servers from the config file to our list. */
958 for (const auto &iter : _network_host_list) {
959 NetworkAddServer(iter);
960 }
961 }
962
963 new NetworkGameWindow(_network_game_window_desc);
964}
965
969
971 {
973
975 this->name_editbox.text.Assign(_settings_client.network.server_name);
976
978 }
979
996
998 {
999 switch (widget) {
1002 size.width += padding.width;
1003 size.height += padding.height;
1004 break;
1005 }
1006 }
1007
1008 void DrawWidget(const Rect &r, WidgetID widget) const override
1009 {
1010 switch (widget) {
1011 case WID_NSS_SETPWD:
1012 /* If password is set, draw red '*' next to 'Set password' button. */
1013 if (!_settings_client.network.server_password.empty()) DrawString(r.right + WidgetDimensions::scaled.framerect.left, this->width - WidgetDimensions::scaled.framerect.right, r.top, "*", TC_RED);
1014 }
1015 }
1016
1017 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1018 {
1019 switch (widget) {
1020 case WID_NSS_CANCEL: // Cancel button
1021 ShowNetworkGameWindow();
1022 break;
1023
1024 case WID_NSS_SETPWD: // Set password button
1025 this->widget_id = WID_NSS_SETPWD;
1027 break;
1028
1029 case WID_NSS_CONNTYPE_BTN: // Connection type
1030 ShowDropDownList(this, BuildVisibilityDropDownList(), _settings_client.network.server_game_type, WID_NSS_CONNTYPE_BTN);
1031 break;
1032
1033 case WID_NSS_CLIENTS_BTND: case WID_NSS_CLIENTS_BTNU: // Click on up/down button for number of clients
1034 case WID_NSS_COMPANIES_BTND: case WID_NSS_COMPANIES_BTNU: // Click on up/down button for number of companies
1035 /* Don't allow too fast scrolling. */
1036 if (!this->flags.Test(WindowFlag::Timeout) || this->timeout_timer <= 1) {
1037 this->HandleButtonClick(widget);
1038 this->SetDirty();
1039 switch (widget) {
1040 default: NOT_REACHED();
1043 break;
1046 break;
1047 }
1048 }
1049 _left_button_clicked = false;
1050 break;
1051
1052 case WID_NSS_CLIENTS_TXT: // Click on number of clients
1055 break;
1056
1057 case WID_NSS_COMPANIES_TXT: // Click on number of companies
1060 break;
1061
1062 case WID_NSS_GENERATE_GAME: // Start game
1063 if (!CheckServerName()) return;
1064 _is_network_server = true;
1065 if (_ctrl_pressed) {
1067 } else {
1069 }
1070 break;
1071
1072 case WID_NSS_LOAD_GAME:
1073 if (!CheckServerName()) return;
1074 _is_network_server = true;
1076 break;
1077
1079 if (!CheckServerName()) return;
1080 _is_network_server = true;
1082 break;
1083
1085 if (!CheckServerName()) return;
1086 _is_network_server = true;
1088 break;
1089 }
1090 }
1091
1092 void OnDropdownSelect(WidgetID widget, int index) override
1093 {
1094 switch (widget) {
1097 break;
1098 default:
1099 NOT_REACHED();
1100 }
1101
1102 this->SetDirty();
1103 }
1104
1105 bool CheckServerName()
1106 {
1107 std::string str = this->name_editbox.text.GetText();
1108 if (!NetworkValidateServerName(str)) return false;
1109
1110 SetSettingValue(GetSettingFromName("network.server_name")->AsStringSetting(), str);
1111 return true;
1112 }
1113
1118
1119 void OnQueryTextFinished(std::optional<std::string> str) override
1120 {
1121 if (!str.has_value()) return;
1122
1123 if (this->widget_id == WID_NSS_SETPWD) {
1124 _settings_client.network.server_password = std::move(*str);
1125 } else {
1126 int32_t value = atoi(str->c_str());
1127 this->SetWidgetDirty(this->widget_id);
1128 switch (this->widget_id) {
1129 default: NOT_REACHED();
1131 case WID_NSS_COMPANIES_TXT: _settings_client.network.max_companies = Clamp(value, 1, MAX_COMPANIES); break;
1132 }
1133 }
1134
1135 this->SetDirty();
1136 }
1137};
1138
1139static constexpr NWidgetPart _nested_network_start_server_window_widgets[] = {
1141 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
1142 NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetStringTip(STR_NETWORK_START_SERVER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1143 EndContainer(),
1144 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NSS_BACKGROUND),
1148 /* Game name widgets */
1149 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NSS_GAMENAME_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME),
1150 NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NSS_GAMENAME), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE, STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP),
1151 EndContainer(),
1152
1155 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NSS_CONNTYPE_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_VISIBILITY_LABEL),
1156 NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_BTN), SetFill(1, 0), SetToolTip(STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP),
1157 EndContainer(),
1159 NWidget(NWID_SPACER), SetFill(1, 1),
1160 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_SETPWD), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_SET_PASSWORD, STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP),
1161 EndContainer(),
1162 EndContainer(),
1163
1166 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NSS_CLIENTS_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS),
1168 NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_BTND), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON), SetFill(0, 1), SetSpriteTip(SPR_ARROW_DOWN, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
1169 NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_TXT), SetFill(1, 0), SetToolTip(STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
1170 NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_BTNU), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON), SetFill(0, 1), SetSpriteTip(SPR_ARROW_UP, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
1171 EndContainer(),
1172 EndContainer(),
1173
1175 NWidget(WWT_TEXT, INVALID_COLOUR, WID_NSS_COMPANIES_LABEL), SetFill(1, 0), SetStringTip(STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES),
1177 NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_BTND), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON), SetFill(0, 1), SetSpriteTip(SPR_ARROW_DOWN, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
1178 NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_TXT), SetFill(1, 0), SetToolTip(STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
1179 NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_BTNU), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON), SetFill(0, 1), SetSpriteTip(SPR_ARROW_UP, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
1180 EndContainer(),
1181 EndContainer(),
1182 EndContainer(),
1183 EndContainer(),
1184
1186 /* 'generate game' and 'load game' buttons */
1188 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_GENERATE_GAME), SetStringTip(STR_INTRO_NEW_GAME, STR_INTRO_TOOLTIP_NEW_GAME), SetFill(1, 0),
1189 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_LOAD_GAME), SetStringTip(STR_INTRO_LOAD_GAME, STR_INTRO_TOOLTIP_LOAD_GAME), SetFill(1, 0),
1190 EndContainer(),
1191
1192 /* 'play scenario' and 'play heightmap' buttons */
1194 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_PLAY_SCENARIO), SetStringTip(STR_INTRO_PLAY_SCENARIO, STR_INTRO_TOOLTIP_PLAY_SCENARIO), SetFill(1, 0),
1195 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_PLAY_HEIGHTMAP), SetStringTip(STR_INTRO_PLAY_HEIGHTMAP, STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP), SetFill(1, 0),
1196 EndContainer(),
1197 EndContainer(),
1198
1200 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_CANCEL), SetStringTip(STR_BUTTON_CANCEL), SetMinimalSize(128, 12),
1201 EndContainer(),
1202 EndContainer(),
1203 EndContainer(),
1204};
1205
1206static WindowDesc _network_start_server_window_desc(
1207 WDP_CENTER, nullptr, 0, 0,
1209 {},
1210 _nested_network_start_server_window_widgets
1211);
1212
1213static void ShowNetworkStartServerWindow()
1214{
1215 if (!NetworkValidateOurClientName()) return;
1216
1218
1219 new NetworkStartServerWindow(_network_start_server_window_desc);
1220}
1221
1222/* The window below gives information about the connected clients
1223 * and also makes able to kick them (if server) and stuff like that. */
1224
1225extern void DrawCompanyIcon(CompanyID cid, int x, int y);
1226
1227static constexpr NWidgetPart _nested_client_list_widgets[] = {
1229 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1230 NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_NETWORK_CLIENT_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1231 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
1232 NWidget(WWT_STICKYBOX, COLOUR_GREY),
1233 EndContainer(),
1234 NWidget(WWT_PANEL, COLOUR_GREY),
1236 NWidget(WWT_FRAME, COLOUR_GREY), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0),
1238 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_NAME),
1239 NWidget(WWT_TEXT, INVALID_COLOUR, WID_CL_SERVER_NAME), SetFill(1, 0), SetResize(1, 0), SetToolTip(STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1240 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_CL_SERVER_NAME_EDIT), SetAspect(WidgetDimensions::ASPECT_RENAME), SetSpriteTip(SPR_RENAME, STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP),
1241 EndContainer(),
1245 NWidget(WWT_TEXT, INVALID_COLOUR), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY),
1246 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_CL_SERVER_VISIBILITY), SetToolTip(STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP),
1247 EndContainer(),
1249 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_INVITE_CODE),
1250 NWidget(WWT_TEXT, INVALID_COLOUR, WID_CL_SERVER_INVITE_CODE), SetFill(1, 0), SetResize(1, 0), SetToolTip(STR_NETWORK_CLIENT_LIST_SERVER_INVITE_CODE_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1251 EndContainer(),
1253 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE),
1254 NWidget(WWT_TEXT, INVALID_COLOUR, WID_CL_SERVER_CONNECTION_TYPE), SetFill(1, 0), SetResize(1, 0), SetToolTip(STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1255 EndContainer(),
1256 EndContainer(),
1257 EndContainer(),
1258 EndContainer(),
1259 NWidget(WWT_FRAME, COLOUR_GREY), SetStringTip(STR_NETWORK_CLIENT_LIST_PLAYER),
1261 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_NETWORK_CLIENT_LIST_PLAYER_NAME),
1262 NWidget(WWT_TEXT, INVALID_COLOUR, WID_CL_CLIENT_NAME), SetFill(1, 0), SetResize(1, 0), SetToolTip(STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1263 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_CL_CLIENT_NAME_EDIT), SetAspect(WidgetDimensions::ASPECT_RENAME), SetSpriteTip(SPR_RENAME, STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP),
1264 EndContainer(),
1265 EndContainer(),
1266 EndContainer(),
1267 EndContainer(),
1271 EndContainer(),
1273 NWidget(WWT_PANEL, COLOUR_GREY),
1274 NWidget(WWT_TEXT, INVALID_COLOUR, WID_CL_CLIENT_COMPANY_COUNT), SetFill(1, 0), SetResize(1, 0), SetPadding(WidgetDimensions::unscaled.framerect), SetAlignment(SA_CENTER), SetToolTip(STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT_TOOLTIP),
1275 EndContainer(),
1276 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
1277 EndContainer(),
1278};
1279
1280static WindowDesc _client_list_desc(
1281 WDP_AUTO, "list_clients", 220, 300,
1283 {},
1284 _nested_client_list_widgets
1285);
1286
1291enum DropDownAdmin : uint8_t {
1292 DD_CLIENT_ADMIN_KICK,
1293 DD_CLIENT_ADMIN_BAN,
1294 DD_COMPANY_ADMIN_RESET,
1295};
1296
1301static void AdminClientKickCallback(Window *, bool confirmed)
1302{
1303 if (confirmed) NetworkServerKickClient(_admin_client_id, {});
1304}
1305
1310static void AdminClientBanCallback(Window *, bool confirmed)
1311{
1312 if (confirmed) NetworkServerKickOrBanIP(_admin_client_id, true, {});
1313}
1314
1319static void AdminCompanyResetCallback(Window *, bool confirmed)
1320{
1321 if (confirmed) {
1324 }
1325}
1326
1335public:
1338 Colours colour;
1340 uint height;
1341 uint width;
1342
1343 ButtonCommon(SpriteID sprite, StringID tooltip, Colours colour, bool disabled = false) :
1344 sprite(sprite),
1346 colour(colour),
1348 {
1350 this->height = d.height + WidgetDimensions::scaled.framerect.Vertical();
1351 this->width = d.width + WidgetDimensions::scaled.framerect.Horizontal();
1352 }
1353 virtual ~ButtonCommon() = default;
1354
1358 virtual void OnClick(struct NetworkClientListWindow *w, Point pt) = 0;
1359};
1360
1364template <typename T>
1365class Button : public ButtonCommon {
1366private:
1367 typedef void (*ButtonCallback)(struct NetworkClientListWindow *w, Point pt, T id);
1368 T id;
1370
1371public:
1372 Button(SpriteID sprite, StringID tooltip, Colours colour, T id, ButtonCallback proc, bool disabled = false) :
1374 id(id),
1375 proc(proc)
1376 {
1377 assert(proc != nullptr);
1378 }
1379
1380 void OnClick(struct NetworkClientListWindow *w, Point pt) override
1381 {
1382 if (this->disabled) return;
1383
1384 this->proc(w, pt, this->id);
1385 }
1386};
1387
1390
1395private:
1397
1399 CompanyID dd_company_id = CompanyID::Invalid();
1400
1401 Scrollbar *vscroll = nullptr;
1402 uint line_height = 0;
1403 uint line_count = 0;
1404 int hover_index = -1;
1407
1408 std::map<uint, std::vector<std::unique_ptr<ButtonCommon>>> buttons{};
1409
1420
1436
1446
1454 {
1455 DropDownList list;
1456 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK, DD_CLIENT_ADMIN_KICK));
1457 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN, DD_CLIENT_ADMIN_BAN));
1458
1459 Rect wi_rect;
1460 wi_rect.left = pt.x;
1461 wi_rect.right = pt.x;
1462 wi_rect.top = pt.y;
1463 wi_rect.bottom = pt.y;
1464
1465 w->dd_client_id = client_id;
1466 ShowDropDownListAt(w, std::move(list), -1, WID_CL_MATRIX, wi_rect, COLOUR_GREY, true);
1467 }
1468
1476 {
1477 DropDownList list;
1478 list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET, DD_COMPANY_ADMIN_RESET, NetworkCompanyHasClients(company_id)));
1479
1480 Rect wi_rect;
1481 wi_rect.left = pt.x;
1482 wi_rect.right = pt.x;
1483 wi_rect.top = pt.y;
1484 wi_rect.bottom = pt.y;
1485
1486 w->dd_company_id = company_id;
1487 ShowDropDownListAt(w, std::move(list), -1, WID_CL_MATRIX, wi_rect, COLOUR_GREY, true);
1488 }
1499
1500 static void OnClickClientAuthorize([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, ClientID client_id)
1501 {
1504 }
1505
1513 {
1515
1517 this->buttons[line_count].emplace_back(chat_button);
1518 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));
1519
1520 this->line_count += 1;
1521
1522 bool has_players = false;
1523 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1524 if (ci->client_playas != company_id) continue;
1525 has_players = true;
1526
1527 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));
1528 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));
1529 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));
1530
1531 if (ci->client_id == _network_own_client_id) {
1532 this->player_self_index = this->line_count;
1533 } else if (ci->client_id == CLIENT_ID_SERVER) {
1534 this->player_host_index = this->line_count;
1535 }
1536
1537 this->line_count += 1;
1538 }
1539
1540 /* Disable the chat button when there are players in this company. */
1542 }
1543
1548 {
1550 CompanyID client_playas = own_ci == nullptr ? COMPANY_SPECTATOR : own_ci->client_playas;
1551
1552 this->buttons.clear();
1553 this->line_count = 0;
1554 this->player_host_index = -1;
1555 this->player_self_index = -1;
1556
1557 /* As spectator, show a line to create a new company. */
1558 if (client_playas == COMPANY_SPECTATOR && !NetworkMaxCompaniesReached()) {
1559 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));
1560 this->line_count += 1;
1561 }
1562
1563 if (client_playas != COMPANY_SPECTATOR) {
1564 this->RebuildListCompany(client_playas, client_playas, false);
1565 }
1566
1567 /* Companies */
1568 for (const Company *c : Company::Iterate()) {
1569 if (c->index == client_playas) continue;
1570
1571 this->RebuildListCompany(c->index, client_playas, (own_ci != nullptr && c->allow_list.Contains(own_ci->public_key)) || _network_server);
1572 }
1573
1574 /* Spectators */
1575 this->RebuildListCompany(COMPANY_SPECTATOR, client_playas, client_playas != COMPANY_SPECTATOR);
1576
1577 this->vscroll->SetCount(this->line_count);
1578 }
1579
1586 {
1587 uint index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CL_MATRIX);
1588 Rect matrix = this->GetWidget<NWidgetBase>(WID_CL_MATRIX)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
1589
1590 bool rtl = _current_text_dir == TD_RTL;
1591 uint x = rtl ? matrix.left : matrix.right;
1592
1593 /* Find the buttons for this row. */
1594 auto button_find = this->buttons.find(index);
1595 if (button_find == this->buttons.end()) return nullptr;
1596
1597 /* Check if we want to display a tooltip for any of the buttons. */
1598 for (auto &button : button_find->second) {
1599 uint left = rtl ? x : x - button->width;
1600 uint right = rtl ? x + button->width : x;
1601
1602 if (IsInsideMM(pt.x, left, right)) {
1603 return button.get();
1604 }
1605
1606 int width = button->width + WidgetDimensions::scaled.framerect.Horizontal();
1607 x += rtl ? width : -width;
1608 }
1609
1610 return nullptr;
1611 }
1612
1613public:
1615 {
1616 this->CreateNestedTree();
1617 this->vscroll = this->GetScrollbar(WID_CL_SCROLLBAR);
1618 this->OnInvalidateData();
1619 this->FinishInitNested(window_number);
1620 }
1621
1622 void OnInit() override
1623 {
1624 RebuildList();
1625 }
1626
1627 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1628 {
1629 this->RebuildList();
1630
1631 /* Currently server information is not sync'd to clients, so we cannot show it on clients. */
1634 }
1635
1637 {
1638 switch (widget) {
1639 case WID_CL_SERVER_NAME:
1640 case WID_CL_CLIENT_NAME: {
1641 std::string str;
1642 if (widget == WID_CL_SERVER_NAME) {
1644 } else {
1647 }
1648 size = GetStringBoundingBox(str);
1649 size.width = std::min(size.width, static_cast<uint>(ScaleGUITrad(200))); // By default, don't open the window too wide.
1650 break;
1651 }
1652
1655 size.width += padding.width;
1656 size.height += padding.height;
1657 break;
1658
1659 case WID_CL_MATRIX: {
1660 uint height = std::max({GetSpriteSize(SPR_COMPANY_ICON).height, GetSpriteSize(SPR_JOIN).height, GetSpriteSize(SPR_ADMIN).height, GetSpriteSize(SPR_CHAT).height});
1662 this->line_height = std::max(height, (uint)GetCharacterHeight(FS_NORMAL)) + padding.height;
1663
1664 resize.width = 1;
1665 resize.height = this->line_height;
1666 fill.height = this->line_height;
1667 size.height = std::max(size.height, 5 * this->line_height);
1668 break;
1669 }
1670 }
1671 }
1672
1673 void OnResize() override
1674 {
1675 this->vscroll->SetCapacityFromWidget(this, WID_CL_MATRIX);
1676 }
1677
1705
1706 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1707 {
1708 switch (widget) {
1710 if (!_network_server) break;
1711
1714 break;
1715
1720 break;
1721 }
1723 if (!_network_server) break;
1724
1726 break;
1727
1728 case WID_CL_MATRIX: {
1729 ButtonCommon *button = this->GetButtonAtPoint(pt);
1730 if (button == nullptr) break;
1731
1732 button->OnClick(this, pt);
1733 break;
1734 }
1735 }
1736 }
1737
1738 bool OnTooltip([[maybe_unused]] Point pt, WidgetID widget, TooltipCloseCondition close_cond) override
1739 {
1740 switch (widget) {
1741 case WID_CL_MATRIX: {
1742 int index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CL_MATRIX);
1743
1744 bool rtl = _current_text_dir == TD_RTL;
1745 Rect matrix = this->GetWidget<NWidgetBase>(WID_CL_MATRIX)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
1746
1747 Dimension d = GetSpriteSize(SPR_COMPANY_ICON);
1748 uint text_left = matrix.left + (rtl ? 0 : d.width + WidgetDimensions::scaled.hsep_wide);
1749 uint text_right = matrix.right - (rtl ? d.width + WidgetDimensions::scaled.hsep_wide : 0);
1750
1751 Dimension d2 = GetSpriteSize(SPR_PLAYER_SELF);
1753
1754 uint player_icon_x = rtl ? text_right - offset_x - d2.width : text_left + offset_x;
1755
1756 if (IsInsideMM(pt.x, player_icon_x, player_icon_x + d2.width)) {
1757 if (index == this->player_self_index) {
1759 return true;
1760 } else if (index == this->player_host_index) {
1762 return true;
1763 }
1764 }
1765
1766 ButtonCommon *button = this->GetButtonAtPoint(pt);
1767 if (button == nullptr) return false;
1768
1769 GuiShowTooltips(this, GetEncodedString(button->tooltip), close_cond);
1770 return true;
1771 };
1772 }
1773
1774 return false;
1775 }
1776
1777 void OnDropdownClose(Point pt, WidgetID widget, int index, bool instant_close) override
1778 {
1779 /* If you close the dropdown outside the list, don't take any action. */
1780 if (widget == WID_CL_MATRIX) return;
1781
1782 Window::OnDropdownClose(pt, widget, index, instant_close);
1783 }
1784
1785 void OnDropdownSelect(WidgetID widget, int index) override
1786 {
1787 switch (widget) {
1789 if (!_network_server) break;
1790
1793 break;
1794
1795 case WID_CL_MATRIX: {
1796 QueryCallbackProc *callback = nullptr;
1797
1798 EncodedString text;
1799 switch (index) {
1800 case DD_CLIENT_ADMIN_KICK:
1802 callback = AdminClientKickCallback;
1804 break;
1805
1806 case DD_CLIENT_ADMIN_BAN:
1808 callback = AdminClientBanCallback;
1810 break;
1811
1812 case DD_COMPANY_ADMIN_RESET:
1814 callback = AdminCompanyResetCallback;
1816 break;
1817
1818 default:
1819 NOT_REACHED();
1820 }
1821
1822 assert(callback != nullptr);
1823
1824 /* Always ask confirmation for all admin actions. */
1825 ShowQuery(
1827 std::move(text),
1828 this, callback);
1829
1830 break;
1831 }
1832
1833 default:
1834 NOT_REACHED();
1835 }
1836
1837 this->SetDirty();
1838 }
1839
1840 void OnQueryTextFinished(std::optional<std::string> str) override
1841 {
1842 if (!str.has_value()) return;
1843
1844 switch (this->query_widget) {
1845 default: NOT_REACHED();
1846
1848 if (!_network_server) break;
1849
1850 SetSettingValue(GetSettingFromName("network.server_name")->AsStringSetting(), *str);
1851 this->InvalidateData();
1852 break;
1853 }
1854
1856 SetSettingValue(GetSettingFromName("network.client_name")->AsStringSetting(), *str);
1857 this->InvalidateData();
1858 break;
1859 }
1860 }
1861 }
1862
1873 void DrawButtons(int &x, uint y, const std::vector<std::unique_ptr<ButtonCommon>> &buttons) const
1874 {
1875 Rect r;
1876
1877 for (auto &button : buttons) {
1878 bool rtl = _current_text_dir == TD_RTL;
1879
1880 int offset = (this->line_height - button->height) / 2;
1881 r.left = rtl ? x : x - button->width + 1;
1882 r.right = rtl ? x + button->width - 1 : x;
1883 r.top = y + offset;
1884 r.bottom = r.top + button->height - 1;
1885
1886 DrawFrameRect(r, button->colour, {});
1887 DrawSprite(button->sprite, PAL_NONE, r.left + WidgetDimensions::scaled.framerect.left, r.top + WidgetDimensions::scaled.framerect.top);
1888 if (button->disabled) {
1890 }
1891
1892 int width = button->width + WidgetDimensions::scaled.hsep_normal;
1893 x += rtl ? width : -width;
1894 }
1895 }
1896
1903 void DrawCompany(CompanyID company_id, const Rect &r, uint &line) const
1904 {
1905 bool rtl = _current_text_dir == TD_RTL;
1906 int text_y_offset = CenterBounds(0, this->line_height, GetCharacterHeight(FS_NORMAL));
1907
1908 Dimension d = GetSpriteSize(SPR_COMPANY_ICON);
1909 int offset = CenterBounds(0, this->line_height, d.height);
1910
1911 uint line_start = this->vscroll->GetPosition();
1912 uint line_end = line_start + this->vscroll->GetCapacity();
1913
1914 uint y = r.top + (this->line_height * (line - line_start));
1915
1916 /* Draw the company line (if in range of scrollbar). */
1917 if (IsInsideMM(line, line_start, line_end)) {
1918 int icon_left = r.WithWidth(d.width, rtl).left;
1920 int &x = rtl ? tr.left : tr.right;
1921
1922 /* If there are buttons for this company, draw them. */
1923 auto button_find = this->buttons.find(line);
1924 if (button_find != this->buttons.end()) {
1925 this->DrawButtons(x, y, button_find->second);
1926 }
1927
1929 DrawSprite(SPR_COMPANY_ICON, PALETTE_TO_GREY, icon_left, y + offset);
1930 DrawString(tr.left, tr.right, y + text_y_offset, STR_NETWORK_CLIENT_LIST_SPECTATORS, TC_SILVER);
1931 } else if (company_id == COMPANY_NEW_COMPANY) {
1932 DrawSprite(SPR_COMPANY_ICON, PALETTE_TO_GREY, icon_left, y + offset);
1934 } else {
1935 DrawCompanyIcon(company_id, icon_left, y + offset);
1936
1938 }
1939 }
1940
1941 y += this->line_height;
1942 line++;
1943
1944 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1945 if (ci->client_playas != company_id) continue;
1946
1947 /* Draw the player line (if in range of scrollbar). */
1948 if (IsInsideMM(line, line_start, line_end)) {
1949 Rect tr = r.Indent(WidgetDimensions::scaled.hsep_indent, rtl);
1950
1951 /* If there are buttons for this client, draw them. */
1952 auto button_find = this->buttons.find(line);
1953 if (button_find != this->buttons.end()) {
1954 int &x = rtl ? tr.left : tr.right;
1955 this->DrawButtons(x, y, button_find->second);
1956 }
1957
1959 if (ci->client_id == _network_own_client_id) {
1960 player_icon = SPR_PLAYER_SELF;
1961 } else if (ci->client_id == CLIENT_ID_SERVER) {
1962 player_icon = SPR_PLAYER_HOST;
1963 }
1964
1965 if (player_icon != 0) {
1967 int offset_y = CenterBounds(0, this->line_height, d2.height);
1968 DrawSprite(player_icon, PALETTE_TO_GREY, rtl ? tr.right - d2.width : tr.left, y + offset_y);
1969 tr = tr.Indent(d2.width + WidgetDimensions::scaled.hsep_normal, rtl);
1970 }
1971
1972 DrawString(tr.left, tr.right, y + text_y_offset, GetString(STR_JUST_RAW_STRING, ci->client_name), TC_BLACK);
1973 }
1974
1975 y += this->line_height;
1976 line++;
1977 }
1978 }
1979
1980 void DrawWidget(const Rect &r, WidgetID widget) const override
1981 {
1982 switch (widget) {
1983 case WID_CL_MATRIX: {
1984 Rect ir = r.Shrink(WidgetDimensions::scaled.framerect, RectPadding::zero);
1985 uint line = 0;
1986
1987 if (this->hover_index >= 0) {
1988 Rect br = r.WithHeight(this->line_height).Translate(0, this->hover_index * this->line_height);
1990 }
1991
1993 CompanyID client_playas = own_ci == nullptr ? COMPANY_SPECTATOR : own_ci->client_playas;
1994
1995 if (client_playas == COMPANY_SPECTATOR && !NetworkMaxCompaniesReached()) {
1996 this->DrawCompany(COMPANY_NEW_COMPANY, ir, line);
1997 }
1998
1999 if (client_playas != COMPANY_SPECTATOR) {
2000 this->DrawCompany(client_playas, ir, line);
2001 }
2002
2003 for (const Company *c : Company::Iterate()) {
2004 if (client_playas == c->index) continue;
2005 this->DrawCompany(c->index, ir, line);
2006 }
2007
2008 /* Spectators */
2009 this->DrawCompany(COMPANY_SPECTATOR, ir, line);
2010
2011 break;
2012 }
2013 }
2014 }
2015
2016 void OnMouseOver([[maybe_unused]] Point pt, WidgetID widget) override
2017 {
2018 if (widget != WID_CL_MATRIX) {
2019 if (this->hover_index != -1) {
2020 this->hover_index = -1;
2022 }
2023 } else {
2024 int index = this->GetRowFromWidget(pt.y, widget, 0, -1);
2025 if (index != this->hover_index) {
2026 this->hover_index = index;
2028 }
2029 }
2030 }
2031};
2032
2033void ShowClientList()
2034{
2035 AllocateWindowDescFront<NetworkClientListWindow>(_client_list_desc, 0);
2036}
2037
2042
2044 std::shared_ptr<NetworkAuthenticationPasswordRequest> request{};
2045
2047 {
2050 }
2051
2052 void DrawWidget(const Rect &r, WidgetID widget) const override
2053 {
2054 switch (widget) {
2055 case WID_NJS_PROGRESS_BAR: {
2056 /* Draw the % complete with a bar and a text */
2059 uint8_t progress; // used for progress bar
2060 switch (_network_join_status) {
2061 case NETWORK_JOIN_STATUS_CONNECTING:
2062 case NETWORK_JOIN_STATUS_AUTHORIZING:
2063 case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
2064 progress = 10; // first two stages 10%
2065 break;
2066 case NETWORK_JOIN_STATUS_WAITING:
2067 progress = 15; // third stage is 15%
2068 break;
2069 case NETWORK_JOIN_STATUS_DOWNLOADING:
2070 if (_network_join_bytes_total == 0) {
2071 progress = 15; // We don't have the final size yet; the server is still compressing!
2072 break;
2073 }
2074 [[fallthrough]];
2075
2076 default: // Waiting is 15%, so the resting receivement of map is maximum 70%
2077 progress = 15 + _network_join_bytes * (100 - 15) / _network_join_bytes_total;
2078 break;
2079 }
2080 DrawFrameRect(ir.WithWidth(ir.Width() * progress / 100, _current_text_dir == TD_RTL), COLOUR_MAUVE, {});
2082 break;
2083 }
2084
2086 switch (_network_join_status) {
2087 case NETWORK_JOIN_STATUS_WAITING:
2089 break;
2090
2091 case NETWORK_JOIN_STATUS_DOWNLOADING:
2092 if (_network_join_bytes_total == 0) {
2094 } else {
2096 }
2097 break;
2098
2099 default:
2100 break;
2101 }
2102 break;
2103 }
2104 }
2105
2107 {
2108 switch (widget) {
2110 /* Account for the statuses */
2111 for (uint i = 0; i < NETWORK_JOIN_STATUS_END; i++) {
2113 }
2114 /* For the number of waiting (other) players */
2116 /* We need some spacing for the 'border' */
2119 break;
2120
2121 case WID_NJS_PROGRESS_TEXT: {
2122 /* Account for downloading ~ 10 MiB */
2126 break;
2127 }
2128 }
2129 }
2130
2131 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2132 {
2133 if (widget == WID_NJS_CANCELOK) { // Disconnect button
2135 SwitchToMode(SM_MENU);
2136 ShowNetworkGameWindow();
2137 }
2138 }
2139
2140 void OnQueryTextFinished(std::optional<std::string> str) override
2141 {
2142 if (!str.has_value() || str->empty() || this->request == nullptr) {
2144 return;
2145 }
2146
2147 this->request->Reply(*str);
2148 }
2149};
2150
2151static constexpr NWidgetPart _nested_network_join_status_window_widgets[] = {
2152 NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_NETWORK_CONNECTING_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2153 NWidget(WWT_PANEL, COLOUR_GREY),
2155 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NJS_PROGRESS_BAR), SetFill(1, 0),
2156 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NJS_PROGRESS_TEXT), SetFill(1, 0), SetMinimalSize(350, 0),
2157 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NJS_CANCELOK), SetMinimalSize(101, 12), SetStringTip(STR_NETWORK_CONNECTION_DISCONNECT), SetFill(1, 0),
2158 EndContainer(),
2159 EndContainer(),
2160};
2161
2162static WindowDesc _network_join_status_window_desc(
2163 WDP_CENTER, nullptr, 0, 0,
2166 _nested_network_join_status_window_widgets
2167);
2168
2169void ShowJoinStatusWindow()
2170{
2172 new NetworkJoinStatusWindow(_network_join_status_window_desc);
2173}
2174
2175void ShowNetworkNeedPassword(std::shared_ptr<NetworkAuthenticationPasswordRequest> request)
2176{
2178 if (w == nullptr) return;
2179 w->request = request;
2180
2181 ShowQueryString({}, STR_NETWORK_NEED_GAME_PASSWORD_CAPTION, NETWORK_PASSWORD_LENGTH, w, CS_ALPHANUMERAL, {});
2182}
2183
2190 std::string token{};
2191
2192 NetworkAskRelayWindow(WindowDesc &desc, Window *parent, const std::string &server_connection_string, const std::string &relay_connection_string, const std::string &token) :
2193 Window(desc),
2196 token(token)
2197 {
2198 this->parent = parent;
2199 this->InitNested(0);
2200 }
2201
2202 void Close(int data = 0) override
2203 {
2205 this->Window::Close();
2206 }
2207
2209 {
2210 if (widget == WID_NAR_TEXT) {
2212 }
2213 }
2214
2215 void DrawWidget(const Rect &r, WidgetID widget) const override
2216 {
2217 if (widget == WID_NAR_TEXT) {
2219 }
2220 }
2221
2223 {
2224 /* Position query window over the calling window, ensuring it's within screen bounds. */
2225 this->left = Clamp(parent->left + (parent->width / 2) - (this->width / 2), 0, _screen.width - this->width);
2226 this->top = Clamp(parent->top + (parent->height / 2) - (this->height / 2), 0, _screen.height - this->height);
2227 this->SetDirty();
2228 }
2229
2230 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2231 {
2232 switch (widget) {
2233 case WID_NAR_NO:
2235 this->Close(NRWCD_HANDLED);
2236 break;
2237
2238 case WID_NAR_YES_ONCE:
2239 _network_coordinator_client.StartTurnConnection(this->token);
2240 this->Close(NRWCD_HANDLED);
2241 break;
2242
2243 case WID_NAR_YES_ALWAYS:
2245 _network_coordinator_client.StartTurnConnection(this->token);
2246 this->Close(NRWCD_HANDLED);
2247 break;
2248 }
2249 }
2250};
2251
2252static constexpr NWidgetPart _nested_network_ask_relay_widgets[] = {
2254 NWidget(WWT_CLOSEBOX, COLOUR_RED),
2255 NWidget(WWT_CAPTION, COLOUR_RED, WID_NAR_CAPTION), SetStringTip(STR_NETWORK_ASK_RELAY_CAPTION),
2256 EndContainer(),
2257 NWidget(WWT_PANEL, COLOUR_RED),
2261 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NAR_NO), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_RELAY_NO),
2262 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NAR_YES_ONCE), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_RELAY_YES_ONCE),
2263 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NAR_YES_ALWAYS), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_RELAY_YES_ALWAYS),
2264 EndContainer(),
2265 EndContainer(),
2266 EndContainer(),
2267};
2268
2269static WindowDesc _network_ask_relay_desc(
2270 WDP_CENTER, nullptr, 0, 0,
2273 _nested_network_ask_relay_widgets
2274);
2275
2282void ShowNetworkAskRelay(const std::string &server_connection_string, const std::string &relay_connection_string, const std::string &token)
2283{
2285
2286 Window *parent = GetMainWindow();
2287 new NetworkAskRelayWindow(_network_ask_relay_desc, parent, server_connection_string, relay_connection_string, token);
2288}
2289
2295 Window(desc)
2296 {
2297 this->parent = parent;
2298 this->InitNested(0);
2299 }
2300
2302 {
2303 if (widget == WID_NAS_TEXT) {
2305 }
2306 }
2307
2308 void DrawWidget(const Rect &r, WidgetID widget) const override
2309 {
2310 if (widget == WID_NAS_TEXT) {
2312 }
2313 }
2314
2316 {
2317 /* Position query window over the calling window, ensuring it's within screen bounds. */
2318 this->left = Clamp(parent->left + (parent->width / 2) - (this->width / 2), 0, _screen.width - this->width);
2319 this->top = Clamp(parent->top + (parent->height / 2) - (this->height / 2), 0, _screen.height - this->height);
2320 this->SetDirty();
2321 }
2322
2323 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2324 {
2325 switch (widget) {
2326 case WID_NAS_PREVIEW:
2327 ShowSurveyResultTextfileWindow();
2328 break;
2329
2330 case WID_NAS_LINK:
2331 OpenBrowser(NETWORK_SURVEY_DETAILS_LINK);
2332 break;
2333
2334 case WID_NAS_NO:
2336 this->Close();
2337 break;
2338
2339 case WID_NAS_YES:
2341 this->Close();
2342 break;
2343 }
2344 }
2345};
2346
2347static constexpr NWidgetPart _nested_network_ask_survey_widgets[] = {
2349 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
2350 NWidget(WWT_CAPTION, COLOUR_GREY, WID_NAS_CAPTION), SetStringTip(STR_NETWORK_ASK_SURVEY_CAPTION),
2351 EndContainer(),
2352 NWidget(WWT_PANEL, COLOUR_GREY),
2356 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NAS_PREVIEW), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_SURVEY_PREVIEW),
2357 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NAS_LINK), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_SURVEY_LINK),
2358 EndContainer(),
2360 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NAS_NO), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_SURVEY_NO),
2361 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NAS_YES), SetMinimalSize(71, 12), SetFill(1, 1), SetStringTip(STR_NETWORK_ASK_SURVEY_YES),
2362 EndContainer(),
2363 EndContainer(),
2364 EndContainer(),
2365};
2366
2367static WindowDesc _network_ask_survey_desc(
2368 WDP_CENTER, nullptr, 0, 0,
2371 _nested_network_ask_survey_widgets
2372);
2373
2378{
2379 /* If we can't send a survey, don't ask the question. */
2380 if constexpr (!NetworkSurveyHandler::IsSurveyPossible()) return;
2381
2383
2384 Window *parent = GetMainWindow();
2385 new NetworkAskSurveyWindow(_network_ask_survey_desc, parent);
2386}
2387
2391
2393 {
2394 this->ConstructWindow();
2395
2396 auto result = _survey.CreatePayload(NetworkSurveyHandler::Reason::PREVIEW, true);
2397 this->LoadText(result);
2398 this->InvalidateData();
2399 }
2400};
2401
2402void ShowSurveyResultTextfileWindow()
2403{
2406}
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Button shown for either a company or client in the client-list.
Colours colour
The colour of the button.
bool disabled
Is the button disabled?
uint width
Calculated width of the button.
virtual void OnClick(struct NetworkClientListWindow *w, Point pt)=0
OnClick handler for when the button is pressed.
SpriteID sprite
The sprite to use on the button.
uint height
Calculated height of the button.
StringID tooltip
The tooltip of the button.
Template version of Button, with callback support.
T id
ID this button belongs to.
void OnClick(struct NetworkClientListWindow *w, Point pt) override
OnClick handler for when the button is pressed.
ButtonCallback proc
Callback proc to call when button is pressed.
void(* ButtonCallback)(struct NetworkClientListWindow *w, Point pt, T id)
Callback function to call on click.
void ConnectFailure(const std::string &token, uint8_t tracking_number)
Callback from a Connecter to let the Game Coordinator know the connection failed.
void GetListing()
Request a listing of all public servers.
Container for an encoded string, created by GetEncodedString.
List template of 'things' T to sort in a GUI.
bool Filter(FilterFunction *decide, F filter_data)
Filter the list.
void RebuildDone()
Notify the sortlist that the rebuild is done.
void SetListing(Listing l)
Import sort conditions.
void SetFilterState(bool state)
Enable or disable the filter.
bool IsDescSortOrder() const
Check if the sort order is descending.
void ToggleSortOrder()
Toggle the sort order Since that is the worst condition for the sort function reverse the list here.
void SetFilterFuncs(std::span< FilterFunction *const > n_funcs)
Hand the filter function pointers to the GUIList.
bool NeedRebuild() const
Check if a rebuild is needed.
void ForceRebuild()
Force that a rebuild is needed.
bool Sort(Comp compare)
Sort the list.
void ForceResort()
Force a resort next Sort call Reset the resort timer if used too.
uint8_t SortType() const
Get the sorttype of the list.
Listing GetListing() const
Export current sort conditions.
void SetSortFuncs(std::span< SortFunction *const > n_funcs)
Hand the sort function pointers to the GUIList.
bool NeedResort()
Check if a resort is needed next loop If used the resort timer will decrease every call till 0.
void SetSortType(uint8_t n_type)
Set the sorttype of the list.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
Baseclass for nested widgets.
uint resize_x
Horizontal resize step (0 means not resizable).
uint fill_x
Horizontal fill stepsize (from initial size, 0 means not resizable).
uint smallest_x
Smallest horizontal size of the widget in a filled window.
uint current_x
Current horizontal size (after resizing).
int pos_y
Vertical position of top-left corner of the widget in the window.
int pos_x
Horizontal position of top-left corner of the widget in the window.
uint smallest_y
Smallest vertical size of the widget in a filled window.
uint fill_y
Vertical fill stepsize (from initial size, 0 means not resizable).
uint resize_y
Vertical resize step (0 means not resizable).
uint current_y
Current vertical size (after resizing).
Baseclass for container widgets.
void Add(std::unique_ptr< NWidgetBase > &&wid)
Append widget wid to container.
Definition widget.cpp:1280
std::vector< std::unique_ptr< NWidgetBase > > children
Child widgets in container.
Full blown container to make it behave exactly as we want :)
static const uint MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER
Minimum width before adding a new header.
void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override
Assign size and position to the widget.
void SetupSmallestSize(Window *w) override
Compute smallest size needed by the widget.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
void OnPaint() override
The window must be repainted.
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:2447
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:2521
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:2468
void ScrollTowards(size_type position)
Scroll towards the given position; if the item is visible nothing happens, otherwise it will be shown...
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
size_type GetPosition() const
Gets the position of the first visible element in the list.
static constexpr TimerGameTick::Ticks TICKS_PER_SECOND
Estimation of how many ticks fit in a single second.
static YearMonthDay ConvertDateToYMD(Date date)
Converts a Date to a Year, Month & Day.
RectPadding framerect
Standard padding inside many panels.
Definition window_gui.h:40
RectPadding frametext
Padding inside frame with text.
Definition window_gui.h:41
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:29
int vsep_wide
Wide vertical spacing.
Definition window_gui.h:60
int hsep_wide
Wide horizontal spacing.
Definition window_gui.h:62
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:94
RectPadding matrix
Padding of WWT_MATRIX items.
Definition window_gui.h:42
int hsep_normal
Normal horizontal spacing.
Definition window_gui.h:61
RectPadding bevel
Bevel thickness, affected by "scaled bevels" game option.
Definition window_gui.h:38
int hsep_indent
Width of indentation for tree layouts.
Definition window_gui.h:63
CompanyID _current_company
Company currently doing an action.
@ CCA_DELETE
Delete a company.
@ CCA_NEW
Create a new company.
static constexpr CompanyID COMPANY_SPECTATOR
The client is spectating.
@ CALCA_ADD
Create a public key.
static constexpr CompanyID COMPANY_NEW_COMPANY
The client wants a new company.
@ CRR_NONE
Dummy reason for actions that don't need one.
@ CRR_MANUAL
The company is manually removed.
static const uint NETWORK_CLIENT_NAME_LENGTH
The maximum length of a client's name, in bytes including '\0'.
Definition config.h:58
static const uint NETWORK_HOSTNAME_PORT_LENGTH
The maximum length of the host name + port, in bytes including '\0'. The extra six is ":" + port numb...
Definition config.h:55
static const uint NETWORK_NAME_LENGTH
The maximum length of the server name and map name, in bytes including '\0'.
Definition config.h:53
static const std::string NETWORK_SURVEY_DETAILS_LINK
Link with more details & privacy statement of the survey.
Definition config.h:30
static const uint NETWORK_PASSWORD_LENGTH
The maximum length of the password, in bytes including '\0'.
Definition config.h:57
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, bool instant_close, bool persist)
Show a drop down list.
Definition dropdown.cpp: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.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
@ SLO_LOAD
File is being loaded.
Definition fileio_type.h:55
@ FT_SCENARIO
old or new scenario
Definition fileio_type.h:19
@ FT_HEIGHTMAP
heightmap file
Definition fileio_type.h:20
@ FT_SAVEGAME
old or new savegame
Definition fileio_type.h:18
void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fop)
Launch save/load dialog in the given mode.
Definition fios_gui.cpp:984
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:77
static const uint32_t GENERATE_NEW_SEED
Create a new random seed.
Definition genworld.h:25
void StartNewGameWithoutGUI(uint32_t seed)
Start a normal game without the GUI.
void ShowGenerateLandscape()
Start with a normal game.
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
int GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition gfx.cpp:705
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition gfx.cpp:923
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:852
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition gfx.cpp:658
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:38
bool _left_button_clicked
Is left mouse button clicked?
Definition gfx.cpp:42
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
Definition gfx.cpp:115
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition gfx.cpp:989
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition gfx.cpp:775
Dimension GetScaledSpriteSize(SpriteID sprid)
Scale sprite size for GUI.
Definition widget.cpp:67
int CenterBounds(int min, int max, int size)
Determine where to draw a centred object inside a widget.
Definition gfx_func.h:166
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:243
@ SA_RIGHT
Right align the text (must be a single bit).
Definition gfx_type.h:377
@ SA_HOR_CENTER
Horizontally center the text.
Definition gfx_type.h:376
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:385
@ SA_VERT_CENTER
Vertically center the text.
Definition gfx_type.h:381
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
@ FILLRECT_CHECKER
Draw only every second pixel, used for greying-out.
Definition gfx_type.h:333
constexpr NWidgetPart SetMatrixDataTip(uint32_t cols, uint32_t rows, StringID tip={})
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
constexpr NWidgetPart NWidgetFunction(NWidgetFunctionType *func_ptr)
Obtain a nested widget (sub)tree from an external source.
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
constexpr NWidgetPart SetSpriteTip(SpriteID sprite, StringID tip={})
Widget part function for setting the sprite and tooltip.
constexpr NWidgetPart SetPIP(uint8_t pre, uint8_t inter, uint8_t post)
Widget part function for setting a pre/inter/post spaces.
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
constexpr NWidgetPart SetPadding(uint8_t top, uint8_t right, uint8_t bottom, uint8_t left)
Widget part function for setting additional space around a widget.
constexpr NWidgetPart SetStringTip(StringID string, StringID tip={})
Widget part function for setting the string and tooltip.
constexpr NWidgetPart SetAspect(float ratio, AspectFlags flags=AspectFlag::ResizeX)
Widget part function for setting the aspect ratio.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
constexpr NWidgetPart SetResizeWidgetTypeTip(ResizeWidgetValues widget_type, StringID tip)
Widget part function for setting the resize widget type and tooltip.
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetToolTip(StringID tip)
Widget part function for setting tooltip and clearing the widget data.
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart SetMinimalTextLines(uint8_t lines, uint8_t spacing, FontSize size=FS_NORMAL)
Widget part function for setting the minimal text lines.
constexpr NWidgetPart SetAlignment(StringAlignment align)
Widget part function for setting the alignment of text/images.
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
constexpr NWidgetPart SetPIPRatio(uint8_t ratio_pre, uint8_t ratio_inter, uint8_t ratio_post)
Widget part function for setting a pre/inter/post ratio.
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition window.cpp:943
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1500
static const uint MAX_MAP_SIZE
Maximal map size = 4096.
Definition map_type.h:40
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
void GuiShowTooltips(Window *parent, EncodedString &&text, TooltipCloseCondition close_tooltip)
Shows a tooltip.
Definition misc_gui.cpp:690
void ShowQuery(EncodedString &&caption, EncodedString &&message, Window *parent, QueryCallbackProc *callback, bool focus)
Show a confirmation window with standard 'yes' and 'no' buttons The window is aligned to the centre o...
void ShowQueryString(std::string_view str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
Show a query popup window with a textbox in it.
bool _is_network_server
Does this client wants to be a network-server?
Definition network.cpp: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.
void ShowMissingContentWindow(const GRFConfigList &list)
Show the content list window with all missing grfs from the given list.
ConnectionType _network_server_connection_type
What type of connection the Game Coordinator detected we are on.
ClientNetworkCoordinatorSocketHandler _network_coordinator_client
The connection to the Game Coordinator.
std::string _network_server_invite_code
Our invite code as indicated by the Game Coordinator.
Part of the network protocol handling Game Coordinator requests.
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, const std::string &reason)
Ban, or kick, everyone joined from the given client's IP.
void NetworkServerKickClient(ClientID client_id, const std::string &reason)
Kick a single client.
void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
Handle the tid-bits of moving a client from one company to another.
bool NetworkCompanyHasClients(CompanyID company)
Check whether a particular company has clients.
void NetworkGameListRemoveItem(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.
DropDownAdmin
The possibly entries in a DropDown for an admin.
static void AdminClientBanCallback(Window *, bool confirmed)
Callback function for admin command to ban client.
void DrawCompanyIcon(CompanyID cid, int x, int y)
Draw the icon of a company.
uint32_t _network_join_bytes_total
The total number of bytes to download.
uint32_t _network_join_bytes
The number of bytes we already downloaded.
void ShowNetworkAskSurvey()
Show a modal confirmation window with "no" / "preview" / "yes" buttons.
static CompanyID _admin_company_id
For what company a confirmation window is open.
static ClientID _admin_client_id
For what client a confirmation window is open.
GUIs related to networking.
@ NRWCD_UNHANDLED
Relay request is unhandled.
Definition network_gui.h:42
@ NRWCD_HANDLED
Relay request is handled, either by user or by timeout.
Definition network_gui.h:43
NetworkJoinStatus
Status of the clients during joining.
Server part of the network protocol.
Part of the network protocol handling opt-in survey.
@ DESTTYPE_CLIENT
Send message/notice to only a certain client (Private)
@ DESTTYPE_TEAM
Send message/notice to everyone playing the same company (Team)
static const uint MAX_CLIENTS
How many clients can we have.
ClientID
'Unique' identifier to be given to clients
@ INVALID_CLIENT_ID
Client is not part of anything.
@ CLIENT_ID_SERVER
Servers always have this ID.
ServerGameType
Game type the server can be using.
void NetworkUDPSearchGame()
Find all servers.
Sending and receiving UDP messages.
@ WID_NJS_PROGRESS_BAR
Simple progress bar.
@ WID_NJS_PROGRESS_TEXT
Text explaining what is happening.
@ WID_NJS_CANCELOK
Cancel / OK button.
@ WID_NG_CLIENT
Panel with editbox to set client name.
@ WID_NG_CLIENTS
'Clients' button.
@ WID_NG_SCROLLBAR
Scrollbar of matrix.
@ WID_NG_YEARS
'Years' button.
@ WID_NG_FILTER_LABEL
Label in front of the filter/search edit box.
@ WID_NG_NEWGRF_MISSING_SEL
Selection widget for the above button.
@ WID_NG_SEARCH_INTERNET
'Search internet server' button.
@ WID_NG_NEWGRF_MISSING
'Find missing NewGRF online' button.
@ WID_NG_LASTJOINED_SPACER
Spacer after last joined server panel.
@ WID_NG_DATE
'Date' button.
@ WID_NG_LASTJOINED
Info about the last joined server.
@ WID_NG_MATRIX
Panel with list of games.
@ WID_NG_CLIENT_LABEL
Label in front of client name edit box.
@ WID_NG_NEWGRF_SEL
Selection 'widget' to hide the NewGRF settings.
@ WID_NG_JOIN
'Join game' button.
@ WID_NG_SEARCH_LAN
'Search LAN server' button.
@ WID_NG_MAPSIZE
'Map size' button.
@ WID_NG_START
'Start server' button.
@ WID_NG_DETAILS
Panel with game details.
@ WID_NG_INFO
Third button in the game list panel.
@ WID_NG_NAME
'Name' button.
@ WID_NG_CANCEL
'Cancel' button.
@ WID_NG_ADD
'Add server' button.
@ WID_NG_MAIN
Main panel.
@ WID_NG_REFRESH
'Refresh server' button.
@ WID_NG_FILTER
Panel with the edit box to enter the search text.
@ WID_NG_LASTJOINED_LABEL
Label "Last joined server:".
@ WID_NG_NEWGRF
'NewGRF Settings' button.
ClientListWidgets
Widgets of the NetworkClientListWindow class.
@ WID_CL_CLIENT_NAME_EDIT
Edit button for client name.
@ WID_CL_SERVER_NAME
Server name.
@ WID_CL_SERVER_INVITE_CODE
Invite code for this server.
@ WID_CL_SERVER_NAME_EDIT
Edit button for server name.
@ WID_CL_CLIENT_NAME
Client name.
@ WID_CL_SERVER_SELECTOR
Selector to hide the server frame.
@ WID_CL_SCROLLBAR
Scrollbar for company/client list.
@ WID_CL_CLIENT_COMPANY_COUNT
Count of clients and companies.
@ WID_CL_SERVER_CONNECTION_TYPE
The type of connection the Game Coordinator detected for this server.
@ WID_CL_SERVER_VISIBILITY
Server visibility.
@ WID_CL_MATRIX
Company/client list.
@ WID_NSS_COMPANIES_BTNU
'Max companies' uparrow.
@ WID_NSS_COMPANIES_LABEL
Label for 'max companies'.
@ WID_NSS_CLIENTS_LABEL
Label for 'max clients'.
@ WID_NSS_CLIENTS_TXT
'Max clients' text.
@ WID_NSS_CLIENTS_BTND
'Max clients' downarrow.
@ WID_NSS_GAMENAME
Background for editbox to set game name.
@ WID_NSS_CANCEL
'Cancel' button.
@ WID_NSS_PLAY_HEIGHTMAP
Play heightmap button.
@ WID_NSS_GAMENAME_LABEL
Label for the game name.
@ WID_NSS_LOAD_GAME
Load game button.
@ WID_NSS_GENERATE_GAME
New game button.
@ WID_NSS_CONNTYPE_LABEL
Label for 'connection type'.
@ WID_NSS_CONNTYPE_BTN
'Connection type' droplist button.
@ WID_NSS_COMPANIES_BTND
'Max companies' downarrow.
@ WID_NSS_SETPWD
'Set password' button.
@ WID_NSS_CLIENTS_BTNU
'Max clients' uparrow.
@ WID_NSS_COMPANIES_TXT
'Max companies' text.
@ WID_NSS_BACKGROUND
Background of the window.
@ WID_NSS_PLAY_SCENARIO
Play scenario button.
@ WID_NAR_YES_ALWAYS
"Yes, always" button.
@ WID_NAR_TEXT
Text in the window.
@ WID_NAR_YES_ONCE
"Yes, once" button.
@ WID_NAR_NO
"No" button.
@ WID_NAR_CAPTION
Caption of the window.
@ WID_NAS_YES
"Yes" button.
@ WID_NAS_LINK
"Details & Privacy" button.
@ WID_NAS_TEXT
Text in the window.
@ WID_NAS_CAPTION
Caption of the window.
@ WID_NAS_NO
"No" button.
@ WID_NAS_PREVIEW
"Preview" button.
void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfigList &config)
Setup the NewGRF gui.
@ SM_MENU
Switch to game intro menu.
Definition openttd.h:33
uint8_t GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
Definition palette.cpp:387
static const uint8_t PC_GREY
Grey palette colour.
static const uint8_t PC_DARK_BLUE
Dark blue palette colour.
#define GREY_SCALE(level)
Return the colour for a particular greyscale level.
bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame)
Top function to save the new value of an element of the Settings struct.
static const SettingDesc * GetSettingFromName(const std::string_view name, const SettingTable &settings)
Given a name of setting, return a setting description from the table.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:57
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:607
@ CS_NUMERAL
Only numeric ones.
Definition string_type.h:26
@ CS_ALPHANUMERAL
Both numeric and alphabetic and spaces and stuff.
Definition string_type.h:25
uint64_t GetParamMaxValue(uint64_t max_value, uint min_count, FontSize size)
Get some number that is suitable for string size computations.
Definition strings.cpp:248
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:426
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:56
uint64_t GetParamMaxDigits(uint count, FontSize size)
Get some number that is suitable for string size computations.
Definition strings.cpp:230
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
@ TD_RTL
Text is written right-to-left by default.
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
NetworkSettings network
settings related to the network
Dimensions (a width and height) of a rectangle in 2D.
Information about GRF, used in the game and (part of it) in savegames.
Data structure describing how to show the list (what sort direction and criteria).
Partial widget specification to allow NWidgets to be written nested.
Window used for asking the user if he is okay using a relay server.
void FindWindowPlacementAndResize(int def_width, int def_height) override
Resize window towards the default size.
std::string relay_connection_string
The relay server we want to connect to.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
std::string token
The token for this connection.
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
std::string server_connection_string
The game server we want to connect to.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
Window used for asking if the user wants to participate in the automated survey.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
void FindWindowPlacementAndResize(int def_width, int def_height) override
Resize window towards the default size.
Container for all information known about a client.
static NetworkClientInfo * GetByClientID(ClientID client_id)
Return the CI given it's client-identifier.
Definition network.cpp:116
std::string client_name
Name of the client.
Main handle for clientlist.
Scrollbar * vscroll
Vertical scrollbar of this window.
void OnResize() override
Called after the window got resized.
uint line_count
Amount of lines in the matrix.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
std::map< uint, std::vector< std::unique_ptr< ButtonCommon > > > buttons
Per line which buttons are available.
void DrawButtons(int &x, uint y, const std::vector< std::unique_ptr< ButtonCommon > > &buttons) const
Draw the buttons for a single line in the matrix.
ClientListWidgets query_widget
During a query this tracks what widget caused the query.
void OnDropdownSelect(WidgetID widget, int index) override
A dropdown option associated to this window has been selected.
CompanyID dd_company_id
During admin dropdown, track which company this was for.
void OnMouseOver(Point pt, WidgetID widget) override
The mouse is currently moving over the window or has just moved outside of the window.
int hover_index
Index of the current line we are hovering over, or -1 if none.
bool OnTooltip(Point pt, WidgetID widget, TooltipCloseCondition close_cond) override
Event to display a custom tooltip.
static void OnClickCompanyNew(NetworkClientListWindow *w, Point pt, CompanyID)
Crete new company button is clicked.
void OnDropdownClose(Point pt, WidgetID widget, int index, bool instant_close) override
A dropdown window associated to this window has been closed.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
uint line_height
Current lineheight of each entry in the matrix.
void OnInit() override
Notification that the nested widget tree gets initialized.
static void OnClickCompanyAdmin(NetworkClientListWindow *w, Point pt, CompanyID company_id)
Admin button on a Company is clicked.
static void OnClickCompanyChat(NetworkClientListWindow *w, Point pt, CompanyID company_id)
Chat button on a Company is clicked.
ClientID dd_client_id
During admin dropdown, track which client this was for.
static void OnClickClientChat(NetworkClientListWindow *w, Point pt, ClientID client_id)
Chat button on a Client is clicked.
void RebuildListCompany(CompanyID company_id, CompanyID client_playas, bool can_join_company)
Part of RebuildList() to create the information for a single company.
int player_self_index
The line the current player is on.
void DrawCompany(CompanyID company_id, const Rect &r, uint &line) const
Draw a company and its clients on the matrix.
int player_host_index
The line the host is on.
static void OnClickClientAdmin(NetworkClientListWindow *w, Point pt, ClientID client_id)
Admin button on a Client is clicked.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
ButtonCommon * GetButtonAtPoint(Point pt)
Get the button at a specific point on the WID_CL_MATRIX.
static void OnClickCompanyJoin(NetworkClientListWindow *w, Point pt, CompanyID company_id)
Join button on a Company is clicked.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void RebuildList()
Rebuild the list, meaning: calculate the lines needed and what buttons go on which line.
bool version_compatible
Can we connect to this server or not? (based on server_revision)
bool compatible
Can we connect to this server or not? (based on server_revision and grf_match.
Structure with information shown in the game list (GUI)
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.
GRFConfigList grfconfig
List of NewGRF files used.
uint16_t map_height
Map height.
std::string server_name
Server name.
uint16_t map_width
Map width.
TimerGameTick::TickCounter ticks_playing
Amount of ticks the game has been running unpaused.
LandscapeType landscape
The used landscape.
uint8_t companies_max
Max companies allowed on server.
std::string gamescript_name
Name of the gamescript.
TimerGameCalendar::Date calendar_date
Current calendar date.
int gamescript_version
Version of the gamescript.
uint8_t companies_on
How many started companies do we have.
uint8_t clients_on
Current count of clients on server.
uint8_t max_clients
maximum amount of clients
uint8_t max_companies
maximum amount of companies
std::string client_name
name of the player (as client)
ServerGameType server_game_type
Server type: local / public / invite-only.
UseRelayService use_relay_service
Use relay service?
std::string connect_to_ip
default for the "Add server" query
std::string last_joined
Last joined server.
std::string server_name
name of the server
std::string server_password
password for joining this server
ParticipateSurvey participate_survey
Participate in the automated survey.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
WidgetID widget_id
The widget that has the pop-up input menu.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnDropdownSelect(WidgetID widget, int index) override
A dropdown option associated to this window has been selected.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
QueryString name_editbox
Server name editbox.
void OnTimeout() override
Called when this window's timeout has been reached.
Coordinates of a point in 2D.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * Get(auto index)
Returns Titem with given index.
static size_t GetNumItems()
Returns number of valid items in the pool.
Data stored about a string that can be modified in the GUI.
int cancel_button
Widget button of parent window to simulate when pressing CANCEL in OSK.
static const int ACTION_CLEAR
Clear editbox.
constexpr uint Horizontal() const
Get total horizontal padding of RectPadding.
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Specification of a rectangle with absolute coordinates of all edges.
Rect WithWidth(int width, bool end) const
Copy Rect and set its width.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Rect WithHeight(int height, bool end=false) const
Copy Rect and set its height.
Rect Indent(int indent, bool end) const
Copy Rect and indent it from its position.
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
uint step_height
Step-size of height resize changes.
Definition window_gui.h:213
String filter and state.
bool IsEmpty() const
Check whether any filter words were entered.
void SetFilterTerm(std::string_view str)
Set the term to filter on.
void ResetState()
Reset the matching state to process a new item.
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(const std::string_view text)
Copy a string into the textbuffer.
Definition textbuf.cpp:422
const char * GetText() const
Get the current text.
Definition textbuf.cpp:286
Window for displaying a textfile.
void LoadText(std::string_view buf)
Load a text into the textfile viewer.
TextfileType file_type
Type of textfile to view.
Container with the data associated to a single widget.
High level window description.
Definition window_gui.h:168
Number to differentiate different windows of the same class.
Data structure for an opened window.
Definition window_gui.h:274
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition window.cpp:955
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1050
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition widget.cpp:793
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1736
std::map< WidgetID, QueryString * > querystrings
QueryString associated to WWT_EDITBOX widgets.
Definition window_gui.h:321
void DrawWidgets() const
Paint all widgets of a window.
Definition widget.cpp:744
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition window.cpp:3164
Window * parent
Parent window.
Definition window_gui.h:329
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:554
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:502
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
Definition widget.cpp:776
ResizeInfo resize
Resize information.
Definition window_gui.h:315
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1726
bool SetFocusedWidget(WidgetID widget_index)
Set focus within this window to the given widget.
Definition window.cpp:483
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:284
bool IsWidgetDisabled(WidgetID widget_index) const
Gets the enabled/disabled status of a widget.
Definition window_gui.h:411
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition window_gui.h:442
int left
x position of left edge of the window
Definition window_gui.h:310
void RaiseWidgetsWhenLowered(Args... widgets)
Raises the widgets and sets widgets dirty that are lowered.
Definition window_gui.h:537
int top
y position of top edge of the window
Definition window_gui.h:311
int GetRowFromWidget(int clickpos, WidgetID widget, int padding, int line_height=-1) const
Compute the row of a widget that a user clicked in.
Definition window.cpp:210
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:973
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:593
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1749
WindowFlags flags
Window flags.
Definition window_gui.h:301
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:311
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:382
int height
Height of the window (number of pixels down in y direction)
Definition window_gui.h:313
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:312
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:303
@ CONNECTION_TYPE_UNKNOWN
The Game Coordinator hasn't informed us yet what type of connection we have.
@ AcceptUnchanged
return success even when the text didn't change
@ LengthIsInChars
the length of the string is counted in characters
void QueryCallbackProc(Window *, bool)
Callback procedure for the ShowQuery method.
Definition textbuf_gui.h:27
TextfileType
Additional text files accompanying Tar archives.
@ TFT_SURVEY_RESULT
Survey result (preview)
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition widget.cpp:296
static RectPadding ScaleGUITrad(const RectPadding &r)
Scale a RectPadding to GUI zoom level.
Definition widget.cpp:48
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ WWT_IMGBTN
(Toggle) Button with image
Definition widget_type.h:42
@ WWT_PUSHIMGBTN
Normal push-button (no toggle button) with image caption.
@ NWID_SPACER
Invisible widget that takes some space.
Definition widget_type.h:69
@ WWT_EDITBOX
a textbox for typing
Definition widget_type.h:61
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:65
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:40
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition widget_type.h:56
@ WWT_MATRIX
Grid of rows and columns.
Definition widget_type.h:49
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:51
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:75
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:67
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:59
@ WWT_FRAME
Frame.
Definition widget_type.h:50
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:38
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:58
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:55
@ WWT_DROPDOWN
Drop down list.
Definition widget_type.h:60
@ WWT_TEXT
Pure simple text.
Definition widget_type.h:48
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition widget_type.h:70
@ SZSP_HORIZONTAL
Display plane with zero size vertically, and filling and resizing horizontally.
@ SZSP_NONE
Display plane with zero size in both directions (none filling and resizing).
@ EqualSize
Containers should keep all their (resizing) children equally large.
SizingType
Different forms of sizing nested widgets, using NWidgetBase::AssignSizePosition()
@ RWV_HIDE_BEVEL
Bevel of resize box is hidden.
Definition widget_type.h:30
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition window.cpp:1143
Window * GetMainWindow()
Get the main window, i.e.
Definition window.cpp:1130
void CloseWindowByClass(WindowClass cls, int data)
Close all windows of a given class.
Definition window.cpp:1155
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
Definition window.cpp:3224
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1101
@ Modal
The window is a modal child of some other window, meaning the parent is 'inactive'.
@ BorderOnly
Draw border only, no background.
@ Lowered
If set the frame is lowered and the background colour brighter (ie. buttons when pressed)
@ Timeout
Window timeout counter.
@ SBS_DOWN
Sort ascending.
Definition window_gui.h:219
@ SBS_UP
Sort descending.
Definition window_gui.h:220
@ WDP_CENTER
Center the window.
Definition window_gui.h:146
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:145
int WidgetID
Widget ID.
Definition window_type.h:20
@ WN_NETWORK_STATUS_WINDOW_JOIN
Network join status.
Definition window_type.h:41
@ WN_NETWORK_WINDOW_GAME
Network game window.
Definition window_type.h:37
@ WN_NETWORK_WINDOW_START
Network start server.
Definition window_type.h:39
EventState
State of handling an event.
@ ES_HANDLED
The passed event is handled.
@ ES_NOT_HANDLED
The passed event is not handled.
@ WC_NETWORK_ASK_RELAY
Network ask relay window; Window numbers:
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:47
@ WC_CLIENT_LIST
Client list; Window numbers:
@ WC_NETWORK_WINDOW
Network window; Window numbers:
@ WC_TEXTFILE
textfile; Window numbers:
@ WC_NETWORK_STATUS_WINDOW
Network status window; Window numbers:
@ WC_NETWORK_ASK_SURVEY
Network ask survey window; Window numbers: