From b7a8497ccdca2dd6f8a36b580187d7db5f90dcf8 Mon Sep 17 00:00:00 2001 From: alberth Date: Sun, 16 May 2010 18:58:13 +0000 Subject: [PATCH] (svn r19837) -Change: Display list of available (non-active) grfs in the NewGRF window. --- src/lang/english.txt | 1 + src/newgrf_gui.cpp | 182 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 167 insertions(+), 16 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index 6041a3ab3f..d527c3bbd5 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2323,6 +2323,7 @@ STR_GENERATION_PREPARING_GAME :{BLACK}Preparin STR_NEWGRF_SETTINGS_CAPTION :{WHITE}NewGRF Settings STR_NEWGRF_SETTINGS_INFO_TITLE :{WHITE}Detailed NewGRF information STR_NEWGRF_SETTINGS_ACTIVE_LIST :{WHITE}Active NewGRF files +STR_NEWGRF_SETTINGS_INACTIVE_LIST :{WHITE}Inactive NewGRF files STR_NEWGRF_SETTINGS_SELECT_PRESET :{ORANGE}Select preset: STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP :{BLACK}Load the selected preset STR_NEWGRF_SETTINGS_PRESET_SAVE :{BLACK}Save preset diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index b7bcd99da6..32b4cfbf9d 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -350,7 +350,7 @@ public: *list = c; DeleteWindowByClass(WC_SAVELOAD); - InvalidateWindowData(WC_GAME_OPTIONS, 0, 2); + InvalidateWindowData(WC_GAME_OPTIONS, 0, 4); } break; @@ -506,6 +506,8 @@ enum ShowNewGRFStateWidgets { SNGRFS_MOVE_DOWN, SNGRFS_FILE_LIST, SNGRFS_SCROLLBAR, + SNGRFS_AVAIL_LIST, + SNGRFS_SCROLL2BAR, SNGRFS_NEWGRF_INFO_TITLE, SNGRFS_NEWGRF_INFO, SNGRFS_SET_PARAMETERS, @@ -518,17 +520,31 @@ enum ShowNewGRFStateWidgets { * Window for showing NewGRF files */ struct NewGRFWindow : public Window { - GRFConfig **orig_list; ///< grf list the window is shown with - GRFConfig *actives; ///< Temporary active grf list to which changes are made. - GRFConfig *active_sel; ///< Selected active grf item. - bool editable; ///< is the window editable - bool show_params; ///< are the grf-parameters shown in the info-panel - bool execute; ///< on pressing 'apply changes' are grf changes applied immediately, or only list is updated - int query_widget; ///< widget that opened a query - int preset; ///< selected preset + typedef GUIList GUIGRFConfigList; + + static Listing last_sorting; ///< Default sorting of #GUIGRFConfigList. + static Filtering last_filtering; ///< Default filtering of #GUIGRFConfigList. + static GUIGRFConfigList::SortFunction * const sorter_funcs[]; ///< Sort functions of the #GUIGRFConfigList. + static GUIGRFConfigList::FilterFunction * const filter_funcs[]; ///< Filter functions of the #GUIGRFConfigList. + + GUIGRFConfigList avails; ///< Available (non-active) grfs. + const GRFConfig *avail_sel; ///< Currently selected available grf. \c NULL is none is selected. + int avail_pos; ///< Index of #avail_sel if existing, else \c -1. + + GRFConfig *actives; ///< Temporary active grf list to which changes are made. + GRFConfig *active_sel; ///< Selected active grf item. + + GRFConfig **orig_list; ///< List active grfs in the game. Used as initial value, may be updated by the window. + bool editable; ///< Is the window editable? + bool show_params; ///< Are the grf-parameters shown in the info-panel? + bool execute; ///< On pressing 'apply changes' are grf changes applied immediately, or only list is updated. + int query_widget; ///< Widget that opened the last query. + int preset; ///< Selected preset. NewGRFWindow(const WindowDesc *desc, bool editable, bool show_params, bool execute, GRFConfig **orig_list) : Window() { + this->avail_sel = NULL; + this->avail_pos = -1; this->active_sel = NULL; this->actives = NULL; this->orig_list = orig_list; @@ -541,6 +557,12 @@ struct NewGRFWindow : public Window { GetGRFPresetList(&_grf_preset_list); this->InitNested(desc); + this->avails.SetListing(this->last_sorting); + this->avails.SetFiltering(this->last_filtering); + this->avails.SetSortFuncs(this->sorter_funcs); + this->avails.SetFilterFuncs(this->filter_funcs); + this->avails.ForceRebuild(); + this->OnInvalidateData(2); } @@ -561,6 +583,11 @@ struct NewGRFWindow : public Window { { switch (widget) { case SNGRFS_FILE_LIST: + resize->height = max(12, FONT_HEIGHT_NORMAL + 2); + size->height = max(size->height, WD_FRAMERECT_TOP + 6 * resize->height + WD_FRAMERECT_BOTTOM); + break; + + case SNGRFS_AVAIL_LIST: resize->height = max(12, FONT_HEIGHT_NORMAL + 2); size->height = max(size->height, WD_FRAMERECT_TOP + 8 * resize->height + WD_FRAMERECT_BOTTOM); break; @@ -602,6 +629,7 @@ struct NewGRFWindow : public Window { virtual void OnResize() { this->vscroll.SetCapacityFromWidget(this, SNGRFS_FILE_LIST); + this->vscroll2.SetCapacityFromWidget(this, SNGRFS_AVAIL_LIST); } virtual void SetStringParameters(int widget) const @@ -690,17 +718,41 @@ struct NewGRFWindow : public Window { } } break; + case SNGRFS_AVAIL_LIST: { + GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, 0xD7); + + uint step_height = this->GetWidget(SNGRFS_AVAIL_LIST)->resize_y; + uint y = r.top + WD_FRAMERECT_TOP; + uint min_index = this->vscroll2.GetPosition(); + uint max_index = min(min_index + this->vscroll2.GetCapacity(), this->avails.Length()); + + for (uint i = min_index; i < max_index; i++) + { + const GRFConfig *c = this->avails[i]; + bool h = (c == this->avail_sel); + const char *text = c->GetName(); + + if (h) GfxFillRect(r.left + 1, y, r.right - 1, y + step_height - 1, 156); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, text, h ? TC_WHITE : TC_SILVER); + y += step_height; + } + break; + } + case SNGRFS_NEWGRF_INFO_TITLE: /* Create the nice grayish rectangle at the details top. */ GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, 157); DrawString(r.left, r.right, (r.top + r.bottom - FONT_HEIGHT_NORMAL) / 2, STR_NEWGRF_SETTINGS_INFO_TITLE, TC_FROMSTRING, SA_CENTER); break; - case SNGRFS_NEWGRF_INFO: - if (this->active_sel != NULL) { - ShowNewGRFInfo(this->active_sel, r.left + WD_FRAMERECT_LEFT, r.top + WD_FRAMERECT_TOP, r.right - WD_FRAMERECT_RIGHT, r.bottom - WD_FRAMERECT_BOTTOM, this->show_params); + case SNGRFS_NEWGRF_INFO: { + const GRFConfig *selected = this->active_sel; + if (selected == NULL) selected = this->avail_sel; + if (selected != NULL) { + ShowNewGRFInfo(selected, r.left + WD_FRAMERECT_LEFT, r.top + WD_FRAMERECT_TOP, r.right - WD_FRAMERECT_RIGHT, r.bottom - WD_FRAMERECT_BOTTOM, this->show_params); } break; + } } } @@ -761,6 +813,9 @@ struct NewGRFWindow : public Window { this->active_sel = newsel; this->preset = -1; + this->avail_pos = -1; + this->avail_sel = NULL; + this->avails.ForceRebuild(); this->InvalidateData(3); this->DeleteChildWindows(WC_QUERY_STRING); // Remove the parameter query window break; @@ -804,7 +859,7 @@ struct NewGRFWindow : public Window { break; } - case SNGRFS_FILE_LIST: { // Select a GRF + case SNGRFS_FILE_LIST: { // Select an active GRF. NWidgetBase *nw = this->GetWidget(SNGRFS_FILE_LIST); uint i = (pt.y - nw->pos_y) / nw->resize_y + this->vscroll.GetPosition(); @@ -813,12 +868,27 @@ struct NewGRFWindow : public Window { if (this->active_sel != c) this->DeleteChildWindows(WC_QUERY_STRING); // Remove the parameter query window this->active_sel = c; + this->avail_sel = NULL; + this->avail_pos = -1; this->InvalidateData(); if (click_count > 1) this->OnClick(pt, SNGRFS_SET_PARAMETERS, 1); break; } + case SNGRFS_AVAIL_LIST: { // Select a non-active GRF. + NWidgetBase *nw = this->GetWidget(SNGRFS_AVAIL_LIST); + uint i = (pt.y - nw->pos_y) / nw->resize_y + this->vscroll2.GetPosition(); + this->active_sel = NULL; + if (i < this->avails.Length()) { + this->avail_sel = this->avails[i]; + this->avail_pos = i; + } + this->InvalidateData(); + this->DeleteChildWindows(WC_QUERY_STRING); // Remove the parameter query window + break; + } + case SNGRFS_APPLY_CHANGES: // Apply changes made to GRF list if (this->execute) { ShowQuery( @@ -891,6 +961,7 @@ struct NewGRFWindow : public Window { ClearGRFConfigList(&this->actives); this->actives = c; this->preset = index; + this->avails.ForceRebuild(); } } @@ -919,6 +990,8 @@ struct NewGRFWindow : public Window { break; case SNGRFS_SET_PARAMETERS: { + if (this->active_sel == NULL) return; + /* Parse our new "int list" */ GRFConfig *c = this->active_sel; c->num_params = ParseIntList(str, (int*)c->param, lengthof(c->param)); @@ -934,6 +1007,13 @@ struct NewGRFWindow : public Window { this->InvalidateData(); } + /** Calback to update internal data. + * - 0: (optionally) build availables, update button status. + * - 1: build availables, Add newly found grfs, update button status. + * - 2: (optionally) build availables, Reset preset, + 3 + * - 3: (optionally) build availables, Update active scrollbar, update button status. + * - 4: Force a rebuild of the availables, + 2 + */ virtual void OnInvalidateData(int data = 0) { switch (data) { @@ -959,8 +1039,10 @@ struct NewGRFWindow : public Window { c->info = f->info == NULL ? NULL : strdup(f->info); c->status = GCS_UNKNOWN; } - break; - + /* Fall through. */ + case 4: + this->avails.ForceRebuild(); + /* Fall through. */ case 2: this->preset = -1; /* Fall through */ @@ -970,10 +1052,15 @@ struct NewGRFWindow : public Window { this->vscroll.SetCapacityFromWidget(this, SNGRFS_FILE_LIST); this->vscroll.SetCount(i); + + this->vscroll2.SetCapacityFromWidget(this, SNGRFS_AVAIL_LIST); + if (this->avail_pos >= 0) this->vscroll2.ScrollTowards(this->avail_pos); break; } } + this->BuildAvailables(); + this->SetWidgetsDisabledState(!this->editable, SNGRFS_PRESET_LIST, SNGRFS_ADD, @@ -1016,8 +1103,55 @@ struct NewGRFWindow : public Window { } this->SetWidgetDisabledState(SNGRFS_PRESET_SAVE, has_missing); } + +private: + /** Sort grfs by name. */ + static int CDECL NameSorter(const GRFConfig * const *a, const GRFConfig * const *b) + { + return strcasecmp((*a)->GetName(), (*b)->GetName()); + } + + /** Filter grfs by tags/name */ + static bool CDECL TagNameFilter(const GRFConfig * const *a, const char *filter_string) + { + if (strcasestr((*a)->GetName(), filter_string) != NULL) return true; + if ((*a)->filename != NULL && strcasestr((*a)->filename, filter_string) != NULL) return true; + if ((*a)->GetDescription() != NULL && strcasestr((*a)->GetDescription(), filter_string) != NULL) return true; + return false; + } + + void BuildAvailables() + { + if (!this->avails.NeedRebuild()) return; + + this->avails.Clear(); + + for (const GRFConfig *c = _all_grfs; c != NULL; c = c->next) { + bool found = false; + for (const GRFConfig *grf = this->actives; grf != NULL && !found; grf = grf->next) found = grf->ident.HasGrfIdentifier(c->ident.grfid, c->ident.md5sum); + if (!found) *this->avails.Append() = c; + } + + this->avails.Compact(); + this->avails.RebuildDone(); + this->avails.Sort(); + + this->vscroll2.SetCount(this->avails.Length()); // Update the scrollbar + } +}; + +Listing NewGRFWindow::last_sorting = {false, 0}; +Filtering NewGRFWindow::last_filtering = {false, 0}; + +NewGRFWindow::GUIGRFConfigList::SortFunction * const NewGRFWindow::sorter_funcs[] = { + &NameSorter, }; +NewGRFWindow::GUIGRFConfigList::FilterFunction * const NewGRFWindow::filter_funcs[] = { + &TagNameFilter, +}; + + /* Widget definition of the manage newgrfs window */ static const NWidgetPart _nested_newgrf_widgets[] = { NWidget(NWID_HORIZONTAL), @@ -1069,6 +1203,21 @@ static const NWidgetPart _nested_newgrf_widgets[] = { EndContainer(), EndContainer(), EndContainer(), + + NWidget(NWID_SPACER), SetMinimalSize(0, WD_RESIZEBOX_WIDTH), SetResize(1, 0), + NWidget(WWT_PANEL, COLOUR_MAUVE), + NWidget(WWT_LABEL, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_INACTIVE_LIST, STR_NULL), + SetFill(1, 0), SetResize(1, 0), SetPadding(3, WD_FRAMETEXT_RIGHT, 0, WD_FRAMETEXT_LEFT), + /* Left side, available grfs. */ + NWidget(NWID_HORIZONTAL), SetPadding(0, 2, 0, 2), + NWidget(WWT_PANEL, COLOUR_MAUVE), + NWidget(WWT_INSET, COLOUR_MAUVE, SNGRFS_AVAIL_LIST), SetMinimalSize(100, 1), SetPadding(2, 2, 2, 2), + SetFill(1, 1), SetResize(1, 1), + EndContainer(), + EndContainer(), + NWidget(WWT_SCROLL2BAR, COLOUR_MAUVE, SNGRFS_SCROLL2BAR), + EndContainer(), + EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), @@ -1130,8 +1279,9 @@ static void NewGRFConfirmationCallback(Window *w, bool confirmed) CopyGRFConfigList(&nw->actives, *nw->orig_list, false); for (c = nw->actives; c != NULL && i > 0; c = c->next, i--) {} nw->active_sel = c; + nw->avails.ForceRebuild(); - w->SetDirty(); + w->InvalidateData(); } }