Changeset - r11832:0a9347eb1597
[Not reviewed]
master
0 2 0
alberth - 16 years ago 2009-05-04 18:42:49
alberth@openttd.org
(svn r16227) -Codechange: Added nested widgets for error windows, tooltip window, and dropdown window.
2 files changed with 69 insertions and 9 deletions:
0 comments (0 inline, 0 general)
src/misc_gui.cpp
Show inline comments
 
@@ -427,57 +427,94 @@ struct AboutWindow : public Window {
 
void ShowAboutWindow()
 
{
 
	DeleteWindowById(WC_GAME_OPTIONS, 0);
 
	new AboutWindow();
 
}
 

	
 
/** Widgets of the error message windows */
 
enum ErrorMessageWidgets {
 
	EMW_CLOSE = 0,
 
	EMW_CAPTION,
 
	EMW_PANEL,
 
	EMW_FACE,
 
	EMW_MESSAGE,
 
};
 

	
 
static const Widget _errmsg_widgets[] = {
 
{   WWT_CLOSEBOX,   RESIZE_NONE,    COLOUR_RED,     0,    10,     0,    13, STR_BLACK_CROSS,           STR_TOOLTIP_CLOSE_WINDOW},
 
{    WWT_CAPTION,   RESIZE_NONE,    COLOUR_RED,    11,   239,     0,    13, STR_ERROR_MESSAGE_CAPTION, STR_NULL},
 
{      WWT_PANEL,   RESIZE_BOTTOM,  COLOUR_RED,     0,   239,    14,    45, 0x0,                       STR_NULL},
 
{      WWT_EMPTY,   RESIZE_NONE,    COLOUR_RED,     0,     0,     0,     0, 0x0,                       STR_NULL},
 
{      WWT_EMPTY,   RESIZE_NONE,    COLOUR_RED,     2,   237,    14,    45, 0x0,                       STR_NULL},
 
{    WIDGETS_END},
 
};
 

	
 
static const NWidgetPart _nested_errmsg_widgets[] = {
 
	NWidget(NWID_LAYERED),
 
		NWidget(NWID_VERTICAL),
 
			NWidget(NWID_HORIZONTAL),
 
				NWidget(WWT_CLOSEBOX, COLOUR_RED, EMW_CLOSE),
 
				NWidget(WWT_CAPTION, COLOUR_RED, EMW_CAPTION), SetDataTip(STR_ERROR_MESSAGE_CAPTION, STR_NULL),
 
			EndContainer(),
 
			NWidget(WWT_PANEL, COLOUR_RED, EMW_PANEL),
 
				NWidget(WWT_EMPTY, COLOUR_RED, EMW_MESSAGE), SetPadding(0, 2, 0, 2), SetMinimalSize(236, 32),
 
				NWidget(NWID_SPACER), SetResize(0, 1),
 
			EndContainer(),
 
		EndContainer(),
 
		NWidget(NWID_VERTICAL),
 
			NWidget(NWID_HORIZONTAL),
 
				NWidget(WWT_EMPTY, COLOUR_RED, EMW_FACE), SetMinimalSize(1, 1), SetFill(false, false),
 
				NWidget(NWID_SPACER), SetFill(1, 0),
 
			EndContainer(),
 
			NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
 
		EndContainer(),
 
	EndContainer(),
 
};
 

	
 
static const Widget _errmsg_face_widgets[] = {
 
{   WWT_CLOSEBOX,   RESIZE_NONE,    COLOUR_RED,     0,    10,     0,    13, STR_BLACK_CROSS,                         STR_TOOLTIP_CLOSE_WINDOW},
 
{    WWT_CAPTION,   RESIZE_NONE,    COLOUR_RED,    11,   333,     0,    13, STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY, STR_NULL},
 
{      WWT_PANEL,   RESIZE_BOTTOM,  COLOUR_RED,     0,   333,    14,   136, 0x0,                                     STR_NULL},
 
{      WWT_EMPTY,   RESIZE_NONE,    COLOUR_RED,     2,    92,    16,   135, 0x0,                                     STR_NULL},
 
{      WWT_EMPTY,   RESIZE_NONE,    COLOUR_RED,    94,   331,    14,   136, 0x0,                                     STR_NULL},
 
{   WIDGETS_END},
 
};
 

	
 
static const NWidgetPart _nested_errmsg_face_widgets[] = {
 
		NWidget(NWID_HORIZONTAL),
 
			NWidget(WWT_CLOSEBOX, COLOUR_RED, EMW_CLOSE),
 
			NWidget(WWT_CAPTION, COLOUR_RED, EMW_CAPTION), SetDataTip(STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY, STR_NULL),
 
		EndContainer(),
 
		NWidget(WWT_PANEL, COLOUR_RED, EMW_PANEL),
 
			NWidget(NWID_HORIZONTAL), SetPIP(2, 1, 2),
 
				NWidget(WWT_EMPTY, COLOUR_RED, EMW_FACE), SetMinimalSize(91, 120), SetPadding(2, 0, 1, 0),
 
				NWidget(WWT_EMPTY, COLOUR_RED, EMW_MESSAGE), SetMinimalSize(238, 123),
 
			EndContainer(),
 
			NWidget(NWID_SPACER), SetResize(0, 1),
 
		EndContainer(),
 
	EndContainer(),
 
};
 

	
 
struct ErrmsgWindow : public Window {
 
private:
 
	uint duration;
 
	uint64 decode_params[20];
 
	StringID message_1;
 
	StringID message_2;
 
	bool show_company_manager_face;
 

	
 
	int y[4];
 

	
 
public:
 
	ErrmsgWindow(Point pt, int width, int height, StringID msg1, StringID msg2, const Widget *widget, bool show_company_manager_face) :
 
			Window(pt.x, pt.y, width, height, WC_ERRMSG, widget),
 
			show_company_manager_face(show_company_manager_face)
 
	{
 
		this->duration = _settings_client.gui.errmsg_duration;
 
		CopyOutDParam(this->decode_params, 0, lengthof(this->decode_params));
 
		this->message_1 = msg1;
 
		this->message_2 = msg2;
 
		this->desc_flags = WDF_STD_BTN | WDF_DEF_WIDGET;
 

	
 
		SwitchToErrorRefStack();
 
		RewindTextRefStack();
 

	
 
@@ -536,86 +573,95 @@ public:
 
	}
 

	
 
	virtual void OnHundredthTick()
 
	{
 
		if (--this->duration == 0) delete this;
 
	}
 

	
 
	~ErrmsgWindow()
 
	{
 
		SetRedErrorSquare(INVALID_TILE);
 
		extern StringID _switch_mode_errorstr;
 
		_switch_mode_errorstr = INVALID_STRING_ID;
 
	}
 

	
 
	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
 
	{
 
		if (keycode != WKC_SPACE) return ES_NOT_HANDLED;
 
		delete this;
 
		return ES_HANDLED;
 
	}
 
};
 

	
 
void ShowErrorMessage(StringID msg_1, StringID msg_2, int x, int y)
 
{
 
	static Widget *generated_errmsg_widgets = NULL;
 
	static Widget *generated_errmsg_face_widgets = NULL;
 

	
 
	DeleteWindowById(WC_ERRMSG, 0);
 

	
 
	if (!_settings_client.gui.errmsg_duration) return;
 

	
 
	if (msg_2 == STR_NULL) msg_2 = STR_EMPTY;
 

	
 
	Point pt;
 
	const ViewPort *vp;
 

	
 
	if (msg_1 != STR_ERROR_OWNED_BY || GetDParam(2) >= MAX_COMPANIES) {
 
		if ((x | y) != 0) {
 
			pt = RemapCoords2(x, y);
 
			vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
 

	
 
			/* move x pos to opposite corner */
 
			pt.x = UnScaleByZoom(pt.x - vp->virtual_left, vp->zoom) + vp->left;
 
			pt.x = (pt.x < (_screen.width >> 1)) ? _screen.width - 260 : 20;
 

	
 
			/* move y pos to opposite corner */
 
			pt.y = UnScaleByZoom(pt.y - vp->virtual_top, vp->zoom) + vp->top;
 
			pt.y = (pt.y < (_screen.height >> 1)) ? _screen.height - 80 : 100;
 

	
 
		} else {
 
			pt.x = (_screen.width - 240) >> 1;
 
			pt.y = (_screen.height - 46) >> 1;
 
		}
 
		new ErrmsgWindow(pt, 240, 46, msg_1, msg_2, _errmsg_widgets, false);
 

	
 
		const Widget *wid = InitializeWidgetArrayFromNestedWidgets(_nested_errmsg_widgets, lengthof(_nested_errmsg_widgets),
 
													_errmsg_widgets, &generated_errmsg_widgets);
 
		new ErrmsgWindow(pt, 240, 46, msg_1, msg_2, wid, false);
 
	} else {
 
		if ((x | y) != 0) {
 
			pt = RemapCoords2(x, y);
 
			vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
 
			pt.x = Clamp(UnScaleByZoom(pt.x - vp->virtual_left, vp->zoom) + vp->left - (334 / 2),  0, _screen.width  - 334);
 
			pt.y = Clamp(UnScaleByZoom(pt.y - vp->virtual_top,  vp->zoom) + vp->top  - (137 / 2), 22, _screen.height - 137);
 
		} else {
 
			pt.x = (_screen.width  - 334) >> 1;
 
			pt.y = (_screen.height - 137) >> 1;
 
		}
 
		new ErrmsgWindow(pt, 334, 137, msg_1, msg_2, _errmsg_face_widgets, true);
 

	
 
		const Widget *wid = InitializeWidgetArrayFromNestedWidgets(_nested_errmsg_face_widgets, lengthof(_nested_errmsg_face_widgets),
 
													_errmsg_face_widgets, &generated_errmsg_face_widgets);
 
		new ErrmsgWindow(pt, 334, 137, msg_1, msg_2, wid, true);
 
	}
 
}
 

	
 
void ShowEstimatedCostOrIncome(Money cost, int x, int y)
 
{
 
	StringID msg = STR_MESSAGE_ESTIMATED_COST;
 

	
 
	if (cost < 0) {
 
		cost = -cost;
 
		msg = STR_MESSAGE_ESTIMATED_INCOME;
 
	}
 
	SetDParam(0, cost);
 
	ShowErrorMessage(INVALID_STRING_ID, msg, x, y);
 
}
 

	
 
void ShowCostOrIncomeAnimation(int x, int y, int z, Money cost)
 
{
 
	Point pt = RemapCoords(x, y, z);
 
	StringID msg = STR_INCOME_FLOAT_COST;
 

	
 
	if (cost < 0) {
 
		cost = -cost;
 
		msg = STR_INCOME_FLOAT_INCOME;
 
	}
 
@@ -641,48 +687,52 @@ TextEffectID ShowFillingPercent(int x, i
 
	return AddTextEffect(string, pt.x, pt.y, 0xFFFF, TE_STATIC);
 
}
 

	
 
void UpdateFillingPercent(TextEffectID te_id, uint8 percent, StringID string)
 
{
 
	assert(string != STR_NULL);
 

	
 
	SetDParam(0, percent);
 
	UpdateTextEffect(te_id, string);
 
}
 

	
 
void HideFillingPercent(TextEffectID *te_id)
 
{
 
	if (*te_id == INVALID_TE_ID) return;
 

	
 
	RemoveTextEffect(*te_id);
 
	*te_id = INVALID_TE_ID;
 
}
 

	
 
static const Widget _tooltips_widgets[] = {
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   199,     0,    31, 0x0, STR_NULL},
 
{   WIDGETS_END},
 
};
 

	
 
static const NWidgetPart _nested_tooltips_widgets[] = {
 
	NWidget(WWT_PANEL, COLOUR_GREY, 0), SetMinimalSize(200, 32), EndContainer(),
 
};
 

	
 
struct TooltipsWindow : public Window
 
{
 
	StringID string_id;
 
	byte paramcount;
 
	uint64 params[5];
 
	bool use_left_mouse_button;
 

	
 
	TooltipsWindow(int x, int y, int width, int height, const Widget *widget,
 
								 StringID str, uint paramcount, const uint64 params[], bool use_left_mouse_button) :
 
			Window(x, y, width, height, WC_TOOLTIPS, widget)
 
	{
 
		this->string_id = str;
 
		assert(sizeof(this->params[0]) == sizeof(params[0]));
 
		assert(paramcount <= lengthof(this->params));
 
		memcpy(this->params, params, sizeof(this->params[0]) * paramcount);
 
		this->paramcount = paramcount;
 
		this->use_left_mouse_button = use_left_mouse_button;
 

	
 
		this->flags4 &= ~WF_WHITE_BORDER_MASK; // remove white-border from tooltip
 
		this->widget[0].right = width;
 
		this->widget[0].bottom = height;
 

	
 
		FindWindowPlacementAndResize(width, height);
 
	}
 
@@ -693,73 +743,77 @@ struct TooltipsWindow : public Window
 
		GfxFillRect(1, 1, this->width - 2, this->height - 2, 0x44);
 

	
 
		for (uint arg = 0; arg < this->paramcount; arg++) {
 
			SetDParam(arg, this->params[arg]);
 
		}
 
		DrawStringMultiLine(1, this->width - 1, 0, this->height, this->string_id, TC_FROMSTRING, SA_CENTER);
 
	}
 

	
 
	virtual void OnMouseLoop()
 
	{
 
		/* We can show tooltips while dragging tools. These are shown as long as
 
		 * we are dragging the tool. Normal tooltips work with rmb */
 
		if (this->use_left_mouse_button ? !_left_button_down : !_right_button_down) delete this;
 
	}
 
};
 

	
 
