changeset 12323:5ae30511f96c draft

(svn r16740) -Codechange: Self-sizing widgets in intro screen, town directory, and found town windows.
author alberth <alberth@openttd.org>
date Sat, 04 Jul 2009 15:35:36 +0000
parents 9f25a6f56a93
children 124e9247dd35
files src/intro_gui.cpp src/town_gui.cpp src/widget.cpp src/widget_type.h src/window.cpp src/window_gui.h
diffstat 6 files changed, 173 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/src/intro_gui.cpp
+++ b/src/intro_gui.cpp
@@ -83,6 +83,18 @@
 		}
 	}
 
+	virtual Dimension GetWidgetContentSize(int widget)
+	{
+		Dimension d = {0, 0};
+		if (widget == SGI_DIFFICULTIES) {
+			for (uint i = STR_DIFFICULTY_LEVEL_EASY; i <= STR_DIFFICULTY_LEVEL_CUSTOM; i++) {
+				SetDParam(0, STR_DIFFICULTY_LEVEL_EASY + _settings_newgame.difficulty.diff_level);
+				d = maxdim(d, GetStringBoundingBox(STR_INTRO_DIFFICULTY));
+			}
+		}
+		return d;
+	}
+
 	virtual void OnClick(Point pt, int widget)
 	{
 #ifdef ENABLE_NETWORK
--- a/src/town_gui.cpp
+++ b/src/town_gui.cpp
@@ -643,6 +643,43 @@
 		}
 	}
 
