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