changeset 15208:ebff51f3984b draft

(svn r19837) -Change: Display list of available (non-active) grfs in the NewGRF window.
author alberth <alberth@openttd.org>
date Sun, 16 May 2010 18:58:13 +0000
parents e31a7ac11eb1
children eb71d6bac72c
files src/lang/english.txt src/newgrf_gui.cpp
diffstat 2 files changed, 167 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -2323,6 +2323,7 @@
 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
--- a/src/newgrf_gui.cpp
+++ b/src/newgrf_gui.cpp
@@ -350,7 +350,7 @@
 					*list = c;
 
 					DeleteWindowByClass(WC_SAVELOAD);
-					InvalidateWindowData(WC_GAME_OPTIONS, 0, 2);
+					InvalidateWindowData(WC_GAME_OPTIONS, 0, 4);
 				}
 				break;
 
@@ -506,6 +506,8 @@
 	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 @@
  * 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<const GRFConfig *> 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 @@
 		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);
 	}
 
@@ -562,6 +584,11 @@
 		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 @@
 	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 @@
 				}
 			} break;
 
+			case SNGRFS_AVAIL_LIST: {
+				GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, 0xD7);
+
+				uint step_height = this->GetWidget<NWidgetBase>(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 @@
 
 				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 @@
 				break;
 			}
 
-			case SNGRFS_FILE_LIST: { // Select a GRF
+			case SNGRFS_FILE_LIST: { // Select an active GRF.
 				NWidgetBase *nw = this->GetWidget<NWidgetBase>(SNGRFS_FILE_LIST);
 				uint i = (pt.y - nw->pos_y) / nw->resize_y + this->vscroll.GetPosition();
 
@@ -813,12 +868,27 @@
 
 				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<NWidgetBase>(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 @@
 				ClearGRFConfigList(&this->actives);
 				this->actives = c;
 				this->preset = index;
+				this->avails.ForceRebuild();
 			}
 		}
 
@@ -919,6 +990,8 @@
 				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 @@
 		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 @@
 					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 @@
 
 				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 @@
 		}
 		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 @@
 						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 @@
 		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();
 	}
 }