00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #if defined(ENABLE_NETWORK)
00013 #include "../stdafx.h"
00014 #include "../strings_func.h"
00015 #include "../gfx_func.h"
00016 #include "../window_func.h"
00017 #include "../gui.h"
00018 #include "../ai/ai.hpp"
00019 #include "../base_media_base.h"
00020 #include "../sortlist_type.h"
00021 #include "../querystring_gui.h"
00022 #include "../core/geometry_func.hpp"
00023 #include "network_content.h"
00024
00025 #include "table/strings.h"
00026 #include "../table/sprites.h"
00027
00029 enum DownloadStatusWindowWidgets {
00030 NCDSWW_BACKGROUND,
00031 NCDSWW_CANCELOK,
00032 };
00033
00035 static const NWidgetPart _nested_network_content_download_status_window_widgets[] = {
00036 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_CONTENT_DOWNLOAD_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00037 NWidget(WWT_PANEL, COLOUR_GREY, NCDSWW_BACKGROUND),
00038 NWidget(NWID_SPACER), SetMinimalSize(350, 0), SetMinimalTextLines(3, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 30),
00039 NWidget(NWID_HORIZONTAL),
00040 NWidget(NWID_SPACER), SetMinimalSize(125, 0),
00041 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NCDSWW_CANCELOK), SetMinimalSize(101, 12), SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
00042 NWidget(NWID_SPACER), SetFill(1, 0),
00043 EndContainer(),
00044 NWidget(NWID_SPACER), SetMinimalSize(0, 4),
00045 EndContainer(),
00046 };
00047
00049 static const WindowDesc _network_content_download_status_window_desc(
00050 WDP_CENTER, 0, 0,
00051 WC_NETWORK_STATUS_WINDOW, WC_NONE,
00052 WDF_MODAL,
00053 _nested_network_content_download_status_window_widgets, lengthof(_nested_network_content_download_status_window_widgets)
00054 );
00055
00057 struct NetworkContentDownloadStatusWindow : public Window, ContentCallback {
00058 private:
00059 ClientNetworkContentSocketHandler *connection;
00060 SmallVector<ContentType, 4> receivedTypes;
00061
00062 uint total_files;
00063 uint downloaded_files;
00064 uint total_bytes;
00065 uint downloaded_bytes;
00066
00067 uint32 cur_id;
00068 char name[48];
00069
00070 public:
00076 NetworkContentDownloadStatusWindow() :
00077 cur_id(UINT32_MAX)
00078 {
00079 this->parent = FindWindowById(WC_NETWORK_WINDOW, 1);
00080
00081 _network_content_client.AddCallback(this);
00082 _network_content_client.DownloadSelectedContent(this->total_files, this->total_bytes);
00083
00084 this->InitNested(&_network_content_download_status_window_desc, 0);
00085 }
00086
00088 ~NetworkContentDownloadStatusWindow()
00089 {
00090
00091 for (ContentType *iter = this->receivedTypes.Begin(); iter != this->receivedTypes.End(); iter++) {
00092 switch (*iter) {
00093 case CONTENT_TYPE_AI:
00094 case CONTENT_TYPE_AI_LIBRARY:
00095 AI::Rescan();
00096 SetWindowClassesDirty(WC_AI_DEBUG);
00097 break;
00098
00099 case CONTENT_TYPE_BASE_GRAPHICS:
00100 BaseGraphics::FindSets();
00101 SetWindowDirty(WC_GAME_OPTIONS, 0);
00102 break;
00103
00104 case CONTENT_TYPE_BASE_SOUNDS:
00105 BaseSounds::FindSets();
00106 SetWindowDirty(WC_GAME_OPTIONS, 0);
00107 break;
00108
00109 case CONTENT_TYPE_BASE_MUSIC:
00110 BaseMusic::FindSets();
00111 SetWindowDirty(WC_GAME_OPTIONS, 0);
00112 break;
00113
00114 case CONTENT_TYPE_NEWGRF:
00115 ScanNewGRFFiles();
00116
00117 InvalidateWindowClassesData(WC_SAVELOAD);
00118 InvalidateWindowData(WC_GAME_OPTIONS, 0, 1);
00119 break;
00120
00121 case CONTENT_TYPE_SCENARIO:
00122 case CONTENT_TYPE_HEIGHTMAP:
00123 extern void ScanScenarios();
00124 ScanScenarios();
00125 InvalidateWindowData(WC_SAVELOAD, 0, 0);
00126 break;
00127
00128 default:
00129 break;
00130 }
00131 }
00132
00133
00134 InvalidateWindowData(WC_NETWORK_WINDOW, 1, 2);
00135 _network_content_client.RemoveCallback(this);
00136 }
00137
00138 virtual void OnPaint()
00139 {
00140 this->DrawWidgets();
00141 }
00142
00143 virtual void DrawWidget(const Rect &r, int widget) const
00144 {
00145 if (widget != NCDSWW_BACKGROUND) return;
00146
00147
00148 DrawFrameRect(r.left + 20, r.top + 4, r.left + 20 + (int)((this->width - 40LL) * this->downloaded_bytes / this->total_bytes), r.top + 14, COLOUR_MAUVE, FR_NONE);
00149
00150 int y = r.top + 20;
00151 SetDParam(0, this->downloaded_bytes);
00152 SetDParam(1, this->total_bytes);
00153 SetDParam(2, this->downloaded_bytes * 100LL / this->total_bytes);
00154 DrawString(r.left + 2, r.right - 2, y, STR_CONTENT_DOWNLOAD_PROGRESS_SIZE, TC_FROMSTRING, SA_CENTER);
00155
00156 StringID str;
00157 if (this->downloaded_bytes == this->total_bytes) {
00158 str = STR_CONTENT_DOWNLOAD_COMPLETE;
00159 } else if (!StrEmpty(this->name)) {
00160 SetDParamStr(0, this->name);
00161 SetDParam(1, this->downloaded_files);
00162 SetDParam(2, this->total_files);
00163 str = STR_CONTENT_DOWNLOAD_FILE;
00164 } else {
00165 str = STR_CONTENT_DOWNLOAD_INITIALISE;
00166 }
00167
00168 y += FONT_HEIGHT_NORMAL + 5;
00169 DrawStringMultiLine(r.left + 2, r.right - 2, y, y + FONT_HEIGHT_NORMAL * 2, str, TC_FROMSTRING, SA_CENTER);
00170 }
00171
00172 virtual void OnClick(Point pt, int widget, int click_count)
00173 {
00174 if (widget == NCDSWW_CANCELOK) {
00175 if (this->downloaded_bytes != this->total_bytes) _network_content_client.Close();
00176 delete this;
00177 }
00178 }
00179
00180 virtual void OnDownloadProgress(const ContentInfo *ci, uint bytes)
00181 {
00182 if (ci->id != this->cur_id) {
00183 strecpy(this->name, ci->filename, lastof(this->name));
00184 this->cur_id = ci->id;
00185 this->downloaded_files++;
00186 this->receivedTypes.Include(ci->type);
00187 }
00188 this->downloaded_bytes += bytes;
00189
00190
00191 if (this->downloaded_bytes == this->total_bytes) {
00192 this->GetWidget<NWidgetCore>(NCDSWW_CANCELOK)->widget_data = STR_BUTTON_OK;
00193 }
00194
00195 this->SetDirty();
00196 }
00197 };
00198
00200 enum NetworkContentListWindowWidgets {
00201 NCLWW_BACKGROUND,
00202
00203 NCLWW_FILTER_CAPT,
00204 NCLWW_FILTER,
00205
00206 NCLWW_CHECKBOX,
00207 NCLWW_TYPE,
00208 NCLWW_NAME,
00209
00210 NCLWW_MATRIX,
00211 NCLWW_SCROLLBAR,
00212
00213 NCLWW_DETAILS,
00214
00215 NCLWW_SELECT_ALL,
00216 NCLWW_SELECT_UPDATE,
00217 NCLWW_UNSELECT,
00218 NCLWW_CANCEL,
00219 NCLWW_DOWNLOAD,
00220
00221 NCLWW_SEL_ALL_UPDATE,
00222 };
00223
00225 class NetworkContentListWindow : public QueryStringBaseWindow, ContentCallback {
00226 typedef GUIList<const ContentInfo*> GUIContentList;
00227
00228 enum {
00229 EDITBOX_MAX_SIZE = 50,
00230 EDITBOX_MAX_LENGTH = 300,
00231 };
00232
00234 static Listing last_sorting;
00235 static Filtering last_filtering;
00237 static GUIContentList::SortFunction * const sorter_funcs[];
00238 static GUIContentList::FilterFunction * const filter_funcs[];
00239 GUIContentList content;
00240
00241 const ContentInfo *selected;
00242 int list_pos;
00243 uint filesize_sum;
00244
00249 void BuildContentList()
00250 {
00251 if (!this->content.NeedRebuild()) return;
00252
00253
00254 this->content.Clear();
00255
00256 for (ConstContentIterator iter = _network_content_client.Begin(); iter != _network_content_client.End(); iter++) {
00257 *this->content.Append() = *iter;
00258 }
00259
00260 this->FilterContentList();
00261 this->content.Compact();
00262 this->content.RebuildDone();
00263 this->SortContentList();
00264
00265 this->vscroll.SetCount(this->content.Length());
00266 this->ScrollToSelected();
00267 }
00268
00270 static int CDECL NameSorter(const ContentInfo * const *a, const ContentInfo * const *b)
00271 {
00272 return strcasecmp((*a)->name, (*b)->name);
00273 }
00274
00276 static int CDECL TypeSorter(const ContentInfo * const *a, const ContentInfo * const *b)
00277 {
00278 int r = 0;
00279 if ((*a)->type != (*b)->type) {
00280 char a_str[64];
00281 char b_str[64];
00282 GetString(a_str, STR_CONTENT_TYPE_BASE_GRAPHICS + (*a)->type - CONTENT_TYPE_BASE_GRAPHICS, lastof(a_str));
00283 GetString(b_str, STR_CONTENT_TYPE_BASE_GRAPHICS + (*b)->type - CONTENT_TYPE_BASE_GRAPHICS, lastof(b_str));
00284 r = strcasecmp(a_str, b_str);
00285 }
00286 if (r == 0) r = NameSorter(a, b);
00287 return r;
00288 }
00289
00291 static int CDECL StateSorter(const ContentInfo * const *a, const ContentInfo * const *b)
00292 {
00293 int r = (*a)->state - (*b)->state;
00294 if (r == 0) r = TypeSorter(a, b);
00295 return r;
00296 }
00297
00299 void SortContentList()
00300 {
00301 if (!this->content.Sort()) return;
00302
00303 for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) {
00304 if (*iter == this->selected) {
00305 this->list_pos = iter - this->content.Begin();
00306 break;
00307 }
00308 }
00309 }
00310
00312 static bool CDECL TagNameFilter(const ContentInfo * const *a, const char *filter_string)
00313 {
00314 for (int i = 0; i < (*a)->tag_count; i++) {
00315 if (strcasestr((*a)->tags[i], filter_string) != NULL) return true;
00316 }
00317 return strcasestr((*a)->name, filter_string) != NULL;
00318 }
00319
00321 void FilterContentList()
00322 {
00323 if (!this->content.Filter(this->edit_str_buf)) return;
00324
00325
00326 for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) {
00327 if (*iter == this->selected) {
00328 this->list_pos = iter - this->content.Begin();
00329 return;
00330 }
00331 }
00332
00333
00334 this->selected = NULL;
00335 this->list_pos = 0;
00336 }
00337
00339 void ScrollToSelected()
00340 {
00341 if (this->selected == NULL) return;
00342
00343 this->vscroll.ScrollTowards(this->list_pos);
00344 }
00345
00346 public:
00351 NetworkContentListWindow(const WindowDesc *desc, bool select_all) :
00352 QueryStringBaseWindow(EDITBOX_MAX_SIZE),
00353 selected(NULL),
00354 list_pos(0)
00355 {
00356 this->InitNested(desc, 1);
00357
00358 this->GetWidget<NWidgetStacked>(NCLWW_SEL_ALL_UPDATE)->SetDisplayedPlane(select_all);
00359
00360 this->afilter = CS_ALPHANUMERAL;
00361 InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, EDITBOX_MAX_LENGTH);
00362 this->SetFocusedWidget(NCLWW_FILTER);
00363
00364 _network_content_client.AddCallback(this);
00365 this->content.SetListing(this->last_sorting);
00366 this->content.SetFiltering(this->last_filtering);
00367 this->content.SetSortFuncs(this->sorter_funcs);
00368 this->content.SetFilterFuncs(this->filter_funcs);
00369 this->content.ForceRebuild();
00370 this->FilterContentList();
00371 this->SortContentList();
00372 this->InvalidateData();
00373 }
00374
00376 ~NetworkContentListWindow()
00377 {
00378 _network_content_client.RemoveCallback(this);
00379 }
00380
00381 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00382 {
00383 switch (widget) {
00384 case NCLWW_FILTER_CAPT:
00385 *size = maxdim(*size, GetStringBoundingBox(STR_CONTENT_FILTER_TITLE));
00386 break;
00387
00388 case NCLWW_TYPE: {
00389 Dimension d = *size;
00390 for (int i = CONTENT_TYPE_BEGIN; i < CONTENT_TYPE_END; i++) {
00391 d = maxdim(d, GetStringBoundingBox(STR_CONTENT_TYPE_BASE_GRAPHICS + i - CONTENT_TYPE_BASE_GRAPHICS));
00392 }
00393 size->width = d.width + WD_MATRIX_RIGHT + WD_MATRIX_LEFT;
00394 break;
00395 }
00396
00397 case NCLWW_MATRIX:
00398 resize->height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM;
00399 size->height = 10 * resize->height;
00400 break;
00401 }
00402 }
00403
00404
00405 virtual void DrawWidget(const Rect &r, int widget) const
00406 {
00407 switch (widget) {
00408 case NCLWW_FILTER_CAPT:
00409 DrawString(r.left, r.right, r.top, STR_CONTENT_FILTER_TITLE, TC_FROMSTRING, SA_RIGHT);
00410 break;
00411
00412 case NCLWW_DETAILS:
00413 this->DrawDetails(r);
00414 break;
00415
00416 case NCLWW_MATRIX:
00417 this->DrawMatrix(r);
00418 break;
00419 }
00420 }
00421
00422 virtual void OnPaint()
00423 {
00424 const SortButtonState arrow = this->content.IsDescSortOrder() ? SBS_DOWN : SBS_UP;
00425
00426 if (this->content.NeedRebuild()) {
00427 this->BuildContentList();
00428 }
00429
00430 this->DrawWidgets();
00431
00432
00433 this->DrawEditBox(NCLWW_FILTER);
00434
00435 switch (this->content.SortType()) {
00436 case NCLWW_CHECKBOX - NCLWW_CHECKBOX: this->DrawSortButtonState(NCLWW_CHECKBOX, arrow); break;
00437 case NCLWW_TYPE - NCLWW_CHECKBOX: this->DrawSortButtonState(NCLWW_TYPE, arrow); break;
00438 case NCLWW_NAME - NCLWW_CHECKBOX: this->DrawSortButtonState(NCLWW_NAME, arrow); break;
00439 }
00440 }
00441
00442 void DrawMatrix(const Rect &r) const
00443 {
00444 const NWidgetBase *nwi_checkbox = this->GetWidget<NWidgetBase>(NCLWW_CHECKBOX);
00445 const NWidgetBase *nwi_name = this->GetWidget<NWidgetBase>(NCLWW_NAME);
00446 const NWidgetBase *nwi_type = this->GetWidget<NWidgetBase>(NCLWW_TYPE);
00447
00448
00449
00450 int sprite_y_offset = WD_MATRIX_TOP + (FONT_HEIGHT_NORMAL - 10) / 2;
00451 uint y = r.top;
00452 int cnt = 0;
00453 for (ConstContentIterator iter = this->content.Get(this->vscroll.GetPosition()); iter != this->content.End() && cnt < this->vscroll.GetCapacity(); iter++, cnt++) {
00454 const ContentInfo *ci = *iter;
00455
00456 if (ci == this->selected) GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->resize.step_height - 1, 10);
00457
00458 SpriteID sprite;
00459 SpriteID pal = PAL_NONE;
00460 switch (ci->state) {
00461 case ContentInfo::UNSELECTED: sprite = SPR_BOX_EMPTY; break;
00462 case ContentInfo::SELECTED: sprite = SPR_BOX_CHECKED; break;
00463 case ContentInfo::AUTOSELECTED: sprite = SPR_BOX_CHECKED; break;
00464 case ContentInfo::ALREADY_HERE: sprite = SPR_BLOT; pal = PALETTE_TO_GREEN; break;
00465 case ContentInfo::DOES_NOT_EXIST: sprite = SPR_BLOT; pal = PALETTE_TO_RED; break;
00466 default: NOT_REACHED();
00467 }
00468 DrawSprite(sprite, pal, nwi_checkbox->pos_x + (pal == PAL_NONE ? 2 : 3), y + sprite_y_offset + (pal == PAL_NONE ? 1 : 0));
00469
00470 StringID str = STR_CONTENT_TYPE_BASE_GRAPHICS + ci->type - CONTENT_TYPE_BASE_GRAPHICS;
00471 DrawString(nwi_type->pos_x, nwi_type->pos_x + nwi_type->current_x - 1, y + WD_MATRIX_TOP, str, TC_BLACK, SA_CENTER);
00472
00473 DrawString(nwi_name->pos_x + WD_FRAMERECT_LEFT, nwi_name->pos_x + nwi_name->current_x - WD_FRAMERECT_RIGHT, y + WD_MATRIX_TOP, ci->name, TC_BLACK);
00474 y += this->resize.step_height;
00475 }
00476 }
00477
00482 void DrawDetails(const Rect &r) const
00483 {
00484 static const int DETAIL_LEFT = 5;
00485 static const int DETAIL_RIGHT = 5;
00486 static const int DETAIL_TOP = 5;
00487
00488
00489 int DETAIL_TITLE_HEIGHT = 5 * FONT_HEIGHT_NORMAL;
00490
00491
00492 GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.top + DETAIL_TITLE_HEIGHT, 157);
00493 DrawString(r.left + WD_INSET_LEFT, r.right - WD_INSET_RIGHT, r.top + FONT_HEIGHT_NORMAL + WD_INSET_TOP, STR_CONTENT_DETAIL_TITLE, TC_FROMSTRING, SA_CENTER);
00494
00495
00496 SetDParam(0, this->filesize_sum);
00497 DrawString(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, r.bottom - FONT_HEIGHT_NORMAL - WD_PAR_VSEP_NORMAL, STR_CONTENT_TOTAL_DOWNLOAD_SIZE);
00498
00499 if (this->selected == NULL) return;
00500
00501
00502 DrawStringMultiLine(r.left + WD_INSET_LEFT, r.right - WD_INSET_RIGHT, r.top + DETAIL_TITLE_HEIGHT / 2, r.top + DETAIL_TITLE_HEIGHT, STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED + this->selected->state, TC_FROMSTRING, SA_CENTER);
00503
00504
00505 const uint max_y = r.bottom - FONT_HEIGHT_NORMAL - WD_PAR_VSEP_WIDE;
00506 int y = r.top + DETAIL_TITLE_HEIGHT + DETAIL_TOP;
00507
00508 if (this->selected->upgrade) {
00509 SetDParam(0, STR_CONTENT_TYPE_BASE_GRAPHICS + this->selected->type - CONTENT_TYPE_BASE_GRAPHICS);
00510 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_UPDATE);
00511 y += WD_PAR_VSEP_WIDE;
00512 }
00513
00514 SetDParamStr(0, this->selected->name);
00515 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_NAME);
00516
00517 if (!StrEmpty(this->selected->version)) {
00518 SetDParamStr(0, this->selected->version);
00519 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_VERSION);
00520 }
00521
00522 if (!StrEmpty(this->selected->description)) {
00523 SetDParamStr(0, this->selected->description);
00524 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_DESCRIPTION);
00525 }
00526
00527 if (!StrEmpty(this->selected->url)) {
00528 SetDParamStr(0, this->selected->url);
00529 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_URL);
00530 }
00531
00532 SetDParam(0, STR_CONTENT_TYPE_BASE_GRAPHICS + this->selected->type - CONTENT_TYPE_BASE_GRAPHICS);
00533 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_TYPE);
00534
00535 y += WD_PAR_VSEP_WIDE;
00536 SetDParam(0, this->selected->filesize);
00537 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_FILESIZE);
00538
00539 if (this->selected->dependency_count != 0) {
00540
00541 char buf[DRAW_STRING_BUFFER] = "";
00542 char *p = buf;
00543 for (uint i = 0; i < this->selected->dependency_count; i++) {
00544 ContentID cid = this->selected->dependencies[i];
00545
00546
00547 ConstContentIterator iter = _network_content_client.Begin();
00548 for (; iter != _network_content_client.End(); iter++) {
00549 const ContentInfo *ci = *iter;
00550 if (ci->id != cid) continue;
00551
00552 p += seprintf(p, lastof(buf), p == buf ? "%s" : ", %s", (*iter)->name);
00553 break;
00554 }
00555 }
00556 SetDParamStr(0, buf);
00557 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_DEPENDENCIES);
00558 }
00559
00560 if (this->selected->tag_count != 0) {
00561
00562 char buf[DRAW_STRING_BUFFER] = "";
00563 char *p = buf;
00564 for (uint i = 0; i < this->selected->tag_count; i++) {
00565 p += seprintf(p, lastof(buf), i == 0 ? "%s" : ", %s", this->selected->tags[i]);
00566 }
00567 SetDParamStr(0, buf);
00568 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_TAGS);
00569 }
00570
00571 if (this->selected->IsSelected()) {
00572
00573 ConstContentVector tree;
00574 _network_content_client.ReverseLookupTreeDependency(tree, this->selected);
00575
00576 char buf[DRAW_STRING_BUFFER] = "";
00577 char *p = buf;
00578 for (ConstContentIterator iter = tree.Begin(); iter != tree.End(); iter++) {
00579 const ContentInfo *ci = *iter;
00580 if (ci == this->selected || ci->state != ContentInfo::SELECTED) continue;
00581
00582 p += seprintf(p, lastof(buf), buf == p ? "%s" : ", %s", ci->name);
00583 }
00584 if (p != buf) {
00585 SetDParamStr(0, buf);
00586 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF);
00587 }
00588 }
00589 }
00590
00591 virtual void OnClick(Point pt, int widget, int click_count)
00592 {
00593 switch (widget) {
00594 case NCLWW_MATRIX: {
00595 uint32 id_v = (pt.y - this->GetWidget<NWidgetBase>(NCLWW_MATRIX)->pos_y) / this->resize.step_height;
00596
00597 if (id_v >= this->vscroll.GetCapacity()) return;
00598 id_v += this->vscroll.GetPosition();
00599
00600 if (id_v >= this->content.Length()) return;
00601
00602 this->selected = *this->content.Get(id_v);
00603 this->list_pos = id_v;
00604
00605 const NWidgetBase *checkbox = this->GetWidget<NWidgetBase>(NCLWW_CHECKBOX);
00606 if (click_count > 1 || IsInsideBS(pt.x, checkbox->pos_x, checkbox->current_x)) {
00607 _network_content_client.ToggleSelectedState(this->selected);
00608 this->content.ForceResort();
00609 }
00610
00611 this->InvalidateData();
00612 } break;
00613
00614 case NCLWW_CHECKBOX:
00615 case NCLWW_TYPE:
00616 case NCLWW_NAME:
00617 if (this->content.SortType() == widget - NCLWW_CHECKBOX) {
00618 this->content.ToggleSortOrder();
00619 this->list_pos = this->content.Length() - this->list_pos - 1;
00620 } else {
00621 this->content.SetSortType(widget - NCLWW_CHECKBOX);
00622 this->content.ForceResort();
00623 this->SortContentList();
00624 }
00625 this->ScrollToSelected();
00626 this->InvalidateData();
00627 break;
00628
00629 case NCLWW_SELECT_ALL:
00630 _network_content_client.SelectAll();
00631 this->InvalidateData();
00632 break;
00633
00634 case NCLWW_SELECT_UPDATE:
00635 _network_content_client.SelectUpgrade();
00636 this->InvalidateData();
00637 break;
00638
00639 case NCLWW_UNSELECT:
00640 _network_content_client.UnselectAll();
00641 this->InvalidateData();
00642 break;
00643
00644 case NCLWW_CANCEL:
00645 delete this;
00646 break;
00647
00648 case NCLWW_DOWNLOAD:
00649 if (BringWindowToFrontById(WC_NETWORK_STATUS_WINDOW, 0) == NULL) new NetworkContentDownloadStatusWindow();
00650 break;
00651 }
00652 }
00653
00654 virtual void OnMouseLoop()
00655 {
00656 this->HandleEditBox(NCLWW_FILTER);
00657 }
00658
00659 virtual EventState OnKeyPress(uint16 key, uint16 keycode)
00660 {
00661 switch (keycode) {
00662 case WKC_UP:
00663
00664 if (this->list_pos > 0) this->list_pos--;
00665 break;
00666 case WKC_DOWN:
00667
00668 if (this->list_pos < (int)this->content.Length() - 1) this->list_pos++;
00669 break;
00670 case WKC_PAGEUP:
00671
00672 this->list_pos = (this->list_pos < this->vscroll.GetCapacity()) ? 0 : this->list_pos - this->vscroll.GetCapacity();
00673 break;
00674 case WKC_PAGEDOWN:
00675
00676 this->list_pos = min(this->list_pos + this->vscroll.GetCapacity(), (int)this->content.Length() - 1);
00677 break;
00678 case WKC_HOME:
00679
00680 this->list_pos = 0;
00681 break;
00682 case WKC_END:
00683
00684 this->list_pos = this->content.Length() - 1;
00685 break;
00686
00687 case WKC_SPACE:
00688 case WKC_RETURN:
00689 if (keycode == WKC_RETURN || !IsWidgetFocused(NCLWW_FILTER)) {
00690 if (this->selected != NULL) {
00691 _network_content_client.ToggleSelectedState(this->selected);
00692 this->content.ForceResort();
00693 this->InvalidateData();
00694 }
00695 return ES_HANDLED;
00696 }
00697
00698
00699 default: {
00700
00701 EventState state = ES_NOT_HANDLED;
00702 if (this->HandleEditBoxKey(NCLWW_FILTER, key, keycode, state) == HEBR_EDITING) {
00703 this->OnOSKInput(NCLWW_FILTER);
00704 }
00705
00706 return state;
00707 }
00708 }
00709
00710 if (_network_content_client.Length() == 0) return ES_HANDLED;
00711
00712 this->selected = *this->content.Get(this->list_pos);
00713
00714
00715 this->ScrollToSelected();
00716
00717
00718 this->InvalidateData();
00719 return ES_HANDLED;
00720 }
00721
00722 virtual void OnOSKInput(int wid)
00723 {
00724 this->content.SetFilterState(!StrEmpty(this->edit_str_buf));
00725 this->content.ForceRebuild();
00726 this->InvalidateData();
00727 }
00728
00729 virtual void OnResize()
00730 {
00731 this->vscroll.SetCapacityFromWidget(this, NCLWW_MATRIX);
00732 this->GetWidget<NWidgetCore>(NCLWW_MATRIX)->widget_data = (this->vscroll.GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START);
00733 }
00734
00735 virtual void OnReceiveContentInfo(const ContentInfo *rci)
00736 {
00737 this->content.ForceRebuild();
00738 this->InvalidateData();
00739 }
00740
00741 virtual void OnDownloadComplete(ContentID cid)
00742 {
00743 this->content.ForceResort();
00744 this->InvalidateData();
00745 }
00746
00747 virtual void OnConnect(bool success)
00748 {
00749 if (!success) {
00750 ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_CONNECT, INVALID_STRING_ID, 0, 0);
00751 delete this;
00752 return;
00753 }
00754
00755 this->InvalidateData();
00756 }
00757
00758 virtual void OnInvalidateData(int data)
00759 {
00760 if (this->content.NeedRebuild()) this->BuildContentList();
00761
00762
00763 this->filesize_sum = 0;
00764 bool show_select_all = false;
00765 bool show_select_upgrade = false;
00766 for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) {
00767 const ContentInfo *ci = *iter;
00768 switch (ci->state) {
00769 case ContentInfo::SELECTED:
00770 case ContentInfo::AUTOSELECTED:
00771 this->filesize_sum += ci->filesize;
00772 break;
00773
00774 case ContentInfo::UNSELECTED:
00775 show_select_all = true;
00776 show_select_upgrade |= ci->upgrade;
00777 break;
00778
00779 default:
00780 break;
00781 }
00782 }
00783
00784
00785 this->SetWidgetDisabledState(NCLWW_DOWNLOAD, this->filesize_sum == 0 || (FindWindowById(WC_NETWORK_STATUS_WINDOW, 0) != NULL && data != 2));
00786 this->SetWidgetDisabledState(NCLWW_UNSELECT, this->filesize_sum == 0);
00787 this->SetWidgetDisabledState(NCLWW_SELECT_ALL, !show_select_all);
00788 this->SetWidgetDisabledState(NCLWW_SELECT_UPDATE, !show_select_upgrade);
00789
00790 this->GetWidget<NWidgetCore>(NCLWW_CANCEL)->widget_data = this->filesize_sum == 0 ? STR_AI_SETTINGS_CLOSE : STR_AI_LIST_CANCEL;
00791 }
00792 };
00793
00794 Listing NetworkContentListWindow::last_sorting = {false, 1};
00795 Filtering NetworkContentListWindow::last_filtering = {false, 0};
00796
00797 NetworkContentListWindow::GUIContentList::SortFunction * const NetworkContentListWindow::sorter_funcs[] = {
00798 &StateSorter,
00799 &TypeSorter,
00800 &NameSorter,
00801 };
00802
00803 NetworkContentListWindow::GUIContentList::FilterFunction * const NetworkContentListWindow::filter_funcs[] = {
00804 &TagNameFilter,
00805 };
00806
00807 static const NWidgetPart _nested_network_content_list_widgets[] = {
00808 NWidget(NWID_HORIZONTAL),
00809 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
00810 NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_CONTENT_TITLE, STR_NULL),
00811 EndContainer(),
00812 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, NCLWW_BACKGROUND),
00813 NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0),
00814 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8),
00815
00816 NWidget(WWT_EMPTY, COLOUR_LIGHT_BLUE, NCLWW_FILTER_CAPT), SetFill(1, 0), SetResize(1, 0),
00817 NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, NCLWW_FILTER), SetFill(1, 0), SetResize(1, 0),
00818 SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
00819 EndContainer(),
00820 NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0),
00821 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8),
00822
00823 NWidget(NWID_VERTICAL),
00824 NWidget(NWID_HORIZONTAL),
00825 NWidget(NWID_VERTICAL),
00826 NWidget(NWID_HORIZONTAL),
00827 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NCLWW_CHECKBOX), SetMinimalSize(13, 1), SetDataTip(STR_EMPTY, STR_NULL),
00828 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NCLWW_TYPE),
00829 SetDataTip(STR_CONTENT_TYPE_CAPTION, STR_CONTENT_TYPE_CAPTION_TOOLTIP),
00830 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NCLWW_NAME), SetResize(1, 0), SetFill(1, 0),
00831 SetDataTip(STR_CONTENT_NAME_CAPTION, STR_CONTENT_NAME_CAPTION_TOOLTIP),
00832 EndContainer(),
00833 NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, NCLWW_MATRIX), SetResize(1, 14), SetFill(1, 1),
00834 EndContainer(),
00835 NWidget(WWT_SCROLLBAR, COLOUR_LIGHT_BLUE, NCLWW_SCROLLBAR),
00836 EndContainer(),
00837 EndContainer(),
00838
00839 NWidget(NWID_VERTICAL),
00840 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, NCLWW_DETAILS), SetResize(1, 1), SetFill(1, 1), EndContainer(),
00841 EndContainer(),
00842 EndContainer(),
00843 NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0),
00844
00845 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8),
00846 NWidget(NWID_SELECTION, INVALID_COLOUR, NCLWW_SEL_ALL_UPDATE), SetResize(1, 0), SetFill(1, 0),
00847 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NCLWW_SELECT_UPDATE), SetResize(1, 0), SetFill(1, 0),
00848 SetDataTip(STR_CONTENT_SELECT_UPDATES_CAPTION, STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP),
00849 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NCLWW_SELECT_ALL), SetResize(1, 0), SetFill(1, 0),
00850 SetDataTip(STR_CONTENT_SELECT_ALL_CAPTION, STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP),
00851 EndContainer(),
00852 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NCLWW_UNSELECT), SetResize(1, 0), SetFill(1, 0),
00853 SetDataTip(STR_CONTENT_UNSELECT_ALL_CAPTION, STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP),
00854 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NCLWW_CANCEL), SetResize(1, 0), SetFill(1, 0),
00855 SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
00856 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, NCLWW_DOWNLOAD), SetResize(1, 0), SetFill(1, 0),
00857 SetDataTip(STR_CONTENT_DOWNLOAD_CAPTION, STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP),
00858 EndContainer(),
00859 NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetResize(1, 0),
00860
00861 NWidget(NWID_HORIZONTAL),
00862 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
00863 NWidget(WWT_RESIZEBOX, COLOUR_LIGHT_BLUE),
00864 EndContainer(),
00865 EndContainer(),
00866 };
00867
00869 static const WindowDesc _network_content_list_desc(
00870 WDP_CENTER, 630, 460,
00871 WC_NETWORK_WINDOW, WC_NONE,
00872 WDF_UNCLICK_BUTTONS,
00873 _nested_network_content_list_widgets, lengthof(_nested_network_content_list_widgets)
00874 );
00875
00881 void ShowNetworkContentListWindow(ContentVector *cv, ContentType type)
00882 {
00883 #if defined(WITH_ZLIB)
00884 _network_content_client.Clear();
00885 if (cv == NULL) {
00886 _network_content_client.RequestContentList(type);
00887 } else {
00888 _network_content_client.RequestContentList(cv, true);
00889 }
00890
00891 DeleteWindowById(WC_NETWORK_WINDOW, 1);
00892 new NetworkContentListWindow(&_network_content_list_desc, cv != NULL);
00893 #else
00894 ShowErrorMessage(STR_CONTENT_NO_ZLIB, STR_CONTENT_NO_ZLIB_SUB, 0, 0);
00895
00896 if (cv != NULL) {
00897 for (ContentIterator iter = cv->Begin(); iter != cv->End(); iter++) delete *iter;
00898 }
00899 #endif
00900 }
00901
00902 #endif