network_gui.cpp

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

Generated on Mon Mar 9 23:33:48 2009 for openttd by  doxygen 1.5.6