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