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