network_gui.cpp

Go to the documentation of this file.
00001 /* $Id: network_gui.cpp 16272 2009-05-10 21:26:46Z rubidium $ */
00002 
00005 #ifdef ENABLE_NETWORK
00006 #include "../stdafx.h"
00007 #include "../openttd.h"
00008 #include "../strings_func.h"
00009 #include "../date_func.h"
00010 #include "../fios.h"
00011 #include "network_internal.h"
00012 #include "network_client.h"
00013 #include "network_gui.h"
00014 #include "network_gamelist.h"
00015 #include "../gui.h"
00016 #include "network_server.h"
00017 #include "network_udp.h"
00018 #include "../window_func.h"
00019 #include "../string_func.h"
00020 #include "../gfx_func.h"
00021 #include "../settings_type.h"
00022 #include "../widgets/dropdown_func.h"
00023 #include "../querystring_gui.h"
00024 #include "../sortlist_type.h"
00025 #include "../company_base.h"
00026 
00027 #include "table/strings.h"
00028 #include "../table/sprites.h"
00029 
00030 
00031 static void ShowNetworkStartServerWindow();
00032 static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
00033 extern void SwitchToMode(SwitchMode new_mode);
00034 
00035 static const StringID _connection_types_dropdown[] = {
00036   STR_NETWORK_LAN_INTERNET,
00037   STR_NETWORK_INTERNET_ADVERTISE,
00038   INVALID_STRING_ID
00039 };
00040 
00041 static const StringID _lan_internet_types_dropdown[] = {
00042   STR_NETWORK_LAN,
00043   STR_NETWORK_INTERNET,
00044   INVALID_STRING_ID
00045 };
00046 
00047 static StringID _language_dropdown[NETLANG_COUNT + 1] = {STR_NULL};
00048 
00049 void SortNetworkLanguages()
00050 {
00051   /* Init the strings */
00052   if (_language_dropdown[0] == STR_NULL) {
00053     for (int i = 0; i < NETLANG_COUNT; i++) _language_dropdown[i] = STR_NETWORK_LANG_ANY + i;
00054     _language_dropdown[NETLANG_COUNT] = INVALID_STRING_ID;
00055   }
00056 
00057   /* Sort the strings (we don't move 'any' and the 'invalid' one) */
00058   qsort(&_language_dropdown[1], NETLANG_COUNT - 1, sizeof(StringID), &StringIDSorter);
00059 }
00060 
00061 enum {
00062   NET_PRC__OFFSET_TOP_WIDGET          = 54,
00063   NET_PRC__OFFSET_TOP_WIDGET_COMPANY  = 52,
00064   NET_PRC__SIZE_OF_ROW                = 14,
00065 };
00066 
00070 void UpdateNetworkGameWindow(bool unselect)
00071 {
00072   InvalidateWindowData(WC_NETWORK_WINDOW, 0, unselect ? 1 : 0);
00073 }
00074 
00076 enum NetworkGameWindowWidgets {
00077   NGWW_CLOSE,         
00078   NGWW_CAPTION,       
00079   NGWW_MAIN,          
00080 
00081   NGWW_CONNECTION,    
00082   NGWW_CONN_BTN,      
00083   NGWW_CLIENT,        
00084 
00085   NGWW_NAME,          
00086   NGWW_CLIENTS,       
00087   NGWW_MAPSIZE,       
00088   NGWW_DATE,          
00089   NGWW_YEARS,         
00090   NGWW_INFO,          
00091 
00092   NGWW_MATRIX,        
00093   NGWW_SCROLLBAR,     
00094 
00095   NGWW_LASTJOINED_LABEL, 
00096   NGWW_LASTJOINED,    
00097 
00098   NGWW_DETAILS,       
00099   NGWW_JOIN,          
00100   NGWW_REFRESH,       
00101   NGWW_NEWGRF,        
00102 
00103   NGWW_FIND,          
00104   NGWW_ADD,           
00105   NGWW_START,         
00106   NGWW_CANCEL,        
00107 
00108   NGWW_RESIZE,        
00109 };
00110 
00111 typedef GUIList<NetworkGameList*> GUIGameServerList;
00112 typedef uint16 ServerListPosition;
00113 static const ServerListPosition SLP_INVALID = 0xFFFF;
00114 
00115 class NetworkGameWindow : public QueryStringBaseWindow {
00116 protected:
00117   /* Runtime saved values */
00118   static Listing last_sorting;
00119 
00120   /* Constants for sorting servers */
00121   static GUIGameServerList::SortFunction * const sorter_funcs[];
00122 
00123   byte field;                  
00124   NetworkGameList *server;     
00125   GUIGameServerList servers;   
00126   ServerListPosition list_pos; 
00127 
00132   void BuildNetworkGameList()
00133   {
00134     if (!this->servers.NeedRebuild()) return;
00135 
00136     /* Create temporary array of games to use for listing */
00137     this->servers.Clear();
00138 
00139     for (NetworkGameList *ngl = _network_game_list; ngl != NULL; ngl = ngl->next) {
00140       *this->servers.Append() = ngl;
00141     }
00142 
00143     this->servers.Compact();
00144     this->servers.RebuildDone();
00145   }
00146 
00148   static int CDECL NGameNameSorter(NetworkGameList * const *a, NetworkGameList * const *b)
00149   {
00150     return strcasecmp((*a)->info.server_name, (*b)->info.server_name);
00151   }
00152 
00156   static int CDECL NGameClientSorter(NetworkGameList * const *a, NetworkGameList * const *b)
00157   {
00158     /* Reverse as per default we are interested in most-clients first */
00159     int r = (*a)->info.clients_on - (*b)->info.clients_on;
00160 
00161     if (r == 0) r = (*a)->info.clients_max - (*b)->info.clients_max;
00162     if (r == 0) r = NGameNameSorter(a, b);
00163 
00164     return r;
00165   }
00166 
00168   static int CDECL NGameMapSizeSorter(NetworkGameList * const *a, NetworkGameList * const *b)
00169   {
00170     /* Sort by the area of the map. */
00171     int r = ((*a)->info.map_height) * ((*a)->info.map_width) - ((*b)->info.map_height) * ((*b)->info.map_width);
00172 
00173     if (r == 0) r = (*a)->info.map_width - (*b)->info.map_width;
00174     return (r != 0) ? r : NGameClientSorter(a, b);
00175   }
00176 
00178   static int CDECL NGameDateSorter(NetworkGameList * const *a, NetworkGameList * const *b)
00179   {
00180     int r = (*a)->info.game_date - (*b)->info.game_date;
00181     return (r != 0) ? r : NGameClientSorter(a, b);
00182   }
00183 
00185   static int CDECL NGameYearsSorter(NetworkGameList * const *a, NetworkGameList * const *b)
00186   {
00187     int r = (*a)->info.game_date - (*a)->info.start_date - (*b)->info.game_date + (*b)->info.start_date;
00188     return (r != 0) ? r : NGameDateSorter(a, b);
00189   }
00190 
00193   static int CDECL NGameAllowedSorter(NetworkGameList * const *a, NetworkGameList * const *b)
00194   {
00195     /* The servers we do not know anything about (the ones that did not reply) should be at the bottom) */
00196     int r = StrEmpty((*a)->info.server_revision) - StrEmpty((*b)->info.server_revision);
00197 
00198     /* Reverse default as we are interested in version-compatible clients first */
00199     if (r == 0) r = (*b)->info.version_compatible - (*a)->info.version_compatible;
00200     /* The version-compatible ones are then sorted with NewGRF compatible first, incompatible last */
00201     if (r == 0) r = (*b)->info.compatible - (*a)->info.compatible;
00202     /* Passworded servers should be below unpassworded servers */
00203     if (r == 0) r = (*a)->info.use_password - (*b)->info.use_password;
00204     /* Finally sort on the name of the server */
00205     if (r == 0) r = NGameNameSorter(a, b);
00206 
00207     return r;
00208   }
00209 
00211   void SortNetworkGameList()
00212   {
00213     if (!this->servers.Sort()) return;
00214 
00215     /* After sorting ngl->sort_list contains the sorted items. Put these back
00216      * into the original list. Basically nothing has changed, we are only
00217      * shuffling the ->next pointers. While iterating, look for the
00218      * currently selected server and set list_pos to its position */
00219     this->list_pos = SLP_INVALID;
00220     _network_game_list = this->servers[0];
00221     NetworkGameList *item = _network_game_list;
00222     if (item == this->server) this->list_pos = 0;
00223     for (uint i = 1; i != this->servers.Length(); i++) {
00224       item->next = this->servers[i];
00225       item = item->next;
00226       if (item == this->server) this->list_pos = i;
00227     }
00228     item->next = NULL;
00229   }
00230 
00237   void DrawServerLine(const NetworkGameList *cur_item, uint y, bool highlight)
00238   {
00239     /* show highlighted item with a different colour */
00240     if (highlight) GfxFillRect(this->widget[NGWW_NAME].left + 1, y - 2, this->widget[NGWW_INFO].right - 1, y + 9, 10);
00241 
00242     SetDParamStr(0, cur_item->info.server_name);
00243     DrawStringTruncated(this->widget[NGWW_NAME].left + 5, y, STR_JUST_RAW_STRING, TC_BLACK, this->widget[NGWW_NAME].right - this->widget[NGWW_NAME].left - 5);
00244 
00245     /* only draw details if the server is online */
00246     if (cur_item->online) {
00247       SetDParam(0, cur_item->info.clients_on);
00248       SetDParam(1, cur_item->info.clients_max);
00249       SetDParam(2, cur_item->info.companies_on);
00250       SetDParam(3, cur_item->info.companies_max);
00251       DrawStringCentered(this->widget[NGWW_CLIENTS].left + 39, y, STR_NETWORK_GENERAL_ONLINE, TC_GOLD);
00252 
00253       /* map size */
00254       if (!this->IsWidgetHidden(NGWW_MAPSIZE)) {
00255         SetDParam(0, cur_item->info.map_width);
00256         SetDParam(1, cur_item->info.map_height);
00257         DrawStringCentered(this->widget[NGWW_MAPSIZE].left + 39, y, STR_NETWORK_MAP_SIZE_SHORT, TC_BLACK);
00258       }
00259 
00260       /* current date */
00261       if (!this->IsWidgetHidden(NGWW_DATE)) {
00262         YearMonthDay ymd;
00263         ConvertDateToYMD(cur_item->info.game_date, &ymd);
00264         SetDParam(0, ymd.year);
00265         DrawStringCentered(this->widget[NGWW_DATE].left + 29, y, STR_JUST_INT, TC_BLACK);
00266       }
00267 
00268       /* number of years the game is running */
00269       if (!this->IsWidgetHidden(NGWW_YEARS)) {
00270         YearMonthDay ymd_cur, ymd_start;
00271         ConvertDateToYMD(cur_item->info.game_date, &ymd_cur);
00272         ConvertDateToYMD(cur_item->info.start_date, &ymd_start);
00273         SetDParam(0, ymd_cur.year - ymd_start.year);
00274         DrawStringCentered(this->widget[NGWW_YEARS].left + 29, y, STR_JUST_INT, TC_BLACK);
00275       }
00276 
00277       /* draw a lock if the server is password protected */
00278       if (cur_item->info.use_password) DrawSprite(SPR_LOCK, PAL_NONE, this->widget[NGWW_INFO].left + 5, y - 1);
00279 
00280       /* draw red or green icon, depending on compatibility with server */
00281       DrawSprite(SPR_BLOT, (cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED)), this->widget[NGWW_INFO].left + 15, y);
00282 
00283       /* draw flag according to server language */
00284       DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, PAL_NONE, this->widget[NGWW_INFO].left + 25, y);
00285     }
00286   }
00287 
00295   void ScrollToSelectedServer()
00296   {
00297     if (this->list_pos == SLP_INVALID) return; // no server selected
00298     if (this->list_pos < this->vscroll.pos) {
00299       /* scroll up to the server */
00300       this->vscroll.pos = this->list_pos;
00301     } else if (this->list_pos >= this->vscroll.pos + this->vscroll.cap) {
00302       /* scroll down so that the server is at the bottom */
00303       this->vscroll.pos = this->list_pos - this->vscroll.cap + 1;
00304     }
00305   }
00306 
00307 public:
00308   NetworkGameWindow(const WindowDesc *desc) : QueryStringBaseWindow(NETWORK_CLIENT_NAME_LENGTH, desc)
00309   {
00310     ttd_strlcpy(this->edit_str_buf, _settings_client.network.client_name, this->edit_str_size);
00311     this->afilter = CS_ALPHANUMERAL;
00312     InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, 120);
00313     this->SetFocusedWidget(NGWW_CLIENT);
00314 
00315     UpdateNetworkGameWindow(true);
00316 
00317     this->vscroll.cap = 11;
00318     this->resize.step_height = NET_PRC__SIZE_OF_ROW;
00319 
00320     this->field = NGWW_CLIENT;
00321     this->server = NULL;
00322     this->list_pos = SLP_INVALID;
00323 
00324     this->servers.SetListing(this->last_sorting);
00325     this->servers.SetSortFuncs(this->sorter_funcs);
00326     this->servers.ForceRebuild();
00327     this->SortNetworkGameList();
00328 
00329     this->FindWindowPlacementAndResize(desc);
00330   }
00331 
00332   ~NetworkGameWindow()
00333   {
00334     this->last_sorting = this->servers.GetListing();
00335   }
00336 
00337   virtual void OnPaint()
00338   {
00339     const NetworkGameList *sel = this->server;
00340     const SortButtonState arrow = this->servers.IsDescSortOrder() ? SBS_DOWN : SBS_UP;
00341 
00342     if (this->servers.NeedRebuild()) {
00343       this->BuildNetworkGameList();
00344       SetVScrollCount(this, this->servers.Length());
00345     }
00346     this->SortNetworkGameList();
00347 
00348     /* 'Refresh' button invisible if no server selected */
00349     this->SetWidgetDisabledState(NGWW_REFRESH, sel == NULL);
00350     /* 'Join' button disabling conditions */
00351     this->SetWidgetDisabledState(NGWW_JOIN, sel == NULL || // no Selected Server
00352         !sel->online || // Server offline
00353         sel->info.clients_on >= sel->info.clients_max || // Server full
00354         !sel->info.compatible); // Revision mismatch
00355 
00356     /* 'NewGRF Settings' button invisible if no NewGRF is used */
00357     this->SetWidgetHiddenState(NGWW_NEWGRF, sel == NULL ||
00358         !sel->online ||
00359         sel->info.grfconfig == NULL);
00360 
00361     SetDParam(0, 0x00);
00362     SetDParam(1, _lan_internet_types_dropdown[_settings_client.network.lan_internet]);
00363     this->DrawWidgets();
00364 
00365     /* Edit box to set client name */
00366     this->DrawEditBox(NGWW_CLIENT);
00367 
00368     DrawString(this->widget[NGWW_CLIENT].left - 100, 23, STR_NETWORK_PLAYER_NAME, TC_GOLD);
00369 
00370     /* Sort based on widgets: name, clients, compatibility */
00371     switch (this->servers.SortType()) {
00372       case NGWW_NAME    - NGWW_NAME: this->DrawSortButtonState(NGWW_NAME,    arrow); break;
00373       case NGWW_CLIENTS - NGWW_NAME: this->DrawSortButtonState(NGWW_CLIENTS, arrow); break;
00374       case NGWW_MAPSIZE - NGWW_NAME: if (!this->IsWidgetHidden(NGWW_MAPSIZE)) this->DrawSortButtonState(NGWW_MAPSIZE, arrow); break;
00375       case NGWW_DATE    - NGWW_NAME: if (!this->IsWidgetHidden(NGWW_DATE))    this->DrawSortButtonState(NGWW_DATE,    arrow); break;
00376       case NGWW_YEARS   - NGWW_NAME: if (!this->IsWidgetHidden(NGWW_YEARS))   this->DrawSortButtonState(NGWW_YEARS,   arrow); break;
00377       case NGWW_INFO    - NGWW_NAME: this->DrawSortButtonState(NGWW_INFO,    arrow); break;
00378     }
00379 
00380     uint16 y = NET_PRC__OFFSET_TOP_WIDGET + 3;
00381 
00382     const int max = min(this->vscroll.pos + this->vscroll.cap, (int)this->servers.Length());
00383 
00384     for (int i = this->vscroll.pos; i < max; ++i) {
00385       const NetworkGameList *ngl = this->servers[i];
00386       this->DrawServerLine(ngl, y, ngl == sel);
00387       y += NET_PRC__SIZE_OF_ROW;
00388     }
00389 
00390     const NetworkGameList *last_joined = NetworkGameListAddItem(inet_addr(_settings_client.network.last_host), _settings_client.network.last_port);
00391     /* Draw the last joined server, if any */
00392     if (last_joined != NULL) this->DrawServerLine(last_joined, y = this->widget[NGWW_LASTJOINED].top + 3, last_joined == sel);
00393 
00394     /* Draw the right menu */
00395     GfxFillRect(this->widget[NGWW_DETAILS].left + 1, 43, this->widget[NGWW_DETAILS].right - 1, 92, 157);
00396     if (sel == NULL) {
00397       DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, 58, STR_NETWORK_GAME_INFO, TC_FROMSTRING);
00398     } else if (!sel->online) {
00399       SetDParamStr(0, sel->info.server_name);
00400       DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, 68, STR_JUST_RAW_STRING, TC_ORANGE); // game name
00401 
00402       DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, 132, STR_NETWORK_SERVER_OFFLINE, TC_FROMSTRING); // server offline
00403     } else { // show game info
00404       uint16 y = 100;
00405       const uint16 x = this->widget[NGWW_DETAILS].left + 5;
00406 
00407       DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, 48, STR_NETWORK_GAME_INFO, TC_FROMSTRING);
00408 
00409 
00410       SetDParamStr(0, sel->info.server_name);
00411       DrawStringCenteredTruncated(this->widget[NGWW_DETAILS].left, this->widget[NGWW_DETAILS].right, 62, STR_JUST_RAW_STRING, TC_ORANGE); // game name
00412 
00413       SetDParamStr(0, sel->info.map_name);
00414       DrawStringCenteredTruncated(this->widget[NGWW_DETAILS].left, this->widget[NGWW_DETAILS].right, 74, STR_JUST_RAW_STRING, TC_BLACK); // map name
00415 
00416       SetDParam(0, sel->info.clients_on);
00417       SetDParam(1, sel->info.clients_max);
00418       SetDParam(2, sel->info.companies_on);
00419       SetDParam(3, sel->info.companies_max);
00420       DrawString(x, y, STR_NETWORK_CLIENTS, TC_GOLD);
00421       y += 10;
00422 
00423       SetDParam(0, STR_NETWORK_LANG_ANY + sel->info.server_lang);
00424       DrawString(x, y, STR_NETWORK_LANGUAGE, TC_GOLD); // server language
00425       y += 10;
00426 
00427       SetDParam(0, STR_TEMPERATE_LANDSCAPE + sel->info.map_set);
00428       DrawString(x, y, STR_NETWORK_TILESET, TC_GOLD); // tileset
00429       y += 10;
00430 
00431       SetDParam(0, sel->info.map_width);
00432       SetDParam(1, sel->info.map_height);
00433       DrawString(x, y, STR_NETWORK_MAP_SIZE, TC_GOLD); // map size
00434       y += 10;
00435 
00436       SetDParamStr(0, sel->info.server_revision);
00437       DrawString(x, y, STR_NETWORK_SERVER_VERSION, TC_GOLD); // server version
00438       y += 10;
00439 
00440       SetDParamStr(0, sel->info.hostname);
00441       SetDParam(1, sel->port);
00442       DrawString(x, y, STR_NETWORK_SERVER_ADDRESS, TC_GOLD); // server address
00443       y += 10;
00444 
00445       SetDParam(0, sel->info.start_date);
00446       DrawString(x, y, STR_NETWORK_START_DATE, TC_GOLD); // start date
00447       y += 10;
00448 
00449       SetDParam(0, sel->info.game_date);
00450       DrawString(x, y, STR_NETWORK_CURRENT_DATE, TC_GOLD); // current date
00451       y += 10;
00452 
00453       y += 2;
00454 
00455       if (!sel->info.compatible) {
00456         DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, y, sel->info.version_compatible ? STR_NETWORK_GRF_MISMATCH : STR_NETWORK_VERSION_MISMATCH, TC_FROMSTRING); // server mismatch
00457       } else if (sel->info.clients_on == sel->info.clients_max) {
00458         /* Show: server full, when clients_on == max_clients */
00459         DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, y, STR_NETWORK_SERVER_FULL, TC_FROMSTRING); // server full
00460       } else if (sel->info.use_password) {
00461         DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, y, STR_NETWORK_PASSWORD, TC_FROMSTRING); // password warning
00462       }
00463 
00464       y += 10;
00465     }
00466   }
00467 
00468   virtual void OnClick(Point pt, int widget)
00469   {
00470     this->field = widget;
00471     switch (widget) {
00472       case NGWW_CANCEL: // Cancel button
00473         DeleteWindowById(WC_NETWORK_WINDOW, 0);
00474         break;
00475 
00476       case NGWW_CONN_BTN: // 'Connection' droplist
00477         ShowDropDownMenu(this, _lan_internet_types_dropdown, _settings_client.network.lan_internet, NGWW_CONN_BTN, 0, 0); // do it for widget NSSW_CONN_BTN
00478         break;
00479 
00480       case NGWW_NAME:    // Sort by name
00481       case NGWW_CLIENTS: // Sort by connected clients
00482       case NGWW_MAPSIZE: // Sort by map size
00483       case NGWW_DATE:    // Sort by date
00484       case NGWW_YEARS:   // Sort by years
00485       case NGWW_INFO:    // Connectivity (green dot)
00486         if (this->servers.SortType() == widget - NGWW_NAME) {
00487           this->servers.ToggleSortOrder();
00488           if (this->list_pos != SLP_INVALID) this->list_pos = this->servers.Length() - this->list_pos - 1;
00489         } else {
00490           this->servers.SetSortType(widget - NGWW_NAME);
00491           this->servers.ForceResort();
00492           this->SortNetworkGameList();
00493         }
00494         this->ScrollToSelectedServer();
00495         this->SetDirty();
00496         break;
00497 
00498       case NGWW_MATRIX: { // Matrix to show networkgames
00499         uint32 id_v = (pt.y - NET_PRC__OFFSET_TOP_WIDGET) / NET_PRC__SIZE_OF_ROW;
00500 
00501         if (id_v >= this->vscroll.cap) return; // click out of bounds
00502         id_v += this->vscroll.pos;
00503 
00504         this->server = (id_v < this->servers.Length()) ? this->servers[id_v] : NULL;
00505         this->list_pos = (server == NULL) ? SLP_INVALID : id_v;
00506         this->SetDirty();
00507       } break;
00508 
00509       case NGWW_LASTJOINED: {
00510         NetworkGameList *last_joined = NetworkGameListAddItem(inet_addr(_settings_client.network.last_host), _settings_client.network.last_port);
00511         if (last_joined != NULL) {
00512           this->server = last_joined;
00513 
00514           /* search the position of the newly selected server */
00515           for (uint i = 0; i < this->servers.Length(); i++) {
00516             if (this->servers[i] == this->server) {
00517               this->list_pos = i;
00518               break;
00519             }
00520           }
00521           this->ScrollToSelectedServer();
00522           this->SetDirty();
00523         }
00524       } break;
00525 
00526       case NGWW_FIND: // Find server automatically
00527         switch (_settings_client.network.lan_internet) {
00528           case 0: NetworkUDPSearchGame(); break;
00529           case 1: NetworkUDPQueryMasterServer(); break;
00530         }
00531         break;
00532 
00533       case NGWW_ADD: // Add a server
00534         SetDParamStr(0, _settings_client.network.connect_to_ip);
00535         ShowQueryString(
00536           STR_JUST_RAW_STRING,
00537           STR_NETWORK_ENTER_IP,
00538           NETWORK_HOSTNAME_LENGTH,  // maximum number of characters including '\0'
00539           0,                        // no limit in pixels
00540           this, CS_ALPHANUMERAL, QSF_ACCEPT_UNCHANGED);
00541         break;
00542 
00543       case NGWW_START: // Start server
00544         ShowNetworkStartServerWindow();
00545         break;
00546 
00547       case NGWW_JOIN: // Join Game
00548         if (this->server != NULL) {
00549           snprintf(_settings_client.network.last_host, sizeof(_settings_client.network.last_host), "%s", inet_ntoa(*(struct in_addr *)&this->server->ip));
00550           _settings_client.network.last_port = this->server->port;
00551           ShowNetworkLobbyWindow(this->server);
00552         }
00553         break;
00554 
00555       case NGWW_REFRESH: // Refresh
00556         if (this->server != NULL) NetworkUDPQueryServer(NetworkAddress(this->server->info.hostname, this->server->port));
00557         break;
00558 
00559       case NGWW_NEWGRF: // NewGRF Settings
00560         if (this->server != NULL) ShowNewGRFSettings(false, false, false, &this->server->info.grfconfig);
00561         break;
00562     }
00563   }
00564 
00565   virtual void OnDoubleClick(Point pt, int widget)
00566   {
00567     if (widget == NGWW_MATRIX || widget == NGWW_LASTJOINED) {
00568       /* is the Join button enabled? */
00569       if (!this->IsWidgetDisabled(NGWW_JOIN)) this->OnClick(pt, NGWW_JOIN);
00570     }
00571   }
00572 
00573   virtual void OnDropdownSelect(int widget, int index)
00574   {
00575     switch (widget) {
00576       case NGWW_CONN_BTN:
00577         _settings_client.network.lan_internet = index;
00578         break;
00579 
00580       default:
00581         NOT_REACHED();
00582     }
00583 
00584     this->SetDirty();
00585   }
00586 
00587   virtual void OnMouseLoop()
00588   {
00589     if (this->field == NGWW_CLIENT) this->HandleEditBox(NGWW_CLIENT);
00590   }
00591 
00592   virtual void OnInvalidateData(int data)
00593   {
00594     switch (data) {
00595       /* Remove the selection */
00596       case 1:
00597         this->server = NULL;
00598         this->list_pos = SLP_INVALID;
00599         break;
00600 
00601       /* Reiterate the whole server list as we downloaded some files */
00602       case 2:
00603         for (NetworkGameList **iter = this->servers.Begin(); iter != this->servers.End(); iter++) {
00604           NetworkGameList *item = *iter;
00605           bool missing_grfs = false;
00606           for (GRFConfig *c = item->info.grfconfig; c != NULL; c = c->next) {
00607             if (c->status != GCS_NOT_FOUND) continue;
00608 
00609             const GRFConfig *f = FindGRFConfig(c->grfid, c->md5sum);
00610             if (f == NULL) {
00611               missing_grfs = true;
00612               continue;
00613             }
00614 
00615             c->filename  = f->filename;
00616             c->name      = f->name;
00617             c->info      = f->info;
00618             c->status    = GCS_UNKNOWN;
00619           }
00620 
00621           if (!missing_grfs) item->info.compatible = item->info.version_compatible;
00622         }
00623         break;
00624     }
00625     this->servers.ForceRebuild();
00626     this->SetDirty();
00627   }
00628 
00629   virtual EventState OnKeyPress(uint16 key, uint16 keycode)
00630   {
00631     EventState state = ES_NOT_HANDLED;
00632 
00633     /* handle up, down, pageup, pagedown, home and end */
00634     if (keycode == WKC_UP || keycode == WKC_DOWN || keycode == WKC_PAGEUP || keycode == WKC_PAGEDOWN || keycode == WKC_HOME || keycode == WKC_END) {
00635       if (this->servers.Length() == 0) return ES_HANDLED;
00636       switch (keycode) {
00637         case WKC_UP:
00638           /* scroll up by one */
00639           if (this->server == NULL) return ES_HANDLED;
00640           if (this->list_pos > 0) this->list_pos--;
00641           break;
00642         case WKC_DOWN:
00643           /* scroll down by one */
00644           if (this->server == NULL) return ES_HANDLED;
00645           if (this->list_pos < this->servers.Length() - 1) this->list_pos++;
00646           break;
00647         case WKC_PAGEUP:
00648           /* scroll up a page */
00649           if (this->server == NULL) return ES_HANDLED;
00650           this->list_pos = (this->list_pos < this->vscroll.cap) ? 0 : this->list_pos - this->vscroll.cap;
00651           break;
00652         case WKC_PAGEDOWN:
00653           /* scroll down a page */
00654           if (this->server == NULL) return ES_HANDLED;
00655           this->list_pos = min(this->list_pos + this->vscroll.cap, (int)this->servers.Length() - 1);
00656           break;
00657         case WKC_HOME:
00658           /* jump to beginning */
00659           this->list_pos = 0;
00660           break;
00661         case WKC_END:
00662           /* jump to end */
00663           this->list_pos = this->servers.Length() - 1;
00664           break;
00665         default: break;
00666       }
00667 
00668       this->server = this->servers[this->list_pos];
00669 
00670       /* scroll to the new server if it is outside the current range */
00671       this->ScrollToSelectedServer();
00672 
00673       /* redraw window */
00674       this->SetDirty();
00675       return ES_HANDLED;
00676     }
00677 
00678     if (this->field != NGWW_CLIENT) {
00679       if (this->server != NULL) {
00680         if (keycode == WKC_DELETE) { // Press 'delete' to remove servers
00681           NetworkGameListRemoveItem(this->server);
00682           NetworkRebuildHostList();
00683           this->server = NULL;
00684           this->list_pos = SLP_INVALID;
00685         }
00686       }
00687       return state;
00688     }
00689 
00690     if (this->HandleEditBoxKey(NGWW_CLIENT, key, keycode, state) == HEBR_CONFIRM) return state;
00691 
00692     /* The name is only allowed when it starts with a letter! */
00693     if (!StrEmpty(this->edit_str_buf) && this->edit_str_buf[0] != ' ') {
00694       strecpy(_settings_client.network.client_name, this->edit_str_buf, lastof(_settings_client.network.client_name));
00695     } else {
00696       strecpy(_settings_client.network.client_name, "Player", lastof(_settings_client.network.client_name));
00697     }
00698     return state;
00699   }
00700 
00701   virtual void OnQueryTextFinished(char *str)
00702   {
00703     if (!StrEmpty(str)) {
00704       NetworkAddServer(str);
00705       NetworkRebuildHostList();
00706     }
00707   }
00708 
00709   virtual void OnResize(Point new_size, Point delta)
00710   {
00711     this->vscroll.cap += delta.y / (int)this->resize.step_height;
00712 
00713     this->widget[NGWW_MATRIX].data = (this->vscroll.cap << 8) + 1;
00714 
00715     SetVScrollCount(this, this->servers.Length());
00716 
00717     /* Additional colums in server list */
00718     if (this->width > NetworkGameWindow::MIN_EXTRA_COLUMNS_WIDTH + GetWidgetWidth(NGWW_MAPSIZE) +
00719         GetWidgetWidth(NGWW_DATE) + GetWidgetWidth(NGWW_YEARS)) {
00720       /* show columns 'Map size', 'Date' and 'Years' */
00721       this->SetWidgetsHiddenState(false, NGWW_MAPSIZE, NGWW_DATE, NGWW_YEARS, WIDGET_LIST_END);
00722       AlignWidgetRight(NGWW_YEARS,   NGWW_INFO);
00723       AlignWidgetRight(NGWW_DATE,    NGWW_YEARS);
00724       AlignWidgetRight(NGWW_MAPSIZE, NGWW_DATE);
00725       AlignWidgetRight(NGWW_CLIENTS, NGWW_MAPSIZE);
00726     } else if (this->width > NetworkGameWindow::MIN_EXTRA_COLUMNS_WIDTH + GetWidgetWidth(NGWW_MAPSIZE) + GetWidgetWidth(NGWW_DATE)) {
00727       /* show columns 'Map size' and 'Date' */
00728       this->SetWidgetsHiddenState(false, NGWW_MAPSIZE, NGWW_DATE, WIDGET_LIST_END);
00729       this->HideWidget(NGWW_YEARS);
00730       AlignWidgetRight(NGWW_DATE,    NGWW_INFO);
00731       AlignWidgetRight(NGWW_MAPSIZE, NGWW_DATE);
00732       AlignWidgetRight(NGWW_CLIENTS, NGWW_MAPSIZE);
00733     } else if (this->width > NetworkGameWindow::MIN_EXTRA_COLUMNS_WIDTH + GetWidgetWidth(NGWW_MAPSIZE)) {
00734       /* show column 'Map size' */
00735       this->ShowWidget(NGWW_MAPSIZE);
00736       this->SetWidgetsHiddenState(true, NGWW_DATE, NGWW_YEARS, WIDGET_LIST_END);
00737       AlignWidgetRight(NGWW_MAPSIZE, NGWW_INFO);
00738       AlignWidgetRight(NGWW_CLIENTS, NGWW_MAPSIZE);
00739     } else {
00740       /* hide columns 'Map size', 'Date' and 'Years' */
00741       this->SetWidgetsHiddenState(true, NGWW_MAPSIZE, NGWW_DATE, NGWW_YEARS, WIDGET_LIST_END);
00742       AlignWidgetRight(NGWW_CLIENTS, NGWW_INFO);
00743     }
00744     this->widget[NGWW_NAME].right = this->widget[NGWW_CLIENTS].left - 1;
00745 
00746     /* BOTTOM */
00747     int widget_width = this->widget[NGWW_FIND].right - this->widget[NGWW_FIND].left;
00748     int space = (this->width - 4 * widget_width - 25) / 3;
00749 
00750     int offset = 10;
00751     for (uint i = 0; i < 4; i++) {
00752       this->widget[NGWW_FIND + i].left  = offset;
00753       offset += widget_width;
00754       this->widget[NGWW_FIND + i].right = offset;
00755       offset += space;
00756     }
00757   }
00758 
00759   static const int MIN_EXTRA_COLUMNS_WIDTH = 550;   
00760 };
00761 
00762 Listing NetworkGameWindow::last_sorting = {false, 5};
00763 GUIGameServerList::SortFunction * const NetworkGameWindow::sorter_funcs[] = {
00764   &NGameNameSorter,
00765   &NGameClientSorter,
00766   &NGameMapSizeSorter,
00767   &NGameDateSorter,
00768   &NGameYearsSorter,
00769   &NGameAllowedSorter
00770 };
00771 
00772 
00773 static const Widget _network_game_window_widgets[] = {
00774 /* TOP */
00775 {   WWT_CLOSEBOX,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},            // NGWW_CLOSE
00776 {    WWT_CAPTION,   RESIZE_RIGHT,  COLOUR_LIGHT_BLUE,    11,   449,     0,    13, STR_NETWORK_MULTIPLAYER,          STR_NULL},                         // NGWW_CAPTION
00777 {      WWT_PANEL,   RESIZE_RB,     COLOUR_LIGHT_BLUE,     0,   449,    14,   263, 0x0,                              STR_NULL},                         // NGWW_MAIN
00778 
00779 {       WWT_TEXT,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,     9,    85,    23,    35, STR_NETWORK_CONNECTION,           STR_NULL},                         // NGWW_CONNECTION
00780 { WWT_DROPDOWNIN,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,    90,   181,    22,    33, STR_NETWORK_LAN_INTERNET_COMBO,   STR_NETWORK_CONNECTION_TIP},       // NGWW_CONN_BTN
00781 
00782 {    WWT_EDITBOX,   RESIZE_LR,     COLOUR_LIGHT_BLUE,   290,   440,    22,    33, STR_NETWORK_PLAYER_NAME_OSKTITLE, STR_NETWORK_ENTER_NAME_TIP},       // NGWW_CLIENT
00783 
00784 /* LEFT SIDE */
00785 { WWT_PUSHTXTBTN,   RESIZE_NONE,   COLOUR_WHITE,         10,    70,    42,    53, STR_NETWORK_GAME_NAME,            STR_NETWORK_GAME_NAME_TIP},        // NGWW_NAME
00786 { WWT_PUSHTXTBTN,   RESIZE_NONE,   COLOUR_WHITE,         71,   150,    42,    53, STR_NETWORK_CLIENTS_CAPTION,      STR_NETWORK_CLIENTS_CAPTION_TIP},  // NGWW_CLIENTS
00787 { WWT_PUSHTXTBTN,   RESIZE_NONE,   COLOUR_WHITE,         71,   150,    42,    53, STR_NETWORK_MAP_SIZE_CAPTION,     STR_NETWORK_MAP_SIZE_CAPTION_TIP}, // NGWW_MAPSIZE
00788 { WWT_PUSHTXTBTN,   RESIZE_NONE,   COLOUR_WHITE,         71,   130,    42,    53, STR_NETWORK_DATE_CAPTION,         STR_NETWORK_DATE_CAPTION_TIP},     // NGWW_DATE
00789 { WWT_PUSHTXTBTN,   RESIZE_NONE,   COLOUR_WHITE,         71,   130,    42,    53, STR_NETWORK_YEARS_CAPTION,        STR_NETWORK_YEARS_CAPTION_TIP},    // NGWW_YEARS
00790 { WWT_PUSHTXTBTN,   RESIZE_LR,     COLOUR_WHITE,        151,   190,    42,    53, STR_EMPTY,                        STR_NETWORK_INFO_ICONS_TIP},       // NGWW_INFO
00791 
00792 {     WWT_MATRIX,   RESIZE_RB,     COLOUR_LIGHT_BLUE,    10,   190,    54,   208, (11 << 8) + 1,                    STR_NETWORK_CLICK_GAME_TO_SELECT}, // NGWW_MATRIX
00793 {  WWT_SCROLLBAR,   RESIZE_LRB,    COLOUR_LIGHT_BLUE,   191,   202,    42,   208, 0x0,                              STR_0190_SCROLL_BAR_SCROLLS_LIST}, // NGWW_SCROLLBAR
00794 {       WWT_TEXT,   RESIZE_RTB,    COLOUR_LIGHT_BLUE,    10,   190,   211,   222, STR_NETWORK_LAST_JOINED_SERVER,   STR_NULL},                         // NGWW_LASTJOINED_LABEL
00795 {      WWT_PANEL,   RESIZE_RTB,    COLOUR_LIGHT_BLUE,    10,   190,   223,   236, 0x0,                              STR_NETWORK_CLICK_TO_SELECT_LAST}, // NGWW_LASTJOINED
00796 
00797 /* RIGHT SIDE */
00798 {      WWT_PANEL,   RESIZE_LRB,    COLOUR_LIGHT_BLUE,   210,   440,    42,   236, 0x0,                              STR_NULL},                         // NGWW_DETAILS
00799 
00800 { WWT_PUSHTXTBTN,   RESIZE_LRTB,   COLOUR_WHITE,        215,   315,   215,   226, STR_NETWORK_JOIN_GAME,            STR_NULL},                         // NGWW_JOIN
00801 { WWT_PUSHTXTBTN,   RESIZE_LRTB,   COLOUR_WHITE,        330,   435,   215,   226, STR_NETWORK_REFRESH,              STR_NETWORK_REFRESH_TIP},          // NGWW_REFRESH
00802 
00803 { WWT_PUSHTXTBTN,   RESIZE_LRTB,   COLOUR_WHITE,        330,   435,   197,   208, STR_NEWGRF_SETTINGS_BUTTON,       STR_NULL},                         // NGWW_NEWGRF
00804 
00805 /* BOTTOM */
00806 { WWT_PUSHTXTBTN,   RESIZE_TB,     COLOUR_WHITE,         10,   110,   246,   257, STR_NETWORK_FIND_SERVER,          STR_NETWORK_FIND_SERVER_TIP},      // NGWW_FIND
00807 { WWT_PUSHTXTBTN,   RESIZE_TB,     COLOUR_WHITE,        118,   218,   246,   257, STR_NETWORK_ADD_SERVER,           STR_NETWORK_ADD_SERVER_TIP},       // NGWW_ADD
00808 { WWT_PUSHTXTBTN,   RESIZE_TB,     COLOUR_WHITE,        226,   326,   246,   257, STR_NETWORK_START_SERVER,         STR_NETWORK_START_SERVER_TIP},     // NGWW_START
00809 { WWT_PUSHTXTBTN,   RESIZE_TB,     COLOUR_WHITE,        334,   434,   246,   257, STR_012E_CANCEL,                  STR_NULL},                         // NGWW_CANCEL
00810 
00811 {  WWT_RESIZEBOX,   RESIZE_LRTB,   COLOUR_LIGHT_BLUE,   438,   449,   252,   263, 0x0,                              STR_RESIZE_BUTTON },               // NGWW_RESIZE
00812 
00813 {   WIDGETS_END},
00814 };
00815 
00816 static const WindowDesc _network_game_window_desc(
00817   WDP_CENTER, WDP_CENTER, 450, 264, 780, 264,
00818   WC_NETWORK_WINDOW, WC_NONE,
00819   WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
00820   _network_game_window_widgets
00821 );
00822 
00823 void ShowNetworkGameWindow()
00824 {
00825   static bool first = true;
00826   DeleteWindowById(WC_NETWORK_WINDOW, 0);
00827 
00828   /* Only show once */
00829   if (first) {
00830     char * const *srv;
00831 
00832     first = false;
00833     /* add all servers from the config file to our list */
00834     for (srv = &_network_host_list[0]; srv != endof(_network_host_list) && *srv != NULL; srv++) {
00835       NetworkAddServer(*srv);
00836     }
00837   }
00838 
00839   new NetworkGameWindow(&_network_game_window_desc);
00840 }
00841 
00842 enum {
00843   NSSWND_START = 64,
00844   NSSWND_ROWSIZE = 12
00845 };
00846 
00848 enum NetworkStartServerWidgets {
00849   NSSW_CLOSE           =  0,   
00850   NSSW_GAMENAME        =  4,   
00851   NSSW_SETPWD          =  5,   
00852   NSSW_SELMAP          =  7,   
00853   NSSW_CONNTYPE_BTN    = 10,   
00854   NSSW_CLIENTS_BTND    = 12,   
00855   NSSW_CLIENTS_TXT     = 13,   
00856   NSSW_CLIENTS_BTNU    = 14,   
00857   NSSW_COMPANIES_BTND  = 16,   
00858   NSSW_COMPANIES_TXT   = 17,   
00859   NSSW_COMPANIES_BTNU  = 18,   
00860   NSSW_SPECTATORS_BTND = 20,   
00861   NSSW_SPECTATORS_TXT  = 21,   
00862   NSSW_SPECTATORS_BTNU = 22,   
00863   NSSW_LANGUAGE_BTN    = 24,   
00864   NSSW_START           = 25,   
00865   NSSW_LOAD            = 26,   
00866   NSSW_CANCEL          = 27,   
00867 };
00868 
00869 struct NetworkStartServerWindow : public QueryStringBaseWindow {
00870   byte field;                  
00871   FiosItem *map;               
00872   byte widget_id;              
00873 
00874   NetworkStartServerWindow(const WindowDesc *desc) : QueryStringBaseWindow(NETWORK_NAME_LENGTH, desc)
00875   {
00876     ttd_strlcpy(this->edit_str_buf, _settings_client.network.server_name, this->edit_str_size);
00877 
00878     _saveload_mode = SLD_NEW_GAME;
00879     BuildFileList();
00880     this->vscroll.cap = 12;
00881     this->vscroll.count = _fios_items.Length() + 1;
00882 
00883     this->afilter = CS_ALPHANUMERAL;
00884     InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, 160);
00885     this->SetFocusedWidget(NSSW_GAMENAME);
00886 
00887     this->field = NSSW_GAMENAME;
00888 
00889     this->FindWindowPlacementAndResize(desc);
00890   }
00891 
00892   virtual void OnPaint()
00893   {
00894     int y = NSSWND_START;
00895     const FiosItem *item;
00896 
00897     /* draw basic widgets */
00898     SetDParam(1, _connection_types_dropdown[_settings_client.network.server_advertise]);
00899     SetDParam(2, _settings_client.network.max_clients);
00900     SetDParam(3, _settings_client.network.max_companies);
00901     SetDParam(4, _settings_client.network.max_spectators);
00902     SetDParam(5, STR_NETWORK_LANG_ANY + _settings_client.network.server_lang);
00903     this->DrawWidgets();
00904 
00905     /* editbox to set game name */
00906     this->DrawEditBox(NSSW_GAMENAME);
00907 
00908     /* if password is set, draw red '*' next to 'Set password' button */
00909     if (!StrEmpty(_settings_client.network.server_password)) DoDrawString("*", 408, 23, TC_RED);
00910 
00911     /* draw list of maps */
00912     GfxFillRect(11, 63, 258, 215, 0xD7);  // black background of maps list
00913 
00914     for (uint pos = this->vscroll.pos; pos < _fios_items.Length() + 1; pos++) {
00915       item = _fios_items.Get(pos - 1);
00916       if (item == this->map || (pos == 0 && this->map == NULL))
00917         GfxFillRect(11, y - 1, 258, y + 10, 155); // show highlighted item with a different colour
00918 
00919       if (pos == 0) {
00920         DrawString(14, y, STR_4010_GENERATE_RANDOM_NEW_GAME, TC_DARK_GREEN);
00921       } else {
00922         DoDrawString(item->title, 14, y, _fios_colours[item->type] );
00923       }
00924       y += NSSWND_ROWSIZE;
00925 
00926       if (y >= this->vscroll.cap * NSSWND_ROWSIZE + NSSWND_START) break;
00927     }
00928   }
00929 
00930   virtual void OnClick(Point pt, int widget)
00931   {
00932     this->field = widget;
00933     switch (widget) {
00934       case NSSW_CLOSE:  // Close 'X'
00935       case NSSW_CANCEL: // Cancel button
00936         ShowNetworkGameWindow();
00937         break;
00938 
00939       case NSSW_SETPWD: // Set password button
00940         this->widget_id = NSSW_SETPWD;
00941         SetDParamStr(0, _settings_client.network.server_password);
00942         ShowQueryString(STR_JUST_RAW_STRING, STR_NETWORK_SET_PASSWORD, 20, 250, this, CS_ALPHANUMERAL, QSF_NONE);
00943         break;
00944 
00945       case NSSW_SELMAP: { // Select map
00946         int y = (pt.y - NSSWND_START) / NSSWND_ROWSIZE;
00947 
00948         y += this->vscroll.pos;
00949         if (y >= this->vscroll.count) return;
00950 
00951         this->map = (y == 0) ? NULL : _fios_items.Get(y - 1);
00952         this->SetDirty();
00953       } break;
00954 
00955       case NSSW_CONNTYPE_BTN: // Connection type
00956         ShowDropDownMenu(this, _connection_types_dropdown, _settings_client.network.server_advertise, NSSW_CONNTYPE_BTN, 0, 0); // do it for widget NSSW_CONNTYPE_BTN
00957         break;
00958 
00959       case NSSW_CLIENTS_BTND:    case NSSW_CLIENTS_BTNU:    // Click on up/down button for number of clients
00960       case NSSW_COMPANIES_BTND:  case NSSW_COMPANIES_BTNU:  // Click on up/down button for number of companies
00961       case NSSW_SPECTATORS_BTND: case NSSW_SPECTATORS_BTNU: // Click on up/down button for number of spectators
00962         /* Don't allow too fast scrolling */
00963         if ((this->flags4 & WF_TIMEOUT_MASK) <= WF_TIMEOUT_TRIGGER) {
00964           this->HandleButtonClick(widget);
00965           this->SetDirty();
00966           switch (widget) {
00967             default: NOT_REACHED();
00968             case NSSW_CLIENTS_BTND: case NSSW_CLIENTS_BTNU:
00969               _settings_client.network.max_clients    = Clamp(_settings_client.network.max_clients    + widget - NSSW_CLIENTS_TXT,    2, MAX_CLIENTS);
00970               break;
00971             case NSSW_COMPANIES_BTND: case NSSW_COMPANIES_BTNU:
00972               _settings_client.network.max_companies  = Clamp(_settings_client.network.max_companies  + widget - NSSW_COMPANIES_TXT,  1, MAX_COMPANIES);
00973               break;
00974             case NSSW_SPECTATORS_BTND: case NSSW_SPECTATORS_BTNU:
00975               _settings_client.network.max_spectators = Clamp(_settings_client.network.max_spectators + widget - NSSW_SPECTATORS_TXT, 0, MAX_CLIENTS);
00976               break;
00977           }
00978         }
00979         _left_button_clicked = false;
00980         break;
00981 
00982       case NSSW_CLIENTS_TXT:    // Click on number of clients
00983         this->widget_id = NSSW_CLIENTS_TXT;
00984         SetDParam(0, _settings_client.network.max_clients);
00985         ShowQueryString(STR_CONFIG_SETTING_INT32, STR_NETWORK_NUMBER_OF_CLIENTS,    4, 50, this, CS_NUMERAL, QSF_NONE);
00986         break;
00987 
00988       case NSSW_COMPANIES_TXT:  // Click on number of companies
00989         this->widget_id = NSSW_COMPANIES_TXT;
00990         SetDParam(0, _settings_client.network.max_companies);
00991         ShowQueryString(STR_CONFIG_SETTING_INT32, STR_NETWORK_NUMBER_OF_COMPANIES,  3, 50, this, CS_NUMERAL, QSF_NONE);
00992         break;
00993 
00994       case NSSW_SPECTATORS_TXT: // Click on number of spectators
00995         this->widget_id = NSSW_SPECTATORS_TXT;
00996         SetDParam(0, _settings_client.network.max_spectators);
00997         ShowQueryString(STR_CONFIG_SETTING_INT32, STR_NETWORK_NUMBER_OF_SPECTATORS, 4, 50, this, CS_NUMERAL, QSF_NONE);
00998         break;
00999 
01000       case NSSW_LANGUAGE_BTN: { // Language
01001         uint sel = 0;
01002         for (uint i = 0; i < lengthof(_language_dropdown) - 1; i++) {
01003           if (_language_dropdown[i] == STR_NETWORK_LANG_ANY + _settings_client.network.server_lang) {
01004             sel = i;
01005             break;
01006           }
01007         }
01008         ShowDropDownMenu(this, _language_dropdown, sel, NSSW_LANGUAGE_BTN, 0, 0);
01009       } break;
01010 
01011       case NSSW_START: // Start game
01012         _is_network_server = true;
01013 
01014         if (this->map == NULL) { // start random new game
01015           ShowGenerateLandscape();
01016         } else { // load a scenario
01017           const char *name = FiosBrowseTo(this->map);
01018           if (name != NULL) {
01019             SetFiosType(this->map->type);
01020             _file_to_saveload.filetype = FT_SCENARIO;
01021             strecpy(_file_to_saveload.name, name, lastof(_file_to_saveload.name));
01022             strecpy(_file_to_saveload.title, this->map->title, lastof(_file_to_saveload.title));
01023 
01024             delete this;
01025             SwitchToMode(SM_START_SCENARIO);
01026           }
01027         }
01028         break;
01029 
01030       case NSSW_LOAD: // Load game
01031         _is_network_server = true;
01032         /* XXX - WC_NETWORK_WINDOW (this window) should stay, but if it stays, it gets
01033          * copied all the elements of 'load game' and upon closing that, it segfaults */
01034         delete this;
01035         ShowSaveLoadDialog(SLD_LOAD_GAME);
01036         break;
01037     }
01038   }
01039 
01040   virtual void OnDropdownSelect(int widget, int index)
01041   {
01042     switch (widget) {
01043       case NSSW_CONNTYPE_BTN:
01044         _settings_client.network.server_advertise = (index != 0);
01045         break;
01046       case NSSW_LANGUAGE_BTN:
01047         _settings_client.network.server_lang = _language_dropdown[index] - STR_NETWORK_LANG_ANY;
01048         break;
01049       default:
01050         NOT_REACHED();
01051     }
01052 
01053     this->SetDirty();
01054   }
01055 
01056   virtual void OnMouseLoop()
01057   {
01058     if (this->field == NSSW_GAMENAME) this->HandleEditBox(NSSW_GAMENAME);
01059   }
01060 
01061   virtual EventState OnKeyPress(uint16 key, uint16 keycode)
01062   {
01063     EventState state = ES_NOT_HANDLED;
01064     if (this->field == NSSW_GAMENAME) {
01065       if (this->HandleEditBoxKey(NSSW_GAMENAME, key, keycode, state) == HEBR_CONFIRM) return state;
01066 
01067       strecpy(_settings_client.network.server_name, this->text.buf, lastof(_settings_client.network.server_name));
01068     }
01069 
01070     return state;
01071   }
01072 
01073   virtual void OnQueryTextFinished(char *str)
01074   {
01075     if (str == NULL) return;
01076 
01077     if (this->widget_id == NSSW_SETPWD) {
01078       strecpy(_settings_client.network.server_password, str, lastof(_settings_client.network.server_password));
01079     } else {
01080       int32 value = atoi(str);
01081       this->InvalidateWidget(this->widget_id);
01082       switch (this->widget_id) {
01083         default: NOT_REACHED();
01084         case NSSW_CLIENTS_TXT:    _settings_client.network.max_clients    = Clamp(value, 2, MAX_CLIENTS); break;
01085         case NSSW_COMPANIES_TXT:  _settings_client.network.max_companies  = Clamp(value, 1, MAX_COMPANIES); break;
01086         case NSSW_SPECTATORS_TXT: _settings_client.network.max_spectators = Clamp(value, 0, MAX_CLIENTS); break;
01087       }
01088     }
01089 
01090     this->SetDirty();
01091   }
01092 };
01093 
01094 static const Widget _network_start_server_window_widgets[] = {
01095 /* Window decoration and background panel */
01096 {   WWT_CLOSEBOX,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,     0,    10,     0,    13, STR_00C5,                           STR_018B_CLOSE_WINDOW },               // NSSW_CLOSE
01097 {    WWT_CAPTION,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,    11,   419,     0,    13, STR_NETWORK_START_GAME_WINDOW,      STR_NULL},
01098 {      WWT_PANEL,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,     0,   419,    14,   243, 0x0,                                STR_NULL},
01099 
01100 /* Set game name and password widgets */
01101 {       WWT_TEXT,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,    10,    90,    22,    34, STR_NETWORK_NEW_GAME_NAME,          STR_NULL},
01102 {    WWT_EDITBOX,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   100,   272,    22,    33, STR_NETWORK_NEW_GAME_NAME_OSKTITLE, STR_NETWORK_NEW_GAME_NAME_TIP},        // NSSW_GAMENAME
01103 { WWT_PUSHTXTBTN,   RESIZE_NONE,   COLOUR_WHITE,        285,   405,    22,    33, STR_NETWORK_SET_PASSWORD,           STR_NETWORK_PASSWORD_TIP},             // NSSW_SETPWD
01104 
01105 /* List of playable scenarios */
01106 {       WWT_TEXT,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,    10,   110,    43,    55, STR_NETWORK_SELECT_MAP,             STR_NULL},
01107 {      WWT_INSET,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,    10,   271,    62,   216, STR_NULL,                           STR_NETWORK_SELECT_MAP_TIP},           // NSSW_SELMAP
01108 {  WWT_SCROLLBAR,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   259,   270,    63,   215, 0x0,                                STR_0190_SCROLL_BAR_SCROLLS_LIST},
01109 
01110 /* Combo/selection boxes to control Connection Type / Max Clients / Max Companies / Max Observers / Language */
01111 {       WWT_TEXT,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   280,   419,    63,    75, STR_NETWORK_CONNECTION,             STR_NULL},
01112 { WWT_DROPDOWNIN,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   280,   410,    77,    88, STR_NETWORK_LAN_INTERNET_COMBO,     STR_NETWORK_CONNECTION_TIP},           // NSSW_CONNTYPE_BTN
01113 
01114 {       WWT_TEXT,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   280,   419,    95,   107, STR_NETWORK_NUMBER_OF_CLIENTS,      STR_NULL},
01115 {     WWT_IMGBTN,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   280,   291,   109,   120, SPR_ARROW_DOWN,                     STR_NETWORK_NUMBER_OF_CLIENTS_TIP},    // NSSW_CLIENTS_BTND
01116 { WWT_PUSHTXTBTN,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   292,   397,   109,   120, STR_NETWORK_CLIENTS_SELECT,         STR_NETWORK_NUMBER_OF_CLIENTS_TIP},    // NSSW_CLIENTS_TXT
01117 {     WWT_IMGBTN,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   398,   410,   109,   120, SPR_ARROW_UP,                       STR_NETWORK_NUMBER_OF_CLIENTS_TIP},    // NSSW_CLIENTS_BTNU
01118 
01119 {       WWT_TEXT,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   280,   419,   127,   139, STR_NETWORK_NUMBER_OF_COMPANIES,    STR_NULL},
01120 {     WWT_IMGBTN,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   280,   291,   141,   152, SPR_ARROW_DOWN,                     STR_NETWORK_NUMBER_OF_COMPANIES_TIP},  // NSSW_COMPANIES_BTND
01121 { WWT_PUSHTXTBTN,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   292,   397,   141,   152, STR_NETWORK_COMPANIES_SELECT,       STR_NETWORK_NUMBER_OF_COMPANIES_TIP},  // NSSW_COMPANIES_TXT
01122 {     WWT_IMGBTN,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   398,   410,   141,   152, SPR_ARROW_UP,                       STR_NETWORK_NUMBER_OF_COMPANIES_TIP},  // NSSW_COMPANIES_BTNU
01123 
01124 {       WWT_TEXT,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   280,   419,   159,   171, STR_NETWORK_NUMBER_OF_SPECTATORS,   STR_NULL},
01125 {     WWT_IMGBTN,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   280,   291,   173,   184, SPR_ARROW_DOWN,                     STR_NETWORK_NUMBER_OF_SPECTATORS_TIP}, // NSSW_SPECTATORS_BTND
01126 { WWT_PUSHTXTBTN,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   292,   397,   173,   184, STR_NETWORK_SPECTATORS_SELECT,      STR_NETWORK_NUMBER_OF_SPECTATORS_TIP}, // NSSW_SPECTATORS_TXT
01127 {     WWT_IMGBTN,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   398,   410,   173,   184, SPR_ARROW_UP,                       STR_NETWORK_NUMBER_OF_SPECTATORS_TIP}, // NSSW_SPECTATORS_BTNU
01128 
01129 {       WWT_TEXT,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   280,   419,   191,   203, STR_NETWORK_LANGUAGE_SPOKEN,        STR_NULL},
01130 { WWT_DROPDOWNIN,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   280,   410,   205,   216, STR_NETWORK_LANGUAGE_COMBO,         STR_NETWORK_LANGUAGE_TIP},             // NSSW_LANGUAGE_BTN
01131 
01132 /* Buttons Start / Load / Cancel */
01133 { WWT_PUSHTXTBTN,   RESIZE_NONE,   COLOUR_WHITE,         40,   140,   224,   235, STR_NETWORK_START_GAME,             STR_NETWORK_START_GAME_TIP},           // NSSW_START
01134 { WWT_PUSHTXTBTN,   RESIZE_NONE,   COLOUR_WHITE,        150,   250,   224,   235, STR_NETWORK_LOAD_GAME,              STR_NETWORK_LOAD_GAME_TIP},            // NSSW_LOAD
01135 { WWT_PUSHTXTBTN,   RESIZE_NONE,   COLOUR_WHITE,        260,   360,   224,   235, STR_012E_CANCEL,                    STR_NULL},                             // NSSW_CANCEL
01136 
01137 {   WIDGETS_END},
01138 };
01139 
01140 static const WindowDesc _network_start_server_window_desc(
01141   WDP_CENTER, WDP_CENTER, 420, 244, 420, 244,
01142   WC_NETWORK_WINDOW, WC_NONE,
01143   WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
01144   _network_start_server_window_widgets
01145 );
01146 
01147 static void ShowNetworkStartServerWindow()
01148 {
01149   DeleteWindowById(WC_NETWORK_WINDOW, 0);
01150 
01151   new NetworkStartServerWindow(&_network_start_server_window_desc);
01152 }
01153 
01155 enum NetworkLobbyWindowWidgets {
01156   NLWW_CLOSE    =  0, 
01157   NLWW_MATRIX   =  5, 
01158   NLWW_DETAILS  =  7, 
01159   NLWW_JOIN     =  8, 
01160   NLWW_NEW      =  9, 
01161   NLWW_SPECTATE = 10, 
01162   NLWW_REFRESH  = 11, 
01163   NLWW_CANCEL   = 12, 
01164 };
01165 
01166 struct NetworkLobbyWindow : public Window {
01167   CompanyID company;       
01168   NetworkGameList *server; 
01169   NetworkCompanyInfo company_info[MAX_COMPANIES];
01170 
01171   NetworkLobbyWindow(const WindowDesc *desc, NetworkGameList *ngl) :
01172       Window(desc), company(INVALID_COMPANY), server(ngl)
01173   {
01174     this->vscroll.cap = 10;
01175 
01176     this->FindWindowPlacementAndResize(desc);
01177   }
01178 
01179   CompanyID NetworkLobbyFindCompanyIndex(byte pos)
01180   {
01181     /* Scroll through all this->company_info and get the 'pos' item that is not empty */
01182     for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
01183       if (!StrEmpty(this->company_info[i].company_name)) {
01184         if (pos-- == 0) return i;
01185       }
01186     }
01187 
01188     return COMPANY_FIRST;
01189   }
01190 
01191   virtual void OnPaint()
01192   {
01193     const NetworkGameInfo *gi = &this->server->info;
01194     int y = NET_PRC__OFFSET_TOP_WIDGET_COMPANY, pos;
01195 
01196     /* Join button is disabled when no company is selected and for AI companies*/
01197     this->SetWidgetDisabledState(NLWW_JOIN, this->company == INVALID_COMPANY || GetLobbyCompanyInfo(this->company)->ai);
01198     /* Cannot start new company if there are too many */
01199     this->SetWidgetDisabledState(NLWW_NEW, gi->companies_on >= gi->companies_max);
01200     /* Cannot spectate if there are too many spectators */
01201     this->SetWidgetDisabledState(NLWW_SPECTATE, gi->spectators_on >= gi->spectators_max);
01202 
01203     /* Draw window widgets */
01204     SetDParamStr(0, gi->server_name);
01205     this->DrawWidgets();
01206 
01207     SetVScrollCount(this, gi->companies_on);
01208 
01209     /* Draw company list */
01210     pos = this->vscroll.pos;
01211     while (pos < gi->companies_on) {
01212       byte company = NetworkLobbyFindCompanyIndex(pos);
01213       bool income = false;
01214       if (this->company == company) {
01215         GfxFillRect(11, y - 1, 154, y + 10, 10); // show highlighted item with a different colour
01216       }
01217 
01218       DoDrawStringTruncated(this->company_info[company].company_name, 13, y, TC_BLACK, 135 - 13);
01219       if (this->company_info[company].use_password != 0) DrawSprite(SPR_LOCK, PAL_NONE, 135, y);
01220 
01221       /* If the company's income was positive puts a green dot else a red dot */
01222       if (this->company_info[company].income >= 0) income = true;
01223       DrawSprite(SPR_BLOT, income ? PALETTE_TO_GREEN : PALETTE_TO_RED, 145, y);
01224 
01225       pos++;
01226       y += NET_PRC__SIZE_OF_ROW;
01227       if (pos >= this->vscroll.pos + this->vscroll.cap) break;
01228     }
01229 
01230     /* Draw info about selected company when it is selected in the left window */
01231     GfxFillRect(174, 39, 403, 75, 157);
01232     DrawStringCentered(290, 50, STR_NETWORK_COMPANY_INFO, TC_FROMSTRING);
01233     if (this->company != INVALID_COMPANY && !StrEmpty(this->company_info[this->company].company_name)) {
01234       const uint x = 183;
01235       const uint trunc_width = this->widget[NLWW_DETAILS].right - x;
01236       y = 80;
01237 
01238       SetDParam(0, gi->clients_on);
01239       SetDParam(1, gi->clients_max);
01240       SetDParam(2, gi->companies_on);
01241       SetDParam(3, gi->companies_max);
01242       DrawString(x, y, STR_NETWORK_CLIENTS, TC_GOLD);
01243       y += 10;
01244 
01245       SetDParamStr(0, this->company_info[this->company].company_name);
01246       DrawStringTruncated(x, y, STR_NETWORK_COMPANY_NAME, TC_GOLD, trunc_width);
01247       y += 10;
01248 
01249       SetDParam(0, this->company_info[this->company].inaugurated_year);
01250       DrawString(x, y, STR_NETWORK_INAUGURATION_YEAR, TC_GOLD); // inauguration year
01251       y += 10;
01252 
01253       SetDParam(0, this->company_info[this->company].company_value);
01254       DrawString(x, y, STR_NETWORK_VALUE, TC_GOLD); // company value
01255       y += 10;
01256 
01257       SetDParam(0, this->company_info[this->company].money);
01258       DrawString(x, y, STR_NETWORK_CURRENT_BALANCE, TC_GOLD); // current balance
01259       y += 10;
01260 
01261       SetDParam(0, this->company_info[this->company].income);
01262       DrawString(x, y, STR_NETWORK_LAST_YEARS_INCOME, TC_GOLD); // last year's income
01263       y += 10;
01264 
01265       SetDParam(0, this->company_info[this->company].performance);
01266       DrawString(x, y, STR_NETWORK_PERFORMANCE, TC_GOLD); // performance
01267       y += 10;
01268 
01269       SetDParam(0, this->company_info[this->company].num_vehicle[0]);
01270       SetDParam(1, this->company_info[this->company].num_vehicle[1]);
01271       SetDParam(2, this->company_info[this->company].num_vehicle[2]);
01272       SetDParam(3, this->company_info[this->company].num_vehicle[3]);
01273       SetDParam(4, this->company_info[this->company].num_vehicle[4]);
01274       DrawString(x, y, STR_NETWORK_VEHICLES, TC_GOLD); // vehicles
01275       y += 10;
01276 
01277       SetDParam(0, this->company_info[this->company].num_station[0]);
01278       SetDParam(1, this->company_info[this->company].num_station[1]);
01279       SetDParam(2, this->company_info[this->company].num_station[2]);
01280       SetDParam(3, this->company_info[this->company].num_station[3]);
01281       SetDParam(4, this->company_info[this->company].num_station[4]);
01282       DrawString(x, y, STR_NETWORK_STATIONS, TC_GOLD); // stations
01283       y += 10;
01284 
01285       SetDParamStr(0, this->company_info[this->company].clients);
01286       DrawStringTruncated(x, y, STR_NETWORK_PLAYERS, TC_GOLD, trunc_width); // players
01287     }
01288   }
01289 
01290   virtual void OnClick(Point pt, int widget)
01291   {
01292     switch (widget) {
01293       case NLWW_CLOSE:    // Close 'X'
01294       case NLWW_CANCEL:   // Cancel button
01295         ShowNetworkGameWindow();
01296         break;
01297 
01298       case NLWW_MATRIX: { // Company list
01299         uint32 id_v = (pt.y - NET_PRC__OFFSET_TOP_WIDGET_COMPANY) / NET_PRC__SIZE_OF_ROW;
01300 
01301         if (id_v >= this->vscroll.cap) break;
01302 
01303         id_v += this->vscroll.pos;
01304         this->company = (id_v >= this->server->info.companies_on) ? INVALID_COMPANY : NetworkLobbyFindCompanyIndex(id_v);
01305         this->SetDirty();
01306       } break;
01307 
01308       case NLWW_JOIN:     // Join company
01309         /* Button can be clicked only when it is enabled */
01310         _network_playas = this->company;
01311         NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01312         break;
01313 
01314       case NLWW_NEW:      // New company
01315         _network_playas = COMPANY_NEW_COMPANY;
01316         NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01317         break;
01318 
01319       case NLWW_SPECTATE: // Spectate game
01320         _network_playas = COMPANY_SPECTATOR;
01321         NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01322         break;
01323 
01324       case NLWW_REFRESH:  // Refresh
01325         NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // company info
01326         NetworkUDPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // general data
01327         /* Clear the information so removed companies don't remain */
01328         memset(this->company_info, 0, sizeof(this->company_info));
01329         break;
01330     }
01331   }
01332 
01333   virtual void OnDoubleClick(Point pt, int widget)
01334   {
01335     if (widget == NLWW_MATRIX) {
01336       /* is the Join button enabled? */
01337       if (!this->IsWidgetDisabled(NLWW_JOIN)) this->OnClick(pt, NLWW_JOIN);
01338     }
01339   }
01340 };
01341 
01342 static const Widget _network_lobby_window_widgets[] = {
01343 {   WWT_CLOSEBOX,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,     0,    10,     0,    13, STR_00C5,                    STR_018B_CLOSE_WINDOW },           // NLWW_CLOSE
01344 {    WWT_CAPTION,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,    11,   419,     0,    13, STR_NETWORK_GAME_LOBBY,      STR_NULL},
01345 {      WWT_PANEL,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,     0,   419,    14,   234, 0x0,                         STR_NULL},
01346 {       WWT_TEXT,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,    10,   419,    22,    34, STR_NETWORK_PREPARE_TO_JOIN, STR_NULL},
01347 
01348 /* company list */
01349 {      WWT_PANEL,   RESIZE_NONE,   COLOUR_WHITE,         10,   155,    38,    49, 0x0,                         STR_NULL},
01350 {     WWT_MATRIX,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,    10,   155,    50,   190, (10 << 8) + 1,               STR_NETWORK_COMPANY_LIST_TIP},     // NLWW_MATRIX
01351 {  WWT_SCROLLBAR,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   156,   167,    38,   190, 0x0,                         STR_0190_SCROLL_BAR_SCROLLS_LIST},
01352 
01353 /* company info */
01354 {      WWT_PANEL,   RESIZE_NONE,   COLOUR_LIGHT_BLUE,   173,   404,    38,   190, 0x0,                         STR_NULL},                         // NLWW_DETAILS
01355 
01356 /* buttons */
01357 { WWT_PUSHTXTBTN,   RESIZE_NONE,   COLOUR_WHITE,         10,   151,   200,   211, STR_NETWORK_JOIN_COMPANY,    STR_NETWORK_JOIN_COMPANY_TIP},     // NLWW_JOIN
01358 { WWT_PUSHTXTBTN,   RESIZE_NONE,   COLOUR_WHITE,         10,   151,   215,   226, STR_NETWORK_NEW_COMPANY,     STR_NETWORK_NEW_COMPANY_TIP},      // NLWW_NEW
01359 { WWT_PUSHTXTBTN,   RESIZE_NONE,   COLOUR_WHITE,        158,   268,   200,   211, STR_NETWORK_SPECTATE_GAME,   STR_NETWORK_SPECTATE_GAME_TIP},    // NLWW_SPECTATE
01360 { WWT_PUSHTXTBTN,   RESIZE_NONE,   COLOUR_WHITE,        158,   268,   215,   226, STR_NETWORK_REFRESH,         STR_NETWORK_REFRESH_TIP},          // NLWW_REFRESH
01361 { WWT_PUSHTXTBTN,   RESIZE_NONE,   COLOUR_WHITE,        278,   388,   200,   211, STR_012E_CANCEL,             STR_NULL},                         // NLWW_CANCEL
01362 
01363 {   WIDGETS_END},
01364 };
01365 
01366 static const WindowDesc _network_lobby_window_desc(
01367   WDP_CENTER, WDP_CENTER, 420, 235, 420, 235,
01368   WC_NETWORK_WINDOW, WC_NONE,
01369   WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
01370   _network_lobby_window_widgets
01371 );
01372 
01373 /* Show the networklobbywindow with the selected server
01374  * @param ngl Selected game pointer which is passed to the new window */
01375 static void ShowNetworkLobbyWindow(NetworkGameList *ngl)
01376 {
01377   DeleteWindowById(WC_NETWORK_WINDOW, 0);
01378 
01379   NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // company info
01380   NetworkUDPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // general data
01381 
01382   new NetworkLobbyWindow(&_network_lobby_window_desc, ngl);
01383 }
01384 
01390 NetworkCompanyInfo *GetLobbyCompanyInfo(CompanyID company)
01391 {
01392   NetworkLobbyWindow *lobby = dynamic_cast<NetworkLobbyWindow*>(FindWindowById(WC_NETWORK_WINDOW, 0));
01393   return (lobby != NULL && company < MAX_COMPANIES) ? &lobby->company_info[company] : NULL;
01394 }
01395 
01396 /* The window below gives information about the connected clients
01397  *  and also makes able to give money to them, kick them (if server)
01398  *  and stuff like that. */
01399 
01400 extern void DrawCompanyIcon(CompanyID cid, int x, int y);
01401 
01402 /* Every action must be of this form */
01403 typedef void ClientList_Action_Proc(byte client_no);
01404 
01405 /* Max 10 actions per client */
01406 #define MAX_CLIENTLIST_ACTION 10
01407 
01408 enum {
01409   CLNWND_OFFSET = 16,
01410   CLNWND_ROWSIZE = 10
01411 };
01412 
01413 static const Widget _client_list_widgets[] = {
01414 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,                 STR_018B_CLOSE_WINDOW},
01415 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   237,     0,    13, STR_NETWORK_CLIENT_LIST,  STR_018C_WINDOW_TITLE_DRAG_THIS},
01416 {  WWT_STICKYBOX,   RESIZE_NONE,  COLOUR_GREY,   238,   249,     0,    13, STR_NULL,                 STR_STICKY_BUTTON},
01417 
01418 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   249,    14,    14 + CLNWND_ROWSIZE + 1, 0x0, STR_NULL},
01419 {   WIDGETS_END},
01420 };
01421 
01422 static const Widget _client_list_popup_widgets[] = {
01423 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   99,     0,     0,     0, STR_NULL},
01424 {   WIDGETS_END},
01425 };
01426 
01427 static const WindowDesc _client_list_desc(
01428   WDP_AUTO, WDP_AUTO, 250, 1, 250, 1,
01429   WC_CLIENT_LIST, WC_NONE,
01430   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
01431   _client_list_widgets
01432 );
01433 
01434 /* Finds the Xth client-info that is active */
01435 static const NetworkClientInfo *NetworkFindClientInfo(byte client_no)
01436 {
01437   const NetworkClientInfo *ci;
01438 
01439   FOR_ALL_CLIENT_INFOS(ci) {
01440     if (client_no == 0) return ci;
01441     client_no--;
01442   }
01443 
01444   return NULL;
01445 }
01446 
01447 /* Here we start to define the options out of the menu */
01448 static void ClientList_Kick(byte client_no)
01449 {
01450   const NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
01451 
01452   if (ci == NULL) return;
01453 
01454   NetworkServerKickClient(ci->client_id);
01455 }
01456 
01457 static void ClientList_Ban(byte client_no)
01458 {
01459   const NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
01460 
01461   if (ci == NULL) return;
01462 
01463   NetworkServerBanIP(GetClientIP(ci));
01464 }
01465 
01466 static void ClientList_GiveMoney(byte client_no)
01467 {
01468   if (NetworkFindClientInfo(client_no) != NULL) {
01469     ShowNetworkGiveMoneyWindow(NetworkFindClientInfo(client_no)->client_playas);
01470   }
01471 }
01472 
01473 static void ClientList_SpeakToClient(byte client_no)
01474 {
01475   if (NetworkFindClientInfo(client_no) != NULL) {
01476     ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, NetworkFindClientInfo(client_no)->client_id);
01477   }
01478 }
01479 
01480 static void ClientList_SpeakToCompany(byte client_no)
01481 {
01482   if (NetworkFindClientInfo(client_no) != NULL) {
01483     ShowNetworkChatQueryWindow(DESTTYPE_TEAM, NetworkFindClientInfo(client_no)->client_playas);
01484   }
01485 }
01486 
01487 static void ClientList_SpeakToAll(byte client_no)
01488 {
01489   ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
01490 }
01491 
01492 static void ClientList_None(byte client_no)
01493 {
01494   /* No action ;) */
01495 }
01496 
01497 
01498 
01499 struct NetworkClientListPopupWindow : Window {
01500   int sel_index;
01501   int client_no;
01502   char action[MAX_CLIENTLIST_ACTION][50];
01503   ClientList_Action_Proc *proc[MAX_CLIENTLIST_ACTION];
01504 
01505   NetworkClientListPopupWindow(int x, int y, const Widget *widgets, int client_no) :
01506       Window(x, y, 150, 100, WC_TOOLBAR_MENU, widgets),
01507       sel_index(0), client_no(client_no)
01508   {
01509     /*
01510      * Fill the actions this client has.
01511      * Watch is, max 50 chars long!
01512      */
01513 
01514     const NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
01515 
01516     int i = 0;
01517     if (_network_own_client_id != ci->client_id) {
01518       GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, lastof(this->action[i]));
01519       this->proc[i++] = &ClientList_SpeakToClient;
01520     }
01521 
01522     if (IsValidCompanyID(ci->client_playas) || ci->client_playas == COMPANY_SPECTATOR) {
01523       GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, lastof(this->action[i]));
01524       this->proc[i++] = &ClientList_SpeakToCompany;
01525     }
01526     GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, lastof(this->action[i]));
01527     this->proc[i++] = &ClientList_SpeakToAll;
01528 
01529     if (_network_own_client_id != ci->client_id) {
01530       /* We are no spectator and the company we want to give money to is no spectator and money gifts are allowed */
01531       if (IsValidCompanyID(_network_playas) && IsValidCompanyID(ci->client_playas) && _settings_game.economy.give_money) {
01532         GetString(this->action[i], STR_NETWORK_CLIENTLIST_GIVE_MONEY, lastof(this->action[i]));
01533         this->proc[i++] = &ClientList_GiveMoney;
01534       }
01535     }
01536 
01537     /* A server can kick clients (but not himself) */
01538     if (_network_server && _network_own_client_id != ci->client_id) {
01539       GetString(this->action[i], STR_NETWORK_CLIENTLIST_KICK, lastof(this->action[i]));
01540       this->proc[i++] = &ClientList_Kick;
01541 
01542       seprintf(this->action[i], lastof(this->action[i]), "Ban"); // XXX GetString?
01543       this->proc[i++] = &ClientList_Ban;
01544     }
01545 
01546     if (i == 0) {
01547       GetString(this->action[i], STR_NETWORK_CLIENTLIST_NONE, lastof(this->action[i]));
01548       this->proc[i++] = &ClientList_None;
01549     }
01550 
01551     /* Calculate the height */
01552     int h = ClientListPopupHeight();
01553 
01554     /* Allocate the popup */
01555     this->widget[0].bottom = this->widget[0].top + h;
01556     this->widget[0].right = this->widget[0].left + 150;
01557 
01558     this->flags4 &= ~WF_WHITE_BORDER_MASK;
01559 
01560     this->FindWindowPlacementAndResize(150, h + 1);
01561   }
01562 
01566   void HandleClientListPopupClick(byte index)
01567   {
01568     /* A click on the Popup of the ClientList.. handle the command */
01569     if (index < MAX_CLIENTLIST_ACTION && this->proc[index] != NULL) {
01570       this->proc[index](this->client_no);
01571     }
01572   }
01573 
01577   uint ClientListPopupHeight()
01578   {
01579     int num = 0;
01580 
01581     /* Find the amount of actions */
01582     for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
01583       if (this->action[i][0] == '\0') continue;
01584       if (this->proc[i] == NULL) continue;
01585       num++;
01586     }
01587 
01588     num *= CLNWND_ROWSIZE;
01589 
01590     return num + 1;
01591   }
01592 
01593 
01594   virtual void OnPaint()
01595   {
01596     this->DrawWidgets();
01597 
01598     /* Draw the actions */
01599     int sel = this->sel_index;
01600     int y = 1;
01601     for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++, y += CLNWND_ROWSIZE) {
01602       if (this->action[i][0] == '\0') continue;
01603       if (this->proc[i] == NULL) continue;
01604 
01605       TextColour colour;
01606       if (sel-- == 0) { // Selected item, highlight it
01607         GfxFillRect(1, y, 150 - 2, y + CLNWND_ROWSIZE - 1, 0);
01608         colour = TC_WHITE;
01609       } else {
01610         colour = TC_BLACK;
01611       }
01612 
01613       DoDrawString(this->action[i], 4, y, colour);
01614     }
01615   }
01616 
01617   virtual void OnMouseLoop()
01618   {
01619     /* We selected an action */
01620     int index = (_cursor.pos.y - this->top) / CLNWND_ROWSIZE;
01621 
01622     if (_left_button_down) {
01623       if (index == -1 || index == this->sel_index) return;
01624 
01625       this->sel_index = index;
01626       this->SetDirty();
01627     } else {
01628       if (index >= 0 && _cursor.pos.y >= this->top) {
01629         HandleClientListPopupClick(index);
01630       }
01631 
01632       DeleteWindowById(WC_TOOLBAR_MENU, 0);
01633     }
01634   }
01635 };
01636 
01640 static void PopupClientList(int client_no, int x, int y)
01641 {
01642   DeleteWindowById(WC_TOOLBAR_MENU, 0);
01643 
01644   if (NetworkFindClientInfo(client_no) == NULL) return;
01645 
01646   new NetworkClientListPopupWindow(x, y, _client_list_popup_widgets, client_no);
01647 }
01648 
01652 struct NetworkClientListWindow : Window
01653 {
01654   int selected_item;
01655   int selected_y;
01656 
01657   NetworkClientListWindow(const WindowDesc *desc, WindowNumber window_number) :
01658       Window(desc, window_number),
01659       selected_item(-1),
01660       selected_y(0)
01661   {
01662     this->FindWindowPlacementAndResize(desc);
01663   }
01664 
01668   bool CheckClientListHeight()
01669   {
01670     int num = 0;
01671     const NetworkClientInfo *ci;
01672 
01673     /* Should be replaced with a loop through all clients */
01674     FOR_ALL_CLIENT_INFOS(ci) {
01675       if (ci->client_playas != COMPANY_INACTIVE_CLIENT) num++;
01676     }
01677 
01678     num *= CLNWND_ROWSIZE;
01679 
01680     /* If height is changed */
01681     if (this->height != CLNWND_OFFSET + num + 1) {
01682       /* XXX - magic unfortunately; (num + 2) has to be one bigger than heigh (num + 1) */
01683       this->SetDirty();
01684       this->widget[3].bottom = this->widget[3].top + num + 2;
01685       this->height = CLNWND_OFFSET + num + 1;
01686       this->SetDirty();
01687       return false;
01688     }
01689     return true;
01690   }
01691 
01692   virtual void OnPaint()
01693   {
01694     NetworkClientInfo *ci;
01695     int i = 0;
01696 
01697     /* Check if we need to reset the height */
01698     if (!this->CheckClientListHeight()) return;
01699 
01700     this->DrawWidgets();
01701 
01702     int y = CLNWND_OFFSET;
01703 
01704     FOR_ALL_CLIENT_INFOS(ci) {
01705       TextColour colour;
01706       if (this->selected_item == i++) { // Selected item, highlight it
01707         GfxFillRect(1, y, 248, y + CLNWND_ROWSIZE - 1, 0);
01708         colour = TC_WHITE;
01709       } else {
01710         colour = TC_BLACK;
01711       }
01712 
01713       if (ci->client_id == CLIENT_ID_SERVER) {
01714         DrawString(4, y, STR_NETWORK_SERVER, colour);
01715       } else {
01716         DrawString(4, y, STR_NETWORK_CLIENT, colour);
01717       }
01718 
01719       /* Filter out spectators */
01720       if (IsValidCompanyID(ci->client_playas)) DrawCompanyIcon(ci->client_playas, 64, y + 1);
01721 
01722       DoDrawString(ci->client_name, 81, y, colour);
01723 
01724       y += CLNWND_ROWSIZE;
01725     }
01726   }
01727 
01728   virtual void OnClick(Point pt, int widget)
01729   {
01730     /* Show the popup with option */
01731     if (this->selected_item != -1) {
01732       PopupClientList(this->selected_item, pt.x + this->left, pt.y + this->top);
01733     }
01734   }
01735 
01736   virtual void OnMouseOver(Point pt, int widget)
01737   {
01738     /* -1 means we left the current window */
01739     if (pt.y == -1) {
01740       this->selected_y = 0;
01741       this->selected_item = -1;
01742       this->SetDirty();
01743       return;
01744     }
01745     /* It did not change.. no update! */
01746     if (pt.y == this->selected_y) return;
01747 
01748     /* Find the new selected item (if any) */
01749     this->selected_y = pt.y;
01750     if (pt.y > CLNWND_OFFSET) {
01751       this->selected_item = (pt.y - CLNWND_OFFSET) / CLNWND_ROWSIZE;
01752     } else {
01753       this->selected_item = -1;
01754     }
01755 
01756     /* Repaint */
01757     this->SetDirty();
01758   }
01759 };
01760 
01761 void ShowClientList()
01762 {
01763   AllocateWindowDescFront<NetworkClientListWindow>(&_client_list_desc, 0);
01764 }
01765 
01766 
01767 static NetworkPasswordType pw_type;
01768 
01769 
01770 void ShowNetworkNeedPassword(NetworkPasswordType npt)
01771 {
01772   StringID caption;
01773 
01774   pw_type = npt;
01775   switch (npt) {
01776     default: NOT_REACHED();
01777     case NETWORK_GAME_PASSWORD:    caption = STR_NETWORK_NEED_GAME_PASSWORD_CAPTION; break;
01778     case NETWORK_COMPANY_PASSWORD: caption = STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION; break;
01779   }
01780   ShowQueryString(STR_EMPTY, caption, 20, 180, FindWindowById(WC_NETWORK_STATUS_WINDOW, 0), CS_ALPHANUMERAL, QSF_NONE);
01781 }
01782 
01783 /* Vars needed for the join-GUI */
01784 NetworkJoinStatus _network_join_status;
01785 uint8 _network_join_waiting;
01786 uint32 _network_join_bytes;
01787 uint32 _network_join_bytes_total;
01788 
01789 struct NetworkJoinStatusWindow : Window {
01790   NetworkJoinStatusWindow(const WindowDesc *desc) : Window(desc)
01791   {
01792     this->parent = FindWindowById(WC_NETWORK_WINDOW, 0);
01793     this->FindWindowPlacementAndResize(desc);
01794   }
01795 
01796   virtual void OnPaint()
01797   {
01798     uint8 progress; // used for progress bar
01799     this->DrawWidgets();
01800 
01801     DrawStringCentered(125, 35, STR_NETWORK_CONNECTING_1 + _network_join_status, TC_GREY);
01802     switch (_network_join_status) {
01803       case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING:
01804       case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
01805         progress = 10; // first two stages 10%
01806         break;
01807       case NETWORK_JOIN_STATUS_WAITING:
01808         SetDParam(0, _network_join_waiting);
01809         DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_WAITING, TC_GREY);
01810         progress = 15; // third stage is 15%
01811         break;
01812       case NETWORK_JOIN_STATUS_DOWNLOADING:
01813         SetDParam(0, _network_join_bytes);
01814         SetDParam(1, _network_join_bytes_total);
01815         DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_DOWNLOADING, TC_GREY);
01816         /* Fallthrough */
01817       default: // Waiting is 15%, so the resting receivement of map is maximum 70%
01818         progress = 15 + _network_join_bytes * (100 - 15) / _network_join_bytes_total;
01819     }
01820 
01821     /* Draw nice progress bar :) */
01822     DrawFrameRect(20, 18, (int)((this->width - 20) * progress / 100), 28, COLOUR_MAUVE, FR_NONE);
01823   }
01824 
01825   virtual void OnClick(Point pt, int widget)
01826   {
01827     if (widget == 2) { // Disconnect button
01828       NetworkDisconnect();
01829       SwitchToMode(SM_MENU);
01830       ShowNetworkGameWindow();
01831     }
01832   }
01833 
01834   virtual void OnQueryTextFinished(char *str)
01835   {
01836     if (StrEmpty(str)) {
01837       NetworkDisconnect();
01838       ShowNetworkGameWindow();
01839     } else {
01840       SEND_COMMAND(PACKET_CLIENT_PASSWORD)(pw_type, str);
01841     }
01842   }
01843 };
01844 
01845 static const Widget _network_join_status_window_widget[] = {
01846 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,      0,   249,     0,    13, STR_NETWORK_CONNECTING, STR_018C_WINDOW_TITLE_DRAG_THIS},
01847 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,      0,   249,    14,    84, 0x0,                    STR_NULL},
01848 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_WHITE,    75,   175,    69,    80, STR_NETWORK_DISCONNECT, STR_NULL},
01849 {   WIDGETS_END},
01850 };
01851 
01852 static const WindowDesc _network_join_status_window_desc(
01853   WDP_CENTER, WDP_CENTER, 250, 85, 250, 85,
01854   WC_NETWORK_STATUS_WINDOW, WC_NONE,
01855   WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_MODAL,
01856   _network_join_status_window_widget
01857 );
01858 
01859 void ShowJoinStatusWindow()
01860 {
01861   DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
01862   new NetworkJoinStatusWindow(&_network_join_status_window_desc);
01863 }
01864 
01865 
01867 enum NetworkCompanyPasswordWindowWidgets {
01868   NCPWW_CLOSE,                    
01869   NCPWW_CAPTION,                  
01870   NCPWW_BACKGROUND,               
01871   NCPWW_LABEL,                    
01872   NCPWW_PASSWORD,                 
01873   NCPWW_SAVE_AS_DEFAULT_PASSWORD, 
01874   NCPWW_CANCEL,                   
01875   NCPWW_OK,                       
01876 };
01877 
01878 struct NetworkCompanyPasswordWindow : public QueryStringBaseWindow {
01879   NetworkCompanyPasswordWindow(const WindowDesc *desc, Window *parent) : QueryStringBaseWindow(lengthof(_settings_client.network.default_company_pass), desc)
01880   {
01881     this->parent = parent;
01882     this->afilter = CS_ALPHANUMERAL;
01883     InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, 0);
01884     this->SetFocusedWidget(NCPWW_PASSWORD);
01885 
01886     this->FindWindowPlacementAndResize(desc);
01887   }
01888 
01889   void OnOk()
01890   {
01891     if (this->IsWidgetLowered(NCPWW_SAVE_AS_DEFAULT_PASSWORD)) {
01892       snprintf(_settings_client.network.default_company_pass, lengthof(_settings_client.network.default_company_pass), "%s", this->edit_str_buf);
01893     }
01894 
01895     /* empty password is a '*' because of console argument */
01896     if (StrEmpty(this->edit_str_buf)) snprintf(this->edit_str_buf, this->edit_str_size, "*");
01897     char *password = this->edit_str_buf;
01898     NetworkChangeCompanyPassword(1, &password);
01899   }
01900 
01901   virtual void OnPaint()
01902   {
01903     this->DrawWidgets();
01904     this->DrawEditBox(4);
01905   }
01906 
01907   virtual void OnClick(Point pt, int widget)
01908   {
01909     switch (widget) {
01910       case NCPWW_OK:
01911         this->OnOk();
01912 
01913       /* FALL THROUGH */
01914       case NCPWW_CANCEL:
01915         delete this;
01916         break;
01917 
01918       case NCPWW_SAVE_AS_DEFAULT_PASSWORD:
01919         this->ToggleWidgetLoweredState(NCPWW_SAVE_AS_DEFAULT_PASSWORD);
01920         this->SetDirty();
01921         break;
01922     }
01923   }
01924 
01925   virtual void OnMouseLoop()
01926   {
01927     this->HandleEditBox(4);
01928   }
01929 
01930   virtual EventState OnKeyPress(uint16 key, uint16 keycode)
01931   {
01932     EventState state = ES_NOT_HANDLED;
01933     switch (this->HandleEditBoxKey(4, key, keycode, state)) {
01934       default: break;
01935 
01936       case HEBR_CONFIRM:
01937         this->OnOk();
01938         /* FALL THROUGH */
01939 
01940       case HEBR_CANCEL:
01941         delete this;
01942         break;
01943     }
01944     return state;
01945   }
01946 
01947   virtual void OnOpenOSKWindow(int wid)
01948   {
01949     ShowOnScreenKeyboard(this, wid, NCPWW_CANCEL, NCPWW_OK);
01950   }
01951 };
01952 
01953 static const Widget _ncp_window_widgets[] = {
01954 {   WWT_CLOSEBOX,  RESIZE_NONE,  COLOUR_GREY,   0,  10,  0, 13, STR_00C5,                          STR_018B_CLOSE_WINDOW},
01955 {    WWT_CAPTION,  RESIZE_NONE,  COLOUR_GREY,  11, 299,  0, 13, STR_COMPANY_PASSWORD_CAPTION,      STR_018C_WINDOW_TITLE_DRAG_THIS},
01956 {      WWT_PANEL,  RESIZE_NONE,  COLOUR_GREY,   0, 299, 14, 50, 0x0,                               STR_NULL},
01957 {       WWT_TEXT,  RESIZE_NONE,  COLOUR_GREY,   5, 100, 19, 30, STR_COMPANY_PASSWORD,              STR_NULL},
01958 {    WWT_EDITBOX,  RESIZE_NONE,  COLOUR_GREY, 101, 294, 19, 30, STR_SET_COMPANY_PASSWORD,          STR_NULL},
01959 {    WWT_TEXTBTN,  RESIZE_NONE,  COLOUR_GREY, 101, 294, 35, 46, STR_MAKE_DEFAULT_COMPANY_PASSWORD, STR_MAKE_DEFAULT_COMPANY_PASSWORD_TIP},
01960 { WWT_PUSHTXTBTN,  RESIZE_NONE,  COLOUR_GREY,   0, 149, 51, 62, STR_012E_CANCEL,                   STR_COMPANY_PASSWORD_CANCEL},
01961 { WWT_PUSHTXTBTN,  RESIZE_NONE,  COLOUR_GREY, 150, 299, 51, 62, STR_012F_OK,                       STR_COMPANY_PASSWORD_OK},
01962 {   WIDGETS_END},
01963 };
01964 
01965 static const WindowDesc _ncp_window_desc(
01966   WDP_AUTO, WDP_AUTO, 300, 63, 300, 63,
01967   WC_COMPANY_PASSWORD_WINDOW, WC_NONE,
01968   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
01969   _ncp_window_widgets
01970 );
01971 
01972 void ShowNetworkCompanyPasswordWindow(Window *parent)
01973 {
01974   DeleteWindowById(WC_COMPANY_PASSWORD_WINDOW, 0);
01975 
01976   new NetworkCompanyPasswordWindow(&_ncp_window_desc, parent);
01977 }
01978 
01979 #endif /* ENABLE_NETWORK */

Generated on Wed Jul 15 20:35:59 2009 for OpenTTD by  doxygen 1.5.6