/** Shows a tooltip
 
 * @param str String to be displayed
 
 * @param paramcount number of params to deal with
 
 * @param params (optional) up to 5 pieces of additional information that may be added to a tooltip
 
 * @param use_left_mouse_button close the tooltip when the left (true) or right (false) mousebutton is released
 
 */
 
void GuiShowTooltips(StringID str, uint paramcount, const uint64 params[], bool use_left_mouse_button)
 
{
 
	static Widget *generated_tooltips_widgets = NULL;
 

	
 
	DeleteWindowById(WC_TOOLTIPS, 0);
 

	
 
	if (str == STR_NULL) return;
 

	
 
	for (uint i = 0; i != paramcount; i++) SetDParam(i, params[i]);
 
	char buffer[512];
 
	GetString(buffer, str, lastof(buffer));
 

	
 
	Dimension br = GetStringBoundingBox(buffer);
 
	br.width += 6; br.height += 4; // increase slightly to have some space around the box
 

	
 
	/* Cut tooltip length to 200 pixels max, wrap to new line if longer */
 
	if (br.width > 200) {
 
		br.height += ((br.width - 4) / 176) * 10;
 
		br.width = 200;
 
	}
 

	
 
	/* Correctly position the tooltip position, watch out for window and cursor size
 
	 * Clamp value to below main toolbar and above statusbar. If tooltip would
 
	 * go below window, flip it so it is shown above the cursor */
 
	int y = Clamp(_cursor.pos.y + _cursor.size.y + _cursor.offs.y + 5, 22, _screen.height - 12);
 
	if (y + br.height > _screen.height - 12) y = _cursor.pos.y + _cursor.offs.y - br.height - 5;
 
	int x = Clamp(_cursor.pos.x - (br.width >> 1), 0, _screen.width - br.width);
 

	
 
	new TooltipsWindow(x, y, br.width, br.height, _tooltips_widgets, str, paramcount, params, use_left_mouse_button);
 
	const Widget *wid = InitializeWidgetArrayFromNestedWidgets(_nested_tooltips_widgets, lengthof(_nested_tooltips_widgets),
 
													_tooltips_widgets, &generated_tooltips_widgets);
 
	new TooltipsWindow(x, y, br.width, br.height, wid, str, paramcount, params, use_left_mouse_button);
 
}
 

	
 

	
 
