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, 1, 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 - 40LL) * 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 * 100LL / 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, 1), 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 || FindWindowById(WC_NETWORK_STATUS_WINDOW, 0) != NULL);
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->widget[NCLWW_CANCEL].data = filesize == 0 ? STR_AI_CLOSE : STR_AI_CANCEL;
00392
00393 this->DrawWidgets();
00394
00395
00396 this->DrawEditBox(NCLWW_FILTER);
00397 DrawStringRightAligned(this->widget[NCLWW_FILTER].left - 8, this->widget[NCLWW_FILTER].top + 2, STR_CONTENT_FILTER_TITLE, TC_FROMSTRING);
00398
00399 switch (this->content.SortType()) {
00400 case NCLWW_CHECKBOX - NCLWW_CHECKBOX: this->DrawSortButtonState(NCLWW_CHECKBOX, arrow); break;
00401 case NCLWW_TYPE - NCLWW_CHECKBOX: this->DrawSortButtonState(NCLWW_TYPE, arrow); break;
00402 case NCLWW_NAME - NCLWW_CHECKBOX: this->DrawSortButtonState(NCLWW_NAME, arrow); break;
00403 }
00404
00405
00406 uint y = this->widget[NCLWW_MATRIX].top + 3;
00407 int cnt = 0;
00408 for (ConstContentIterator iter = this->content.Get(this->vscroll.pos); iter != this->content.End() && cnt < this->vscroll.cap; iter++, cnt++) {
00409 const ContentInfo *ci = *iter;
00410
00411 if (ci == this->selected) GfxFillRect(this->widget[NCLWW_CHECKBOX].left + 1, y - 2, this->widget[NCLWW_NAME].right - 1, y + 9, 10);
00412
00413 SpriteID sprite;
00414 SpriteID pal = PAL_NONE;
00415 switch (ci->state) {
00416 case ContentInfo::UNSELECTED: sprite = SPR_BOX_EMPTY; break;
00417 case ContentInfo::SELECTED: sprite = SPR_BOX_CHECKED; break;
00418 case ContentInfo::AUTOSELECTED: sprite = SPR_BOX_CHECKED; break;
00419 case ContentInfo::ALREADY_HERE: sprite = SPR_BLOT; pal = PALETTE_TO_GREEN; break;
00420 case ContentInfo::DOES_NOT_EXIST: sprite = SPR_BLOT; pal = PALETTE_TO_RED; break;
00421 default: NOT_REACHED();
00422 }
00423 DrawSprite(sprite, pal, this->widget[NCLWW_CHECKBOX].left + (pal == PAL_NONE ? 3 : 4), y + (pal == PAL_NONE ? 1 : 0));
00424
00425 StringID str = STR_CONTENT_TYPE_BASE_GRAPHICS + ci->type - CONTENT_TYPE_BASE_GRAPHICS;
00426 DrawStringCenteredTruncated(this->widget[NCLWW_TYPE].left, this->widget[NCLWW_TYPE].right, y, str, TC_BLACK);
00427
00428 SetDParamStr(0, ci->name);
00429 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);
00430 y += this->resize.step_height;
00431 }
00432
00433
00434 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);
00435 DrawStringCentered((this->widget[NCLWW_DETAILS].left + this->widget[NCLWW_DETAILS].right) / 2, this->widget[NCLWW_DETAILS].top + 11, STR_CONTENT_DETAIL_TITLE, TC_FROMSTRING);
00436
00437 if (this->selected == NULL) return;
00438
00439
00440 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);
00441
00442
00443 const uint max_y = this->widget[NCLWW_DETAILS].bottom - 15;
00444 y = this->widget[NCLWW_DETAILS].top + 55;
00445
00446 if (this->selected->upgrade) {
00447 SetDParam(0, STR_CONTENT_TYPE_BASE_GRAPHICS + this->selected->type - CONTENT_TYPE_BASE_GRAPHICS);
00448 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);
00449 y += 11;
00450 }
00451
00452 SetDParamStr(0, this->selected->name);
00453 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);
00454
00455 if (!StrEmpty(this->selected->version)) {
00456 SetDParamStr(0, this->selected->version);
00457 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);
00458 }
00459
00460 if (!StrEmpty(this->selected->description)) {
00461 SetDParamStr(0, this->selected->description);
00462 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);
00463 }
00464
00465 if (!StrEmpty(this->selected->url)) {
00466 SetDParamStr(0, this->selected->url);
00467 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);
00468 }
00469
00470 SetDParam(0, STR_CONTENT_TYPE_BASE_GRAPHICS + this->selected->type - CONTENT_TYPE_BASE_GRAPHICS);
00471 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);
00472
00473 y += 11;
00474 SetDParam(0, this->selected->filesize);
00475 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);
00476
00477 if (this->selected->dependency_count != 0) {
00478
00479 char buf[8192] = "";
00480 char *p = buf;
00481 for (uint i = 0; i < this->selected->dependency_count; i++) {
00482 ContentID cid = this->selected->dependencies[i];
00483
00484
00485 ConstContentIterator iter = _network_content_client.Begin();
00486 for (; iter != _network_content_client.End(); iter++) {
00487 const ContentInfo *ci = *iter;
00488 if (ci->id != cid) continue;
00489
00490 p += seprintf(p, lastof(buf), p == buf ? "%s" : ", %s", (*iter)->name);
00491 break;
00492 }
00493 }
00494 SetDParamStr(0, buf);
00495 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);
00496 }
00497
00498 if (this->selected->tag_count != 0) {
00499
00500 char buf[8192] = "";
00501 char *p = buf;
00502 for (uint i = 0; i < this->selected->tag_count; i++) {
00503 p += seprintf(p, lastof(buf), i == 0 ? "%s" : ", %s", this->selected->tags[i]);
00504 }
00505 SetDParamStr(0, buf);
00506 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);
00507 }
00508
00509 if (this->selected->IsSelected()) {
00510
00511 ConstContentVector tree;
00512 _network_content_client.ReverseLookupTreeDependency(tree, this->selected);
00513
00514 char buf[8192] = "";
00515 char *p = buf;
00516 for (ConstContentIterator iter = tree.Begin(); iter != tree.End(); iter++) {
00517 const ContentInfo *ci = *iter;
00518 if (ci == this->selected || ci->state != ContentInfo::SELECTED) continue;
00519
00520 p += seprintf(p, lastof(buf), buf == p ? "%s" : ", %s", ci->name);
00521 }
00522 if (p != buf) {
00523 SetDParamStr(0, buf);
00524 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);
00525 }
00526 }
00527
00528
00529 SetDParam(0, filesize);
00530 DrawString(this->widget[NCLWW_DETAILS].left + 5, this->widget[NCLWW_DETAILS].bottom - 12, STR_CONTENT_TOTAL_DOWNLOAD_SIZE, TC_BLACK);
00531 }
00532
00533 virtual void OnDoubleClick(Point pt, int widget)
00534 {
00535
00536 if (widget != NCLWW_MATRIX) return;
00537
00538 pt.x = this->widget[NCLWW_CHECKBOX].left;
00539 this->OnClick(pt, widget);
00540 }
00541
00542 virtual void OnClick(Point pt, int widget)
00543 {
00544 switch (widget) {
00545 case NCLWW_MATRIX: {
00546 uint32 id_v = (pt.y - this->widget[NCLWW_MATRIX].top) / this->resize.step_height;
00547
00548 if (id_v >= this->vscroll.cap) return;
00549 id_v += this->vscroll.pos;
00550
00551 if (id_v >= this->content.Length()) return;
00552
00553 this->selected = *this->content.Get(id_v);
00554 this->list_pos = id_v;
00555
00556 if (pt.x <= this->widget[NCLWW_CHECKBOX].right) {
00557 _network_content_client.ToggleSelectedState(this->selected);
00558 this->content.ForceResort();
00559 }
00560
00561 this->SetDirty();
00562 } break;
00563
00564 case NCLWW_CHECKBOX:
00565 case NCLWW_TYPE:
00566 case NCLWW_NAME:
00567 if (this->content.SortType() == widget - NCLWW_CHECKBOX) {
00568 this->content.ToggleSortOrder();
00569 this->list_pos = this->content.Length() - this->list_pos - 1;
00570 } else {
00571 this->content.SetSortType(widget - NCLWW_CHECKBOX);
00572 this->content.ForceResort();
00573 this->SortContentList();
00574 }
00575 this->ScrollToSelected();
00576 this->SetDirty();
00577 break;
00578
00579 case NCLWW_SELECT_ALL:
00580 _network_content_client.SelectAll();
00581 this->SetDirty();
00582 break;
00583
00584 case NCLWW_SELECT_UPDATE:
00585 _network_content_client.SelectUpgrade();
00586 this->SetDirty();
00587 break;
00588
00589 case NCLWW_UNSELECT:
00590 _network_content_client.UnselectAll();
00591 this->SetDirty();
00592 break;
00593
00594 case NCLWW_CANCEL:
00595 delete this;
00596 break;
00597
00598 case NCLWW_DOWNLOAD:
00599 if (BringWindowToFrontById(WC_NETWORK_STATUS_WINDOW, 0) == NULL) new NetworkContentDownloadStatusWindow();
00600 break;
00601 }
00602 }
00603
00604 virtual void OnMouseLoop()
00605 {
00606 this->HandleEditBox(NCLWW_FILTER);
00607 }
00608
00609 virtual EventState OnKeyPress(uint16 key, uint16 keycode)
00610 {
00611 switch (keycode) {
00612 case WKC_UP:
00613
00614 if (this->list_pos > 0) this->list_pos--;
00615 break;
00616 case WKC_DOWN:
00617
00618 if (this->list_pos < (int)this->content.Length() - 1) this->list_pos++;
00619 break;
00620 case WKC_PAGEUP:
00621
00622 this->list_pos = (this->list_pos < this->vscroll.cap) ? 0 : this->list_pos - this->vscroll.cap;
00623 break;
00624 case WKC_PAGEDOWN:
00625
00626 this->list_pos = min(this->list_pos + this->vscroll.cap, (int)this->content.Length() - 1);
00627 break;
00628 case WKC_HOME:
00629
00630 this->list_pos = 0;
00631 break;
00632 case WKC_END:
00633
00634 this->list_pos = this->content.Length() - 1;
00635 break;
00636
00637 case WKC_SPACE:
00638 case WKC_RETURN:
00639 if (keycode == WKC_RETURN || !IsWidgetFocused(NCLWW_FILTER)) {
00640 if (this->selected != NULL) {
00641 _network_content_client.ToggleSelectedState(this->selected);
00642 this->content.ForceResort();
00643 this->SetDirty();
00644 }
00645 return ES_HANDLED;
00646 }
00647
00648
00649 default: {
00650
00651 EventState state = ES_NOT_HANDLED;
00652 if (this->HandleEditBoxKey(NCLWW_FILTER, key, keycode, state) == HEBR_EDITING) {
00653 this->OnOSKInput(NCLWW_FILTER);
00654 }
00655
00656 return state;
00657 }
00658 }
00659
00660 if (_network_content_client.Length() == 0) return ES_HANDLED;
00661
00662 this->selected = *this->content.Get(this->list_pos);
00663
00664
00665 this->ScrollToSelected();
00666
00667
00668 this->SetDirty();
00669 return ES_HANDLED;
00670 }
00671
00672 virtual void OnOSKInput(int wid)
00673 {
00674 this->content.SetFilterState(!StrEmpty(this->edit_str_buf));
00675 this->content.ForceRebuild();
00676 this->SetDirty();
00677 }
00678
00679 virtual void OnResize(Point new_size, Point delta)
00680 {
00681 this->vscroll.cap += delta.y / (int)this->resize.step_height;
00682
00683 this->widget[NCLWW_MATRIX].data = (this->vscroll.cap << 8) + 1;
00684
00685 SetVScrollCount(this, this->content.Length());
00686
00687
00688 delta.x /= 2;
00689 this->widget[NCLWW_NAME].right -= delta.x;
00690 this->widget[NCLWW_MATRIX].right -= delta.x;
00691 this->widget[NCLWW_SCROLLBAR].left -= delta.x;
00692 this->widget[NCLWW_SCROLLBAR].right -= delta.x;
00693 this->widget[NCLWW_DETAILS].left -= delta.x;
00694 }
00695
00696 virtual void OnReceiveContentInfo(const ContentInfo *rci)
00697 {
00698 this->content.ForceRebuild();
00699 this->SetDirty();
00700 }
00701
00702 virtual void OnDownloadComplete(ContentID cid)
00703 {
00704 this->content.ForceResort();
00705 this->SetDirty();
00706 }
00707
00708 virtual void OnConnect(bool success)
00709 {
00710 if (!success) {
00711 ShowErrorMessage(INVALID_STRING_ID, STR_CONTENT_ERROR_COULD_NOT_CONNECT, 0, 0);
00712 delete this;
00713 }
00714
00715 this->SetDirty();
00716 }
00717 };
00718
00719 Listing NetworkContentListWindow::last_sorting = {false, 1};
00720 Filtering NetworkContentListWindow::last_filtering = {false, 0};
00721
00722 NetworkContentListWindow::GUIContentList::SortFunction * const NetworkContentListWindow::sorter_funcs[] = {
00723 &StateSorter,
00724 &TypeSorter,
00725 &NameSorter,
00726 };
00727
00728 NetworkContentListWindow::GUIContentList::FilterFunction * const NetworkContentListWindow::filter_funcs[] = {
00729 &TagNameFilter,
00730 };
00731
00733 static const Widget _network_content_list_widgets[] = {
00734
00735 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_LIGHT_BLUE, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00736 { WWT_CAPTION, RESIZE_RIGHT, COLOUR_LIGHT_BLUE, 11, 449, 0, 13, STR_CONTENT_TITLE, STR_NULL},
00737 { WWT_PANEL, RESIZE_RB, COLOUR_LIGHT_BLUE, 0, 449, 14, 277, 0x0, STR_NULL},
00738
00739 { WWT_EDITBOX, RESIZE_LR, COLOUR_LIGHT_BLUE, 210, 440, 20, 31, STR_CONTENT_FILTER_OSKTITLE, STR_CONTENT_FILTER_TIP},
00740
00741
00742 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 8, 20, 36, 47, STR_EMPTY, STR_NULL},
00743 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 21, 110, 36, 47, STR_CONTENT_TYPE_CAPTION, STR_CONTENT_TYPE_CAPTION_TIP},
00744 { WWT_PUSHTXTBTN, RESIZE_RIGHT, COLOUR_WHITE, 111, 190, 36, 47, STR_CONTENT_NAME_CAPTION, STR_CONTENT_NAME_CAPTION_TIP},
00745
00746 { WWT_MATRIX, RESIZE_RB, COLOUR_LIGHT_BLUE, 8, 190, 48, 244, (14 << 8) | 1, STR_CONTENT_MATRIX_TIP},
00747 { WWT_SCROLLBAR, RESIZE_LRB, COLOUR_LIGHT_BLUE, 191, 202, 36, 244, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00748
00749
00750 { WWT_PANEL, RESIZE_LRB, COLOUR_LIGHT_BLUE, 210, 440, 36, 244, 0x0, STR_NULL},
00751
00752
00753 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 10, 110, 252, 263, STR_CONTENT_SELECT_ALL_CAPTION, STR_CONTENT_SELECT_ALL_CAPTION_TIP},
00754 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 10, 110, 252, 263, STR_CONTENT_SELECT_UPDATES_CAPTION, STR_CONTENT_SELECT_UPDATES_CAPTION_TIP},
00755 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 118, 218, 252, 263, STR_CONTENT_UNSELECT_ALL_CAPTION, STR_CONTENT_UNSELECT_ALL_CAPTION_TIP},
00756 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_WHITE, 226, 326, 252, 263, STR_012E_CANCEL, STR_NULL},
00757 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_WHITE, 334, 434, 252, 263, STR_CONTENT_DOWNLOAD_CAPTION, STR_CONTENT_DOWNLOAD_CAPTION_TIP},
00758
00759 { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_LIGHT_BLUE, 438, 449, 266, 277, 0x0, STR_RESIZE_BUTTON },
00760
00761 { WIDGETS_END},
00762 };
00763
00765 static const WindowDesc _network_content_list_desc(
00766 WDP_CENTER, WDP_CENTER, 450, 278, 630, 460,
00767 WC_NETWORK_WINDOW, WC_NONE,
00768 WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
00769 _network_content_list_widgets
00770 );
00771
00777 void ShowNetworkContentListWindow(ContentVector *cv, ContentType type)
00778 {
00779 #if defined(WITH_ZLIB)
00780 _network_content_client.Clear();
00781 if (cv == NULL) {
00782 _network_content_client.RequestContentList(type);
00783 } else {
00784 _network_content_client.RequestContentList(cv, true);
00785 }
00786
00787 DeleteWindowById(WC_NETWORK_WINDOW, 1);
00788 new NetworkContentListWindow(&_network_content_list_desc, cv != NULL);
00789 #else
00790 ShowErrorMessage(STR_CONTENT_NO_ZLIB_SUB, STR_CONTENT_NO_ZLIB, 0, 0);
00791
00792 if (cv != NULL) {
00793 for (ContentIterator iter = cv->Begin(); iter != cv->End(); iter++) delete *iter;
00794 }
00795 #endif
00796 }
00797
00798 #endif