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