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 QueryStringBaseWindow, ContentCallback {
00281 typedef GUIList<const ContentInfo *, StringFilter &> GUIContentList;
00282
00283 static const uint EDITBOX_MAX_SIZE = 50;
00284 static const uint EDITBOX_MAX_LENGTH = 300;
00285
00286 static Listing last_sorting;
00287 static Filtering last_filtering;
00288 static GUIContentList::SortFunction * const sorter_funcs[];
00289 static GUIContentList::FilterFunction * const filter_funcs[];
00290 GUIContentList content;
00291 bool auto_select;
00292 StringFilter string_filter;
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 QueryStringBaseWindow(EDITBOX_MAX_SIZE),
00410 auto_select(select_all),
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->afilter = CS_ALPHANUMERAL;
00421 this->text.Initialize(this->edit_str_buf, this->edit_str_size, EDITBOX_MAX_LENGTH);
00422 this->SetFocusedWidget(WID_NCL_FILTER);
00423
00424 _network_content_client.AddCallback(this);
00425 this->content.SetListing(this->last_sorting);
00426 this->content.SetFiltering(this->last_filtering);
00427 this->content.SetSortFuncs(this->sorter_funcs);
00428 this->content.SetFilterFuncs(this->filter_funcs);
00429 this->content.ForceRebuild();
00430 this->FilterContentList();
00431 this->SortContentList();
00432 this->InvalidateData();
00433 }
00434
00436 ~NetworkContentListWindow()
00437 {
00438 _network_content_client.RemoveCallback(this);
00439 }
00440
00441 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00442 {
00443 switch (widget) {
00444 case WID_NCL_FILTER_CAPT:
00445 *size = maxdim(*size, GetStringBoundingBox(STR_CONTENT_FILTER_TITLE));
00446 break;
00447
00448 case WID_NCL_TYPE: {
00449 Dimension d = *size;
00450 for (int i = CONTENT_TYPE_BEGIN; i < CONTENT_TYPE_END; i++) {
00451 d = maxdim(d, GetStringBoundingBox(STR_CONTENT_TYPE_BASE_GRAPHICS + i - CONTENT_TYPE_BASE_GRAPHICS));
00452 }
00453 size->width = d.width + WD_MATRIX_RIGHT + WD_MATRIX_LEFT;
00454 break;
00455 }
00456
00457 case WID_NCL_MATRIX:
00458 resize->height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM;
00459 size->height = 10 * resize->height;
00460 break;
00461 }
00462 }
00463
00464
00465 virtual void DrawWidget(const Rect &r, int widget) const
00466 {
00467 switch (widget) {
00468 case WID_NCL_FILTER_CAPT:
00469 DrawString(r.left, r.right, r.top, STR_CONTENT_FILTER_TITLE, TC_FROMSTRING, SA_RIGHT);
00470 break;
00471
00472 case WID_NCL_DETAILS:
00473 this->DrawDetails(r);
00474 break;
00475
00476 case WID_NCL_MATRIX:
00477 this->DrawMatrix(r);
00478 break;
00479 }
00480 }
00481
00482 virtual void OnPaint()
00483 {
00484 const SortButtonState arrow = this->content.IsDescSortOrder() ? SBS_DOWN : SBS_UP;
00485
00486 if (this->content.NeedRebuild()) {
00487 this->BuildContentList();
00488 }
00489
00490 this->DrawWidgets();
00491
00492
00493 this->DrawEditBox(WID_NCL_FILTER);
00494
00495 switch (this->content.SortType()) {
00496 case WID_NCL_CHECKBOX - WID_NCL_CHECKBOX: this->DrawSortButtonState(WID_NCL_CHECKBOX, arrow); break;
00497 case WID_NCL_TYPE - WID_NCL_CHECKBOX: this->DrawSortButtonState(WID_NCL_TYPE, arrow); break;
00498 case WID_NCL_NAME - WID_NCL_CHECKBOX: this->DrawSortButtonState(WID_NCL_NAME, arrow); break;
00499 }
00500 }
00501
00506 void DrawMatrix(const Rect &r) const
00507 {
00508 const NWidgetBase *nwi_checkbox = this->GetWidget<NWidgetBase>(WID_NCL_CHECKBOX);
00509 const NWidgetBase *nwi_name = this->GetWidget<NWidgetBase>(WID_NCL_NAME);
00510 const NWidgetBase *nwi_type = this->GetWidget<NWidgetBase>(WID_NCL_TYPE);
00511
00512
00513
00514 int sprite_y_offset = WD_MATRIX_TOP + (FONT_HEIGHT_NORMAL - 10) / 2;
00515 uint y = r.top;
00516 int cnt = 0;
00517 for (ConstContentIterator iter = this->content.Get(this->vscroll->GetPosition()); iter != this->content.End() && cnt < this->vscroll->GetCapacity(); iter++, cnt++) {
00518 const ContentInfo *ci = *iter;
00519
00520 if (ci == this->selected) GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->resize.step_height - 1, PC_GREY);
00521
00522 SpriteID sprite;
00523 SpriteID pal = PAL_NONE;
00524 switch (ci->state) {
00525 case ContentInfo::UNSELECTED: sprite = SPR_BOX_EMPTY; break;
00526 case ContentInfo::SELECTED: sprite = SPR_BOX_CHECKED; break;
00527 case ContentInfo::AUTOSELECTED: sprite = SPR_BOX_CHECKED; break;
00528 case ContentInfo::ALREADY_HERE: sprite = SPR_BLOT; pal = PALETTE_TO_GREEN; break;
00529 case ContentInfo::DOES_NOT_EXIST: sprite = SPR_BLOT; pal = PALETTE_TO_RED; break;
00530 default: NOT_REACHED();
00531 }
00532 DrawSprite(sprite, pal, nwi_checkbox->pos_x + (pal == PAL_NONE ? 2 : 3), y + sprite_y_offset + (pal == PAL_NONE ? 1 : 0));
00533
00534 StringID str = STR_CONTENT_TYPE_BASE_GRAPHICS + ci->type - CONTENT_TYPE_BASE_GRAPHICS;
00535 DrawString(nwi_type->pos_x, nwi_type->pos_x + nwi_type->current_x - 1, y + WD_MATRIX_TOP, str, TC_BLACK, SA_HOR_CENTER);
00536
00537 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);
00538 y += this->resize.step_height;
00539 }
00540 }
00541
00546 void DrawDetails(const Rect &r) const
00547 {
00548 static const int DETAIL_LEFT = 5;
00549 static const int DETAIL_RIGHT = 5;
00550 static const int DETAIL_TOP = 5;
00551
00552
00553 int DETAIL_TITLE_HEIGHT = 5 * FONT_HEIGHT_NORMAL;
00554
00555
00556 GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.top + DETAIL_TITLE_HEIGHT, PC_DARK_BLUE);
00557 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);
00558
00559
00560 SetDParam(0, this->filesize_sum);
00561 DrawString(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, r.bottom - FONT_HEIGHT_NORMAL - WD_PAR_VSEP_NORMAL, STR_CONTENT_TOTAL_DOWNLOAD_SIZE);
00562
00563 if (this->selected == NULL) return;
00564
00565
00566 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);
00567
00568
00569 const uint max_y = r.bottom - FONT_HEIGHT_NORMAL - WD_PAR_VSEP_WIDE;
00570 int y = r.top + DETAIL_TITLE_HEIGHT + DETAIL_TOP;
00571
00572 if (this->selected->upgrade) {
00573 SetDParam(0, STR_CONTENT_TYPE_BASE_GRAPHICS + this->selected->type - CONTENT_TYPE_BASE_GRAPHICS);
00574 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_UPDATE);
00575 y += WD_PAR_VSEP_WIDE;
00576 }
00577
00578 SetDParamStr(0, this->selected->name);
00579 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_NAME);
00580
00581 if (!StrEmpty(this->selected->version)) {
00582 SetDParamStr(0, this->selected->version);
00583 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_VERSION);
00584 }
00585
00586 if (!StrEmpty(this->selected->description)) {
00587 SetDParamStr(0, this->selected->description);
00588 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_DESCRIPTION);
00589 }
00590
00591 if (!StrEmpty(this->selected->url)) {
00592 SetDParamStr(0, this->selected->url);
00593 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_URL);
00594 }
00595
00596 SetDParam(0, STR_CONTENT_TYPE_BASE_GRAPHICS + this->selected->type - CONTENT_TYPE_BASE_GRAPHICS);
00597 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_TYPE);
00598
00599 y += WD_PAR_VSEP_WIDE;
00600 SetDParam(0, this->selected->filesize);
00601 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_FILESIZE);
00602
00603 if (this->selected->dependency_count != 0) {
00604
00605 char buf[DRAW_STRING_BUFFER] = "";
00606 char *p = buf;
00607 for (uint i = 0; i < this->selected->dependency_count; i++) {
00608 ContentID cid = this->selected->dependencies[i];
00609
00610
00611 ConstContentIterator iter = _network_content_client.Begin();
00612 for (; iter != _network_content_client.End(); iter++) {
00613 const ContentInfo *ci = *iter;
00614 if (ci->id != cid) continue;
00615
00616 p += seprintf(p, lastof(buf), p == buf ? "%s" : ", %s", (*iter)->name);
00617 break;
00618 }
00619 }
00620 SetDParamStr(0, buf);
00621 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_DEPENDENCIES);
00622 }
00623
00624 if (this->selected->tag_count != 0) {
00625
00626 char buf[DRAW_STRING_BUFFER] = "";
00627 char *p = buf;
00628 for (uint i = 0; i < this->selected->tag_count; i++) {
00629 p += seprintf(p, lastof(buf), i == 0 ? "%s" : ", %s", this->selected->tags[i]);
00630 }
00631 SetDParamStr(0, buf);
00632 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_TAGS);
00633 }
00634
00635 if (this->selected->IsSelected()) {
00636
00637 ConstContentVector tree;
00638 _network_content_client.ReverseLookupTreeDependency(tree, this->selected);
00639
00640 char buf[DRAW_STRING_BUFFER] = "";
00641 char *p = buf;
00642 for (ConstContentIterator iter = tree.Begin(); iter != tree.End(); iter++) {
00643 const ContentInfo *ci = *iter;
00644 if (ci == this->selected || ci->state != ContentInfo::SELECTED) continue;
00645
00646 p += seprintf(p, lastof(buf), buf == p ? "%s" : ", %s", ci->name);
00647 }
00648 if (p != buf) {
00649 SetDParamStr(0, buf);
00650 y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF);
00651 }
00652 }
00653 }
00654
00655 virtual void OnClick(Point pt, int widget, int click_count)
00656 {
00657 if (widget >= WID_NCL_TEXTFILE && widget < WID_NCL_TEXTFILE + TFT_END) {
00658 if (this->selected == NULL || this->selected->state != ContentInfo::ALREADY_HERE) return;
00659
00660 ShowContentTextfileWindow((TextfileType)(widget - WID_NCL_TEXTFILE), this->selected);
00661 return;
00662 }
00663
00664 switch (widget) {
00665 case WID_NCL_MATRIX: {
00666 uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NCL_MATRIX);
00667 if (id_v >= this->content.Length()) return;
00668
00669 this->selected = *this->content.Get(id_v);
00670 this->list_pos = id_v;
00671
00672 const NWidgetBase *checkbox = this->GetWidget<NWidgetBase>(WID_NCL_CHECKBOX);
00673 if (click_count > 1 || IsInsideBS(pt.x, checkbox->pos_x, checkbox->current_x)) {
00674 _network_content_client.ToggleSelectedState(this->selected);
00675 this->content.ForceResort();
00676 }
00677
00678 this->InvalidateData();
00679 break;
00680 }
00681
00682 case WID_NCL_CHECKBOX:
00683 case WID_NCL_TYPE:
00684 case WID_NCL_NAME:
00685 if (this->content.SortType() == widget - WID_NCL_CHECKBOX) {
00686 this->content.ToggleSortOrder();
00687 this->list_pos = this->content.Length() - this->list_pos - 1;
00688 } else {
00689 this->content.SetSortType(widget - WID_NCL_CHECKBOX);
00690 this->content.ForceResort();
00691 this->SortContentList();
00692 }
00693 this->ScrollToSelected();
00694 this->InvalidateData();
00695 break;
00696
00697 case WID_NCL_SELECT_ALL:
00698 _network_content_client.SelectAll();
00699 this->InvalidateData();
00700 break;
00701
00702 case WID_NCL_SELECT_UPDATE:
00703 _network_content_client.SelectUpgrade();
00704 this->InvalidateData();
00705 break;
00706
00707 case WID_NCL_UNSELECT:
00708 _network_content_client.UnselectAll();
00709 this->InvalidateData();
00710 break;
00711
00712 case WID_NCL_CANCEL:
00713 delete this;
00714 break;
00715
00716 case WID_NCL_OPEN_URL:
00717 if (this->selected != NULL) {
00718 extern void OpenBrowser(const char *url);
00719 OpenBrowser(this->selected->url);
00720 }
00721 break;
00722
00723 case WID_NCL_DOWNLOAD:
00724 if (BringWindowToFrontById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD) == NULL) new NetworkContentDownloadStatusWindow();
00725 break;
00726 }
00727 }
00728
00729 virtual void OnMouseLoop()
00730 {
00731 this->HandleEditBox(WID_NCL_FILTER);
00732 }
00733
00734 virtual EventState OnKeyPress(uint16 key, uint16 keycode)
00735 {
00736 switch (keycode) {
00737 case WKC_UP:
00738
00739 if (this->list_pos > 0) this->list_pos--;
00740 break;
00741 case WKC_DOWN:
00742
00743 if (this->list_pos < (int)this->content.Length() - 1) this->list_pos++;
00744 break;
00745 case WKC_PAGEUP:
00746
00747 this->list_pos = (this->list_pos < this->vscroll->GetCapacity()) ? 0 : this->list_pos - this->vscroll->GetCapacity();
00748 break;
00749 case WKC_PAGEDOWN:
00750
00751 this->list_pos = min(this->list_pos + this->vscroll->GetCapacity(), (int)this->content.Length() - 1);
00752 break;
00753 case WKC_HOME:
00754
00755 this->list_pos = 0;
00756 break;
00757 case WKC_END:
00758
00759 this->list_pos = this->content.Length() - 1;
00760 break;
00761
00762 case WKC_SPACE:
00763 case WKC_RETURN:
00764 if (keycode == WKC_RETURN || !IsWidgetFocused(WID_NCL_FILTER)) {
00765 if (this->selected != NULL) {
00766 _network_content_client.ToggleSelectedState(this->selected);
00767 this->content.ForceResort();
00768 this->InvalidateData();
00769 }
00770 return ES_HANDLED;
00771 }
00772
00773
00774 default: {
00775
00776 EventState state = ES_NOT_HANDLED;
00777 if (this->HandleEditBoxKey(WID_NCL_FILTER, key, keycode, state) == HEBR_EDITING) {
00778 this->OnOSKInput(WID_NCL_FILTER);
00779 }
00780
00781 return state;
00782 }
00783 }
00784
00785 if (_network_content_client.Length() == 0) return ES_HANDLED;
00786
00787 this->selected = *this->content.Get(this->list_pos);
00788
00789
00790 this->ScrollToSelected();
00791
00792
00793 this->InvalidateData();
00794 return ES_HANDLED;
00795 }
00796
00797 virtual void OnOSKInput(int wid)
00798 {
00799 this->string_filter.SetFilterTerm(this->edit_str_buf);
00800 this->content.SetFilterState(!this->string_filter.IsEmpty());
00801 this->content.ForceRebuild();
00802 this->InvalidateData();
00803 }
00804
00805 virtual void OnResize()
00806 {
00807 this->vscroll->SetCapacityFromWidget(this, WID_NCL_MATRIX);
00808 this->GetWidget<NWidgetCore>(WID_NCL_MATRIX)->widget_data = (this->vscroll->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START);
00809 }
00810
00811 virtual void OnReceiveContentInfo(const ContentInfo *rci)
00812 {
00813 if (this->auto_select && !rci->IsSelected()) _network_content_client.ToggleSelectedState(rci);
00814 this->content.ForceRebuild();
00815 this->InvalidateData();
00816 }
00817
00818 virtual void OnDownloadComplete(ContentID cid)
00819 {
00820 this->content.ForceResort();
00821 this->InvalidateData();
00822 }
00823
00824 virtual void OnConnect(bool success)
00825 {
00826 if (!success) {
00827 ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_CONNECT, INVALID_STRING_ID, WL_ERROR);
00828 delete this;
00829 return;
00830 }
00831
00832 this->InvalidateData();
00833 }
00834
00840 virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
00841 {
00842 if (!gui_scope) return;
00843 if (this->content.NeedRebuild()) this->BuildContentList();
00844
00845
00846 this->filesize_sum = 0;
00847 bool show_select_all = false;
00848 bool show_select_upgrade = false;
00849 for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) {
00850 const ContentInfo *ci = *iter;
00851 switch (ci->state) {
00852 case ContentInfo::SELECTED:
00853 case ContentInfo::AUTOSELECTED:
00854 this->filesize_sum += ci->filesize;
00855 break;
00856
00857 case ContentInfo::UNSELECTED:
00858 show_select_all = true;
00859 show_select_upgrade |= ci->upgrade;
00860 break;
00861
00862 default:
00863 break;
00864 }
00865 }
00866
00867
00868 this->SetWidgetDisabledState(WID_NCL_DOWNLOAD, this->filesize_sum == 0 || (FindWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD) != NULL && data != 2));
00869 this->SetWidgetDisabledState(WID_NCL_UNSELECT, this->filesize_sum == 0);
00870 this->SetWidgetDisabledState(WID_NCL_SELECT_ALL, !show_select_all);
00871 this->SetWidgetDisabledState(WID_NCL_SELECT_UPDATE, !show_select_upgrade);
00872 this->SetWidgetDisabledState(WID_NCL_OPEN_URL, this->selected == NULL || StrEmpty(this->selected->url));
00873 for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) {
00874 this->SetWidgetDisabledState(WID_NCL_TEXTFILE + tft, this->selected == NULL || this->selected->state != ContentInfo::ALREADY_HERE || this->selected->GetTextfile(tft) == NULL);
00875 }
00876
00877 this->GetWidget<NWidgetCore>(WID_NCL_CANCEL)->widget_data = this->filesize_sum == 0 ? STR_AI_SETTINGS_CLOSE : STR_AI_LIST_CANCEL;
00878 }
00879 };
00880
00881 Listing NetworkContentListWindow::last_sorting = {false, 1};
00882 Filtering NetworkContentListWindow::last_filtering = {false, 0};
00883
00884 NetworkContentListWindow::GUIContentList::SortFunction * const NetworkContentListWindow::sorter_funcs[] = {
00885 &StateSorter,
00886 &TypeSorter,
00887 &NameSorter,
00888 };
00889
00890 NetworkContentListWindow::GUIContentList::FilterFunction * const NetworkContentListWindow::filter_funcs[] = {
00891 &TagNameFilter,
00892 };
00893
00895 static const NWidgetPart _nested_network_content_list_widgets[] = {
00896 NWidget(NWID_HORIZONTAL),
00897 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
00898 NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_CONTENT_TITLE, STR_NULL),
00899 EndContainer(),
00900 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NCL_BACKGROUND),
00901 NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0),
00902 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8),
00903
00904 NWidget(WWT_EMPTY, COLOUR_LIGHT_BLUE, WID_NCL_FILTER_CAPT), SetFill(1, 0), SetResize(1, 0),
00905 NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NCL_FILTER), SetFill(1, 0), SetResize(1, 0),
00906 SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
00907 EndContainer(),
00908 NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0),
00909 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8),
00910
00911 NWidget(NWID_VERTICAL),
00912 NWidget(NWID_HORIZONTAL),
00913 NWidget(NWID_VERTICAL),
00914 NWidget(NWID_HORIZONTAL),
00915 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_CHECKBOX), SetMinimalSize(13, 1), SetDataTip(STR_EMPTY, STR_NULL),
00916 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TYPE),
00917 SetDataTip(STR_CONTENT_TYPE_CAPTION, STR_CONTENT_TYPE_CAPTION_TOOLTIP),
00918 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_NAME), SetResize(1, 0), SetFill(1, 0),
00919 SetDataTip(STR_CONTENT_NAME_CAPTION, STR_CONTENT_NAME_CAPTION_TOOLTIP),
00920 EndContainer(),
00921 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),
00922 EndContainer(),
00923 NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NCL_SCROLLBAR),
00924 EndContainer(),
00925 EndContainer(),
00926
00927 NWidget(NWID_VERTICAL),
00928 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NCL_DETAILS), SetResize(1, 1), SetFill(1, 1), EndContainer(),
00929 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7),
00930 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL),
00931 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL),
00932 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL),
00933 EndContainer(),
00934 EndContainer(),
00935 EndContainer(),
00936 NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0),
00937
00938 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8),
00939 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8),
00940 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NCL_SEL_ALL_UPDATE), SetResize(1, 0), SetFill(1, 0),
00941 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SELECT_UPDATE), SetResize(1, 0), SetFill(1, 0),
00942 SetDataTip(STR_CONTENT_SELECT_UPDATES_CAPTION, STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP),
00943 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SELECT_ALL), SetResize(1, 0), SetFill(1, 0),
00944 SetDataTip(STR_CONTENT_SELECT_ALL_CAPTION, STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP),
00945 EndContainer(),
00946 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_UNSELECT), SetResize(1, 0), SetFill(1, 0),
00947 SetDataTip(STR_CONTENT_UNSELECT_ALL_CAPTION, STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP),
00948 EndContainer(),
00949 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8),
00950 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_OPEN_URL), SetResize(1, 0), SetFill(1, 0),
00951 SetDataTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP),
00952 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_CANCEL), SetResize(1, 0), SetFill(1, 0),
00953 SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
00954 NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_DOWNLOAD), SetResize(1, 0), SetFill(1, 0),
00955 SetDataTip(STR_CONTENT_DOWNLOAD_CAPTION, STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP),
00956 EndContainer(),
00957 EndContainer(),
00958 NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetResize(1, 0),
00959
00960 NWidget(NWID_HORIZONTAL),
00961 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
00962 NWidget(WWT_RESIZEBOX, COLOUR_LIGHT_BLUE),
00963 EndContainer(),
00964 EndContainer(),
00965 };
00966
00968 static const WindowDesc _network_content_list_desc(
00969 WDP_CENTER, 630, 460,
00970 WC_NETWORK_WINDOW, WC_NONE,
00971 WDF_UNCLICK_BUTTONS,
00972 _nested_network_content_list_widgets, lengthof(_nested_network_content_list_widgets)
00973 );
00974
00980 void ShowNetworkContentListWindow(ContentVector *cv, ContentType type)
00981 {
00982 #if defined(WITH_ZLIB)
00983 _network_content_client.Clear();
00984 if (cv == NULL) {
00985 _network_content_client.RequestContentList(type);
00986 } else {
00987 _network_content_client.RequestContentList(cv, true);
00988 }
00989
00990 DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_CONTENT_LIST);
00991 new NetworkContentListWindow(&_network_content_list_desc, cv != NULL);
00992 #else
00993 ShowErrorMessage(STR_CONTENT_NO_ZLIB, STR_CONTENT_NO_ZLIB_SUB, WL_ERROR);
00994
00995 if (cv != NULL) {
00996 for (ContentIterator iter = cv->Begin(); iter != cv->End(); iter++) delete *iter;
00997 }
00998 #endif
00999 }
01000
01001 #endif