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