OpenTTD Source  1.10.3
network_gui.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
10 #include "../stdafx.h"
11 #include "../strings_func.h"
12 #include "../date_func.h"
13 #include "../fios.h"
14 #include "network_client.h"
15 #include "network_gui.h"
16 #include "network_gamelist.h"
17 #include "network.h"
18 #include "network_base.h"
19 #include "network_content.h"
20 #include "../gui.h"
21 #include "network_udp.h"
22 #include "../window_func.h"
23 #include "../gfx_func.h"
24 #include "../widgets/dropdown_func.h"
25 #include "../querystring_gui.h"
26 #include "../sortlist_type.h"
27 #include "../company_func.h"
28 #include "../core/geometry_func.hpp"
29 #include "../genworld.h"
30 #include "../map_type.h"
31 #include "../guitimer_func.h"
32 
33 #include "../widgets/network_widget.h"
34 
35 #include "table/strings.h"
36 #include "../table/sprites.h"
37 
38 #include "../stringfilter_type.h"
39 
40 #include "../safeguards.h"
41 
42 
43 static void ShowNetworkStartServerWindow();
44 static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
45 
50  STR_NETWORK_START_SERVER_UNADVERTISED,
51  STR_NETWORK_START_SERVER_ADVERTISED,
53 };
54 
59  STR_NETWORK_SERVER_LIST_ADVERTISED_NO,
60  STR_NETWORK_SERVER_LIST_ADVERTISED_YES,
62 };
63 
64 static std::vector<StringID> _language_dropdown;
65 
66 void SortNetworkLanguages()
67 {
68  /* Init the strings */
69  if (_language_dropdown.empty()) {
70  for (int i = 0; i < NETLANG_COUNT; i++) _language_dropdown.emplace_back(STR_NETWORK_LANG_ANY + i);
71  _language_dropdown.emplace_back(INVALID_STRING_ID);
72  }
73 
74  /* Sort the strings (we don't move 'any' and the 'invalid' one) */
75  std::sort(_language_dropdown.begin() + 1, _language_dropdown.end() - 1, StringIDSorter);
76 }
77 
83 {
85 }
86 
88 typedef uint16 ServerListPosition;
89 static const ServerListPosition SLP_INVALID = 0xFFFF;
90 
93  static const uint MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER = 150;
94  bool visible[6];
95 public:
97  {
98  NWidgetLeaf *leaf = new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NAME, STR_NETWORK_SERVER_LIST_GAME_NAME, STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP);
99  leaf->SetResize(1, 0);
100  leaf->SetFill(1, 0);
101  this->Add(leaf);
102 
103  this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CLIENTS, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP));
104  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));
105  this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_DATE, STR_NETWORK_SERVER_LIST_DATE_CAPTION, STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP));
106  this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_YEARS, STR_NETWORK_SERVER_LIST_YEARS_CAPTION, STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP));
107 
108  leaf = new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_INFO, STR_EMPTY, STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP);
109  leaf->SetMinimalSize(14 + GetSpriteSize(SPR_LOCK).width + GetSpriteSize(SPR_BLOT).width + GetSpriteSize(SPR_FLAGS_BASE).width, 12);
110  leaf->SetFill(0, 1);
111  this->Add(leaf);
112 
113  /* First and last are always visible, the rest is implicitly zeroed */
114  this->visible[0] = true;
115  *lastof(this->visible) = true;
116  }
117 
118  void SetupSmallestSize(Window *w, bool init_array) override
119  {
120  /* Oh yeah, we ought to be findable! */
121  w->nested_array[WID_NG_HEADER] = this;
122 
123  this->smallest_y = 0; // Biggest child.
124  this->fill_x = 1;
125  this->fill_y = 0;
126  this->resize_x = 1; // We only resize in this direction
127  this->resize_y = 0; // We never resize in this direction
128 
129  /* First initialise some variables... */
130  for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
131  child_wid->SetupSmallestSize(w, init_array);
132  this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom);
133  }
134 
135  /* ... then in a second pass make sure the 'current' sizes are set. Won't change for most widgets. */
136  for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
137  child_wid->current_x = child_wid->smallest_x;
138  child_wid->current_y = this->smallest_y;
139  }
140 
141  this->smallest_x = this->head->smallest_x + this->tail->smallest_x; // First and last are always shown, rest not
142  }
143 
144  void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override
145  {
146  assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
147 
148  this->pos_x = x;
149  this->pos_y = y;
150  this->current_x = given_width;
151  this->current_y = given_height;
152 
153  given_width -= this->tail->smallest_x;
154  NWidgetBase *child_wid = this->head->next;
155  /* The first and last widget are always visible, determine which other should be visible */
156  for (uint i = 1; i < lengthof(this->visible) - 1; i++) {
157  if (given_width > MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER + child_wid->smallest_x && this->visible[i - 1]) {
158  this->visible[i] = true;
159  given_width -= child_wid->smallest_x;
160  } else {
161  this->visible[i] = false;
162  }
163  child_wid = child_wid->next;
164  }
165 
166  /* All remaining space goes to the first (name) widget */
167  this->head->current_x = given_width;
168 
169  /* Now assign the widgets to their rightful place */
170  uint position = 0; // Place to put next child relative to origin of the container.
171  uint i = rtl ? lengthof(this->visible) - 1 : 0;
172  child_wid = rtl ? this->tail : this->head;
173  while (child_wid != nullptr) {
174  if (this->visible[i]) {
175  child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl);
176  position += child_wid->current_x;
177  }
178 
179  child_wid = rtl ? child_wid->prev : child_wid->next;
180  i += rtl ? -1 : 1;
181  }
182  }
183 
184  void Draw(const Window *w) override
185  {
186  int i = 0;
187  for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
188  if (!this->visible[i++]) continue;
189 
190  child_wid->Draw(w);
191  }
192  }
193 
194  NWidgetCore *GetWidgetFromPos(int x, int y) override
195  {
196  if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return nullptr;
197 
198  int i = 0;
199  for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
200  if (!this->visible[i++]) continue;
201  NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y);
202  if (nwid != nullptr) return nwid;
203  }
204  return nullptr;
205  }
206 
213  {
214  assert((uint)(widget - WID_NG_NAME) < lengthof(this->visible));
215  return this->visible[widget - WID_NG_NAME];
216  }
217 };
218 
219 class NetworkGameWindow : public Window {
220 protected:
221  /* Runtime saved values */
222  static Listing last_sorting;
223 
224  /* Constants for sorting servers */
225  static GUIGameServerList::SortFunction * const sorter_funcs[];
226  static GUIGameServerList::FilterFunction * const filter_funcs[];
227 
231  ServerListPosition list_pos;
236 
240 
247  {
248  if (!this->servers.NeedRebuild()) return;
249 
250  /* Create temporary array of games to use for listing */
251  this->servers.clear();
252 
253  for (NetworkGameList *ngl = _network_game_list; ngl != nullptr; ngl = ngl->next) {
254  this->servers.push_back(ngl);
255  }
256 
257  /* Apply the filter condition immediately, if a search string has been provided. */
258  StringFilter sf;
259  sf.SetFilterTerm(this->filter_editbox.text.buf);
260 
261  if (!sf.IsEmpty()) {
262  this->servers.SetFilterState(true);
263  this->servers.Filter(sf);
264  } else {
265  this->servers.SetFilterState(false);
266  }
267 
268  this->servers.shrink_to_fit();
269  this->servers.RebuildDone();
270  this->vscroll->SetCount((int)this->servers.size());
271 
272  /* Sort the list of network games as requested. */
273  this->servers.Sort();
274  this->UpdateListPos();
275  }
276 
278  static bool NGameNameSorter(NetworkGameList * const &a, NetworkGameList * const &b)
279  {
280  int r = strnatcmp(a->info.server_name, b->info.server_name, true); // Sort by name (natural sorting).
281  return r == 0 ? a->address.CompareTo(b->address) < 0: r < 0;
282  }
283 
289  static bool NGameClientSorter(NetworkGameList * const &a, NetworkGameList * const &b)
290  {
291  /* Reverse as per default we are interested in most-clients first */
292  int r = a->info.clients_on - b->info.clients_on;
293 
294  if (r == 0) r = a->info.clients_max - b->info.clients_max;
295  if (r == 0) return NGameNameSorter(a, b);
296 
297  return r < 0;
298  }
299 
301  static bool NGameMapSizeSorter(NetworkGameList * const &a, NetworkGameList * const &b)
302  {
303  /* Sort by the area of the map. */
304  int r = (a->info.map_height) * (a->info.map_width) - (b->info.map_height) * (b->info.map_width);
305 
306  if (r == 0) r = a->info.map_width - b->info.map_width;
307  return (r != 0) ? r < 0 : NGameClientSorter(a, b);
308  }
309 
311  static bool NGameDateSorter(NetworkGameList * const &a, NetworkGameList * const &b)
312  {
313  int r = a->info.game_date - b->info.game_date;
314  return (r != 0) ? r < 0 : NGameClientSorter(a, b);
315  }
316 
318  static bool NGameYearsSorter(NetworkGameList * const &a, NetworkGameList * const &b)
319  {
320  int r = a->info.game_date - a->info.start_date - b->info.game_date + b->info.start_date;
321  return (r != 0) ? r < 0: NGameDateSorter(a, b);
322  }
323 
328  static bool NGameAllowedSorter(NetworkGameList * const &a, NetworkGameList * const &b)
329  {
330  /* The servers we do not know anything about (the ones that did not reply) should be at the bottom) */
332 
333  /* Reverse default as we are interested in version-compatible clients first */
334  if (r == 0) r = b->info.version_compatible - a->info.version_compatible;
335  /* The version-compatible ones are then sorted with NewGRF compatible first, incompatible last */
336  if (r == 0) r = b->info.compatible - a->info.compatible;
337  /* Passworded servers should be below unpassworded servers */
338  if (r == 0) r = a->info.use_password - b->info.use_password;
339  /* Finally sort on the number of clients of the server */
340  if (r == 0) return NGameClientSorter(a, b);
341 
342  return r < 0;
343  }
344 
347  {
348  if (this->servers.Sort()) this->UpdateListPos();
349  }
350 
353  {
354  this->list_pos = SLP_INVALID;
355  for (uint i = 0; i != this->servers.size(); i++) {
356  if (this->servers[i] == this->server) {
357  this->list_pos = i;
358  break;
359  }
360  }
361  }
362 
363  static bool CDECL NGameSearchFilter(NetworkGameList * const *item, StringFilter &sf)
364  {
365  assert(item != nullptr);
366  assert((*item) != nullptr);
367 
368  sf.ResetState();
369  sf.AddLine((*item)->info.server_name);
370  return sf.GetState();
371  }
372 
379  void DrawServerLine(const NetworkGameList *cur_item, uint y, bool highlight) const
380  {
381  const NWidgetBase *nwi_name = this->GetWidget<NWidgetBase>(WID_NG_NAME);
382  const NWidgetBase *nwi_info = this->GetWidget<NWidgetBase>(WID_NG_INFO);
383 
384  /* show highlighted item with a different colour */
385  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);
386 
387  /* offsets to vertically centre text and icons */
388  int text_y_offset = (this->resize.step_height - FONT_HEIGHT_NORMAL) / 2 + 1;
389  int icon_y_offset = (this->resize.step_height - GetSpriteSize(SPR_BLOT).height) / 2;
390 
391  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);
392 
393  /* only draw details if the server is online */
394  if (cur_item->online) {
395  const NWidgetServerListHeader *nwi_header = this->GetWidget<NWidgetServerListHeader>(WID_NG_HEADER);
396 
397  if (nwi_header->IsWidgetVisible(WID_NG_CLIENTS)) {
398  const NWidgetBase *nwi_clients = this->GetWidget<NWidgetBase>(WID_NG_CLIENTS);
399  SetDParam(0, cur_item->info.clients_on);
400  SetDParam(1, cur_item->info.clients_max);
401  SetDParam(2, cur_item->info.companies_on);
402  SetDParam(3, cur_item->info.companies_max);
403  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);
404  }
405 
406  if (nwi_header->IsWidgetVisible(WID_NG_MAPSIZE)) {
407  /* map size */
408  const NWidgetBase *nwi_mapsize = this->GetWidget<NWidgetBase>(WID_NG_MAPSIZE);
409  SetDParam(0, cur_item->info.map_width);
410  SetDParam(1, cur_item->info.map_height);
411  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);
412  }
413 
414  if (nwi_header->IsWidgetVisible(WID_NG_DATE)) {
415  /* current date */
416  const NWidgetBase *nwi_date = this->GetWidget<NWidgetBase>(WID_NG_DATE);
417  YearMonthDay ymd;
418  ConvertDateToYMD(cur_item->info.game_date, &ymd);
419  SetDParam(0, ymd.year);
420  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);
421  }
422 
423  if (nwi_header->IsWidgetVisible(WID_NG_YEARS)) {
424  /* number of years the game is running */
425  const NWidgetBase *nwi_years = this->GetWidget<NWidgetBase>(WID_NG_YEARS);
426  YearMonthDay ymd_cur, ymd_start;
427  ConvertDateToYMD(cur_item->info.game_date, &ymd_cur);
428  ConvertDateToYMD(cur_item->info.start_date, &ymd_start);
429  SetDParam(0, ymd_cur.year - ymd_start.year);
430  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);
431  }
432 
433  /* draw a lock if the server is password protected */
434  if (cur_item->info.use_password) DrawSprite(SPR_LOCK, PAL_NONE, nwi_info->pos_x + this->lock_offset, y + icon_y_offset - 1);
435 
436  /* draw red or green icon, depending on compatibility with server */
437  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);
438 
439  /* draw flag according to server language */
440  DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, PAL_NONE, nwi_info->pos_x + this->flag_offset, y + icon_y_offset);
441  }
442  }
443 
452  {
453  if (this->list_pos == SLP_INVALID) return; // no server selected
454  this->vscroll->ScrollTowards(this->list_pos);
455  }
456 
457 public:
458  NetworkGameWindow(WindowDesc *desc) : Window(desc), name_editbox(NETWORK_CLIENT_NAME_LENGTH), filter_editbox(120)
459  {
460  this->list_pos = SLP_INVALID;
461  this->server = nullptr;
462 
463  this->lock_offset = 5;
464  this->blot_offset = this->lock_offset + 3 + GetSpriteSize(SPR_LOCK).width;
465  this->flag_offset = this->blot_offset + 2 + GetSpriteSize(SPR_BLOT).width;
466 
467  this->CreateNestedTree();
468  this->vscroll = this->GetScrollbar(WID_NG_SCROLLBAR);
469  this->FinishInitNested(WN_NETWORK_WINDOW_GAME);
470 
471  this->querystrings[WID_NG_CLIENT] = &this->name_editbox;
472  this->name_editbox.text.Assign(_settings_client.network.client_name);
473 
474  this->querystrings[WID_NG_FILTER] = &this->filter_editbox;
475  this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
476  this->SetFocusedWidget(WID_NG_FILTER);
477 
479  this->server = this->last_joined;
480  if (this->last_joined != nullptr) NetworkUDPQueryServer(this->last_joined->address);
481 
482  this->requery_timer.SetInterval(MILLISECONDS_PER_TICK);
483 
484  this->servers.SetListing(this->last_sorting);
485  this->servers.SetSortFuncs(this->sorter_funcs);
486  this->servers.SetFilterFuncs(this->filter_funcs);
487  this->servers.ForceRebuild();
488  }
489 
491  {
492  this->last_sorting = this->servers.GetListing();
493  }
494 
495  void SetStringParameters(int widget) const override
496  {
497  switch (widget) {
498  case WID_NG_CONN_BTN:
500  break;
501  }
502  }
503 
504  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
505  {
506  switch (widget) {
507  case WID_NG_CONN_BTN:
509  size->width += padding.width;
510  size->height += padding.height;
511  break;
512 
513  case WID_NG_MATRIX:
514  resize->height = WD_MATRIX_TOP + max(GetSpriteSize(SPR_BLOT).height, (uint)FONT_HEIGHT_NORMAL) + WD_MATRIX_BOTTOM;
515  size->height = 10 * resize->height;
516  break;
517 
518  case WID_NG_LASTJOINED:
519  size->height = WD_MATRIX_TOP + max(GetSpriteSize(SPR_BLOT).height, (uint)FONT_HEIGHT_NORMAL) + WD_MATRIX_BOTTOM;
520  break;
521 
523  size->width = NWidgetScrollbar::GetVerticalDimension().width;
524  break;
525 
526  case WID_NG_NAME:
527  size->width += 2 * Window::SortButtonWidth(); // Make space for the arrow
528  break;
529 
530  case WID_NG_CLIENTS:
531  size->width += 2 * Window::SortButtonWidth(); // Make space for the arrow
536  *size = maxdim(*size, GetStringBoundingBox(STR_NETWORK_SERVER_LIST_GENERAL_ONLINE));
537  break;
538 
539  case WID_NG_MAPSIZE:
540  size->width += 2 * Window::SortButtonWidth(); // Make space for the arrow
543  *size = maxdim(*size, GetStringBoundingBox(STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT));
544  break;
545 
546  case WID_NG_DATE:
547  case WID_NG_YEARS:
548  size->width += 2 * Window::SortButtonWidth(); // Make space for the arrow
549  SetDParamMaxValue(0, 5);
550  *size = maxdim(*size, GetStringBoundingBox(STR_JUST_INT));
551  break;
552 
554  size->height = 20 + 12 * FONT_HEIGHT_NORMAL;
555  break;
556  }
557  }
558 
559  void DrawWidget(const Rect &r, int widget) const override
560  {
561  switch (widget) {
562  case WID_NG_MATRIX: {
563  uint16 y = r.top;
564 
565  const int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (int)this->servers.size());
566 
567  for (int i = this->vscroll->GetPosition(); i < max; ++i) {
568  const NetworkGameList *ngl = this->servers[i];
569  this->DrawServerLine(ngl, y, ngl == this->server);
570  y += this->resize.step_height;
571  }
572  break;
573  }
574 
575  case WID_NG_LASTJOINED:
576  /* Draw the last joined server, if any */
577  if (this->last_joined != nullptr) this->DrawServerLine(this->last_joined, r.top, this->last_joined == this->server);
578  break;
579 
580  case WID_NG_DETAILS:
581  this->DrawDetails(r);
582  break;
583 
584  case WID_NG_NAME:
585  case WID_NG_CLIENTS:
586  case WID_NG_MAPSIZE:
587  case WID_NG_DATE:
588  case WID_NG_YEARS:
589  case WID_NG_INFO:
590  if (widget - WID_NG_NAME == this->servers.SortType()) this->DrawSortButtonState(widget, this->servers.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
591  break;
592  }
593  }
594 
595 
596  void OnPaint() override
597  {
598  if (this->servers.NeedRebuild()) {
599  this->BuildGUINetworkGameList();
600  }
601  if (this->servers.NeedResort()) {
602  this->SortNetworkGameList();
603  }
604 
605  NetworkGameList *sel = this->server;
606  /* 'Refresh' button invisible if no server selected */
607  this->SetWidgetDisabledState(WID_NG_REFRESH, sel == nullptr);
608  /* 'Join' button disabling conditions */
609  this->SetWidgetDisabledState(WID_NG_JOIN, sel == nullptr || // no Selected Server
610  !sel->online || // Server offline
611  sel->info.clients_on >= sel->info.clients_max || // Server full
612  !sel->info.compatible); // Revision mismatch
613 
614  /* 'NewGRF Settings' button invisible if no NewGRF is used */
615  this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == nullptr || !sel->online || sel->info.grfconfig == nullptr);
616  this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_MISSING_SEL)->SetDisplayedPlane(sel == nullptr || !sel->online || sel->info.grfconfig == nullptr || !sel->info.version_compatible || sel->info.compatible);
617 
618  this->DrawWidgets();
619  }
620 
621  void DrawDetails(const Rect &r) const
622  {
623  NetworkGameList *sel = this->server;
624 
625  const int detail_height = 6 + 8 + 6 + 3 * FONT_HEIGHT_NORMAL;
626 
627  /* Draw the right menu */
628  GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.top + detail_height - 1, PC_DARK_BLUE);
629  if (sel == nullptr) {
630  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);
631  } else if (!sel->online) {
632  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
633 
634  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
635  } else { // show game info
636 
637  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);
638  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
639  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
640 
641  uint16 y = r.top + detail_height + 4;
642 
643  SetDParam(0, sel->info.clients_on);
644  SetDParam(1, sel->info.clients_max);
645  SetDParam(2, sel->info.companies_on);
646  SetDParam(3, sel->info.companies_max);
647  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CLIENTS);
648  y += FONT_HEIGHT_NORMAL;
649 
650  SetDParam(0, STR_NETWORK_LANG_ANY + sel->info.server_lang);
651  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_LANGUAGE); // server language
652  y += FONT_HEIGHT_NORMAL;
653 
654  SetDParam(0, STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE + sel->info.map_set);
655  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_LANDSCAPE); // landscape
656  y += FONT_HEIGHT_NORMAL;
657 
658  SetDParam(0, sel->info.map_width);
659  SetDParam(1, sel->info.map_height);
660  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_MAP_SIZE); // map size
661  y += FONT_HEIGHT_NORMAL;
662 
664  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_VERSION); // server version
665  y += FONT_HEIGHT_NORMAL;
666 
667  char network_addr_buffer[NETWORK_HOSTNAME_LENGTH + 6 + 7];
668  sel->address.GetAddressAsString(network_addr_buffer, lastof(network_addr_buffer));
669  SetDParamStr(0, network_addr_buffer);
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  for (auto &company : this->company_info) company = {};
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 {
1692  NetworkServerKickClient(ci->client_id, nullptr);
1693 }
1694 
1695 static void ClientList_Ban(const NetworkClientInfo *ci)
1696 {
1697  NetworkServerKickOrBanIP(ci->client_id, true, nullptr);
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 
1889  /* Should be replaced with a loop through all clients */
1890  for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1891  if (ci->client_playas != COMPANY_INACTIVE_CLIENT) num++;
1892  }
1893 
1894  num *= this->line_height;
1895 
1896  int diff = (num + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM) - (this->GetWidget<NWidgetBase>(WID_CL_PANEL)->current_y);
1897  /* If height is changed */
1898  if (diff != 0) {
1899  ResizeWindow(this, 0, diff, false);
1900  return false;
1901  }
1902  return true;
1903  }
1904 
1905  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
1906  {
1907  if (widget != WID_CL_PANEL) return;
1908 
1909  this->server_client_width = max(GetStringBoundingBox(STR_NETWORK_SERVER).width, GetStringBoundingBox(STR_NETWORK_CLIENT).width) + WD_FRAMERECT_RIGHT;
1910  this->icon_size = GetSpriteSize(SPR_COMPANY_ICON);
1911  this->line_height = max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL);
1912 
1913  uint width = 100; // Default width
1914  for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1915  width = max(width, GetStringBoundingBox(ci->client_name).width);
1916  }
1917 
1918  size->width = WD_FRAMERECT_LEFT + this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT + width + WD_FRAMERECT_RIGHT;
1919  }
1920 
1921  void OnPaint() override
1922  {
1923  /* Check if we need to reset the height */
1924  if (!this->CheckClientListHeight()) return;
1925 
1926  this->DrawWidgets();
1927  }
1928 
1929  void DrawWidget(const Rect &r, int widget) const override
1930  {
1931  if (widget != WID_CL_PANEL) return;
1932 
1933  bool rtl = _current_text_dir == TD_RTL;
1934  int icon_offset = (this->line_height - icon_size.height) / 2;
1935  int text_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2;
1936 
1937  uint y = r.top + WD_FRAMERECT_TOP;
1938  uint left = r.left + WD_FRAMERECT_LEFT;
1939  uint right = r.right - WD_FRAMERECT_RIGHT;
1940  uint type_icon_width = this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT;
1941 
1942 
1943  uint type_left = rtl ? right - this->server_client_width : left;
1944  uint type_right = rtl ? right : left + this->server_client_width - 1;
1945  uint icon_left = rtl ? right - type_icon_width + WD_FRAMERECT_LEFT : left + this->server_client_width;
1946  uint name_left = rtl ? left : left + type_icon_width;
1947  uint name_right = rtl ? right - type_icon_width : right;
1948 
1949  int i = 0;
1950  for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1951  TextColour colour;
1952  if (this->selected_item == i++) { // Selected item, highlight it
1953  GfxFillRect(r.left + 1, y, r.right - 1, y + this->line_height - 1, PC_BLACK);
1954  colour = TC_WHITE;
1955  } else {
1956  colour = TC_BLACK;
1957  }
1958 
1959  if (ci->client_id == CLIENT_ID_SERVER) {
1960  DrawString(type_left, type_right, y + text_offset, STR_NETWORK_SERVER, colour);
1961  } else {
1962  DrawString(type_left, type_right, y + text_offset, STR_NETWORK_CLIENT, colour);
1963  }
1964 
1965  /* Filter out spectators */
1966  if (Company::IsValidID(ci->client_playas)) DrawCompanyIcon(ci->client_playas, icon_left, y + icon_offset);
1967 
1968  DrawString(name_left, name_right, y + text_offset, ci->client_name, colour);
1969 
1970  y += line_height;
1971  }
1972  }
1973 
1974  void OnClick(Point pt, int widget, int click_count) override
1975  {
1976  /* Show the popup with option */
1977  if (this->selected_item != -1) {
1978  int client_no = this->selected_item;
1980  if (client_no == 0) {
1981  PopupClientList(ci->client_id, pt.x + this->left, pt.y + this->top);
1982  break;
1983  }
1984  client_no--;
1985  }
1986  }
1987  }
1988 
1989  void OnMouseOver(Point pt, int widget) override
1990  {
1991  /* -1 means we left the current window */
1992  if (pt.y == -1) {
1993  this->selected_item = -1;
1994  this->SetDirty();
1995  return;
1996  }
1997 
1998  /* Find the new selected item (if any) */
1999  pt.y -= this->GetWidget<NWidgetBase>(WID_CL_PANEL)->pos_y;
2000  int item = -1;
2002  item = (pt.y - WD_FRAMERECT_TOP) / this->line_height;
2003  }
2004 
2005  /* It did not change.. no update! */
2006  if (item == this->selected_item) return;
2007  this->selected_item = item;
2008 
2009  /* Repaint */
2010  this->SetDirty();
2011  }
2012 };
2013 
2014 void ShowClientList()
2015 {
2016  AllocateWindowDescFront<NetworkClientListWindow>(&_client_list_desc, 0);
2017 }
2018 
2023 
2025  NetworkPasswordType password_type;
2026 
2028  {
2030  this->InitNested(WN_NETWORK_STATUS_WINDOW_JOIN);
2031  }
2032 
2033  void DrawWidget(const Rect &r, int widget) const override
2034  {
2035  if (widget != WID_NJS_BACKGROUND) return;
2036 
2037  uint8 progress; // used for progress bar
2038  DrawString(r.left + 2, r.right - 2, r.top + 20, STR_NETWORK_CONNECTING_1 + _network_join_status, TC_FROMSTRING, SA_HOR_CENTER);
2039  switch (_network_join_status) {
2040  case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING:
2041  case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
2042  progress = 10; // first two stages 10%
2043  break;
2044  case NETWORK_JOIN_STATUS_WAITING:
2045  SetDParam(0, _network_join_waiting);
2046  DrawString(r.left + 2, r.right - 2, r.top + 20 + FONT_HEIGHT_NORMAL, STR_NETWORK_CONNECTING_WAITING, TC_FROMSTRING, SA_HOR_CENTER);
2047  progress = 15; // third stage is 15%
2048  break;
2049  case NETWORK_JOIN_STATUS_DOWNLOADING:
2050  SetDParam(0, _network_join_bytes);
2051  SetDParam(1, _network_join_bytes_total);
2052  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);
2053  if (_network_join_bytes_total == 0) {
2054  progress = 15; // We don't have the final size yet; the server is still compressing!
2055  break;
2056  }
2057  FALLTHROUGH;
2058 
2059  default: // Waiting is 15%, so the resting receivement of map is maximum 70%
2060  progress = 15 + _network_join_bytes * (100 - 15) / _network_join_bytes_total;
2061  }
2062 
2063  /* Draw nice progress bar :) */
2064  DrawFrameRect(r.left + 20, r.top + 5, (int)((this->width - 20) * progress / 100), r.top + 15, COLOUR_MAUVE, FR_NONE);
2065  }
2066 
2067  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
2068  {
2069  if (widget != WID_NJS_BACKGROUND) return;
2070 
2071  size->height = 25 + 2 * FONT_HEIGHT_NORMAL;
2072 
2073  /* Account for the statuses */
2074  uint width = 0;
2075  for (uint i = 0; i < NETWORK_JOIN_STATUS_END; i++) {
2076  width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_1 + i).width);
2077  }
2078 
2079  /* For the number of waiting (other) players */
2081  width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_WAITING).width);
2082 
2083  /* Account for downloading ~ 10 MiB */
2084  SetDParamMaxDigits(0, 8);
2085  SetDParamMaxDigits(1, 8);
2086  width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_DOWNLOADING_1).width);
2087  width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_DOWNLOADING_2).width);
2088 
2089  /* Give a bit more clearing for the widest strings than strictly needed */
2090  size->width = width + WD_FRAMERECT_LEFT + WD_FRAMERECT_BOTTOM + 10;
2091  }
2092 
2093  void OnClick(Point pt, int widget, int click_count) override
2094  {
2095  if (widget == WID_NJS_CANCELOK) { // Disconnect button
2097  SwitchToMode(SM_MENU);
2098  ShowNetworkGameWindow();
2099  }
2100  }
2101 
2102  void OnQueryTextFinished(char *str) override
2103  {
2104  if (StrEmpty(str)) {
2106  ShowNetworkGameWindow();
2107  return;
2108  }
2109 
2110  switch (this->password_type) {
2113  default: NOT_REACHED();
2114  }
2115  }
2116 };
2117 
2118 static const NWidgetPart _nested_network_join_status_window_widgets[] = {
2119  NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_CONNECTING_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2120  NWidget(WWT_PANEL, COLOUR_GREY),
2121  NWidget(WWT_EMPTY, COLOUR_GREY, WID_NJS_BACKGROUND),
2123  NWidget(NWID_SPACER), SetMinimalSize(75, 0), SetFill(1, 0),
2124  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NJS_CANCELOK), SetMinimalSize(101, 12), SetDataTip(STR_NETWORK_CONNECTION_DISCONNECT, STR_NULL),
2125  NWidget(NWID_SPACER), SetMinimalSize(75, 0), SetFill(1, 0),
2126  EndContainer(),
2128  EndContainer(),
2129 };
2130 
2131 static WindowDesc _network_join_status_window_desc(
2132  WDP_CENTER, nullptr, 0, 0,
2134  WDF_MODAL,
2135  _nested_network_join_status_window_widgets, lengthof(_nested_network_join_status_window_widgets)
2136 );
2137 
2138 void ShowJoinStatusWindow()
2139 {
2141  new NetworkJoinStatusWindow(&_network_join_status_window_desc);
2142 }
2143 
2144 void ShowNetworkNeedPassword(NetworkPasswordType npt)
2145 {
2147  if (w == nullptr) return;
2148  w->password_type = npt;
2149 
2150  StringID caption;
2151  switch (npt) {
2152  default: NOT_REACHED();
2153  case NETWORK_GAME_PASSWORD: caption = STR_NETWORK_NEED_GAME_PASSWORD_CAPTION; break;
2154  case NETWORK_COMPANY_PASSWORD: caption = STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION; break;
2155  }
2157 }
2158 
2162 
2163  NetworkCompanyPasswordWindow(WindowDesc *desc, Window *parent) : Window(desc), password_editbox(lengthof(_settings_client.network.default_company_pass))
2164  {
2165  this->InitNested(0);
2166  this->UpdateWarningStringSize();
2167 
2168  this->parent = parent;
2169  this->querystrings[WID_NCP_PASSWORD] = &this->password_editbox;
2170  this->password_editbox.cancel_button = WID_NCP_CANCEL;
2171  this->password_editbox.ok_button = WID_NCP_OK;
2172  this->SetFocusedWidget(WID_NCP_PASSWORD);
2173  }
2174 
2175  void UpdateWarningStringSize()
2176  {
2177  assert(this->nested_root->smallest_x > 0);
2178  this->warning_size.width = this->nested_root->current_x - (WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT);
2179  this->warning_size.height = GetStringHeight(STR_WARNING_PASSWORD_SECURITY, this->warning_size.width);
2180  this->warning_size.height += WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
2181 
2182  this->ReInit();
2183  }
2184 
2185  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
2186  {
2187  if (widget == WID_NCP_WARNING) {
2188  *size = this->warning_size;
2189  }
2190  }
2191 
2192  void DrawWidget(const Rect &r, int widget) const override
2193  {
2194  if (widget != WID_NCP_WARNING) return;
2195 
2197  r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM,
2198  STR_WARNING_PASSWORD_SECURITY, TC_FROMSTRING, SA_CENTER);
2199  }
2200 
2201  void OnOk()
2202  {
2203  if (this->IsWidgetLowered(WID_NCP_SAVE_AS_DEFAULT_PASSWORD)) {
2205  }
2206 
2207  NetworkChangeCompanyPassword(_local_company, this->password_editbox.text.buf);
2208  }
2209 
2210  void OnClick(Point pt, int widget, int click_count) override
2211  {
2212  switch (widget) {
2213  case WID_NCP_OK:
2214  this->OnOk();
2215  FALLTHROUGH;
2216 
2217  case WID_NCP_CANCEL:
2218  delete this;
2219  break;
2220 
2222  this->ToggleWidgetLoweredState(WID_NCP_SAVE_AS_DEFAULT_PASSWORD);
2223  this->SetDirty();
2224  break;
2225  }
2226  }
2227 };
2228 
2229 static const NWidgetPart _nested_network_company_password_window_widgets[] = {
2231  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
2232  NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_COMPANY_PASSWORD_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2233  EndContainer(),
2234  NWidget(WWT_PANEL, COLOUR_GREY, WID_NCP_BACKGROUND),
2235  NWidget(NWID_VERTICAL), SetPIP(5, 5, 5),
2236  NWidget(NWID_HORIZONTAL), SetPIP(5, 5, 5),
2237  NWidget(WWT_TEXT, COLOUR_GREY, WID_NCP_LABEL), SetDataTip(STR_COMPANY_VIEW_PASSWORD, STR_NULL),
2238  NWidget(WWT_EDITBOX, COLOUR_GREY, WID_NCP_PASSWORD), SetFill(1, 0), SetMinimalSize(194, 12), SetDataTip(STR_COMPANY_VIEW_SET_PASSWORD, STR_NULL),
2239  EndContainer(),
2240  NWidget(NWID_HORIZONTAL), SetPIP(5, 0, 5),
2241  NWidget(NWID_SPACER), SetFill(1, 0),
2243  SetDataTip(STR_COMPANY_PASSWORD_MAKE_DEFAULT, STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP),
2244  EndContainer(),
2245  EndContainer(),
2246  EndContainer(),
2247  NWidget(WWT_PANEL, COLOUR_GREY, WID_NCP_WARNING), EndContainer(),
2249  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NCP_CANCEL), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_COMPANY_PASSWORD_CANCEL),
2250  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NCP_OK), SetFill(1, 0), SetDataTip(STR_BUTTON_OK, STR_COMPANY_PASSWORD_OK),
2251  EndContainer(),
2252 };
2253 
2254 static WindowDesc _network_company_password_window_desc(
2255  WDP_AUTO, nullptr, 0, 0,
2257  0,
2258  _nested_network_company_password_window_widgets, lengthof(_nested_network_company_password_window_widgets)
2259 );
2260 
2261 void ShowNetworkCompanyPasswordWindow(Window *parent)
2262 {
2264 
2265  new NetworkCompanyPasswordWindow(&_network_company_password_window_desc, parent);
2266 }
EventState
State of handling an event.
Definition: window_type.h:717
void Draw(const Window *w) override
Draw the widgets of the tree.
Date start_date
When the game started.
Definition: game.h:34
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:47
Owner
Enum for all companies/owners.
Definition: company_type.h:18
byte spectators_max
Max spectators allowed on server.
Definition: game.h:51
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:37
Empty widget, place holder to reserve space in widget array.
Definition: widget_type.h:46
Panel of the window.
Send message/notice to all clients (All)
Definition: network_type.h:82
Main handle for clientlist.
SizingType
Different forms of sizing nested widgets, using NWidgetBase::AssignSizePosition() ...
Definition: widget_type.h:109
Network game window.
Definition: window_type.h:27
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:80
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:23
Horizontally center the text.
Definition: gfx_func.h:95
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:729
static NWidgetPart SetResize(int16 dx, int16 dy)
Widget part function for setting the resize step.
Definition: widget_type.h:928
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:110
bool server_advertise
advertise the server to the masterserver
Point pos
logical mouse position
Definition: gfx_type.h:117
static NWidgetPart NWidgetFunction(NWidgetFunctionType *func_ptr)
Obtain a nested widget (sub)tree from an external source.
Definition: widget_type.h:1144
uint resize_x
Horizontal resize step (0 means not resizable).
Definition: widget_type.h:164
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:166
&#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:472
void SetMinimalSize(uint min_x, uint min_y)
Set minimal size of the widget.
Definition: widget.cpp:815
&#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:903
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:366
static NetworkRecvStatus SendGamePassword(const char *password)
Set the game password as requested.
Switch to game intro menu.
Definition: openttd.h:30
NetworkGameList * next
Next pointer to make a linked game list.
GUIs related to networking.
Scrollbar data structure.
Definition: widget_type.h:587
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:407
byte server_lang
Language of the server (we should make a nice table for this)
Definition: game.h:46
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:276
Offset at top to draw the frame rectangular area.
Definition: window_gui.h:62
Normal amount of vertical space between two paragraphs of text.
Definition: window_gui.h:137
Horizontal container.
Definition: widget_type.h:73
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition: window.cpp:1133
void ResetState()
Reset the matching state to process a new item.
The passed event is not handled.
Definition: window_type.h:719
bool Elapsed(uint delta)
Test if a timer has elapsed.
Definition: guitimer_func.h:55
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:381
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:24
Popup for the client list; Window numbers:
Definition: window_type.h:478
bool version_compatible
Can we connect to this server or not? (based on server_revision)
Definition: game.h:42
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:34
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:69
Resize box (normally at bottom-right of a window)
Definition: widget_type.h:66
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:16
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:685
Close box (at top-left of a window)
Definition: widget_type.h:67
QueryString password_editbox
Password editbox.
Offset at top of a matrix cell.
Definition: window_gui.h:78
Header container of the matrix.
uint16 map_width
Map width.
Definition: game.h:36
Send message/notice to only a certain client (Private)
Definition: network_type.h:84
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:48
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:20
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:78
ClientID
&#39;Unique&#39; identifier to be given to clients
Definition: network_type.h:39
uint smallest_x
Smallest horizontal size of the widget in a filled window.
Definition: widget_type.h:169
static T max(const T a, const T b)
Returns the maximum of two values.
Definition: math_func.hpp:24
&#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:56
EventState OnKeyPress(WChar key, uint16 keycode) override
A key has been pressed.
char server_name[NETWORK_NAME_LENGTH]
Server name.
Definition: game.h:38
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:82
static const uint MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER
Minimum width before adding a new header.
Definition: network_gui.cpp:93
static const uint32 GENERATE_NEW_SEED
Create a new random seed.
Definition: genworld.h:24
bool _left_button_clicked
Is left mouse button clicked?
Definition: gfx.cpp:39
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:248
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:175
Network lobby window.
Definition: window_type.h:28
The password of the company.
Definition: network_type.h:74
Leaf widget.
Definition: widget_type.h:768
void SetCount(int num)
Sets the number of elements in the list.
Definition: widget_type.h:668
bool Sort(Comp compare)
Sort the list.
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:908
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:276
The game information that is sent from the server to the clients.
Definition: game.h:32
bool _ctrl_pressed
Is Ctrl pressed?
Definition: gfx.cpp:35
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:178
byte companies_max
Max companies allowed on server.
Definition: game.h:49
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:1030
old or new savegame
Definition: fileio_type.h:18
void SetFilterTerm(const char *str)
Set the term to filter on.
old or new scenario
Definition: fileio_type.h:19
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:264
void StartNewGameWithoutGUI(uint32 seed)
Start a normal game without the GUI.
Bottom offset of the text of the frame.
Definition: window_gui.h:73
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:279
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:942
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:56
Only numeric ones.
Definition: string_type.h:28
NWidgetBase ** nested_array
Array of pointers into the tree. Do not access directly, use Window::GetWidget() instead.
Definition: window_gui.h:330
NetworkGameList * NetworkGameListAddItem(NetworkAddress address)
Add a new item to the linked gamelist.
Invisible widget that takes some space.
Definition: widget_type.h:77
CompanyID client_playas
As which company is this client playing (CompanyID)
Definition: network_base.h:27
Cancel / OK button.
&#39;Find server&#39; button.
byte companies_on
How many started companies do we have.
Definition: game.h:48
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:79
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX) ...
Definition: widget_type.h:63
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:1957
&#39;NewGRF Settings&#39; button.
The client is spectating.
Definition: company_type.h:35
Selection widget for the above button.
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:47
uint smallest_y
Smallest vertical size of the widget in a filled window.
Definition: widget_type.h:170
uint current_y
Current vertical size (after resizing).
Definition: widget_type.h:173
&#39;Map size&#39; button.
Company information stored at the client side.
Definition: network_gui.h:28
void DrawWidget(const Rect &r, int widget) const override
Draw the contents of a nested widget.
Sort descending.
Definition: window_gui.h:225
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:38
Play heightmap button.
#define FONT_HEIGHT_NORMAL
Height of characters in the normal (FS_NORMAL) font.
Definition: gfx_func.h:177
static NWidgetPart SetDataTip(uint32 data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1012
void SetFill(uint fill_x, uint fill_y)
Set the filling of the widget from initial size.
Definition: widget.cpp:837
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:59
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:79
static NWidgetPart SetMinimalSize(int16 x, int16 y)
Widget part function for setting the minimal size.
Definition: widget_type.h:945
void NetworkUDPQueryMasterServer()
Request the the server-list from the master server.
Center both horizontally and vertically.
Definition: gfx_func.h:104
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:44
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:245
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:102
uint fill_y
Vertical fill stepsize (from initial size, 0 means not resizable).
Definition: widget_type.h:163
Simple depressed panel.
Definition: widget_type.h:48
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:305
void OnPaint() override
The window must be repainted.
Window timeout counter.
Definition: window_gui.h:232
static const StringID _connection_types_dropdown[]
Advertisement options in the start server window.
Definition: network_gui.cpp:49
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:175
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:120
void SetPadding(uint8 top, uint8 right, uint8 bottom, uint8 left)
Set additional space (padding) around the widget.
Definition: widget_type.h:147
Center the window.
Definition: window_gui.h:155
&#39;Join game&#39; button.
New game button.
byte clients_on
Current count of clients on server.
Definition: game.h:26
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:1112
&#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:40
NetworkGameList * _network_game_list
Game list of this client.
Offset at bottom to draw the frame rectangular area.
Definition: window_gui.h:63
Baseclass for nested widgets.
Definition: widget_type.h:124
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:636
void SetupSmallestSize(Window *w, bool init_array) override
Compute smallest size needed by the widget.
All flags cleared.
Definition: widget_type.h:426
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:94
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:71
int lock_offset
Left offset for lock icon.
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:40
Label for &#39;max companies&#39;.
uint resize_y
Vertical resize step (0 means not resizable).
Definition: widget_type.h:165
Grid of rows and columns.
Definition: widget_type.h:57
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:49
static T min(const T a, const T b)
Returns the minimum of two values.
Definition: math_func.hpp:40
&#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:179
Top offset of the text of the frame.
Definition: window_gui.h:72
&#39;Join company&#39; button.
Left offset of the text of the frame.
Definition: window_gui.h:70
static const uint NETWORK_HOSTNAME_LENGTH
The maximum length of the host name, in bytes including &#39;\0&#39;.
Definition: config.h:42
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.
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition: widget.cpp:656
uint32 StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
void DeleteWindowByClass(WindowClass cls)
Delete all windows of a given class.
Definition: window.cpp:1178
static const uint8 PC_BLACK
Black palette colour.
Definition: gfx_func.h:204
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:30
static const int WIDGET_LIST_END
indicate the end of widgets&#39; list for vararg functions
Definition: widget_type.h:20
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:209
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:137
CompanyID company
Selected company.
void Assign(StringID string)
Render a string into the textbuffer.
Definition: textbuf.cpp:396
Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:838
Network status window; Window numbers:
Definition: window_type.h:485
&#39;Max clients&#39; downarrow.
void AddLine(const char *str)
Pass another text line from the current item to the filter.
void NetworkServerKickClient(ClientID client_id, const char *reason)
Kick a single client.
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:25
StringList _network_host_list
The servers we know.
Definition: network.cpp:64
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:38
byte map_set
Graphical set.
Definition: game.h:52
void DeleteWindowById(WindowClass cls, WindowNumber number, bool force)
Delete a window by its class and window number (if it is open).
Definition: window.cpp:1165
static const StringID _lan_internet_types_dropdown[]
Advertisement options in the server list.
Definition: network_gui.cpp:58
The client is joining.
Definition: company_type.h:33
Date game_date
Current date.
Definition: game.h:35
static const uint8 PC_GREY
Grey palette colour.
Definition: gfx_func.h:206
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:73
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:848
ClientList_Action_Proc * proc
Action to execute.
Network join status.
Definition: window_type.h:32
char *const buf
buffer in which text is saved
Definition: textbuf_type.h:32
An invalid company.
Definition: company_type.h:30
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, const char *reason)
Ban, or kick, everyone joined from the given client&#39;s IP.
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:27
Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override
Compute the initial position of the window.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition: pool_type.hpp:378
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:59
int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
Definition: string.cpp:578
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:57
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:918
&#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:22
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition: strings.cpp:48
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:50
Label for &#39;max clients&#39;.
Sort ascending.
Definition: window_gui.h:224
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:104
&#39;Max companies&#39; text.
Vertical container.
Definition: widget_type.h:75
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:997
Label in front of connection droplist.
Network window; Window numbers:
Definition: window_type.h:466
&#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:66
&#39;Find missing NewGRF online&#39; button.
uint current_x
Current horizontal size (after resizing).
Definition: widget_type.h:172
&#39;Max spectators&#39; downarrow.
Maximum number of companies.
Definition: company_type.h:23
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:380
bool _network_server
network-server is active
Definition: network.cpp:53
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:908
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:318
Data structure describing how to show the list (what sort direction and criteria).
Definition: sortlist_type.h:31
void SetStringParameters(int widget) const override
Initialize string parameters for a widget.
Drop down list.
Definition: widget_type.h:68
&#39;Refresh server&#39; button.
uint16 GetPort() const
Get the port.
Definition: address.cpp:35
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:620
void NetworkDisconnect(bool blocking, bool close_admins)
We want to disconnect from the host/clients.
Definition: network.cpp:781
&#39;Max companies&#39; uparrow.
heightmap file
Definition: fileio_type.h:20
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:17
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:61
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:64
Company password query; Window numbers:
Definition: window_type.h:497
&#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:40
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:45
static NWidgetPart SetFill(uint fill_x, uint fill_y)
Widget part function for setting filling.
Definition: widget_type.h:981
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:41
Full blown container to make it behave exactly as we want :)
Definition: network_gui.cpp:92
NetworkGameList * server
selected server
static const uint MAX_MAP_SIZE
Maximal map size = 4096.
Definition: map_type.h:66
int32 WindowNumber
Number to differentiate different windows of the same class.
Definition: window_type.h:711
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:1971
Specification of a rectangle with absolute coordinates of all edges.
Vertical scrollbar.
Definition: widget_type.h:82
NetworkPasswordType
The type of password we&#39;re asking for.
Definition: network_type.h:72
The passed event is handled.
Definition: window_type.h:718
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:24
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:119
Find a place automatically.
Definition: window_gui.h:154
(Toggle) Button with image
Definition: widget_type.h:50
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:162
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition: widget_type.h:78
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:23
bool SortFunction(const T &, const T &)
Signature of sort function.
Definition: sortlist_type.h:49
GRFConfig * grfconfig
List of NewGRF files used.
Definition: game.h:33
uint32 WChar
Type for wide characters, i.e.
Definition: string_type.h:35
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:95
void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen)
Resize the window.
Definition: window.cpp:2145
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:773
Window white border counter bit mask.
Definition: window_gui.h:240
&#39;Cancel&#39; button.
Send message/notice to everyone playing the same company (Team)
Definition: network_type.h:83
static NWidgetPart SetScrollbar(int index)
Attach a scrollbar to a widget.
Definition: widget_type.h:1093
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:44
uint fill_x
Horizontal fill stepsize (from initial size, 0 means not resizable).
Definition: widget_type.h:162
Dimensions (a width and height) of a rectangle in 2D.
Value of the NCB_EQUALSIZE flag.
Definition: widget_type.h:427
bool IsEmpty() const
Check whether any filter words were entered.
Offset at left to draw the frame rectangular area.
Definition: window_gui.h:60
&#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:77
byte spectators_on
How many spectators do we have?
Definition: game.h:50
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:973
static NWidgetPart SetPIP(uint8 pre, uint8 inter, uint8 post)
Widget part function for setting a pre/inter/post spaces.
Definition: widget_type.h:1074
bool compatible
Can we connect to this server or not? (based on server_revision and grf_match.
Definition: game.h:43
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:176
static const SpriteID SPR_FLAGS_BASE
Flags sprites (in same order as enum NetworkLanguage)
Definition: sprites.h:289
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:3319
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:759
(Toggle) Button with text
Definition: widget_type.h:53
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:629
&#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:94
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:199
Base class for a &#39;real&#39; widget.
Definition: widget_type.h:282
void OnMouseLoop() override
Called for every mouse loop run, which is at least once per (game) tick.