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