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