changeset 17548:c0fce44f4000 draft

(svn r22312) -Codechange: Add GameOptionsWindow::BuildDropDownList() for construction of all dropdown lists in the GameOptionsWindow. -Change: Sort the items in the currency dropdown; separate the "Custom" item with a horizontal line from the rest. -Change: Separate default and NewGRF-supplied townnames with a horizontal line and only sort them within these groups. -Fix: Resize all dropdown lists in the GameOptionsWindow, so no text is truncated.
author frosch <frosch@openttd.org>
date Sun, 10 Apr 2011 15:30:08 +0000
parents 01aee9a39e6e
children 95acd4a68214
files src/settings_gui.cpp
diffstat 1 files changed, 176 insertions(+), 111 deletions(-) [+]
line wrap: on
line diff
--- a/src/settings_gui.cpp
+++ b/src/settings_gui.cpp
@@ -59,21 +59,6 @@
 	INVALID_STRING_ID,
 };
 
-/**
- * Fill a static array with consecutive stringIDs for use with a drop down.
- * @param base First stringID.
- * @param num  Number of stringIDs (must be at most 32).
- * *return Pointer to the static buffer with stringIDs.
- */
-static StringID *BuildDynamicDropdown(StringID base, int num)
-{
-	static StringID buf[32 + 1];
-	StringID *p = buf;
-	while (--num >= 0) *p++ = base++;
-	*p = INVALID_STRING_ID;
-	return buf;
-}
-
 int _nb_orig_names = SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1; ///< Number of original town names.
 static StringID *_grf_names = NULL; ///< Pointer to town names defined by NewGRFs.
 static int _nb_grf_names = 0;       ///< Number of town names defined by NewGRFs.
@@ -139,44 +124,20 @@
 	GOW_BASE_MUSIC_DESCRIPTION, ///< Description of selected base music set
 };
 
-/**
- * Update/redraw the townnames dropdown
- * @param w   the window the dropdown belongs to
- * @param sel the currently selected townname generator
- */
-static void ShowTownnameDropdown(Window *w, int sel)
-{
-	typedef std::map<StringID, int, StringIDCompare> TownList;
-	TownList townnames;
-
-	/* Add and sort original townnames generators */
-	for (int i = 0; i < _nb_orig_names; i++) townnames[STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH + i] = i;
-
-	/* Add and sort newgrf townnames generators */
-	for (int i = 0; i < _nb_grf_names; i++) townnames[_grf_names[i]] = _nb_orig_names + i;
-
-	DropDownList *list = new DropDownList();
-	for (TownList::iterator it = townnames.begin(); it != townnames.end(); it++) {
-		list->push_back(new DropDownListStringItem((*it).first, (*it).second, !(_game_mode == GM_MENU || Town::GetNumItems() == 0 || (*it).second == sel)));
-	}
-
-	ShowDropDownList(w, list, sel, GOW_TOWNNAME_DROPDOWN);
-}
-
 static void ShowCustCurrency();
 
 template <class T>
-static void ShowSetMenu(Window *w, int widget)
+static DropDownList *BuiltSetDropDownList(int *selected_index)
 {
 	int n = T::GetNumSets();
-	int current = T::GetIndexOfUsedSet();
+	*selected_index = T::GetIndexOfUsedSet();
 
 	DropDownList *list = new DropDownList();
 	for (int i = 0; i < n; i++) {
-		list->push_back(new DropDownListCharStringItem(T::GetSet(i)->name, i, (_game_mode == GM_MENU) ? false : (current != i)));
+		list->push_back(new DropDownListCharStringItem(T::GetSet(i)->name, i, (_game_mode == GM_MENU) ? false : (*selected_index != i)));
 	}
 
-	ShowDropDownList(w, list, current, widget);
+	return list;
 }
 
 struct GameOptionsWindow : Window {
@@ -198,6 +159,153 @@
 		if (this->reload) _switch_mode = SM_MENU;
 	}
 
