From d65c6cae545f36e7f25efcee0b28bbfac7d64769 Mon Sep 17 00:00:00 2001 From: alberth Date: Sat, 4 Jul 2009 15:35:36 +0000 Subject: [PATCH] (svn r16740) -Codechange: Self-sizing widgets in intro screen, town directory, and found town windows. --- src/intro_gui.cpp | 12 +++++ src/town_gui.cpp | 39 ++++++++++++++- src/widget.cpp | 124 +++++++++++++++++++++++++++++++++++++--------- src/widget_type.h | 14 +++--- src/window.cpp | 4 +- src/window_gui.h | 14 ++++++ 6 files changed, 173 insertions(+), 34 deletions(-) diff --git a/src/intro_gui.cpp b/src/intro_gui.cpp index 0b08be4db2..d61f5b2529 100644 --- a/src/intro_gui.cpp +++ b/src/intro_gui.cpp @@ -83,6 +83,18 @@ struct SelectGameWindow : public Window { } } + 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 diff --git a/src/town_gui.cpp b/src/town_gui.cpp index bbc03ea61f..fd2eb949a3 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -643,6 +643,43 @@ public: } } + 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 @@ public: 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 { diff --git a/src/widget.cpp b/src/widget.cpp index 73056788e0..167e4653be 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -891,15 +891,18 @@ NWidgetBase::NWidgetBase(WidgetType tp) : ZeroedMemoryAllocator() /* ~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 @@ void NWidgetCore::SetDataTip(uint16 widget_data, StringID tool_tip) 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 @@ NWidgetStacked::NWidgetStacked(WidgetType tp) : NWidgetContainer(tp) { } -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 @@ int NWidgetStacked::SetupSmallestSize() 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 @@ NWidgetHorizontal::NWidgetHorizontal(NWidContainerFlags flags) : NWidgetPIPConta { } -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 @@ int NWidgetHorizontal::SetupSmallestSize() /* 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 @@ NWidgetVertical::NWidgetVertical(NWidContainerFlags flags) : NWidgetPIPContainer { } -int NWidgetVertical::SetupSmallestSize() +int NWidgetVertical::SetupSmallestSize(Window *w) { int biggest_index = -1; this->smallest_x = 0; // Biggest child. @@ -1513,7 +1508,7 @@ int NWidgetVertical::SetupSmallestSize() /* 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 @@ NWidgetSpacer::NWidgetSpacer(int length, int height) : NWidgetResizeBase(NWID_SP 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 @@ void NWidgetBackground::SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post) 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 @@ int NWidgetBackground::SetupSmallestSize() 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 @@ NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint16 data, } } +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 @@ NWidgetBase *NWidgetLeaf::GetWidgetOfType(WidgetType tp) 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. */ diff --git a/src/widget_type.h b/src/widget_type.h index 084f36be83..0e5fd42c4b 100644 --- a/src/widget_type.h +++ b/src/widget_type.h @@ -165,7 +165,7 @@ class NWidgetBase : public ZeroedMemoryAllocator { 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 @@ public: 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 @@ class NWidgetStacked : public NWidgetContainer { 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 @@ class NWidgetHorizontal : public NWidgetPIPContainer { 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 @@ class NWidgetVertical : public NWidgetPIPContainer { 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 @@ class NWidgetSpacer : public NWidgetResizeBase { 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 @@ public: 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 @@ class NWidgetLeaf : public NWidgetCore { 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); diff --git a/src/window.cpp b/src/window.cpp index 8aaa78d69a..29aec3ab34 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -574,7 +574,7 @@ void Window::ReInit() 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 @@ void Window::Initialize(int x, int y, int min_width, int min_height, 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(this->nested_array_size); this->nested_root->FillNestedArray(this->nested_array, this->nested_array_size); diff --git a/src/window_gui.h b/src/window_gui.h index 552c0a6e23..e399eb06a4 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -500,6 +500,20 @@ public: */ 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 */