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