+	virtual Dimension GetWidgetContentSize(int widget)
+	{
+		Dimension d = {0, 0};
+		switch (widget) {
+			case TDW_SORTNAME: {
+				d = GetStringBoundingBox(STR_SORT_BY_NAME);
+				d.width += WD_SORTBUTTON_ARROW_WIDTH * 2; // Doubled since the word is centered, also looks nice.
+				break;
+			}
+
+			case TDW_SORTPOPULATION: {
+				d = GetStringBoundingBox(STR_SORT_BY_POPULATION);
+				d.width += WD_SORTBUTTON_ARROW_WIDTH * 2; // Doubled since the word is centered, also looks nice.
+				break;
+			}
+
+			case TDW_CENTERTOWN:
+				for (uint i = 0; i < this->towns.Length(); i++) {
+					const Town *t = this->towns[i];
+
+					assert(t != NULL);
+
+					SetDParam(0, t->index);
+					SetDParam(1, 10000000); // 10^7
+					d = maxdim(d, GetStringBoundingBox(STR_TOWN_DIRECTORY_TOWN));
+				}
+				d.width += 2 + 2; // Text is rendered with 2 pixel offset at both sides.
+				break;
+
+			case TDW_EMPTYBOTTOM:
+				SetDParam(0, 1000000000); // 10^9
+				d = GetStringBoundingBox(STR_TOWN_POPULATION);
+				break;
+		}
+		return d;
+	}
+
 	virtual void OnClick(Point pt, int widget)
 	{
 		switch (widget) {
@@ -676,7 +713,7 @@
 				if (id_v >= this->towns.Length()) return; // click out of town bounds
 
 				const Town *t = this->towns[id_v];
-				assert(t->xy != INVALID_TILE);
+				assert(t != NULL);
 				if (_ctrl_pressed) {
 					ShowExtraViewPortWindow(t->xy);
 				} else {
--- a/src/widget.cpp
+++ b/src/widget.cpp
@@ -891,15 +891,18 @@
 /* ~NWidgetContainer() takes care of #next and #prev data members. */
 
 /**
- * @fn int NWidgetBase::SetupSmallestSize()
+ * @fn int NWidgetBase::SetupSmallestSize(Window *w)
  * Compute smallest size needed by the widget.
  *
  * The smallest size of a widget is the smallest size that a widget needs to
- * display itself properly.
- * In addition, filling and resizing of the widget are computed.
+ * display itself properly. In addition, filling and resizing of the widget are computed.
+ * If \a w is not \c NULL, the function calls #Window::GetWidgetContentSize for each leaf widget and
+ * background widget without child with a non-negative index.
+ *
+ * @param w Optional window owning the widget.
  * @return Biggest index in the widget array of all child widgets (\c -1 if no index is used).
  *
- * @note After the computation, the results can be queried by accessing the data members of the widget.
+ * @note After the computation, the results can be queried by accessing the #smallest_x and #smallest_y data members of the widget.
  */
 
 /**
@@ -1083,14 +1086,6 @@
 	this->tool_tip = tool_tip;
 }
 
-int NWidgetCore::SetupSmallestSize()
-{
-	this->smallest_x = this->min_x;
-	this->smallest_y = this->min_y;
-	/* All other data is already at the right place. */
-	return this->index;
-}
-
 void NWidgetCore::FillNestedArray(NWidgetCore **array, uint length)
 {
 	if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this;
@@ -1237,7 +1232,7 @@
 {
 }
 
-int NWidgetStacked::SetupSmallestSize()
+int NWidgetStacked::SetupSmallestSize(Window *w)
 {
 	/* First sweep, recurse down and compute minimal size and filling. */
 	int biggest_index = -1;
@@ -1248,7 +1243,7 @@
 	this->resize_x = (this->head != NULL) ? 1 : 0;
 	this->resize_y = (this->head != NULL) ? 1 : 0;
 	for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
-		int idx = child_wid->SetupSmallestSize();
+		int idx = child_wid->SetupSmallestSize(w);
 		biggest_index = max(biggest_index, idx);
 
 		this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right);
@@ -1349,7 +1344,7 @@
 {
 }
 
-int NWidgetHorizontal::SetupSmallestSize()
+int NWidgetHorizontal::SetupSmallestSize(Window *w)
 {
 	int biggest_index = -1;
 	this->smallest_x = 0;   // Sum of minimal size of all childs.
@@ -1362,7 +1357,7 @@
 	/* 1. Forward call, collect biggest nested array index, and longest child length. */
 	uint longest = 0; // Longest child found.
 	for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
-		int idx = child_wid->SetupSmallestSize();
+		int idx = child_wid->SetupSmallestSize(w);
 		biggest_index = max(biggest_index, idx);
 		longest = max(longest, child_wid->smallest_x);
 	}
@@ -1500,7 +1495,7 @@
 {
 }
 
-int NWidgetVertical::SetupSmallestSize()
+int NWidgetVertical::SetupSmallestSize(Window *w)
 {
 	int biggest_index = -1;
 	this->smallest_x = 0;   // Biggest child.
@@ -1513,7 +1508,7 @@
 	/* 1. Forward call, collect biggest nested array index, and longest child length. */
 	uint highest = 0; // Highest child found.
 	for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
-		int idx = child_wid->SetupSmallestSize();
+		int idx = child_wid->SetupSmallestSize(w);
 		biggest_index = max(biggest_index, idx);
 		highest = max(highest, child_wid->smallest_y);
 	}
@@ -1628,7 +1623,7 @@
 	this->SetResize(0, 0);
 }
 
-int NWidgetSpacer::SetupSmallestSize()
+int NWidgetSpacer::SetupSmallestSize(Window *w)
 {
 	this->smallest_x = this->min_x;
 	this->smallest_y = this->min_y;
@@ -1719,11 +1714,11 @@
 	this->child->SetPIP(pip_pre, pip_inter, pip_post);
 }
 
-int NWidgetBackground::SetupSmallestSize()
+int NWidgetBackground::SetupSmallestSize(Window *w)
 {
 	int biggest_index = this->index;
 	if (this->child != NULL) {
-		int idx = this->child->SetupSmallestSize();
+		int idx = this->child->SetupSmallestSize(w);
 		biggest_index = max(biggest_index, idx);
 
 		this->smallest_x = this->child->smallest_x;
@@ -1733,8 +1728,13 @@
 		this->resize_x = this->child->resize_x;
 		this->resize_y = this->child->resize_y;
 	} else {
-		this->smallest_x = this->min_x;
-		this->smallest_y = this->min_y;
+		Dimension d = {this->min_x, this->min_y};
+		if (w != NULL) { // A non-NULL window pointer acts as switch to turn dynamic widget size on.
+			if (this->index >= 0) d = maxdim(d, w->GetWidgetContentSize(this->index));
+			if (this->type == WWT_FRAME || this->type == WWT_INSET) d = maxdim(d, GetStringBoundingBox(this->widget_data));
+		}
+		this->smallest_x = d.width;
+		this->smallest_y = d.height;
 	}
 
 	return biggest_index;
@@ -1918,6 +1918,82 @@
 	}
 }
 
+int NWidgetLeaf::SetupSmallestSize(Window *w)
+{
+	Dimension d = {this->min_x, this->min_y}; // At least minimal size is needed.
+
+	if (w != NULL) { // A non-NULL window pointer acts as switch to turn dynamic widget sizing on.
+		Dimension d2 = {0, 0};
+		if (this->index >= 0) d2 = maxdim(d2, w->GetWidgetContentSize(this->index)); // If appropriate, ask window for smallest size.
+
+		/* Check size requirements of the widget itself too.
+		 * Also, add the offset used for rendering.
+		 */
+		switch (this->type) {
+			case WWT_EMPTY:
+			case WWT_MATRIX:
+			case WWT_SCROLLBAR:
+			case WWT_SCROLL2BAR:
+			case WWT_HSCROLLBAR:
+			case WWT_STICKYBOX:
+			case WWT_RESIZEBOX:
+				break;
+
+			case WWT_PUSHBTN:
+			case WWT_EDITBOX:
+				d2.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
+				d2.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
+				break;
+
+			case WWT_IMGBTN:
+			case WWT_PUSHIMGBTN:
+			case WWT_IMGBTN_2:
+				d2 = maxdim(d2, GetSpriteSize(this->widget_data));
+				d2.height += WD_IMGBTN_TOP;
+				d2.width += WD_IMGBTN_LEFT;
+				break;
+
+			case WWT_CLOSEBOX:
+				d2 = maxdim(d2, GetSpriteSize(this->widget_data));
+				d2.height += WD_CLOSEBOX_TOP;
+				break;
+
+			case WWT_TEXTBTN:
+			case WWT_PUSHTXTBTN:
+			case WWT_TEXTBTN_2:
+				d2 = maxdim(d2, GetStringBoundingBox(this->widget_data));
+				d2.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
+				d2.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
+				break;
+
+			case WWT_LABEL:
+			case WWT_TEXT:
+				d2 = maxdim(d2, GetStringBoundingBox(this->widget_data));
+				break;
+
+			case WWT_CAPTION:
+				d2 = maxdim(d2, GetStringBoundingBox(this->widget_data));
+				d2.width += WD_CAPTIONTEXT_LEFT + WD_CAPTIONTEXT_RIGHT;
+				d2.height += WD_CAPTIONTEXT_TOP;
+				break;
+
+			case WWT_DROPDOWN:
+				d2 = maxdim(d2, GetStringBoundingBox(this->widget_data));
+				d2.width += WD_DROPDOWNTEXT_LEFT + WD_DROPDOWNTEXT_RIGHT;
+				d2.height += WD_DROPDOWNTEXT_TOP;
+				break;
+
+			default:
+				NOT_REACHED();
+		}
+		d = maxdim(d, d2);
+	}
+	this->smallest_x = d.width;
+	this->smallest_y = d.height;
+	/* All other data is already at the right place. */
+	return this->index;
+}
+
 void NWidgetLeaf::Draw(const Window *w)
 {
 	if (this->current_x == 0 || this->current_y == 0) return;
@@ -2062,7 +2138,7 @@
 Widget *InitializeNWidgets(NWidgetBase *nwid, bool rtl)
 {
 	/* Initialize nested widgets. */
-	int biggest_index = nwid->SetupSmallestSize();
+	int biggest_index = nwid->SetupSmallestSize(NULL);
 	nwid->AssignSizePosition(ST_ARRAY, 0, 0, nwid->smallest_x, nwid->smallest_y, (nwid->resize_x > 0), (nwid->resize_y > 0), rtl);
 
 	/* Construct a local widget array and initialize all its types to #WWT_LAST. */
--- a/src/widget_type.h
+++ b/src/widget_type.h
@@ -165,7 +165,7 @@
 public:
 	NWidgetBase(WidgetType tp);
 
-	virtual int SetupSmallestSize() = 0;
+	virtual int SetupSmallestSize(Window *w) = 0;
 	virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool allow_resize_x, bool allow_resize_y, bool rtl) = 0;
 
 	virtual void StoreWidgets(Widget *widgets, int length, bool left_moving, bool top_moving, bool rtl) = 0;
@@ -284,7 +284,6 @@
 	inline void SetDisabled(bool disabled);
 	inline bool IsDisabled();
 
-	int SetupSmallestSize();
 	void StoreWidgets(Widget *widgets, int length, bool left_moving, bool top_moving, bool rtl);
 	/* virtual */ void FillNestedArray(NWidgetCore **array, uint length);
 
@@ -355,7 +354,7 @@
 public:
 	NWidgetStacked(WidgetType tp);
 
-	int SetupSmallestSize();
+	int SetupSmallestSize(Window *w);
 	void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool allow_resize_x, bool allow_resize_y, bool rtl);
 	void StoreWidgets(Widget *widgets, int length, bool left_moving, bool top_moving, bool rtl);
 
@@ -395,7 +394,7 @@
 public:
 	NWidgetHorizontal(NWidContainerFlags flags = NC_NONE);
 
-	int SetupSmallestSize();
+	int SetupSmallestSize(Window *w);
 	void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool allow_resize_x, bool allow_resize_y, bool rtl);
 
 	void StoreWidgets(Widget *widgets, int length, bool left_moving, bool top_moving, bool rtl);
