00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #ifdef ENABLE_NETWORK
00013 #include "../stdafx.h"
00014 #include "../strings_func.h"
00015 #include "../date_func.h"
00016 #include "../fios.h"
00017 #include "network_client.h"
00018 #include "network_gui.h"
00019 #include "network_gamelist.h"
00020 #include "network.h"
00021 #include "network_base.h"
00022 #include "network_content.h"
00023 #include "../gui.h"
00024 #include "network_udp.h"
00025 #include "../window_func.h"
00026 #include "../gfx_func.h"
00027 #include "../widgets/dropdown_func.h"
00028 #include "../querystring_gui.h"
00029 #include "../sortlist_type.h"
00030 #include "../company_func.h"
00031 #include "../core/geometry_func.hpp"
00032 #include "../genworld.h"
00033 #include "../map_type.h"
00034
00035 #include "../widgets/network_widget.h"
00036
00037 #include "table/strings.h"
00038 #include "../table/sprites.h"
00039
00040 #include "../stringfilter_type.h"
00041
00042
00043 static void ShowNetworkStartServerWindow();
00044 static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
00045
00046 static const StringID _connection_types_dropdown[] = {
00047 STR_NETWORK_START_SERVER_LAN_INTERNET,
00048 STR_NETWORK_START_SERVER_INTERNET_ADVERTISE,
00049 INVALID_STRING_ID
00050 };
00051
00052 static const StringID _lan_internet_types_dropdown[] = {
00053 STR_NETWORK_SERVER_LIST_LAN,
00054 STR_NETWORK_SERVER_LIST_INTERNET,
00055 INVALID_STRING_ID
00056 };
00057
00058 static StringID _language_dropdown[NETLANG_COUNT + 1] = {STR_NULL};
00059
00060 void SortNetworkLanguages()
00061 {
00062
00063 if (_language_dropdown[0] == STR_NULL) {
00064 for (int i = 0; i < NETLANG_COUNT; i++) _language_dropdown[i] = STR_NETWORK_LANG_ANY + i;
00065 _language_dropdown[NETLANG_COUNT] = INVALID_STRING_ID;
00066 }
00067
00068
00069 QSortT(_language_dropdown + 1, NETLANG_COUNT - 1, &StringIDSorter);
00070 }
00071
00076 void UpdateNetworkGameWindow()
00077 {
00078 InvalidateWindowData(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME, 0);
00079 }
00080
00081 typedef GUIList<NetworkGameList*, StringFilter&> GUIGameServerList;
00082 typedef uint16 ServerListPosition;
00083 static const ServerListPosition SLP_INVALID = 0xFFFF;
00084
00086 class NWidgetServerListHeader : public NWidgetContainer {
00087 static const uint MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER = 150;
00088 bool visible[6];
00089 public:
00090 NWidgetServerListHeader() : NWidgetContainer(NWID_HORIZONTAL)
00091 {
00092 NWidgetLeaf *leaf = new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NAME, STR_NETWORK_SERVER_LIST_GAME_NAME, STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP);
00093 leaf->SetResize(1, 0);
00094 leaf->SetFill(1, 0);
00095 this->Add(leaf);
00096
00097 this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CLIENTS, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP));
00098 this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_MAPSIZE, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP));
00099 this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_DATE, STR_NETWORK_SERVER_LIST_DATE_CAPTION, STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP));
00100 this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_YEARS, STR_NETWORK_SERVER_LIST_YEARS_CAPTION, STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP));
00101
00102 leaf = new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_INFO, STR_EMPTY, STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP);
00103 leaf->SetMinimalSize(40, 12);
00104 leaf->SetFill(0, 1);
00105 this->Add(leaf);
00106
00107
00108 this->visible[0] = true;
00109 *lastof(this->visible) = true;
00110 }
00111
00112 void SetupSmallestSize(Window *w, bool init_array)
00113 {
00114
00115 w->nested_array[WID_NG_HEADER] = this;
00116
00117 this->smallest_y = 0;
00118 this->fill_x = 1;
00119 this->fill_y = 0;
00120 this->resize_x = 1;
00121 this->resize_y = 0;
00122
00123
00124 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
00125 child_wid->SetupSmallestSize(w, init_array);
00126 this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom);
00127 }
00128
00129
00130 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
00131 child_wid->current_x = child_wid->smallest_x;
00132 child_wid->current_y = this->smallest_y;
00133 }
00134
00135 this->smallest_x = this->head->smallest_x + this->tail->smallest_x;
00136 }
00137
00138 void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
00139 {
00140 assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
00141
00142 this->pos_x = x;
00143 this->pos_y = y;
00144 this->current_x = given_width;
00145 this->current_y = given_height;
00146
00147 given_width -= this->tail->smallest_x;
00148 NWidgetBase *child_wid = this->head->next;
00149
00150 for (uint i = 1; i < lengthof(this->visible) - 1; i++) {
00151 if (given_width > MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER + child_wid->smallest_x && this->visible[i - 1]) {
00152 this->visible[i] = true;
00153 given_width -= child_wid->smallest_x;
00154 } else {
00155 this->visible[i] = false;
00156 }
00157 child_wid = child_wid->next;
00158 }
00159
00160
00161 this->head->current_x = given_width;
00162
00163
00164 uint position = 0;
00165 uint i = rtl ? lengthof(this->visible) - 1 : 0;
00166 child_wid = rtl ? this->tail : this->head;
00167 while (child_wid != NULL) {
00168 if (this->visible[i]) {
00169 child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl);
00170 position += child_wid->current_x;
00171 }
00172
00173 child_wid = rtl ? child_wid->prev : child_wid->next;
00174 i += rtl ? -1 : 1;
00175 }
00176 }
00177
00178 void Draw(const Window *w)
00179 {
00180 int i = 0;
00181 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
00182 if (!this->visible[i++]) continue;
00183
00184 child_wid->Draw(w);
00185 }
00186 }
00187
00188 NWidgetCore *GetWidgetFromPos(int x, int y)
00189 {
00190 if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
00191
00192 int i = 0;
00193 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
00194 if (!this->visible[i++]) continue;
00195 NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y);
00196 if (nwid != NULL) return nwid;
00197 }
00198 return NULL;
00199 }
00200
00206 bool IsWidgetVisible(NetworkGameWidgets widget) const
00207 {
00208 assert((uint)(widget - WID_NG_NAME) < lengthof(this->visible));
00209 return this->visible[widget - WID_NG_NAME];
00210 }
00211 };
00212
00213 class NetworkGameWindow : public Window {
00214 protected:
00215
00216 static Listing last_sorting;
00217
00218
00219 static GUIGameServerList::SortFunction * const sorter_funcs[];
00220 static GUIGameServerList::FilterFunction * const filter_funcs[];
00221
00222 NetworkGameList *server;
00223 NetworkGameList *last_joined;
00224 GUIGameServerList servers;
00225 ServerListPosition list_pos;
00226 Scrollbar *vscroll;
00227 QueryString name_editbox;
00228 QueryString filter_editbox;
00229
00235 void BuildGUINetworkGameList()
00236 {
00237 if (!this->servers.NeedRebuild()) return;
00238
00239
00240 this->servers.Clear();
00241
00242 for (NetworkGameList *ngl = _network_game_list; ngl != NULL; ngl = ngl->next) {
00243 *this->servers.Append() = ngl;
00244 }
00245
00246
00247 StringFilter sf;
00248 sf.SetFilterTerm(this->filter_editbox.text.buf);
00249
00250 if (!sf.IsEmpty()) {
00251 this->servers.SetFilterState(true);
00252 this->servers.Filter(sf);
00253 } else {
00254 this->servers.SetFilterState(false);
00255 }
00256
00257 this->servers.Compact();
00258 this->servers.RebuildDone();
00259 this->vscroll->SetCount(this->servers.Length());
00260
00261
00262 this->servers.Sort();
00263 this->UpdateListPos();
00264 }
00265
00274 static const char *SkipGarbage(const char *str)
00275 {
00276 while (*str != '\0' && (*str < 'A' || IsInsideMM(*str, '[', '`' + 1) || IsInsideMM(*str, '{', '~' + 1))) str++;
00277 return str;
00278 }
00279
00281 static int CDECL NGameNameSorter(NetworkGameList * const *a, NetworkGameList * const *b)
00282 {
00283 int r = strnatcmp(SkipGarbage((*a)->info.server_name), SkipGarbage((*b)->info.server_name));
00284 return r == 0 ? (*a)->address.CompareTo((*b)->address) : r;
00285 }
00286
00292 static int CDECL NGameClientSorter(NetworkGameList * const *a, NetworkGameList * const *b)
00293 {
00294
00295 int r = (*a)->info.clients_on - (*b)->info.clients_on;
00296
00297 if (r == 0) r = (*a)->info.clients_max - (*b)->info.clients_max;
00298 if (r == 0) r = NGameNameSorter(a, b);
00299
00300 return r;
00301 }
00302
00304 static int CDECL NGameMapSizeSorter(NetworkGameList * const *a, NetworkGameList * const *b)
00305 {
00306
00307 int r = ((*a)->info.map_height) * ((*a)->info.map_width) - ((*b)->info.map_height) * ((*b)->info.map_width);
00308
00309 if (r == 0) r = (*a)->info.map_width - (*b)->info.map_width;
00310 return (r != 0) ? r : NGameClientSorter(a, b);
00311 }
00312
00314 static int CDECL NGameDateSorter(NetworkGameList * const *a, NetworkGameList * const *b)
00315 {
00316 int r = (*a)->info.game_date - (*b)->info.game_date;
00317 return (r != 0) ? r : NGameClientSorter(a, b);
00318 }
00319
00321 static int CDECL NGameYearsSorter(NetworkGameList * const *a, NetworkGameList * const *b)
00322 {
00323 int r = (*a)->info.game_date - (*a)->info.start_date - (*b)->info.game_date + (*b)->info.start_date;
00324 return (r != 0) ? r : NGameDateSorter(a, b);
00325 }
00326
00331 static int CDECL NGameAllowedSorter(NetworkGameList * const *a, NetworkGameList * const *b)
00332 {
00333
00334 int r = StrEmpty((*a)->info.server_revision) - StrEmpty((*b)->info.server_revision);
00335
00336
00337 if (r == 0) r = (*b)->info.version_compatible - (*a)->info.version_compatible;
00338
00339 if (r == 0) r = (*b)->info.compatible - (*a)->info.compatible;
00340
00341 if (r == 0) r = (*a)->info.use_password - (*b)->info.use_password;
00342
00343 if (r == 0) r = -NGameClientSorter(a, b);
00344
00345 return r;
00346 }
00347
00349 void SortNetworkGameList()
00350 {
00351 if (this->servers.Sort()) this->UpdateListPos();
00352 }
00353
00355 void UpdateListPos()
00356 {
00357 this->list_pos = SLP_INVALID;
00358 for (uint i = 0; i != this->servers.Length(); i++) {
00359 if (this->servers[i] == this->server) {
00360 this->list_pos = i;
00361 break;
00362 }
00363 }
00364 }
00365
00366 static bool CDECL NGameSearchFilter(NetworkGameList * const *item, StringFilter &sf)
00367 {
00368 assert(item != NULL);
00369 assert((*item) != NULL);
00370
00371 sf.ResetState();
00372 sf.AddLine((*item)->info.server_name);
00373 return sf.GetState();
00374 }
00375
00382 void DrawServerLine(const NetworkGameList *cur_item, uint y, bool highlight) const
00383 {
00384 const NWidgetBase *nwi_name = this->GetWidget<NWidgetBase>(WID_NG_NAME);
00385 const NWidgetBase *nwi_info = this->GetWidget<NWidgetBase>(WID_NG_INFO);
00386
00387
00388 if (highlight) GfxFillRect(nwi_name->pos_x + 1, y - 2, nwi_info->pos_x + nwi_info->current_x - 2, y + FONT_HEIGHT_NORMAL - 1, PC_GREY);
00389
00390 DrawString(nwi_name->pos_x + WD_FRAMERECT_LEFT, nwi_name->pos_x + nwi_name->current_x - WD_FRAMERECT_RIGHT, y, cur_item->info.server_name, TC_BLACK);
00391
00392
00393 if (cur_item->online) {
00394 const NWidgetServerListHeader *nwi_header = this->GetWidget<NWidgetServerListHeader>(WID_NG_HEADER);
00395
00396 if (nwi_header->IsWidgetVisible(WID_NG_CLIENTS)) {
00397 const NWidgetBase *nwi_clients = this->GetWidget<NWidgetBase>(WID_NG_CLIENTS);
00398 SetDParam(0, cur_item->info.clients_on);
00399 SetDParam(1, cur_item->info.clients_max);
00400 SetDParam(2, cur_item->info.companies_on);
00401 SetDParam(3, cur_item->info.companies_max);
00402 DrawString(nwi_clients->pos_x, nwi_clients->pos_x + nwi_clients->current_x - 1, y, STR_NETWORK_SERVER_LIST_GENERAL_ONLINE, TC_FROMSTRING, SA_HOR_CENTER);
00403 }
00404
00405 if (nwi_header->IsWidgetVisible(WID_NG_MAPSIZE)) {
00406
00407 const NWidgetBase *nwi_mapsize = this->GetWidget<NWidgetBase>(WID_NG_MAPSIZE);
00408 SetDParam(0, cur_item->info.map_width);
00409 SetDParam(1, cur_item->info.map_height);
00410 DrawString(nwi_mapsize->pos_x, nwi_mapsize->pos_x + nwi_mapsize->current_x - 1, y, STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT, TC_FROMSTRING, SA_HOR_CENTER);
00411 }
00412
00413 if (nwi_header->IsWidgetVisible(WID_NG_DATE)) {
00414
00415 const NWidgetBase *nwi_date = this->GetWidget<NWidgetBase>(WID_NG_DATE);
00416 YearMonthDay ymd;
00417 ConvertDateToYMD(cur_item->info.game_date, &ymd);
00418 SetDParam(0, ymd.year);
00419 DrawString(nwi_date->pos_x, nwi_date->pos_x + nwi_date->current_x - 1, y, STR_JUST_INT, TC_BLACK, SA_HOR_CENTER);
00420 }
00421
00422 if (nwi_header->IsWidgetVisible(WID_NG_YEARS)) {
00423
00424 const NWidgetBase *nwi_years = this->GetWidget<NWidgetBase>(WID_NG_YEARS);
00425 YearMonthDay ymd_cur, ymd_start;
00426 ConvertDateToYMD(cur_item->info.game_date, &ymd_cur);
00427 ConvertDateToYMD(cur_item->info.start_date, &ymd_start);
00428 SetDParam(0, ymd_cur.year - ymd_start.year);
00429 DrawString(nwi_years->pos_x, nwi_years->pos_x + nwi_years->current_x - 1, y, STR_JUST_INT, TC_BLACK, SA_HOR_CENTER);
00430 }
00431
00432
00433 y += (FONT_HEIGHT_NORMAL - 10) / 2;
00434
00435
00436 if (cur_item->info.use_password) DrawSprite(SPR_LOCK, PAL_NONE, nwi_info->pos_x + 5, y - 1);
00437
00438
00439 DrawSprite(SPR_BLOT, (cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED)), nwi_info->pos_x + 15, y);
00440
00441
00442 DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, PAL_NONE, nwi_info->pos_x + 25, y);
00443 }
00444 }
00445
00453 void ScrollToSelectedServer()
00454 {
00455 if (this->list_pos == SLP_INVALID) return;
00456 this->vscroll->ScrollTowards(this->list_pos);
00457 }
00458
00459 public:
00460 NetworkGameWindow(const WindowDesc *desc) : name_editbox(NETWORK_CLIENT_NAME_LENGTH), filter_editbox(120)
00461 {
00462 this->list_pos = SLP_INVALID;
00463 this->server = NULL;
00464
00465 this->CreateNestedTree(desc);
00466 this->vscroll = this->GetScrollbar(WID_NG_SCROLLBAR);
00467 this->FinishInitNested(desc, WN_NETWORK_WINDOW_GAME);
00468
00469 this->querystrings[WID_NG_CLIENT] = &this->name_editbox;
00470 this->name_editbox.text.Assign(_settings_client.network.client_name);
00471 this->name_editbox.afilter = CS_ALPHANUMERAL;
00472
00473 this->querystrings[WID_NG_FILTER] = &this->filter_editbox;
00474 this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
00475 this->SetFocusedWidget(WID_NG_FILTER);
00476
00477 this->last_joined = NetworkGameListAddItem(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
00478 this->server = this->last_joined;
00479 if (this->last_joined != NULL) NetworkUDPQueryServer(this->last_joined->address);
00480
00481 this->servers.SetListing(this->last_sorting);
00482 this->servers.SetSortFuncs(this->sorter_funcs);
00483 this->servers.SetFilterFuncs(this->filter_funcs);
00484 this->servers.ForceRebuild();
00485 }
00486
00487 ~NetworkGameWindow()
00488 {
00489 this->last_sorting = this->servers.GetListing();
00490 }
00491
00492 virtual void SetStringParameters(int widget) const
00493 {
00494 switch (widget) {
00495 case WID_NG_CONN_BTN:
00496 SetDParam(0, _lan_internet_types_dropdown[_settings_client.network.lan_internet]);
00497 break;
00498 }
00499 }
00500
00501 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00502 {
00503 switch (widget) {
00504 case WID_NG_CONN_BTN:
00505 *size = maxdim(GetStringBoundingBox(_lan_internet_types_dropdown[0]), GetStringBoundingBox(_lan_internet_types_dropdown[1]));
00506 size->width += padding.width;
00507 size->height += padding.height;
00508 break;
00509
00510 case WID_NG_MATRIX:
00511 resize->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
00512 size->height = 10 * resize->height;
00513 break;
00514
00515 case WID_NG_LASTJOINED:
00516 size->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
00517 break;
00518
00519 case WID_NG_LASTJOINED_SPACER:
00520 size->width = NWidgetScrollbar::GetVerticalDimension().width;
00521 break;
00522
00523 case WID_NG_NAME:
00524 size->width += 2 * WD_SORTBUTTON_ARROW_WIDTH;
00525 break;
00526
00527 case WID_NG_CLIENTS:
00528 size->width += 2 * WD_SORTBUTTON_ARROW_WIDTH;
00529 SetDParamMaxValue(0, MAX_CLIENTS);
00530 SetDParamMaxValue(1, MAX_CLIENTS);
00531 SetDParamMaxValue(2, MAX_COMPANIES);
00532 SetDParamMaxValue(3, MAX_COMPANIES);
00533 *size = maxdim(*size, GetStringBoundingBox(STR_NETWORK_SERVER_LIST_GENERAL_ONLINE));
00534 break;
00535
00536 case WID_NG_MAPSIZE:
00537 size->width += 2 * WD_SORTBUTTON_ARROW_WIDTH;
00538 SetDParamMaxValue(0, MAX_MAP_SIZE);
00539 SetDParamMaxValue(1, MAX_MAP_SIZE);
00540 *size = maxdim(*size, GetStringBoundingBox(STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT));
00541 break;
00542
00543 case WID_NG_DATE:
00544 case WID_NG_YEARS:
00545 size->width += 2 * WD_SORTBUTTON_ARROW_WIDTH;
00546 SetDParamMaxValue(0, 5);
00547 *size = maxdim(*size, GetStringBoundingBox(STR_JUST_INT));
00548 break;
00549
00550 case WID_NG_DETAILS_SPACER:
00551 size->height = 20 + 12 * FONT_HEIGHT_NORMAL;
00552 break;
00553 }
00554 }
00555
00556 virtual void DrawWidget(const Rect &r, int widget) const
00557 {
00558 switch (widget) {
00559 case WID_NG_MATRIX: {
00560 uint16 y = r.top + WD_MATRIX_TOP;
00561
00562 const int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (int)this->servers.Length());
00563
00564 for (int i = this->vscroll->GetPosition(); i < max; ++i) {
00565 const NetworkGameList *ngl = this->servers[i];
00566 this->DrawServerLine(ngl, y, ngl == this->server);
00567 y += this->resize.step_height;
00568 }
00569 break;
00570 }
00571
00572 case WID_NG_LASTJOINED:
00573
00574 if (this->last_joined != NULL) this->DrawServerLine(this->last_joined, r.top + WD_MATRIX_TOP, this->last_joined == this->server);
00575 break;
00576
00577 case WID_NG_DETAILS:
00578 this->DrawDetails(r);
00579 break;
00580
00581 case WID_NG_NAME:
00582 case WID_NG_CLIENTS:
00583 case WID_NG_MAPSIZE:
00584 case WID_NG_DATE:
00585 case WID_NG_YEARS:
00586 case WID_NG_INFO:
00587 if (widget - WID_NG_NAME == this->servers.SortType()) this->DrawSortButtonState(widget, this->servers.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
00588 break;
00589 }
00590 }
00591
00592
00593 virtual void OnPaint()
00594 {
00595 if (this->servers.NeedRebuild()) {
00596 this->BuildGUINetworkGameList();
00597 }
00598 if (this->servers.NeedResort()) {
00599 this->SortNetworkGameList();
00600 }
00601
00602 NetworkGameList *sel = this->server;
00603
00604 this->SetWidgetDisabledState(WID_NG_REFRESH, sel == NULL);
00605
00606 this->SetWidgetDisabledState(WID_NG_JOIN, sel == NULL ||
00607 !sel->online ||
00608 sel->info.clients_on >= sel->info.clients_max ||
00609 !sel->info.compatible);
00610
00611
00612 this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == NULL || !sel->online || sel->info.grfconfig == NULL);
00613 this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_MISSING_SEL)->SetDisplayedPlane(sel == NULL || !sel->online || sel->info.grfconfig == NULL || !sel->info.version_compatible || sel->info.compatible);
00614
00615 this->DrawWidgets();
00616 }
00617
00618 void DrawDetails(const Rect &r) const
00619 {
00620 NetworkGameList *sel = this->server;
00621
00622 const int detail_height = 6 + 8 + 6 + 3 * FONT_HEIGHT_NORMAL;
00623
00624
00625 GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.top + detail_height - 1, PC_DARK_BLUE);
00626 if (sel == NULL) {
00627 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 4 + FONT_HEIGHT_NORMAL, STR_NETWORK_SERVER_LIST_GAME_INFO, TC_FROMSTRING, SA_HOR_CENTER);
00628 } else if (!sel->online) {
00629 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 4 + FONT_HEIGHT_NORMAL, sel->info.server_name, TC_ORANGE, SA_HOR_CENTER);
00630
00631 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + detail_height + 4, STR_NETWORK_SERVER_LIST_SERVER_OFFLINE, TC_FROMSTRING, SA_HOR_CENTER);
00632 } else {
00633
00634 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6, STR_NETWORK_SERVER_LIST_GAME_INFO, TC_FROMSTRING, SA_HOR_CENTER);
00635 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 4 + FONT_HEIGHT_NORMAL, sel->info.server_name, TC_ORANGE, SA_HOR_CENTER);
00636 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 8 + 2 * FONT_HEIGHT_NORMAL, sel->info.map_name, TC_BLACK, SA_HOR_CENTER);
00637
00638 uint16 y = r.top + detail_height + 4;
00639
00640 SetDParam(0, sel->info.clients_on);
00641 SetDParam(1, sel->info.clients_max);
00642 SetDParam(2, sel->info.companies_on);
00643 SetDParam(3, sel->info.companies_max);
00644 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CLIENTS);
00645 y += FONT_HEIGHT_NORMAL;
00646
00647 SetDParam(0, STR_NETWORK_LANG_ANY + sel->info.server_lang);
00648 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_LANGUAGE);
00649 y += FONT_HEIGHT_NORMAL;
00650
00651 SetDParam(0, STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE + sel->info.map_set);
00652 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_LANDSCAPE);
00653 y += FONT_HEIGHT_NORMAL;
00654
00655 SetDParam(0, sel->info.map_width);
00656 SetDParam(1, sel->info.map_height);
00657 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_MAP_SIZE);
00658 y += FONT_HEIGHT_NORMAL;
00659
00660 SetDParamStr(0, sel->info.server_revision);
00661 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_VERSION);
00662 y += FONT_HEIGHT_NORMAL;
00663
00664 SetDParamStr(0, sel->address.GetAddressAsString());
00665 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_ADDRESS);
00666 y += FONT_HEIGHT_NORMAL;
00667
00668 SetDParam(0, sel->info.start_date);
00669 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_START_DATE);
00670 y += FONT_HEIGHT_NORMAL;
00671
00672 SetDParam(0, sel->info.game_date);
00673 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CURRENT_DATE);
00674 y += FONT_HEIGHT_NORMAL;
00675
00676 y += WD_PAR_VSEP_NORMAL;
00677
00678 if (!sel->info.compatible) {
00679 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, sel->info.version_compatible ? STR_NETWORK_SERVER_LIST_GRF_MISMATCH : STR_NETWORK_SERVER_LIST_VERSION_MISMATCH, TC_FROMSTRING, SA_HOR_CENTER);
00680 } else if (sel->info.clients_on == sel->info.clients_max) {
00681
00682 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_FULL, TC_FROMSTRING, SA_HOR_CENTER);
00683 } else if (sel->info.use_password) {
00684 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_PASSWORD, TC_FROMSTRING, SA_HOR_CENTER);
00685 }
00686 }
00687 }
00688
00689 virtual void OnClick(Point pt, int widget, int click_count)
00690 {
00691 switch (widget) {
00692 case WID_NG_CANCEL:
00693 DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME);
00694 break;
00695
00696 case WID_NG_CONN_BTN:
00697 ShowDropDownMenu(this, _lan_internet_types_dropdown, _settings_client.network.lan_internet, WID_NG_CONN_BTN, 0, 0);
00698 break;
00699
00700 case WID_NG_NAME:
00701 case WID_NG_CLIENTS:
00702 case WID_NG_MAPSIZE:
00703 case WID_NG_DATE:
00704 case WID_NG_YEARS:
00705 case WID_NG_INFO:
00706 if (this->servers.SortType() == widget - WID_NG_NAME) {
00707 this->servers.ToggleSortOrder();
00708 if (this->list_pos != SLP_INVALID) this->list_pos = this->servers.Length() - this->list_pos - 1;
00709 } else {
00710 this->servers.SetSortType(widget - WID_NG_NAME);
00711 this->servers.ForceResort();
00712 this->SortNetworkGameList();
00713 }
00714 this->ScrollToSelectedServer();
00715 this->SetDirty();
00716 break;
00717
00718 case WID_NG_MATRIX: {
00719 uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NG_MATRIX);
00720 this->server = (id_v < this->servers.Length()) ? this->servers[id_v] : NULL;
00721 this->list_pos = (server == NULL) ? SLP_INVALID : id_v;
00722 this->SetDirty();
00723
00724
00725 if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
00726 break;
00727 }
00728
00729 case WID_NG_LASTJOINED: {
00730 if (this->last_joined != NULL) {
00731 this->server = this->last_joined;
00732
00733
00734 this->UpdateListPos();
00735 this->ScrollToSelectedServer();
00736 this->SetDirty();
00737
00738
00739 if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
00740 }
00741 break;
00742 }
00743
00744 case WID_NG_FIND:
00745 switch (_settings_client.network.lan_internet) {
00746 case 0: NetworkUDPSearchGame(); break;
00747 case 1: NetworkUDPQueryMasterServer(); break;
00748 }
00749 break;
00750
00751 case WID_NG_ADD:
00752 SetDParamStr(0, _settings_client.network.connect_to_ip);
00753 ShowQueryString(
00754 STR_JUST_RAW_STRING,
00755 STR_NETWORK_SERVER_LIST_ENTER_IP,
00756 NETWORK_HOSTNAME_LENGTH,
00757 this, CS_ALPHANUMERAL, QSF_ACCEPT_UNCHANGED);
00758 break;
00759
00760 case WID_NG_START:
00761 ShowNetworkStartServerWindow();
00762 break;
00763
00764 case WID_NG_JOIN:
00765 if (this->server != NULL) {
00766 snprintf(_settings_client.network.last_host, sizeof(_settings_client.network.last_host), "%s", this->server->address.GetHostname());
00767 _settings_client.network.last_port = this->server->address.GetPort();
00768 ShowNetworkLobbyWindow(this->server);
00769 }
00770 break;
00771
00772 case WID_NG_REFRESH:
00773 if (this->server != NULL) NetworkUDPQueryServer(this->server->address);
00774 break;
00775
00776 case WID_NG_NEWGRF:
00777 if (this->server != NULL) ShowNewGRFSettings(false, false, false, &this->server->info.grfconfig);
00778 break;
00779
00780 case WID_NG_NEWGRF_MISSING:
00781 if (this->server != NULL) ShowMissingContentWindow(this->server->info.grfconfig);
00782 break;
00783 }
00784 }
00785
00786 virtual void OnDropdownSelect(int widget, int index)
00787 {
00788 switch (widget) {
00789 case WID_NG_CONN_BTN:
00790 _settings_client.network.lan_internet = index;
00791 break;
00792
00793 default:
00794 NOT_REACHED();
00795 }
00796
00797 this->SetDirty();
00798 }
00799
00805 virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
00806 {
00807 this->servers.ForceRebuild();
00808 this->SetDirty();
00809 }
00810
00811 virtual EventState OnKeyPress(uint16 key, uint16 keycode)
00812 {
00813 EventState state = ES_NOT_HANDLED;
00814
00815
00816 if (keycode == WKC_UP || keycode == WKC_DOWN || keycode == WKC_PAGEUP || keycode == WKC_PAGEDOWN || keycode == WKC_HOME || keycode == WKC_END) {
00817 if (this->servers.Length() == 0) return ES_HANDLED;
00818 switch (keycode) {
00819 case WKC_UP:
00820
00821 if (this->list_pos == SLP_INVALID) return ES_HANDLED;
00822 if (this->list_pos > 0) this->list_pos--;
00823 break;
00824 case WKC_DOWN:
00825
00826 if (this->list_pos == SLP_INVALID) return ES_HANDLED;
00827 if (this->list_pos < this->servers.Length() - 1) this->list_pos++;
00828 break;
00829 case WKC_PAGEUP:
00830
00831 if (this->list_pos == SLP_INVALID) return ES_HANDLED;
00832 this->list_pos = (this->list_pos < this->vscroll->GetCapacity()) ? 0 : this->list_pos - this->vscroll->GetCapacity();
00833 break;
00834 case WKC_PAGEDOWN:
00835
00836 if (this->list_pos == SLP_INVALID) return ES_HANDLED;
00837 this->list_pos = min(this->list_pos + this->vscroll->GetCapacity(), (int)this->servers.Length() - 1);
00838 break;
00839 case WKC_HOME:
00840
00841 this->list_pos = 0;
00842 break;
00843 case WKC_END:
00844
00845 this->list_pos = this->servers.Length() - 1;
00846 break;
00847 default: break;
00848 }
00849
00850 this->server = this->servers[this->list_pos];
00851
00852
00853 this->ScrollToSelectedServer();
00854
00855
00856 this->SetDirty();
00857 return ES_HANDLED;
00858 }
00859
00860 if (this->server != NULL) {
00861 if (keycode == WKC_DELETE) {
00862 NetworkGameListRemoveItem(this->server);
00863 if (this->server == this->last_joined) this->last_joined = NULL;
00864 this->server = NULL;
00865 this->list_pos = SLP_INVALID;
00866 }
00867 }
00868
00869 return state;
00870 }
00871
00872 virtual void OnEditboxChanged(int wid)
00873 {
00874 switch (wid) {
00875 case WID_NG_FILTER: {
00876 this->servers.ForceRebuild();
00877 this->BuildGUINetworkGameList();
00878 this->ScrollToSelectedServer();
00879 this->SetDirty();
00880 break;
00881 }
00882
00883 case WID_NG_CLIENT:
00884
00885 if (!StrEmpty(this->name_editbox.text.buf) && this->name_editbox.text.buf[0] != ' ') {
00886 strecpy(_settings_client.network.client_name, this->name_editbox.text.buf, lastof(_settings_client.network.client_name));
00887 } else {
00888 strecpy(_settings_client.network.client_name, "Player", lastof(_settings_client.network.client_name));
00889 }
00890 break;
00891 }
00892 }
00893
00894 virtual void OnQueryTextFinished(char *str)
00895 {
00896 if (!StrEmpty(str)) NetworkAddServer(str);
00897 }
00898
00899 virtual void OnResize()
00900 {
00901 this->vscroll->SetCapacityFromWidget(this, WID_NG_MATRIX);
00902 this->GetWidget<NWidgetCore>(WID_NG_MATRIX)->widget_data = (this->vscroll->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START);
00903 }
00904
00905 virtual void OnTick()
00906 {
00907 NetworkGameListRequery();
00908 }
00909 };
00910
00911 Listing NetworkGameWindow::last_sorting = {false, 5};
00912 GUIGameServerList::SortFunction * const NetworkGameWindow::sorter_funcs[] = {
00913 &NGameNameSorter,
00914 &NGameClientSorter,
00915 &NGameMapSizeSorter,
00916 &NGameDateSorter,
00917 &NGameYearsSorter,
00918 &NGameAllowedSorter
00919 };
00920
00921 GUIGameServerList::FilterFunction * const NetworkGameWindow::filter_funcs[] = {
00922 &NGameSearchFilter
00923 };
00924
00925 static NWidgetBase *MakeResizableHeader(int *biggest_index)
00926 {
00927 *biggest_index = max<int>(*biggest_index, WID_NG_INFO);
00928 return new NWidgetServerListHeader();
00929 }
00930
00931 static const NWidgetPart _nested_network_game_widgets[] = {
00932
00933 NWidget(NWID_HORIZONTAL),
00934 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
00935 NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_SERVER_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00936 EndContainer(),
00937 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_MAIN),
00938 NWidget(NWID_VERTICAL), SetPIP(10, 7, 0),
00939 NWidget(NWID_HORIZONTAL), SetPIP(10, 7, 10),
00940
00941 NWidget(NWID_VERTICAL), SetPIP(0, 7, 0),
00942 NWidget(NWID_HORIZONTAL), SetPIP(0, 7, 0),
00943 NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_CONNECTION), SetDataTip(STR_NETWORK_SERVER_LIST_CONNECTION, STR_NULL),
00944 NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NG_CONN_BTN),
00945 SetDataTip(STR_BLACK_STRING, STR_NETWORK_SERVER_LIST_CONNECTION_TOOLTIP),
00946 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
00947 EndContainer(),
00948 NWidget(NWID_HORIZONTAL), SetPIP(0, 7, 0),
00949 NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_FILTER_LABEL), SetDataTip(STR_LIST_FILTER_TITLE, STR_NULL),
00950 NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_FILTER), SetMinimalSize(251, 12), SetFill(1, 0), SetResize(1, 0),
00951 SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
00952 EndContainer(),
00953 NWidget(NWID_HORIZONTAL),
00954 NWidget(NWID_VERTICAL),
00955 NWidgetFunction(MakeResizableHeader),
00956 NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NG_MATRIX), SetResize(1, 1), SetFill(1, 0),
00957 SetDataTip(0, STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT), SetScrollbar(WID_NG_SCROLLBAR),
00958 EndContainer(),
00959 NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NG_SCROLLBAR),
00960 EndContainer(),
00961 NWidget(NWID_VERTICAL),
00962 NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_LASTJOINED_LABEL), SetFill(1, 0),
00963 SetDataTip(STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER, STR_NULL), SetResize(1, 0),
00964 NWidget(NWID_HORIZONTAL),
00965 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_LASTJOINED), SetFill(1, 0), SetResize(1, 0),
00966 SetDataTip(0x0, STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST),
00967 EndContainer(),
00968 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NG_LASTJOINED_SPACER), SetFill(0, 0),
00969 EndContainer(),
00970 EndContainer(),
00971 EndContainer(),
00972
00973 NWidget(NWID_VERTICAL), SetPIP(0, 7, 0),
00974 NWidget(NWID_HORIZONTAL), SetPIP(0, 7, 0),
00975 NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_CLIENT_LABEL), SetDataTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME, STR_NULL),
00976 NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_CLIENT), SetMinimalSize(151, 12), SetFill(1, 0), SetResize(1, 0),
00977 SetDataTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE, STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP),
00978 EndContainer(),
00979 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_DETAILS),
00980 NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(5, 5, 5),
00981 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NG_DETAILS_SPACER), SetMinimalSize(140, 155), SetResize(0, 1), SetFill(1, 1),
00982 NWidget(NWID_HORIZONTAL, NC_NONE), SetPIP(5, 5, 5),
00983 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NG_NEWGRF_MISSING_SEL),
00984 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NEWGRF_MISSING), SetFill(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON, STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP),
00985 NWidget(NWID_SPACER), SetFill(1, 0),
00986 EndContainer(),
00987 EndContainer(),
00988 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(5, 5, 5),
00989 NWidget(NWID_SPACER), SetFill(1, 0),
00990 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NG_NEWGRF_SEL),
00991 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NEWGRF), SetFill(1, 0), SetDataTip(STR_INTRO_NEWGRF_SETTINGS, STR_NULL),
00992 NWidget(NWID_SPACER), SetFill(1, 0),
00993 EndContainer(),
00994 EndContainer(),
00995 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(5, 5, 5),
00996 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_JOIN), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_JOIN_GAME, STR_NULL),
00997 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_REFRESH), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_REFRESH, STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP),
00998 EndContainer(),
00999 EndContainer(),
01000 EndContainer(),
01001 EndContainer(),
01002 EndContainer(),
01003
01004 NWidget(NWID_HORIZONTAL),
01005 NWidget(NWID_VERTICAL),
01006 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 7, 4),
01007 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_FIND), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_FIND_SERVER, STR_NETWORK_SERVER_LIST_FIND_SERVER_TOOLTIP),
01008 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_ADD), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_ADD_SERVER, STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP),
01009 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_START), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_START_SERVER, STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP),
01010 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CANCEL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
01011 EndContainer(),
01012 NWidget(NWID_SPACER), SetMinimalSize(0, 6), SetResize(1, 0), SetFill(1, 0),
01013 EndContainer(),
01014 NWidget(NWID_VERTICAL),
01015 NWidget(NWID_SPACER), SetFill(0, 1),
01016 NWidget(WWT_RESIZEBOX, COLOUR_LIGHT_BLUE),
01017 EndContainer(),
01018 EndContainer(),
01019 EndContainer(),
01020 EndContainer(),
01021 };
01022
01023 static const WindowDesc _network_game_window_desc(
01024 WDP_CENTER, 1000, 730,
01025 WC_NETWORK_WINDOW, WC_NONE,
01026 0,
01027 _nested_network_game_widgets, lengthof(_nested_network_game_widgets)
01028 );
01029
01030 void ShowNetworkGameWindow()
01031 {
01032 static bool first = true;
01033 DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY);
01034 DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_START);
01035
01036
01037 if (first) {
01038 first = false;
01039
01040 for (char **iter = _network_host_list.Begin(); iter != _network_host_list.End(); iter++) {
01041 NetworkAddServer(*iter);
01042 }
01043 }
01044
01045 new NetworkGameWindow(&_network_game_window_desc);
01046 }
01047
01048 struct NetworkStartServerWindow : public Window {
01049 byte widget_id;
01050 QueryString name_editbox;
01051
01052 NetworkStartServerWindow(const WindowDesc *desc) : name_editbox(NETWORK_NAME_LENGTH)
01053 {
01054 this->InitNested(desc, WN_NETWORK_WINDOW_START);
01055
01056 this->querystrings[WID_NSS_GAMENAME] = &this->name_editbox;
01057 this->name_editbox.text.Assign(_settings_client.network.server_name);
01058
01059 this->name_editbox.afilter = CS_ALPHANUMERAL;
01060 this->SetFocusedWidget(WID_NSS_GAMENAME);
01061 }
01062
01063 virtual void SetStringParameters(int widget) const
01064 {
01065 switch (widget) {
01066 case WID_NSS_CONNTYPE_BTN:
01067 SetDParam(0, _connection_types_dropdown[_settings_client.network.server_advertise]);
01068 break;
01069
01070 case WID_NSS_CLIENTS_TXT:
01071 SetDParam(0, _settings_client.network.max_clients);
01072 break;
01073
01074 case WID_NSS_COMPANIES_TXT:
01075 SetDParam(0, _settings_client.network.max_companies);
01076 break;
01077
01078 case WID_NSS_SPECTATORS_TXT:
01079 SetDParam(0, _settings_client.network.max_spectators);
01080 break;
01081
01082 case WID_NSS_LANGUAGE_BTN:
01083 SetDParam(0, STR_NETWORK_LANG_ANY + _settings_client.network.server_lang);
01084 break;
01085 }
01086 }
01087
01088 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
01089 {
01090 switch (widget) {
01091 case WID_NSS_CONNTYPE_BTN:
01092 *size = maxdim(GetStringBoundingBox(_connection_types_dropdown[0]), GetStringBoundingBox(_connection_types_dropdown[1]));
01093 size->width += padding.width;
01094 size->height += padding.height;
01095 break;
01096 }
01097 }
01098
01099 virtual void DrawWidget(const Rect &r, int widget) const
01100 {
01101 switch (widget) {
01102 case WID_NSS_SETPWD:
01103
01104 if (!StrEmpty(_settings_client.network.server_password)) DrawString(r.right + WD_FRAMERECT_LEFT, this->width - WD_FRAMERECT_RIGHT, r.top, "*", TC_RED);
01105 }
01106 }
01107
01108 virtual void OnClick(Point pt, int widget, int click_count)
01109 {
01110 switch (widget) {
01111 case WID_NSS_CANCEL:
01112 ShowNetworkGameWindow();
01113 break;
01114
01115 case WID_NSS_SETPWD:
01116 this->widget_id = WID_NSS_SETPWD;
01117 SetDParamStr(0, _settings_client.network.server_password);
01118 ShowQueryString(STR_JUST_RAW_STRING, STR_NETWORK_START_SERVER_SET_PASSWORD, 20, this, CS_ALPHANUMERAL, QSF_NONE);
01119 break;
01120
01121 case WID_NSS_CONNTYPE_BTN:
01122 ShowDropDownMenu(this, _connection_types_dropdown, _settings_client.network.server_advertise, WID_NSS_CONNTYPE_BTN, 0, 0);
01123 break;
01124
01125 case WID_NSS_CLIENTS_BTND: case WID_NSS_CLIENTS_BTNU:
01126 case WID_NSS_COMPANIES_BTND: case WID_NSS_COMPANIES_BTNU:
01127 case WID_NSS_SPECTATORS_BTND: case WID_NSS_SPECTATORS_BTNU:
01128
01129 if (!(this->flags & WF_TIMEOUT) || this->timeout_timer <= 1) {
01130 this->HandleButtonClick(widget);
01131 this->SetDirty();
01132 switch (widget) {
01133 default: NOT_REACHED();
01134 case WID_NSS_CLIENTS_BTND: case WID_NSS_CLIENTS_BTNU:
01135 _settings_client.network.max_clients = Clamp(_settings_client.network.max_clients + widget - WID_NSS_CLIENTS_TXT, 2, MAX_CLIENTS);
01136 break;
01137 case WID_NSS_COMPANIES_BTND: case WID_NSS_COMPANIES_BTNU:
01138 _settings_client.network.max_companies = Clamp(_settings_client.network.max_companies + widget - WID_NSS_COMPANIES_TXT, 1, MAX_COMPANIES);
01139 break;
01140 case WID_NSS_SPECTATORS_BTND: case WID_NSS_SPECTATORS_BTNU:
01141 _settings_client.network.max_spectators = Clamp(_settings_client.network.max_spectators + widget - WID_NSS_SPECTATORS_TXT, 0, MAX_CLIENTS);
01142 break;
01143 }
01144 }
01145 _left_button_clicked = false;
01146 break;
01147
01148 case WID_NSS_CLIENTS_TXT:
01149 this->widget_id = WID_NSS_CLIENTS_TXT;
01150 SetDParam(0, _settings_client.network.max_clients);
01151 ShowQueryString(STR_JUST_INT, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS, 4, this, CS_NUMERAL, QSF_NONE);
01152 break;
01153
01154 case WID_NSS_COMPANIES_TXT:
01155 this->widget_id = WID_NSS_COMPANIES_TXT;
01156 SetDParam(0, _settings_client.network.max_companies);
01157 ShowQueryString(STR_JUST_INT, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES, 3, this, CS_NUMERAL, QSF_NONE);
01158 break;
01159
01160 case WID_NSS_SPECTATORS_TXT:
01161 this->widget_id = WID_NSS_SPECTATORS_TXT;
01162 SetDParam(0, _settings_client.network.max_spectators);
01163 ShowQueryString(STR_JUST_INT, STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS, 4, this, CS_NUMERAL, QSF_NONE);
01164 break;
01165
01166 case WID_NSS_LANGUAGE_BTN: {
01167 uint sel = 0;
01168 for (uint i = 0; i < lengthof(_language_dropdown) - 1; i++) {
01169 if (_language_dropdown[i] == STR_NETWORK_LANG_ANY + _settings_client.network.server_lang) {
01170 sel = i;
01171 break;
01172 }
01173 }
01174 ShowDropDownMenu(this, _language_dropdown, sel, WID_NSS_LANGUAGE_BTN, 0, 0);
01175 break;
01176 }
01177
01178 case WID_NSS_GENERATE_GAME:
01179 _is_network_server = true;
01180 if (_ctrl_pressed) {
01181 StartNewGameWithoutGUI(GENERATE_NEW_SEED);
01182 } else {
01183 ShowGenerateLandscape();
01184 }
01185 break;
01186
01187 case WID_NSS_LOAD_GAME:
01188 _is_network_server = true;
01189 ShowSaveLoadDialog(SLD_LOAD_GAME);
01190 break;
01191
01192 case WID_NSS_PLAY_SCENARIO:
01193 _is_network_server = true;
01194 ShowSaveLoadDialog(SLD_LOAD_SCENARIO);
01195 break;
01196
01197 case WID_NSS_PLAY_HEIGHTMAP:
01198 _is_network_server = true;
01199 ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP);
01200 break;
01201 }
01202 }
01203
01204 virtual void OnDropdownSelect(int widget, int index)
01205 {
01206 switch (widget) {
01207 case WID_NSS_CONNTYPE_BTN:
01208 _settings_client.network.server_advertise = (index != 0);
01209 break;
01210 case WID_NSS_LANGUAGE_BTN:
01211 _settings_client.network.server_lang = _language_dropdown[index] - STR_NETWORK_LANG_ANY;
01212 break;
01213 default:
01214 NOT_REACHED();
01215 }
01216
01217 this->SetDirty();
01218 }
01219
01220 virtual void OnEditboxChanged(int wid)
01221 {
01222 if (wid == WID_NSS_GAMENAME) {
01223 strecpy(_settings_client.network.server_name, this->name_editbox.text.buf, lastof(_settings_client.network.server_name));
01224 }
01225 }
01226
01227 virtual void OnTimeout()
01228 {
01229 static const int raise_widgets[] = {WID_NSS_CLIENTS_BTND, WID_NSS_CLIENTS_BTNU, WID_NSS_COMPANIES_BTND, WID_NSS_COMPANIES_BTNU, WID_NSS_SPECTATORS_BTND, WID_NSS_SPECTATORS_BTNU, WIDGET_LIST_END};
01230 for (const int *widget = raise_widgets; *widget != WIDGET_LIST_END; widget++) {
01231 if (this->IsWidgetLowered(*widget)) {
01232 this->RaiseWidget(*widget);
01233 this->SetWidgetDirty(*widget);
01234 }
01235 }
01236 }
01237
01238 virtual void OnQueryTextFinished(char *str)
01239 {
01240 if (str == NULL) return;
01241
01242 if (this->widget_id == WID_NSS_SETPWD) {
01243 strecpy(_settings_client.network.server_password, str, lastof(_settings_client.network.server_password));
01244 } else {
01245 int32 value = atoi(str);
01246 this->SetWidgetDirty(this->widget_id);
01247 switch (this->widget_id) {
01248 default: NOT_REACHED();
01249 case WID_NSS_CLIENTS_TXT: _settings_client.network.max_clients = Clamp(value, 2, MAX_CLIENTS); break;
01250 case WID_NSS_COMPANIES_TXT: _settings_client.network.max_companies = Clamp(value, 1, MAX_COMPANIES); break;
01251 case WID_NSS_SPECTATORS_TXT: _settings_client.network.max_spectators = Clamp(value, 0, MAX_CLIENTS); break;
01252 }
01253 }
01254
01255 this->SetDirty();
01256 }
01257 };
01258
01259 static const NWidgetPart _nested_network_start_server_window_widgets[] = {
01260 NWidget(NWID_HORIZONTAL),
01261 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
01262 NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_START_SERVER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01263 EndContainer(),
01264 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NSS_BACKGROUND),
01265 NWidget(NWID_VERTICAL), SetPIP(10, 6, 10),
01266 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 6, 10),
01267 NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
01268
01269 NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_GAMENAME_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME, STR_NULL),
01270 NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NSS_GAMENAME), SetMinimalSize(10, 12), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE, STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP),
01271 EndContainer(),
01272 EndContainer(),
01273
01274 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 6, 10),
01275 NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
01276 NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_CONNECTION, STR_NULL),
01277 NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_BTN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_SERVER_LIST_CONNECTION_TOOLTIP),
01278 EndContainer(),
01279 NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
01280 NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_LANGUAGE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN, STR_NULL),
01281 NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_LANGUAGE_BTN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP),
01282 EndContainer(),
01283 NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
01284 NWidget(NWID_SPACER), SetFill(1, 1),
01285 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_SETPWD), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_SET_PASSWORD, STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP),
01286 EndContainer(),
01287 EndContainer(),
01288
01289 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 6, 10),
01290 NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
01291 NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS, STR_NULL),
01292 NWidget(NWID_HORIZONTAL),
01293 NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_BTND), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_ARROW_DOWN, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
01294 NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_TXT), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_CLIENTS_SELECT, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
01295 NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_BTNU), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_ARROW_UP, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP),
01296 EndContainer(),
01297 EndContainer(),
01298
01299 NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
01300 NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES, STR_NULL),
01301 NWidget(NWID_HORIZONTAL),
01302 NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_BTND), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_ARROW_DOWN, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
01303 NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_TXT), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_COMPANIES_SELECT, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
01304 NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_BTNU), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_ARROW_UP, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP),
01305 EndContainer(),
01306 EndContainer(),
01307
01308 NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
01309 NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_SPECTATORS_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS, STR_NULL),
01310 NWidget(NWID_HORIZONTAL),
01311 NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_SPECTATORS_BTND), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_ARROW_DOWN, STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP),
01312 NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_NSS_SPECTATORS_TXT), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_SPECTATORS_SELECT, STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP),
01313 NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_SPECTATORS_BTNU), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_ARROW_UP, STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP),
01314 EndContainer(),
01315 EndContainer(),
01316 EndContainer(),
01317
01318
01319 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 6, 10),
01320 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_GENERATE_GAME), SetDataTip(STR_INTRO_NEW_GAME, STR_INTRO_TOOLTIP_NEW_GAME), SetFill(1, 0),
01321 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_LOAD_GAME), SetDataTip(STR_INTRO_LOAD_GAME, STR_INTRO_TOOLTIP_LOAD_GAME), SetFill(1, 0),
01322 EndContainer(),
01323
01324
01325 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 6, 10),
01326 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_PLAY_SCENARIO), SetDataTip(STR_INTRO_PLAY_SCENARIO, STR_INTRO_TOOLTIP_PLAY_SCENARIO), SetFill(1, 0),
01327 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_PLAY_HEIGHTMAP), SetDataTip(STR_INTRO_PLAY_HEIGHTMAP, STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP), SetFill(1, 0),
01328 EndContainer(),
01329
01330 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 0, 10),
01331 NWidget(NWID_SPACER), SetFill(1, 0),
01332 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_CANCEL), SetDataTip(STR_BUTTON_CANCEL, STR_NULL), SetMinimalSize(128, 12),
01333 NWidget(NWID_SPACER), SetFill(1, 0),
01334 EndContainer(),
01335 EndContainer(),
01336 EndContainer(),
01337 };
01338
01339 static const WindowDesc _network_start_server_window_desc(
01340 WDP_CENTER, 0, 0,
01341 WC_NETWORK_WINDOW, WC_NONE,
01342 0,
01343 _nested_network_start_server_window_widgets, lengthof(_nested_network_start_server_window_widgets)
01344 );
01345
01346 static void ShowNetworkStartServerWindow()
01347 {
01348 DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME);
01349 DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY);
01350
01351 new NetworkStartServerWindow(&_network_start_server_window_desc);
01352 }
01353
01354 struct NetworkLobbyWindow : public Window {
01355 CompanyID company;
01356 NetworkGameList *server;
01357 NetworkCompanyInfo company_info[MAX_COMPANIES];
01358 Scrollbar *vscroll;
01359
01360 NetworkLobbyWindow(const WindowDesc *desc, NetworkGameList *ngl) :
01361 Window(), company(INVALID_COMPANY), server(ngl)
01362 {
01363 this->CreateNestedTree(desc);
01364 this->vscroll = this->GetScrollbar(WID_NL_SCROLLBAR);
01365 this->FinishInitNested(desc, WN_NETWORK_WINDOW_LOBBY);
01366 this->OnResize();
01367 }
01368
01369 CompanyID NetworkLobbyFindCompanyIndex(byte pos) const
01370 {
01371
01372 for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
01373 if (!StrEmpty(this->company_info[i].company_name)) {
01374 if (pos-- == 0) return i;
01375 }
01376 }
01377
01378 return COMPANY_FIRST;
01379 }
01380
01381 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
01382 {
01383 switch (widget) {
01384 case WID_NL_HEADER:
01385 size->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
01386 break;
01387
01388 case WID_NL_MATRIX:
01389 resize->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
01390 size->height = 10 * resize->height;
01391 break;
01392
01393 case WID_NL_DETAILS:
01394 size->height = 30 + 11 * FONT_HEIGHT_NORMAL;
01395 break;
01396 }
01397 }
01398
01399 virtual void SetStringParameters(int widget) const
01400 {
01401 switch (widget) {
01402 case WID_NL_TEXT:
01403 SetDParamStr(0, this->server->info.server_name);
01404 break;
01405 }
01406 }
01407
01408 virtual void DrawWidget(const Rect &r, int widget) const
01409 {
01410 switch (widget) {
01411 case WID_NL_DETAILS:
01412 this->DrawDetails(r);
01413 break;
01414
01415 case WID_NL_MATRIX:
01416 this->DrawMatrix(r);
01417 break;
01418 }
01419 }
01420
01421 virtual void OnPaint()
01422 {
01423 const NetworkGameInfo *gi = &this->server->info;
01424
01425
01426 this->SetWidgetDisabledState(WID_NL_JOIN, this->company == INVALID_COMPANY || GetLobbyCompanyInfo(this->company)->ai);
01427
01428 this->SetWidgetDisabledState(WID_NL_NEW, gi->companies_on >= gi->companies_max);
01429
01430 this->SetWidgetDisabledState(WID_NL_SPECTATE, gi->spectators_on >= gi->spectators_max);
01431
01432 this->vscroll->SetCount(gi->companies_on);
01433
01434
01435 this->DrawWidgets();
01436 }
01437
01438 void DrawMatrix(const Rect &r) const
01439 {
01440 bool rtl = _current_text_dir == TD_RTL;
01441 uint left = r.left + WD_FRAMERECT_LEFT;
01442 uint right = r.right - WD_FRAMERECT_RIGHT;
01443
01444 Dimension lock_size = GetSpriteSize(SPR_LOCK);
01445 int lock_width = lock_size.width;
01446 int lock_y_offset = (this->resize.step_height - WD_MATRIX_TOP - WD_MATRIX_BOTTOM - lock_size.height) / 2;
01447
01448 Dimension profit_size = GetSpriteSize(SPR_PROFIT_LOT);
01449 int profit_width = lock_size.width;
01450 int profit_y_offset = (this->resize.step_height - WD_MATRIX_TOP - WD_MATRIX_BOTTOM - profit_size.height) / 2;
01451
01452 uint text_left = left + (rtl ? lock_width + profit_width + 4 : 0);
01453 uint text_right = right - (rtl ? 0 : lock_width + profit_width + 4);
01454 uint profit_left = rtl ? left : right - profit_width;
01455 uint lock_left = rtl ? left + profit_width + 2 : right - profit_width - lock_width - 2;
01456
01457 int y = r.top + WD_MATRIX_TOP;
01458
01459 int pos = this->vscroll->GetPosition();
01460 while (pos < this->server->info.companies_on) {
01461 byte company = NetworkLobbyFindCompanyIndex(pos);
01462 bool income = false;
01463 if (this->company == company) {
01464 GfxFillRect(r.left + 1, y - 2, r.right - 1, y + FONT_HEIGHT_NORMAL, PC_GREY);
01465 }
01466
01467 DrawString(text_left, text_right, y, this->company_info[company].company_name, TC_BLACK);
01468 if (this->company_info[company].use_password != 0) DrawSprite(SPR_LOCK, PAL_NONE, lock_left, y + lock_y_offset);
01469
01470
01471 if (this->company_info[company].income >= 0) income = true;
01472 DrawSprite(income ? SPR_PROFIT_LOT : SPR_PROFIT_NEGATIVE, PAL_NONE, profit_left, y + profit_y_offset);
01473
01474 pos++;
01475 y += this->resize.step_height;
01476 if (pos >= this->vscroll->GetPosition() + this->vscroll->GetCapacity()) break;
01477 }
01478 }
01479
01480 void DrawDetails(const Rect &r) const
01481 {
01482 const int detail_height = 12 + FONT_HEIGHT_NORMAL + 12;
01483
01484 GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.top + detail_height - 1, PC_DARK_BLUE);
01485 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 12, STR_NETWORK_GAME_LOBBY_COMPANY_INFO, TC_FROMSTRING, SA_HOR_CENTER);
01486
01487 if (this->company == INVALID_COMPANY || StrEmpty(this->company_info[this->company].company_name)) return;
01488
01489 int y = r.top + detail_height + 4;
01490 const NetworkGameInfo *gi = &this->server->info;
01491
01492 SetDParam(0, gi->clients_on);
01493 SetDParam(1, gi->clients_max);
01494 SetDParam(2, gi->companies_on);
01495 SetDParam(3, gi->companies_max);
01496 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CLIENTS);
01497 y += FONT_HEIGHT_NORMAL;
01498
01499 SetDParamStr(0, this->company_info[this->company].company_name);
01500 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_COMPANY_NAME);
01501 y += FONT_HEIGHT_NORMAL;
01502
01503 SetDParam(0, this->company_info[this->company].inaugurated_year);
01504 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR);
01505 y += FONT_HEIGHT_NORMAL;
01506
01507 SetDParam(0, this->company_info[this->company].company_value);
01508 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_VALUE);
01509 y += FONT_HEIGHT_NORMAL;
01510
01511 SetDParam(0, this->company_info[this->company].money);
01512 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_CURRENT_BALANCE);
01513 y += FONT_HEIGHT_NORMAL;
01514
01515 SetDParam(0, this->company_info[this->company].income);
01516 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_LAST_YEARS_INCOME);
01517 y += FONT_HEIGHT_NORMAL;
01518
01519 SetDParam(0, this->company_info[this->company].performance);
01520 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_PERFORMANCE);
01521 y += FONT_HEIGHT_NORMAL;
01522
01523 SetDParam(0, this->company_info[this->company].num_vehicle[NETWORK_VEH_TRAIN]);
01524 SetDParam(1, this->company_info[this->company].num_vehicle[NETWORK_VEH_LORRY]);
01525 SetDParam(2, this->company_info[this->company].num_vehicle[NETWORK_VEH_BUS]);
01526 SetDParam(3, this->company_info[this->company].num_vehicle[NETWORK_VEH_SHIP]);
01527 SetDParam(4, this->company_info[this->company].num_vehicle[NETWORK_VEH_PLANE]);
01528 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_VEHICLES);
01529 y += FONT_HEIGHT_NORMAL;
01530
01531 SetDParam(0, this->company_info[this->company].num_station[NETWORK_VEH_TRAIN]);
01532 SetDParam(1, this->company_info[this->company].num_station[NETWORK_VEH_LORRY]);
01533 SetDParam(2, this->company_info[this->company].num_station[NETWORK_VEH_BUS]);
01534 SetDParam(3, this->company_info[this->company].num_station[NETWORK_VEH_SHIP]);
01535 SetDParam(4, this->company_info[this->company].num_station[NETWORK_VEH_PLANE]);
01536 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_STATIONS);
01537 y += FONT_HEIGHT_NORMAL;
01538
01539 SetDParamStr(0, this->company_info[this->company].clients);
01540 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_PLAYERS);
01541 }
01542
01543 virtual void OnClick(Point pt, int widget, int click_count)
01544 {
01545 switch (widget) {
01546 case WID_NL_CANCEL:
01547 ShowNetworkGameWindow();
01548 break;
01549
01550 case WID_NL_MATRIX: {
01551 uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NL_MATRIX);
01552 this->company = (id_v >= this->server->info.companies_on) ? INVALID_COMPANY : NetworkLobbyFindCompanyIndex(id_v);
01553 this->SetDirty();
01554
01555
01556 if (click_count > 1 && !this->IsWidgetDisabled(WID_NL_JOIN)) this->OnClick(pt, WID_NL_JOIN, 1);
01557 break;
01558 }
01559
01560 case WID_NL_JOIN:
01561
01562 NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), this->company);
01563 break;
01564
01565 case WID_NL_NEW:
01566 NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), COMPANY_NEW_COMPANY);
01567 break;
01568
01569 case WID_NL_SPECTATE:
01570 NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), COMPANY_SPECTATOR);
01571 break;
01572
01573 case WID_NL_REFRESH:
01574 NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01575 NetworkUDPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01576
01577 memset(this->company_info, 0, sizeof(this->company_info));
01578 break;
01579 }
01580 }
01581
01582 virtual void OnResize()
01583 {
01584 this->vscroll->SetCapacityFromWidget(this, WID_NL_MATRIX);
01585 this->GetWidget<NWidgetCore>(WID_NL_MATRIX)->widget_data = (this->vscroll->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START);
01586 }
01587 };
01588
01589 static const NWidgetPart _nested_network_lobby_window_widgets[] = {
01590 NWidget(NWID_HORIZONTAL),
01591 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
01592 NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_GAME_LOBBY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01593 EndContainer(),
01594 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NL_BACKGROUND),
01595 NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NL_TEXT), SetDataTip(STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN, STR_NULL), SetResize(1, 0), SetPadding(10, 10, 0, 10),
01596 NWidget(NWID_SPACER), SetMinimalSize(0, 3),
01597 NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 10),
01598
01599 NWidget(NWID_VERTICAL),
01600 NWidget(WWT_PANEL, COLOUR_WHITE, WID_NL_HEADER), SetMinimalSize(146, 0), SetResize(1, 0), SetFill(1, 0), EndContainer(),
01601 NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NL_MATRIX), SetMinimalSize(146, 0), SetResize(1, 1), SetFill(1, 1), SetDataTip(0, STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP), SetScrollbar(WID_NL_SCROLLBAR),
01602 EndContainer(),
01603 NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NL_SCROLLBAR),
01604 NWidget(NWID_SPACER), SetMinimalSize(5, 0), SetResize(0, 1),
01605
01606 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NL_DETAILS), SetMinimalSize(232, 0), SetResize(1, 1), SetFill(1, 1), EndContainer(),
01607 EndContainer(),
01608 NWidget(NWID_SPACER), SetMinimalSize(0, 9),
01609
01610 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 3, 10),
01611 NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 3, 0),
01612 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_JOIN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_GAME_LOBBY_JOIN_COMPANY, STR_NETWORK_GAME_LOBBY_JOIN_COMPANY_TOOLTIP),
01613 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_NEW), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_GAME_LOBBY_NEW_COMPANY, STR_NETWORK_GAME_LOBBY_NEW_COMPANY_TOOLTIP),
01614 EndContainer(),
01615 NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 3, 0),
01616 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_SPECTATE), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_GAME_LOBBY_SPECTATE_GAME, STR_NETWORK_GAME_LOBBY_SPECTATE_GAME_TOOLTIP),
01617 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_REFRESH), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_REFRESH, STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP),
01618 EndContainer(),
01619 NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 3, 0),
01620 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_CANCEL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
01621 NWidget(NWID_SPACER), SetFill(1, 1),
01622 EndContainer(),
01623 EndContainer(),
01624 NWidget(NWID_SPACER), SetMinimalSize(0, 8),
01625 EndContainer(),
01626 };
01627
01628 static const WindowDesc _network_lobby_window_desc(
01629 WDP_CENTER, 0, 0,
01630 WC_NETWORK_WINDOW, WC_NONE,
01631 0,
01632 _nested_network_lobby_window_widgets, lengthof(_nested_network_lobby_window_widgets)
01633 );
01634
01639 static void ShowNetworkLobbyWindow(NetworkGameList *ngl)
01640 {
01641 DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_START);
01642 DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME);
01643
01644 NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01645 NetworkUDPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
01646
01647 new NetworkLobbyWindow(&_network_lobby_window_desc, ngl);
01648 }
01649
01655 NetworkCompanyInfo *GetLobbyCompanyInfo(CompanyID company)
01656 {
01657 NetworkLobbyWindow *lobby = dynamic_cast<NetworkLobbyWindow*>(FindWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY));
01658 return (lobby != NULL && company < MAX_COMPANIES) ? &lobby->company_info[company] : NULL;
01659 }
01660
01661
01662
01663
01664
01665 extern void DrawCompanyIcon(CompanyID cid, int x, int y);
01666
01671 typedef void ClientList_Action_Proc(const NetworkClientInfo *ci);
01672
01673 static const NWidgetPart _nested_client_list_popup_widgets[] = {
01674 NWidget(WWT_PANEL, COLOUR_GREY, WID_CLP_PANEL), EndContainer(),
01675 };
01676
01677 static const WindowDesc _client_list_popup_desc(
01678 WDP_AUTO, 0, 0,
01679 WC_CLIENT_LIST_POPUP, WC_CLIENT_LIST,
01680 0,
01681 _nested_client_list_popup_widgets, lengthof(_nested_client_list_popup_widgets)
01682 );
01683
01684
01685 static void ClientList_Kick(const NetworkClientInfo *ci)
01686 {
01687 NetworkServerKickClient(ci->client_id);
01688 }
01689
01690 static void ClientList_Ban(const NetworkClientInfo *ci)
01691 {
01692 NetworkServerKickOrBanIP(ci->client_id, true);
01693 }
01694
01695 static void ClientList_GiveMoney(const NetworkClientInfo *ci)
01696 {
01697 ShowNetworkGiveMoneyWindow(ci->client_playas);
01698 }
01699
01700 static void ClientList_SpeakToClient(const NetworkClientInfo *ci)
01701 {
01702 ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, ci->client_id);
01703 }
01704
01705 static void ClientList_SpeakToCompany(const NetworkClientInfo *ci)
01706 {
01707 ShowNetworkChatQueryWindow(DESTTYPE_TEAM, ci->client_playas);
01708 }
01709
01710 static void ClientList_SpeakToAll(const NetworkClientInfo *ci)
01711 {
01712 ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
01713 }
01714
01716 struct NetworkClientListPopupWindow : Window {
01718 struct ClientListAction {
01719 StringID name;
01720 ClientList_Action_Proc *proc;
01721 };
01722
01723 uint sel_index;
01724 ClientID client_id;
01725 Point desired_location;
01726 SmallVector<ClientListAction, 2> actions;
01727
01733 inline void AddAction(StringID name, ClientList_Action_Proc *proc)
01734 {
01735 ClientListAction *action = this->actions.Append();
01736 action->name = name;
01737 action->proc = proc;
01738 }
01739
01740 NetworkClientListPopupWindow(const WindowDesc *desc, int x, int y, ClientID client_id) :
01741 Window(),
01742 sel_index(0), client_id(client_id)
01743 {
01744 this->desired_location.x = x;
01745 this->desired_location.y = y;
01746
01747 const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
01748
01749 if (_network_own_client_id != ci->client_id) {
01750 this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, &ClientList_SpeakToClient);
01751 }
01752
01753 if (Company::IsValidID(ci->client_playas) || ci->client_playas == COMPANY_SPECTATOR) {
01754 this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, &ClientList_SpeakToCompany);
01755 }
01756 this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, &ClientList_SpeakToAll);
01757
01758 if (_network_own_client_id != ci->client_id) {
01759
01760 if (Company::IsValidID(_local_company) && Company::IsValidID(ci->client_playas) && _settings_game.economy.give_money) {
01761 this->AddAction(STR_NETWORK_CLIENTLIST_GIVE_MONEY, &ClientList_GiveMoney);
01762 }
01763 }
01764
01765
01766 if (_network_server && _network_own_client_id != ci->client_id) {
01767 this->AddAction(STR_NETWORK_CLIENTLIST_KICK, &ClientList_Kick);
01768 this->AddAction(STR_NETWORK_CLIENTLIST_BAN, &ClientList_Ban);
01769 }
01770
01771 this->InitNested(desc, client_id);
01772 CLRBITS(this->flags, WF_WHITE_BORDER);
01773 }
01774
01775 virtual Point OnInitialPosition(const WindowDesc *desc, int16 sm_width, int16 sm_height, int window_number)
01776 {
01777 return this->desired_location;
01778 }
01779
01780 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
01781 {
01782 Dimension d = *size;
01783 for (const ClientListAction *action = this->actions.Begin(); action != this->actions.End(); action++) {
01784 d = maxdim(GetStringBoundingBox(action->name), d);
01785 }
01786
01787 d.height *= this->actions.Length();
01788 d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
01789 d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
01790 *size = d;
01791 }
01792
01793 virtual void DrawWidget(const Rect &r, int widget) const
01794 {
01795
01796 int sel = this->sel_index;
01797 int y = r.top + WD_FRAMERECT_TOP;
01798 for (const ClientListAction *action = this->actions.Begin(); action != this->actions.End(); action++, y += FONT_HEIGHT_NORMAL) {
01799 TextColour colour;
01800 if (sel-- == 0) {
01801 GfxFillRect(r.left + 1, y, r.right - 1, y + FONT_HEIGHT_NORMAL - 1, PC_BLACK);
01802 colour = TC_WHITE;
01803 } else {
01804 colour = TC_BLACK;
01805 }
01806
01807 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, action->name, colour);
01808 }
01809 }
01810
01811 virtual void OnMouseLoop()
01812 {
01813
01814 uint index = (_cursor.pos.y - this->top - WD_FRAMERECT_TOP) / FONT_HEIGHT_NORMAL;
01815
01816 if (_left_button_down) {
01817 if (index == this->sel_index || index >= this->actions.Length()) return;
01818
01819 this->sel_index = index;
01820 this->SetDirty();
01821 } else {
01822 if (index < this->actions.Length() && _cursor.pos.y >= this->top) {
01823 const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(this->client_id);
01824 if (ci != NULL) this->actions[index].proc(ci);
01825 }
01826
01827 DeleteWindowByClass(WC_CLIENT_LIST_POPUP);
01828 }
01829 }
01830 };
01831
01835 static void PopupClientList(ClientID client_id, int x, int y)
01836 {
01837 DeleteWindowByClass(WC_CLIENT_LIST_POPUP);
01838
01839 if (NetworkClientInfo::GetByClientID(client_id) == NULL) return;
01840
01841 new NetworkClientListPopupWindow(&_client_list_popup_desc, x, y, client_id);
01842 }
01843
01844 static const NWidgetPart _nested_client_list_widgets[] = {
01845 NWidget(NWID_HORIZONTAL),
01846 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
01847 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_COMPANY_LIST_CLIENT_LIST, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01848 NWidget(WWT_STICKYBOX, COLOUR_GREY),
01849 EndContainer(),
01850 NWidget(WWT_PANEL, COLOUR_GREY, WID_CL_PANEL), SetMinimalSize(250, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM), SetResize(1, 1), EndContainer(),
01851 };
01852
01853 static const WindowDesc _client_list_desc(
01854 WDP_AUTO, 0, 0,
01855 WC_CLIENT_LIST, WC_NONE,
01856 0,
01857 _nested_client_list_widgets, lengthof(_nested_client_list_widgets)
01858 );
01859
01863 struct NetworkClientListWindow : Window {
01864 int selected_item;
01865
01866 uint server_client_width;
01867 uint company_icon_width;
01868
01869 NetworkClientListWindow(const WindowDesc *desc, WindowNumber window_number) :
01870 Window(),
01871 selected_item(-1)
01872 {
01873 this->InitNested(desc, window_number);
01874 }
01875
01879 bool CheckClientListHeight()
01880 {
01881 int num = 0;
01882 const NetworkClientInfo *ci;
01883
01884
01885 FOR_ALL_CLIENT_INFOS(ci) {
01886 if (ci->client_playas != COMPANY_INACTIVE_CLIENT) num++;
01887 }
01888
01889 num *= FONT_HEIGHT_NORMAL;
01890
01891 int diff = (num + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM) - (this->GetWidget<NWidgetBase>(WID_CL_PANEL)->current_y);
01892
01893 if (diff != 0) {
01894 ResizeWindow(this, 0, diff);
01895 return false;
01896 }
01897 return true;
01898 }
01899
01900 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
01901 {
01902 if (widget != WID_CL_PANEL) return;
01903
01904 this->server_client_width = max(GetStringBoundingBox(STR_NETWORK_SERVER).width, GetStringBoundingBox(STR_NETWORK_CLIENT).width) + WD_FRAMERECT_RIGHT;
01905 this->company_icon_width = GetSpriteSize(SPR_COMPANY_ICON).width + WD_FRAMERECT_LEFT;
01906
01907 uint width = 100;
01908 const NetworkClientInfo *ci;
01909 FOR_ALL_CLIENT_INFOS(ci) {
01910 width = max(width, GetStringBoundingBox(ci->client_name).width);
01911 }
01912
01913 size->width = WD_FRAMERECT_LEFT + this->server_client_width + this->company_icon_width + width + WD_FRAMERECT_RIGHT;
01914 }
01915
01916 virtual void OnPaint()
01917 {
01918
01919 if (!this->CheckClientListHeight()) return;
01920
01921 this->DrawWidgets();
01922 }
01923
01924 virtual void DrawWidget(const Rect &r, int widget) const
01925 {
01926 if (widget != WID_CL_PANEL) return;
01927
01928 bool rtl = _current_text_dir == TD_RTL;
01929 int icon_y_offset = 1 + (FONT_HEIGHT_NORMAL - 10) / 2;
01930 uint y = r.top + WD_FRAMERECT_TOP;
01931 uint left = r.left + WD_FRAMERECT_LEFT;
01932 uint right = r.right - WD_FRAMERECT_RIGHT;
01933 uint type_icon_width = this->server_client_width + this->company_icon_width;
01934
01935
01936 uint type_left = rtl ? right - this->server_client_width : left;
01937 uint type_right = rtl ? right : left + this->server_client_width - 1;
01938 uint icon_left = rtl ? right - type_icon_width + WD_FRAMERECT_LEFT : left + this->server_client_width;
01939 uint name_left = rtl ? left : left + type_icon_width;
01940 uint name_right = rtl ? right - type_icon_width : right;
01941
01942 int i = 0;
01943 const NetworkClientInfo *ci;
01944 FOR_ALL_CLIENT_INFOS(ci) {
01945 TextColour colour;
01946 if (this->selected_item == i++) {
01947 GfxFillRect(r.left + 1, y, r.right - 1, y + FONT_HEIGHT_NORMAL - 1, PC_BLACK);
01948 colour = TC_WHITE;
01949 } else {
01950 colour = TC_BLACK;
01951 }
01952
01953 if (ci->client_id == CLIENT_ID_SERVER) {
01954 DrawString(type_left, type_right, y, STR_NETWORK_SERVER, colour);
01955 } else {
01956 DrawString(type_left, type_right, y, STR_NETWORK_CLIENT, colour);
01957 }
01958
01959
01960 if (Company::IsValidID(ci->client_playas)) DrawCompanyIcon(ci->client_playas, icon_left, y + icon_y_offset);
01961
01962 DrawString(name_left, name_right, y, ci->client_name, colour);
01963
01964 y += FONT_HEIGHT_NORMAL;
01965 }
01966 }
01967
01968 virtual void OnClick(Point pt, int widget, int click_count)
01969 {
01970
01971 if (this->selected_item != -1) {
01972 NetworkClientInfo *ci;
01973
01974 int client_no = this->selected_item;
01975 FOR_ALL_CLIENT_INFOS(ci) {
01976 if (client_no == 0) break;
01977 client_no--;
01978 }
01979
01980 if (ci != NULL) PopupClientList(ci->client_id, pt.x + this->left, pt.y + this->top);
01981 }
01982 }
01983
01984 virtual void OnMouseOver(Point pt, int widget)
01985 {
01986
01987 if (pt.y == -1) {
01988 this->selected_item = -1;
01989 this->SetDirty();
01990 return;
01991 }
01992
01993
01994 pt.y -= this->GetWidget<NWidgetBase>(WID_CL_PANEL)->pos_y;
01995 int item = -1;
01996 if (IsInsideMM(pt.y, WD_FRAMERECT_TOP, this->GetWidget<NWidgetBase>(WID_CL_PANEL)->current_y - WD_FRAMERECT_BOTTOM)) {
01997 item = (pt.y - WD_FRAMERECT_TOP) / FONT_HEIGHT_NORMAL;
01998 }
01999
02000
02001 if (item == this->selected_item) return;
02002 this->selected_item = item;
02003
02004
02005 this->SetDirty();
02006 }
02007 };
02008
02009 void ShowClientList()
02010 {
02011 AllocateWindowDescFront<NetworkClientListWindow>(&_client_list_desc, 0);
02012 }
02013
02014 NetworkJoinStatus _network_join_status;
02015 uint8 _network_join_waiting;
02016 uint32 _network_join_bytes;
02017 uint32 _network_join_bytes_total;
02018
02019 struct NetworkJoinStatusWindow : Window {
02020 NetworkPasswordType password_type;
02021
02022 NetworkJoinStatusWindow(const WindowDesc *desc) : Window()
02023 {
02024 this->parent = FindWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME);
02025 this->InitNested(desc, WN_NETWORK_STATUS_WINDOW_JOIN);
02026 }
02027
02028 virtual void DrawWidget(const Rect &r, int widget) const
02029 {
02030 if (widget != WID_NJS_BACKGROUND) return;
02031
02032 uint8 progress;
02033 DrawString(r.left + 2, r.right - 2, r.top + 20, STR_NETWORK_CONNECTING_1 + _network_join_status, TC_FROMSTRING, SA_HOR_CENTER);
02034 switch (_network_join_status) {
02035 case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING:
02036 case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
02037 progress = 10;
02038 break;
02039 case NETWORK_JOIN_STATUS_WAITING:
02040 SetDParam(0, _network_join_waiting);
02041 DrawString(r.left + 2, r.right - 2, r.top + 20 + FONT_HEIGHT_NORMAL, STR_NETWORK_CONNECTING_WAITING, TC_FROMSTRING, SA_HOR_CENTER);
02042 progress = 15;
02043 break;
02044 case NETWORK_JOIN_STATUS_DOWNLOADING:
02045 SetDParam(0, _network_join_bytes);
02046 SetDParam(1, _network_join_bytes_total);
02047 DrawString(r.left + 2, r.right - 2, r.top + 20 + FONT_HEIGHT_NORMAL, _network_join_bytes_total == 0 ? STR_NETWORK_CONNECTING_DOWNLOADING_1 : STR_NETWORK_CONNECTING_DOWNLOADING_2, TC_FROMSTRING, SA_HOR_CENTER);
02048 if (_network_join_bytes_total == 0) {
02049 progress = 15;
02050 break;
02051 }
02052
02053 default:
02054 progress = 15 + _network_join_bytes * (100 - 15) / _network_join_bytes_total;
02055 }
02056
02057
02058 DrawFrameRect(r.left + 20, r.top + 5, (int)((this->width - 20) * progress / 100), r.top + 15, COLOUR_MAUVE, FR_NONE);
02059 }
02060
02061 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
02062 {
02063 if (widget != WID_NJS_BACKGROUND) return;
02064
02065 size->height = 25 + 2 * FONT_HEIGHT_NORMAL;
02066
02067
02068 uint width = 0;
02069 for (uint i = 0; i < NETWORK_JOIN_STATUS_END; i++) {
02070 width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_1 + i).width);
02071 }
02072
02073
02074 SetDParamMaxValue(0, MAX_CLIENTS);
02075 width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_WAITING).width);
02076
02077
02078 SetDParamMaxDigits(0, 8);
02079 SetDParamMaxDigits(1, 8);
02080 width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_DOWNLOADING_1).width);
02081 width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_DOWNLOADING_2).width);
02082
02083
02084 size->width = width + WD_FRAMERECT_LEFT + WD_FRAMERECT_BOTTOM + 10;
02085 }
02086
02087 virtual void OnClick(Point pt, int widget, int click_count)
02088 {
02089 if (widget == WID_NJS_CANCELOK) {
02090 NetworkDisconnect();
02091 SwitchToMode(SM_MENU);
02092 ShowNetworkGameWindow();
02093 }
02094 }
02095
02096 virtual void OnQueryTextFinished(char *str)
02097 {
02098 if (StrEmpty(str)) {
02099 NetworkDisconnect();
02100 ShowNetworkGameWindow();
02101 return;
02102 }
02103
02104 switch (this->password_type) {
02105 case NETWORK_GAME_PASSWORD: MyClient::SendGamePassword (str); break;
02106 case NETWORK_COMPANY_PASSWORD: MyClient::SendCompanyPassword(str); break;
02107 default: NOT_REACHED();
02108 }
02109 }
02110 };
02111
02112 static const NWidgetPart _nested_network_join_status_window_widgets[] = {
02113 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_CONNECTING_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
02114 NWidget(WWT_PANEL, COLOUR_GREY),
02115 NWidget(WWT_EMPTY, COLOUR_GREY, WID_NJS_BACKGROUND),
02116 NWidget(NWID_HORIZONTAL),
02117 NWidget(NWID_SPACER), SetMinimalSize(75, 0), SetFill(1, 0),
02118 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NJS_CANCELOK), SetMinimalSize(101, 12), SetDataTip(STR_NETWORK_CONNECTION_DISCONNECT, STR_NULL),
02119 NWidget(NWID_SPACER), SetMinimalSize(75, 0), SetFill(1, 0),
02120 EndContainer(),
02121 NWidget(NWID_SPACER), SetMinimalSize(0, 4),
02122 EndContainer(),
02123 };
02124
02125 static const WindowDesc _network_join_status_window_desc(
02126 WDP_CENTER, 0, 0,
02127 WC_NETWORK_STATUS_WINDOW, WC_NONE,
02128 WDF_MODAL,
02129 _nested_network_join_status_window_widgets, lengthof(_nested_network_join_status_window_widgets)
02130 );
02131
02132 void ShowJoinStatusWindow()
02133 {
02134 DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
02135 new NetworkJoinStatusWindow(&_network_join_status_window_desc);
02136 }
02137
02138 void ShowNetworkNeedPassword(NetworkPasswordType npt)
02139 {
02140 NetworkJoinStatusWindow *w = (NetworkJoinStatusWindow *)FindWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
02141 if (w == NULL) return;
02142 w->password_type = npt;
02143
02144 StringID caption;
02145 switch (npt) {
02146 default: NOT_REACHED();
02147 case NETWORK_GAME_PASSWORD: caption = STR_NETWORK_NEED_GAME_PASSWORD_CAPTION; break;
02148 case NETWORK_COMPANY_PASSWORD: caption = STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION; break;
02149 }
02150 ShowQueryString(STR_EMPTY, caption, NETWORK_PASSWORD_LENGTH, w, CS_ALPHANUMERAL, QSF_NONE);
02151 }
02152
02153 struct NetworkCompanyPasswordWindow : public Window {
02154 QueryString password_editbox;
02155
02156 NetworkCompanyPasswordWindow(const WindowDesc *desc, Window *parent) : password_editbox(lengthof(_settings_client.network.default_company_pass))
02157 {
02158 this->InitNested(desc, 0);
02159
02160 this->parent = parent;
02161 this->querystrings[WID_NCP_PASSWORD] = &this->password_editbox;
02162 this->password_editbox.cancel_button = WID_NCP_CANCEL;
02163 this->password_editbox.ok_button = WID_NCP_OK;
02164 this->password_editbox.afilter = CS_ALPHANUMERAL;
02165 this->SetFocusedWidget(WID_NCP_PASSWORD);
02166 }
02167
02168 void OnOk()
02169 {
02170 if (this->IsWidgetLowered(WID_NCP_SAVE_AS_DEFAULT_PASSWORD)) {
02171 strecpy(_settings_client.network.default_company_pass, this->password_editbox.text.buf, lastof(_settings_client.network.default_company_pass));
02172 }
02173
02174 NetworkChangeCompanyPassword(_local_company, this->password_editbox.text.buf);
02175 }
02176
02177 virtual void OnClick(Point pt, int widget, int click_count)
02178 {
02179 switch (widget) {
02180 case WID_NCP_OK:
02181 this->OnOk();
02182
02183
02184 case WID_NCP_CANCEL:
02185 delete this;
02186 break;
02187
02188 case WID_NCP_SAVE_AS_DEFAULT_PASSWORD:
02189 this->ToggleWidgetLoweredState(WID_NCP_SAVE_AS_DEFAULT_PASSWORD);
02190 this->SetDirty();
02191 break;
02192 }
02193 }
02194 };
02195
02196 static const NWidgetPart _nested_network_company_password_window_widgets[] = {
02197 NWidget(NWID_HORIZONTAL),
02198 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
02199 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_COMPANY_PASSWORD_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
02200 EndContainer(),
02201 NWidget(WWT_PANEL, COLOUR_GREY, WID_NCP_BACKGROUND),
02202 NWidget(NWID_VERTICAL), SetPIP(5, 5, 5),
02203 NWidget(NWID_HORIZONTAL), SetPIP(5, 5, 5),
02204 NWidget(WWT_TEXT, COLOUR_GREY, WID_NCP_LABEL), SetDataTip(STR_COMPANY_VIEW_PASSWORD, STR_NULL),
02205 NWidget(WWT_EDITBOX, COLOUR_GREY, WID_NCP_PASSWORD), SetMinimalSize(194, 12), SetDataTip(STR_COMPANY_VIEW_SET_PASSWORD, STR_NULL),
02206 EndContainer(),
02207 NWidget(NWID_HORIZONTAL), SetPIP(5, 0, 5),
02208 NWidget(NWID_SPACER), SetFill(1, 0),
02209 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_NCP_SAVE_AS_DEFAULT_PASSWORD), SetMinimalSize(194, 12),
02210 SetDataTip(STR_COMPANY_PASSWORD_MAKE_DEFAULT, STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP),
02211 EndContainer(),
02212 EndContainer(),
02213 EndContainer(),
02214 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
02215 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NCP_CANCEL), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_COMPANY_PASSWORD_CANCEL),
02216 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NCP_OK), SetFill(1, 0), SetDataTip(STR_BUTTON_OK, STR_COMPANY_PASSWORD_OK),
02217 EndContainer(),
02218 };
02219
02220 static const WindowDesc _network_company_password_window_desc(
02221 WDP_AUTO, 0, 0,
02222 WC_COMPANY_PASSWORD_WINDOW, WC_NONE,
02223 0,
02224 _nested_network_company_password_window_widgets, lengthof(_nested_network_company_password_window_widgets)
02225 );
02226
02227 void ShowNetworkCompanyPasswordWindow(Window *parent)
02228 {
02229 DeleteWindowById(WC_COMPANY_PASSWORD_WINDOW, 0);
02230
02231 new NetworkCompanyPasswordWindow(&_network_company_password_window_desc, parent);
02232 }
02233
02234 #endif