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