@@ -418,7 +417,7 @@
 public:
 	NWidgetVertical(NWidContainerFlags flags = NC_NONE);
 
-	int SetupSmallestSize();
+	int SetupSmallestSize(Window *w);
 	void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool allow_resize_x, bool allow_resize_y, bool rtl);
 
 	void StoreWidgets(Widget *widgets, int length, bool left_moving, bool top_moving, bool rtl);
@@ -431,7 +430,7 @@
 public:
 	NWidgetSpacer(int length, int height);
 
-	int SetupSmallestSize();
+	int SetupSmallestSize(Window *w);
 	void StoreWidgets(Widget *widgets, int length, bool left_moving, bool top_moving, bool rtl);
 	/* virtual */ void FillNestedArray(NWidgetCore **array, uint length);
 
@@ -451,7 +450,7 @@
 	void Add(NWidgetBase *nwid);
 	void SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post);
 
-	int SetupSmallestSize();
+	int SetupSmallestSize(Window *w);
 	void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool allow_resize_x, bool allow_resize_y, bool rtl);
 
 	void StoreWidgets(Widget *widgets, int length, bool left_moving, bool top_moving, bool rtl);
@@ -472,6 +471,7 @@
 public:
 	NWidgetLeaf(WidgetType tp, Colours colour, int index, uint16 data, StringID tip);
 
