Changeset - r10543:1ca1d5bb615b
[Not reviewed]
master
0 1 0
rubidium - 16 years ago 2009-01-03 11:24:27
rubidium@openttd.org
(svn r14800) -Codechange: make the advanced settings window resizeable and scrollable (most by Alberth)
1 file changed with 55 insertions and 47 deletions:
0 comments (0 inline, 0 general)
src/settings_gui.cpp
Show inline comments
 
@@ -564,48 +564,68 @@ public:
 
			case GDW_CANCEL: // Cancel button - close window, abandon changes
 
				delete this;
 
				break;
 
		}
 
	}
 

	
 
	virtual void OnTick()
 
	{
 
		if (this->timeout != 0) {
 
			this->timeout--;
 
			if (this->timeout == 0) this->clicked_button = NO_SETTINGS_BUTTON;
 
			this->SetDirty();
 
		}
 
	}
 
};
 

	
 
void ShowGameDifficulty()
 
{
 
	DeleteWindowById(WC_GAME_OPTIONS, 0);
 
	new GameDifficultyWindow();
 
}
 

	
 
static const int SETTING_HEIGHT = 11;         ///< Height of a single patch setting in the tree view
 

	
 
/** Data structure describing a single patch in a tab */
 
struct PatchEntry {
 
	const SettingDesc *setting; ///< Setting description of the patch
 
	uint index;                 ///< Index of the setting in the settings table
 
};
 

	
 
/**
 
 * Data structure describing one page of patches in the patch settings window.
 
 *
 
 * The names of the patches to display are statically defined, and from this
 
 * information, a dynamic array (with length \a num) of PatchEntry entries is
 
 * constructed.
 
 */
 
struct PatchPage {
 
	const char **names;  ///< Static list of strings with patch names that are settable from the tab
 
	PatchEntry *entries; ///< Array of patch entries of the page. Initially \c NULL, filled in at run time
 
	byte num;            ///< Number of entries on the page (statically filled).
 
};
 

	
 

	
 
static const char *_patches_ui[] = {
 
	"gui.vehicle_speed",
 
	"gui.status_long_date",
 
	"gui.date_format_in_default_names",
 
	"gui.show_finances",
 
	"gui.autoscroll",
 
	"gui.reverse_scroll",
 
	"gui.smooth_scroll",
 
	"gui.errmsg_duration",
 
	"gui.toolbar_pos",
 
	"gui.measure_tooltip",
 
	"gui.window_snap_radius",
 
	"gui.population_in_label",
 
	"gui.link_terraform_toolbar",
 
	"gui.liveries",
 
	"gui.prefer_teamchat",
 
	/* While the horizontal scrollwheel scrolling is written as general code, only
 
	 *  the cocoa (OSX) driver generates input for it.
 
	 *  Since it's also able to completely disable the scrollwheel will we display it on all platforms anyway */
 
	"gui.scrollwheel_scrolling",
 
	"gui.scrollwheel_multiplier",
 
#ifdef __APPLE__
 
	/* We might need to emulate a right mouse button on mac */
 
	"gui.right_mouse_btn_emulation",
 
@@ -690,155 +710,135 @@ static const char *_patches_vehicles[] =
 
	"gui.order_review_system",
 
	"vehicle.never_expire_vehicles",
 
	"gui.lost_train_warn",
 
	"gui.autorenew",
 
	"gui.autorenew_months",
 
	"gui.autorenew_money",
 
	"vehicle.max_trains",
 
	"vehicle.max_roadveh",
 
	"vehicle.max_aircraft",
 
	"vehicle.max_ships",
 
	"vehicle.servint_ispercent",
 
	"vehicle.servint_trains",
 
	"vehicle.servint_roadveh",
 
	"vehicle.servint_ships",
 
	"vehicle.servint_aircraft",
 
	"order.no_servicing_if_no_breakdowns",
 
	"vehicle.wagon_speed_limits",
 
	"vehicle.disable_elrails",
 
	"vehicle.freight_trains",
 
	"vehicle.plane_speed",
 
	"order.timetabling",
 
	"vehicle.dynamic_engines",
 
};
 

	
 
/** Data structure describing a single patch in a tab */
 
struct PatchEntry {
 
	const SettingDesc *setting; ///< Setting description of the patch
 
	uint index;                 ///< Index of the setting in the settings table
 
};
 

	
 