static int DrawStationCoverageText(const AcceptedCargo cargo,
 
	int str_x, int str_y, StationCoverageType sct, bool supplies)
 
{
 
	bool first = true;
 

	
 
	char string[512];
 
	char *b = InlineString(string, supplies ? STR_STATION_BUILD_SUPPLIES_CARGO : STR_STATION_BUILD_ACCEPTS_CARGO);
 

	
 
	for (CargoID i = 0; i < NUM_CARGO; i++) {
 
		if (b >= lastof(string) - (1 + 2 * 4)) break; // ',' or ' ' and two calls to Utf8Encode()
 
		switch (sct) {
 
			case SCT_PASSENGERS_ONLY: if (!IsCargoInClass(i, CC_PASSENGERS)) continue; break;
 
			case SCT_NON_PASSENGERS_ONLY: if (IsCargoInClass(i, CC_PASSENGERS)) continue; break;
 
			case SCT_ALL: break;
 
			default: NOT_REACHED();
 
		}
 
		if (cargo[i] >= (supplies ? 1U : 8U)) {
 
			if (first) {
 
				first = false;
 
			} else {
 
				/* Add a comma if this is not the first item */
src/widgets/dropdown.cpp
Show inline comments
 
@@ -48,48 +48,55 @@ uint DropDownListCharStringItem::Width()
 
void DropDownListCharStringItem::Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const
 
{
 
	DrawString(left + 2, right - 2, top, this->string, sel ? TC_WHITE : TC_BLACK);
 
}
 

	
 
/**
 
 * Delete all items of a drop down list and the list itself
 
 * @param list List to delete.
 
 */
 
static void DeleteDropDownList(DropDownList *list)
 
{
 
	for (DropDownList::iterator it = list->begin(); it != list->end(); ++it) {
 
		DropDownListItem *item = *it;
 
		delete item;
 
	}
 
	delete list;
 
}
 

	
 
static const Widget _dropdown_menu_widgets[] = {
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_END,     0, 0,     0, 0, 0x0, STR_NULL},
 
{  WWT_SCROLLBAR,   RESIZE_NONE,  COLOUR_END,     0, 0,     0, 0, 0x0, STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST},
 
{   WIDGETS_END},
 
};
 

	
 
static const NWidgetPart _nested_dropdown_menu_widgets[] = {
 
	NWidget(NWID_LAYERED),
 
		NWidget(WWT_PANEL, COLOUR_END, 0), SetMinimalSize(1, 1), EndContainer(),
 
		NWidget(WWT_SCROLLBAR, COLOUR_END, 1), SetMinimalSize(1, 1),
 
	EndContainer(),
 
};
 

	
 
struct DropdownWindow : Window {
 
	WindowClass parent_wnd_class;
 
	WindowNumber parent_wnd_num;
 
	byte parent_button;
 
	DropDownList *list;
 
	int selected_index;
 
	byte click_delay;
 
	bool drag_mode;
 
	bool instant_close;
 
	int scrolling;
 

	
 
	DropdownWindow(int x, int y, int width, int height, const Widget *widget) : Window(x, y, width, height, WC_DROPDOWN_MENU, widget)
 
	{
 
		this->FindWindowPlacementAndResize(width, height);
 
	}
 

	
 
	~DropdownWindow()
 
	{
 
		Window *w2 = FindWindowById(this->parent_wnd_class, this->parent_wnd_num);
 
		if (w2 != NULL) {
 
			w2->RaiseWidget(this->parent_button);
 
			w2->InvalidateWidget(this->parent_button);
 
		}
 

	
 
@@ -217,48 +224,50 @@ struct DropdownWindow : Window {
 
				}
 
				this->click_delay = 2;
 
			} else {
 
				if (_cursor.pos.y <= this->top + 2) {
 
					/* Cursor is above the list, set scroll up */
 
					this->scrolling = -1;
 
					return;
 
				} else if (_cursor.pos.y >= this->top + this->height - 2) {
 
					/* Cursor is below list, set scroll down */
 
					this->scrolling = 1;
 
					return;
 
				}
 

	
 
				if (!this->GetDropDownItem(item)) return;
 
			}
 

	
 
			this->selected_index = item;
 
			this->SetDirty();
 
		}
 
	}
 
};
 

	
 
void ShowDropDownList(Window *w, DropDownList *list, int selected, int button, uint width, bool auto_width, bool instant_close)
 
{
 
	static Widget *generated_dropdown_menu_widgets = NULL;
 

	
 
	DeleteWindowById(WC_DROPDOWN_MENU, 0);
 

	
 
	w->LowerWidget(button);
 
	w->InvalidateWidget(button);
 

	
 
	/* Our parent's button widget is used to determine where to place the drop
 
	 * down list window. */
 
	const Widget *wi = &w->widget[button];
 

	
 
	/* The preferred position is just below the dropdown calling widget */
 
	int top = w->top + wi->bottom + 1;
 

	
 
	if (width == 0) width = wi->right - wi->left + 1;
 

	
 
	uint max_item_width = 0;
 

	
 
	if (auto_width) {
 
		/* Find the longest item in the list */
 
		for (DropDownList::const_iterator it = list->begin(); it != list->end(); ++it) {
 
			const DropDownListItem *item = *it;
 
			max_item_width = max(max_item_width, item->Width() + 5);
 
		}
 
	}
 

	
 
@@ -281,54 +290,51 @@ void ShowDropDownList(Window *w, DropDow
 

	
 
	/* Check if the dropdown will fully fit below the widget */
 
	if (top + height + 4 >= screen_bottom) {
 
		w3 = FindWindowById(WC_MAIN_TOOLBAR, 0);
 
		int screen_top = w3 == NULL ? 0 : w3->top + w3->height;
 

	
 
		/* If not, check if it will fit above the widget */
 
		if (w->top + wi->top - height > screen_top) {
 
			top = w->top + wi->top - height - 4;
 
		} else {
 
			/* ... and lastly if it won't, enable the scroll bar and fit the
 
			 * list in below the widget */
 
			int avg_height = list_height / (int)list->size();
 
			int rows = (screen_bottom - 4 - top) / avg_height;
 
			height = rows * avg_height;
 
			scroll = true;
 
			/* Add space for the scroll bar if we automatically determined
 
			 * the width of the list. */
 
			max_item_width += 12;
 
		}
 
	}
 

	
 
	if (auto_width) width = max(width, max_item_width);
 

	
 
	DropdownWindow *dw = new DropdownWindow(
 
		w->left + wi->left,
 
		top,
 
		width,
 
		height + 4,
 
		_dropdown_menu_widgets);
 
	const Widget *wid = InitializeWidgetArrayFromNestedWidgets(_nested_dropdown_menu_widgets, lengthof(_nested_dropdown_menu_widgets),
 
													_dropdown_menu_widgets, &generated_dropdown_menu_widgets);
 
	DropdownWindow *dw = new DropdownWindow(w->left + wi->left, top, width, height + 4, wid);
 

	
 
	dw->widget[0].colour = wi->colour;
 
	dw->widget[0].right = width - 1;
 
	dw->widget[0].bottom = height + 3;
 

	
 
	dw->SetWidgetHiddenState(1, !scroll);
 

	
 
	if (scroll) {
 
		/* We're scrolling, so enable the scroll bar and shrink the list by
 
		 * the scrollbar's width */
 
		dw->widget[1].colour = wi->colour;
 
		dw->widget[1].right  = dw->widget[0].right;
 
		dw->widget[1].left   = dw->widget[1].right - 11;
 
		dw->widget[1].bottom = dw->widget[0].bottom;
 
		dw->widget[0].right -= 12;
 

	
 
		/* Capacity is the average number of items visible */
 
		dw->vscroll.cap   = height * (uint16)list->size() / list_height;
 
		dw->vscroll.count = (uint16)list->size();
 
	}
 

	
 
	dw->desc_flags = WDF_DEF_WIDGET;
 
	dw->flags4 &= ~WF_WHITE_BORDER_MASK;
 

	
0 comments (0 inline, 0 general)