# network_gui.cpp

Go to the documentation of this file.

    00001 /* $Id: network_gui.cpp 18595 2009-12-21 20:32:20Z rubidium $ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * 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.
    00006  * 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.
    00007  * 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/>.
    00008  */
    00009
    00012 #ifdef ENABLE_NETWORK
    00013 #include "../stdafx.h"
    00014 #include "../strings_func.h"
    00015 #include "../date_func.h"
    00016 #include "../fios.h"
    00017 #include "network_internal.h"
    00018 #include "network_client.h"
    00019 #include "network_gui.h"
    00020 #include "network_gamelist.h"
    00021 #include "../gui.h"
    00022 #include "network_udp.h"
    00023 #include "../window_func.h"
    00024 #include "../gfx_func.h"
    00025 #include "../widgets/dropdown_func.h"
    00026 #include "../querystring_gui.h"
    00027 #include "../sortlist_type.h"
    00028 #include "../company_base.h"
    00029 #include "../company_func.h"
    00030
    00031 #include "table/strings.h"
    00032 #include "../table/sprites.h"
    00033
    00034
    00035 static void ShowNetworkStartServerWindow();
    00036 static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
    00037 extern void SwitchToMode(SwitchMode new_mode);
    00038
    00039 static const StringID _connection_types_dropdown[] = {
    00040   STR_NETWORK_START_SERVER_LAN_INTERNET,
    00041   STR_NETWORK_START_SERVER_INTERNET_ADVERTISE,
    00042   INVALID_STRING_ID
    00043 };
    00044
    00045 static const StringID _lan_internet_types_dropdown[] = {
    00046   STR_NETWORK_SERVER_LIST_LAN,
    00047   STR_NETWORK_SERVER_LIST_INTERNET,
    00048   INVALID_STRING_ID
    00049 };
    00050
    00051 static StringID _language_dropdown[NETLANG_COUNT + 1] = {STR_NULL};
    00052
    00053 void SortNetworkLanguages()
    00054 {
    00055   /* Init the strings */
    00056   if (_language_dropdown[0] == STR_NULL) {
    00057     for (int i = 0; i < NETLANG_COUNT; i++) _language_dropdown[i] = STR_NETWORK_LANG_ANY + i;
    00058     _language_dropdown[NETLANG_COUNT] = INVALID_STRING_ID;
    00059   }
    00060
    00061   /* Sort the strings (we don't move 'any' and the 'invalid' one) */
    00062   QSortT(_language_dropdown, NETLANG_COUNT - 1, &StringIDSorter);
    00063 }
    00064
    00068 void UpdateNetworkGameWindow(bool unselect)
    00069 {
    00070   InvalidateWindowData(WC_NETWORK_WINDOW, 0, unselect ? 1 : 0);
    00071 }
    00072
    00074 enum NetworkGameWindowWidgets {
    00075   NGWW_MAIN,
    00076
    00077   NGWW_CONNECTION,
    00078   NGWW_CONN_BTN,
    00079   NGWW_CLIENT_LABEL,
    00080   NGWW_CLIENT,
    00081
    00082   NGWW_HEADER,
    00083   NGWW_NAME,
    00084   NGWW_CLIENTS,
    00085   NGWW_MAPSIZE,
    00086   NGWW_DATE,
    00087   NGWW_YEARS,
    00088   NGWW_INFO,
    00089
    00090   NGWW_MATRIX,
    00091   NGWW_SCROLLBAR,
    00092
    00093   NGWW_LASTJOINED_LABEL,
    00094   NGWW_LASTJOINED,
    00095
    00096   NGWW_DETAILS,
    00097   NGWW_DETAILS_SPACER,
    00098   NGWW_JOIN,
    00099   NGWW_REFRESH,
    00100   NGWW_NEWGRF,
    00101   NGWW_NEWGRF_SEL,
    00102
    00103   NGWW_FIND,
    00104   NGWW_ADD,
    00105   NGWW_START,
    00106   NGWW_CANCEL,
    00107 };
    00108
    00109 typedef GUIList<NetworkGameList*> GUIGameServerList;
    00110 typedef uint16 ServerListPosition;
    00111 static const ServerListPosition SLP_INVALID = 0xFFFF;
    00112
    00114 class NWidgetServerListHeader : public NWidgetContainer {
    00115   static const uint MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER = 150;
    00116   bool visible[6];
    00117 public:
    00118   NWidgetServerListHeader() : NWidgetContainer(NWID_HORIZONTAL)
    00119   {
    00120     NWidgetLeaf *leaf = new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, NGWW_NAME, STR_NETWORK_SERVER_LIST_GAME_NAME, STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP);
    00121     leaf->SetResize(1, 0);
    00122     leaf->SetFill(1, 0);
    00123     this->Add(leaf);
    00124
    00125     this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, NGWW_CLIENTS, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP));
    00126     this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, NGWW_MAPSIZE, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP));
    00127     this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, NGWW_DATE, STR_NETWORK_SERVER_LIST_DATE_CAPTION, STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP));
    00128     this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, NGWW_YEARS, STR_NETWORK_SERVER_LIST_YEARS_CAPTION, STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP));
    00129
    00130     leaf = new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, NGWW_INFO, STR_EMPTY, STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP);
    00131     leaf->SetMinimalSize(40, 12);
    00132     leaf->SetFill(0, 1);
    00133     this->Add(leaf);
    00134
    00135     /* First and last are always visible, the rest is implicitly zeroed */
    00136     this->visible[0] = true;
    00137     *lastof(this->visible) = true;
    00138   }
    00139
    00140   void SetupSmallestSize(Window *w, bool init_array)
    00141   {
    00142     /* Oh yeah, we ought to be findable! */
    00143     w->nested_array[NGWW_HEADER] = this;
    00144
    00145     this->smallest_x = this->head->smallest_x + this->tail->smallest_x; // First and last are always shown, rest not
    00146     this->smallest_y = 0; // Biggest child.
    00147     this->fill_x = 1;
    00148     this->fill_y = 0;
    00149     this->resize_x = 1; // We only resize in this direction
    00150     this->resize_y = 0; // We never resize in this direction
    00151
    00152     /* First initialise some variables... */
    00153     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
    00154       child_wid->SetupSmallestSize(w, init_array);
    00155       this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom);
    00156     }
    00157
    00158     /* ... then in a second pass make sure the 'current' sizes are set. Won't change for most widgets. */
    00159     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
    00160       child_wid->current_x = child_wid->smallest_x;
    00161       child_wid->current_y = this->smallest_y;
    00162     }
    00163   }
    00164
    00165   void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
    00166   {
    00167     assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
    00168
    00169     this->pos_x = x;
    00170     this->pos_y = y;
    00171     this->current_x = given_width;
    00172     this->current_y = given_height;
    00173
    00174     given_width -= this->tail->smallest_x;
    00175     NWidgetBase *child_wid = this->head->next;
    00176     /* The first and last widget are always visible, determine which other should be visible */
    00177     for (uint i = 1; i < lengthof(this->visible) - 1; i++) {
    00178       if (given_width - child_wid->smallest_x > MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER && this->visible[i - 1]) {
    00179         this->visible[i] = true;
    00180         given_width -= child_wid->smallest_x;
    00181       } else {
    00182         this->visible[i] = false;
    00183       }
    00184       child_wid = child_wid->next;
    00185     }
    00186
    00187     /* All remaining space goes to the first (name) widget */
    00188     this->head->current_x = given_width;
    00189
    00190     /* Now assign the widgets to their rightful place */
    00191     uint position = 0; // Place to put next child relative to origin of the container.
    00192     uint i = rtl ? lengthof(this->visible) - 1 : 0;
    00193     child_wid = rtl ? this->tail : this->head;
    00194     while (child_wid != NULL) {
    00195       if (this->visible[i]) {
    00196         child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl);
    00197         position += child_wid->current_x;
    00198       }
    00199
    00200       child_wid = rtl ? child_wid->prev : child_wid->next;
    00201       i += rtl ? -1 : 1;
    00202     }
    00203   }
    00204
    00205   /* virtual */ void Draw(const Window *w)
    00206   {
    00207     int i = 0;
    00208     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
    00209       if (!this->visible[i++]) continue;
    00210
    00211       child_wid->Draw(w);
    00212     }
    00213   }
    00214
    00215   /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y)
    00216   {
    00217     if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
    00218
    00219     int i = 0;
    00220     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
    00221       if (!this->visible[i++]) continue;
    00222       NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y);
    00223       if (nwid != NULL) return nwid;
    00224     }
    00225     return NULL;
    00226   }
    00227
    00233   bool IsWidgetVisible(NetworkGameWindowWidgets widget) const
    00234   {
    00235     assert((uint)(widget - NGWW_NAME) < lengthof(this->visible));
    00236     return this->visible[widget - NGWW_NAME];
    00237   }
    00238 };
    00239
    00240 class NetworkGameWindow : public QueryStringBaseWindow {
    00241 protected:
    00242   /* Runtime saved values */
    00243   static Listing last_sorting;
    00244
    00245   /* Constants for sorting servers */
    00246   static GUIGameServerList::SortFunction * const sorter_funcs[];
    00247
    00248   byte field;
    00249   NetworkGameList *server;
    00250   NetworkGameList *last_joined;
    00251   GUIGameServerList servers;
    00252   ServerListPosition list_pos;
    00253
    00258   void BuildNetworkGameList()
    00259   {
    00260     if (!this->servers.NeedRebuild()) return;
    00261
    00262     /* Create temporary array of games to use for listing */
    00263     this->servers.Clear();
    00264
    00265     for (NetworkGameList *ngl = _network_game_list; ngl != NULL; ngl = ngl->next) {
    00266       *this->servers.Append() = ngl;
    00267     }
    00268
    00269     this->servers.Compact();
    00270     this->servers.RebuildDone();
    00271     this->vscroll.SetCount(this->servers.Length());
    00272   }
    00273
    00275   static int CDECL NGameNameSorter(NetworkGameList * const *a, NetworkGameList * const *b)
    00276   {
    00277     return strcasecmp((*a)->info.server_name, (*b)->info.server_name);
    00278   }
    00279
    00283   static int CDECL NGameClientSorter(NetworkGameList * const *a, NetworkGameList * const *b)
    00284   {
    00285     /* Reverse as per default we are interested in most-clients first */
    00286     int r = (*a)->info.clients_on - (*b)->info.clients_on;
    00287
    00288     if (r == 0) r = (*a)->info.clients_max - (*b)->info.clients_max;
    00289     if (r == 0) r = NGameNameSorter(a, b);
    00290
    00291     return r;
    00292   }
    00293
    00295   static int CDECL NGameMapSizeSorter(NetworkGameList * const *a, NetworkGameList * const *b)
    00296   {
    00297     /* Sort by the area of the map. */
    00298     int r = ((*a)->info.map_height) * ((*a)->info.map_width) - ((*b)->info.map_height) * ((*b)->info.map_width);
    00299
    00300     if (r == 0) r = (*a)->info.map_width - (*b)->info.map_width;
    00301     return (r != 0) ? r : NGameClientSorter(a, b);
    00302   }
    00303
    00305   static int CDECL NGameDateSorter(NetworkGameList * const *a, NetworkGameList * const *b)
    00306   {
    00307     int r = (*a)->info.game_date - (*b)->info.game_date;
    00308     return (r != 0) ? r : NGameClientSorter(a, b);
    00309   }
    00310
    00312   static int CDECL NGameYearsSorter(NetworkGameList * const *a, NetworkGameList * const *b)
    00313   {
    00314     int r = (*a)->info.game_date - (*a)->info.start_date - (*b)->info.game_date + (*b)->info.start_date;
    00315     return (r != 0) ? r : NGameDateSorter(a, b);
    00316   }
    00317
    00320   static int CDECL NGameAllowedSorter(NetworkGameList * const *a, NetworkGameList * const *b)
    00321   {
    00322     /* The servers we do not know anything about (the ones that did not reply) should be at the bottom) */
    00323     int r = StrEmpty((*a)->info.server_revision) - StrEmpty((*b)->info.server_revision);
    00324
    00325     /* Reverse default as we are interested in version-compatible clients first */
    00326     if (r == 0) r = (*b)->info.version_compatible - (*a)->info.version_compatible;
    00327     /* The version-compatible ones are then sorted with NewGRF compatible first, incompatible last */
    00328     if (r == 0) r = (*b)->info.compatible - (*a)->info.compatible;
    00329     /* Passworded servers should be below unpassworded servers */
    00330     if (r == 0) r = (*a)->info.use_password - (*b)->info.use_password;
    00331     /* Finally sort on the name of the server */
    00332     if (r == 0) r = NGameNameSorter(a, b);
    00333
    00334     return r;
    00335   }
    00336
    00338   void SortNetworkGameList()
    00339   {
    00340     if (!this->servers.Sort()) return;
    00341
    00342     /* After sorting ngl->sort_list contains the sorted items. Put these back
    00343      * into the original list. Basically nothing has changed, we are only
    00344      * shuffling the ->next pointers. While iterating, look for the
    00345      * currently selected server and set list_pos to its position */
    00346     this->list_pos = SLP_INVALID;
    00347     _network_game_list = this->servers[0];
    00348     NetworkGameList *item = _network_game_list;
    00349     if (item == this->server) this->list_pos = 0;
    00350     for (uint i = 1; i != this->servers.Length(); i++) {
    00351       item->next = this->servers[i];
    00352       item = item->next;
    00353       if (item == this->server) this->list_pos = i;
    00354     }
    00355     item->next = NULL;
    00356   }
    00357
    00364   void DrawServerLine(const NetworkGameList *cur_item, uint y, bool highlight) const
    00365   {
    00366     const NWidgetBase *nwi_name = this->GetWidget<NWidgetBase>(NGWW_NAME);
    00367     const NWidgetBase *nwi_info = this->GetWidget<NWidgetBase>(NGWW_INFO);
    00368
    00369     /* show highlighted item with a different colour */
    00370     if (highlight) GfxFillRect(nwi_name->pos_x + 1, y - 2, nwi_info->pos_x + nwi_info->current_x - 2, y + FONT_HEIGHT_NORMAL - 1, 10);
    00371
    00372     DrawString(nwi_name->pos_x + WD_FRAMERECT_LEFT, nwi_name->pos_x + nwi_name->current_x - WD_FRAMERECT_RIGHT, y, cur_item->info.server_name, TC_BLACK);
    00373
    00374     /* only draw details if the server is online */
    00375     if (cur_item->online) {
    00376       const NWidgetServerListHeader *nwi_header = this->GetWidget<NWidgetServerListHeader>(NGWW_HEADER);
    00377
    00378       if (nwi_header->IsWidgetVisible(NGWW_CLIENTS)) {
    00379         const NWidgetBase *nwi_clients = this->GetWidget<NWidgetBase>(NGWW_CLIENTS);
    00380         SetDParam(0, cur_item->info.clients_on);
    00381         SetDParam(1, cur_item->info.clients_max);
    00382         SetDParam(2, cur_item->info.companies_on);
    00383         SetDParam(3, cur_item->info.companies_max);
    00384         DrawString(nwi_clients->pos_x, nwi_clients->pos_x + nwi_clients->current_x - 1, y, STR_NETWORK_SERVER_LIST_GENERAL_ONLINE, TC_FROMSTRING, SA_CENTER);
    00385       }
    00386
    00387       if (nwi_header->IsWidgetVisible(NGWW_MAPSIZE)) {
    00388         /* map size */
    00389         const NWidgetBase *nwi_mapsize = this->GetWidget<NWidgetBase>(NGWW_MAPSIZE);
    00390         SetDParam(0, cur_item->info.map_width);
    00391         SetDParam(1, cur_item->info.map_height);
    00392         DrawString(nwi_mapsize->pos_x, nwi_mapsize->pos_x + nwi_mapsize->current_x - 1, y, STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT, TC_FROMSTRING, SA_CENTER);
    00393       }
    00394
    00395       if (nwi_header->IsWidgetVisible(NGWW_DATE)) {
    00396         /* current date */
    00397         const NWidgetBase *nwi_date = this->GetWidget<NWidgetBase>(NGWW_DATE);
    00398         YearMonthDay ymd;
    00399         ConvertDateToYMD(cur_item->info.game_date, &ymd);
    00400         SetDParam(0, ymd.year);
    00401         DrawString(nwi_date->pos_x, nwi_date->pos_x + nwi_date->current_x - 1, y, STR_JUST_INT, TC_BLACK, SA_CENTER);
    00402       }
    00403
    00404       if (nwi_header->IsWidgetVisible(NGWW_YEARS)) {
    00405         /* number of years the game is running */
    00406         const NWidgetBase *nwi_years = this->GetWidget<NWidgetBase>(NGWW_YEARS);
    00407         YearMonthDay ymd_cur, ymd_start;
    00408         ConvertDateToYMD(cur_item->info.game_date, &ymd_cur);
    00409         ConvertDateToYMD(cur_item->info.start_date, &ymd_start);
    00410         SetDParam(0, ymd_cur.year - ymd_start.year);
    00411         DrawString(nwi_years->pos_x, nwi_years->pos_x + nwi_years->current_x - 1, y, STR_JUST_INT, TC_BLACK, SA_CENTER);
    00412       }
    00413
    00414       /* Align the sprites */
    00415       y += (FONT_HEIGHT_NORMAL - 10) / 2;
    00416
    00417       /* draw a lock if the server is password protected */
    00418       if (cur_item->info.use_password) DrawSprite(SPR_LOCK, PAL_NONE, nwi_info->pos_x + 5, y - 1);
    00419
    00420       /* draw red or green icon, depending on compatibility with server */
    00421       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 + 15, y);
    00422
    00423       /* draw flag according to server language */
    00424       DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, PAL_NONE, nwi_info->pos_x + 25, y);
    00425     }
    00426   }
    00427
    00435   void ScrollToSelectedServer()
    00436   {
    00437     if (this->list_pos == SLP_INVALID) return; // no server selected
    00438     this->vscroll.ScrollTowards(this->list_pos);
    00439   }
    00440
    00441 public:
    00442   NetworkGameWindow(const WindowDesc *desc) : QueryStringBaseWindow(NETWORK_CLIENT_NAME_LENGTH)
    00443   {
    00444     this->InitNested(desc, 0);
    00445
    00446     ttd_strlcpy(this->edit_str_buf, _settings_client.network.client_name, this->edit_str_size);
    00447     this->afilter = CS_ALPHANUMERAL;
    00448     InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, 120);
    00449     this->SetFocusedWidget(NGWW_CLIENT);
    00450
    00451     UpdateNetworkGameWindow(true);
    00452
    00453     this->field = NGWW_CLIENT;
    00454     this->last_joined = NetworkGameListAddItem(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
    00455     this->server = this->last_joined;
    00456
    00457     this->servers.SetListing(this->last_sorting);
    00458     this->servers.SetSortFuncs(this->sorter_funcs);
    00459     this->servers.ForceRebuild();
    00460     this->SortNetworkGameList();
    00461   }
    00462
    00463   ~NetworkGameWindow()
    00464   {
    00465     this->last_sorting = this->servers.GetListing();
    00466   }
    00467
    00468   virtual void SetStringParameters(int widget) const
    00469   {
    00470     switch (widget) {
    00471       case NGWW_CONN_BTN:
    00472         SetDParam(0, _lan_internet_types_dropdown[_settings_client.network.lan_internet]);
    00473         break;
    00474     }
    00475   }
    00476
    00477   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    00478   {
    00479     switch (widget) {
    00480       case NGWW_CONN_BTN:
    00481         *size = maxdim(GetStringBoundingBox(_lan_internet_types_dropdown[0]), GetStringBoundingBox(_lan_internet_types_dropdown[1]));
    00482         size->width += padding.width;
    00483         size->height += padding.height;
    00484         break;
    00485
    00486       case NGWW_MATRIX:
    00487         resize->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
    00488         size->height = 10 * resize->height;
    00489         break;
    00490
    00491       case NGWW_LASTJOINED:
    00492         size->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
    00493         break;
    00494
    00495       case NGWW_NAME:
    00496         size->width += 2 * WD_SORTBUTTON_ARROW_WIDTH; // Make space for the arrow
    00497         break;
    00498
    00499       case NGWW_CLIENTS:
    00500         size->width += 2 * WD_SORTBUTTON_ARROW_WIDTH; // Make space for the arrow
    00501         SetDParam(0, 255);
    00502         SetDParam(1, 255);
    00503         SetDParam(2, 15);
    00504         SetDParam(3, 15);
    00505         *size = maxdim(*size, GetStringBoundingBox(STR_NETWORK_SERVER_LIST_GENERAL_ONLINE));
    00506         break;
    00507
    00508       case NGWW_MAPSIZE:
    00509         size->width += 2 * WD_SORTBUTTON_ARROW_WIDTH; // Make space for the arrow
    00510         SetDParam(0, 2048);
    00511         SetDParam(1, 2048);
    00512         *size = maxdim(*size, GetStringBoundingBox(STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT));
    00513         break;
    00514
    00515       case NGWW_DATE:
    00516       case NGWW_YEARS:
    00517         size->width += 2 * WD_SORTBUTTON_ARROW_WIDTH; // Make space for the arrow
    00518         SetDParam(0, 99999);
    00519         *size = maxdim(*size, GetStringBoundingBox(STR_JUST_INT));
    00520         break;
    00521
    00522       case NGWW_DETAILS_SPACER:
    00523         size->height = 20 + 12 * FONT_HEIGHT_NORMAL;
    00524         break;
    00525     }
    00526   }
    00527
    00528   virtual void DrawWidget(const Rect &r, int widget) const
    00529   {
    00530     switch (widget) {
    00531       case NGWW_MATRIX: {
    00532         uint16 y = r.top + WD_MATRIX_TOP;
    00533
    00534         const int max = min(this->vscroll.GetPosition() + this->vscroll.GetCapacity(), (int)this->servers.Length());
    00535
    00536         for (int i = this->vscroll.GetPosition(); i < max; ++i) {
    00537           const NetworkGameList *ngl = this->servers[i];
    00538           this->DrawServerLine(ngl, y, ngl == this->server);
    00539           y += this->resize.step_height;
    00540         }
    00541       } break;
    00542
    00543       case NGWW_LASTJOINED:
    00544         /* Draw the last joined server, if any */
    00545         if (this->last_joined != NULL) this->DrawServerLine(this->last_joined, r.top + WD_MATRIX_TOP, this->last_joined == this->server);
    00546         break;
    00547
    00548       case NGWW_DETAILS:
    00549         this->DrawDetails(r);
    00550         break;
    00551
    00552       case NGWW_NAME:
    00553       case NGWW_CLIENTS:
    00554       case NGWW_MAPSIZE:
    00555       case NGWW_DATE:
    00556       case NGWW_YEARS:
    00557       case NGWW_INFO:
    00558         if (widget - NGWW_NAME == this->servers.SortType()) this->DrawSortButtonState(widget, this->servers.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
    00559         break;
    00560     }
    00561   }
    00562
    00563
    00564   virtual void OnPaint()
    00565   {
    00566     if (this->servers.NeedRebuild()) {
    00567       this->BuildNetworkGameList();
    00568     }
    00569     this->SortNetworkGameList();
    00570
    00571     NetworkGameList *sel = this->server;
    00572     /* 'Refresh' button invisible if no server selected */
    00573     this->SetWidgetDisabledState(NGWW_REFRESH, sel == NULL);
    00574     /* 'Join' button disabling conditions */
    00575     this->SetWidgetDisabledState(NGWW_JOIN, sel == NULL || // no Selected Server
    00576         !sel->online || // Server offline
    00577         sel->info.clients_on >= sel->info.clients_max || // Server full
    00578         !sel->info.compatible); // Revision mismatch
    00579
    00580     /* 'NewGRF Settings' button invisible if no NewGRF is used */
    00581     this->GetWidget<NWidgetStacked>(NGWW_NEWGRF_SEL)->SetDisplayedPlane(sel == NULL || !sel->online || sel->info.grfconfig == NULL);
    00582
    00583     this->DrawWidgets();
    00584     /* Edit box to set client name */
    00585     this->DrawEditBox(NGWW_CLIENT);
    00586   }
    00587
    00588   void DrawDetails(const Rect &r) const
    00589   {
    00590     NetworkGameList *sel = this->server;
    00591
    00592     const int detail_height = 6 + 8 + 6 + 3 * FONT_HEIGHT_NORMAL;
    00593
    00594     /* Draw the right menu */
    00595     GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.top + detail_height - 1, 157);
    00596     if (sel == NULL) {
    00597       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_CENTER);
    00598     } else if (!sel->online) {
    00599       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_CENTER); // game name
    00600
    00601       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_CENTER); // server offline
    00602     } else { // show game info
    00603
    00604       DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6, STR_NETWORK_SERVER_LIST_GAME_INFO, TC_FROMSTRING, SA_CENTER);
    00605       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_CENTER); // game name
    00606       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_CENTER); // map name
    00607
    00608       uint16 y = r.top + detail_height + 4;
    00609
    00610       SetDParam(0, sel->info.clients_on);
    00611       SetDParam(1, sel->info.clients_max);
    00612       SetDParam(2, sel->info.companies_on);
    00613       SetDParam(3, sel->info.companies_max);
    00614       DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CLIENTS);
    00615       y += FONT_HEIGHT_NORMAL;
    00616
    00617       SetDParam(0, STR_NETWORK_LANG_ANY + sel->info.server_lang);
    00618       DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_LANGUAGE); // server language
    00619       y += FONT_HEIGHT_NORMAL;
    00620
    00621       SetDParam(0, STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE + sel->info.map_set);
    00622       DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_TILESET); // tileset
    00623       y += FONT_HEIGHT_NORMAL;
    00624
    00625       SetDParam(0, sel->info.map_width);
    00626       SetDParam(1, sel->info.map_height);
    00627       DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_MAP_SIZE); // map size
    00628       y += FONT_HEIGHT_NORMAL;
    00629
    00630       SetDParamStr(0, sel->info.server_revision);
    00631       DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_VERSION); // server version
    00632       y += FONT_HEIGHT_NORMAL;
    00633
    00634       SetDParamStr(0, sel->address.GetAddressAsString());
    00635       DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_ADDRESS); // server address
    00636       y += FONT_HEIGHT_NORMAL;
    00637
    00638       SetDParam(0, sel->info.start_date);
    00639       DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_START_DATE); // start date
    00640       y += FONT_HEIGHT_NORMAL;
    00641
    00642       SetDParam(0, sel->info.game_date);
    00643       DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CURRENT_DATE); // current date
    00644       y += FONT_HEIGHT_NORMAL;
    00645
    00646       y += WD_PAR_VSEP_NORMAL;
    00647
    00648       if (!sel->info.compatible) {
    00649         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_CENTER); // server mismatch
    00650       } else if (sel->info.clients_on == sel->info.clients_max) {
    00651         /* Show: server full, when clients_on == max_clients */
    00652         DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_FULL, TC_FROMSTRING, SA_CENTER); // server full
    00653       } else if (sel->info.use_password) {
    00654         DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_PASSWORD, TC_FROMSTRING, SA_CENTER); // password warning
    00655       }
    00656     }
    00657   }
    00658
    00659   virtual void OnClick(Point pt, int widget)
    00660   {
    00661     this->field = widget;
    00662     switch (widget) {
    00663       case NGWW_CANCEL: // Cancel button
    00664         DeleteWindowById(WC_NETWORK_WINDOW, 0);
    00665         break;
    00666
    00667       case NGWW_CONN_BTN: // 'Connection' droplist
    00668         ShowDropDownMenu(this, _lan_internet_types_dropdown, _settings_client.network.lan_internet, NGWW_CONN_BTN, 0, 0); // do it for widget NSSW_CONN_BTN
    00669         break;
    00670
    00671       case NGWW_NAME:    // Sort by name
    00672       case NGWW_CLIENTS: // Sort by connected clients
    00673       case NGWW_MAPSIZE: // Sort by map size
    00674       case NGWW_DATE:    // Sort by date
    00675       case NGWW_YEARS:   // Sort by years
    00676       case NGWW_INFO:    // Connectivity (green dot)
    00677         if (this->servers.SortType() == widget - NGWW_NAME) {
    00678           this->servers.ToggleSortOrder();
    00679           if (this->list_pos != SLP_INVALID) this->list_pos = this->servers.Length() - this->list_pos - 1;
    00680         } else {
    00681           this->servers.SetSortType(widget - NGWW_NAME);
    00682           this->servers.ForceResort();
    00683           this->SortNetworkGameList();
    00684         }
    00685         this->ScrollToSelectedServer();
    00686         this->SetDirty();
    00687         break;
    00688
    00689       case NGWW_MATRIX: { // Matrix to show networkgames
    00690         uint32 id_v = (pt.y - this->GetWidget<NWidgetBase>(NGWW_MATRIX)->pos_y) / this->resize.step_height;
    00691
    00692         if (id_v >= this->vscroll.GetCapacity()) return; // click out of bounds
    00693         id_v += this->vscroll.GetPosition();
    00694
    00695         this->server = (id_v < this->servers.Length()) ? this->servers[id_v] : NULL;
    00696         this->list_pos = (server == NULL) ? SLP_INVALID : id_v;
    00697         this->SetDirty();
    00698       } break;
    00699
    00700       case NGWW_LASTJOINED: {
    00701         NetworkGameList *last_joined = NetworkGameListAddItem(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
    00702         if (last_joined != NULL) {
    00703           this->server = last_joined;
    00704
    00705           /* search the position of the newly selected server */
    00706           for (uint i = 0; i < this->servers.Length(); i++) {
    00707             if (this->servers[i] == this->server) {
    00708               this->list_pos = i;
    00709               break;
    00710             }
    00711           }
    00712           this->ScrollToSelectedServer();
    00713           this->SetDirty();
    00714         }
    00715       } break;
    00716
    00717       case NGWW_FIND: // Find server automatically
    00718         switch (_settings_client.network.lan_internet) {
    00719           case 0: NetworkUDPSearchGame(); break;
    00720           case 1: NetworkUDPQueryMasterServer(); break;
    00721         }
    00722         break;
    00723
    00724       case NGWW_ADD: // Add a server
    00725         SetDParamStr(0, _settings_client.network.connect_to_ip);
    00726         ShowQueryString(
    00727           STR_JUST_RAW_STRING,
    00728           STR_NETWORK_SERVER_LIST_ENTER_IP,
    00729           NETWORK_HOSTNAME_LENGTH,  // maximum number of characters including '\0'
    00730           0,                        // no limit in pixels
    00731           this, CS_ALPHANUMERAL, QSF_ACCEPT_UNCHANGED);
    00732         break;
    00733
    00734       case NGWW_START: // Start server
    00735         ShowNetworkStartServerWindow();
    00736         break;
    00737
    00738       case NGWW_JOIN: // Join Game
    00739         if (this->server != NULL) {
    00740           snprintf(_settings_client.network.last_host, sizeof(_settings_client.network.last_host), "%s", this->server->address.GetHostname());
    00741           _settings_client.network.last_port = this->server->address.GetPort();
    00742           ShowNetworkLobbyWindow(this->server);
    00743         }
    00744         break;
    00745
    00746       case NGWW_REFRESH: // Refresh
    00747         if (this->server != NULL) NetworkUDPQueryServer(this->server->address);
    00748         break;
    00749
    00750       case NGWW_NEWGRF: // NewGRF Settings
    00751         if (this->server != NULL) ShowNewGRFSettings(false, false, false, &this->server->info.grfconfig);
    00752         break;
    00753     }
    00754   }
    00755
    00756   virtual void OnDoubleClick(Point pt, int widget)
    00757   {
    00758     if (widget == NGWW_MATRIX || widget == NGWW_LASTJOINED) {
    00759       /* is the Join button enabled? */
    00760       if (!this->IsWidgetDisabled(NGWW_JOIN)) this->OnClick(pt, NGWW_JOIN);
    00761     }
    00762   }
    00763
    00764   virtual void OnDropdownSelect(int widget, int index)
    00765   {
    00766     switch (widget) {
    00767       case NGWW_CONN_BTN:
    00768         _settings_client.network.lan_internet = index;
    00769         break;
    00770
    00771       default:
    00772         NOT_REACHED();
    00773     }
    00774
    00775     this->SetDirty();
    00776   }
    00777
    00778   virtual void OnMouseLoop()
    00779   {
    00780     if (this->field == NGWW_CLIENT) this->HandleEditBox(NGWW_CLIENT);
    00781   }
    00782
    00783   virtual void OnInvalidateData(int data)
    00784   {
    00785     switch (data) {
    00786       /* Remove the selection */
    00787       case 1:
    00788         this->server = NULL;
    00789         this->list_pos = SLP_INVALID;
    00790         break;
    00791
    00792       /* Reiterate the whole server list as we downloaded some files */
    00793       case 2:
    00794         for (NetworkGameList **iter = this->servers.Begin(); iter != this->servers.End(); iter++) {
    00795           NetworkGameList *item = *iter;
    00796           bool missing_grfs = false;
    00797           for (GRFConfig *c = item->info.grfconfig; c != NULL; c = c->next) {
    00798             if (c->status != GCS_NOT_FOUND) continue;
    00799
    00800             const GRFConfig *f = FindGRFConfig(c->grfid, c->md5sum);
    00801             if (f == NULL) {
    00802               missing_grfs = true;
    00803               continue;
    00804             }
    00805
    00806             c->filename  = f->filename;
    00807             c->name      = f->name;
    00808             c->info      = f->info;
    00809             c->status    = GCS_UNKNOWN;
    00810           }
    00811
    00812           if (!missing_grfs) item->info.compatible = item->info.version_compatible;
    00813         }
    00814         break;
    00815     }
    00816     this->servers.ForceRebuild();
    00817     this->SetDirty();
    00818   }
    00819
    00820   virtual EventState OnKeyPress(uint16 key, uint16 keycode)
    00821   {
    00822     EventState state = ES_NOT_HANDLED;
    00823
    00824     /* handle up, down, pageup, pagedown, home and end */
    00825     if (keycode == WKC_UP || keycode == WKC_DOWN || keycode == WKC_PAGEUP || keycode == WKC_PAGEDOWN || keycode == WKC_HOME || keycode == WKC_END) {
    00826       if (this->servers.Length() == 0) return ES_HANDLED;
    00827       switch (keycode) {
    00828         case WKC_UP:
    00829           /* scroll up by one */
    00830           if (this->server == NULL) return ES_HANDLED;
    00831           if (this->list_pos > 0) this->list_pos--;
    00832           break;
    00833         case WKC_DOWN:
    00834           /* scroll down by one */
    00835           if (this->server == NULL) return ES_HANDLED;
    00836           if (this->list_pos < this->servers.Length() - 1) this->list_pos++;
    00837           break;
    00838         case WKC_PAGEUP:
    00839           /* scroll up a page */
    00840           if (this->server == NULL) return ES_HANDLED;
    00841           this->list_pos = (this->list_pos < this->vscroll.GetCapacity()) ? 0 : this->list_pos - this->vscroll.GetCapacity();
    00842           break;
    00843         case WKC_PAGEDOWN:
    00844           /* scroll down a page */
    00845           if (this->server == NULL) return ES_HANDLED;
    00846           this->list_pos = min(this->list_pos + this->vscroll.GetCapacity(), (int)this->servers.Length() - 1);
    00847           break;
    00848         case WKC_HOME:
    00849           /* jump to beginning */
    00850           this->list_pos = 0;
    00851           break;
    00852         case WKC_END:
    00853           /* jump to end */
    00854           this->list_pos = this->servers.Length() - 1;
    00855           break;
    00856         default: break;
    00857       }
    00858
    00859       this->server = this->servers[this->list_pos];
    00860
    00861       /* scroll to the new server if it is outside the current range */
    00862       this->ScrollToSelectedServer();
    00863
    00864       /* redraw window */
    00865       this->SetDirty();
    00866       return ES_HANDLED;
    00867     }
    00868
    00869     if (this->field != NGWW_CLIENT) {
    00870       if (this->server != NULL) {
    00871         if (keycode == WKC_DELETE) { // Press 'delete' to remove servers
    00872           NetworkGameListRemoveItem(this->server);
    00873           this->server = NULL;
    00874           this->list_pos = SLP_INVALID;
    00875         }
    00876       }
    00877       return state;
    00878     }
    00879
    00880     if (this->HandleEditBoxKey(NGWW_CLIENT, key, keycode, state) == HEBR_CONFIRM) return state;
    00881
    00882     /* The name is only allowed when it starts with a letter! */
    00883     if (!StrEmpty(this->edit_str_buf) && this->edit_str_buf[0] != ' ') {
    00884       strecpy(_settings_client.network.client_name, this->edit_str_buf, lastof(_settings_client.network.client_name));
    00885     } else {
    00886       strecpy(_settings_client.network.client_name, "Player", lastof(_settings_client.network.client_name));
    00887     }
    00888     return state;
    00889   }
    00890
    00891   virtual void OnQueryTextFinished(char *str)
    00892   {
    00893     if (!StrEmpty(str)) NetworkAddServer(str);
    00894   }
    00895
    00896   virtual void OnResize()
    00897   {
    00898     this->vscroll.SetCapacityFromWidget(this, NGWW_MATRIX);
    00899     this->GetWidget<NWidgetCore>(NGWW_MATRIX)->widget_data = (this->vscroll.GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START);
    00900   }
    00901 };
    00902
    00903 Listing NetworkGameWindow::last_sorting = {false, 5};
    00904 GUIGameServerList::SortFunction * const NetworkGameWindow::sorter_funcs[] = {
    00905   &NGameNameSorter,
    00906   &NGameClientSorter,
    00907   &NGameMapSizeSorter,
    00908   &NGameDateSorter,
    00909   &NGameYearsSorter,
    00910   &NGameAllowedSorter
    00911 };
    00912
    00913 static NWidgetBase *MakeResizableHeader(int *biggest_index)
    00914 {
    00915   *biggest_index = max<int>(*biggest_index, NGWW_INFO);
    00916   return new NWidgetServerListHeader();
    00917 }
    00918
    00919 static const NWidgetPart _nested_network_game_widgets[] = {
    00920   /* TOP */
    00921   NWidget(NWID_HORIZONTAL),
    00922     NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
    00923     NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_SERVER_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    00924   EndContainer(),
    00925   NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, NGWW_MAIN),
    00926     NWidget(NWID_VERTICAL), SetPIP(10, 7, 0),
    00927       NWidget(NWID_HORIZONTAL), SetPIP(10, 7, 10),
    00928         NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, NGWW_CONNECTION), SetDataTip(STR_NETWORK_SERVER_LIST_CONNECTION, STR_NULL),
    00929         NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, NGWW_CONN_BTN),
    00930                     SetDataTip(STR_BLACK_STRING, STR_NETWORK_SERVER_LIST_CONNECTION_TOOLTIP),
    00931         NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
    00932         NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, NGWW_CLIENT_LABEL), SetDataTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME, STR_NULL),
    00933         NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, NGWW_CLIENT), SetMinimalSize(151, 12),
    00934                     SetDataTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE, STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP),
    00935       EndContainer(),
    00936       NWidget(NWID_HORIZONTAL), SetPIP(10, 7, 10),
    00937         /* LEFT SIDE */
    00938         NWidget(NWID_VERTICAL),
    00939           NWidget(NWID_HORIZONTAL),
    00940             NWidget(NWID_VERTICAL),
    00941               NWidgetFunction(MakeResizableHeader),
    00942               NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, NGWW_MATRIX), SetResize(1, 1), SetFill(1, 0),
    00943                         SetDataTip(0, STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT),
    00944             EndContainer(),
    00945             NWidget(WWT_SCROLLBAR, COLOUR_LIGHT_BLUE, NGWW_SCROLLBAR),
    00946           EndContainer(),
    00947           NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0), SetFill(1, 1),
    00948           NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, NGWW_LASTJOINED_LABEL), SetFill(1, 0),
    00949                     SetDataTip(STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER, STR_NULL), SetResize(1, 0),
    00950           NWidget(NWID_HORIZONTAL), SetPIP(0, 0, WD_VSCROLLBAR_WIDTH),
    00951             NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, NGWW_LASTJOINED), SetFill(1, 0), SetResize(1, 0),
    00952                       SetDataTip(0x0, STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST),
    00953             EndContainer(),
    00954           EndContainer(),
    00955         EndContainer(),
    00956         /* RIGHT SIDE */
    00957         NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, NGWW_DETAILS),
    00958           NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(5, 5, 5),
    00959             NWidget(WWT_EMPTY, INVALID_COLOUR, NGWW_DETAILS_SPACER), SetMinimalSize(140, 155), SetResize(0, 1), SetFill(1, 1), // Make sure it's at least this wide
    00960             NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(5, 5, 5),
    00961               NWidget(NWID_SPACER), SetFill(1, 0),
    00962               NWidget(NWID_SELECTION, INVALID_COLOUR, NGWW_NEWGRF_SEL),
    00963                 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NGWW_NEWGRF), SetFill(1, 0), SetDataTip(STR_INTRO_NEWGRF_SETTINGS, STR_NULL),
    00964                 NWidget(NWID_SPACER), SetFill(1, 0),
    00965               EndContainer(),
    00966             EndContainer(),
    00967             NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(5, 5, 5),
    00968               NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NGWW_JOIN), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_JOIN_GAME, STR_NULL),
    00969               NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NGWW_REFRESH), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_REFRESH, STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP),
    00970             EndContainer(),
    00971           EndContainer(),
    00972         EndContainer(),
    00973       EndContainer(),
    00974       /* BOTTOM */
    00975       NWidget(NWID_HORIZONTAL),
    00976         NWidget(NWID_VERTICAL),
    00977           NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 7, 4),
    00978             NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NGWW_FIND), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_FIND_SERVER, STR_NETWORK_SERVER_LIST_FIND_SERVER_TOOLTIP),
    00979             NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NGWW_ADD), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_ADD_SERVER, STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP),
    00980             NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NGWW_START), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_START_SERVER, STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP),
    00981             NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NGWW_CANCEL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
    00982           EndContainer(),
    00983           NWidget(NWID_SPACER), SetMinimalSize(0, 6), SetResize(1, 0), SetFill(1, 0),
    00984         EndContainer(),
    00985         NWidget(NWID_VERTICAL),
    00986           NWidget(NWID_SPACER), SetFill(0, 1),
    00987           NWidget(WWT_RESIZEBOX, COLOUR_LIGHT_BLUE),
    00988         EndContainer(),
    00989       EndContainer(),
    00990     EndContainer(),
    00991   EndContainer(),
    00992 };
    00993
    00994 static const WindowDesc _network_game_window_desc(
    00995   WDP_CENTER, 1000, 730,
    00996   WC_NETWORK_WINDOW, WC_NONE,
    00997   WDF_UNCLICK_BUTTONS,
    00998   _nested_network_game_widgets, lengthof(_nested_network_game_widgets)
    00999 );
    01000
    01001 void ShowNetworkGameWindow()
    01002 {
    01003   static bool first = true;
    01004   DeleteWindowById(WC_NETWORK_WINDOW, 0);
    01005
    01006   /* Only show once */
    01007   if (first) {
    01008     first = false;
    01009     /* add all servers from the config file to our list */
    01010     for (char **iter = _network_host_list.Begin(); iter != _network_host_list.End(); iter++) {
    01011       NetworkAddServer(*iter);
    01012     }
    01013   }
    01014
    01015   new NetworkGameWindow(&_network_game_window_desc);
    01016 }
    01017
    01019 enum NetworkStartServerWidgets {
    01020   NSSW_BACKGROUND,
    01021   NSSW_GAMENAME_LABEL,
    01022   NSSW_GAMENAME,
    01023   NSSW_SETPWD,
    01024   NSSW_SELECT_MAP_LABEL,
    01025   NSSW_SELMAP,
    01026   NSSW_SCROLLBAR,
    01027   NSSW_CONNTYPE_LABEL,
    01028   NSSW_CONNTYPE_BTN,
    01029   NSSW_CLIENTS_LABEL,
    01030   NSSW_CLIENTS_BTND,
    01031   NSSW_CLIENTS_TXT,
    01032   NSSW_CLIENTS_BTNU,
    01033   NSSW_COMPANIES_LABEL,
    01034   NSSW_COMPANIES_BTND,
    01035   NSSW_COMPANIES_TXT,
    01036   NSSW_COMPANIES_BTNU,
    01037   NSSW_SPECTATORS_LABEL,
    01038   NSSW_SPECTATORS_BTND,
    01039   NSSW_SPECTATORS_TXT,
    01040   NSSW_SPECTATORS_BTNU,
    01041
    01042   NSSW_LANGUAGE_LABEL,
    01043   NSSW_LANGUAGE_BTN,
    01044   NSSW_START,
    01045   NSSW_LOAD,
    01046   NSSW_CANCEL,
    01047 };
    01048
    01049 struct NetworkStartServerWindow : public QueryStringBaseWindow {
    01050   byte field;
    01051   FiosItem *map;
    01052   byte widget_id;
    01053
    01054   NetworkStartServerWindow(const WindowDesc *desc) : QueryStringBaseWindow(NETWORK_NAME_LENGTH)
    01055   {
    01056     this->InitNested(desc, 0);
    01057
    01058     ttd_strlcpy(this->edit_str_buf, _settings_client.network.server_name, this->edit_str_size);
    01059
    01060     _saveload_mode = SLD_NEW_GAME;
    01061     BuildFileList();
    01062     this->vscroll.SetCapacity(14);
    01063     this->vscroll.SetCount(_fios_items.Length() + 1);
    01064
    01065     this->afilter = CS_ALPHANUMERAL;
    01066     InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, 160);
    01067     this->SetFocusedWidget(NSSW_GAMENAME);
    01068
    01069     this->field = NSSW_GAMENAME;
    01070   }
    01071
    01072   virtual void SetStringParameters(int widget) const
    01073   {
    01074     switch (widget) {
    01075       case NSSW_CONNTYPE_BTN:
    01076         SetDParam(0, _connection_types_dropdown[_settings_client.network.server_advertise]);
    01077         break;
    01078
    01079       case NSSW_CLIENTS_TXT:
    01080         SetDParam(0, _settings_client.network.max_clients);
    01081         break;
    01082
    01083       case NSSW_COMPANIES_TXT:
    01084         SetDParam(0, _settings_client.network.max_companies);
    01085         break;
    01086
    01087       case NSSW_SPECTATORS_TXT:
    01088         SetDParam(0, _settings_client.network.max_spectators);
    01089         break;
    01090
    01091       case NSSW_LANGUAGE_BTN:
    01092         SetDParam(0, STR_NETWORK_LANG_ANY + _settings_client.network.server_lang);
    01093         break;
    01094     }
    01095   }
    01096
    01097   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    01098   {
    01099     switch (widget) {
    01100       case NSSW_CONNTYPE_BTN:
    01101         *size = maxdim(GetStringBoundingBox(_connection_types_dropdown[0]), GetStringBoundingBox(_connection_types_dropdown[1]));
    01102         size->width += padding.width;
    01103         size->height += padding.height;
    01104         break;
    01105
    01106       case NSSW_SELMAP:
    01107         resize->height = FONT_HEIGHT_NORMAL;
    01108         size->height = 14 * resize->height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
    01109         break;
    01110     }
    01111   }
    01112
    01113   virtual void DrawWidget(const Rect &r, int widget) const
    01114   {
    01115     switch (widget) {
    01116       case NSSW_SELMAP:
    01117         this->DrawMapSelection(r);
    01118         break;
    01119
    01120       case NSSW_SETPWD:
    01121         /* if password is set, draw red '*' next to 'Set password' button */
    01122         if (!StrEmpty(_settings_client.network.server_password)) DrawString(r.right + WD_FRAMERECT_LEFT, this->width - WD_FRAMERECT_RIGHT, r.top, "*", TC_RED);
    01123     }
    01124   }
    01125
    01126   virtual void OnPaint()
    01127   {
    01128     /* draw basic widgets */
    01129     this->DrawWidgets();
    01130
    01131     /* editbox to set game name */
    01132     this->DrawEditBox(NSSW_GAMENAME);
    01133   }
    01134
    01135   void DrawMapSelection(const Rect &r) const
    01136   {
    01137     int y = r.top + WD_FRAMERECT_TOP;
    01138     /* draw list of maps */
    01139     GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, 0xD7);  // black background of maps list
    01140
    01141     for (uint pos = this->vscroll.GetPosition(); pos < _fios_items.Length() + 1; pos++) {
    01142       const FiosItem *item = _fios_items.Get(pos - 1);
    01143       if (item == this->map || (pos == 0 && this->map == NULL)) {
    01144         GfxFillRect(r.left + 1, y, r.right - 1, y + FONT_HEIGHT_NORMAL - 1, 155); // show highlighted item with a different colour
    01145       }
    01146
    01147       if (pos == 0) {
    01148         DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_START_SERVER_SERVER_RANDOM_GAME, TC_DARK_GREEN);
    01149       } else {
    01150         DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, item->title, _fios_colours[item->type] );
    01151       }
    01152       y += FONT_HEIGHT_NORMAL;
    01153
    01154       if (y >= this->vscroll.GetCapacity() * FONT_HEIGHT_NORMAL + r.top) break;
    01155     }
    01156   }
    01157
    01158   virtual void OnClick(Point pt, int widget)
    01159   {
    01160     this->field = widget;
    01161     switch (widget) {
    01162       case NSSW_CANCEL: // Cancel button
    01163         ShowNetworkGameWindow();
    01164         break;
    01165
    01166       case NSSW_SETPWD: // Set password button
    01167         this->widget_id = NSSW_SETPWD;
    01168         SetDParamStr(0, _settings_client.network.server_password);
    01169         ShowQueryString(STR_JUST_RAW_STRING, STR_NETWORK_START_SERVER_SET_PASSWORD, 20, 250, this, CS_ALPHANUMERAL, QSF_NONE);
    01170         break;
    01171
    01172       case NSSW_SELMAP: { // Select map
    01173         int y = (pt.y - this->GetWidget<NWidgetBase>(NSSW_SELMAP)->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_NORMAL;
    01174
    01175         y += this->vscroll.GetPosition();
    01176         if (y >= this->vscroll.GetCount()) return;
    01177
    01178         this->map = (y == 0) ? NULL : _fios_items.Get(y - 1);
    01179         this->SetDirty();
    01180       } break;
    01181
    01182       case NSSW_CONNTYPE_BTN: // Connection type
    01183         ShowDropDownMenu(this, _connection_types_dropdown, _settings_client.network.server_advertise, NSSW_CONNTYPE_BTN, 0, 0); // do it for widget NSSW_CONNTYPE_BTN
    01184         break;
    01185
    01186       case NSSW_CLIENTS_BTND:    case NSSW_CLIENTS_BTNU:    // Click on up/down button for number of clients
    01187       case NSSW_COMPANIES_BTND:  case NSSW_COMPANIES_BTNU:  // Click on up/down button for number of companies
    01188       case NSSW_SPECTATORS_BTND: case NSSW_SPECTATORS_BTNU: // Click on up/down button for number of spectators
    01189         /* Don't allow too fast scrolling */
    01190         if ((this->flags4 & WF_TIMEOUT_MASK) <= WF_TIMEOUT_TRIGGER) {
    01191           this->HandleButtonClick(widget);
    01192           this->SetDirty();
    01193           switch (widget) {
    01194             default: NOT_REACHED();
    01195             case NSSW_CLIENTS_BTND: case NSSW_CLIENTS_BTNU:
    01196               _settings_client.network.max_clients    = Clamp(_settings_client.network.max_clients    + widget - NSSW_CLIENTS_TXT,    2, MAX_CLIENTS);
    01197               break;
    01198             case NSSW_COMPANIES_BTND: case NSSW_COMPANIES_BTNU:
    01199               _settings_client.network.max_companies  = Clamp(_settings_client.network.max_companies  + widget - NSSW_COMPANIES_TXT,  1, MAX_COMPANIES);
    01200               break;
    01201             case NSSW_SPECTATORS_BTND: case NSSW_SPECTATORS_BTNU:
    01202               _settings_client.network.max_spectators = Clamp(_settings_client.network.max_spectators + widget - NSSW_SPECTATORS_TXT, 0, MAX_CLIENTS);
    01203               break;
    01204           }
    01205         }
    01206         _left_button_clicked = false;
    01207         break;
    01208
    01209       case NSSW_CLIENTS_TXT:    // Click on number of clients
    01210         this->widget_id = NSSW_CLIENTS_TXT;
    01211         SetDParam(0, _settings_client.network.max_clients);
    01212         ShowQueryString(STR_JUST_INT, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS,    4, 50, this, CS_NUMERAL, QSF_NONE);
    01213         break;
    01214
    01215       case NSSW_COMPANIES_TXT:  // Click on number of companies
    01216         this->widget_id = NSSW_COMPANIES_TXT;
    01217         SetDParam(0, _settings_client.network.max_companies);
    01218         ShowQueryString(STR_JUST_INT, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES,  3, 50, this, CS_NUMERAL, QSF_NONE);
    01219         break;
    01220
    01221       case NSSW_SPECTATORS_TXT: // Click on number of spectators
    01222         this->widget_id = NSSW_SPECTATORS_TXT;
    01223         SetDParam(0, _settings_client.network.max_spectators);
    01224         ShowQueryString(STR_JUST_INT, STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS, 4, 50, this, CS_NUMERAL, QSF_NONE);
    01225         break;
    01226
    01227       case NSSW_LANGUAGE_BTN: { // Language
    01228         uint sel = 0;
    01229         for (uint i = 0; i < lengthof(_language_dropdown) - 1; i++) {
    01230           if (_language_dropdown[i] == STR_NETWORK_LANG_ANY + _settings_client.network.server_lang) {
    01231             sel = i;
    01232             break;
    01233           }
    01234         }
    01235         ShowDropDownMenu(this, _language_dropdown, sel, NSSW_LANGUAGE_BTN, 0, 0);
    01236       } break;
    01237
    01238       case NSSW_START: // Start game
    01239         _is_network_server = true;
    01240
    01241         if (this->map == NULL) { // start random new game
    01242           ShowGenerateLandscape();
    01243         } else { // load a scenario
    01244           const char *name = FiosBrowseTo(this->map);
    01245           if (name != NULL) {
    01246             SetFiosType(this->map->type);
    01247             _file_to_saveload.filetype = FT_SCENARIO;
    01248             strecpy(_file_to_saveload.name, name, lastof(_file_to_saveload.name));
    01249             strecpy(_file_to_saveload.title, this->map->title, lastof(_file_to_saveload.title));
    01250
    01251             delete this;
    01252             SwitchToMode(SM_START_SCENARIO);
    01253           }
    01254         }
    01255         break;
    01256
    01257       case NSSW_LOAD: // Load game
    01258         _is_network_server = true;
    01259         /* XXX - WC_NETWORK_WINDOW (this window) should stay, but if it stays, it gets
    01260          * copied all the elements of 'load game' and upon closing that, it segfaults */
    01261         delete this;
    01262         ShowSaveLoadDialog(SLD_LOAD_GAME);
    01263         break;
    01264     }
    01265   }
    01266
    01267   virtual void OnDropdownSelect(int widget, int index)
    01268   {
    01269     switch (widget) {
    01270       case NSSW_CONNTYPE_BTN:
    01271         _settings_client.network.server_advertise = (index != 0);
    01272         break;
    01273       case NSSW_LANGUAGE_BTN:
    01274         _settings_client.network.server_lang = _language_dropdown[index] - STR_NETWORK_LANG_ANY;
    01275         break;
    01276       default:
    01277         NOT_REACHED();
    01278     }
    01279
    01280     this->SetDirty();
    01281   }
    01282
    01283   virtual void OnMouseLoop()
    01284   {
    01285     if (this->field == NSSW_GAMENAME) this->HandleEditBox(NSSW_GAMENAME);
    01286   }
    01287
    01288   virtual EventState OnKeyPress(uint16 key, uint16 keycode)
    01289   {
    01290     EventState state = ES_NOT_HANDLED;
    01291     if (this->field == NSSW_GAMENAME) {
    01292       if (this->HandleEditBoxKey(NSSW_GAMENAME, key, keycode, state) == HEBR_CONFIRM) return state;
    01293
    01294       strecpy(_settings_client.network.server_name, this->text.buf, lastof(_settings_client.network.server_name));
    01295     }
    01296
    01297     return state;
    01298   }
    01299
    01300   virtual void OnTimeout()
    01301   {
    01302     static const int raise_widgets[] = {NSSW_CLIENTS_BTND, NSSW_CLIENTS_BTNU, NSSW_COMPANIES_BTND, NSSW_COMPANIES_BTNU, NSSW_SPECTATORS_BTND, NSSW_SPECTATORS_BTNU, WIDGET_LIST_END};
    01303     for (const int *widget = raise_widgets; *widget != WIDGET_LIST_END; widget++) {
    01304       if (this->IsWidgetLowered(*widget)) {
    01305         this->RaiseWidget(*widget);
    01306         this->SetWidgetDirty(*widget);
    01307       }
    01308     }
    01309   }
    01310
    01311   virtual void OnQueryTextFinished(char *str)
    01312   {
    01313     if (str == NULL) return;
    01314
    01315     if (this->widget_id == NSSW_SETPWD) {
    01316       strecpy(_settings_client.network.server_password, str, lastof(_settings_client.network.server_password));
    01317     } else {
    01318       int32 value = atoi(str);
    01319       this->SetWidgetDirty(this->widget_id);
    01320       switch (this->widget_id) {
    01321         default: NOT_REACHED();
    01322         case NSSW_CLIENTS_TXT:    _settings_client.network.max_clients    = Clamp(value, 2, MAX_CLIENTS); break;
    01323         case NSSW_COMPANIES_TXT:  _settings_client.network.max_companies  = Clamp(value, 1, MAX_COMPANIES); break;
    01324         case NSSW_SPECTATORS_TXT: _settings_client.network.max_spectators = Clamp(value, 0, MAX_CLIENTS); break;
    01325       }
    01326     }
    01327
    01328     this->SetDirty();
    01329   }
    01330 };
    01331
    01332 static const NWidgetPart _nested_network_start_server_window_widgets[] = {
    01333   NWidget(NWID_HORIZONTAL),
    01334     NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
    01335     NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_START_SERVER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    01336   EndContainer(),
    01337   NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, NSSW_BACKGROUND),
    01338     NWidget(NWID_HORIZONTAL), SetPIP(10, 8, 10),
    01339       NWidget(NWID_VERTICAL), SetPIP(10, 0, 10),
    01340         /* Game name widgets */
    01341         NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0),
    01342           NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, NSSW_GAMENAME_LABEL), SetDataTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME, STR_NULL),
    01343           NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, NSSW_GAMENAME), SetMinimalSize(10, 12), SetFill(1, 0),
    01344                             SetDataTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE, STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP),
    01345         EndContainer(),
    01346         /* List of playable scenarios. */
    01347         NWidget(NWID_SPACER), SetMinimalSize(0, 8), SetFill(1, 0),
    01348         NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, NSSW_SELECT_MAP_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_SELECT_MAP, STR_NULL),
    01349         NWidget(NWID_SPACER), SetMinimalSize(0, 6), SetFill(1, 0),
    01350         NWidget(NWID_HORIZONTAL),
    01351           NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, NSSW_SELMAP), SetMinimalSize(250, 0), SetFill(1, 1), SetDataTip(STR_NULL, STR_NETWORK_START_SERVER_SELECT_MAP_TOOLTIP), EndContainer(),
    01352           NWidget(WWT_SCROLLBAR, COLOUR_LIGHT_BLUE, NSSW_SCROLLBAR),
    01353         EndContainer(),
    01354       EndContainer(),
    01355       NWidget(NWID_VERTICAL), SetPIP(10, 0, 10),
    01356         /* Password widgets. */
    01357         NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NSSW_SETPWD), SetFill(1, 0),
    01358                             SetDataTip(STR_NETWORK_START_SERVER_SET_PASSWORD, STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP),
    01359         /* Combo/selection boxes to control Connection Type / Max Clients / Max Companies / Max Observers / Language */
    01360         NWidget(NWID_SPACER), SetFill(1, 1),
    01361         NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, NSSW_CONNTYPE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_CONNECTION, STR_NULL),
    01362         NWidget(NWID_SPACER), SetMinimalSize(0, 1),
    01363         NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, NSSW_CONNTYPE_BTN), SetFill(1, 0),
    01364                         SetDataTip(STR_BLACK_STRING, STR_NETWORK_SERVER_LIST_CONNECTION_TOOLTIP),
    01365
    01366         NWidget(NWID_SPACER), SetMinimalSize(0, 6),
    01367         NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, NSSW_CLIENTS_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS, STR_NULL),
    01368         NWidget(NWID_SPACER), SetMinimalSize(0, 1),
    01369         NWidget(NWID_HORIZONTAL),
    01370           NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, NSSW_CLIENTS_BTND), SetMinimalSize(12, 12), SetFill(0, 1),
    01371                         SetDataTip(SPR_ARROW_DOWN, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
    01372           NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, NSSW_CLIENTS_TXT), SetFill(1, 0),
    01373                         SetDataTip(STR_NETWORK_START_SERVER_CLIENTS_SELECT, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
    01374           NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, NSSW_CLIENTS_BTNU), SetMinimalSize(12, 12), SetFill(0, 1),
    01375                         SetDataTip(SPR_ARROW_UP, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
    01376         EndContainer(),
    01377
    01378         NWidget(NWID_SPACER), SetMinimalSize(0, 6),
    01379         NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, NSSW_COMPANIES_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES, STR_NULL),
    01380         NWidget(NWID_SPACER), SetMinimalSize(0, 1),
    01381         NWidget(NWID_HORIZONTAL),
    01382           NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, NSSW_COMPANIES_BTND), SetMinimalSize(12, 12), SetFill(0, 1),
    01383                         SetDataTip(SPR_ARROW_DOWN, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
    01384           NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, NSSW_COMPANIES_TXT), SetFill(1, 0),
    01385                         SetDataTip(STR_NETWORK_START_SERVER_COMPANIES_SELECT, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
    01386           NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, NSSW_COMPANIES_BTNU), SetMinimalSize(12, 12), SetFill(0, 1),
    01387                         SetDataTip(SPR_ARROW_UP, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
    01388         EndContainer(),
    01389
    01390         NWidget(NWID_SPACER), SetMinimalSize(0, 6),
    01391         NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, NSSW_SPECTATORS_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS, STR_NULL),
    01392         NWidget(NWID_SPACER), SetMinimalSize(0, 1),
    01393         NWidget(NWID_HORIZONTAL),
    01394           NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, NSSW_SPECTATORS_BTND), SetMinimalSize(12, 12), SetFill(0, 1),
    01395                         SetDataTip(SPR_ARROW_DOWN, STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP),
    01396           NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, NSSW_SPECTATORS_TXT), SetFill(1, 0),
    01397                         SetDataTip(STR_NETWORK_START_SERVER_SPECTATORS_SELECT, STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP),
    01398           NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, NSSW_SPECTATORS_BTNU), SetMinimalSize(12, 12), SetFill(0, 1),
    01399                         SetDataTip(SPR_ARROW_UP, STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP),
    01400         EndContainer(),
    01401
    01402         NWidget(NWID_SPACER), SetMinimalSize(0, 6),
    01403         NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, NSSW_LANGUAGE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN, STR_NULL),
    01404         NWidget(NWID_SPACER), SetMinimalSize(0, 1),
    01405         NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, NSSW_LANGUAGE_BTN), SetFill(1, 0),
    01406                         SetDataTip(STR_BLACK_STRING, STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP),
    01407       EndContainer(),
    01408     EndContainer(),
    01409     /* Buttons Start / Load / Cancel. */
    01410     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 5, 10),
    01411       NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NSSW_START), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_START_GAME, STR_NETWORK_START_SERVER_START_GAME_TOOLTIP),
    01412       NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NSSW_LOAD), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_LOAD_GAME, STR_NETWORK_START_SERVER_LOAD_GAME_TOOLTIP),
    01413       NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NSSW_CANCEL), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
    01414     EndContainer(),
    01415     NWidget(NWID_SPACER), SetMinimalSize(0, 10),
    01416   EndContainer(),
    01417 };
    01418
    01419 static const WindowDesc _network_start_server_window_desc(
    01420   WDP_CENTER, 0, 0,
    01421   WC_NETWORK_WINDOW, WC_NONE,
    01422   WDF_UNCLICK_BUTTONS,
    01423   _nested_network_start_server_window_widgets, lengthof(_nested_network_start_server_window_widgets)
    01424 );
    01425
    01426 static void ShowNetworkStartServerWindow()
    01427 {
    01428   DeleteWindowById(WC_NETWORK_WINDOW, 0);
    01429
    01430   new NetworkStartServerWindow(&_network_start_server_window_desc);
    01431 }
    01432
    01434 enum NetworkLobbyWindowWidgets {
    01435   NLWW_BACKGROUND,
    01436   NLWW_TEXT,
    01437   NLWW_HEADER,
    01438   NLWW_MATRIX,
    01439   NLWW_SCROLLBAR,
    01440   NLWW_DETAILS,
    01441   NLWW_JOIN,
    01442   NLWW_NEW,
    01443   NLWW_SPECTATE,
    01444   NLWW_REFRESH,
    01445   NLWW_CANCEL,
    01446 };
    01447
    01448 struct NetworkLobbyWindow : public Window {
    01449   CompanyID company;
    01450   NetworkGameList *server;
    01451   NetworkCompanyInfo company_info[MAX_COMPANIES];
    01452
    01453   NetworkLobbyWindow(const WindowDesc *desc, NetworkGameList *ngl) :
    01454       Window(), company(INVALID_COMPANY), server(ngl)
    01455   {
    01456     this->InitNested(desc, 0);
    01457     this->OnResize();
    01458   }
    01459
    01460   CompanyID NetworkLobbyFindCompanyIndex(byte pos) const
    01461   {
    01462     /* Scroll through all this->company_info and get the 'pos' item that is not empty */
    01463     for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
    01464       if (!StrEmpty(this->company_info[i].company_name)) {
    01465         if (pos-- == 0) return i;
    01466       }
    01467     }
    01468
    01469     return COMPANY_FIRST;
    01470   }
    01471
    01472   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    01473   {
    01474     switch (widget) {
    01475       case NLWW_HEADER:
    01476         size->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;;
    01477         break;
    01478
    01479       case NLWW_MATRIX:
    01480         resize->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
    01481         size->height = 10 * resize->height;
    01482         break;
    01483
    01484       case NLWW_DETAILS:
    01485         size->height = 30 + 11 * FONT_HEIGHT_NORMAL;
    01486         break;
    01487     }
    01488   }
    01489
    01490   virtual void SetStringParameters(int widget) const
    01491   {
    01492     switch (widget) {
    01493       case NLWW_TEXT:
    01494         SetDParamStr(0, this->server->info.server_name);
    01495         break;
    01496     }
    01497   }
    01498
    01499   virtual void DrawWidget(const Rect &r, int widget) const
    01500   {
    01501     switch (widget) {
    01502       case NLWW_DETAILS:
    01503         this->DrawDetails(r);
    01504         break;
    01505
    01506       case NLWW_MATRIX:
    01507         this->DrawMatrix(r);
    01508         break;
    01509     }
    01510   }
    01511
    01512   virtual void OnPaint()
    01513   {
    01514     const NetworkGameInfo *gi = &this->server->info;
    01515
    01516     /* Join button is disabled when no company is selected and for AI companies*/
    01517     this->SetWidgetDisabledState(NLWW_JOIN, this->company == INVALID_COMPANY || GetLobbyCompanyInfo(this->company)->ai);
    01518     /* Cannot start new company if there are too many */
    01519     this->SetWidgetDisabledState(NLWW_NEW, gi->companies_on >= gi->companies_max);
    01520     /* Cannot spectate if there are too many spectators */
    01521     this->SetWidgetDisabledState(NLWW_SPECTATE, gi->spectators_on >= gi->spectators_max);
    01522
    01523     this->vscroll.SetCount(gi->companies_on);
    01524
    01525     /* Draw window widgets */
    01526     this->DrawWidgets();
    01527   }
    01528
    01529   void DrawMatrix(const Rect &r) const
    01530   {
    01531     bool rtl = _dynlang.text_dir == TD_RTL;
    01532     uint left = r.left + WD_FRAMERECT_LEFT;
    01533     uint right = r.right - WD_FRAMERECT_RIGHT;
    01534
    01535     uint text_left  = left + (rtl ? 20 : 0);
    01536     uint text_right = right - (rtl ? 0 : 20);
    01537     uint blob_left  = rtl ? left : right - 10;
    01538     uint lock_left  = rtl ? left + 10 : right - 20;
    01539
    01540     int y = r.top + WD_MATRIX_TOP;
    01541     /* Draw company list */
    01542     int pos = this->vscroll.GetPosition();
    01543     while (pos < this->server->info.companies_on) {
    01544       byte company = NetworkLobbyFindCompanyIndex(pos);
    01545       bool income = false;
    01546       if (this->company == company) {
    01547         GfxFillRect(r.left + 1, y - 2, r.right - 1, y + FONT_HEIGHT_NORMAL, 10); // show highlighted item with a different colour
    01548       }
    01549
    01550       DrawString(text_left, text_right, y, this->company_info[company].company_name, TC_BLACK);
    01551       if (this->company_info[company].use_password != 0) DrawSprite(SPR_LOCK, PAL_NONE, lock_left, y);
    01552
    01553       /* If the company's income was positive puts a green dot else a red dot */
    01554       if (this->company_info[company].income >= 0) income = true;
    01555       DrawSprite(SPR_BLOT, income ? PALETTE_TO_GREEN : PALETTE_TO_RED, blob_left, y + (FONT_HEIGHT_NORMAL - 10) / 2);
    01556
    01557       pos++;
    01558       y += this->resize.step_height;
    01559       if (pos >= this->vscroll.GetPosition() + this->vscroll.GetCapacity()) break;
    01560     }
    01561   }
    01562
    01563   void DrawDetails(const Rect &r) const
    01564   {
    01565     const int detail_height = 12 + FONT_HEIGHT_NORMAL + 12;
    01566     /* Draw info about selected company when it is selected in the left window */
    01567     GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.top + detail_height - 1, 157);
    01568     DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 12, STR_NETWORK_GAME_LOBBY_COMPANY_INFO, TC_FROMSTRING, SA_CENTER);
    01569
    01570     if (this->company == INVALID_COMPANY || StrEmpty(this->company_info[this->company].company_name)) return;
    01571
    01572     int y = r.top + detail_height + 4;
    01573     const NetworkGameInfo *gi = &this->server->info;
    01574
    01575     SetDParam(0, gi->clients_on);
    01576     SetDParam(1, gi->clients_max);
    01577     SetDParam(2, gi->companies_on);
    01578     SetDParam(3, gi->companies_max);
    01579     DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CLIENTS);
    01580     y += FONT_HEIGHT_NORMAL;
    01581
    01582     SetDParamStr(0, this->company_info[this->company].company_name);
    01583     DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_COMPANY_NAME);
    01584     y += FONT_HEIGHT_NORMAL;
    01585
    01586     SetDParam(0, this->company_info[this->company].inaugurated_year);
    01587     DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR); // inauguration year
    01588     y += FONT_HEIGHT_NORMAL;
    01589
    01590     SetDParam(0, this->company_info[this->company].company_value);
    01591     DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_VALUE); // company value
    01592     y += FONT_HEIGHT_NORMAL;
    01593
    01594     SetDParam(0, this->company_info[this->company].money);
    01595     DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_CURRENT_BALANCE); // current balance
    01596     y += FONT_HEIGHT_NORMAL;
    01597
    01598     SetDParam(0, this->company_info[this->company].income);
    01599     DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_LAST_YEARS_INCOME); // last year's income
    01600     y += FONT_HEIGHT_NORMAL;
    01601
    01602     SetDParam(0, this->company_info[this->company].performance);
    01603     DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_PERFORMANCE); // performance
    01604     y += FONT_HEIGHT_NORMAL;
    01605
    01606     for (uint i = 0; i < lengthof(this->company_info[this->company].num_vehicle); i++) {
    01607       SetDParam(i, this->company_info[this->company].num_vehicle[i]);
    01608     }
    01609     DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_VEHICLES); // vehicles
    01610     y += FONT_HEIGHT_NORMAL;
    01611
    01612     for (uint i = 0; i < lengthof(this->company_info[this->company].num_station); i++) {
    01613       SetDParam(i, this->company_info[this->company].num_station[i]);
    01614     }
    01615     DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_STATIONS); // stations
    01616     y += FONT_HEIGHT_NORMAL;
    01617
    01618     SetDParamStr(0, this->company_info[this->company].clients);
    01619     DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_PLAYERS); // players
    01620   }
    01621
    01622   virtual void OnClick(Point pt, int widget)
    01623   {
    01624     switch (widget) {
    01625       case NLWW_CANCEL:   // Cancel button
    01626         ShowNetworkGameWindow();
    01627         break;
    01628
    01629       case NLWW_MATRIX: { // Company list
    01630         uint32 id_v = (pt.y - this->GetWidget<NWidgetBase>(NLWW_MATRIX)->pos_y) / this->resize.step_height;
    01631
    01632         if (id_v >= this->vscroll.GetCapacity()) break;
    01633
    01634         id_v += this->vscroll.GetPosition();
    01635         this->company = (id_v >= this->server->info.companies_on) ? INVALID_COMPANY : NetworkLobbyFindCompanyIndex(id_v);
    01636         this->SetDirty();
    01637       } break;
    01638
    01639       case NLWW_JOIN:     // Join company
    01640         /* Button can be clicked only when it is enabled */
    01641         NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), this->company);
    01642         break;
    01643
    01644       case NLWW_NEW:      // New company
    01645         NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), COMPANY_NEW_COMPANY);
    01646         break;
    01647
    01648       case NLWW_SPECTATE: // Spectate game
    01649         NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), COMPANY_SPECTATOR);
    01650         break;
    01651
    01652       case NLWW_REFRESH:  // Refresh
    01653         NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // company info
    01654         NetworkUDPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // general data
    01655         /* Clear the information so removed companies don't remain */
    01656         memset(this->company_info, 0, sizeof(this->company_info));
    01657         break;
    01658     }
    01659   }
    01660
    01661   virtual void OnDoubleClick(Point pt, int widget)
    01662   {
    01663     if (widget == NLWW_MATRIX) {
    01664       /* is the Join button enabled? */
    01665       if (!this->IsWidgetDisabled(NLWW_JOIN)) this->OnClick(pt, NLWW_JOIN);
    01666     }
    01667   }
    01668
    01669   virtual void OnResize()
    01670   {
    01671     this->vscroll.SetCapacityFromWidget(this, NLWW_MATRIX);
    01672     this->GetWidget<NWidgetCore>(NLWW_MATRIX)->widget_data = (this->vscroll.GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START);
    01673   }
    01674 };
    01675
    01676 static const NWidgetPart _nested_network_lobby_window_widgets[] = {
    01677   NWidget(NWID_HORIZONTAL),
    01678     NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
    01679     NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_GAME_LOBBY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    01680   EndContainer(),
    01681   NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, NLWW_BACKGROUND),
    01682     NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, NLWW_TEXT), SetDataTip(STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN, STR_NULL), SetResize(1, 0), SetPadding(10, 10, 0, 10),
    01683     NWidget(NWID_SPACER), SetMinimalSize(0, 3),
    01684     NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 10),
    01685       /* Company list. */
    01686       NWidget(NWID_VERTICAL),
    01687         NWidget(WWT_PANEL, COLOUR_WHITE, NLWW_HEADER), SetMinimalSize(146, 0), SetResize(1, 0), SetFill(1, 0), EndContainer(),
    01688         NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, NLWW_MATRIX), SetMinimalSize(146, 0), SetResize(1, 1), SetFill(1, 1), SetDataTip(0, STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP),
    01689       EndContainer(),
    01690       NWidget(WWT_SCROLLBAR, COLOUR_LIGHT_BLUE, NLWW_SCROLLBAR),
    01691       NWidget(NWID_SPACER), SetMinimalSize(5, 0), SetResize(0, 1),
    01692       /* Company info. */
    01693       NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, NLWW_DETAILS), SetMinimalSize(232, 0), SetResize(1, 1), SetFill(1, 1), EndContainer(),
    01694     EndContainer(),
    01695     NWidget(NWID_SPACER), SetMinimalSize(0, 9),
    01696     /* Buttons. */
    01697     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 3, 10),
    01698       NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 3, 0),
    01699         NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NLWW_JOIN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_GAME_LOBBY_JOIN_COMPANY, STR_NETWORK_GAME_LOBBY_JOIN_COMPANY_TOOLTIP),
    01700         NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NLWW_NEW), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_GAME_LOBBY_NEW_COMPANY, STR_NETWORK_GAME_LOBBY_NEW_COMPANY_TOOLTIP),
    01701       EndContainer(),
    01702       NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 3, 0),
    01703         NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NLWW_SPECTATE), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_GAME_LOBBY_SPECTATE_GAME, STR_NETWORK_GAME_LOBBY_SPECTATE_GAME_TOOLTIP),
    01704         NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NLWW_REFRESH), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_REFRESH, STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP),
    01705       EndContainer(),
    01706       NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 3, 0),
    01707         NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NLWW_CANCEL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
    01708         NWidget(NWID_SPACER), SetFill(1, 1),
    01709       EndContainer(),
    01710     EndContainer(),
    01711     NWidget(NWID_SPACER), SetMinimalSize(0, 8),
    01712   EndContainer(),
    01713 };
    01714
    01715 static const WindowDesc _network_lobby_window_desc(
    01716   WDP_CENTER, 0, 0,
    01717   WC_NETWORK_WINDOW, WC_NONE,
    01718   WDF_UNCLICK_BUTTONS,
    01719   _nested_network_lobby_window_widgets, lengthof(_nested_network_lobby_window_widgets)
    01720 );
    01721
    01722 /* Show the networklobbywindow with the selected server
    01723  * @param ngl Selected game pointer which is passed to the new window */
    01724 static void ShowNetworkLobbyWindow(NetworkGameList *ngl)
    01725 {
    01726   DeleteWindowById(WC_NETWORK_WINDOW, 0);
    01727
    01728   NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // company info
    01729   NetworkUDPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // general data
    01730
    01731   new NetworkLobbyWindow(&_network_lobby_window_desc, ngl);
    01732 }
    01733
    01739 NetworkCompanyInfo *GetLobbyCompanyInfo(CompanyID company)
    01740 {
    01741   NetworkLobbyWindow *lobby = dynamic_cast<NetworkLobbyWindow*>(FindWindowById(WC_NETWORK_WINDOW, 0));
    01742   return (lobby != NULL && company < MAX_COMPANIES) ? &lobby->company_info[company] : NULL;
    01743 }
    01744
    01745 /* The window below gives information about the connected clients
    01746  *  and also makes able to give money to them, kick them (if server)
    01747  *  and stuff like that. */
    01748
    01749 extern void DrawCompanyIcon(CompanyID cid, int x, int y);
    01750
    01751 /* Every action must be of this form */
    01752 typedef void ClientList_Action_Proc(byte client_no);
    01753
    01754 static const NWidgetPart _nested_client_list_popup_widgets[] = {
    01755   NWidget(WWT_PANEL, COLOUR_GREY, 0), EndContainer(),
    01756 };
    01757
    01758 static const WindowDesc _client_list_popup_desc(
    01759   WDP_AUTO, 0, 0,
    01760   WC_TOOLBAR_MENU, WC_CLIENT_LIST,
    01761   0,
    01762   _nested_client_list_popup_widgets, lengthof(_nested_client_list_popup_widgets)
    01763 );
    01764
    01765 /* Finds the Xth client-info that is active */
    01766 static NetworkClientInfo *NetworkFindClientInfo(byte client_no)
    01767 {
    01768   NetworkClientInfo *ci;
    01769
    01770   FOR_ALL_CLIENT_INFOS(ci) {
    01771     if (client_no == 0) return ci;
    01772     client_no--;
    01773   }
    01774
    01775   return NULL;
    01776 }
    01777
    01778 /* Here we start to define the options out of the menu */
    01779 static void ClientList_Kick(byte client_no)
    01780 {
    01781   const NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
    01782
    01783   if (ci == NULL) return;
    01784
    01785   NetworkServerKickClient(ci->client_id);
    01786 }
    01787
    01788 static void ClientList_Ban(byte client_no)
    01789 {
    01790   NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
    01791
    01792   if (ci == NULL) return;
    01793
    01794   NetworkServerBanIP(GetClientIP(ci));
    01795 }
    01796
    01797 static void ClientList_GiveMoney(byte client_no)
    01798 {
    01799   if (NetworkFindClientInfo(client_no) != NULL) {
    01800     ShowNetworkGiveMoneyWindow(NetworkFindClientInfo(client_no)->client_playas);
    01801   }
    01802 }
    01803
    01804 static void ClientList_SpeakToClient(byte client_no)
    01805 {
    01806   if (NetworkFindClientInfo(client_no) != NULL) {
    01807     ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, NetworkFindClientInfo(client_no)->client_id);
    01808   }
    01809 }
    01810
    01811 static void ClientList_SpeakToCompany(byte client_no)
    01812 {
    01813   if (NetworkFindClientInfo(client_no) != NULL) {
    01814     ShowNetworkChatQueryWindow(DESTTYPE_TEAM, NetworkFindClientInfo(client_no)->client_playas);
    01815   }
    01816 }
    01817
    01818 static void ClientList_SpeakToAll(byte client_no)
    01819 {
    01820   ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
    01821 }
    01822
    01824 struct NetworkClientListPopupWindow : Window {
    01826   struct ClientListAction {
    01827     StringID name;
    01828     ClientList_Action_Proc *proc;
    01829   };
    01830
    01831   uint sel_index;
    01832   int client_no;
    01833   Point desired_location;
    01834   SmallVector<ClientListAction, 2> actions;
    01835
    01841   inline void AddAction(StringID name, ClientList_Action_Proc *proc)
    01842   {
    01843     ClientListAction *action = this->actions.Append();
    01844     action->name = name;
    01845     action->proc = proc;
    01846   }
    01847
    01848   NetworkClientListPopupWindow(const WindowDesc *desc, int x, int y, int client_no) :
    01849       Window(),
    01850       sel_index(0), client_no(client_no)
    01851   {
    01852     this->desired_location.x = x;
    01853     this->desired_location.y = y;
    01854
    01855     const NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
    01856
    01857     if (_network_own_client_id != ci->client_id) {
    01858       this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, &ClientList_SpeakToClient);
    01859     }
    01860
    01861     if (Company::IsValidID(ci->client_playas) || ci->client_playas == COMPANY_SPECTATOR) {
    01862       this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, &ClientList_SpeakToCompany);
    01863     }
    01864     this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, &ClientList_SpeakToAll);
    01865
    01866     if (_network_own_client_id != ci->client_id) {
    01867       /* We are no spectator and the company we want to give money to is no spectator and money gifts are allowed */
    01868       if (Company::IsValidID(_local_company) && Company::IsValidID(ci->client_playas) && _settings_game.economy.give_money) {
    01869         this->AddAction(STR_NETWORK_CLIENTLIST_GIVE_MONEY, &ClientList_GiveMoney);
    01870       }
    01871     }
    01872
    01873     /* A server can kick clients (but not himself) */
    01874     if (_network_server && _network_own_client_id != ci->client_id) {
    01875       this->AddAction(STR_NETWORK_CLIENTLIST_KICK, &ClientList_Kick);
    01876       this->AddAction(STR_NETWORK_CLIENTLIST_BAN, &ClientList_Ban);
    01877     }
    01878
    01879     this->flags4 &= ~WF_WHITE_BORDER_MASK;
    01880     this->InitNested(desc, 0);
    01881   }
    01882
    01883   virtual Point OnInitialPosition(const WindowDesc *desc, int16 sm_width, int16 sm_height, int window_number)
    01884   {
    01885     return this->desired_location;
    01886   }
    01887
    01888   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    01889   {
    01890     Dimension d = *size;
    01891     for (const ClientListAction *action = this->actions.Begin(); action != this->actions.End(); action++) {
    01892       d = maxdim(GetStringBoundingBox(action->name), d);
    01893     }
    01894
    01895     d.height *= this->actions.Length();
    01896     d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
    01897     d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
    01898     *size = d;
    01899   }
    01900
    01901   virtual void DrawWidget(const Rect &r, int widget) const
    01902   {
    01903     /* Draw the actions */
    01904     int sel = this->sel_index;
    01905     int y = r.top + WD_FRAMERECT_TOP;
    01906     for (const ClientListAction *action = this->actions.Begin(); action != this->actions.End(); action++, y += FONT_HEIGHT_NORMAL) {
    01907       TextColour colour;
    01908       if (sel-- == 0) { // Selected item, highlight it
    01909         GfxFillRect(r.left + 1, y, r.right - 1, y + FONT_HEIGHT_NORMAL - 1, 0);
    01910         colour = TC_WHITE;
    01911       } else {
    01912         colour = TC_BLACK;
    01913       }
    01914
    01915       DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, action->name, colour);
    01916     }
    01917   }
    01918
    01919   virtual void OnPaint()
    01920   {
    01921     this->DrawWidgets();
    01922   }
    01923
    01924   virtual void OnMouseLoop()
    01925   {
    01926     /* We selected an action */
    01927     uint index = (_cursor.pos.y - this->top - WD_FRAMERECT_TOP) / FONT_HEIGHT_NORMAL;
    01928
    01929     if (_left_button_down) {
    01930       if (index == this->sel_index || index >= this->actions.Length()) return;
    01931
    01932       this->sel_index = index;
    01933       this->SetDirty();
    01934     } else {
    01935       if (index < this->actions.Length() && _cursor.pos.y >= this->top) {
    01936         this->actions[index].proc(this->client_no);
    01937       }
    01938
    01939       DeleteWindowById(WC_TOOLBAR_MENU, 0);
    01940     }
    01941   }
    01942 };
    01943
    01947 static void PopupClientList(int client_no, int x, int y)
    01948 {
    01949   DeleteWindowById(WC_TOOLBAR_MENU, 0);
    01950
    01951   if (NetworkFindClientInfo(client_no) == NULL) return;
    01952
    01953   new NetworkClientListPopupWindow(&_client_list_popup_desc, x, y, client_no);
    01954 }
    01955
    01956
    01958 enum ClientListWidgets {
    01959   CLW_PANEL,
    01960 };
    01961
    01962 static const NWidgetPart _nested_client_list_widgets[] = {
    01963   NWidget(NWID_HORIZONTAL),
    01964     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
    01965     NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_COMPANY_LIST_CLIENT_LIST, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    01966     NWidget(WWT_STICKYBOX, COLOUR_GREY),
    01967   EndContainer(),
    01968   NWidget(WWT_PANEL, COLOUR_GREY, CLW_PANEL), SetMinimalSize(250, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM), SetResize(1, 1), EndContainer(),
    01969 };
    01970
    01971 static const WindowDesc _client_list_desc(
    01972   WDP_AUTO, 0, 0,
    01973   WC_CLIENT_LIST, WC_NONE,
    01974   0,
    01975   _nested_client_list_widgets, lengthof(_nested_client_list_widgets)
    01976 );
    01977
    01981 struct NetworkClientListWindow : Window {
    01982   int selected_item;
    01983
    01984   uint server_client_width;
    01985   uint company_icon_width;
    01986
    01987   NetworkClientListWindow(const WindowDesc *desc, WindowNumber window_number) :
    01988       Window(),
    01989       selected_item(-1)
    01990   {
    01991     this->InitNested(desc, window_number);
    01992   }
    01993
    01997   bool CheckClientListHeight()
    01998   {
    01999     int num = 0;
    02000     const NetworkClientInfo *ci;
    02001
    02002     /* Should be replaced with a loop through all clients */
    02003     FOR_ALL_CLIENT_INFOS(ci) {
    02004       if (ci->client_playas != COMPANY_INACTIVE_CLIENT) num++;
    02005     }
    02006
    02007     num *= FONT_HEIGHT_NORMAL;
    02008
    02009     int diff = (num + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM) - (this->GetWidget<NWidgetBase>(CLW_PANEL)->current_y);
    02010     /* If height is changed */
    02011     if (diff != 0) {
    02012       ResizeWindow(this, 0, diff);
    02013       return false;
    02014     }
    02015     return true;
    02016   }
    02017
    02018   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    02019   {
    02020     if (widget != CLW_PANEL) return;
    02021
    02022     this->server_client_width = max(GetStringBoundingBox(STR_NETWORK_SERVER).width, GetStringBoundingBox(STR_NETWORK_CLIENT).width) + WD_FRAMERECT_RIGHT;
    02023     this->company_icon_width = GetSpriteSize(SPR_COMPANY_ICON).width + WD_FRAMERECT_LEFT;
    02024
    02025     uint width = 100; // Default width
    02026     const NetworkClientInfo *ci;
    02027     FOR_ALL_CLIENT_INFOS(ci) {
    02028       width = max(width, GetStringBoundingBox(ci->client_name).width);
    02029     }
    02030
    02031     size->width = WD_FRAMERECT_LEFT + this->server_client_width + this->company_icon_width + width + WD_FRAMERECT_RIGHT;
    02032   }
    02033
    02034   virtual void OnPaint()
    02035   {
    02036     /* Check if we need to reset the height */
    02037     if (!this->CheckClientListHeight()) return;
    02038
    02039     this->DrawWidgets();
    02040   }
    02041
    02042   virtual void DrawWidget(const Rect &r, int widget) const
    02043   {
    02044     if (widget != CLW_PANEL) return;
    02045
    02046     bool rtl = _dynlang.text_dir == TD_RTL;
    02047     int icon_y_offset = 1 + (FONT_HEIGHT_NORMAL - 10) / 2;
    02048     uint y = r.top + WD_FRAMERECT_TOP;
    02049     uint left = r.left + WD_FRAMERECT_LEFT;
    02050     uint right = r.right - WD_FRAMERECT_RIGHT;
    02051     uint type_icon_width = this->server_client_width + this->company_icon_width;
    02052
    02053
    02054     uint type_left  = rtl ? right - this->server_client_width : left;
    02055     uint type_right = rtl ? right : left + this->server_client_width - 1;
    02056     uint icon_left  = rtl ? right - type_icon_width + WD_FRAMERECT_LEFT : left + this->server_client_width;
    02057     uint name_left  = rtl ? left : left + type_icon_width;
    02058     uint name_right = rtl ? right - type_icon_width : right;
    02059
    02060     int i = 0;
    02061     const NetworkClientInfo *ci;
    02062     FOR_ALL_CLIENT_INFOS(ci) {
    02063       TextColour colour;
    02064       if (this->selected_item == i++) { // Selected item, highlight it
    02065         GfxFillRect(r.left + 1, y, r.right - 1, y + FONT_HEIGHT_NORMAL - 1, 0);
    02066         colour = TC_WHITE;
    02067       } else {
    02068         colour = TC_BLACK;
    02069       }
    02070
    02071       if (ci->client_id == CLIENT_ID_SERVER) {
    02072         DrawString(type_left, type_right, y, STR_NETWORK_SERVER, colour);
    02073       } else {
    02074         DrawString(type_left, type_right, y, STR_NETWORK_CLIENT, colour);
    02075       }
    02076
    02077       /* Filter out spectators */
    02078       if (Company::IsValidID(ci->client_playas)) DrawCompanyIcon(ci->client_playas, icon_left, y + icon_y_offset);
    02079
    02080       DrawString(name_left, name_right, y, ci->client_name, colour);
    02081
    02082       y += FONT_HEIGHT_NORMAL;
    02083     }
    02084   }
    02085
    02086   virtual void OnClick(Point pt, int widget)
    02087   {
    02088     /* Show the popup with option */
    02089     if (this->selected_item != -1) {
    02090       PopupClientList(this->selected_item, pt.x + this->left, pt.y + this->top);
    02091     }
    02092   }
    02093
    02094   virtual void OnMouseOver(Point pt, int widget)
    02095   {
    02096     /* -1 means we left the current window */
    02097     if (pt.y == -1) {
    02098       this->selected_item = -1;
    02099       this->SetDirty();
    02100       return;
    02101     }
    02102
    02103     /* Find the new selected item (if any) */
    02104     pt.y -= this->GetWidget<NWidgetBase>(CLW_PANEL)->pos_y;
    02105     int item = -1;
    02106     if (IsInsideMM(pt.y, WD_FRAMERECT_TOP, this->GetWidget<NWidgetBase>(CLW_PANEL)->current_y - WD_FRAMERECT_BOTTOM)) {
    02107       item = (pt.y - WD_FRAMERECT_TOP) / FONT_HEIGHT_NORMAL;
    02108     }
    02109
    02110     /* It did not change.. no update! */
    02111     if (item == this->selected_item) return;
    02112     this->selected_item = item;
    02113
    02114     /* Repaint */
    02115     this->SetDirty();
    02116   }
    02117 };
    02118
    02119 void ShowClientList()
    02120 {
    02121   AllocateWindowDescFront<NetworkClientListWindow>(&_client_list_desc, 0);
    02122 }
    02123
    02124
    02125 static NetworkPasswordType pw_type;
    02126
    02127
    02128 void ShowNetworkNeedPassword(NetworkPasswordType npt)
    02129 {
    02130   StringID caption;
    02131
    02132   pw_type = npt;
    02133   switch (npt) {
    02134     default: NOT_REACHED();
    02135     case NETWORK_GAME_PASSWORD:    caption = STR_NETWORK_NEED_GAME_PASSWORD_CAPTION; break;
    02136     case NETWORK_COMPANY_PASSWORD: caption = STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION; break;
    02137   }
    02138   ShowQueryString(STR_EMPTY, caption, 20, 180, FindWindowById(WC_NETWORK_STATUS_WINDOW, 0), CS_ALPHANUMERAL, QSF_NONE);
    02139 }
    02140
    02141 /* Vars needed for the join-GUI */
    02142 NetworkJoinStatus _network_join_status;
    02143 uint8 _network_join_waiting;
    02144 uint32 _network_join_bytes;
    02145 uint32 _network_join_bytes_total;
    02146
    02148 enum NetworkJoinStatusWidgets {
    02149   NJSW_BACKGROUND,
    02150   NJSW_CANCELOK,
    02151 };
    02152
    02153 struct NetworkJoinStatusWindow : Window {
    02154   NetworkJoinStatusWindow(const WindowDesc *desc) : Window()
    02155   {
    02156     this->parent = FindWindowById(WC_NETWORK_WINDOW, 0);
    02157     this->InitNested(desc, 0);
    02158   }
    02159
    02160   virtual void OnPaint()
    02161   {
    02162     this->DrawWidgets();
    02163   }
    02164
    02165   virtual void DrawWidget(const Rect &r, int widget) const
    02166   {
    02167     if (widget != NJSW_BACKGROUND) return;
    02168
    02169     uint8 progress; // used for progress bar
    02170     DrawString(r.left + 2, r.right - 2, r.top + 20, STR_NETWORK_CONNECTING_1 + _network_join_status, TC_FROMSTRING, SA_CENTER);
    02171     switch (_network_join_status) {
    02172       case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING:
    02173       case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
    02174         progress = 10; // first two stages 10%
    02175         break;
    02176       case NETWORK_JOIN_STATUS_WAITING:
    02177         SetDParam(0, _network_join_waiting);
    02178         DrawString(r.left + 2, r.right - 2, r.top + 20 + FONT_HEIGHT_NORMAL, STR_NETWORK_CONNECTING_WAITING, TC_FROMSTRING, SA_CENTER);
    02179         progress = 15; // third stage is 15%
    02180         break;
    02181       case NETWORK_JOIN_STATUS_DOWNLOADING:
    02182         SetDParam(0, _network_join_bytes);
    02183         SetDParam(1, _network_join_bytes_total);
    02184         DrawString(r.left + 2, r.right - 2, r.top + 20 + FONT_HEIGHT_NORMAL, STR_NETWORK_CONNECTING_DOWNLOADING, TC_FROMSTRING, SA_CENTER);
    02185         /* Fallthrough */
    02186       default: // Waiting is 15%, so the resting receivement of map is maximum 70%
    02187         progress = 15 + _network_join_bytes * (100 - 15) / _network_join_bytes_total;
    02188     }
    02189
    02190     /* Draw nice progress bar :) */
    02191     DrawFrameRect(r.left + 20, r.top + 5, (int)((this->width - 20) * progress / 100), r.top + 15, COLOUR_MAUVE, FR_NONE);
    02192   }
    02193
    02194   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    02195   {
    02196     if (widget != NJSW_BACKGROUND) return;
    02197
    02198     size->height = 25 + 2 * FONT_HEIGHT_NORMAL;
    02199
    02200     /* Account for the statuses */
    02201     uint width = 0;
    02202     for (uint i = 0; i < NETWORK_JOIN_STATUS_END; i++) {
    02203       width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_1 + i).width);
    02204     }
    02205
    02206     /* For the number of waiting (other) players */
    02207     SetDParam(0, 255);
    02208     width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_WAITING).width);
    02209
    02210     /* Account for downloading ~ 10 MiB */
    02211     SetDParam(0, 10000000);
    02212     SetDParam(1, 10000000);
    02213     width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_DOWNLOADING).width);
    02214
    02215     /* Give a bit more clearing for the widest strings than strictly needed */
    02216     size->width = width + WD_FRAMERECT_LEFT + WD_FRAMERECT_BOTTOM + 10;
    02217   }
    02218
    02219   virtual void OnClick(Point pt, int widget)
    02220   {
    02221     if (widget == NJSW_CANCELOK) { // Disconnect button
    02222       NetworkDisconnect();
    02223       SwitchToMode(SM_MENU);
    02224       ShowNetworkGameWindow();
    02225     }
    02226   }
    02227
    02228   virtual void OnQueryTextFinished(char *str)
    02229   {
    02230     if (StrEmpty(str)) {
    02231       NetworkDisconnect();
    02232       ShowNetworkGameWindow();
    02233     } else {
    02234       SEND_COMMAND(PACKET_CLIENT_PASSWORD)(pw_type, str);
    02235     }
    02236   }
    02237 };
    02238
    02239 static const NWidgetPart _nested_network_join_status_window_widgets[] = {
    02240   NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_CONNECTING_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    02241   NWidget(WWT_PANEL, COLOUR_GREY),
    02242     NWidget(WWT_EMPTY, COLOUR_GREY, NJSW_BACKGROUND),
    02243     NWidget(NWID_HORIZONTAL),
    02244       NWidget(NWID_SPACER), SetMinimalSize(75, 0), SetFill(1, 0),
    02245       NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NJSW_CANCELOK), SetMinimalSize(101, 12), SetDataTip(STR_NETWORK_CONNECTION_DISCONNECT, STR_NULL),
    02246       NWidget(NWID_SPACER), SetMinimalSize(75, 0), SetFill(1, 0),
    02247     EndContainer(),
    02248     NWidget(NWID_SPACER), SetMinimalSize(0, 4),
    02249   EndContainer(),
    02250 };
    02251
    02252 static const WindowDesc _network_join_status_window_desc(
    02253   WDP_CENTER, 0, 0,
    02254   WC_NETWORK_STATUS_WINDOW, WC_NONE,
    02255   WDF_MODAL,
    02256   _nested_network_join_status_window_widgets, lengthof(_nested_network_join_status_window_widgets)
    02257 );
    02258
    02259 void ShowJoinStatusWindow()
    02260 {
    02261   DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
    02262   new NetworkJoinStatusWindow(&_network_join_status_window_desc);
    02263 }
    02264
    02265
    02267 enum NetworkCompanyPasswordWindowWidgets {
    02268   NCPWW_BACKGROUND,
    02269   NCPWW_LABEL,
    02270   NCPWW_PASSWORD,
    02271   NCPWW_SAVE_AS_DEFAULT_PASSWORD,
    02272   NCPWW_CANCEL,
    02273   NCPWW_OK,
    02274 };
    02275
    02276 struct NetworkCompanyPasswordWindow : public QueryStringBaseWindow {
    02277   NetworkCompanyPasswordWindow(const WindowDesc *desc, Window *parent) : QueryStringBaseWindow(lengthof(_settings_client.network.default_company_pass))
    02278   {
    02279     this->InitNested(desc, 0);
    02280
    02281     this->parent = parent;
    02282     this->afilter = CS_ALPHANUMERAL;
    02283     InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, 0);
    02284     this->SetFocusedWidget(NCPWW_PASSWORD);
    02285   }
    02286
    02287   void OnOk()
    02288   {
    02289     if (this->IsWidgetLowered(NCPWW_SAVE_AS_DEFAULT_PASSWORD)) {
    02290       snprintf(_settings_client.network.default_company_pass, lengthof(_settings_client.network.default_company_pass), "%s", this->edit_str_buf);
    02291     }
    02292
    02293     /* empty password is a '*' because of console argument */
    02294     if (StrEmpty(this->edit_str_buf)) snprintf(this->edit_str_buf, this->edit_str_size, "*");
    02295     char *password = this->edit_str_buf;
    02296     NetworkChangeCompanyPassword(1, &password);
    02297   }
    02298
    02299   virtual void OnPaint()
    02300   {
    02301     this->DrawWidgets();
    02302     this->DrawEditBox(NCPWW_PASSWORD);
    02303   }
    02304
    02305   virtual void OnClick(Point pt, int widget)
    02306   {
    02307     switch (widget) {
    02308       case NCPWW_OK:
    02309         this->OnOk();
    02310
    02311       /* FALL THROUGH */
    02312       case NCPWW_CANCEL:
    02313         delete this;
    02314         break;
    02315
    02316       case NCPWW_SAVE_AS_DEFAULT_PASSWORD:
    02317         this->ToggleWidgetLoweredState(NCPWW_SAVE_AS_DEFAULT_PASSWORD);
    02318         this->SetDirty();
    02319         break;
    02320     }
    02321   }
    02322
    02323   virtual void OnMouseLoop()
    02324   {
    02325     this->HandleEditBox(4);
    02326   }
    02327
    02328   virtual EventState OnKeyPress(uint16 key, uint16 keycode)
    02329   {
    02330     EventState state = ES_NOT_HANDLED;
    02331     switch (this->HandleEditBoxKey(NCPWW_PASSWORD, key, keycode, state)) {
    02332       default: break;
    02333
    02334       case HEBR_CONFIRM:
    02335         this->OnOk();
    02336         /* FALL THROUGH */
    02337
    02338       case HEBR_CANCEL:
    02339         delete this;
    02340         break;
    02341     }
    02342     return state;
    02343   }
    02344
    02345   virtual void OnOpenOSKWindow(int wid)
    02346   {
    02347     ShowOnScreenKeyboard(this, wid, NCPWW_CANCEL, NCPWW_OK);
    02348   }
    02349 };
    02350
    02351 static const NWidgetPart _nested_network_company_password_window_widgets[] = {
    02352   NWidget(NWID_HORIZONTAL),
    02353     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
    02354     NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_COMPANY_PASSWORD_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    02355   EndContainer(),
    02356   NWidget(WWT_PANEL, COLOUR_GREY, NCPWW_BACKGROUND),
    02357     NWidget(NWID_VERTICAL), SetPIP(5, 5, 5),
    02358       NWidget(NWID_HORIZONTAL), SetPIP(5, 5, 5),
    02359         NWidget(WWT_TEXT, COLOUR_GREY, NCPWW_LABEL), SetDataTip(STR_COMPANY_VIEW_PASSWORD, STR_NULL),
    02360         NWidget(WWT_EDITBOX, COLOUR_GREY, NCPWW_PASSWORD), SetMinimalSize(194, 12), SetDataTip(STR_COMPANY_VIEW_SET_PASSWORD, STR_NULL),
    02361       EndContainer(),
    02362       NWidget(NWID_HORIZONTAL), SetPIP(5, 0, 5),
    02363         NWidget(NWID_SPACER), SetFill(1, 0),
    02364         NWidget(WWT_TEXTBTN, COLOUR_GREY, NCPWW_SAVE_AS_DEFAULT_PASSWORD), SetMinimalSize(194, 12),
    02365                       SetDataTip(STR_COMPANY_PASSWORD_MAKE_DEFAULT, STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP),
    02366       EndContainer(),
    02367     EndContainer(),
    02368   EndContainer(),
    02369   NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    02370     NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, NCPWW_CANCEL), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_COMPANY_PASSWORD_CANCEL),
    02371     NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, NCPWW_OK), SetFill(1, 0), SetDataTip(STR_BUTTON_OK, STR_COMPANY_PASSWORD_OK),
    02372   EndContainer(),
    02373 };
    02374
    02375 static const WindowDesc _network_company_password_window_desc(
    02376   WDP_AUTO, 0, 0,
    02377   WC_COMPANY_PASSWORD_WINDOW, WC_NONE,
    02378   WDF_UNCLICK_BUTTONS,
    02379   _nested_network_company_password_window_widgets, lengthof(_nested_network_company_password_window_widgets)
    02380 );
    02381
    02382 void ShowNetworkCompanyPasswordWindow(Window *parent)
    02383 {
    02384   DeleteWindowById(WC_COMPANY_PASSWORD_WINDOW, 0);
    02385
    02386   new NetworkCompanyPasswordWindow(&_network_company_password_window_desc, parent);
    02387 }
    02388
    02389 #endif /* ENABLE_NETWORK */