/**
 
 * Data structure describing one page of patches in the patch settings window.
 
 *
 
 * The names of the patches to display are statically defined, and from this
 
 * information, a dynamic array (with length \a num) of PatchEntry entries is
 
 * constructed.
 
 */
 
struct PatchPage {
 
	const char **names;  ///< Static list of strings with patch names that are settable from the tab
 
	PatchEntry *entries; ///< Array of patch entries of the page. Initially \c NULL, filled in at run time
 
	byte num;            ///< Number of entries on the page (statically filled).
 
};
 

	
 
/** Array of pages (tabs), where each page holds a number of advanced settings. */
 
static PatchPage _patches_page[] = {
 
	{_patches_ui,           NULL, lengthof(_patches_ui)},
 
	{_patches_construction, NULL, lengthof(_patches_construction)},
 
	{_patches_vehicles,     NULL, lengthof(_patches_vehicles)},
 
	{_patches_stations,     NULL, lengthof(_patches_stations)},
 
	{_patches_economy,      NULL, lengthof(_patches_economy)},
 
	{_patches_ai,           NULL, lengthof(_patches_ai)},
 
};
 

	
 
/** Widget numbers of config patches window */
 
enum PatchesSelectionWidgets {
 
	PATCHSEL_OPTIONSPANEL = 3, ///< Panel widget containing the option lists
 
	PATCHSEL_SCROLLBAR,        ///< Scrollbar
 
	PATCHSEL_RESIZE,           ///< Resize button
 
	PATCHSEL_INTERFACE,        ///< Button 'Interface'
 
	PATCHSEL_CONSTRUCTION,     ///< Button 'Construction'
 
	PATCHSEL_VEHICLES,         ///< Button 'Vehicles'
 
	PATCHSEL_STATIONS,         ///< Button 'Stations'
 
	PATCHSEL_ECONOMY,          ///< Button 'Economy'
 
	PATCHSEL_COMPETITORS       ///< Button 'Competitors'
 
};
 

	
 
struct PatchesSelectionWindow : Window {
 
	static const int SETTINGTREE_LEFT_OFFSET; ///< Position of left edge of patch values
 
	static const int SETTINGTREE_TOP_OFFSET;  ///< Position of top edge of patch values
 

	
 
	static GameSettings *patches_ptr;  ///< Pointer to the game settings being displayed and modified
 
	static int patches_max;  ///< Maximal number of patches on a single page
 

	
 
	int page;
 
	int entry;
 
	int click;
 

	
 
	PatchesSelectionWindow(const WindowDesc *desc) : Window(desc)
 