+	/* virtual */ int SetupSmallestSize(Window *w);
 	/* virtual */ void Draw(const Window *w);
 	/* virtual */ void Invalidate(const Window *w) const;
 	/* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y);
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -574,7 +574,7 @@
 	int window_height = this->height;
 
 	/* Re-initialize the window from the ground up. No need to change the nested_array, as all widgets stay where they are. */
-	this->nested_root->SetupSmallestSize();
+	this->nested_root->SetupSmallestSize(this);
 	this->nested_root->AssignSizePosition(ST_SMALLEST, 0, 0, this->nested_root->smallest_x, this->nested_root->smallest_y, false, false, false);
 	this->width  = this->nested_root->smallest_x;
 	this->height = this->nested_root->smallest_y;
@@ -884,7 +884,7 @@
 	if (nested_root != NULL) {
 		this->nested_root = nested_root;
 		/* Setup nested_array pointers into the tree. */
-		int biggest_index = this->nested_root->SetupSmallestSize();
+		int biggest_index = this->nested_root->SetupSmallestSize(this);
 		this->nested_array_size = (uint)(biggest_index + 1);
 		this->nested_array = CallocT<NWidgetCore *>(this->nested_array_size);
 		this->nested_root->FillNestedArray(this->nested_array, this->nested_array_size);
--- a/src/window_gui.h
+++ b/src/window_gui.h
@@ -501,6 +501,20 @@
 	virtual void DrawWidget(const Rect &r, int widget) const {}
 
 	/**
+	 * Compute size of the contents of a widget.
+	 * If no useful size can be computed, return null-size (both width and height \c 0).
+	 * @param widget Number of the widget to get the size of.
+	 * @return Size of the contents of the widget.
+	 * @note If the contents ever becomes larger than what is returned here, the window should be re-initialized (with #Window::ReInit),
+	 *       and this function should return a larger size.
+	 */
+	virtual Dimension GetWidgetContentSize(int widget)
+	{
+		Dimension d = {0, 0};
+		return d;
+	}
+
+	/**
 	 * Called when window gains focus
 	 */
 	virtual void OnFocus() {}