+	/**
+	 * Build the dropdown list for a specific widget.
+	 * @param widget         Widget to build list for
+	 * @param selected_index Currently selected item
+	 * @return the built dropdown list, or NULL if the widget has no dropdown menu.
+	 */
+	DropDownList *BuildDropDownList(int widget, int *selected_index) const
+	{
+		DropDownList *list = NULL;
+		switch (widget) {
+			case GOW_CURRENCY_DROPDOWN: { // Setup currencies dropdown
+				list = new DropDownList();
+				*selected_index = this->opt->locale.currency;
+				StringID *items = BuildCurrencyDropdown();
+				uint disabled = _game_mode == GM_MENU ? 0 : ~GetMaskOfAllowedCurrencies();
+				int custom_index = -1;
+
+				/* Add non-custom currencies; sorted naturally */
+				for (uint i = 0; *items != INVALID_STRING_ID; items++, i++) {
+					if (*items == STR_GAME_OPTIONS_CURRENCY_CUSTOM) {
+						custom_index = i;
+					} else {
+						list->push_back(new DropDownListStringItem(*items, i, HasBit(disabled, i)));
+					}
+				}
+				list->sort(DropDownListStringItem::NatSortFunc);
+
+				/* Append custom currency at the end */
+				if (custom_index >= 0) {
+					list->push_back(new DropDownListItem(-1, false)); // separator line
+					list->push_back(new DropDownListStringItem(STR_GAME_OPTIONS_CURRENCY_CUSTOM, custom_index, HasBit(disabled, custom_index)));
+				}
+				break;
+			}
+
+			case GOW_DISTANCE_DROPDOWN: { // Setup distance unit dropdown
+				list = new DropDownList();
+				*selected_index = this->opt->locale.units;
+				const StringID *items = _units_dropdown;
+				for (uint i = 0; *items != INVALID_STRING_ID; items++, i++) {
+					list->push_back(new DropDownListStringItem(*items, i, false));
+				}
+				break;
+			}
+
+			case GOW_ROADSIDE_DROPDOWN: { // Setup road-side dropdown
+				list = new DropDownList();
+				*selected_index = this->opt->vehicle.road_side;
+				const StringID *items = _driveside_dropdown;
+				uint disabled = 0;
+
+				/* You can only change the drive side if you are in the menu or ingame with
+				 * no vehicles present. In a networking game only the server can change it */
+				extern bool RoadVehiclesAreBuilt();
+				if ((_game_mode != GM_MENU && RoadVehiclesAreBuilt()) || (_networking && !_network_server)) {
+					disabled = ~(1 << this->opt->vehicle.road_side); // disable the other value
+				}
+
+				for (uint i = 0; *items != INVALID_STRING_ID; items++, i++) {
+					list->push_back(new DropDownListStringItem(*items, i, HasBit(disabled, i)));
+				}
+				break;
+			}
+
+			case GOW_TOWNNAME_DROPDOWN: { // Setup townname dropdown
+				list = new DropDownList();
+				*selected_index = this->opt->game_creation.town_name;
+
+				int enabled_item = (_game_mode == GM_MENU || Town::GetNumItems() == 0) ? -1 : *selected_index;
+
+				/* Add and sort original townnames generators */
+				for (int i = 0; i < _nb_orig_names; i++) {
+					list->push_back(new DropDownListStringItem(STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH + i, i, enabled_item != i && enabled_item >= 0));
+				}
+				list->sort(DropDownListStringItem::NatSortFunc);
+
+				/* Add and sort newgrf townnames generators */
+				DropDownList newgrf_names;
+				for (int i = 0; i < _nb_grf_names; i++) {
+					int result = _nb_orig_names + i;
+					newgrf_names.push_back(new DropDownListStringItem(_grf_names[i], result, enabled_item != result && enabled_item >= 0));
+				}
+				newgrf_names.sort(DropDownListStringItem::NatSortFunc);
+
+				/* Append newgrf_names at the end of list */
+				if (newgrf_names.size() > 0) {
+					list->push_back(new DropDownListItem(-1, false)); // separator line
+					list->splice(list->end(), newgrf_names);
+				}
+				break;
+			}
+
+			case GOW_AUTOSAVE_DROPDOWN: { // Setup autosave dropdown
+				list = new DropDownList();
+				*selected_index = _settings_client.gui.autosave;
+				const StringID *items = _autosave_dropdown;
+				for (uint i = 0; *items != INVALID_STRING_ID; items++, i++) {
+					list->push_back(new DropDownListStringItem(*items, i, false));
+				}
+				break;
+			}
+
+			case GOW_LANG_DROPDOWN: { // Setup interface language dropdown
+				list = new DropDownList();
+				for (uint i = 0; i < _languages.Length(); i++) {
+					if (&_languages[i] == _current_language) *selected_index = i;
+					list->push_back(new DropDownListStringItem(SPECSTR_LANGUAGE_START + i, i, false));
+				}
+				list->sort(DropDownListStringItem::NatSortFunc);
+				break;
+			}
+
+			case GOW_RESOLUTION_DROPDOWN: // Setup resolution dropdown
+				list = new DropDownList();
+				*selected_index = GetCurRes();
+				for (int i = 0; i < _num_resolutions; i++) {
+					list->push_back(new DropDownListStringItem(SPECSTR_RESOLUTION_START + i, i, false));
+				}
+				break;
+
+			case GOW_SCREENSHOT_DROPDOWN: // Setup screenshot format dropdown
+				list = new DropDownList();
+				*selected_index = _cur_screenshot_format;
+				for (uint i = 0; i < _num_screenshot_formats; i++) {
+					list->push_back(new DropDownListStringItem(SPECSTR_SCREENSHOT_START + i, i, false));
+				}
+				break;
+
+			case GOW_BASE_GRF_DROPDOWN:
+				list = BuiltSetDropDownList<BaseGraphics>(selected_index);
+				break;
+
+			case GOW_BASE_SFX_DROPDOWN:
+				list = BuiltSetDropDownList<BaseSounds>(selected_index);
+				break;
+
+			case GOW_BASE_MUSIC_DROPDOWN:
+				list = BuiltSetDropDownList<BaseMusic>(selected_index);
+				break;
+
+			default:
+				return NULL;
+		}
+
+		return list;
+	}
+
 	virtual void SetStringParameters(int widget) const
 	{
 		switch (widget) {
@@ -285,66 +393,30 @@
 					*size = maxdim(*size, GetStringBoundingBox(STR_GAME_OPTIONS_BASE_MUSIC_STATUS));
 				}
 				break;
+
+			default: {
+				int selected;
+				DropDownList *list = this->BuildDropDownList(widget, &selected);
+				if (list != NULL) {
+					/* Find the biggest item for the default size. */
+					for (DropDownList::iterator it = list->begin(); it != list->end(); it++) {
+						static const Dimension extra = {WD_DROPDOWNTEXT_LEFT + WD_DROPDOWNTEXT_RIGHT, WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM};
+						Dimension string_dim;
+						int width = (*it)->Width();
+						string_dim.width = width + extra.width;
+						string_dim.height = (*it)->Height(width) + extra.height;
+						*size = maxdim(*size, string_dim);
+						delete *it;
+					}
+					delete list;
+				}
+			}
 		}
 	}
 
 	virtual void OnClick(Point pt, int widget, int click_count)
 	{
 		switch (widget) {
-			case GOW_CURRENCY_DROPDOWN: // Setup currencies dropdown
-				ShowDropDownMenu(this, BuildCurrencyDropdown(), this->opt->locale.currency, GOW_CURRENCY_DROPDOWN, _game_mode == GM_MENU ? 0 : ~GetMaskOfAllowedCurrencies(), 0);
-				break;
-
-			case GOW_DISTANCE_DROPDOWN: // Setup distance unit dropdown
-				ShowDropDownMenu(this, _units_dropdown, this->opt->locale.units, GOW_DISTANCE_DROPDOWN, 0, 0);
-				break;
-
-			case GOW_ROADSIDE_DROPDOWN: { // Setup road-side dropdown
-				int i = 0;
-				extern bool RoadVehiclesAreBuilt();
-
-				/* You can only change the drive side if you are in the menu or ingame with
-				 * no vehicles present. In a networking game only the server can change it */
-				if ((_game_mode != GM_MENU && RoadVehiclesAreBuilt()) || (_networking && !_network_server)) {
-					i = (-1) ^ (1 << this->opt->vehicle.road_side); // disable the other value
-				}
-
-				ShowDropDownMenu(this, _driveside_dropdown, this->opt->vehicle.road_side, GOW_ROADSIDE_DROPDOWN, i, 0);
-				break;
-			}
-
-			case GOW_TOWNNAME_DROPDOWN: // Setup townname dropdown
-				ShowTownnameDropdown(this, this->opt->game_creation.town_name);
-				break;
-
-			case GOW_AUTOSAVE_DROPDOWN: // Setup autosave dropdown
-				ShowDropDownMenu(this, _autosave_dropdown, _settings_client.gui.autosave, GOW_AUTOSAVE_DROPDOWN, 0, 0);
-				break;
-
-			case GOW_LANG_DROPDOWN: { // Setup interface language dropdown
-				typedef std::map<StringID, int, StringIDCompare> LangList;
-
-				/* Sort language names */
-				LangList langs;
-				int current_lang = 0;
-				for (int i = 0; i < (int)_languages.Length(); i++) {
-					if (&_languages[i] == _current_language) current_lang = i;
-					langs[SPECSTR_LANGUAGE_START + i] = i;
-				}
-
-				DropDownList *list = new DropDownList();
-				for (LangList::iterator it = langs.begin(); it != langs.end(); it++) {
-					list->push_back(new DropDownListStringItem((*it).first, (*it).second, false));
-				}
-
-				ShowDropDownList(this, list, current_lang, GOW_LANG_DROPDOWN);
-				break;
-			}
-
-			case GOW_RESOLUTION_DROPDOWN: // Setup resolution dropdown
-				ShowDropDownMenu(this, BuildDynamicDropdown(SPECSTR_RESOLUTION_START, _num_resolutions), GetCurRes(), GOW_RESOLUTION_DROPDOWN, 0, 0);
-				break;
-
 			case GOW_FULLSCREEN_BUTTON: // Click fullscreen on/off
 				/* try to toggle full-screen on/off */
 				if (!ToggleFullScreen(!_fullscreen)) {
@@ -354,21 +426,14 @@
 				this->SetDirty();
 				break;
 
-			case GOW_SCREENSHOT_DROPDOWN: // Setup screenshot format dropdown
-				ShowDropDownMenu(this, BuildDynamicDropdown(SPECSTR_SCREENSHOT_START, _num_screenshot_formats), _cur_screenshot_format, GOW_SCREENSHOT_DROPDOWN, 0, 0);
-				break;
-
-			case GOW_BASE_GRF_DROPDOWN:
-				ShowSetMenu<BaseGraphics>(this, GOW_BASE_GRF_DROPDOWN);
+			default: {
+				int selected;
+				DropDownList *list = this->BuildDropDownList(widget, &selected);
+				if (list != NULL) {
+					ShowDropDownList(this, list, selected, widget);
+				}
 				break;
-
-			case GOW_BASE_SFX_DROPDOWN:
-				ShowSetMenu<BaseSounds>(this, GOW_BASE_SFX_DROPDOWN);
-				break;
-
-			case GOW_BASE_MUSIC_DROPDOWN:
-				ShowSetMenu<BaseMusic>(this, GOW_BASE_MUSIC_DROPDOWN);
-				break;
+			}
 		}
 	}