OpenTTD
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 
668  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_ADDRESS); // server address
669  y += FONT_HEIGHT_NORMAL;
670 
671  SetDParam(0, sel->info.start_date);
672  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_START_DATE); // start date
673  y += FONT_HEIGHT_NORMAL;
674 
675  SetDParam(0, sel->info.game_date);
676  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CURRENT_DATE); // current date
677  y += FONT_HEIGHT_NORMAL;
678 
679  y += WD_PAR_VSEP_NORMAL;
680 
681  if (!sel->info.compatible) {
682  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
683  } else if (sel->info.clients_on == sel->info.clients_max) {
684  /* Show: server full, when clients_on == max_clients */
685  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
686  } else if (sel->info.use_password) {
687  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_PASSWORD, TC_FROMSTRING, SA_HOR_CENTER); // password warning
688  }
689  }
690  }
691 
692  void OnClick(Point pt, int widget, int click_count) override
693  {
694  switch (widget) {
695  case WID_NG_CANCEL: // Cancel button
697  break;
698 
699  case WID_NG_CONN_BTN: // 'Connection' droplist
700  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
701  break;
702 
703  case WID_NG_NAME: // Sort by name
704  case WID_NG_CLIENTS: // Sort by connected clients
705  case WID_NG_MAPSIZE: // Sort by map size
706  case WID_NG_DATE: // Sort by date
707  case WID_NG_YEARS: // Sort by years
708  case WID_NG_INFO: // Connectivity (green dot)
709  if (this->servers.SortType() == widget - WID_NG_NAME) {
710  this->servers.ToggleSortOrder();
711  if (this->list_pos != SLP_INVALID) this->list_pos = (ServerListPosition)this->servers.size() - this->list_pos - 1;
712  } else {
713  this->servers.SetSortType(widget - WID_NG_NAME);
714  this->servers.ForceResort();
715  this->SortNetworkGameList();
716  }
717  this->ScrollToSelectedServer();
718  this->SetDirty();
719  break;
720 
721  case WID_NG_MATRIX: { // Show available network games
722  uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NG_MATRIX);
723  this->server = (id_v < this->servers.size()) ? this->servers[id_v] : nullptr;
724  this->list_pos = (server == nullptr) ? SLP_INVALID : id_v;
725  this->SetDirty();
726 
727  /* FIXME the disabling should go into some InvalidateData, which is called instead of the SetDirty */
728  if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
729  break;
730  }
731 
732  case WID_NG_LASTJOINED: {
733  if (this->last_joined != nullptr) {
734  this->server = this->last_joined;
735 
736  /* search the position of the newly selected server */
737  this->UpdateListPos();
738  this->ScrollToSelectedServer();
739  this->SetDirty();
740 
741  /* FIXME the disabling should go into some InvalidateData, which is called instead of the SetDirty */
742  if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
743  }
744  break;
745  }
746 
747  case WID_NG_FIND: // Find server automatically
749  case 0: NetworkUDPSearchGame(); break;
750  case 1: NetworkUDPQueryMasterServer(); break;
751  }
752  break;
753 
754  case WID_NG_ADD: // Add a server
757  STR_JUST_RAW_STRING,
758  STR_NETWORK_SERVER_LIST_ENTER_IP,
759  NETWORK_HOSTNAME_LENGTH, // maximum number of characters including '\0'
761  break;
762 
763  case WID_NG_START: // Start server
764  ShowNetworkStartServerWindow();
765  break;
766 
767  case WID_NG_JOIN: // Join Game
768  if (this->server != nullptr) {
769  seprintf(_settings_client.network.last_host, lastof(_settings_client.network.last_host), "%s", this->server->address.GetHostname());
771  ShowNetworkLobbyWindow(this->server);
772  }
773  break;
774 
775  case WID_NG_REFRESH: // Refresh
776  if (this->server != nullptr) NetworkUDPQueryServer(this->server->address);
777  break;
778 
779  case WID_NG_NEWGRF: // NewGRF Settings
780  if (this->server != nullptr) ShowNewGRFSettings(false, false, false, &this->server->info.grfconfig);
781  break;
782 
783  case WID_NG_NEWGRF_MISSING: // Find missing content online
784  if (this->server != nullptr) ShowMissingContentWindow(this->server->info.grfconfig);
785  break;
786  }
787  }
788 
789  void OnDropdownSelect(int widget, int index) override
790  {
791  switch (widget) {
792  case WID_NG_CONN_BTN:
794  break;
795 
796  default:
797  NOT_REACHED();
798  }
799 
800  this->SetDirty();
801  }
802 
808  void OnInvalidateData(int data = 0, bool gui_scope = true) override
809  {
810  this->servers.ForceRebuild();
811  this->SetDirty();
812  }
813 
814  EventState OnKeyPress(WChar key, uint16 keycode) override
815  {
816  EventState state = ES_NOT_HANDLED;
817 
818  /* handle up, down, pageup, pagedown, home and end */
819  if (keycode == WKC_UP || keycode == WKC_DOWN || keycode == WKC_PAGEUP || keycode == WKC_PAGEDOWN || keycode == WKC_HOME || keycode == WKC_END) {
820  if (this->servers.size() == 0) return ES_HANDLED;
821  switch (keycode) {
822  case WKC_UP:
823  /* scroll up by one */
824  if (this->list_pos == SLP_INVALID) return ES_HANDLED;
825  if (this->list_pos > 0) this->list_pos--;
826  break;
827  case WKC_DOWN:
828  /* scroll down by one */
829  if (this->list_pos == SLP_INVALID) return ES_HANDLED;
830  if (this->list_pos < this->servers.size() - 1) this->list_pos++;
831  break;
832  case WKC_PAGEUP:
833  /* scroll up a page */
834  if (this->list_pos == SLP_INVALID) return ES_HANDLED;
835  this->list_pos = (this->list_pos < this->vscroll->GetCapacity()) ? 0 : this->list_pos - this->vscroll->GetCapacity();
836  break;
837  case WKC_PAGEDOWN:
838  /* scroll down a page */
839  if (this->list_pos == SLP_INVALID) return ES_HANDLED;
840  this->list_pos = min(this->list_pos + this->vscroll->GetCapacity(), (int)this->servers.size() - 1);
841  break;
842  case WKC_HOME:
843  /* jump to beginning */
844  this->list_pos = 0;
845  break;
846  case WKC_END:
847  /* jump to end */
848  this->list_pos = (ServerListPosition)this->servers.size() - 1;
849  break;
850  default: NOT_REACHED();
851  }
852 
853  this->server = this->servers[this->list_pos];
854 
855  /* Scroll to the new server if it is outside the current range. */
856  this->ScrollToSelectedServer();
857 
858  /* redraw window */
859  this->SetDirty();
860  return ES_HANDLED;
861  }
862 
863  if (this->server != nullptr) {
864  if (keycode == WKC_DELETE) { // Press 'delete' to remove servers
865  NetworkGameListRemoveItem(this->server);
866  if (this->server == this->last_joined) this->last_joined = nullptr;
867  this->server = nullptr;
868  this->list_pos = SLP_INVALID;
869  }
870  }
871 
872  return state;
873  }
874 
875  void OnEditboxChanged(int wid) override
876  {
877  switch (wid) {
878  case WID_NG_FILTER: {
879  this->servers.ForceRebuild();
880  this->BuildGUINetworkGameList();
881  this->ScrollToSelectedServer();
882  this->SetDirty();
883  break;
884  }
885 
886  case WID_NG_CLIENT:
887  /* Make sure the name does not start with a space, so TAB completion works */
888  if (!StrEmpty(this->name_editbox.text.buf) && this->name_editbox.text.buf[0] != ' ') {
890  } else {
892  }
893  break;
894  }
895  }
896 
897  void OnQueryTextFinished(char *str) override
898  {
899  if (!StrEmpty(str)) NetworkAddServer(str);
900  }
901 
902  void OnResize() override
903  {
904  this->vscroll->SetCapacityFromWidget(this, WID_NG_MATRIX);
905  }
906 
907  void OnRealtimeTick(uint delta_ms) override
908  {
909  if (!this->requery_timer.Elapsed(delta_ms)) return;
910  this->requery_timer.SetInterval(MILLISECONDS_PER_TICK);
911 
913  }
914 };
915 
916 Listing NetworkGameWindow::last_sorting = {false, 5};
917 GUIGameServerList::SortFunction * const NetworkGameWindow::sorter_funcs[] = {
918  &NGameNameSorter,
919  &NGameClientSorter,
920  &NGameMapSizeSorter,
921  &NGameDateSorter,
922  &NGameYearsSorter,
923  &NGameAllowedSorter
924 };
925 
926 GUIGameServerList::FilterFunction * const NetworkGameWindow::filter_funcs[] = {
927  &NGameSearchFilter
928 };
929 
930 static NWidgetBase *MakeResizableHeader(int *biggest_index)
931 {
932  *biggest_index = max<int>(*biggest_index, WID_NG_INFO);
933  return new NWidgetServerListHeader();
934 }
935 
936 static const NWidgetPart _nested_network_game_widgets[] = {
937  /* TOP */
939  NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
940  NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_SERVER_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
941  NWidget(WWT_DEFSIZEBOX, COLOUR_LIGHT_BLUE),
942  EndContainer(),
943  NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_MAIN),
944  NWidget(NWID_VERTICAL), SetPIP(10, 7, 0),
945  NWidget(NWID_HORIZONTAL), SetPIP(10, 7, 10),
946  /* LEFT SIDE */
947  NWidget(NWID_VERTICAL), SetPIP(0, 7, 0),
948  NWidget(NWID_HORIZONTAL), SetPIP(0, 7, 0),
949  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_CONNECTION), SetDataTip(STR_NETWORK_SERVER_LIST_ADVERTISED, STR_NULL),
950  NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NG_CONN_BTN),
951  SetDataTip(STR_BLACK_STRING, STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP),
952  NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
953  EndContainer(),
954  NWidget(NWID_HORIZONTAL), SetPIP(0, 7, 0),
955  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_FILTER_LABEL), SetDataTip(STR_LIST_FILTER_TITLE, STR_NULL),
956  NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_FILTER), SetMinimalSize(251, 12), SetFill(1, 0), SetResize(1, 0),
957  SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
958  EndContainer(),
961  NWidgetFunction(MakeResizableHeader),
962  NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NG_MATRIX), SetResize(1, 1), SetFill(1, 0),
963  SetMatrixDataTip(1, 0, STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT), SetScrollbar(WID_NG_SCROLLBAR),
964  EndContainer(),
965  NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NG_SCROLLBAR),
966  EndContainer(),
968  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_LASTJOINED_LABEL), SetFill(1, 0),
969  SetDataTip(STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER, STR_NULL), SetResize(1, 0),
971  NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_LASTJOINED), SetFill(1, 0), SetResize(1, 0),
972  SetDataTip(0x0, STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST),
973  EndContainer(),
974  NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NG_LASTJOINED_SPACER), SetFill(0, 0),
975  EndContainer(),
976  EndContainer(),
977  EndContainer(),
978  /* RIGHT SIDE */
979  NWidget(NWID_VERTICAL), SetPIP(0, 7, 0),
980  NWidget(NWID_HORIZONTAL), SetPIP(0, 7, 0),
981  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_CLIENT_LABEL), SetDataTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME, STR_NULL),
982  NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_CLIENT), SetMinimalSize(151, 12), SetFill(1, 0), SetResize(1, 0),
983  SetDataTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE, STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP),
984  EndContainer(),
985  NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_DETAILS),
987  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
990  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),
991  NWidget(NWID_SPACER), SetFill(1, 0),
992  EndContainer(),
993  EndContainer(),
995  NWidget(NWID_SPACER), SetFill(1, 0),
996  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NG_NEWGRF_SEL),
997  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NEWGRF), SetFill(1, 0), SetDataTip(STR_INTRO_NEWGRF_SETTINGS, STR_NULL),
998  NWidget(NWID_SPACER), SetFill(1, 0),
999  EndContainer(),
1000  EndContainer(),
1002  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_JOIN), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_JOIN_GAME, STR_NULL),
1003  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_REFRESH), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_REFRESH, STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP),
1004  EndContainer(),
1005  EndContainer(),
1006  EndContainer(),
1007  EndContainer(),
1008  EndContainer(),
1009  /* BOTTOM */
1013  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),
1014  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),
1015  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),
1016  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CANCEL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
1017  EndContainer(),
1018  NWidget(NWID_SPACER), SetMinimalSize(0, 6), SetResize(1, 0), SetFill(1, 0),
1019  EndContainer(),
1021  NWidget(NWID_SPACER), SetFill(0, 1),
1022  NWidget(WWT_RESIZEBOX, COLOUR_LIGHT_BLUE),
1023  EndContainer(),
1024  EndContainer(),
1025  EndContainer(),
1026  EndContainer(),
1027 };
1028 
1029 static WindowDesc _network_game_window_desc(
1030  WDP_CENTER, "list_servers", 1000, 730,
1032  0,
1033  _nested_network_game_widgets, lengthof(_nested_network_game_widgets)
1034 );
1035 
1036 void ShowNetworkGameWindow()
1037 {
1038  static bool first = true;
1041 
1042  /* Only show once */
1043  if (first) {
1044  first = false;
1045  /* Add all servers from the config file to our list. */
1046  for (const auto &iter : _network_host_list) {
1047  NetworkAddServer(iter.c_str());
1048  }
1049  }
1050 
1051  new NetworkGameWindow(&_network_game_window_desc);
1052 }
1053 
1055  byte widget_id;
1057 
1058  NetworkStartServerWindow(WindowDesc *desc) : Window(desc), name_editbox(NETWORK_NAME_LENGTH)
1059  {
1060  this->InitNested(WN_NETWORK_WINDOW_START);
1061 
1062  this->querystrings[WID_NSS_GAMENAME] = &this->name_editbox;
1063  this->name_editbox.text.Assign(_settings_client.network.server_name);
1064 
1065  this->SetFocusedWidget(WID_NSS_GAMENAME);
1066  }
1067 
1068  void SetStringParameters(int widget) const override
1069  {
1070  switch (widget) {
1071  case WID_NSS_CONNTYPE_BTN:
1073  break;
1074 
1075  case WID_NSS_CLIENTS_TXT:
1077  break;
1078 
1079  case WID_NSS_COMPANIES_TXT:
1081  break;
1082 
1085  break;
1086 
1087  case WID_NSS_LANGUAGE_BTN:
1088  SetDParam(0, STR_NETWORK_LANG_ANY + _settings_client.network.server_lang);
1089  break;
1090  }
1091  }
1092 
1093  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
1094  {
1095  switch (widget) {
1096  case WID_NSS_CONNTYPE_BTN:
1098  size->width += padding.width;
1099  size->height += padding.height;
1100  break;
1101  }
1102  }
1103 
1104  void DrawWidget(const Rect &r, int widget) const override
1105  {
1106  switch (widget) {
1107  case WID_NSS_SETPWD:
1108  /* If password is set, draw red '*' next to 'Set password' button. */
1109  if (!StrEmpty(_settings_client.network.server_password)) DrawString(r.right + WD_FRAMERECT_LEFT, this->width - WD_FRAMERECT_RIGHT, r.top, "*", TC_RED);
1110  }
1111  }
1112 
1113  void OnClick(Point pt, int widget, int click_count) override
1114  {
1115  switch (widget) {
1116  case WID_NSS_CANCEL: // Cancel button
1117  ShowNetworkGameWindow();
1118  break;
1119 
1120  case WID_NSS_SETPWD: // Set password button
1121  this->widget_id = WID_NSS_SETPWD;
1123  ShowQueryString(STR_JUST_RAW_STRING, STR_NETWORK_START_SERVER_SET_PASSWORD, 20, this, CS_ALPHANUMERAL, QSF_NONE);
1124  break;
1125 
1126  case WID_NSS_CONNTYPE_BTN: // Connection type
1127  ShowDropDownMenu(this, _connection_types_dropdown, _settings_client.network.server_advertise, WID_NSS_CONNTYPE_BTN, 0, 0); // do it for widget WID_NSS_CONNTYPE_BTN
1128  break;
1129 
1130  case WID_NSS_CLIENTS_BTND: case WID_NSS_CLIENTS_BTNU: // Click on up/down button for number of clients
1131  case WID_NSS_COMPANIES_BTND: case WID_NSS_COMPANIES_BTNU: // Click on up/down button for number of companies
1132  case WID_NSS_SPECTATORS_BTND: case WID_NSS_SPECTATORS_BTNU: // Click on up/down button for number of spectators
1133  /* Don't allow too fast scrolling. */
1134  if (!(this->flags & WF_TIMEOUT) || this->timeout_timer <= 1) {
1135  this->HandleButtonClick(widget);
1136  this->SetDirty();
1137  switch (widget) {
1138  default: NOT_REACHED();
1141  break;
1144  break;
1147  break;
1148  }
1149  }
1150  _left_button_clicked = false;
1151  break;
1152 
1153  case WID_NSS_CLIENTS_TXT: // Click on number of clients
1154  this->widget_id = WID_NSS_CLIENTS_TXT;
1156  ShowQueryString(STR_JUST_INT, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS, 4, this, CS_NUMERAL, QSF_NONE);
1157  break;
1158 
1159  case WID_NSS_COMPANIES_TXT: // Click on number of companies
1160  this->widget_id = WID_NSS_COMPANIES_TXT;
1162  ShowQueryString(STR_JUST_INT, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES, 3, this, CS_NUMERAL, QSF_NONE);
1163  break;
1164 
1165  case WID_NSS_SPECTATORS_TXT: // Click on number of spectators
1166  this->widget_id = WID_NSS_SPECTATORS_TXT;
1168  ShowQueryString(STR_JUST_INT, STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS, 4, this, CS_NUMERAL, QSF_NONE);
1169  break;
1170 
1171  case WID_NSS_LANGUAGE_BTN: { // Language
1172  uint sel = 0;
1173  for (uint i = 0; i < _language_dropdown.size() - 1; i++) {
1174  if (_language_dropdown[i] == STR_NETWORK_LANG_ANY + _settings_client.network.server_lang) {
1175  sel = i;
1176  break;
1177  }
1178  }
1179  ShowDropDownMenu(this, _language_dropdown.data(), sel, WID_NSS_LANGUAGE_BTN, 0, 0);
1180  break;
1181  }
1182 
1183  case WID_NSS_GENERATE_GAME: // Start game
1184  _is_network_server = true;
1185  if (_ctrl_pressed) {
1187  } else {
1189  }
1190  break;
1191 
1192  case WID_NSS_LOAD_GAME:
1193  _is_network_server = true;
1195  break;
1196 
1197  case WID_NSS_PLAY_SCENARIO:
1198  _is_network_server = true;
1200  break;
1201 
1203  _is_network_server = true;
1205  break;
1206  }
1207  }
1208 
1209  void OnDropdownSelect(int widget, int index) override
1210  {
1211  switch (widget) {
1212  case WID_NSS_CONNTYPE_BTN:
1213  _settings_client.network.server_advertise = (index != 0);
1214  break;
1215  case WID_NSS_LANGUAGE_BTN:
1216  _settings_client.network.server_lang = _language_dropdown[index] - STR_NETWORK_LANG_ANY;
1217  break;
1218  default:
1219  NOT_REACHED();
1220  }
1221 
1222  this->SetDirty();
1223  }
1224 
1225  void OnEditboxChanged(int wid) override
1226  {
1227  if (wid == WID_NSS_GAMENAME) {
1229  }
1230  }
1231 
1232  void OnTimeout() override
1233  {
1235  for (const int *widget = raise_widgets; *widget != WIDGET_LIST_END; widget++) {
1236  if (this->IsWidgetLowered(*widget)) {
1237  this->RaiseWidget(*widget);
1238  this->SetWidgetDirty(*widget);
1239  }
1240  }
1241  }
1242 
1243  void OnQueryTextFinished(char *str) override
1244  {
1245  if (str == nullptr) return;
1246 
1247  if (this->widget_id == WID_NSS_SETPWD) {
1249  } else {
1250  int32 value = atoi(str);
1251  this->SetWidgetDirty(this->widget_id);
1252  switch (this->widget_id) {
1253  default: NOT_REACHED();
1257  }
1258  }
1259 
1260  this->SetDirty();
1261  }
1262 };
1263 
1264 static const NWidgetPart _nested_network_start_server_window_widgets[] = {
1266  NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
1267  NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_START_SERVER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1268  EndContainer(),
1269  NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NSS_BACKGROUND),
1270  NWidget(NWID_VERTICAL), SetPIP(10, 6, 10),
1272  NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
1273  /* Game name widgets */
1274  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_GAMENAME_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME, STR_NULL),
1275  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),
1276  EndContainer(),
1277  EndContainer(),
1278 
1280  NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
1281  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_ADVERTISED, STR_NULL),
1282  NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_BTN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP),
1283  EndContainer(),
1284  NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
1285  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_LANGUAGE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN, STR_NULL),
1286  NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_LANGUAGE_BTN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP),
1287  EndContainer(),
1288  NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
1289  NWidget(NWID_SPACER), SetFill(1, 1),
1290  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_SETPWD), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_SET_PASSWORD, STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP),
1291  EndContainer(),
1292  EndContainer(),
1293 
1295  NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
1296  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS, STR_NULL),
1298  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),
1299  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),
1300  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),
1301  EndContainer(),
1302  EndContainer(),
1303 
1304  NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
1305  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES, STR_NULL),
1307  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),
1308  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),
1309  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),
1310  EndContainer(),
1311  EndContainer(),
1312 
1313  NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
1314  NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_SPECTATORS_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS, STR_NULL),
1316  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),
1317  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),
1318  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),
1319  EndContainer(),
1320  EndContainer(),
1321  EndContainer(),
1322 
1323  /* 'generate game' and 'load game' buttons */
1325  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_GENERATE_GAME), SetDataTip(STR_INTRO_NEW_GAME, STR_INTRO_TOOLTIP_NEW_GAME), SetFill(1, 0),
1326  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_LOAD_GAME), SetDataTip(STR_INTRO_LOAD_GAME, STR_INTRO_TOOLTIP_LOAD_GAME), SetFill(1, 0),
1327  EndContainer(),
1328 
1329  /* 'play scenario' and 'play heightmap' buttons */
1331  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_PLAY_SCENARIO), SetDataTip(STR_INTRO_PLAY_SCENARIO, STR_INTRO_TOOLTIP_PLAY_SCENARIO), SetFill(1, 0),
1332  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_PLAY_HEIGHTMAP), SetDataTip(STR_INTRO_PLAY_HEIGHTMAP, STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP), SetFill(1, 0),
1333  EndContainer(),
1334 
1336  NWidget(NWID_SPACER), SetFill(1, 0),
1337  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_CANCEL), SetDataTip(STR_BUTTON_CANCEL, STR_NULL), SetMinimalSize(128, 12),
1338  NWidget(NWID_SPACER), SetFill(1, 0),
1339  EndContainer(),
1340  EndContainer(),
1341  EndContainer(),
1342 };
1343 
1344 static WindowDesc _network_start_server_window_desc(
1345  WDP_CENTER, nullptr, 0, 0,
1347  0,
1348  _nested_network_start_server_window_widgets, lengthof(_nested_network_start_server_window_widgets)
1349 );
1350 
1351 static void ShowNetworkStartServerWindow()
1352 {
1355 
1356  new NetworkStartServerWindow(&_network_start_server_window_desc);
1357 }
1358 
1359 struct NetworkLobbyWindow : public Window {
1362  NetworkCompanyInfo company_info[MAX_COMPANIES];
1363  Scrollbar *vscroll;
1364 
1366  Window(desc), company(INVALID_COMPANY), server(ngl)
1367  {
1368  this->CreateNestedTree();
1369  this->vscroll = this->GetScrollbar(WID_NL_SCROLLBAR);
1370  this->FinishInitNested(WN_NETWORK_WINDOW_LOBBY);
1371  }
1372 
1373  CompanyID NetworkLobbyFindCompanyIndex(byte pos) const
1374  {
1375  /* Scroll through all this->company_info and get the 'pos' item that is not empty. */
1376  for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
1377  if (!StrEmpty(this->company_info[i].company_name)) {
1378  if (pos-- == 0) return i;
1379  }
1380  }
1381 
1382  return COMPANY_FIRST;
1383  }
1384 
1385  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
1386  {
1387  switch (widget) {
1388  case WID_NL_HEADER:
1390  break;
1391 
1392  case WID_NL_MATRIX:
1393  resize->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
1394  size->height = 10 * resize->height;
1395  break;
1396 
1397  case WID_NL_DETAILS:
1398  size->height = 30 + 11 * FONT_HEIGHT_NORMAL;
1399  break;
1400  }
1401  }
1402 
1403  void SetStringParameters(int widget) const override
1404  {
1405  switch (widget) {
1406  case WID_NL_TEXT:
1407  SetDParamStr(0, this->server->info.server_name);
1408  break;
1409  }
1410  }
1411 
1412  void DrawWidget(const Rect &r, int widget) const override
1413  {
1414  switch (widget) {
1415  case WID_NL_DETAILS:
1416  this->DrawDetails(r);
1417  break;
1418 
1419  case WID_NL_MATRIX:
1420  this->DrawMatrix(r);
1421  break;
1422  }
1423  }
1424 
1425  void OnPaint() override
1426  {
1427  const NetworkGameInfo *gi = &this->server->info;
1428 
1429  /* Join button is disabled when no company is selected and for AI companies. */
1430  this->SetWidgetDisabledState(WID_NL_JOIN, this->company == INVALID_COMPANY || GetLobbyCompanyInfo(this->company)->ai);
1431  /* Cannot start new company if there are too many. */
1432  this->SetWidgetDisabledState(WID_NL_NEW, gi->companies_on >= gi->companies_max);
1433  /* Cannot spectate if there are too many spectators. */
1434  this->SetWidgetDisabledState(WID_NL_SPECTATE, gi->spectators_on >= gi->spectators_max);
1435 
1436  this->vscroll->SetCount(gi->companies_on);
1437 
1438  /* Draw window widgets */
1439  this->DrawWidgets();
1440  }
1441 
1442  void DrawMatrix(const Rect &r) const
1443  {
1444  bool rtl = _current_text_dir == TD_RTL;
1445  uint left = r.left + WD_FRAMERECT_LEFT;
1446  uint right = r.right - WD_FRAMERECT_RIGHT;
1447 
1448  Dimension lock_size = GetSpriteSize(SPR_LOCK);
1449  int lock_width = lock_size.width;
1450  int lock_y_offset = (this->resize.step_height - WD_MATRIX_TOP - WD_MATRIX_BOTTOM - lock_size.height) / 2;
1451 
1452  Dimension profit_size = GetSpriteSize(SPR_PROFIT_LOT);
1453  int profit_width = lock_size.width;
1454  int profit_y_offset = (this->resize.step_height - WD_MATRIX_TOP - WD_MATRIX_BOTTOM - profit_size.height) / 2;
1455 
1456  uint text_left = left + (rtl ? lock_width + profit_width + 4 : 0);
1457  uint text_right = right - (rtl ? 0 : lock_width + profit_width + 4);
1458  uint profit_left = rtl ? left : right - profit_width;
1459  uint lock_left = rtl ? left + profit_width + 2 : right - profit_width - lock_width - 2;
1460 
1461  int y = r.top + WD_MATRIX_TOP;
1462  /* Draw company list */
1463  int pos = this->vscroll->GetPosition();
1464  while (pos < this->server->info.companies_on) {
1465  byte company = NetworkLobbyFindCompanyIndex(pos);
1466  bool income = false;
1467  if (this->company == company) {
1468  GfxFillRect(r.left + 1, y - 2, r.right - 1, y + FONT_HEIGHT_NORMAL, PC_GREY); // show highlighted item with a different colour
1469  }
1470 
1471  DrawString(text_left, text_right, y, this->company_info[company].company_name, TC_BLACK);
1472  if (this->company_info[company].use_password != 0) DrawSprite(SPR_LOCK, PAL_NONE, lock_left, y + lock_y_offset);
1473 
1474  /* If the company's income was positive puts a green dot else a red dot */
1475  if (this->company_info[company].income >= 0) income = true;
1476  DrawSprite(income ? SPR_PROFIT_LOT : SPR_PROFIT_NEGATIVE, PAL_NONE, profit_left, y + profit_y_offset);
1477 
1478  pos++;
1479  y += this->resize.step_height;
1480  if (pos >= this->vscroll->GetPosition() + this->vscroll->GetCapacity()) break;
1481  }
1482  }
1483 
1484  void DrawDetails(const Rect &r) const
1485  {
1486  const int detail_height = 12 + FONT_HEIGHT_NORMAL + 12;
1487  /* Draw info about selected company when it is selected in the left window. */
1488  GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.top + detail_height - 1, PC_DARK_BLUE);
1489  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);
1490 
1491  if (this->company == INVALID_COMPANY || StrEmpty(this->company_info[this->company].company_name)) return;
1492 
1493  int y = r.top + detail_height + 4;
1494  const NetworkGameInfo *gi = &this->server->info;
1495 
1496  SetDParam(0, gi->clients_on);
1497  SetDParam(1, gi->clients_max);
1498  SetDParam(2, gi->companies_on);
1499  SetDParam(3, gi->companies_max);
1500  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CLIENTS);
1501  y += FONT_HEIGHT_NORMAL;
1502 
1503  SetDParamStr(0, this->company_info[this->company].company_name);
1504  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_COMPANY_NAME);
1505  y += FONT_HEIGHT_NORMAL;
1506 
1507  SetDParam(0, this->company_info[this->company].inaugurated_year);
1508  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR); // inauguration year
1509  y += FONT_HEIGHT_NORMAL;
1510 
1511  SetDParam(0, this->company_info[this->company].company_value);
1512  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_VALUE); // company value
1513  y += FONT_HEIGHT_NORMAL;
1514 
1515  SetDParam(0, this->company_info[this->company].money);
1516  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_CURRENT_BALANCE); // current balance
1517  y += FONT_HEIGHT_NORMAL;
1518 
1519  SetDParam(0, this->company_info[this->company].income);
1520  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_LAST_YEARS_INCOME); // last year's income
1521  y += FONT_HEIGHT_NORMAL;
1522 
1523  SetDParam(0, this->company_info[this->company].performance);
1524  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_PERFORMANCE); // performance
1525  y += FONT_HEIGHT_NORMAL;
1526 
1527  SetDParam(0, this->company_info[this->company].num_vehicle[NETWORK_VEH_TRAIN]);
1528  SetDParam(1, this->company_info[this->company].num_vehicle[NETWORK_VEH_LORRY]);
1529  SetDParam(2, this->company_info[this->company].num_vehicle[NETWORK_VEH_BUS]);
1530  SetDParam(3, this->company_info[this->company].num_vehicle[NETWORK_VEH_SHIP]);
1531  SetDParam(4, this->company_info[this->company].num_vehicle[NETWORK_VEH_PLANE]);
1532  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_VEHICLES); // vehicles
1533  y += FONT_HEIGHT_NORMAL;
1534 
1535  SetDParam(0, this->company_info[this->company].num_station[NETWORK_VEH_TRAIN]);
1536  SetDParam(1, this->company_info[this->company].num_station[NETWORK_VEH_LORRY]);
1537  SetDParam(2, this->company_info[this->company].num_station[NETWORK_VEH_BUS]);
1538  SetDParam(3, this->company_info[this->company].num_station[NETWORK_VEH_SHIP]);
1539  SetDParam(4, this->company_info[this->company].num_station[NETWORK_VEH_PLANE]);
1540  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_STATIONS); // stations
1541  y += FONT_HEIGHT_NORMAL;
1542 
1543  SetDParamStr(0, this->company_info[this->company].clients);
1544  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_PLAYERS); // players
1545  }
1546 
1547  void OnClick(Point pt, int widget, int click_count) override
1548  {
1549  switch (widget) {
1550  case WID_NL_CANCEL: // Cancel button
1551  ShowNetworkGameWindow();
1552  break;
1553 
1554  case WID_NL_MATRIX: { // Company list
1555  uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NL_MATRIX);
1556  this->company = (id_v >= this->server->info.companies_on) ? INVALID_COMPANY : NetworkLobbyFindCompanyIndex(id_v);
1557  this->SetDirty();
1558 
1559  /* FIXME the disabling should go into some InvalidateData, which is called instead of the SetDirty */
1560  if (click_count > 1 && !this->IsWidgetDisabled(WID_NL_JOIN)) this->OnClick(pt, WID_NL_JOIN, 1);
1561  break;
1562  }
1563 
1564  case WID_NL_JOIN: // Join company
1565  /* Button can be clicked only when it is enabled. */
1566  NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), this->company);
1567  break;
1568 
1569  case WID_NL_NEW: // New company
1571  break;
1572 
1573  case WID_NL_SPECTATE: // Spectate game
1575  break;
1576 
1577  case WID_NL_REFRESH: // Refresh
1578  NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // company info
1580  /* Clear the information so removed companies don't remain */
1581  memset(this->company_info, 0, sizeof(this->company_info));
1582  break;
1583  }
1584  }
1585 
1586  void OnResize() override
1587  {
1588  this->vscroll->SetCapacityFromWidget(this, WID_NL_MATRIX);
1589  }
1590 };
1591 
1592 static const NWidgetPart _nested_network_lobby_window_widgets[] = {
1594  NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
1595  NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_GAME_LOBBY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1596  EndContainer(),
1597  NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NL_BACKGROUND),
1598  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),
1600  NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 10),
1601  /* Company list. */
1603  NWidget(WWT_PANEL, COLOUR_WHITE, WID_NL_HEADER), SetMinimalSize(146, 0), SetResize(1, 0), SetFill(1, 0), EndContainer(),
1604  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),
1605  EndContainer(),
1606  NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NL_SCROLLBAR),
1608  /* Company info. */
1609  NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NL_DETAILS), SetMinimalSize(232, 0), SetResize(1, 1), SetFill(1, 1), EndContainer(),
1610  EndContainer(),
1612  /* Buttons. */
1615  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),
1616  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),
1617  EndContainer(),
1619  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),
1620  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),
1621  EndContainer(),
1623  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_CANCEL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
1624  NWidget(NWID_SPACER), SetFill(1, 1),
1625  EndContainer(),
1626  EndContainer(),
1628  EndContainer(),
1629 };
1630 
1631 static WindowDesc _network_lobby_window_desc(
1632  WDP_CENTER, nullptr, 0, 0,
1634  0,
1635  _nested_network_lobby_window_widgets, lengthof(_nested_network_lobby_window_widgets)
1636 );
1637 
1643 {
1646 
1647  NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // company info
1649 
1650  new NetworkLobbyWindow(&_network_lobby_window_desc, ngl);
1651 }
1652 
1659 {
1661  return (lobby != nullptr && company < MAX_COMPANIES) ? &lobby->company_info[company] : nullptr;
1662 }
1663 
1664 /* The window below gives information about the connected clients
1665  * and also makes able to give money to them, kick them (if server)
1666  * and stuff like that. */
1667 
1668 extern void DrawCompanyIcon(CompanyID cid, int x, int y);
1669 
1675 
1676 static const NWidgetPart _nested_client_list_popup_widgets[] = {
1677  NWidget(WWT_PANEL, COLOUR_GREY, WID_CLP_PANEL), EndContainer(),
1678 };
1679 
1680 static WindowDesc _client_list_popup_desc(
1681  WDP_AUTO, nullptr, 0, 0,
1683  0,
1684  _nested_client_list_popup_widgets, lengthof(_nested_client_list_popup_widgets)
1685 );
1686 
1687 /* Here we start to define the options out of the menu */
1688 static void ClientList_Kick(const NetworkClientInfo *ci)
1689 {
1691 }
1692 
1693 static void ClientList_Ban(const NetworkClientInfo *ci)
1694 {
1696 }
1697 
1698 static void ClientList_GiveMoney(const NetworkClientInfo *ci)
1699 {
1700  ShowNetworkGiveMoneyWindow(ci->client_playas);
1701 }
1702 
1703 static void ClientList_SpeakToClient(const NetworkClientInfo *ci)
1704 {
1706 }
1707 
1708 static void ClientList_SpeakToCompany(const NetworkClientInfo *ci)
1709 {
1711 }
1712 
1713 static void ClientList_SpeakToAll(const NetworkClientInfo *ci)
1714 {
1716 }
1717 
1724  };
1725 
1726  uint sel_index;
1727  ClientID client_id;
1728  Point desired_location;
1729  std::vector<ClientListAction> actions;
1730 
1736  inline void AddAction(StringID name, ClientList_Action_Proc *proc)
1737  {
1738  this->actions.push_back({name, proc});
1739  }
1740 
1741  NetworkClientListPopupWindow(WindowDesc *desc, int x, int y, ClientID client_id) :
1742  Window(desc),
1743  sel_index(0), client_id(client_id)
1744  {
1745  this->desired_location.x = x;
1746  this->desired_location.y = y;
1747 
1748  const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
1749 
1750  if (_network_own_client_id != ci->client_id) {
1751  this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, &ClientList_SpeakToClient);
1752  }
1753 
1755  this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, &ClientList_SpeakToCompany);
1756  }
1757  this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, &ClientList_SpeakToAll);
1758 
1759  if (_network_own_client_id != ci->client_id) {
1760  /* We are no spectator and the company we want to give money to is no spectator and money gifts are allowed. */
1762  this->AddAction(STR_NETWORK_CLIENTLIST_GIVE_MONEY, &ClientList_GiveMoney);
1763  }
1764  }
1765 
1766  /* A server can kick clients (but not himself). */
1768  this->AddAction(STR_NETWORK_CLIENTLIST_KICK, &ClientList_Kick);
1769  this->AddAction(STR_NETWORK_CLIENTLIST_BAN, &ClientList_Ban);
1770  }
1771 
1772  this->InitNested(client_id);
1773  CLRBITS(this->flags, WF_WHITE_BORDER);
1774  }
1775 
1776  Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override
1777  {
1778  return this->desired_location;
1779  }
1780 
1781  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
1782  {
1783  Dimension d = *size;
1784  for (const ClientListAction &action : this->actions) {
1785  d = maxdim(GetStringBoundingBox(action.name), d);
1786  }
1787 
1788  d.height *= (uint)this->actions.size();
1790  d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
1791  *size = d;
1792  }
1793 
1794  void DrawWidget(const Rect &r, int widget) const override
1795  {
1796  /* Draw the actions */
1797  int sel = this->sel_index;
1798  int y = r.top + WD_FRAMERECT_TOP;
1799  for (const ClientListAction &action : this->actions) {
1800  TextColour colour;
1801  if (sel-- == 0) { // Selected item, highlight it
1802  GfxFillRect(r.left + 1, y, r.right - 1, y + FONT_HEIGHT_NORMAL - 1, PC_BLACK);
1803  colour = TC_WHITE;
1804  } else {
1805  colour = TC_BLACK;
1806  }
1807 
1808  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, action.name, colour);
1809  y += FONT_HEIGHT_NORMAL;
1810  }
1811  }
1812 
1813  void OnMouseLoop() override
1814  {
1815  /* We selected an action */
1816  uint index = (_cursor.pos.y - this->top - WD_FRAMERECT_TOP) / FONT_HEIGHT_NORMAL;
1817 
1818  if (_left_button_down) {
1819  if (index == this->sel_index || index >= this->actions.size()) return;
1820 
1821  this->sel_index = index;
1822  this->SetDirty();
1823  } else {
1824  if (index < this->actions.size() && _cursor.pos.y >= this->top) {
1825  const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(this->client_id);
1826  if (ci != nullptr) this->actions[index].proc(ci);
1827  }
1828 
1830  }
1831  }
1832 };
1833 
1837 static void PopupClientList(ClientID client_id, int x, int y)
1838 {
1840 
1841  if (NetworkClientInfo::GetByClientID(client_id) == nullptr) return;
1842 
1843  new NetworkClientListPopupWindow(&_client_list_popup_desc, x, y, client_id);
1844 }
1845 
1846 static const NWidgetPart _nested_client_list_widgets[] = {
1848  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1849  NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1850  NWidget(WWT_STICKYBOX, COLOUR_GREY),
1851  EndContainer(),
1853 };
1854 
1855 static WindowDesc _client_list_desc(
1856  WDP_AUTO, "list_clients", 0, 0,
1858  0,
1859  _nested_client_list_widgets, lengthof(_nested_client_list_widgets)
1860 );
1861 
1866  int selected_item;
1867 
1868  uint server_client_width;
1869  uint line_height;
1870 
1871  Dimension icon_size;
1872 
1873  NetworkClientListWindow(WindowDesc *desc, WindowNumber window_number) :
1874  Window(desc),
1875  selected_item(-1)
1876  {
1877  this->InitNested(window_number);
1878  }
1879 
1884  {
1885  int num = 0;
1886 
1887  /* Should be replaced with a loop through all clients */
1888  for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1889  if (ci->client_playas != COMPANY_INACTIVE_CLIENT) num++;
1890  }
1891 
1892  num *= this->line_height;
1893 
1894  int diff = (num + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM) - (this->GetWidget<NWidgetBase>(WID_CL_PANEL)->current_y);
1895  /* If height is changed */
1896  if (diff != 0) {
1897  ResizeWindow(this, 0, diff, false);
1898  return false;
1899  }
1900  return true;
1901  }
1902 
1903  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
1904  {
1905  if (widget != WID_CL_PANEL) return;
1906 
1907  this->server_client_width = max(GetStringBoundingBox(STR_NETWORK_SERVER).width, GetStringBoundingBox(STR_NETWORK_CLIENT).width) + WD_FRAMERECT_RIGHT;
1908  this->icon_size = GetSpriteSize(SPR_COMPANY_ICON);
1909  this->line_height = max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL);
1910 
1911  uint width = 100; // Default width
1912  for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1913  width = max(width, GetStringBoundingBox(ci->client_name).width);
1914  }
1915 
1916  size->width = WD_FRAMERECT_LEFT + this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT + width + WD_FRAMERECT_RIGHT;
1917  }
1918 
1919  void OnPaint() override
1920  {
1921  /* Check if we need to reset the height */
1922  if (!this->CheckClientListHeight()) return;
1923 
1924  this->DrawWidgets();
1925  }
1926 
1927  void DrawWidget(const Rect &r, int widget) const override
1928  {
1929  if (widget != WID_CL_PANEL) return;
1930 
1931  bool rtl = _current_text_dir == TD_RTL;
1932  int icon_offset = (this->line_height - icon_size.height) / 2;
1933  int text_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2;
1934 
1935  uint y = r.top + WD_FRAMERECT_TOP;
1936  uint left = r.left + WD_FRAMERECT_LEFT;
1937  uint right = r.right - WD_FRAMERECT_RIGHT;
1938  uint type_icon_width = this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT;
1939 
1940 
1941  uint type_left = rtl ? right - this->server_client_width : left;
1942  uint type_right = rtl ? right : left + this->server_client_width - 1;
1943  uint icon_left = rtl ? right - type_icon_width + WD_FRAMERECT_LEFT : left + this->server_client_width;
1944  uint name_left = rtl ? left : left + type_icon_width;
1945  uint name_right = rtl ? right - type_icon_width : right;
1946 
1947  int i = 0;
1948  for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1949  TextColour colour;
1950  if (this->selected_item == i++) { // Selected item, highlight it
1951  GfxFillRect(r.left + 1, y, r.right - 1, y + this->line_height - 1, PC_BLACK);
1952  colour = TC_WHITE;
1953  } else {
1954  colour = TC_BLACK;
1955  }
1956 
1957  if (ci->client_id == CLIENT_ID_SERVER) {
1958  DrawString(type_left, type_right, y + text_offset, STR_NETWORK_SERVER, colour);
1959  } else {
1960  DrawString(type_left, type_right, y + text_offset, STR_NETWORK_CLIENT, colour);
1961  }
1962 
1963  /* Filter out spectators */
1964  if (Company::IsValidID(ci->client_playas)) DrawCompanyIcon(ci->client_playas, icon_left, y + icon_offset);
1965 
1966  DrawString(name_left, name_right, y + text_offset, ci->client_name, colour);
1967 
1968  y += line_height;
1969  }
1970  }
1971 
1972  void OnClick(Point pt, int widget, int click_count) override
1973  {
1974  /* Show the popup with option */
1975  if (this->selected_item != -1) {
1976  int client_no = this->selected_item;
1978  if (client_no == 0) {
1979  PopupClientList(ci->client_id, pt.x + this->left, pt.y + this->top);
1980  break;
1981  }
1982  client_no--;
1983  }
1984  }
1985  }
1986 
1987  void OnMouseOver(Point pt, int widget) override
1988  {
1989  /* -1 means we left the current window */
1990  if (pt.y == -1) {
1991  this->selected_item = -1;
1992  this->SetDirty();
1993  return;
1994  }
1995 
1996  /* Find the new selected item (if any) */
1997  pt.y -= this->GetWidget<NWidgetBase>(WID_CL_PANEL)->pos_y;
1998  int item = -1;
2000  item = (pt.y - WD_FRAMERECT_TOP) / this->line_height;
2001  }
2002 
2003  /* It did not change.. no update! */
2004  if (item == this->selected_item) return;
2005  this->selected_item = item;
2006 
2007  /* Repaint */
2008  this->SetDirty();
2009  }
2010 };
2011 
2012 void ShowClientList()
2013 {
2014  AllocateWindowDescFront<NetworkClientListWindow>(&_client_list_desc, 0);
2015 }
2016 
2021 
2023  NetworkPasswordType password_type;
2024 
2026  {
2028  this->InitNested(WN_NETWORK_STATUS_WINDOW_JOIN);
2029  }
2030 
2031  void DrawWidget(const Rect &r, int widget) const override
2032  {
2033  if (widget != WID_NJS_BACKGROUND) return;
2034 
2035  uint8 progress; // used for progress bar
2036  DrawString(r.left + 2, r.right - 2, r.top + 20, STR_NETWORK_CONNECTING_1 + _network_join_status, TC_FROMSTRING, SA_HOR_CENTER);
2037  switch (_network_join_status) {
2038  case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING:
2039  case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
2040  progress = 10; // first two stages 10%
2041  break;
2042  case NETWORK_JOIN_STATUS_WAITING:
2043  SetDParam(0, _network_join_waiting);
2044  DrawString(r.left + 2, r.right - 2, r.top + 20 + FONT_HEIGHT_NORMAL, STR_NETWORK_CONNECTING_WAITING, TC_FROMSTRING, SA_HOR_CENTER);
2045  progress = 15; // third stage is 15%
2046  break;
2047  case NETWORK_JOIN_STATUS_DOWNLOADING:
2048  SetDParam(0, _network_join_bytes);
2049  SetDParam(1, _network_join_bytes_total);
2050  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);
2051  if (_network_join_bytes_total == 0) {
2052  progress = 15; // We don't have the final size yet; the server is still compressing!
2053  break;
2054  }
2055  FALLTHROUGH;
2056 
2057  default: // Waiting is 15%, so the resting receivement of map is maximum 70%
2058  progress = 15 + _network_join_bytes * (100 - 15) / _network_join_bytes_total;
2059  }
2060 
2061  /* Draw nice progress bar :) */
2062  DrawFrameRect(r.left + 20, r.top + 5, (int)((this->width - 20) * progress / 100), r.top + 15, COLOUR_MAUVE, FR_NONE);
2063  }
2064 
2065  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
2066  {
2067  if (widget != WID_NJS_BACKGROUND) return;
2068 
2069  size->height = 25 + 2 * FONT_HEIGHT_NORMAL;
2070 
2071  /* Account for the statuses */
2072  uint width = 0;
2073  for (uint i = 0; i < NETWORK_JOIN_STATUS_END; i++) {
2074  width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_1 + i).width);
2075  }
2076 
2077  /* For the number of waiting (other) players */
2079  width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_WAITING).width);
2080 
2081  /* Account for downloading ~ 10 MiB */
2082  SetDParamMaxDigits(0, 8);
2083  SetDParamMaxDigits(1, 8);
2084  width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_DOWNLOADING_1).width);
2085  width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_DOWNLOADING_2).width);
2086 
2087  /* Give a bit more clearing for the widest strings than strictly needed */
2088  size->width = width + WD_FRAMERECT_LEFT + WD_FRAMERECT_BOTTOM + 10;
2089  }
2090 
2091  void OnClick(Point pt, int widget, int click_count) override
2092  {
2093  if (widget == WID_NJS_CANCELOK) { // Disconnect button
2095  SwitchToMode(SM_MENU);
2096  ShowNetworkGameWindow();
2097  }
2098  }
2099 
2100  void OnQueryTextFinished(char *str) override
2101  {
2102  if (StrEmpty(str)) {
2104  ShowNetworkGameWindow();
2105  return;
2106  }
2107 
2108  switch (this->password_type) {
2111  default: NOT_REACHED();
2112  }
2113  }
2114 };
2115 
2116 static const NWidgetPart _nested_network_join_status_window_widgets[] = {
2117  NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_CONNECTING_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2118  NWidget(WWT_PANEL, COLOUR_GREY),
2119  NWidget(WWT_EMPTY, COLOUR_GREY, WID_NJS_BACKGROUND),
2121  NWidget(NWID_SPACER), SetMinimalSize(75, 0), SetFill(1, 0),
2122  NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NJS_CANCELOK), SetMinimalSize(101, 12), SetDataTip(STR_NETWORK_CONNECTION_DISCONNECT, STR_NULL),
2123  NWidget(NWID_SPACER), SetMinimalSize(75, 0), SetFill(1, 0),
2124  EndContainer(),
2126  EndContainer(),
2127 };
2128 
2129 static WindowDesc _network_join_status_window_desc(
2130  WDP_CENTER, nullptr, 0, 0,
2132  WDF_MODAL,
2133  _nested_network_join_status_window_widgets, lengthof(_nested_network_join_status_window_widgets)
2134 );
2135 
2136 void ShowJoinStatusWindow()
2137 {
2139  new NetworkJoinStatusWindow(&_network_join_status_window_desc);
2140 }
2141 
2142 void ShowNetworkNeedPassword(NetworkPasswordType npt)
2143 {
2145  if (w == nullptr) return;
2146  w->password_type = npt;
2147 
2148  StringID caption;
2149  switch (npt) {
2150  default: NOT_REACHED();
2151  case NETWORK_GAME_PASSWORD: caption = STR_NETWORK_NEED_GAME_PASSWORD_CAPTION; break;
2152  case NETWORK_COMPANY_PASSWORD: caption = STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION; break;
2153  }
2155 }
2156 
2160 
2161  NetworkCompanyPasswordWindow(WindowDesc *desc, Window *parent) : Window(desc), password_editbox(lengthof(_settings_client.network.default_company_pass))
2162  {
2163  this->InitNested(0);
2164  this->UpdateWarningStringSize();
2165 
2166  this->parent = parent;
2167  this->querystrings[WID_NCP_PASSWORD] = &this->password_editbox;
2168  this->password_editbox.cancel_button = WID_NCP_CANCEL;
2169  this->password_editbox.ok_button = WID_NCP_OK;
2170  this->SetFocusedWidget(WID_NCP_PASSWORD);
2171  }
2172 
2173  void UpdateWarningStringSize()
2174  {
2175  assert(this->nested_root->smallest_x > 0);
2176  this->warning_size.width = this->nested_root->current_x - (WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT);
2177  this->warning_size.height = GetStringHeight(STR_WARNING_PASSWORD_SECURITY, this->warning_size.width);
2178  this->warning_size.height += WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
2179 
2180  this->ReInit();
2181  }
2182 
2183  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
2184  {
2185  if (widget == WID_NCP_WARNING) {
2186  *size = this->warning_size;
2187  }
2188  }
2189 
2190  void DrawWidget(const Rect &r, int widget) const override
2191  {
2192  if (widget != WID_NCP_WARNING) return;
2193 
2195  r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM,
2196  STR_WARNING_PASSWORD_SECURITY, TC_FROMSTRING, SA_CENTER);
2197  }
2198 
2199  void OnOk()
2200  {
2201  if (this->IsWidgetLowered(WID_NCP_SAVE_AS_DEFAULT_PASSWORD)) {
2203  }
2204 
2205  NetworkChangeCompanyPassword(_local_company, this->password_editbox.text.buf);
2206  }
2207 
2208  void OnClick(Point pt, int widget, int click_count) override
2209  {
2210  switch (widget) {
2211  case WID_NCP_OK:
2212  this->OnOk();
2213  FALLTHROUGH;
2214 
2215  case WID_NCP_CANCEL:
2216  delete this;
2217  break;
2218 
2220  this->ToggleWidgetLoweredState(WID_NCP_SAVE_AS_DEFAULT_PASSWORD);
2221  this->SetDirty();
2222  break;
2223  }
2224  }
2225 };
2226 
2227 static const NWidgetPart _nested_network_company_password_window_widgets[] = {
2229  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
2230  NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_COMPANY_PASSWORD_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2231  EndContainer(),
2232  NWidget(WWT_PANEL, COLOUR_GREY, WID_NCP_BACKGROUND),
2233  NWidget(NWID_VERTICAL), SetPIP(5, 5, 5),
2234  NWidget(NWID_HORIZONTAL), SetPIP(5, 5, 5),
2235  NWidget(WWT_TEXT, COLOUR_GREY, WID_NCP_LABEL), SetDataTip(STR_COMPANY_VIEW_PASSWORD, STR_NULL),
2236  NWidget(WWT_EDITBOX, COLOUR_GREY, WID_NCP_PASSWORD), SetFill(1, 0), SetMinimalSize(194, 12), SetDataTip(STR_COMPANY_VIEW_SET_PASSWORD, STR_NULL),
2237  EndContainer(),
2238  NWidget(NWID_HORIZONTAL), SetPIP(5, 0, 5),
2239  NWidget(NWID_SPACER), SetFill(1, 0),
2241  SetDataTip(STR_COMPANY_PASSWORD_MAKE_DEFAULT, STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP),
2242  EndContainer(),
2243  EndContainer(),
2244  EndContainer(),
2245  NWidget(WWT_PANEL, COLOUR_GREY, WID_NCP_WARNING), EndContainer(),
2247  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NCP_CANCEL), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_COMPANY_PASSWORD_CANCEL),
2248  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NCP_OK), SetFill(1, 0), SetDataTip(STR_BUTTON_OK, STR_COMPANY_PASSWORD_OK),
2249  EndContainer(),
2250 };
2251 
2252 static WindowDesc _network_company_password_window_desc(
2253  WDP_AUTO, nullptr, 0, 0,
2255  0,
2256  _nested_network_company_password_window_widgets, lengthof(_nested_network_company_password_window_widgets)
2257 );
2258 
2259 void ShowNetworkCompanyPasswordWindow(Window *parent)
2260 {
2262 
2263  new NetworkCompanyPasswordWindow(&_network_company_password_window_desc, parent);
2264 }
EventState
State of handling an event.
Definition: window_type.h:711
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:79
Main handle for clientlist.
SizingType
Different forms of sizing nested widgets, using NWidgetBase::AssignSizePosition() ...
Definition: widget_type.h:109
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban)
Ban, or kick, everyone joined from the given client&#39;s IP.
Network game window.
Definition: window_type.h: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:79
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:128
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:1130
void ResetState()
Reset the matching state to process a new item.
The passed event is not handled.
Definition: window_type.h:713
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:1119
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:27
bool give_money
allow giving other companies money
void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override
Assign size and position to the widget.
Toggle &#39;button&#39; for saving the current password as default password.
int GetStringHeight(const char *str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition: gfx.cpp:547
Close box (at top-left of a window)
Definition: widget_type.h: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:81
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
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
void NetworkServerKickClient(ClientID client_id)
Kick a single client.
&#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:176
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:78
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:101
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:498
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.
bool Sort(SortFunction *compare)
Sort 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:1175
static const uint8 PC_BLACK
Black palette colour.
Definition: gfx_func.h:203
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:700
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 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:1162
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:205
static const uint8 PC_DARK_BLUE
Dark blue palette colour.
Definition: gfx_func.h:222
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
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:340
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:888
&#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:770
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:280
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:780
&#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:705
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:712
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:92
void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen)
Resize the window.
Definition: window.cpp:2142
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:80
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:835
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:3316
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:621
(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.