	{
 
		/* Check that the widget doesn't get moved without adapting the constant as well.
 
		 *  - SETTINGTREE_LEFT_OFFSET should be 5 pixels to the right of the left edge of the panel
 
		 *  - SETTINGTREE_TOP_OFFSET should be 5 pixels below the top edge of the panel
 
		 */
 
		assert(this->widget[PATCHSEL_OPTIONSPANEL].left + 5 == SETTINGTREE_LEFT_OFFSET);
 
		assert(this->widget[PATCHSEL_OPTIONSPANEL].top + 5 == SETTINGTREE_TOP_OFFSET);
 

	
 
		static bool first_time = true;
 

	
 
		patches_ptr = (_game_mode == GM_MENU) ? &_settings_newgame : &_settings_game;
 

	
 
		/* Build up the dynamic settings-array only once per OpenTTD session */
 
		if (first_time) {
 
			PatchPage *page;
 
			for (page = &_patches_page[0]; page != endof(_patches_page); page++) {
 
				uint i;
 

	
 
				if (patches_max < page->num) patches_max = page->num;
 

	
 
			for (PatchPage *page = &_patches_page[0]; page != endof(_patches_page); page++) {
 
				page->entries = MallocT<PatchEntry>(page->num);
 
				for (i = 0; i != page->num; i++) {
 
				for (uint i = 0; i != page->num; i++) {
 
					uint index;
 
					const SettingDesc *sd = GetPatchFromName(page->names[i], &index);
 
					assert(sd != NULL);
 

	
 
					page->entries[i].setting = sd;
 
					page->entries[i].index = index;
 
				}
 
			}
 
			first_time = false;
 
		}
 

	
 
		/* Resize the window to fit the largest patch tab */
 
		ResizeWindowForWidget(this, PATCHSEL_OPTIONSPANEL, 0, patches_max * SETTING_HEIGHT);
 
		this->page = 0;
 
		this->vscroll.pos = 0;
 
		this->vscroll.cap = (this->widget[PATCHSEL_OPTIONSPANEL].bottom - this->widget[PATCHSEL_OPTIONSPANEL].top - 8) / SETTING_HEIGHT;
 
		SetVScrollCount(this, _patches_page[page].num);
 

	
 
		/* Recentre the window for the new size */
 
		this->top = this->top - (patches_max * SETTING_HEIGHT) / 2;
 
		this->resize.step_height = SETTING_HEIGHT;
 
		this->resize.height = this->height;
 
		this->resize.step_width = 1;
 
		this->resize.width = this->width;
 

	
 
		this->LowerWidget(PATCHSEL_INTERFACE);
 
		this->LowerWidget(page + PATCHSEL_INTERFACE); // Depress button of currently selected page
 

	
 
		this->FindWindowPlacementAndResize(desc);
 
	}
 

	
 
	virtual void OnPaint()
 
	{
 
		const PatchPage *page = &_patches_page[this->page];
 
		uint i;
 

	
 
		/* Set up selected category */
 
		this->DrawWidgets();
 

	
 
		int x = SETTINGTREE_LEFT_OFFSET;
 
		int y = SETTINGTREE_TOP_OFFSET;
 
		for (i = 0; i != page->num; i++) {
 
		for (uint i = vscroll.pos; i != page->num && i < vscroll.pos + vscroll.cap; i++) {
 
			const SettingDesc *sd = page->entries[i].setting;
 
			DrawPatch(patches_ptr, sd, x, y, this->click - (i * 2));
 
			y += SETTING_HEIGHT;
 
		}
 
	}
 

	
 
	void DrawPatch(GameSettings *patches_ptr, const SettingDesc *sd, int x, int y, int state)
 
	{
 
		const SettingDescBase *sdb = &sd->desc;
 
		const void *var = GetVariableAddress(patches_ptr, &sd->save);
 
		bool editable = true;
 
		bool disabled = false;
 

	
 
		/* We do not allow changes of some items when we are a client in a networkgame */
 
		if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) editable = false;
 
		if ((sdb->flags & SGF_NETWORK_ONLY) && !_networking) editable = false;
 
		if ((sdb->flags & SGF_NO_NETWORK) && _networking) editable = false;
 

	
 
		if (sdb->cmd == SDT_BOOLX) {
 
			static const int _bool_ctabs[2][2] = {{9, 4}, {7, 6}};
 
			/* Draw checkbox for boolean-value either on/off */
 
			bool on = (*(bool*)var);
 

	
 
			DrawFrameRect(x, y, x + 19, y + 8, _bool_ctabs[!!on][!!editable], on ? FR_LOWERED : FR_NONE);
 
@@ -857,49 +857,49 @@ struct PatchesSelectionWindow : Window {
 
			} else {
 
				if (sdb->flags & SGF_CURRENCY) {
 
					SetDParam(0, STR_CONFIG_PATCHES_CURRENCY);
 
				} else if (sdb->flags & SGF_MULTISTRING) {
 
					SetDParam(0, sdb->str + value + 1);
 
				} else {
 
					SetDParam(0, (sdb->flags & SGF_NOCOMMA) ? STR_CONFIG_PATCHES_INT32 : STR_7024);
 
				}
 
				SetDParam(1, value);
 
			}
 
		}
 
		DrawString(x + 25, y, (sdb->str) + disabled, TC_FROMSTRING);
 
	}
 

	
 
	virtual void OnClick(Point pt, int widget)
 
	{
 
		switch (widget) {
 
			case PATCHSEL_OPTIONSPANEL: {
 
				int y = pt.y - SETTINGTREE_TOP_OFFSET;  // Shift y coordinate
 
				if (y < 0) return;  // Clicked above first entry
 

	
 
				int x = pt.x - SETTINGTREE_LEFT_OFFSET;  // Shift x coordinate
 
				if (x < 0) return;  // Clicked left of the entry
 

	
 
				byte btn = y / SETTING_HEIGHT;  // Compute which setting is selected
 
				byte btn = this->vscroll.pos + y / SETTING_HEIGHT;  // Compute which setting is selected
 
				if (y % SETTING_HEIGHT > SETTING_HEIGHT - 2) return;  // Clicked too low at the setting
 

	
 
				const PatchPage *page = &_patches_page[this->page];
 

	
 
				if (btn >= page->num) return;  // Clicked below the last setting of the page
 

	
 
				const SettingDesc *sd = page->entries[btn].setting;
 

	
 
				/* return if action is only active in network, or only settable by server */
 
				if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) return;
 
				if ((sd->desc.flags & SGF_NETWORK_ONLY) && !_networking) return;
 
				if ((sd->desc.flags & SGF_NO_NETWORK) && _networking) return;
 

	
 
				void *var = GetVariableAddress(patches_ptr, &sd->save);
 
				int32 value = (int32)ReadValue(var, sd->save.conv);
 

	
 
				/* clicked on the icon on the left side. Either scroller or bool on/off */
 
				if (x < 21) {
 
					const SettingDescBase *sdb = &sd->desc;
 
					int32 oldvalue = value;
 

	
 
					switch (sdb->cmd) {
 
					case SDT_BOOLX: value ^= 1; break;
 
					case SDT_ONEOFMANY:
 
@@ -937,100 +937,108 @@ struct PatchesSelectionWindow : Window {
 
					}
 

	
 
					if (value != oldvalue) {
 
						SetPatchValue(page->entries[btn].index, value);
 
						this->SetDirty();
 
					}
 
				} else {
 
					/* only open editbox for types that its sensible for */
 
					if (sd->desc.cmd != SDT_BOOLX && !(sd->desc.flags & SGF_MULTISTRING)) {
 
						/* Show the correct currency-translated value */
 
						if (sd->desc.flags & SGF_CURRENCY) value *= _currency->rate;
 

	
 
						this->entry = btn;
 
						SetDParam(0, value);
 
						ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_CONFIG_PATCHES_QUERY_CAPT, 10, 100, this, CS_NUMERAL, QSF_NONE);
 
					}
 
				}
 
			} break;
 

	
 
			case PATCHSEL_INTERFACE: case PATCHSEL_CONSTRUCTION: case PATCHSEL_VEHICLES:
 
			case PATCHSEL_STATIONS:  case PATCHSEL_ECONOMY:      case PATCHSEL_COMPETITORS:
 
				this->RaiseWidget(this->page + PATCHSEL_INTERFACE);
 
				this->page = widget - PATCHSEL_INTERFACE;
 
				this->LowerWidget(this->page + PATCHSEL_INTERFACE);
 
				SetVScrollCount(this, _patches_page[page].num);
 
				DeleteWindowById(WC_QUERY_STRING, 0);
 
				this->SetDirty();
 
				break;
 
		}
 
	}
 

	
 
	virtual void OnTimeout()
 
	{
 
		this->click = 0;
 
		this->SetDirty();
 
	}
 

	
 
	virtual void OnQueryTextFinished(char *str)
 
	{
 
		if (!StrEmpty(str)) {
 
			const PatchEntry *pe = &_patches_page[this->page].entries[this->entry];
 
			const SettingDesc *sd = pe->setting;
 
			int32 value = atoi(str);
 

	
 
			/* Save the correct currency-translated value */
 
			if (sd->desc.flags & SGF_CURRENCY) value /= _currency->rate;
 

	
 
			SetPatchValue(pe->index, value);
 
			this->SetDirty();
 
		}
 
	}
 

	
 
	virtual void OnResize(Point new_size, Point delta)
 
	{
 
		this->vscroll.cap += delta.y / SETTING_HEIGHT;
 
		SetVScrollCount(this, _patches_page[page].num);
 
	}
 
};
 

	
 
GameSettings *PatchesSelectionWindow::patches_ptr = NULL;
 
const int PatchesSelectionWindow::SETTINGTREE_LEFT_OFFSET = 5;
 
const int PatchesSelectionWindow::SETTINGTREE_TOP_OFFSET = 47;
 
int PatchesSelectionWindow::patches_max = 0;
 

	
 
static const Widget _patches_selection_widgets[] = {
 
{   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_MAUVE,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
 
{    WWT_CAPTION,   RESIZE_NONE,  COLOUR_MAUVE,    11,   369,     0,    13, STR_CONFIG_PATCHES_CAPTION,      STR_018C_WINDOW_TITLE_DRAG_THIS},
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_MAUVE,     0,   369,    14,    41, 0x0,                             STR_NULL},
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_MAUVE,     0,   369,    42,    50, 0x0,                             STR_NULL}, // PATCHSEL_OPTIONSPANEL
 
{    WWT_CAPTION,  RESIZE_RIGHT,  COLOUR_MAUVE,    11,   381,     0,    13, STR_CONFIG_PATCHES_CAPTION,      STR_018C_WINDOW_TITLE_DRAG_THIS},
 
{      WWT_PANEL,  RESIZE_RIGHT,  COLOUR_MAUVE,     0,   381,    14,    41, 0x0,                             STR_NULL},
 
{      WWT_PANEL,     RESIZE_RB,  COLOUR_MAUVE,     0,   369,    42,   215, 0x0,                             STR_NULL}, // PATCHSEL_OPTIONSPANEL
 
{  WWT_SCROLLBAR,    RESIZE_LRB,  COLOUR_MAUVE,   370,   381,    42,   203, 0x0,                             STR_0190_SCROLL_BAR_SCROLLS_LIST}, // PATCHSEL_SCROLLBAR
 
{  WWT_RESIZEBOX,   RESIZE_LRTB,  COLOUR_MAUVE,   370,   381,   204,   215, 0x0,                             STR_RESIZE_BUTTON}, // PATCHSEL_RESIZE
 

	
 
{    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_YELLOW,   10,    96,    16,    27, STR_CONFIG_PATCHES_GUI,          STR_NULL}, // PATCHSEL_INTERFACE
 
{    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_YELLOW,   97,   183,    16,    27, STR_CONFIG_PATCHES_CONSTRUCTION, STR_NULL}, // PATCHSEL_CONSTRUCTION
 
{    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_YELLOW,  184,   270,    16,    27, STR_CONFIG_PATCHES_VEHICLES,     STR_NULL}, // PATCHSEL_VEHICLES
 
{    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_YELLOW,  271,   357,    16,    27, STR_CONFIG_PATCHES_STATIONS,     STR_NULL}, // PATCHSEL_STATIONS
 
{    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_YELLOW,   10,    96,    28,    39, STR_CONFIG_PATCHES_ECONOMY,      STR_NULL}, // PATCHSEL_ECONOMY
 
{    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_YELLOW,   97,   183,    28,    39, STR_CONFIG_PATCHES_AI,           STR_NULL}, // PATCHSEL_COMPETITORS
 
{    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_YELLOW,   10,   100,    16,    27, STR_CONFIG_PATCHES_GUI,          STR_NULL}, // PATCHSEL_INTERFACE
 
{    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_YELLOW,  101,   191,    16,    27, STR_CONFIG_PATCHES_CONSTRUCTION, STR_NULL}, // PATCHSEL_CONSTRUCTION
 
{    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_YELLOW,  192,   283,    16,    27, STR_CONFIG_PATCHES_VEHICLES,     STR_NULL}, // PATCHSEL_VEHICLES
 
{    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_YELLOW,  284,   375,    16,    27, STR_CONFIG_PATCHES_STATIONS,     STR_NULL}, // PATCHSEL_STATIONS
 
{    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_YELLOW,   10,   100,    28,    39, STR_CONFIG_PATCHES_ECONOMY,      STR_NULL}, // PATCHSEL_ECONOMY
 
{    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_YELLOW,  101,   191,    28,    39, STR_CONFIG_PATCHES_AI,           STR_NULL}, // PATCHSEL_COMPETITORS
 
{   WIDGETS_END},
 
};
 

	
 
