OpenTTD
network_gui.cpp
Go to the documentation of this file.
1 /* $Id$ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * 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.
6  * 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.
7  * 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/>.
8  */
9 
12 #include "../stdafx.h"
13 #include "../strings_func.h"
14 #include "../date_func.h"
15 #include "../fios.h"
16 #include "network_client.h"
17 #include "network_gui.h"
18 #include "network_gamelist.h"
19 #include "network.h"
20 #include "network_base.h"
21 #include "network_content.h"
22 #include "../gui.h"
23 #include "network_udp.h"
24 #include "../window_func.h"
25 #include "../gfx_func.h"
26 #include "../widgets/dropdown_func.h"
27 #include "../querystring_gui.h"
28 #include "../sortlist_type.h"
29 #include "../company_func.h"
30 #include "../core/geometry_func.hpp"
31 #include "../genworld.h"
32 #include "../map_type.h"
33 #include "../guitimer_func.h"
34 
35 #include "../widgets/network_widget.h"
36 
37 #include "table/strings.h"
38 #include "../table/sprites.h"
39 
40 #include "../stringfilter_type.h"
41 
42 #include "../safeguards.h"
43 
44 
45 static void ShowNetworkStartServerWindow();
46 static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
47 
52  STR_NETWORK_START_SERVER_UNADVERTISED,
53  STR_NETWORK_START_SERVER_ADVERTISED,
55 };
56 
61  STR_NETWORK_SERVER_LIST_ADVERTISED_NO,
62  STR_NETWORK_SERVER_LIST_ADVERTISED_YES,
64 };
65 
66 static std::vector<StringID> _language_dropdown;
67 
68 void SortNetworkLanguages()
69 {
70  /* Init the strings */
71  if (_language_dropdown.empty()) {
72  for (int i = 0; i < NETLANG_COUNT; i++) _language_dropdown.emplace_back(STR_NETWORK_LANG_ANY + i);
73  _language_dropdown.emplace_back(INVALID_STRING_ID);
74  }
75 
76  /* Sort the strings (we don't move 'any' and the 'invalid' one) */
77  std::sort(_language_dropdown.begin() + 1, _language_dropdown.end() - 1, StringIDSorter);
78 }
79 
85 {
87 }
88 
90 typedef uint16 ServerListPosition;
91 static const ServerListPosition SLP_INVALID = 0xFFFF;
92 
95  static const uint MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER = 150;
96  bool visible[6];
97 public:
99  {
100  NWidgetLeaf *leaf = new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NAME, STR_NETWORK_SERVER_LIST_GAME_NAME, STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP);
101  leaf->SetResize(1, 0);
102  leaf->SetFill(1, 0);
103  this->Add(leaf);
104 
105  this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CLIENTS, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP));
106  this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_MAPSIZE, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP));
107  this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_DATE, STR_NETWORK_SERVER_LIST_DATE_CAPTION, STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP));
108  this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_YEARS, STR_NETWORK_SERVER_LIST_YEARS_CAPTION, STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP));
109 
110  leaf = new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_INFO, STR_EMPTY, STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP);
111  leaf->SetMinimalSize(14 + GetSpriteSize(SPR_LOCK).width + GetSpriteSize(SPR_BLOT).width + GetSpriteSize(SPR_FLAGS_BASE).width, 12);
112  leaf->SetFill(0, 1);
113  this->Add(leaf);
114 
115  /* First and last are always visible, the rest is implicitly zeroed */
116  this->visible[0] = true;
117  *lastof(this->visible) = true;
118  }
119 
120  void SetupSmallestSize(Window *w, bool init_array) override
121  {
122  /* Oh yeah, we ought to be findable! */
123  w->nested_array[WID_NG_HEADER] = this;
124 
125  this->smallest_y = 0; // Biggest child.
126  this->fill_x = 1;
127  this->fill_y = 0;
128  this->resize_x = 1; // We only resize in this direction
129  this->resize_y = 0; // We never resize in this direction
130 
131  /* First initialise some variables... */
132  for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
133  child_wid->SetupSmallestSize(w, init_array);
134  this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom);
135  }
136 
137  /* ... then in a second pass make sure the 'current' sizes are set. Won't change for most widgets. */
138  for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
139  child_wid->current_x = child_wid->smallest_x;
140  child_wid->current_y = this->smallest_y;
141  }
142 
143  this->smallest_x = this->head->smallest_x + this->tail->smallest_x; // First and last are always shown, rest not
144  }
145 
146  void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override
147  {
148  assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
149 
150  this->pos_x = x;
151  this->pos_y = y;
152  this->current_x = given_width;
153  this->current_y = given_height;
154 
155  given_width -= this->tail->smallest_x;
156  NWidgetBase *child_wid = this->head->next;
157  /* The first and last widget are always visible, determine which other should be visible */
158  for (uint i = 1; i < lengthof(this->visible) - 1; i++) {
159  if (given_width > MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER + child_wid->smallest_x && this->visible[i - 1]) {
160  this->visible[i] = true;
161  given_width -= child_wid->smallest_x;
162  } else {
163  this->visible[i] = false;
164  }
165  child_wid = child_wid->next;
166  }
167 
168  /* All remaining space goes to the first (name) widget */
169  this->head->current_x = given_width;
170 
171  /* Now assign the widgets to their rightful place */
172  uint position = 0; // Place to put next child relative to origin of the container.
173  uint i = rtl ? lengthof(this->visible) - 1 : 0;
174  child_wid = rtl ? this->tail : this->head;
175  while (child_wid != nullptr) {
176  if (this->visible[i]) {
177  child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl);
178  position += child_wid->current_x;
179  }
180 
181  child_wid = rtl ? child_wid->prev : child_wid->next;
182  i += rtl ? -1 : 1;
183  }
184  }
185 
186  void Draw(const Window *w) override
187  {
188  int i = 0;
189  for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
190  if (!this->visible[i++]) continue;
191 
192  child_wid->Draw(w);
193  }
194  }
195 
196  NWidgetCore *GetWidgetFromPos(int x, int y) override
197  {
198  if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return nullptr;
199 
200  int i = 0;
201  for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
202  if (!this->visible[i++]) continue;
203  NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y);
204  if (nwid != nullptr) return nwid;
205  }
206  return nullptr;
207  }
208 
215  {
216  assert((uint)(widget - WID_NG_NAME) < lengthof(this->visible));
217  return this->visible[widget - WID_NG_NAME];
218  }
219 };
220 
221 class NetworkGameWindow : public Window {
222 protected:
223  /* Runtime saved values */
224  static Listing last_sorting;
225 
226  /* Constants for sorting servers */
227  static GUIGameServerList::SortFunction * const sorter_funcs[];
228  static GUIGameServerList::FilterFunction * const filter_funcs[];
229 
233  ServerListPosition list_pos;
238 
242 
249  {
250  if (!this->servers.NeedRebuild()) return;
251 
252  /* Create temporary array of games to use for listing */
253  this->servers.clear();
254 
255  for (NetworkGameList *ngl = _network_game_list; ngl != nullptr; ngl = ngl->next) {
256  this->servers.push_back(ngl);
257  }
258 
259  /* Apply the filter condition immediately, if a search string has been provided. */
260  StringFilter sf;
261  sf.SetFilterTerm(this->filter_editbox.text.buf);
262 
263  if (!sf.IsEmpty()) {
264  this->servers.SetFilterState(true);
265  this->servers.Filter(sf);
266  } else {
267  this->servers.SetFilterState(false);
268  }
269 
270  this->servers.shrink_to_fit();
271  this->servers.RebuildDone();
272  this->vscroll->SetCount((int)this->servers.size());
273 
274  /* Sort the list of network games as requested. */
275  this->servers.Sort();
276  this->UpdateListPos();
277  }
278 
280  static bool NGameNameSorter(NetworkGameList * const &a, NetworkGameList * const &b)
281  {
282  int r = strnatcmp(a->info.server_name, b->info.server_name, true); // Sort by name (natural sorting).
283  return r == 0 ? a->address.CompareTo(b->address) < 0: r < 0;
284  }
285 
291  static bool NGameClientSorter(NetworkGameList * const &a, NetworkGameList * const &b)
292  {
293  /* Reverse as per default we are interested in most-clients first */
294  int r = a->info.clients_on - b->info.clients_on;
295 
296  if (r == 0) r = a->info.clients_max - b->info.clients_max;
297  if (r == 0) return NGameNameSorter(a, b);
298 
299  return r < 0;
300  }
301 
303  static bool NGameMapSizeSorter(NetworkGameList * const &a, NetworkGameList * const &b)
304  {
305  /* Sort by the area of the map. */
306  int r = (a->info.map_height) * (a->info.map_width) - (b->info.map_height) * (b->info.map_width);
307 
308  if (r == 0) r = a->info.map_width - b->info.map_width;
309  return (r != 0) ? r < 0 : NGameClientSorter(a, b);
310  }
311 
313  static bool NGameDateSorter(NetworkGameList * const &a, NetworkGameList * const &b)
314  {
315  int r = a->info.game_date - b->info.game_date;
316  return (r != 0) ? r < 0 : NGameClientSorter(a, b);
317  }
318 
320  static bool NGameYearsSorter(NetworkGameList * const &a, NetworkGameList * const &b)
321  {
322  int r = a->info.game_date - a->info.start_date - b->info.game_date + b->info.start_date;
323  return (r != 0) ? r < 0: NGameDateSorter(a, b);
324  }
325 
330  static bool NGameAllowedSorter(NetworkGameList * const &a, NetworkGameList * const &b)
331  {
332  /* The servers we do not know anything about (the ones that did not reply) should be at the bottom) */
334 
335  /* Reverse default as we are interested in version-compatible clients first */
336  if (r == 0) r = b->info.version_compatible - a->info.version_compatible;
337  /* The version-compatible ones are then sorted with NewGRF compatible first, incompatible last */
338  if (r == 0) r = b->info.compatible - a->info.compatible;
339  /* Passworded servers should be below unpassworded servers */
340  if (r == 0) r = a->info.use_password - b->info.use_password;
341  /* Finally sort on the number of clients of the server */
342  if (r == 0) return NGameClientSorter(a, b);
343 
344  return r < 0;
345  }
346 
349  {
350  if (this->servers.Sort()) this->UpdateListPos();
351  }
352 
355  {
356  this->list_pos = SLP_INVALID;
357  for (uint i = 0; i != this->servers.size(); i++) {
358  if (this->servers[i] == this->server) {
359  this->list_pos = i;
360  break;
361  }
362  }
363  }
364 
365  static bool CDECL NGameSearchFilter(NetworkGameList * const *item, StringFilter &sf)
366  {
367  assert(item != nullptr);
368  assert((*item) != nullptr);
369 
370  sf.ResetState();
371  sf.AddLine((*item)->info.server_name);
372  return sf.GetState();
373  }
374 
381  void DrawServerLine(const NetworkGameList *cur_item, uint y, bool highlight) const
382  {
383  const NWidgetBase *nwi_name = this->GetWidget<NWidgetBase>(WID_NG_NAME);
384  const NWidgetBase *nwi_info = this->GetWidget<NWidgetBase>(WID_NG_INFO);
385 
386  /* show highlighted item with a different colour */
387  if (highlight) GfxFillRect(nwi_name->pos_x + 1, y + 1, nwi_info->pos_x + nwi_info->current_x - 2, y + this->resize.step_height - 2, PC_GREY);
388 
389  /* offsets to vertically centre text and icons */
390  int text_y_offset = (this->resize.step_height - FONT_HEIGHT_NORMAL) / 2 + 1;
391  int icon_y_offset = (this->resize.step_height - GetSpriteSize(SPR_BLOT).height) / 2;
392 
393  DrawString(nwi_name->pos_x + WD_FRAMERECT_LEFT, nwi_name->pos_x + nwi_name->current_x - WD_FRAMERECT_RIGHT, y + text_y_offset, cur_item->info.server_name, TC_BLACK);
394 
395  /* only draw details if the server is online */
396  if (cur_item->online) {
397  const NWidgetServerListHeader *nwi_header = this->GetWidget<NWidgetServerListHeader>(WID_NG_HEADER);
398 
399  if (nwi_header->IsWidgetVisible(WID_NG_CLIENTS)) {
400  const NWidgetBase *nwi_clients = this->GetWidget<NWidgetBase>(WID_NG_CLIENTS);
401  SetDParam(0, cur_item->info.clients_on);
402  SetDParam(1, cur_item->info.clients_max);
403  SetDParam(2, cur_item->info.companies_on);
404  SetDParam(3, cur_item->info.companies_max);
405  DrawString(nwi_clients->pos_x, nwi_clients->pos_x + nwi_clients->current_x - 1, y + text_y_offset, STR_NETWORK_SERVER_LIST_GENERAL_ONLINE, TC_FROMSTRING, SA_HOR_CENTER);
406  }
407 
408  if (nwi_header->IsWidgetVisible(WID_NG_MAPSIZE)) {
409  /* map size */
410  const NWidgetBase *nwi_mapsize = this->GetWidget<NWidgetBase>(WID_NG_MAPSIZE);
411  SetDParam(0, cur_item->info.map_width);
412  SetDParam(1, cur_item->info.map_height);
413  DrawString(nwi_mapsize->pos_x, nwi_mapsize->pos_x + nwi_mapsize->current_x - 1, y + text_y_offset, STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT, TC_FROMSTRING, SA_HOR_CENTER);
414  }
415 
416  if (nwi_header->IsWidgetVisible(WID_NG_DATE)) {
417  /* current date */
418  const NWidgetBase *nwi_date = this->GetWidget<NWidgetBase>(WID_NG_DATE);
419  YearMonthDay ymd;
420  ConvertDateToYMD(cur_item->info.game_date, &ymd);
421  SetDParam(0, ymd.year);
422  DrawString(nwi_date->pos_x, nwi_date->pos_x + nwi_date->current_x - 1, y + text_y_offset, STR_JUST_INT, TC_BLACK, SA_HOR_CENTER);
423  }
424 
425  if (nwi_header->IsWidgetVisible(WID_NG_YEARS)) {
426  /* number of years the game is running */
427  const NWidgetBase *nwi_years = this->GetWidget<NWidgetBase>(WID_NG_YEARS);
428  YearMonthDay ymd_cur, ymd_start;
429  ConvertDateToYMD(cur_item->info.game_date, &ymd_cur);
430  ConvertDateToYMD(cur_item->info.start_date, &ymd_start);
431  SetDParam(0, ymd_cur.year - ymd_start.year);
432  DrawString(nwi_years->pos_x, nwi_years->pos_x + nwi_years->current_x - 1, y + text_y_offset, STR_JUST_INT, TC_BLACK, SA_HOR_CENTER);
433  }
434 
435  /* draw a lock if the server is password protected */
436  if (cur_item->info.use_password) DrawSprite(SPR_LOCK, PAL_NONE, nwi_info->pos_x + this->lock_offset, y + icon_y_offset - 1);
437 
438  /* draw red or green icon, depending on compatibility with server */
439  DrawSprite(SPR_BLOT, (cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED)), nwi_info->pos_x + this->blot_offset, y + icon_y_offset);
440 
441  /* draw flag according to server language */
442  DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, PAL_NONE, nwi_info->pos_x + this->flag_offset, y + icon_y_offset);
443  }
444  }
445 
454  {
455  if (this->list_pos == SLP_INVALID) return; // no server selected
456  this->vscroll->ScrollTowards(this->list_pos);
457  }
458 
459 public:
460  NetworkGameWindow(WindowDesc *desc) : Window(desc), name_editbox(NETWORK_CLIENT_NAME_LENGTH), filter_editbox(120)
461  {
462  this->list_pos = SLP_INVALID;
463  this->server = nullptr;
464 
465  this->lock_offset = 5;
466  this->blot_offset = this->lock_offset + 3 + GetSpriteSize(SPR_LOCK).width;
467  this->flag_offset = this->blot_offset + 2 + GetSpriteSize(SPR_BLOT).width;
468 
469  this->CreateNestedTree();
470  this->vscroll = this->GetScrollbar(WID_NG_SCROLLBAR);
471  this->FinishInitNested(WN_NETWORK_WINDOW_GAME);
472 
473  this->querystrings[WID_NG_CLIENT] = &this->name_editbox;
474  this->name_editbox.text.Assign(_settings_client.network.client_name);
475 
476  this->querystrings[WID_NG_FILTER] = &this->filter_editbox;
477  this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
478  this->SetFocusedWidget(WID_NG_FILTER);
479 
481  this->server = this->last_joined;
482  if (this->last_joined != nullptr) NetworkUDPQueryServer(this->last_joined->address);
483 
484  this->requery_timer.SetInterval(MILLISECONDS_PER_TICK);
485 
486  this->servers.SetListing(this->last_sorting);
487  this->servers.SetSortFuncs(this->sorter_funcs);
488  this->servers.SetFilterFuncs(this->filter_funcs);
489  this->servers.ForceRebuild();
490  }
491 
493  {
494  this->last_sorting = this->servers.GetListing();
495  }
496 
497  void SetStringParameters(int widget) const override
498  {
499  switch (widget) {
500  case WID_NG_CONN_BTN:
502  break;
503  }
504  }
505 
506  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
507  {
508  switch (widget) {
509  case WID_NG_CONN_BTN:
511  size->width += padding.width;
512  size->height += padding.height;
513  break;
514 
515  case WID_NG_MATRIX:
516  resize->height = WD_MATRIX_TOP + max(GetSpriteSize(SPR_BLOT).height, (uint)FONT_HEIGHT_NORMAL) + WD_MATRIX_BOTTOM;
517  size->height = 10 * resize->height;
518  break;
519 
520  case WID_NG_LASTJOINED:
521  size->height = WD_MATRIX_TOP + max(GetSpriteSize(SPR_BLOT).height, (uint)FONT_HEIGHT_NORMAL) + WD_MATRIX_BOTTOM;
522  break;
523 
525  size->width = NWidgetScrollbar::GetVerticalDimension().width;
526  break;
527 
528  case WID_NG_NAME:
529  size->width += 2 * Window::SortButtonWidth(); // Make space for the arrow
530  break;
531 
532  case WID_NG_CLIENTS:
533  size->width += 2 * Window::SortButtonWidth(); // Make space for the arrow
538  *size = maxdim(*size, GetStringBoundingBox(STR_NETWORK_SERVER_LIST_GENERAL_ONLINE));
539  break;
540 
541  case WID_NG_MAPSIZE:
542  size->width += 2 * Window::SortButtonWidth(); // Make space for the arrow
545  *size = maxdim(*size, GetStringBoundingBox(STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT));
546  break;
547 
548  case WID_NG_DATE:
549  case WID_NG_YEARS:
550  size->width += 2 * Window::SortButtonWidth(); // Make space for the arrow
551  SetDParamMaxValue(0, 5);
552  *size = maxdim(*size, GetStringBoundingBox(STR_JUST_INT));
553  break;
554 
556  size->height = 20 + 12 * FONT_HEIGHT_NORMAL;
557  break;
558  }
559  }
560 
561  void DrawWidget(const Rect &r, int widget) const override
562  {
563  switch (widget) {
564  case WID_NG_MATRIX: {
565  uint16 y = r.top;
566 
567  const int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (int)this->servers.size());
568 
569  for (int i = this->vscroll->GetPosition(); i < max; ++i) {
570  const NetworkGameList *ngl = this->servers[i];
571  this->DrawServerLine(ngl, y, ngl == this->server);
572  y += this->resize.step_height;
573  }
574  break;
575  }
576 
577  case WID_NG_LASTJOINED:
578  /* Draw the last joined server, if any */
579  if (this->last_joined != nullptr) this->DrawServerLine(this->last_joined, r.top, this->last_joined == this->server);
580  break;
581 
582  case WID_NG_DETAILS:
583  this->DrawDetails(r);
584  break;
585 
586  case WID_NG_NAME:
587  case WID_NG_CLIENTS:
588  case WID_NG_MAPSIZE:
589  case WID_NG_DATE:
590  case WID_NG_YEARS:
591  case WID_NG_INFO:
592  if (widget - WID_NG_NAME == this->servers.SortType()) this->DrawSortButtonState(widget, this->servers.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
593  break;
594  }
595  }
596 
597 
598  void OnPaint() override
599  {
600  if (this->servers.NeedRebuild()) {
601  this->BuildGUINetworkGameList();
602  }
603  if (this->servers.NeedResort()) {
604  this->SortNetworkGameList();
605  }
606 
607  NetworkGameList *sel = this->server;
608  /* 'Refresh' button invisible if no server selected */
609  this->SetWidgetDisabledState(WID_NG_REFRESH, sel == nullptr);
610  /* 'Join' button disabling conditions */
611  this->SetWidgetDisabledState(WID_NG_JOIN, sel == nullptr || // no Selected Server
612  !sel->online || // Server offline
613  sel->info.clients_on >= sel->info.clients_max || // Server full
614  !sel->info.compatible); // Revision mismatch
615 
616  /* 'NewGRF Settings' button invisible if no NewGRF is used */
617  this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == nullptr || !sel->online || sel->info.grfconfig == nullptr);
618  this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_MISSING_SEL)->SetDisplayedPlane(sel == nullptr || !sel->online || sel->info.grfconfig == nullptr || !sel->info.version_compatible || sel->info.compatible);
619 
620  this->DrawWidgets();
621  }
622 
623  void DrawDetails(const Rect &r) const
624  {
625  NetworkGameList *sel = this->server;
626 
627  const int detail_height = 6 + 8 + 6 + 3 * FONT_HEIGHT_NORMAL;
628 
629  /* Draw the right menu */
630  GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.top + detail_height - 1, PC_DARK_BLUE);
631  if (sel == nullptr) {
632  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 4 + FONT_HEIGHT_NORMAL, STR_NETWORK_SERVER_LIST_GAME_INFO, TC_FROMSTRING, SA_HOR_CENTER);
633  } else if (!sel->online) {
634  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 4 + FONT_HEIGHT_NORMAL, sel->info.server_name, TC_ORANGE, SA_HOR_CENTER); // game name
635 
636  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + detail_height + 4, STR_NETWORK_SERVER_LIST_SERVER_OFFLINE, TC_FROMSTRING, SA_HOR_CENTER); // server offline
637  } else { // show game info
638 
639  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6, STR_NETWORK_SERVER_LIST_GAME_INFO, TC_FROMSTRING, SA_HOR_CENTER);
640  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 4 + FONT_HEIGHT_NORMAL, sel->info.server_name, TC_ORANGE, SA_HOR_CENTER); // game name
641  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 8 + 2 * FONT_HEIGHT_NORMAL, sel->info.map_name, TC_BLACK, SA_HOR_CENTER); // map name
642 
643  uint16 y = r.top + detail_height + 4;
644 
645  SetDParam(0, sel->info.clients_on);
646  SetDParam(1, sel->info.clients_max);
647  SetDParam(2, sel->info.companies_on);
648  SetDParam(3, sel->info.companies_max);
649  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CLIENTS);
650  y += FONT_HEIGHT_NORMAL;
651 
652  SetDParam(0, STR_NETWORK_LANG_ANY + sel->info.server_lang);
653  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_LANGUAGE); // server language
654  y += FONT_HEIGHT_NORMAL;
655 
656  SetDParam(0, STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE + sel->info.map_set);
657  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_LANDSCAPE); // landscape
658  y += FONT_HEIGHT_NORMAL;
659 
660  SetDParam(0, sel->info.map_width);
661  SetDParam(1, sel->info.map_height);
662  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_MAP_SIZE); // map size
663  y += FONT_HEIGHT_NORMAL;
664 
666  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_VERSION); // server version
667  y += FONT_HEIGHT_NORMAL;
668 
670  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_ADDRESS); // server address
671  y += FONT_HEIGHT_NORMAL;
672 
673  SetDParam(0, sel->info.start_date);
674  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_START_DATE); // start date
675  y += FONT_HEIGHT_NORMAL;
676 
677  SetDParam(0, sel->info.game_date);
678  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CURRENT_DATE); // current date
679  y += FONT_HEIGHT_NORMAL;
680 
681  y += WD_PAR_VSEP_NORMAL;
682 
683  if (!sel->info.compatible) {
684  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, sel->info.version_compatible ? STR_NETWORK_SERVER_LIST_GRF_MISMATCH : STR_NETWORK_SERVER_LIST_VERSION_MISMATCH, TC_FROMSTRING, SA_HOR_CENTER); // server mismatch
685  } else if (sel->info.clients_on == sel->info.clients_max) {
686  /* Show: server full, when clients_on == max_clients */
687  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_FULL, TC_FROMSTRING, SA_HOR_CENTER); // server full
688  } else if (sel->info.use_password) {
689  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_PASSWORD, TC_FROMSTRING, SA_HOR_CENTER); // password warning
690  }
691  }
692  }
693 
694  void OnClick(Point pt, int widget, int click_count) override
695  {
696  switch (widget) {
697  case WID_NG_CANCEL: // Cancel button
699  break;
700 
701  case WID_NG_CONN_BTN: // 'Connection' droplist
702  ShowDropDownMenu(this, _lan_internet_types_dropdown, _settings_client.network.lan_internet, WID_NG_CONN_BTN, 0, 0); // do it for widget WID_NSS_CONN_BTN
703  break;
704 
705  case WID_NG_NAME: // Sort by name
706  case WID_NG_CLIENTS: // Sort by connected clients
707  case WID_NG_MAPSIZE: // Sort by map size
708  case WID_NG_DATE: // Sort by date
709  case WID_NG_YEARS: // Sort by years
710  case WID_NG_INFO: // Connectivity (green dot)
711  if (this->servers.SortType() == widget - WID_NG_NAME) {
712  this->servers.ToggleSortOrder();
713  if (this->list_pos != SLP_INVALID) this->list_pos = (ServerListPosition)this->servers.size() - this->list_pos - 1;
714  } else {
715  this->servers.SetSortType(widget - WID_NG_NAME);
716  this->servers.ForceResort();
717  this->SortNetworkGameList();
718  }
719  this->ScrollToSelectedServer();
720  this->SetDirty();
721  break;
722 
723  case WID_NG_MATRIX: { // Show available network games
724  uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NG_MATRIX);
725  this->server = (id_v < this->servers.size()) ? this->servers[id_v] : nullptr;
726  this->list_pos = (server == nullptr) ? SLP_INVALID : id_v;
727  this->SetDirty();
728 
729  /* FIXME the disabling should go into some InvalidateData, which is called instead of the SetDirty */
730  if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
731  break;
732  }
733 
734  case WID_NG_LASTJOINED: {
735  if (this->last_joined != nullptr) {
736  this->server = this->last_joined;
737 
738  /* search the position of the newly selected server */
739  this->UpdateListPos();
740  this->ScrollToSelectedServer();
741  this->SetDirty();
742 
743  /* FIXME the disabling should go into some InvalidateData, which is called instead of the SetDirty */
744  if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
745  }
746  break;
747  }
748 
749  case WID_NG_FIND: // Find server automatically
751  case 0: NetworkUDPSearchGame(); break;
752  case 1: NetworkUDPQueryMasterServer(); break;
753  }
754  break;
755 
756  case WID_NG_ADD: // Add a server
759  STR_JUST_RAW_STRING,
760  STR_NETWORK_SERVER_LIST_ENTER_IP,
761  NETWORK_HOSTNAME_LENGTH, // maximum number of characters including '\0'
763  break;
764 
765  case WID_NG_START: // Start server
766  ShowNetworkStartServerWindow();
767  break;
768 
769  case WID_NG_JOIN: // Join Game
770  if (this->server != nullptr) {
771  seprintf(_settings_client.network.last_host, lastof(_settings_client.network.last_host), "%s", this->server->address.GetHostname());
773  ShowNetworkLobbyWindow(this->server);
774  }
775  break;
776 
777  case WID_NG_REFRESH: // Refresh
778  if (this->server != nullptr) NetworkUDPQueryServer(this->server->address);
779  break;
780 
781  case WID_NG_NEWGRF: // NewGRF Settings
782  if (this->server != nullptr) ShowNewGRFSettings(false, false, false, &this->server->info.grfconfig);
783  break;
784 
785  case WID_NG_NEWGRF_MISSING: // Find missing content online
786  if (this->server != nullptr) ShowMissingContentWindow(this->server->info.grfconfig);
787  break;
788  }
789  }
790 
791  void OnDropdownSelect(int widget, int index) override
792  {
793  switch (widget) {
794  case WID_NG_CONN_BTN:
796  break;
797 
798  default:
799  NOT_REACHED();
800  }
801 
802  this->SetDirty();
803  }
804 
810  void OnInvalidateData(int data = 0, bool gui_scope = true) override
811  {
812  this->servers.ForceRebuild();
813  this->SetDirty();
814  }
815 
816  EventState OnKeyPress(WChar key, uint16 keycode) override
817  {
818  EventState state = ES_NOT_HANDLED;
819 
820  /* handle up, down, pageup, pagedown, home and end */
821  if (keycode == WKC_UP || keycode == WKC_DOWN || keycode == WKC_PAGEUP || keycode == WKC_PAGEDOWN || keycode == WKC_HOME || keycode == WKC_END) {
822  if (this->servers.size() == 0) return ES_HANDLED;
823  switch (keycode) {
824  case WKC_UP:
825  /* scroll up by one */
826  if (this->list_pos == SLP_INVALID) return ES_HANDLED;
827  if (this->list_pos > 0) this->list_pos--;
828  break;
829  case WKC_DOWN:
830  /* scroll down by one */
831  if (this->list_pos == SLP_INVALID) return ES_HANDLED;
832  if (this->list_pos < this->servers.size() - 1) this->list_pos++;
833  break;
834  case WKC_PAGEUP:
835  /* scroll up a page */
836  if (this->list_pos == SLP_INVALID) return ES_HANDLED;
837  this->list_pos = (this->list_pos < this->vscroll->GetCapacity()) ? 0 : this->list_pos - this->vscroll->GetCapacity();
838  break;
839  case WKC_PAGEDOWN:
840  /* scroll down a page */
841  if (this->list_pos == SLP_INVALID) return ES_HANDLED;
842  this->list_pos = min(this->list_pos + this->vscroll->GetCapacity(), (int)this->servers.size() - 1);
843  break;
844  case WKC_HOME:
845  /* jump to beginning */
846  this->list_pos = 0;
847  break;
848  case WKC_END:
849  /* jump to end */
850  this->list_pos = (ServerListPosition)this->servers.size() - 1;
851  break;
852  default: NOT_REACHED();
853  }
854 
855  this->server = this->servers[this->list_pos];
856 
857  /* Scroll to the new server if it is outside the current range. */
858  this->ScrollToSelectedServer();
859 
860  /* redraw window */
861  this->SetDirty();
862  return ES_HANDLED;
863  }
864 
865  if (this->server != nullptr) {
866  if (keycode == WKC_DELETE) { // Press 'delete' to remove servers
867  NetworkGameListRemoveItem(this->server);
868  if (this->server == this->last_joined) this->last_joined = nullptr;
869  this->server = nullptr;
870  this->list_pos = SLP_INVALID;
871  }
872  }
873 
874  return state;
875  }
876 
877  void OnEditboxChanged(int wid) override
878  {
879  switch (wid) {
880  case WID_NG_FILTER: {
881  this->servers.ForceRebuild();
882  this->BuildGUINetworkGameList();
883  this->ScrollToSelectedServer();
884  this->SetDirty();
885  break;
886  }
887 
888  case WID_NG_CLIENT:
889  /* Make sure the name does not start with a space, so TAB completion works */
890  if (!StrEmpty(this->name_editbox.text.buf) && this->name_editbox.text.buf[0] != ' ') {
892  } else {
894  }
895  break;
896  }
897  }
898 
899  void OnQueryTextFinished(char *str) override
900  {
901  if (!StrEmpty(str)) NetworkAddServer(str);
902  }
903 
904  void OnResize() override
905  {
906  this->vscroll->SetCapacityFromWidget(this, WID_NG_MATRIX);
907  }
908 
909  void OnRealtimeTick(uint delta_ms) override
910  {
911  if (!this->requery_timer.Elapsed(delta_ms)) return;
912  this->requery_timer.SetInterval(MILLISECONDS_PER_TICK);
913 
915  }
916 };
917 
918 Listing NetworkGameWindow::last_sorting = {false, 5};
919 GUIGameServerList::SortFunction * const NetworkGameWindow::sorter_funcs[] = {
920  &NGameNameSorter,
921  &NGameClientSorter,
922  &NGameMapSizeSorter,
923  &NGameDateSorter,
924  &NGameYearsSorter,
925  &NGameAllowedSorter
926 };
927 
928 GUIGameServerList::FilterFunction * const NetworkGameWindow::filter_funcs[] = {
929  &NGameSearchFilter
930 };
931 
932 static NWidgetBase *MakeResizableHeader(int *biggest_index)
933 {
934  *biggest_index = max<int>(*biggest_index, WID_NG_INFO);
935  return new NWidgetServerListHeader();
936 }
937 
938 static const NWidgetPart _nested_network_game_widgets[] = {
939  /* TOP */
941  NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
942  NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_SERVER_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
943  NWidget(WWT_DEFSIZEBOX, COLOUR_LIGHT_BLUE),
944  EndContainer(),
945  NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_MAIN),
946  NWidget(NWID_VERTICAL), SetPIP(10, 7, 0),
947  NWidget(NWID_HORIZONTAL), SetPIP(10, 7, 10),
948  /* LEFT SIDE */
949  NWidget(NWID_VERTICAL), SetPIP(0, 7, 0),
950  NWidget(NWID_HORIZONTAL), SetPIP(0, 7, 0),
951  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_CONNECTION), SetDataTip(STR_NETWORK_SERVER_LIST_ADVERTISED, STR_NULL),
952  NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NG_CONN_BTN),
953  SetDataTip(STR_BLACK_STRING, STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP),
954  NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
955  EndContainer(),
956  NWidget(NWID_HORIZONTAL), SetPIP(0, 7, 0),
957  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_FILTER_LABEL), SetDataTip(STR_LIST_FILTER_TITLE, STR_NULL),
958  NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_FILTER), SetMinimalSize(251, 12), SetFill(1, 0), SetResize(1, 0),
959  SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
960  EndContainer(),
963  NWidgetFunction(MakeResizableHeader),
964  NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NG_MATRIX), SetResize(1, 1), SetFill(1, 0),
965  SetMatrixDataTip(1, 0, STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT), SetScrollbar(WID_NG_SCROLLBAR),
966  EndContainer(),
967  NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NG_SCROLLBAR),
968  EndContainer(),
970  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_LASTJOINED_LABEL), SetFill(1, 0),
971  SetDataTip(STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER, STR_NULL), SetResize(1, 0),
973  NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_LASTJOINED), SetFill(1, 0), SetResize(1, 0),
974  SetDataTip(0x0, STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST),
975  EndContainer(),
976  NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NG_LASTJOINED_SPACER), SetFill(0, 0),
977  EndContainer(),
978  EndContainer(),
979  EndContainer(),
980  /* RIGHT SIDE */
981  NWidget(NWID_VERTICAL), SetPIP(0, 7, 0),
982  NWidget(NWID_HORIZONTAL), SetPIP(0, 7, 0),
983  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_CLIENT_LABEL), SetDataTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME, STR_NULL),
984  NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_CLIENT), SetMinimalSize(151, 12), SetFill(1, 0), SetResize(1, 0),
985  SetDataTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE, STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP),
986  EndContainer(),
987  NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_DETAILS),
989  NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NG_DETAILS_SPACER), SetMinimalSize(140, 155), SetResize(0, 1), SetFill(1, 1), // Make sure it's at least this wide
992  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),
993  NWidget(NWID_SPACER), SetFill(1, 0),
994  EndContainer(),
995  EndContainer(),
997  NWidget(NWID_SPACER), SetFill(1, 0),
998  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NG_NEWGRF_SEL),
999  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NEWGRF), SetFill(1, 0), SetDataTip(STR_INTRO_NEWGRF_SETTINGS, STR_NULL),
1000  NWidget(NWID_SPACER), SetFill(1, 0),
1001  EndContainer(),
1002  EndContainer(),
1004  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_JOIN), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_JOIN_GAME, STR_NULL),
1005  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_REFRESH), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_REFRESH, STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP),
1006  EndContainer(),
1007  EndContainer(),
1008  EndContainer(),
1009  EndContainer(),
1010  EndContainer(),
1011  /* BOTTOM */
1015  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_FIND), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_FIND_SERVER, STR_NETWORK_SERVER_LIST_FIND_SERVER_TOOLTIP),
1016  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),
1017  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),
1018  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CANCEL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
1019  EndContainer(),
1020  NWidget(NWID_SPACER), SetMinimalSize(0, 6), SetResize(1, 0), SetFill(1, 0),
1021  EndContainer(),
1023  NWidget(NWID_SPACER), SetFill(0, 1),
1024  NWidget(WWT_RESIZEBOX, COLOUR_LIGHT_BLUE),
1025  EndContainer(),
1026  EndContainer(),
1027  EndContainer(),
1028  EndContainer(),
1029 };
1030 
1031 static WindowDesc _network_game_window_desc(
1032  WDP_CENTER, "list_servers", 1000, 730,
1034  0,
1035  _nested_network_game_widgets, lengthof(_nested_network_game_widgets)
1036 );
1037 
1038 void ShowNetworkGameWindow()
1039 {
1040  static bool first = true;
1043 
1044  /* Only show once */
1045  if (first) {
1046  first = false;
1047  /* Add all servers from the config file to our list. */
1048  for (const auto &iter : _network_host_list) {
1049  NetworkAddServer(iter.c_str());
1050  }
1051  }
1052 
1053  new NetworkGameWindow(&_network_game_window_desc);
1054 }
1055 
1057  byte widget_id;
1059 
1060  NetworkStartServerWindow(WindowDesc *desc) : Window(desc), name_editbox(NETWORK_NAME_LENGTH)
1061  {
1062  this->InitNested(WN_NETWORK_WINDOW_START);
1063 
1064  this->querystrings[WID_NSS_GAMENAME] = &this->name_editbox;
1065  this->name_editbox.text.Assign(_settings_client.network.server_name);
1066 
1067  this->SetFocusedWidget(WID_NSS_GAMENAME);
1068  }
1069 
1070  void SetStringParameters(int widget) const override
1071  {
1072  switch (widget) {
1073  case WID_NSS_CONNTYPE_BTN:
1075  break;
1076 
1077  case WID_NSS_CLIENTS_TXT:
1079  break;
1080 
1081  case WID_NSS_COMPANIES_TXT:
1083  break;
1084 
1087  break;
1088 
1089  case WID_NSS_LANGUAGE_BTN:
1090  SetDParam(0, STR_NETWORK_LANG_ANY + _settings_client.network.server_lang);
1091  break;
1092  }
1093  }
1094 
1095  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
1096  {
1097  switch (widget) {
1098  case WID_NSS_CONNTYPE_BTN:
1100  size->width += padding.width;
1101  size->height += padding.height;
1102  break;
1103  }
1104  }
1105 
1106  void DrawWidget(const Rect &r, int widget) const override
1107  {
1108  switch (widget) {
1109  case WID_NSS_SETPWD:
1110  /* If password is set, draw red '*' next to 'Set password' button. */
1111  if (!StrEmpty(_settings_client.network.server_password)) DrawString(r.right + WD_FRAMERECT_LEFT, this->width - WD_FRAMERECT_RIGHT, r.top, "*", TC_RED);
1112  }
1113  }
1114 
1115  void OnClick(Point pt, int widget, int click_count) override
1116  {
1117  switch (widget) {
1118  case WID_NSS_CANCEL: // Cancel button
1119  ShowNetworkGameWindow();
1120  break;
1121 
1122  case WID_NSS_SETPWD: // Set password button
1123  this->widget_id = WID_NSS_SETPWD;
1125  ShowQueryString(STR_JUST_RAW_STRING, STR_NETWORK_START_SERVER_SET_PASSWORD, 20, this, CS_ALPHANUMERAL, QSF_NONE);
1126  break;
1127 
1128  case WID_NSS_CONNTYPE_BTN: // Connection type
1129  ShowDropDownMenu(this, _connection_types_dropdown, _settings_client.network.server_advertise, WID_NSS_CONNTYPE_BTN, 0, 0); // do it for widget WID_NSS_CONNTYPE_BTN
1130  break;
1131 
1132  case WID_NSS_CLIENTS_BTND: case WID_NSS_CLIENTS_BTNU: // Click on up/down button for number of clients
1133  case WID_NSS_COMPANIES_BTND: case WID_NSS_COMPANIES_BTNU: // Click on up/down button for number of companies
1134  case WID_NSS_SPECTATORS_BTND: case WID_NSS_SPECTATORS_BTNU: // Click on up/down button for number of spectators
1135  /* Don't allow too fast scrolling. */
1136  if (!(this->flags & WF_TIMEOUT) || this->timeout_timer <= 1) {
1137  this->HandleButtonClick(widget);
1138  this->SetDirty();
1139  switch (widget) {
1140  default: NOT_REACHED();
1143  break;
1146  break;
1149  break;
1150  }
1151  }
1152  _left_button_clicked = false;
1153  break;
1154 
1155  case WID_NSS_CLIENTS_TXT: // Click on number of clients
1156  this->widget_id = WID_NSS_CLIENTS_TXT;
1158  ShowQueryString(STR_JUST_INT, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS, 4, this, CS_NUMERAL, QSF_NONE);
1159  break;
1160 
1161  case WID_NSS_COMPANIES_TXT: // Click on number of companies
1162  this->widget_id = WID_NSS_COMPANIES_TXT;
1164  ShowQueryString(STR_JUST_INT, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES, 3, this, CS_NUMERAL, QSF_NONE);
1165  break;
1166 
1167  case WID_NSS_SPECTATORS_TXT: // Click on number of spectators
1168  this->widget_id = WID_NSS_SPECTATORS_TXT;
1170  ShowQueryString(STR_JUST_INT, STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS, 4, this, CS_NUMERAL, QSF_NONE);
1171  break;
1172 
1173  case WID_NSS_LANGUAGE_BTN: { // Language
1174  uint sel = 0;
1175  for (uint i = 0; i < _language_dropdown.size() - 1; i++) {
1176  if (_language_dropdown[i] == STR_NETWORK_LANG_ANY + _settings_client.network.server_lang) {
1177  sel = i;
1178  break;
1179  }
1180  }
1181  ShowDropDownMenu(this, _language_dropdown.data(), sel, WID_NSS_LANGUAGE_BTN, 0, 0);
1182  break;
1183  }
1184 
1185  case WID_NSS_GENERATE_GAME: // Start game
1186  _is_network_server = true;
1187  if (_ctrl_pressed) {
1189  } else {
1191  }
1192  break;
1193 
1194  case WID_NSS_LOAD_GAME:
1195  _is_network_server = true;
1197  break;
1198 
1199  case WID_NSS_PLAY_SCENARIO:
1200  _is_network_server = true;
1202  break;
1203 
1205  _is_network_server = true;
1207  break;
1208  }
1209  }
1210 
1211  void OnDropdownSelect(int widget, int index) override
1212  {
1213  switch (widget) {
1214  case WID_NSS_CONNTYPE_BTN:
1215  _settings_client.network.server_advertise = (index != 0);
1216  break;
1217  case WID_NSS_LANGUAGE_BTN:
1218  _settings_client.network.server_lang = _language_dropdown[index] - STR_NETWORK_LANG_ANY;
1219  break;
1220  default:
1221  NOT_REACHED();
1222  }
1223 
1224  this->SetDirty();
1225  }
1226 
1227  void OnEditboxChanged(int wid) override
1228  {
1229  if (wid == WID_NSS_GAMENAME) {
1231  }
1232  }
1233 
1234  void OnTimeout() override
1235  {
1237  for (const int *widget = raise_widgets; *widget != WIDGET_LIST_END; widget++) {
1238  if (this->IsWidgetLowered(*widget)) {
1239  this->RaiseWidget(*widget);
1240  this->SetWidgetDirty(*widget);
1241  }
1242  }
1243  }
1244 
1245  void OnQueryTextFinished(char *str) override
1246  {
1247  if (str == nullptr) return;
1248 
1249  if (this->widget_id == WID_NSS_SETPWD) {
1251  } else {
1252  int32 value = atoi(str);
1253  this->SetWidgetDirty(this->widget_id);
1254  switch (this->widget_id) {
1255  default: NOT_REACHED();
1259  }
1260  }
1261 
1262  this->SetDirty();
1263  }
1264 };
1265 
1266 static const NWidgetPart _nested_network_start_server_window_widgets[] = {
1268  NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
1269  NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_START_SERVER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1270  EndContainer(),
1271  NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NSS_BACKGROUND),
1272  NWidget(NWID_VERTICAL), SetPIP(10, 6, 10),
1274  NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
1275  /* Game name widgets */
1276  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_GAMENAME_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME, STR_NULL),
1277  NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NSS_GAMENAME), SetMinimalSize(10, 12), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE, STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP),
1278  EndContainer(),
1279  EndContainer(),
1280 
1282  NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
1283  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_ADVERTISED, STR_NULL),
1284  NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_BTN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP),
1285  EndContainer(),
1286  NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
1287  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_LANGUAGE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN, STR_NULL),
1288  NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_LANGUAGE_BTN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP),
1289  EndContainer(),
1290  NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
1291  NWidget(NWID_SPACER), SetFill(1, 1),
1292  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_SETPWD), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_SET_PASSWORD, STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP),
1293  EndContainer(),
1294  EndContainer(),
1295 
1297  NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
1298  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS, STR_NULL),
1300  NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_BTND), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_ARROW_DOWN, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
1301  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),
1302  NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_BTNU), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_ARROW_UP, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
1303  EndContainer(),
1304  EndContainer(),
1305 
1306  NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
1307  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES, STR_NULL),
1309  NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_BTND), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_ARROW_DOWN, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
1310  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),
1311  NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_BTNU), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_ARROW_UP, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
1312  EndContainer(),
1313  EndContainer(),
1314 
1315  NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
1316  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_SPECTATORS_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS, STR_NULL),
1318  NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_SPECTATORS_BTND), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_ARROW_DOWN, STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP),
1319  NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_NSS_SPECTATORS_TXT), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_SPECTATORS_SELECT, STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP),
1320  NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_SPECTATORS_BTNU), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_ARROW_UP, STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP),
1321  EndContainer(),
1322  EndContainer(),
1323  EndContainer(),
1324 
1325  /* 'generate game' and 'load game' buttons */
1327  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_GENERATE_GAME), SetDataTip(STR_INTRO_NEW_GAME, STR_INTRO_TOOLTIP_NEW_GAME), SetFill(1, 0),
1328  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_LOAD_GAME), SetDataTip(STR_INTRO_LOAD_GAME, STR_INTRO_TOOLTIP_LOAD_GAME), SetFill(1, 0),
1329  EndContainer(),
1330 
1331  /* 'play scenario' and 'play heightmap' buttons */
1333  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_PLAY_SCENARIO), SetDataTip(STR_INTRO_PLAY_SCENARIO, STR_INTRO_TOOLTIP_PLAY_SCENARIO), SetFill(1, 0),
1334  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_PLAY_HEIGHTMAP), SetDataTip(STR_INTRO_PLAY_HEIGHTMAP, STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP), SetFill(1, 0),
1335  EndContainer(),
1336 
1338  NWidget(NWID_SPACER), SetFill(1, 0),
1339  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_CANCEL), SetDataTip(STR_BUTTON_CANCEL, STR_NULL), SetMinimalSize(128, 12),
1340  NWidget(NWID_SPACER), SetFill(1, 0),
1341  EndContainer(),
1342  EndContainer(),
1343  EndContainer(),
1344 };
1345 
1346 static WindowDesc _network_start_server_window_desc(
1347  WDP_CENTER, nullptr, 0, 0,
1349  0,
1350  _nested_network_start_server_window_widgets, lengthof(_nested_network_start_server_window_widgets)
1351 );
1352 
1353 static void ShowNetworkStartServerWindow()
1354 {
1357 
1358  new NetworkStartServerWindow(&_network_start_server_window_desc);
1359 }
1360 
1361 struct NetworkLobbyWindow : public Window {
1364  NetworkCompanyInfo company_info[MAX_COMPANIES];
1365  Scrollbar *vscroll;
1366 
1368  Window(desc), company(INVALID_COMPANY), server(ngl)
1369  {
1370  this->CreateNestedTree();
1371  this->vscroll = this->GetScrollbar(WID_NL_SCROLLBAR);
1372  this->FinishInitNested(WN_NETWORK_WINDOW_LOBBY);
1373  }
1374 
1375  CompanyID NetworkLobbyFindCompanyIndex(byte pos) const
1376  {
1377  /* Scroll through all this->company_info and get the 'pos' item that is not empty. */
1378  for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
1379  if (!StrEmpty(this->company_info[i].company_name)) {
1380  if (pos-- == 0) return i;
1381  }
1382  }
1383 
1384  return COMPANY_FIRST;
1385  }
1386 
1387  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
1388  {
1389  switch (widget) {
1390  case WID_NL_HEADER:
1392  break;
1393 
1394  case WID_NL_MATRIX:
1395  resize->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
1396  size->height = 10 * resize->height;
1397  break;
1398 
1399  case WID_NL_DETAILS:
1400  size->height = 30 + 11 * FONT_HEIGHT_NORMAL;
1401  break;
1402  }
1403  }
1404 
1405  void SetStringParameters(int widget) const override
1406  {
1407  switch (widget) {
1408  case WID_NL_TEXT:
1409  SetDParamStr(0, this->server->info.server_name);
1410  break;
1411  }
1412  }
1413 
1414  void DrawWidget(const Rect &r, int widget) const override
1415  {
1416  switch (widget) {
1417  case WID_NL_DETAILS:
1418  this->DrawDetails(r);
1419  break;
1420 
1421  case WID_NL_MATRIX:
1422  this->DrawMatrix(r);
1423  break;
1424  }
1425  }
1426 
1427  void OnPaint() override
1428  {
1429  const NetworkGameInfo *gi = &this->server->info;
1430 
1431  /* Join button is disabled when no company is selected and for AI companies. */
1432  this->SetWidgetDisabledState(WID_NL_JOIN, this->company == INVALID_COMPANY || GetLobbyCompanyInfo(this->company)->ai);
1433  /* Cannot start new company if there are too many. */
1434  this->SetWidgetDisabledState(WID_NL_NEW, gi->companies_on >= gi->companies_max);
1435  /* Cannot spectate if there are too many spectators. */
1436  this->SetWidgetDisabledState(WID_NL_SPECTATE, gi->spectators_on >= gi->spectators_max);
1437 
1438  this->vscroll->SetCount(gi->companies_on);
1439 
1440  /* Draw window widgets */
1441  this->DrawWidgets();
1442  }
1443 
1444  void DrawMatrix(const Rect &r) const
1445  {
1446  bool rtl = _current_text_dir == TD_RTL;
1447  uint left = r.left + WD_FRAMERECT_LEFT;
1448  uint right = r.right - WD_FRAMERECT_RIGHT;
1449 
1450  Dimension lock_size = GetSpriteSize(SPR_LOCK);
1451  int lock_width = lock_size.width;
1452  int lock_y_offset = (this->resize.step_height - WD_MATRIX_TOP - WD_MATRIX_BOTTOM - lock_size.height) / 2;
1453 
1454  Dimension profit_size = GetSpriteSize(SPR_PROFIT_LOT);
1455  int profit_width = lock_size.width;
1456  int profit_y_offset = (this->resize.step_height - WD_MATRIX_TOP - WD_MATRIX_BOTTOM - profit_size.height) / 2;
1457 
1458  uint text_left = left + (rtl ? lock_width + profit_width + 4 : 0);
1459  uint text_right = right - (rtl ? 0 : lock_width + profit_width + 4);
1460  uint profit_left = rtl ? left : right - profit_width;
1461  uint lock_left = rtl ? left + profit_width + 2 : right - profit_width - lock_width - 2;
1462 
1463  int y = r.top + WD_MATRIX_TOP;
1464  /* Draw company list */
1465  int pos = this->vscroll->GetPosition();
1466  while (pos < this->server->info.companies_on) {
1467  byte company = NetworkLobbyFindCompanyIndex(pos);
1468  bool income = false;
1469  if (this->company == company) {
1470  GfxFillRect(r.left + 1, y - 2, r.right - 1, y + FONT_HEIGHT_NORMAL, PC_GREY); // show highlighted item with a different colour
1471  }
1472 
1473  DrawString(text_left, text_right, y, this->company_info[company].company_name, TC_BLACK);
1474  if (this->company_info[company].use_password != 0) DrawSprite(SPR_LOCK, PAL_NONE, lock_left, y + lock_y_offset);
1475 
1476  /* If the company's income was positive puts a green dot else a red dot */
1477  if (this->company_info[company].income >= 0) income = true;
1478  DrawSprite(income ? SPR_PROFIT_LOT : SPR_PROFIT_NEGATIVE, PAL_NONE, profit_left, y + profit_y_offset);
1479 
1480  pos++;
1481  y += this->resize.step_height;
1482  if (pos >= this->vscroll->GetPosition() + this->vscroll->GetCapacity()) break;
1483  }
1484  }
1485 
1486  void DrawDetails(const Rect &r) const
1487  {
1488  const int detail_height = 12 + FONT_HEIGHT_NORMAL + 12;
1489  /* Draw info about selected company when it is selected in the left window. */
1490  GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.top + detail_height - 1, PC_DARK_BLUE);
1491  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 12, STR_NETWORK_GAME_LOBBY_COMPANY_INFO, TC_FROMSTRING, SA_HOR_CENTER);
1492 
1493  if (this->company == INVALID_COMPANY || StrEmpty(this->company_info[this->company].company_name)) return;
1494 
1495  int y = r.top + detail_height + 4;
1496  const NetworkGameInfo *gi = &this->server->info;
1497 
1498  SetDParam(0, gi->clients_on);
1499  SetDParam(1, gi->clients_max);
1500  SetDParam(2, gi->companies_on);
1501  SetDParam(3, gi->companies_max);
1502  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CLIENTS);
1503  y += FONT_HEIGHT_NORMAL;
1504 
1505  SetDParamStr(0, this->company_info[this->company].company_name);
1506  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_COMPANY_NAME);
1507  y += FONT_HEIGHT_NORMAL;
1508 
1509  SetDParam(0, this->company_info[this->company].inaugurated_year);
1510  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR); // inauguration year
1511  y += FONT_HEIGHT_NORMAL;
1512 
1513  SetDParam(0, this->company_info[this->company].company_value);
1514  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_VALUE); // company value
1515  y += FONT_HEIGHT_NORMAL;
1516 
1517  SetDParam(0, this->company_info[this->company].money);
1518  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_CURRENT_BALANCE); // current balance
1519  y += FONT_HEIGHT_NORMAL;
1520 
1521  SetDParam(0, this->company_info[this->company].income);
1522  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_LAST_YEARS_INCOME); // last year's income
1523  y += FONT_HEIGHT_NORMAL;
1524 
1525  SetDParam(0, this->company_info[this->company].performance);
1526  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_PERFORMANCE); // performance
1527  y += FONT_HEIGHT_NORMAL;
1528 
1529  SetDParam(0, this->company_info[this->company].num_vehicle[NETWORK_VEH_TRAIN]);
1530  SetDParam(1, this->company_info[this->company].num_vehicle[NETWORK_VEH_LORRY]);
1531  SetDParam(2, this->company_info[this->company].num_vehicle[NETWORK_VEH_BUS]);
1532  SetDParam(3, this->company_info[this->company].num_vehicle[NETWORK_VEH_SHIP]);
1533  SetDParam(4, this->company_info[this->company].num_vehicle[NETWORK_VEH_PLANE]);
1534  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_VEHICLES); // vehicles
1535  y += FONT_HEIGHT_NORMAL;
1536 
1537  SetDParam(0, this->company_info[this->company].num_station[NETWORK_VEH_TRAIN]);
1538  SetDParam(1, this->company_info[this->company].num_station[NETWORK_VEH_LORRY]);
1539  SetDParam(2, this->company_info[this->company].num_station[NETWORK_VEH_BUS]);
1540  SetDParam(3, this->company_info[this->company].num_station[NETWORK_VEH_SHIP]);
1541  SetDParam(4, this->company_info[this->company].num_station[NETWORK_VEH_PLANE]);
1542  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_STATIONS); // stations
1543  y += FONT_HEIGHT_NORMAL;
1544 
1545  SetDParamStr(0, this->company_info[this->company].clients);
1546  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_PLAYERS); // players
1547  }
1548 
1549  void OnClick(Point pt, int widget, int click_count) override
1550  {
1551  switch (widget) {
1552  case WID_NL_CANCEL: // Cancel button
1553  ShowNetworkGameWindow();
1554  break;
1555 
1556  case WID_NL_MATRIX: { // Company list
1557  uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NL_MATRIX);
1558  this->company = (id_v >= this->server->info.companies_on) ? INVALID_COMPANY : NetworkLobbyFindCompanyIndex(id_v);
1559  this->SetDirty();
1560 
1561  /* FIXME the disabling should go into some InvalidateData, which is called instead of the SetDirty */
1562  if (click_count > 1 && !this->IsWidgetDisabled(WID_NL_JOIN)) this->OnClick(pt, WID_NL_JOIN, 1);
1563  break;
1564  }
1565 
1566  case WID_NL_JOIN: // Join company
1567  /* Button can be clicked only when it is enabled. */
1568  NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), this->company);
1569  break;
1570 
1571  case WID_NL_NEW: // New company
1573  break;
1574 
1575  case WID_NL_SPECTATE: // Spectate game
1577  break;
1578 
1579  case WID_NL_REFRESH: // Refresh
1580  NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // company info
1582  /* Clear the information so removed companies don't remain */
1583  memset(this->company_info, 0, sizeof(this->company_info));
1584  break;
1585  }
1586  }
1587 
1588  void OnResize() override
1589  {
1590  this->vscroll->SetCapacityFromWidget(this, WID_NL_MATRIX);
1591  }
1592 };
1593 
1594 static const NWidgetPart _nested_network_lobby_window_widgets[] = {
1596  NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
1597  NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_GAME_LOBBY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1598  EndContainer(),
1599  NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NL_BACKGROUND),
1600  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NL_TEXT), SetDataTip(STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN, STR_NULL), SetResize(1, 0), SetPadding(10, 10, 0, 10),
1602  NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 10),
1603  /* Company list. */
1605  NWidget(WWT_PANEL, COLOUR_WHITE, WID_NL_HEADER), SetMinimalSize(146, 0), SetResize(1, 0), SetFill(1, 0), EndContainer(),
1606  NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NL_MATRIX), SetMinimalSize(146, 0), SetResize(1, 1), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP), SetScrollbar(WID_NL_SCROLLBAR),
1607  EndContainer(),
1608  NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NL_SCROLLBAR),
1610  /* Company info. */
1611  NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NL_DETAILS), SetMinimalSize(232, 0), SetResize(1, 1), SetFill(1, 1), EndContainer(),
1612  EndContainer(),
1614  /* Buttons. */
1617  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_JOIN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_GAME_LOBBY_JOIN_COMPANY, STR_NETWORK_GAME_LOBBY_JOIN_COMPANY_TOOLTIP),
1618  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_NEW), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_GAME_LOBBY_NEW_COMPANY, STR_NETWORK_GAME_LOBBY_NEW_COMPANY_TOOLTIP),
1619  EndContainer(),
1621  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_SPECTATE), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_GAME_LOBBY_SPECTATE_GAME, STR_NETWORK_GAME_LOBBY_SPECTATE_GAME_TOOLTIP),
1622  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_REFRESH), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_REFRESH, STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP),
1623  EndContainer(),
1625  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_CANCEL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
1626  NWidget(NWID_SPACER), SetFill(1, 1),
1627  EndContainer(),
1628  EndContainer(),
1630  EndContainer(),
1631 };
1632 
1633 static WindowDesc _network_lobby_window_desc(
1634  WDP_CENTER, nullptr, 0, 0,
1636  0,
1637  _nested_network_lobby_window_widgets, lengthof(_nested_network_lobby_window_widgets)
1638 );
1639 
1645 {
1648 
1649  NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // company info
1651 
1652  new NetworkLobbyWindow(&_network_lobby_window_desc, ngl);
1653 }
1654 
1661 {
1663  return (lobby != nullptr && company < MAX_COMPANIES) ? &lobby->company_info[company] : nullptr;
1664 }
1665 
1666 /* The window below gives information about the connected clients
1667  * and also makes able to give money to them, kick them (if server)
1668  * and stuff like that. */
1669 
1670 extern void DrawCompanyIcon(CompanyID cid, int x, int y);
1671 
1677 
1678 static const NWidgetPart _nested_client_list_popup_widgets[] = {
1679  NWidget(WWT_PANEL, COLOUR_GREY, WID_CLP_PANEL), EndContainer(),
1680 };
1681 
1682 static WindowDesc _client_list_popup_desc(
1683  WDP_AUTO, nullptr, 0, 0,
1685  0,
1686  _nested_client_list_popup_widgets, lengthof(_nested_client_list_popup_widgets)
1687 );
1688 
1689 /* Here we start to define the options out of the menu */
1690 static void ClientList_Kick(const NetworkClientInfo *ci)
1691 {
1693 }
1694 
1695 static void ClientList_Ban(const NetworkClientInfo *ci)
1696 {
1698 }
1699 
1700 static void ClientList_GiveMoney(const NetworkClientInfo *ci)
1701 {
1702  ShowNetworkGiveMoneyWindow(ci->client_playas);
1703 }
1704 
1705 static void ClientList_SpeakToClient(const NetworkClientInfo *ci)
1706 {
1708 }
1709 
1710 static void ClientList_SpeakToCompany(const NetworkClientInfo *ci)
1711 {
1713 }
1714 
1715 static void ClientList_SpeakToAll(const NetworkClientInfo *ci)
1716 {
1718 }
1719 
1726  };
1727 
1728  uint sel_index;
1729  ClientID client_id;
1730  Point desired_location;
1731  std::vector<ClientListAction> actions;
1732 
1738  inline void AddAction(StringID name, ClientList_Action_Proc *proc)
1739  {
1740  this->actions.push_back({name, proc});
1741  }
1742 
1743  NetworkClientListPopupWindow(WindowDesc *desc, int x, int y, ClientID client_id) :
1744  Window(desc),
1745  sel_index(0), client_id(client_id)
1746  {
1747  this->desired_location.x = x;
1748  this->desired_location.y = y;
1749 
1750  const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
1751 
1752  if (_network_own_client_id != ci->client_id) {
1753  this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, &ClientList_SpeakToClient);
1754  }
1755 
1757  this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, &ClientList_SpeakToCompany);
1758  }
1759  this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, &ClientList_SpeakToAll);
1760 
1761  if (_network_own_client_id != ci->client_id) {
1762  /* We are no spectator and the company we want to give money to is no spectator and money gifts are allowed. */
1764  this->AddAction(STR_NETWORK_CLIENTLIST_GIVE_MONEY, &ClientList_GiveMoney);
1765  }
1766  }
1767 
1768  /* A server can kick clients (but not himself). */
1770  this->AddAction(STR_NETWORK_CLIENTLIST_KICK, &ClientList_Kick);
1771  this->AddAction(STR_NETWORK_CLIENTLIST_BAN, &ClientList_Ban);
1772  }
1773 
1774  this->InitNested(client_id);
1775  CLRBITS(this->flags, WF_WHITE_BORDER);
1776  }
1777 
1778  Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override
1779  {
1780  return this->desired_location;
1781  }
1782 
1783  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
1784  {
1785  Dimension d = *size;
1786  for (const ClientListAction &action : this->actions) {
1787  d = maxdim(GetStringBoundingBox(action.name), d);
1788  }
1789 
1790  d.height *= (uint)this->actions.size();
1792  d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
1793  *size = d;
1794  }
1795 
1796  void DrawWidget(const Rect &r, int widget) const override
1797  {
1798  /* Draw the actions */
1799  int sel = this->sel_index;
1800  int y = r.top + WD_FRAMERECT_TOP;
1801  for (const ClientListAction &action : this->actions) {
1802  TextColour colour;
1803  if (sel-- == 0) { // Selected item, highlight it
1804  GfxFillRect(r.left + 1, y, r.right - 1, y + FONT_HEIGHT_NORMAL - 1, PC_BLACK);
1805  colour = TC_WHITE;
1806  } else {
1807  colour = TC_BLACK;
1808  }
1809 
1810  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, action.name, colour);
1811  y += FONT_HEIGHT_NORMAL;
1812  }
1813  }
1814 
1815  void OnMouseLoop() override
1816  {
1817  /* We selected an action */
1818  uint index = (_cursor.pos.y - this->top - WD_FRAMERECT_TOP) / FONT_HEIGHT_NORMAL;
1819 
1820  if (_left_button_down) {
1821  if (index == this->sel_index || index >= this->actions.size()) return;
1822 
1823  this->sel_index = index;
1824  this->SetDirty();
1825  } else {
1826  if (index < this->actions.size() && _cursor.pos.y >= this->top) {
1827  const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(this->client_id);
1828  if (ci != nullptr) this->actions[index].proc(ci);
1829  }
1830 
1832  }
1833  }
1834 };
1835 
1839 static void PopupClientList(ClientID client_id, int x, int y)
1840 {
1842 
1843  if (NetworkClientInfo::GetByClientID(client_id) == nullptr) return;
1844 
1845  new NetworkClientListPopupWindow(&_client_list_popup_desc, x, y, client_id);
1846 }
1847 
1848 static const NWidgetPart _nested_client_list_widgets[] = {
1850  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1851  NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1852  NWidget(WWT_STICKYBOX, COLOUR_GREY),
1853  EndContainer(),
1855 };
1856 
1857 static WindowDesc _client_list_desc(
1858  WDP_AUTO, "list_clients", 0, 0,
1860  0,
1861  _nested_client_list_widgets, lengthof(_nested_client_list_widgets)
1862 );
1863 
1868  int selected_item;
1869 
1870  uint server_client_width;
1871  uint line_height;
1872 
1873  Dimension icon_size;
1874 
1875  NetworkClientListWindow(WindowDesc *desc, WindowNumber window_number) :
1876  Window(desc),
1877  selected_item(-1)
1878  {
1879  this->InitNested(window_number);
1880  }
1881 
1886  {
1887  int num = 0;
1888  const NetworkClientInfo *ci;
1889 
1890  /* Should be replaced with a loop through all clients */
1891  FOR_ALL_CLIENT_INFOS(ci) {
1892  if (ci->client_playas != COMPANY_INACTIVE_CLIENT) num++;
1893  }
1894 
1895  num *= this->line_height;
1896 
1897  int diff = (num + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM) - (this->GetWidget<NWidgetBase>(WID_CL_PANEL)->current_y);
1898  /* If height is changed */
1899  if (diff != 0) {
1900  ResizeWindow(this, 0, diff, false);
1901  return false;
1902  }
1903  return true;
1904  }
1905 
1906  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
1907  {
1908  if (widget != WID_CL_PANEL) return;
1909 
1910  this->server_client_width = max(GetStringBoundingBox(STR_NETWORK_SERVER).width, GetStringBoundingBox(STR_NETWORK_CLIENT).width) + WD_FRAMERECT_RIGHT;
1911  this->icon_size = GetSpriteSize(SPR_COMPANY_ICON);
1912  this->line_height = max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL);
1913 
1914  uint width = 100; // Default width
1915  const NetworkClientInfo *ci;
1916  FOR_ALL_CLIENT_INFOS(ci) {
1917  width = max(width, GetStringBoundingBox(ci->client_name).width);
1918  }
1919 
1920  size->width = WD_FRAMERECT_LEFT + this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT + width + WD_FRAMERECT_RIGHT;
1921  }
1922 
1923  void OnPaint() override
1924  {
1925  /* Check if we need to reset the height */
1926  if (!this->CheckClientListHeight()) return;
1927 
1928  this->DrawWidgets();
1929  }
1930 
1931  void DrawWidget(const Rect &r, int widget) const override
1932  {
1933  if (widget != WID_CL_PANEL) return;
1934 
1935  bool rtl = _current_text_dir == TD_RTL;
1936  int icon_offset = (this->line_height - icon_size.height) / 2;
1937  int text_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2;
1938 
1939  uint y = r.top + WD_FRAMERECT_TOP;
1940  uint left = r.left + WD_FRAMERECT_LEFT;
1941  uint right = r.right - WD_FRAMERECT_RIGHT;
1942  uint type_icon_width = this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT;
1943 
1944 
1945  uint type_left = rtl ? right - this->server_client_width : left;
1946  uint type_right = rtl ? right : left + this->server_client_width - 1;
1947  uint icon_left = rtl ? right - type_icon_width + WD_FRAMERECT_LEFT : left + this->server_client_width;
1948  uint name_left = rtl ? left : left + type_icon_width;
1949  uint name_right = rtl ? right - type_icon_width : right;
1950 
1951  int i = 0;
1952  const NetworkClientInfo *ci;
1953  FOR_ALL_CLIENT_INFOS(ci) {
1954  TextColour colour;
1955  if (this->selected_item == i++) { // Selected item, highlight it
1956  GfxFillRect(r.left + 1, y, r.right - 1, y + this->line_height - 1, PC_BLACK);
1957  colour = TC_WHITE;
1958  } else {
1959  colour = TC_BLACK;
1960  }
1961 
1962  if (ci->client_id == CLIENT_ID_SERVER) {
1963  DrawString(type_left, type_right, y + text_offset, STR_NETWORK_SERVER, colour);
1964  } else {
1965  DrawString(type_left, type_right, y + text_offset, STR_NETWORK_CLIENT, colour);
1966  }
1967 
1968  /* Filter out spectators */
1969  if (Company::IsValidID(ci->client_playas)) DrawCompanyIcon(ci->client_playas, icon_left, y + icon_offset);
1970 
1971  DrawString(name_left, name_right, y + text_offset, ci->client_name, colour);
1972 
1973  y += line_height;
1974  }
1975  }
1976 
1977  void OnClick(Point pt, int widget, int click_count) override
1978  {
1979  /* Show the popup with option */
1980  if (this->selected_item != -1) {
1981  NetworkClientInfo *ci;
1982 
1983  int client_no = this->selected_item;
1984  FOR_ALL_CLIENT_INFOS(ci) {
1985  if (client_no == 0) break;
1986  client_no--;
1987  }
1988 
1989  if (ci != nullptr) PopupClientList(ci->client_id, pt.x + this->left, pt.y + this->top);
1990  }
1991  }
1992 
1993  void OnMouseOver(Point pt, int widget) override
1994  {
1995  /* -1 means we left the current window */
1996  if (pt.y == -1) {
1997  this->selected_item = -1;
1998  this->SetDirty();
1999  return;
2000  }
2001 
2002  /* Find the new selected item (if any) */
2003  pt.y -= this->GetWidget<NWidgetBase>(WID_CL_PANEL)->pos_y;
2004  int item = -1;
2006  item = (pt.y - WD_FRAMERECT_TOP) / this->line_height;
2007  }
2008 
2009  /* It did not change.. no update! */
2010  if (item == this->selected_item) return;
2011  this->selected_item = item;
2012 
2013  /* Repaint */
2014  this->SetDirty();
2015  }
2016 };
2017 
2018 void ShowClientList()
2019 {
2020  AllocateWindowDescFront<NetworkClientListWindow>(&_client_list_desc, 0);
2021 }
2022 
2027 
2029  NetworkPasswordType password_type;
2030 
2032  {
2034  this->InitNested(WN_NETWORK_STATUS_WINDOW_JOIN);
2035  }
2036 
2037  void DrawWidget(const Rect &r, int widget) const override
2038  {
2039  if (widget != WID_NJS_BACKGROUND) return;
2040 
2041  uint8 progress; // used for progress bar
2042  DrawString(r.left + 2, r.right - 2, r.top + 20, STR_NETWORK_CONNECTING_1 + _network_join_status, TC_FROMSTRING, SA_HOR_CENTER);
2043  switch (_network_join_status) {
2044  case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING:
2045  case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
2046  progress = 10; // first two stages 10%
2047  break;
2048  case NETWORK_JOIN_STATUS_WAITING:
2049  SetDParam(0, _network_join_waiting);
2050  DrawString(r.left + 2, r.right - 2, r.top + 20 + FONT_HEIGHT_NORMAL, STR_NETWORK_CONNECTING_WAITING, TC_FROMSTRING, SA_HOR_CENTER);
2051  progress = 15; // third stage is 15%
2052  break;
2053  case NETWORK_JOIN_STATUS_DOWNLOADING:
2054  SetDParam(0, _network_join_bytes);
2055  SetDParam(1, _network_join_bytes_total);
2056  DrawString(r.left + 2, r.right - 2, r.top + 20 + FONT_HEIGHT_NORMAL, _network_join_bytes_total == 0 ? STR_NETWORK_CONNECTING_DOWNLOADING_1 : STR_NETWORK_CONNECTING_DOWNLOADING_2, TC_FROMSTRING, SA_HOR_CENTER);
2057  if (_network_join_bytes_total == 0) {
2058  progress = 15; // We don't have the final size yet; the server is still compressing!
2059  break;
2060  }
2061  FALLTHROUGH;
2062 
2063  default: // Waiting is 15%, so the resting receivement of map is maximum 70%
2064  progress = 15 + _network_join_bytes * (100 - 15) / _network_join_bytes_total;
2065  }
2066 
2067  /* Draw nice progress bar :) */
2068  DrawFrameRect(r.left + 20, r.top + 5, (int)((this->width - 20) * progress / 100), r.top + 15, COLOUR_MAUVE, FR_NONE);
2069  }
2070 
2071  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
2072  {
2073  if (widget != WID_NJS_BACKGROUND) return;
2074 
2075  size->height = 25 + 2 * FONT_HEIGHT_NORMAL;
2076 
2077  /* Account for the statuses */
2078  uint width = 0;
2079  for (uint i = 0; i < NETWORK_JOIN_STATUS_END; i++) {
2080  width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_1 + i).width);
2081  }
2082 
2083  /* For the number of waiting (other) players */
2085  width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_WAITING).width);
2086 
2087  /* Account for downloading ~ 10 MiB */
2088  SetDParamMaxDigits(0, 8);
2089  SetDParamMaxDigits(1, 8);
2090  width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_DOWNLOADING_1).width);
2091  width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_DOWNLOADING_2).width);
2092 
2093  /* Give a bit more clearing for the widest strings than strictly needed */
2094  size->width = width + WD_FRAMERECT_LEFT + WD_FRAMERECT_BOTTOM + 10;
2095  }
2096 
2097  void OnClick(Point pt, int widget, int click_count) override
2098  {
2099  if (widget == WID_NJS_CANCELOK) { // Disconnect button
2101  SwitchToMode(SM_MENU);
2102  ShowNetworkGameWindow();
2103  }
2104  }
2105 
2106  void OnQueryTextFinished(char *str) override
2107  {
2108  if (StrEmpty(str)) {
2110  ShowNetworkGameWindow();
2111  return;
2112  }
2113 
2114  switch (this->password_type) {
2117  default: NOT_REACHED();
2118  }
2119  }
2120 };
2121 
2122 static const NWidgetPart _nested_network_join_status_window_widgets[] = {
2123  NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_CONNECTING_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2124  NWidget(WWT_PANEL, COLOUR_GREY),
2125  NWidget(WWT_EMPTY, COLOUR_GREY, WID_NJS_BACKGROUND),
2127  NWidget(NWID_SPACER), SetMinimalSize(75, 0), SetFill(1, 0),
2128  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NJS_CANCELOK), SetMinimalSize(101, 12), SetDataTip(STR_NETWORK_CONNECTION_DISCONNECT, STR_NULL),
2129  NWidget(NWID_SPACER), SetMinimalSize(75, 0), SetFill(1, 0),
2130  EndContainer(),
2132  EndContainer(),
2133 };
2134 
2135 static WindowDesc _network_join_status_window_desc(
2136  WDP_CENTER, nullptr, 0, 0,
2138  WDF_MODAL,
2139  _nested_network_join_status_window_widgets, lengthof(_nested_network_join_status_window_widgets)
2140 );
2141 
2142 void ShowJoinStatusWindow()
2143 {
2145  new NetworkJoinStatusWindow(&_network_join_status_window_desc);
2146 }
2147 
2148 void ShowNetworkNeedPassword(NetworkPasswordType npt)
2149 {
2151  if (w == nullptr) return;
2152  w->password_type = npt;
2153 
2154  StringID caption;
2155  switch (npt) {
2156  default: NOT_REACHED();
2157  case NETWORK_GAME_PASSWORD: caption = STR_NETWORK_NEED_GAME_PASSWORD_CAPTION; break;
2158  case NETWORK_COMPANY_PASSWORD: caption = STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION; break;
2159  }
2161 }
2162 
2166 
2167  NetworkCompanyPasswordWindow(WindowDesc *desc, Window *parent) : Window(desc), password_editbox(lengthof(_settings_client.network.default_company_pass))
2168  {
2169  this->InitNested(0);
2170  this->UpdateWarningStringSize();
2171 
2172  this->parent = parent;
2173  this->querystrings[WID_NCP_PASSWORD] = &this->password_editbox;
2174  this->password_editbox.cancel_button = WID_NCP_CANCEL;
2175  this->password_editbox.ok_button = WID_NCP_OK;
2176  this->SetFocusedWidget(WID_NCP_PASSWORD);
2177  }
2178 
2179  void UpdateWarningStringSize()
2180  {
2181  assert(this->nested_root->smallest_x > 0);
2182  this->warning_size.width = this->nested_root->current_x - (WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT);
2183  this->warning_size.height = GetStringHeight(STR_WARNING_PASSWORD_SECURITY, this->warning_size.width);
2184  this->warning_size.height += WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
2185 
2186  this->ReInit();
2187  }
2188 
2189  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
2190  {
2191  if (widget == WID_NCP_WARNING) {
2192  *size = this->warning_size;
2193  }
2194  }
2195 
2196  void DrawWidget(const Rect &r, int widget) const override
2197  {
2198  if (widget != WID_NCP_WARNING) return;
2199 
2201  r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM,
2202  STR_WARNING_PASSWORD_SECURITY, TC_FROMSTRING, SA_CENTER);
2203  }
2204 
2205  void OnOk()
2206  {
2207  if (this->IsWidgetLowered(WID_NCP_SAVE_AS_DEFAULT_PASSWORD)) {
2209  }
2210 
2211  NetworkChangeCompanyPassword(_local_company, this->password_editbox.text.buf);
2212  }
2213 
2214  void OnClick(Point pt, int widget, int click_count) override
2215  {
2216  switch (widget) {
2217  case WID_NCP_OK:
2218  this->OnOk();
2219  FALLTHROUGH;
2220 
2221  case WID_NCP_CANCEL:
2222  delete this;
2223  break;
2224 
2226  this->ToggleWidgetLoweredState(WID_NCP_SAVE_AS_DEFAULT_PASSWORD);
2227  this->SetDirty();
2228  break;
2229  }
2230  }
2231 };
2232 
2233 static const NWidgetPart _nested_network_company_password_window_widgets[] = {
2235  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
2236  NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_COMPANY_PASSWORD_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2237  EndContainer(),
2238  NWidget(WWT_PANEL, COLOUR_GREY, WID_NCP_BACKGROUND),
2239  NWidget(NWID_VERTICAL), SetPIP(5, 5, 5),
2240  NWidget(NWID_HORIZONTAL), SetPIP(5, 5, 5),
2241  NWidget(WWT_TEXT, COLOUR_GREY, WID_NCP_LABEL), SetDataTip(STR_COMPANY_VIEW_PASSWORD, STR_NULL),
2242  NWidget(WWT_EDITBOX, COLOUR_GREY, WID_NCP_PASSWORD), SetFill(1, 0), SetMinimalSize(194, 12), SetDataTip(STR_COMPANY_VIEW_SET_PASSWORD, STR_NULL),
2243  EndContainer(),
2244  NWidget(NWID_HORIZONTAL), SetPIP(5, 0, 5),
2245  NWidget(NWID_SPACER), SetFill(1, 0),
2247  SetDataTip(STR_COMPANY_PASSWORD_MAKE_DEFAULT, STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP),
2248  EndContainer(),
2249  EndContainer(),
2250  EndContainer(),
2251  NWidget(WWT_PANEL, COLOUR_GREY, WID_NCP_WARNING), EndContainer(),
2253  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NCP_CANCEL), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_COMPANY_PASSWORD_CANCEL),
2254  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NCP_OK), SetFill(1, 0), SetDataTip(STR_BUTTON_OK, STR_COMPANY_PASSWORD_OK),
2255  EndContainer(),
2256 };
2257 
2258 static WindowDesc _network_company_password_window_desc(
2259  WDP_AUTO, nullptr, 0, 0,
2261  0,
2262  _nested_network_company_password_window_widgets, lengthof(_nested_network_company_password_window_widgets)
2263 );
2264 
2265 void ShowNetworkCompanyPasswordWindow(Window *parent)
2266 {
2268 
2269  new NetworkCompanyPasswordWindow(&_network_company_password_window_desc, parent);
2270 }
EventState
State of handling an event.
Definition: window_type.h:713
void Draw(const Window *w) override
Draw the widgets of the tree.
Date start_date
When the game started.
Definition: game.h:36
static const uint NETWORK_CLIENT_NAME_LENGTH
The maximum length of a client&#39;s name, in bytes including &#39;\0&#39;.
Definition: config.h:49
Owner
Enum for all companies/owners.
Definition: company_type.h:20
byte spectators_max
Max spectators allowed on server.
Definition: game.h:53
Label for &#39;connection type&#39;.
static bool NGameClientSorter(NetworkGameList *const &a, NetworkGameList *const &b)
Sort servers by the amount of clients online on a server.
uint16 map_height
Map height.
Definition: game.h:39
Empty widget, place holder to reserve space in widget array.
Definition: widget_type.h:48
Panel of the window.
Send message/notice to all clients (All)
Definition: network_type.h:81
Main handle for clientlist.
SizingType
Different forms of sizing nested widgets, using NWidgetBase::AssignSizePosition() ...
Definition: widget_type.h:111
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban)
Ban, or kick, everyone joined from the given client&#39;s IP.
Network game window.
Definition: window_type.h:29
void RebuildDone()
Notify the sortlist that the rebuild is done.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:81
bool CheckClientListHeight()
Finds the amount of clients and set the height correct.
Main panel.
Spacer for game actual details.
void OnPaint() override
The window must be repainted.
Container for all information known about a client.
Definition: network_base.h:25
Horizontally center the text.
Definition: gfx_func.h:97
void DrawWidget(const Rect &r, int widget) const override
Draw the contents of a nested widget.
void ScrollTowards(int position)
Scroll towards the given position; if the item is visible nothing happens, otherwise it will be shown...
Definition: widget_type.h:731
static NWidgetPart SetResize(int16 dx, int16 dy)
Widget part function for setting the resize step.
Definition: widget_type.h:930
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
Update size and resize step of a widget in the window.
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:112
bool server_advertise
advertise the server to the masterserver
Point pos
logical mouse position
Definition: gfx_type.h:119
static NWidgetPart NWidgetFunction(NWidgetFunctionType *func_ptr)
Obtain a nested widget (sub)tree from an external source.
Definition: widget_type.h:1146
uint resize_x
Horizontal resize step (0 means not resizable).
Definition: widget_type.h:166
uint8 lan_internet
search on the LAN or internet for servers
void OnPaint() override
The window must be repainted.
uint16 last_port
port of the last joined server
High level window description.
Definition: window_gui.h:168
&#39;Max spectators&#39; text.
int CompareTo(NetworkAddress &address)
Compare the address of this class with the address of another.
Definition: address.h:130
void OnClick(Point pt, int widget, int click_count) override
A click with the left mouse button has been made on the window.
Client list; Window numbers:
Definition: window_type.h:474
void SetMinimalSize(uint min_x, uint min_y)
Set minimal size of the widget.
Definition: widget.cpp:817
&#39;Cancel&#39; button.
EconomySettings economy
settings to change the economy
NWidgetCore * GetWidgetFromPos(int x, int y) override
Retrieve a widget by its position.
Definition: widget.cpp:905
bool Filter(FilterFunction *decide, F filter_data)
Filter the list.
char server_name[NETWORK_NAME_LENGTH]
name of the server
Load game button.
Baseclass for container widgets.
Definition: widget_type.h:368
static NetworkRecvStatus SendGamePassword(const char *password)
Set the game password as requested.
Switch to game intro menu.
Definition: openttd.h:32
NetworkGameList * next
Next pointer to make a linked game list.
GUIs related to networking.
Scrollbar data structure.
Definition: widget_type.h:589
void OnResize() override
Called after the window got resized.
Label for &#39;max spectators&#39;.
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
Definition: string.cpp:409
byte server_lang
Language of the server (we should make a nice table for this)
Definition: game.h:48
static void DrawMatrix(const Rect &r, Colours colour, bool clicked, uint16 data, uint resize_x, uint resize_y)
Draw a matrix widget.
Definition: widget.cpp:278
Offset at top to draw the frame rectangular area.
Definition: window_gui.h:64
Normal amount of vertical space between two paragraphs of text.
Definition: window_gui.h:139
Horizontal container.
Definition: widget_type.h:75
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition: window.cpp:1114
void ResetState()
Reset the matching state to process a new item.
The passed event is not handled.
Definition: window_type.h:715
bool Elapsed(uint delta)
Test if a timer has elapsed.
Definition: guitimer_func.h:57
Background of the window.
void SetSortFuncs(SortFunction *const *n_funcs)
Hand the array of sort function pointers to the sort list.
bool GetState() const
Get the matching state of the current item.
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:1121
NWidgetBase * tail
Pointer to last widget in container.
Definition: widget_type.h:383
Input field for the password.
Label for &#39;language spoken&#39;.
ClientID client_id
Client identifier (same as ClientState->client_id)
Definition: network_base.h:26
Popup for the client list; Window numbers:
Definition: window_type.h:480
bool version_compatible
Can we connect to this server or not? (based on server_revision)
Definition: game.h:44
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
Update size and resize step of a widget in the window.
void OnClick(Point pt, int widget, int click_count) override
A click with the left mouse button has been made on the window.
&#39;Cancel&#39; button.
NetworkJoinStatus _network_join_status
The status of joining.
The client wants a new company.
Definition: company_type.h:36
void OnClick(Point pt, int widget, int click_count) override
A click with the left mouse button has been made on the window.
a textbox for typing
Definition: widget_type.h:71
Resize box (normally at bottom-right of a window)
Definition: widget_type.h:68
static const int ACTION_CLEAR
Clear editbox.
void DrawWidget(const Rect &r, int widget) const override
Draw the contents of a nested widget.
NetworkGameList * last_joined
the last joined server
static const uint MAX_CLIENTS
How many clients can we have.
Definition: network_type.h:18
Sending and receiving UDP messages.
&#39;New company&#39; button.
Client part of the network protocol.
QueryString filter_editbox
Editbox for filter on servers.
void NetworkGameListRemoveItem(NetworkGameList *remove)
Remove an item from the gamelist linked list.
ServerListPosition list_pos
position of the selected server
Wrapper for (un)resolved network addresses; there&#39;s no reason to transform a numeric IP to a string a...
Definition: address.h:29
bool give_money
allow giving other companies money
void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override
Assign size and position to the widget.
Toggle &#39;button&#39; for saving the current password as default password.
int GetStringHeight(const char *str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition: gfx.cpp:547
Close box (at top-left of a window)
Definition: widget_type.h:69
QueryString password_editbox
Password editbox.
Offset at top of a matrix cell.
Definition: window_gui.h:80
Header container of the matrix.
uint16 map_width
Map width.
Definition: game.h:38
Send message/notice to only a certain client (Private)
Definition: network_type.h:83
bool NeedResort()
Check if a resort is needed next loop If used the resort timer will decrease every call till 0...
Heading text.
Panel with editbox to set client name.
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
Update size and resize step of a widget in the window.
String filter and state.
#define lastof(x)
Get the last element of an fixed size array.
Definition: depend.cpp:50
bool IsWidgetVisible(NetworkGameWidgets widget) const
Checks whether the given widget is actually visible.
return success even when the text didn&#39;t change
Definition: textbuf_gui.h:22
void OnDropdownSelect(int widget, int index) override
A dropdown option associated to this window has been selected.
Play scenario button.
void DrawWidget(const Rect &r, int widget) const override
Draw the contents of a nested widget.
Base core network types and some helper functions to access them.
void SetFilterFuncs(FilterFunction *const *n_funcs)
Hand the array of filter function pointers to the sort list.
Structure with information shown in the game list (GUI)
#define CLRBITS(x, y)
Clears several bits in a variable.
&#39;Max clients&#39; uparrow.
void NetworkUDPQueryServer(NetworkAddress address, bool manually)
Query a specific server.
Definition: network_udp.cpp:80
ClientID
&#39;Unique&#39; identifier to be given to clients
Definition: network_type.h:41
uint smallest_x
Smallest horizontal size of the widget in a filled window.
Definition: widget_type.h:171
static T max(const T a, const T b)
Returns the maximum of two values.
Definition: math_func.hpp:26
&#39;Add server&#39; button.
&#39;Years&#39; button.
Label "Last joined server:".
&#39;Language spoken&#39; droplist button.
void SetListing(Listing l)
Import sort conditions.
Pure simple text.
Definition: widget_type.h:58
EventState OnKeyPress(WChar key, uint16 keycode) override
A key has been pressed.
char server_name[NETWORK_NAME_LENGTH]
Server name.
Definition: game.h:40
bool NeedRebuild() const
Check if a rebuild is needed.
void SortNetworkGameList()
Sort the server list.
void UpdateNetworkGameWindow()
Update the network new window because a new server is found on the network.
Definition: network_gui.cpp:84
static const uint MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER
Minimum width before adding a new header.
Definition: network_gui.cpp:95
static const uint32 GENERATE_NEW_SEED
Create a new random seed.
Definition: genworld.h:26
bool _left_button_clicked
Is left mouse button clicked?
Definition: gfx.cpp:41
static bool IsInsideBS(const T x, const size_t base, const size_t size)
Checks if a value is between a window started at some base point.
Definition: math_func.hpp:250
std::vector< ClientListAction > actions
Actions to execute.
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition: widget.cpp:177
Network lobby window.
Definition: window_type.h:30
The password of the company.
Definition: network_type.h:76
Leaf widget.
Definition: widget_type.h:770
void SetCount(int num)
Sets the number of elements in the list.
Definition: widget_type.h:670
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:910
void ForceRebuild()
Force that a rebuild is needed.
void OnDropdownSelect(int widget, int index) override
A dropdown option associated to this window has been selected.
Data structure for an opened window.
Definition: window_gui.h:278
The game information that is sent from the server to the clients.
Definition: game.h:34
bool _ctrl_pressed
Is Ctrl pressed?
Definition: gfx.cpp:37
static bool NGameNameSorter(NetworkGameList *const &a, NetworkGameList *const &b)
Sort servers by name.
NWidgetBase * next
Pointer to next widget in container. Managed by parent container widget.
Definition: widget_type.h:180
byte companies_max
Max companies allowed on server.
Definition: game.h:51
static NWidgetPart SetMatrixDataTip(uint8 cols, uint8 rows, StringID tip)
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
Definition: widget_type.h:1032
old or new savegame
Definition: fileio_type.h:20
void SetFilterTerm(const char *str)
Set the term to filter on.
old or new scenario
Definition: fileio_type.h:21
static bool IsInsideMM(const T x, const size_t min, const size_t max)
Checks if a value is in an interval.
Definition: math_func.hpp:266
void StartNewGameWithoutGUI(uint32 seed)
Start a normal game without the GUI.
Bottom offset of the text of the frame.
Definition: window_gui.h:75
byte widget_id
The widget that has the pop-up input menu.
void OnResize() override
Called after the window got resized.
void SetDParamStr(uint n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition: strings.cpp:281
void ShowMissingContentWindow(const GRFConfig *list)
Show the content list window with all missing grfs from the given list.
void Add(NWidgetBase *wid)
Append widget wid to container.
Definition: widget.cpp:944
List of companies.
NetworkSettings network
settings related to the network
void BuildGUINetworkGameList()
(Re)build the GUI network game list (a.k.a.
bool _is_network_server
Does this client wants to be a network-server?
Definition: network.cpp:58
Only numeric ones.
Definition: string_type.h:30
NWidgetBase ** nested_array
Array of pointers into the tree. Do not access directly, use Window::GetWidget() instead.
Definition: window_gui.h:332
NetworkGameList * NetworkGameListAddItem(NetworkAddress address)
Add a new item to the linked gamelist.
Invisible widget that takes some space.
Definition: widget_type.h:79
CompanyID client_playas
As which company is this client playing (CompanyID)
Definition: network_base.h:29
Cancel / OK button.
&#39;Find server&#39; button.
byte companies_on
How many started companies do we have.
Definition: game.h:50
void NetworkUDPSearchGame()
Find all servers.
static void ShowNetworkLobbyWindow(NetworkGameList *ngl)
Show the networklobbywindow with the selected server.
Offset at bottom of a matrix cell.
Definition: window_gui.h:81
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX) ...
Definition: widget_type.h:65
static NetworkRecvStatus SendCompanyPassword(const char *password)
Set the company password as requested.
int GetScrolledRowFromWidget(int clickpos, const Window *const w, int widget, int padding=0, int line_height=-1) const
Compute the row of a scrolled widget that a user clicked in.
Definition: widget.cpp:1959
void NetworkServerKickClient(ClientID client_id)
Kick a single client.
&#39;NewGRF Settings&#39; button.
The client is spectating.
Definition: company_type.h:37
Selection widget for the above button.
char client_name[NETWORK_CLIENT_NAME_LENGTH]
Name of the client.
Definition: network_base.h:27
Listing GetListing() const
Export current sort conditions.
void OnQueryTextFinished(char *str) override
The query window opened from this window has closed.
void DrawWidget(const Rect &r, int widget) const override
Draw the contents of a nested widget.
Header above list of companies.
int ok_button
Widget button of parent window to simulate when pressing OK in OSK.
Scrollbar of matrix.
uint8 max_spectators
maximum amount of spectators
byte clients_max
Max clients allowed on server.
Definition: game.h:49
uint smallest_y
Smallest vertical size of the widget in a filled window.
Definition: widget_type.h:172
uint current_y
Current vertical size (after resizing).
Definition: widget_type.h:175
&#39;Map size&#39; button.
Company information stored at the client side.
Definition: network_gui.h:30
void DrawWidget(const Rect &r, int widget) const override
Draw the contents of a nested widget.
Sort descending.
Definition: window_gui.h:227
void SetStringParameters(int widget) const override
Initialize string parameters for a widget.
Safe the password etc.
bool _left_button_down
Is left mouse button pressed?
Definition: gfx.cpp:40
Play heightmap button.
#define FONT_HEIGHT_NORMAL
Height of characters in the normal (FS_NORMAL) font.
Definition: gfx_func.h:178
static NWidgetPart SetDataTip(uint32 data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1014
void SetFill(uint fill_x, uint fill_y)
Set the filling of the widget from initial size.
Definition: widget.cpp:839
void DrawServerLine(const NetworkGameList *cur_item, uint y, bool highlight) const
Draw a single server line.
Data stored about a string that can be modified in the GUI.
ClientID _network_own_client_id
Our client identifier.
Definition: network.cpp:61
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:80
static NWidgetPart SetMinimalSize(int16 x, int16 y)
Widget part function for setting the minimal size.
Definition: widget_type.h:947
void NetworkUDPQueryMasterServer()
Request the the server-list from the master server.
Center both horizontally and vertically.
Definition: gfx_func.h:106
Data structure to convert between Date and triplet (year, month, and day).
Definition: date_type.h:103
void OnMouseOver(Point pt, int widget) override
The mouse is currently moving over the window or has just moved outside of the window.
bool use_password
Is this server passworded?
Definition: game.h:46
void OnEditboxChanged(int wid) override
The text in an editbox has been edited.
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition: gfx_type.h:247
void DrawWidget(const Rect &r, int widget) const override
Draw the contents of a nested widget.
Third button in the game list panel.
char connect_to_ip[NETWORK_HOSTNAME_LENGTH]
default for the "Add server" query
Warning text about password security.
Normal push-button (no toggle button) with text caption.
Definition: widget_type.h:104
uint fill_y
Vertical fill stepsize (from initial size, 0 means not resizable).
Definition: widget_type.h:165
Simple depressed panel.
Definition: widget_type.h:50
void OnClick(Point pt, int widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnRealtimeTick(uint delta_ms) override
Called periodically.
static const uint MILLISECONDS_PER_TICK
The number of milliseconds per game tick.
Definition: gfx_type.h:306
void OnPaint() override
The window must be repainted.
Window timeout counter.
Definition: window_gui.h:234
static const StringID _connection_types_dropdown[]
Advertisement options in the start server window.
Definition: network_gui.cpp:51
Spacer after last joined server panel.
int pos_x
Horizontal position of top-left corner of the widget in the window.
Definition: widget_type.h:177
void ShowGenerateLandscape()
Start with a normal game.
NetworkAddress address
The connection info of the game server.
void SetDParamMaxDigits(uint n, uint count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition: strings.cpp:122
#define FOR_ALL_CLIENT_INFOS(var)
Iterate over all the clients.
Definition: network_base.h:53
void SetPadding(uint8 top, uint8 right, uint8 bottom, uint8 left)
Set additional space (padding) around the widget.
Definition: widget_type.h:149
Center the window.
Definition: window_gui.h:157
&#39;Join game&#39; button.
New game button.
byte clients_on
Current count of clients on server.
Definition: game.h:28
NetworkGameInfo info
The game information of this server.
void OnClick(Point pt, int widget, int click_count) override
A click with the left mouse button has been made on the window.
static NWidgetPart NWidget(WidgetType tp, Colours col, int16 idx=-1)
Widget part function for starting a new &#39;real&#39; widget.
Definition: widget_type.h:1114
&#39;Set password&#39; button.
char server_revision[NETWORK_REVISION_LENGTH]
The version number the server is using (e.g.: &#39;r304&#39; or 0.5.0)
Definition: game.h:42
NetworkGameList * _network_game_list
Game list of this client.
Offset at bottom to draw the frame rectangular area.
Definition: window_gui.h:65
Baseclass for nested widgets.
Definition: widget_type.h:126
int DrawString(int left, int right, int top, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition: gfx.cpp:499
void SetupSmallestSize(Window *w, bool init_array) override
Compute smallest size needed by the widget.
All flags cleared.
Definition: widget_type.h:428
Basic functions/variables used all over the place.
Part of the network protocol handling content distribution.
bool visible[6]
The visible headers.
Definition: network_gui.cpp:96
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
Update size and resize step of a widget in the window.
&#39;Max companies&#39; downarrow.
void NetworkGameListRequery()
Requeries the (game) servers we have not gotten a reply from.
Background of the window.
Right offset of the text of the frame.
Definition: window_gui.h:73
int lock_offset
Left offset for lock icon.
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:42
Label for &#39;max companies&#39;.
uint resize_y
Vertical resize step (0 means not resizable).
Definition: widget_type.h:167
Grid of rows and columns.
Definition: widget_type.h:59
static bool NGameDateSorter(NetworkGameList *const &a, NetworkGameList *const &b)
Sort servers by current date.
&#39;Clients&#39; button.
Panel with game details.
File is being loaded.
Definition: fileio_type.h:51
static T min(const T a, const T b)
Returns the minimum of two values.
Definition: math_func.hpp:42
&#39;Date&#39; button.
uint8 server_lang
language of the server
NWidgetBase * prev
Pointer to previous widget in container. Managed by parent container widget.
Definition: widget_type.h:181
Top offset of the text of the frame.
Definition: window_gui.h:74
&#39;Join company&#39; button.
Left offset of the text of the frame.
Definition: window_gui.h:72
static const uint NETWORK_HOSTNAME_LENGTH
The maximum length of the host name, in bytes including &#39;\0&#39;.
Definition: config.h:44
int cancel_button
Widget button of parent window to simulate when pressing CANCEL in OSK.
void SetSortType(uint8 n_type)
Set the sorttype of the list.
bool Sort(SortFunction *compare)
Sort the list.
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition: widget.cpp:658
uint32 StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:18
void DeleteWindowByClass(WindowClass cls)
Delete all windows of a given class.
Definition: window.cpp:1159
static const uint8 PC_BLACK
Black palette colour.
Definition: gfx_func.h:205
Background of the window.
Panel with the edit box to enter the search text.
uint32 _network_join_bytes
The number of bytes we already downloaded.
static bool NGameYearsSorter(NetworkGameList *const &a, NetworkGameList *const &b)
Sort servers by the number of days the game is running.
NetworkGameList * server
Selected server.
Network start server.
Definition: window_type.h:32
static const int WIDGET_LIST_END
indicate the end of widgets&#39; list for vararg functions
Definition: widget_type.h:22
Selection &#39;widget&#39; to hide the NewGRF settings.
The window is a modal child of some other window, meaning the parent is &#39;inactive&#39;.
Definition: window_gui.h:211
uint8 max_companies
maximum amount of companies
static T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition: math_func.hpp:139
CompanyID company
Selected company.
void Assign(StringID string)
Render a string into the textbuffer.
Definition: textbuf.cpp:398
Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:698
Network status window; Window numbers:
Definition: window_type.h:487
&#39;Max clients&#39; downarrow.
void AddLine(const char *str)
Pass another text line from the current item to the filter.
void OnEditboxChanged(int wid) override
The text in an editbox has been edited.
StringID name
Name of the action to execute.
char map_name[NETWORK_NAME_LENGTH]
Map which is played ["random" for a randomized map].
Definition: game.h:27
StringList _network_host_list
The servers we know.
Definition: network.cpp:66
int blot_offset
Left offset for green/yellow/red compatibility icon.
void ForceResort()
Force a resort next Sort call Reset the resort timer if used too.
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Label in front of the filter/search edit box.
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:40
byte map_set
Graphical set.
Definition: game.h:54
void DeleteWindowById(WindowClass cls, WindowNumber number, bool force)
Delete a window by its class and window number (if it is open).
Definition: window.cpp:1146
static const StringID _lan_internet_types_dropdown[]
Advertisement options in the server list.
Definition: network_gui.cpp:60
The client is joining.
Definition: company_type.h:35
Date game_date
Current date.
Definition: game.h:37
static const uint8 PC_GREY
Grey palette colour.
Definition: gfx_func.h:207
static const uint8 PC_DARK_BLUE
Dark blue palette colour.
Definition: gfx_func.h:224
void DrawCompanyIcon(CompanyID cid, int x, int y)
Draw the icon of a company.
The password of the game.
Definition: network_type.h:75
bool online
False if the server did not respond (default status)
&#39;Max clients&#39; text.
void SetResize(uint resize_x, uint resize_y)
Set resize step of the widget.
Definition: widget.cpp:850
ClientList_Action_Proc * proc
Action to execute.
Network join status.
Definition: window_type.h:34
char *const buf
buffer in which text is saved
Definition: textbuf_type.h:34
An invalid company.
Definition: company_type.h:32
void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config)
Setup the NewGRF gui.
char client_name[NETWORK_CLIENT_NAME_LENGTH]
name of the player (as client)
Info about the last joined server.
virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)=0
Assign size and position to the widget.
Both numeric and alphabetic and spaces and stuff.
Definition: string_type.h:29
Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override
Compute the initial position of the window.
NetworkJoinStatus
Status of the clients during joining.
Label for the game name.
Panel with list of games.
Window caption (window title between closebox and stickybox)
Definition: widget_type.h:61
int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
Definition: string.cpp:580
void OnClick(Point pt, int widget, int click_count) override
A click with the left mouse button has been made on the window.
static bool StrEmpty(const char *s)
Check if a string buffer is empty.
Definition: string_func.h:59
void SetFilterState(bool state)
Enable or disable the filter.
int flag_offset
Left offset for language flag icon.
GUITimer requery_timer
Timer for network requery.
void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fop)
Launch save/load dialog in the given mode.
Definition: fios_gui.cpp:890
&#39;Start server&#39; button.
Label in front of client name edit box.
void SetStringParameters(int widget) const override
Initialize string parameters for a widget.
Handling of the list of games.
First company, same as owner.
Definition: company_type.h:24
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition: strings.cpp:50
void ToggleSortOrder()
Toggle the sort order Since that is the worst condition for the sort function reverse the list here...
static void PopupClientList(ClientID client_id, int x, int y)
Show the popup (action list)
Scroll bar.
void OnQueryTextFinished(char *str) override
The query window opened from this window has closed.
bool CDECL FilterFunction(const T *, F)
Signature of filter function.
Definition: sortlist_type.h:52
Label for &#39;max clients&#39;.
Sort ascending.
Definition: window_gui.h:226
uint8 max_clients
maximum amount of clients
void SetDParamMaxValue(uint n, uint64 max_value, uint min_count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition: strings.cpp:106
&#39;Max companies&#39; text.
Vertical container.
Definition: widget_type.h:77
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
Update size and resize step of a widget in the window.
NWidgetCore * GetWidgetFromPos(int x, int y) override
Retrieve a widget by its position.
static NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME, WWT_INSET, or WWT_PANEL).
Definition: widget_type.h:999
Label in front of connection droplist.
Network window; Window numbers:
Definition: window_type.h:468
&#39;Refresh server&#39; button.
char * strecpy(char *dst, const char *src, const char *last)
Copies characters from one buffer to another.
Definition: depend.cpp:68
&#39;Find missing NewGRF online&#39; button.
uint current_x
Current horizontal size (after resizing).
Definition: widget_type.h:174
&#39;Max spectators&#39; downarrow.
Maximum number of companies.
Definition: company_type.h:25
Background of the window.
static bool NGameMapSizeSorter(NetworkGameList *const &a, NetworkGameList *const &b)
Sort servers by map size.
Popup selection window to chose an action to perform.
Company details.
char default_company_pass[NETWORK_PASSWORD_LENGTH]
default password for new companies in encrypted form
void DrawWidget(const Rect &r, int widget) const override
Draw the contents of a nested widget.
NetworkGameWidgets
Widgets of the NetworkGameWindow class.
NWidgetBase * head
Pointer to first widget in container.
Definition: widget_type.h:382
bool _network_server
network-server is active
Definition: network.cpp:55
Panel of the window.
Coordinates of a point in 2D.
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition: gfx.cpp:767
Dimension warning_size
How much space to use for the warning text.
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition: pool_type.hpp:235
Data structure describing how to show the list (what sort direction and criteria).
Definition: sortlist_type.h:33
void SetStringParameters(int widget) const override
Initialize string parameters for a widget.
Drop down list.
Definition: widget_type.h:70
&#39;Refresh server&#39; button.
uint16 GetPort() const
Get the port.
Definition: address.cpp:37
void OnQueryTextFinished(char *str) override
The query window opened from this window has closed.
uint16 GetCapacity() const
Gets the number of visible elements of the scrollbar.
Definition: widget_type.h:622
void NetworkDisconnect(bool blocking, bool close_admins)
We want to disconnect from the host/clients.
Definition: network.cpp:796
&#39;Max companies&#39; uparrow.
heightmap file
Definition: fileio_type.h:22
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:19
uint32 _network_join_bytes_total
The total number of bytes to download.
Background for editbox to set game name.
Offset at right to draw the frame rectangular area.
Definition: window_gui.h:63
char last_host[NETWORK_HOSTNAME_LENGTH]
IP address of the last joined server.
void AddAction(StringID name, ClientList_Action_Proc *proc)
Add an action to the list of actions to execute.
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition: widget_type.h:66
Company password query; Window numbers:
Definition: window_type.h:499
&#39;Spectate game&#39; button.
static const uint NETWORK_NAME_LENGTH
The maximum length of the server name and map name, in bytes including &#39;\0&#39;.
Definition: config.h:42
static const uint NETWORK_PASSWORD_LENGTH
The maximum length of the password, in bytes including &#39;\0&#39; (must be >= NETWORK_SERVER_ID_LENGTH) ...
Definition: config.h:47
static NWidgetPart SetFill(uint fill_x, uint fill_y)
Widget part function for setting filling.
Definition: widget_type.h:983
static bool NGameAllowedSorter(NetworkGameList *const &a, NetworkGameList *const &b)
Sort servers by joinability.
Close the window without changing anything.
&#39;Name&#39; button.
QueryString name_editbox
Client name editbox.
bool IsDescSortOrder() const
Check if the sort order is descending.
Servers always have this ID.
Definition: network_type.h:43
Full blown container to make it behave exactly as we want :)
Definition: network_gui.cpp:94
NetworkGameList * server
selected server
static const uint MAX_MAP_SIZE
Maximal map size = 4096.
Definition: map_type.h:68
int32 WindowNumber
Number to differentiate different windows of the same class.
Definition: window_type.h:707
void SetCapacityFromWidget(Window *w, int widget, int padding=0)
Set capacity of visible elements from the size and resize properties of a widget. ...
Definition: widget.cpp:1973
Specification of a rectangle with absolute coordinates of all edges.
Vertical scrollbar.
Definition: widget_type.h:84
NetworkPasswordType
The type of password we&#39;re asking for.
Definition: network_type.h:74
The passed event is handled.
Definition: window_type.h:714
void ScrollToSelectedServer()
Scroll the list up or down to the currently selected server.
Text is written right-to-left by default.
Definition: strings_type.h:26
void ClientList_Action_Proc(const NetworkClientInfo *ci)
Prototype for ClientList actions.
QueryString name_editbox
Server name editbox.
static NetworkClientInfo * GetByClientID(ClientID client_id)
Return the CI given it&#39;s client-identifier.
Definition: network.cpp:124
Find a place automatically.
Definition: window_gui.h:156
(Toggle) Button with image
Definition: widget_type.h:52
GUIGameServerList servers
list with game servers.
char server_password[NETWORK_PASSWORD_LENGTH]
password for joining this server
&#39;Connection&#39; droplist button.
const char * NetworkChangeCompanyPassword(CompanyID company_id, const char *password)
Change the company password of a given company.
Definition: network.cpp:172
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition: widget_type.h:80
uint8 _network_join_waiting
The number of clients waiting in front of us.
password entry box, show warning about password security
Definition: textbuf_gui.h:25
bool SortFunction(const T &, const T &)
Signature of sort function.
Definition: sortlist_type.h:51
GRFConfig * grfconfig
List of NewGRF files used.
Definition: game.h:35
uint32 WChar
Type for wide characters, i.e.
Definition: string_type.h:37
Container for actions that can be executed.
Scrollbar * vscroll
vertical scrollbar of the list of servers
void ConvertDateToYMD(Date date, YearMonthDay *ymd)
Converts a Date to a Year, Month & Day.
Definition: date.cpp:94
void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen)
Resize the window.
Definition: window.cpp:2126
Label in front of the password field.
virtual void SetDirty(const Window *w) const
Mark the widget as &#39;dirty&#39; (in need of repaint).
Definition: widget.cpp:775
Window white border counter bit mask.
Definition: window_gui.h:242
&#39;Cancel&#39; button.
Send message/notice to everyone playing the same company (Team)
Definition: network_type.h:82
static NWidgetPart SetScrollbar(int index)
Attach a scrollbar to a widget.
Definition: widget_type.h:1095
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:46
uint fill_x
Horizontal fill stepsize (from initial size, 0 means not resizable).
Definition: widget_type.h:164
Dimensions (a width and height) of a rectangle in 2D.
Value of the NCB_EQUALSIZE flag.
Definition: widget_type.h:429
bool IsEmpty() const
Check whether any filter words were entered.
Offset at left to draw the frame rectangular area.
Definition: window_gui.h:62
&#39;Connection type&#39; droplist button.
void UpdateListPos()
Set this->list_pos to match this->server.
void GetAddressAsString(char *buffer, const char *last, bool with_family=true)
Get the address as a string, e.g.
Definition: address.cpp:79
byte spectators_on
How many spectators do we have?
Definition: game.h:52
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:832
static NWidgetPart SetPIP(uint8 pre, uint8 inter, uint8 post)
Widget part function for setting a pre/inter/post spaces.
Definition: widget_type.h:1076
bool compatible
Can we connect to this server or not? (based on server_revision and grf_match.
Definition: game.h:45
void ShowNetworkChatQueryWindow(DestType type, int dest)
Show the chat window.
void OnTimeout() override
Called when this window&#39;s timeout has been reached.
int pos_y
Vertical position of top-left corner of the widget in the window.
Definition: widget_type.h:178
static const SpriteID SPR_FLAGS_BASE
Flags sprites (in same order as enum NetworkLanguage)
Definition: sprites.h:291
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:3300
int DrawStringMultiLine(int left, int right, int top, int bottom, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition: gfx.cpp:620
(Toggle) Button with text
Definition: widget_type.h:55
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
Update size and resize step of a widget in the window.
NetworkCompanyInfo * GetLobbyCompanyInfo(CompanyID company)
Get the company information of a given company to fill for the lobby.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
uint16 GetPosition() const
Gets the position of the first visible element in the list.
Definition: widget_type.h:631
&#39;Max spectators&#39; uparrow.
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
Update size and resize step of a widget in the window.
uint8 SortType() const
Get the sorttype of the list.
Definition: sortlist_type.h:96
static void SetDParam(uint n, uint64 v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings_func.h:201
Base class for a &#39;real&#39; widget.
Definition: widget_type.h:284
void OnMouseLoop() override
Called for every mouse loop run, which is at least once per (game) tick.