(svn r16740) -Codechange: Self-sizing widgets in intro screen, town directory, and found town windows.

This commit is contained in:
alberth 2009-07-04 15:35:36 +00:00
parent 2385aeae3c
commit d65c6cae54
6 changed files with 173 additions and 34 deletions

View File

@ -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) virtual void OnClick(Point pt, int widget)
{ {
#ifdef ENABLE_NETWORK #ifdef ENABLE_NETWORK

View File

@ -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) virtual void OnClick(Point pt, int widget)
{ {
switch (widget) { switch (widget) {
@ -676,7 +713,7 @@ public:
if (id_v >= this->towns.Length()) return; // click out of town bounds if (id_v >= this->towns.Length()) return; // click out of town bounds
const Town *t = this->towns[id_v]; const Town *t = this->towns[id_v];
assert(t->xy != INVALID_TILE); assert(t != NULL);
if (_ctrl_pressed) { if (_ctrl_pressed) {
ShowExtraViewPortWindow(t->xy); ShowExtraViewPortWindow(t->xy);
} else { } else {

View File

@ -891,15 +891,18 @@ NWidgetBase::NWidgetBase(WidgetType tp) : ZeroedMemoryAllocator()
/* ~NWidgetContainer() takes care of #next and #prev data members. */ /* ~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. * Compute smallest size needed by the widget.
* *
* The smallest size of a widget is the smallest size that a widget needs to * The smallest size of a widget is the smallest size that a widget needs to
* display itself properly. * display itself properly. In addition, filling and resizing of the widget are computed.
* 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). * @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; 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) void NWidgetCore::FillNestedArray(NWidgetCore **array, uint length)
{ {
if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this; 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. */ /* First sweep, recurse down and compute minimal size and filling. */
int biggest_index = -1; int biggest_index = -1;
@ -1248,7 +1243,7 @@ int NWidgetStacked::SetupSmallestSize()
this->resize_x = (this->head != NULL) ? 1 : 0; this->resize_x = (this->head != NULL) ? 1 : 0;
this->resize_y = (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) { 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); 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); 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; int biggest_index = -1;
this->smallest_x = 0; // Sum of minimal size of all childs. 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. */ /* 1. Forward call, collect biggest nested array index, and longest child length. */
uint longest = 0; // Longest child found. uint longest = 0; // Longest child found.
for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { 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); biggest_index = max(biggest_index, idx);
longest = max(longest, child_wid->smallest_x); 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; int biggest_index = -1;
this->smallest_x = 0; // Biggest child. 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. */ /* 1. Forward call, collect biggest nested array index, and longest child length. */
uint highest = 0; // Highest child found. uint highest = 0; // Highest child found.
for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { 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); biggest_index = max(biggest_index, idx);
highest = max(highest, child_wid->smallest_y); highest = max(highest, child_wid->smallest_y);
} }
@ -1628,7 +1623,7 @@ NWidgetSpacer::NWidgetSpacer(int length, int height) : NWidgetResizeBase(NWID_SP
this->SetResize(0, 0); this->SetResize(0, 0);
} }
int NWidgetSpacer::SetupSmallestSize() int NWidgetSpacer::SetupSmallestSize(Window *w)
{ {
this->smallest_x = this->min_x; this->smallest_x = this->min_x;
this->smallest_y = this->min_y; 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); this->child->SetPIP(pip_pre, pip_inter, pip_post);
} }
int NWidgetBackground::SetupSmallestSize() int NWidgetBackground::SetupSmallestSize(Window *w)
{ {
int biggest_index = this->index; int biggest_index = this->index;
if (this->child != NULL) { if (this->child != NULL) {
int idx = this->child->SetupSmallestSize(); int idx = this->child->SetupSmallestSize(w);
biggest_index = max(biggest_index, idx); biggest_index = max(biggest_index, idx);
this->smallest_x = this->child->smallest_x; this->smallest_x = this->child->smallest_x;
@ -1733,8 +1728,13 @@ int NWidgetBackground::SetupSmallestSize()
this->resize_x = this->child->resize_x; this->resize_x = this->child->resize_x;
this->resize_y = this->child->resize_y; this->resize_y = this->child->resize_y;
} else { } else {
this->smallest_x = this->min_x; Dimension d = {this->min_x, this->min_y};
this->smallest_y = 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; 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) void NWidgetLeaf::Draw(const Window *w)
{ {
if (this->current_x == 0 || this->current_y == 0) return; 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) Widget *InitializeNWidgets(NWidgetBase *nwid, bool rtl)
{ {
/* Initialize nested widgets. */ /* 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); 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. */ /* Construct a local widget array and initialize all its types to #WWT_LAST. */

View File

@ -165,7 +165,7 @@ class NWidgetBase : public ZeroedMemoryAllocator {
public: public:
NWidgetBase(WidgetType tp); 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 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; 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 void SetDisabled(bool disabled);
inline bool IsDisabled(); inline bool IsDisabled();
int SetupSmallestSize();
void StoreWidgets(Widget *widgets, int length, bool left_moving, bool top_moving, bool rtl); void StoreWidgets(Widget *widgets, int length, bool left_moving, bool top_moving, bool rtl);
/* virtual */ void FillNestedArray(NWidgetCore **array, uint length); /* virtual */ void FillNestedArray(NWidgetCore **array, uint length);
@ -355,7 +354,7 @@ class NWidgetStacked : public NWidgetContainer {
public: public:
NWidgetStacked(WidgetType tp); 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 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); void StoreWidgets(Widget *widgets, int length, bool left_moving, bool top_moving, bool rtl);
@ -395,7 +394,7 @@ class NWidgetHorizontal : public NWidgetPIPContainer {
public: public:
NWidgetHorizontal(NWidContainerFlags flags = NC_NONE); 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 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); void StoreWidgets(Widget *widgets, int length, bool left_moving, bool top_moving, bool rtl);
@ -418,7 +417,7 @@ class NWidgetVertical : public NWidgetPIPContainer {
public: public:
NWidgetVertical(NWidContainerFlags flags = NC_NONE); 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 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); void StoreWidgets(Widget *widgets, int length, bool left_moving, bool top_moving, bool rtl);
@ -431,7 +430,7 @@ class NWidgetSpacer : public NWidgetResizeBase {
public: public:
NWidgetSpacer(int length, int height); 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); void StoreWidgets(Widget *widgets, int length, bool left_moving, bool top_moving, bool rtl);
/* virtual */ void FillNestedArray(NWidgetCore **array, uint length); /* virtual */ void FillNestedArray(NWidgetCore **array, uint length);
@ -451,7 +450,7 @@ public:
void Add(NWidgetBase *nwid); void Add(NWidgetBase *nwid);
void SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post); 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 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); void StoreWidgets(Widget *widgets, int length, bool left_moving, bool top_moving, bool rtl);
@ -472,6 +471,7 @@ class NWidgetLeaf : public NWidgetCore {
public: public:
NWidgetLeaf(WidgetType tp, Colours colour, int index, uint16 data, StringID tip); NWidgetLeaf(WidgetType tp, Colours colour, int index, uint16 data, StringID tip);
/* virtual */ int SetupSmallestSize(Window *w);
/* virtual */ void Draw(const Window *w); /* virtual */ void Draw(const Window *w);
/* virtual */ void Invalidate(const Window *w) const; /* virtual */ void Invalidate(const Window *w) const;
/* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y); /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y);

View File

@ -574,7 +574,7 @@ void Window::ReInit()
int window_height = this->height; 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. */ /* 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->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->width = this->nested_root->smallest_x;
this->height = this->nested_root->smallest_y; 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) { if (nested_root != NULL) {
this->nested_root = nested_root; this->nested_root = nested_root;
/* Setup nested_array pointers into the tree. */ /* 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_size = (uint)(biggest_index + 1);
this->nested_array = CallocT<NWidgetCore *>(this->nested_array_size); this->nested_array = CallocT<NWidgetCore *>(this->nested_array_size);
this->nested_root->FillNestedArray(this->nested_array, this->nested_array_size); this->nested_root->FillNestedArray(this->nested_array, this->nested_array_size);

View File

@ -500,6 +500,20 @@ public:
*/ */
virtual void DrawWidget(const Rect &r, int widget) const {} 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 * Called when window gains focus
*/ */