static const WindowDesc _patches_selection_desc = {
 
	WDP_CENTER, WDP_CENTER, 370, 51, 370, 51,
 
	WDP_CENTER, WDP_CENTER, 382, 216, 382, 425,
 
	WC_GAME_OPTIONS, WC_NONE,
 
	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 
	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
 
	_patches_selection_widgets,
 
};
 

	
 
void ShowPatchesSelection()
 
{
 
	DeleteWindowById(WC_GAME_OPTIONS, 0);
 
	new PatchesSelectionWindow(&_patches_selection_desc);
 
}
 

	
 

	
 
/**
 
 * Draw [<][>] boxes.
 
 * @param x the x position to draw
 
 * @param y the y position to draw
 
 * @param button_colour the colour of the button
 
 * @param state 0 = none clicked, 1 = first clicked, 2 = second clicked
 
 * @param clickable_left is the left button clickable?
 
 * @param clickable_right is the right button clickable?
 
 */
 
void DrawArrowButtons(int x, int y, Colours button_colour, byte state, bool clickable_left, bool clickable_right)
 
{
 
	int colour = _colour_gradient[button_colour][2];
 

	
 
	DrawFrameRect(x,      y + 1, x +  9, y + 9, button_colour, (state == 1) ? FR_LOWERED : FR_NONE);
0 comments (0 inline, 0 general)