00001
00002
00005 #if defined(ENABLE_NETWORK)
00006 #include "../stdafx.h"
00007 #include "../string_func.h"
00008 #include "../strings_func.h"
00009 #include "../gfx_func.h"
00010 #include "../window_func.h"
00011 #include "../window_gui.h"
00012 #include "../gui.h"
00013 #include "../ai/ai.hpp"
00014 #include "../gfxinit.h"
00015 #include "../sortlist_type.h"
00016 #include "../querystring_gui.h"
00017 #include "network_content.h"
00018
00019 #include "table/strings.h"
00020 #include "../table/sprites.h"
00021
00023 static const Widget _network_content_download_status_window_widget[] = {
00024 { WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 0, 349, 0, 13, STR_CONTENT_DOWNLOAD_TITLE, STR_018C_WINDOW_TITLE_DRAG_THIS},
00025 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 349, 14, 84, 0x0, STR_NULL},
00026 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 125, 225, 69, 80, STR_012E_CANCEL, STR_NULL},
00027 { WIDGETS_END},
00028 };
00029
00031 static const WindowDesc _network_content_download_status_window_desc(
00032 WDP_CENTER, WDP_CENTER, 350, 85, 350, 85,
00033 WC_NETWORK_STATUS_WINDOW, WC_NONE,
00034 WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_MODAL,
00035 _network_content_download_status_window_widget
00036 );
00037
00039 struct NetworkContentDownloadStatusWindow : public Window, ContentCallback {
00041 enum Widgets {
00042 NCDSWW_CAPTION,
00043 NCDSWW_BACKGROUND,
00044 NCDSWW_CANCELOK,
00045 };
00046
00047 private:
00048 ClientNetworkContentSocketHandler *connection;
00049 SmallVector<ContentType, 4> receivedTypes;
00050
00051 uint total_files;
00052 uint downloaded_files;
00053 uint total_bytes;
00054 uint downloaded_bytes;
00055
00056 uint32 cur_id;
00057 char name[48];
00058
00059 public:
00065 NetworkContentDownloadStatusWindow() :
00066 Window(&_network_content_download_status_window_desc),
00067 cur_id(UINT32_MAX)
00068 {
00069 this->parent = FindWindowById(WC_NETWORK_WINDOW, 1);
00070
00071 _network_content_client.AddCallback(this);
00072 _network_content_client.DownloadSelectedContent(this->total_files, this->total_bytes);
00073
00074 this->FindWindowPlacementAndResize(&_network_content_download_status_window_desc);
00075 }
00076
00078 ~NetworkContentDownloadStatusWindow()
00079 {
00080
00081 for (ContentType *iter = this->receivedTypes.Begin(); iter != this->receivedTypes.End(); iter++) {
00082 switch (*iter) {
00083 case CONTENT_TYPE_AI:
00084 case CONTENT_TYPE_AI_LIBRARY:
00085 AI::Rescan();
00086 InvalidateWindowClasses(WC_AI_DEBUG);
00087 break;
00088
00089 case CONTENT_TYPE_BASE_GRAPHICS:
00090 FindGraphicsSets();
00091 InvalidateWindow(WC_GAME_OPTIONS, 0);
00092 break;
00093
00094 case CONTENT_TYPE_NEWGRF:
00095 ScanNewGRFFiles();
00096
00097 InvalidateWindowClasses(WC_SAVELOAD);
00098 InvalidateWindowData(WC_GAME_OPTIONS, 0, 1);
00099 InvalidateWindowData(WC_NETWORK_WINDOW, 1, 2);
00100 break;
00101
00102 case CONTENT_TYPE_SCENARIO:
00103 case CONTENT_TYPE_HEIGHTMAP:
00104 extern void ScanScenarios();
00105 ScanScenarios();
00106 InvalidateWindowData(WC_SAVELOAD, 0, 0);
00107 break;
00108
00109 default:
00110 break;
00111 }
00112 }
00113
00114 _network_content_client.RemoveCallback(this);
00115 }
00116
00117 virtual void OnPaint()
00118 {
00119
00120 if (this->downloaded_bytes == this->total_bytes) {
00121 this->widget[NCDSWW_CANCELOK].data = STR_012F_OK;
00122 }
00123
00124 this->DrawWidgets();
00125
00126
00127 DrawFrameRect(20, 18, 20 + (int)((this->width - 40LL) * this->downloaded_bytes / this->total_bytes), 28, COLOUR_MAUVE, FR_NONE);
00128
00129 SetDParam(0, this->downloaded_bytes);
00130 SetDParam(1, this->total_bytes);
00131 SetDParam(2, this->downloaded_bytes * 100LL / this->total_bytes);
00132 DrawStringCentered(this->width / 2, 35, STR_CONTENT_DOWNLOAD_PROGRESS_SIZE, TC_GREY);
00133
00134 if (this->downloaded_bytes == this->total_bytes) {
00135 DrawStringCentered(this->width / 2, 50, STR_CONTENT_DOWNLOAD_COMPLETE, TC_GREY);
00136 } else if (!StrEmpty(this->name)) {
00137 SetDParamStr(0, this->name);
00138 SetDParam(1, this->downloaded_files);
00139 SetDParam(2, this->total_files);
00140 DrawStringMultiCenter(this->width / 2, 50, STR_CONTENT_DOWNLOAD_FILE, this->width);
00141 } else {
00142 DrawStringCentered(this->width / 2, 50, STR_CONTENT_DOWNLOAD_INITIALISE, TC_GREY);
00143 }
00144 }
00145
00146 virtual void OnClick(Point pt, int widget)
00147 {
00148 if (widget == NCDSWW_CANCELOK) {
00149 if (this->downloaded_bytes != this->total_bytes) _network_content_client.Close();
00150 delete this;
00151 }
00152 }
00153
00154 virtual void OnDownloadProgress(const ContentInfo *ci, uint bytes)
00155 {
00156 if (ci->id != this->cur_id) {
00157 strecpy(this->name, ci->filename, lastof(this->name));
00158 this->cur_id = ci->id;
00159 this->downloaded_files++;
00160 this->receivedTypes.Include(ci->type);
00161 }
00162 this->downloaded_bytes += bytes;
00163
00164 this->SetDirty();
00165 }
00166 };
00167
00169 class NetworkContentListWindow : public QueryStringBaseWindow, ContentCallback {
00170 typedef GUIList<const ContentInfo*> GUIContentList;
00171
00173 enum Widgets {
00174 NCLWW_CLOSE,
00175 NCLWW_CAPTION,
00176 NCLWW_BACKGROUND,
00177
00178 NCLWW_FILTER,
00179
00180 NCLWW_CHECKBOX,
00181 NCLWW_TYPE,
00182 NCLWW_NAME,
00183
00184 NCLWW_MATRIX,
00185 NCLWW_SCROLLBAR,
00186
00187 NCLWW_DETAILS,
00188
00189 NCLWW_SELECT_ALL,
00190 NCLWW_SELECT_UPDATE,
00191 NCLWW_UNSELECT,
00192 NCLWW_CANCEL,
00193 NCLWW_DOWNLOAD,
00194
00195 NCLWW_RESIZE,
00196 };
00197
00198 enum {
00199 EDITBOX_MAX_SIZE = 50,
00200 EDITBOX_MAX_LENGTH = 300,
00201 };
00202
00204 static Listing last_sorting;
00205 static Filtering last_filtering;
00207 static GUIContentList::SortFunction * const sorter_funcs[];
00208 static GUIContentList::FilterFunction * const filter_funcs[];
00209 GUIContentList content;
00210
00211 const ContentInfo *selected;
00212 int list_pos;
00213
00218 void BuildContentList()
00219 {
00220 if (!this->content.NeedRebuild()) return;
00221
00222
00223 this->content.Clear();
00224
00225 for (ConstContentIterator iter = _network_content_client.Begin(); iter != _network_content_client.End(); iter++) {
00226 *this->content.Append() = *iter;
00227 }
00228
00229 this->FilterContentList();
00230 this->content.Compact();
00231 this->content.RebuildDone();
00232 }
00233
00235 static int CDECL NameSorter(const ContentInfo * const *a, const ContentInfo * const *b)
00236 {
00237 return strcasecmp((*a)->name, (*b)->name);
00238 }
00239
00241 static int CDECL TypeSorter(const ContentInfo * const *a, const ContentInfo * const *b)
00242 {
00243 int r = 0;
00244 if ((*a)->type != (*b)->type) {
00245 char a_str[64];
00246 char b_str[64];
00247 GetString(a_str, STR_CONTENT_TYPE_BASE_GRAPHICS + (*a)->type - CONTENT_TYPE_BASE_GRAPHICS, lastof(a_str));
00248 GetString(b_str, STR_CONTENT_TYPE_BASE_GRAPHICS + (*b)->type - CONTENT_TYPE_BASE_GRAPHICS, lastof(b_str));
00249 r = strcasecmp(a_str, b_str);
00250 }
00251 if (r == 0) r = NameSorter(a, b);
00252 return r;
00253 }
00254
00256 static int CDECL StateSorter(const ContentInfo * const *a, const ContentInfo * const *b)
00257 {
00258 int r = (*a)->state - (*b)->state;
00259 if (r == 0) r = TypeSorter(a, b);
00260 return r;
00261 }
00262
00264 void SortContentList()
00265 {
00266 if (!this->content.Sort()) return;
00267
00268 for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) {
00269 if (*iter == this->selected) {
00270 this->list_pos = iter - this->content.Begin();
00271 break;
00272 }
00273 }
00274 }
00275
00277 static bool CDECL TagNameFilter(const ContentInfo * const *a, const char *filter_string)
00278 {
00279 for (int i = 0; i < (*a)->tag_count; i++) {
00280 if (strcasestr((*a)->tags[i], filter_string) != NULL) return true;
00281 }
00282 return strcasestr((*a)->name, filter_string) != NULL;
00283 }
00284
00286 void FilterContentList()
00287 {
00288 if (!this->content.Filter(this->edit_str_buf)) return;
00289
00290
00291 for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) {
00292 if (*iter == this->selected) {
00293 this->list_pos = iter - this->content.Begin();
00294 this->ScrollToSelected();
00295 return;
00296 }
00297 }
00298
00299
00300 this->selected = NULL;
00301 this->list_pos = 0;
00302 }
00303
00305 void ScrollToSelected()
00306 {
00307 if (this->selected == NULL) return;
00308
00309 if (this->list_pos < this->vscroll.pos) {
00310
00311 this->vscroll.pos = this->list_pos;
00312 } else if (this->list_pos >= this->vscroll.pos + this->vscroll.cap) {
00313
00314 this->vscroll.pos = this->list_pos - this->vscroll.cap + 1;
00315 }
00316 }
00317
00318 public:
00323 NetworkContentListWindow(const WindowDesc *desc, bool select_all) : QueryStringBaseWindow(EDITBOX_MAX_SIZE, desc, 1), selected(NULL), list_pos(0)
00324 {
00325 ttd_strlcpy(this->edit_str_buf, "", this->edit_str_size);
00326 this->afilter = CS_ALPHANUMERAL;
00327 InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, EDITBOX_MAX_LENGTH);
00328 this->SetFocusedWidget(NCLWW_FILTER);
00329
00330 this->vscroll.cap = 14;
00331 this->resize.step_height = 14;
00332 this->resize.step_width = 2;
00333
00334 _network_content_client.AddCallback(this);
00335 this->HideWidget(select_all ? NCLWW_SELECT_UPDATE : NCLWW_SELECT_ALL);
00336
00337 this->content.SetListing(this->last_sorting);
00338 this->content.SetFiltering(this->last_filtering);
00339 this->content.SetSortFuncs(this->sorter_funcs);
00340 this->content.SetFilterFuncs(this->filter_funcs);
00341 this->content.ForceRebuild();
00342 this->FilterContentList();
00343 this->SortContentList();
00344
00345 SetVScrollCount(this, this->content.Length());
00346 this->FindWindowPlacementAndResize(desc);
00347 }
00348
00350 ~NetworkContentListWindow()
00351 {
00352 _network_content_client.RemoveCallback(this);
00353 }
00354
00355 virtual void OnPaint()
00356 {
00357 const SortButtonState arrow = this->content.IsDescSortOrder() ? SBS_DOWN : SBS_UP;
00358
00359 if (this->content.NeedRebuild()) {
00360 this->BuildContentList();
00361 SetVScrollCount(this, this->content.Length());
00362 }
00363 this->SortContentList();
00364
00365
00366 uint filesize = 0;
00367 bool show_select_all = false;
00368 bool show_select_upgrade = false;
00369 for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) {
00370 const ContentInfo *ci = *iter;
00371 switch (ci->state) {
00372 case ContentInfo::SELECTED:
00373 case ContentInfo::AUTOSELECTED:
00374 filesize += ci->filesize;
00375 break;
00376
00377 case ContentInfo::UNSELECTED:
00378 show_select_all = true;
00379 show_select_upgrade |= ci->upgrade;
00380 break;
00381
00382 default:
00383 break;
00384 }
00385 }
00386
00387 this->SetWidgetDisabledState(NCLWW_DOWNLOAD, filesize == 0 || FindWindowById(WC_NETWORK_STATUS_WINDOW, 0) != NULL);
00388 this->SetWidgetDisabledState(NCLWW_UNSELECT, filesize == 0);
00389 this->SetWidgetDisabledState(NCLWW_SELECT_ALL, !show_select_all);
00390 this->SetWidgetDisabledState(NCLWW_SELECT_UPDATE, !show_select_upgrade);
00391
00392 this->widget[NCLWW_CANCEL].data = filesize == 0 ? STR_AI_CLOSE : STR_AI_CANCEL;
00393
00394 this->DrawWidgets();
00395
00396
00397 this->DrawEditBox(NCLWW_FILTER);
00398 DrawStringRightAligned(this->widget[NCLWW_FILTER].left - 8, this->widget[NCLWW_FILTER].top + 2, STR_CONTENT_FILTER_TITLE, TC_FROMSTRING);
00399
00400 switch (this->content.SortType()) {
00401 case NCLWW_CHECKBOX - NCLWW_CHECKBOX: this->DrawSortButtonState(NCLWW_CHECKBOX, arrow); break;
00402 case NCLWW_TYPE - NCLWW_CHECKBOX: this->DrawSortButtonState(NCLWW_TYPE, arrow); break;
00403 case NCLWW_NAME - NCLWW_CHECKBOX: this->DrawSortButtonState(NCLWW_NAME, arrow); break;
00404 }
00405
00406
00407 uint y = this->widget[NCLWW_MATRIX].top + 3;
00408 int cnt = 0;
00409 for (ConstContentIterator iter = this->content.Get(this->vscroll.pos); iter != this->content.End() && cnt < this->vscroll.cap; iter++, cnt++) {
00410 const ContentInfo *ci = *iter;
00411
00412 if (ci == this->selected) GfxFillRect(this->widget[NCLWW_CHECKBOX].left + 1, y - 2, this->widget[NCLWW_NAME].right - 1, y + 9, 10);
00413
00414 SpriteID sprite;
00415 SpriteID pal = PAL_NONE;
00416 switch (ci->state) {
00417 case ContentInfo::UNSELECTED: sprite = SPR_BOX_EMPTY; break;
00418 case ContentInfo::SELECTED: sprite = SPR_BOX_CHECKED; break;
00419 case ContentInfo::AUTOSELECTED: sprite = SPR_BOX_CHECKED; break;
00420 case ContentInfo::ALREADY_HERE: sprite = SPR_BLOT; pal = PALETTE_TO_GREEN; break;
00421 case ContentInfo::DOES_NOT_EXIST: sprite = SPR_BLOT; pal = PALETTE_TO_RED; break;
00422 default: NOT_REACHED();
00423 }
00424 DrawSprite(sprite, pal, this->widget[NCLWW_CHECKBOX].left + (pal == PAL_NONE ? 3 : 4), y + (pal == PAL_NONE ? 1 : 0));
00425
00426 StringID str = STR_CONTENT_TYPE_BASE_GRAPHICS + ci->type - CONTENT_TYPE_BASE_GRAPHICS;
00427 DrawStringCenteredTruncated(this->widget[NCLWW_TYPE].left, this->widget[NCLWW_TYPE].right, y, str, TC_BLACK);
00428
00429 SetDParamStr(0, ci->name);
00430 DrawStringTruncated(this->widget[NCLWW_NAME].left + 5, y, STR_JUST_RAW_STRING, TC_BLACK, this->widget[NCLWW_NAME].right - this->widget[NCLWW_NAME].left - 5);
00431 y += this->resize.step_height;
00432 }
00433
00434
00435 GfxFillRect(this->widget[NCLWW_DETAILS].left + 1, this->widget[NCLWW_DETAILS].top + 1, this->widget[NCLWW_DETAILS].right - 1, this->widget[NCLWW_DETAILS].top + 50, 157);
00436 DrawStringCentered((this->widget[NCLWW_DETAILS].left + this->widget[NCLWW_DETAILS].right) / 2, this->widget[NCLWW_DETAILS].top + 11, STR_CONTENT_DETAIL_TITLE, TC_FROMSTRING);
00437
00438 if (this->selected == NULL) return;
00439
00440
00441 DrawStringMultiCenter((this->widget[NCLWW_DETAILS].left + this->widget[NCLWW_DETAILS].right) / 2, this->widget[NCLWW_DETAILS].top + 32, STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED + this->selected->state, this->widget[NCLWW_DETAILS].right - this->widget[NCLWW_DETAILS].left - 10);
00442
00443
00444 const uint max_y = this->widget[NCLWW_DETAILS].bottom - 15;
00445 y = this->widget[NCLWW_DETAILS].top + 55;
00446
00447 if (this->selected->upgrade) {
00448 SetDParam(0, STR_CONTENT_TYPE_BASE_GRAPHICS + this->selected->type - CONTENT_TYPE_BASE_GRAPHICS);
00449 y += DrawStringMultiLine(this->widget[NCLWW_DETAILS].left + 5, y, STR_CONTENT_DETAIL_UPDATE, this->widget[NCLWW_DETAILS].right - this->widget[NCLWW_DETAILS].left - 5, max_y - y);
00450 y += 11;
00451 }
00452
00453 SetDParamStr(0, this->selected->name);
00454 y += DrawStringMultiLine(this->widget[NCLWW_DETAILS].left + 5, y, STR_CONTENT_DETAIL_NAME, this->widget[NCLWW_DETAILS].right - this->widget[NCLWW_DETAILS].left - 5, max_y - y);
00455
00456 if (!StrEmpty(this->selected->version)) {
00457 SetDParamStr(0, this->selected->version);
00458 y += DrawStringMultiLine(this->widget[NCLWW_DETAILS].left + 5, y, STR_CONTENT_DETAIL_VERSION, this->widget[NCLWW_DETAILS].right - this->widget[NCLWW_DETAILS].left - 5, max_y - y);
00459 }
00460
00461 if (!StrEmpty(this->selected->description)) {
00462 SetDParamStr(0, this->selected->description);
00463 y += DrawStringMultiLine(this->widget[NCLWW_DETAILS].left + 5, y, STR_CONTENT_DETAIL_DESCRIPTION, this->widget[NCLWW_DETAILS].right - this->widget[NCLWW_DETAILS].left - 5, max_y - y);
00464 }
00465
00466 if (!StrEmpty(this->selected->url)) {
00467 SetDParamStr(0, this->selected->url);
00468 y += DrawStringMultiLine(this->widget[NCLWW_DETAILS].left + 5, y, STR_CONTENT_DETAIL_URL, this->widget[NCLWW_DETAILS].right - this->widget[NCLWW_DETAILS].left - 5, max_y - y);
00469 }
00470
00471 SetDParam(0, STR_CONTENT_TYPE_BASE_GRAPHICS + this->selected->type - CONTENT_TYPE_BASE_GRAPHICS);
00472 y += DrawStringMultiLine(this->widget[NCLWW_DETAILS].left + 5, y, STR_CONTENT_DETAIL_TYPE, this->widget[NCLWW_DETAILS].right - this->widget[NCLWW_DETAILS].left - 5, max_y - y);
00473
00474 y += 11;
00475 SetDParam(0, this->selected->filesize);
00476 y += DrawStringMultiLine(this->widget[NCLWW_DETAILS].left + 5, y, STR_CONTENT_DETAIL_FILESIZE, this->widget[NCLWW_DETAILS].right - this->widget[NCLWW_DETAILS].left - 5, max_y - y);
00477
00478 if (this->selected->dependency_count != 0) {
00479
00480 char buf[8192] = "";
00481 char *p = buf;
00482 for (uint i = 0; i < this->selected->dependency_count; i++) {
00483 ContentID cid = this->selected->dependencies[i];
00484
00485
00486 ConstContentIterator iter = _network_content_client.Begin();
00487 for (; iter != _network_content_client.End(); iter++) {
00488 const ContentInfo *ci = *iter;
00489 if (ci->id != cid) continue;
00490
00491 p += seprintf(p, lastof(buf), p == buf ? "%s" : ", %s", (*iter)->name);
00492 break;
00493 }
00494 }
00495 SetDParamStr(0, buf);
00496 y += DrawStringMultiLine(this->widget[NCLWW_DETAILS].left + 5, y, STR_CONTENT_DETAIL_DEPENDENCIES, this->widget[NCLWW_DETAILS].right - this->widget[NCLWW_DETAILS].left - 5, max_y - y);
00497 }
00498
00499 if (this->selected->tag_count != 0) {
00500
00501 char buf[8192] = "";
00502 char *p = buf;
00503 for (uint i = 0; i < this->selected->tag_count; i++) {
00504 p += seprintf(p, lastof(buf), i == 0 ? "%s" : ", %s", this->selected->tags[i]);
00505 }
00506 SetDParamStr(0, buf);
00507 y += DrawStringMultiLine(this->widget[NCLWW_DETAILS].left + 5, y, STR_CONTENT_DETAIL_TAGS, this->widget[NCLWW_DETAILS].right - this->widget[NCLWW_DETAILS].left - 5, max_y - y);
00508 }
00509
00510 if (this->selected->IsSelected()) {
00511
00512 ConstContentVector tree;
00513 _network_content_client.ReverseLookupTreeDependency(tree, this->selected);
00514
00515 char buf[8192] = "";
00516 char *p = buf;
00517 for (ConstContentIterator iter = tree.Begin(); iter != tree.End(); iter++) {
00518 const ContentInfo *ci = *iter;
00519 if (ci == this->selected || ci->state != ContentInfo::SELECTED) continue;
00520
00521 p += seprintf(p, lastof(buf), buf == p ? "%s" : ", %s", ci->name);
00522 }
00523 if (p != buf) {
00524 SetDParamStr(0, buf);
00525 y += DrawStringMultiLine(this->widget[NCLWW_DETAILS].left + 5, y, STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF, this->widget[NCLWW_DETAILS].right - this->widget[NCLWW_DETAILS].left - 5, max_y - y);
00526 }
00527 }
00528
00529
00530 SetDParam(0, filesize);
00531 DrawString(this->widget[NCLWW_DETAILS].left + 5, this->widget[NCLWW_DETAILS].bottom - 12, STR_CONTENT_TOTAL_DOWNLOAD_SIZE, TC_BLACK);
00532 }
00533
00534 virtual void OnDoubleClick(Point pt, int widget)
00535 {
00536
00537 if (widget != NCLWW_MATRIX) return;
00538
00539 pt.x = this->widget[NCLWW_CHECKBOX].left;
00540 this->OnClick(pt, widget);
00541 }
00542
00543 virtual void OnClick(Point pt, int widget)
00544 {
00545 switch (widget) {
00546 case NCLWW_MATRIX: {
00547 uint32 id_v = (pt.y - this->widget[NCLWW_MATRIX].top) / this->resize.step_height;
00548
00549 if (id_v >= this->vscroll.cap) return;
00550 id_v += this->vscroll.pos;
00551
00552 if (id_v >= this->content.Length()) return;
00553
00554 this->selected = *this->content.Get(id_v);
00555 this->list_pos = id_v;
00556
00557 if (pt.x <= this->widget[NCLWW_CHECKBOX].right) {
00558 _network_content_client.ToggleSelectedState(this->selected);
00559 this->content.ForceResort();
00560 }
00561
00562 this->SetDirty();
00563 } break;
00564
00565 case NCLWW_CHECKBOX:
00566 case NCLWW_TYPE:
00567 case NCLWW_NAME:
00568 if (this->content.SortType() == widget - NCLWW_CHECKBOX) {
00569 this->content.ToggleSortOrder();
00570 this->list_pos = this->content.Length() - this->list_pos - 1;
00571 } else {
00572 this->content.SetSortType(widget - NCLWW_CHECKBOX);
00573 this->content.ForceResort();
00574 this->SortContentList();
00575 }
00576 this->ScrollToSelected();
00577 this->SetDirty();
00578 break;
00579
00580 case NCLWW_SELECT_ALL:
00581 _network_content_client.SelectAll();
00582 this->SetDirty();
00583 break;
00584
00585 case NCLWW_SELECT_UPDATE:
00586 _network_content_client.SelectUpgrade();
00587 this->SetDirty();
00588 break;
00589
00590 case NCLWW_UNSELECT:
00591 _network_content_client.UnselectAll();
00592 this->SetDirty();
00593 break;
00594
00595 case NCLWW_CANCEL:
00596 delete this;
00597 break;
00598
00599 case NCLWW_DOWNLOAD:
00600 if (BringWindowToFrontById(WC_NETWORK_STATUS_WINDOW, 0) == NULL) new NetworkContentDownloadStatusWindow();
00601 break;
00602 }
00603 }
00604
00605 virtual void OnMouseLoop()
00606 {
00607 this->HandleEditBox(NCLWW_FILTER);
00608 }
00609
00610 virtual EventState OnKeyPress(uint16 key, uint16 keycode)
00611 {
00612 switch (keycode) {
00613 case WKC_UP:
00614
00615 if (this->list_pos > 0) this->list_pos--;
00616 break;
00617 case WKC_DOWN:
00618
00619 if (this->list_pos < (int)this->content.Length() - 1) this->list_pos++;
00620 break;
00621 case WKC_PAGEUP:
00622
00623 this->list_pos = (this->list_pos < this->vscroll.cap) ? 0 : this->list_pos - this->vscroll.cap;
00624 break;
00625 case WKC_PAGEDOWN:
00626
00627 this->list_pos = min(this->list_pos + this->vscroll.cap, (int)this->content.Length() - 1);
00628 break;
00629 case WKC_HOME:
00630
00631 this->list_pos = 0;
00632 break;
00633 case WKC_END:
00634
00635 this->list_pos = this->content.Length() - 1;
00636 break;
00637
00638 case WKC_SPACE:
00639 case WKC_RETURN:
00640 if (keycode == WKC_RETURN || !IsWidgetFocused(NCLWW_FILTER)) {
00641 if (this->selected != NULL) {
00642 _network_content_client.ToggleSelectedState(this->selected);
00643 this->content.ForceResort();
00644 this->SetDirty();
00645 }
00646 return ES_HANDLED;
00647 }
00648
00649
00650 default: {
00651
00652 EventState state = ES_NOT_HANDLED;
00653 if (this->HandleEditBoxKey(NCLWW_FILTER, key, keycode, state) == HEBR_EDITING) {
00654 this->OnOSKInput(NCLWW_FILTER);
00655 }
00656
00657 return state;
00658 }
00659 }
00660
00661 if (_network_content_client.Length() == 0) return ES_HANDLED;
00662
00663 this->selected = *this->content.Get(this->list_pos);
00664
00665
00666 this->ScrollToSelected();
00667
00668
00669 this->SetDirty();
00670 return ES_HANDLED;
00671 }
00672
00673 virtual void OnOSKInput(int wid)
00674 {
00675 this->content.SetFilterState(!StrEmpty(this->edit_str_buf));
00676 this->content.ForceRebuild();
00677 this->SetDirty();
00678 }
00679
00680 virtual void OnResize(Point new_size, Point delta)
00681 {
00682 this->vscroll.cap += delta.y / (int)this->resize.step_height;
00683
00684 this->widget[NCLWW_MATRIX].data = (this->vscroll.cap << 8) + 1;
00685
00686 SetVScrollCount(this, this->content.Length());
00687
00688
00689 delta.x /= 2;
00690 this->widget[NCLWW_NAME].right -= delta.x;
00691 this->widget[NCLWW_MATRIX].right -= delta.x;
00692 this->widget[NCLWW_SCROLLBAR].left -= delta.x;
00693 this->widget[NCLWW_SCROLLBAR].right -= delta.x;
00694 this->widget[NCLWW_DETAILS].left -= delta.x;
00695 }
00696
00697 virtual void OnReceiveContentInfo(const ContentInfo *rci)
00698 {
00699 this->content.ForceRebuild();
00700 this->SetDirty();
00701 }
00702
00703 virtual void OnDownloadComplete(ContentID cid)
00704 {
00705 this->content.ForceResort();
00706 this->SetDirty();
00707 }
00708
00709 virtual void OnConnect(bool success)
00710 {
00711 if (!success) {
00712 ShowErrorMessage(INVALID_STRING_ID, STR_CONTENT_ERROR_COULD_NOT_CONNECT, 0, 0);
00713 delete this;
00714 }
00715
00716 this->SetDirty();
00717 }
00718 };
00719
00720 Listing NetworkContentListWindow::last_sorting = {false, 1};
00721 Filtering NetworkContentListWindow::last_filtering = {false, 0};
00722
00723 NetworkContentListWindow::GUIContentList::SortFunction * const NetworkContentListWindow::sorter_funcs[] = {
00724 &StateSorter,
00725 &TypeSorter,
00726 &NameSorter,
00727 };
00728
00729 NetworkContentListWindow::GUIContentList::FilterFunction * const NetworkContentListWindow::filter_funcs[] = {
00730 &TagNameFilter,
00731 };
00732
00734 static const Widget _network_content_list_widgets[] = {
00735
00736 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_LIGHT_BLUE, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00737 { WWT_CAPTION, RESIZE_RIGHT, COLOUR_LIGHT_BLUE, 11, 449, 0, 13, STR_CONTENT_TITLE, STR_NULL},
00738 { WWT_PANEL, RESIZE_RB, COLOUR_LIGHT_BLUE, 0, 449, 14, 277, 0x0, STR_NULL},
00739
00740 { WWT_EDITBOX, RESIZE_LR, COLOUR_LIGHT_BLUE, 210, 440, 20, 31, STR_CONTENT_FILTER_OSKTITLE, STR_CONTENT_FILTER_TIP},
00741
00742
00743 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 8, 20, 36, 47, STR_EMPTY, STR_NULL},
00744 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 21, 110, 36, 47, STR_CONTENT_TYPE_CAPTION, STR_CONTENT_TYPE_CAPTION_TIP},
00745 { WWT_PUSHTXTBTN, RESIZE_RIGHT, COLOUR_WHITE, 111, 190, 36, 47, STR_CONTENT_NAME_CAPTION, STR_CONTENT_NAME_CAPTION_TIP},
00746
00747 { WWT_MATRIX, RESIZE_RB, COLOUR_LIGHT_BLUE, 8, 190, 48, 244, (14 << 8) | 1, STR_CONTENT_MATRIX_TIP},
00748 { WWT_SCROLLBAR, RESIZE_LRB, COLOUR_LIGHT_BLUE, 191, 202, 36, 244, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00749
00750
00751 { WWT_PANEL, RESIZE_LRB, COLOUR_LIGHT_BLUE, 210, 440, 36, 244, 0x0, STR_NULL},
00752
00753
00754 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 10, 110, 252, 263, STR_CONTENT_SELECT_ALL_CAPTION, STR_CONTENT_SELECT_ALL_CAPTION_TIP},
00755 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 10, 110, 252, 263, STR_CONTENT_SELECT_UPDATES_CAPTION, STR_CONTENT_SELECT_UPDATES_CAPTION_TIP},
00756 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 118, 218, 252, 263, STR_CONTENT_UNSELECT_ALL_CAPTION, STR_CONTENT_UNSELECT_ALL_CAPTION_TIP},
00757 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_WHITE, 226, 326, 252, 263, STR_012E_CANCEL, STR_NULL},
00758 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_WHITE, 334, 434, 252, 263, STR_CONTENT_DOWNLOAD_CAPTION, STR_CONTENT_DOWNLOAD_CAPTION_TIP},
00759
00760 { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_LIGHT_BLUE, 438, 449, 266, 277, 0x0, STR_RESIZE_BUTTON },
00761
00762 { WIDGETS_END},
00763 };
00764
00766 static const WindowDesc _network_content_list_desc(
00767 WDP_CENTER, WDP_CENTER, 450, 278, 630, 460,
00768 WC_NETWORK_WINDOW, WC_NONE,
00769 WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
00770 _network_content_list_widgets
00771 );
00772
00778 void ShowNetworkContentListWindow(ContentVector *cv, ContentType type)
00779 {
00780 #if defined(WITH_ZLIB)
00781 _network_content_client.Clear();
00782 if (cv == NULL) {
00783 _network_content_client.RequestContentList(type);
00784 } else {
00785 _network_content_client.RequestContentList(cv, true);
00786 }
00787
00788 DeleteWindowById(WC_NETWORK_WINDOW, 1);
00789 new NetworkContentListWindow(&_network_content_list_desc, cv != NULL);
00790 #else
00791 ShowErrorMessage(STR_CONTENT_NO_ZLIB_SUB, STR_CONTENT_NO_ZLIB, 0, 0);
00792
00793 if (cv != NULL) {
00794 for (ContentIterator iter = cv->Begin(); iter != cv->End(); iter++) delete *iter;
00795 }
00796 #endif
00797 }
00798
00799 #endif