Changeset - r11795:0a62fd75edf4
[Not reviewed]
master
0 2 0
alberth - 15 years ago 2009-04-30 19:21:51
alberth@openttd.org
(svn r16190) -Codechange: Allow stacking of nested widgets.
2 files changed with 131 insertions and 15 deletions:
0 comments (0 inline, 0 general)
src/widget.cpp
Show inline comments
 
@@ -669,6 +669,7 @@ void Window::DrawSortButtonState(int wid
 
 *   never swap order.
 
 * - #NWidgetVertical for organizing child widgets underneath each other.
 
 * - #NWidgetBackground for adding a background behind its child widget.
 
 * - #NWidgetStacked for stacking child widgets on top of each other.
 
 *
 
 * @see NestedWidgetParts
 
 */
 
@@ -896,6 +897,86 @@ void NWidgetContainer::Add(NWidgetBase *
 
}
 

	
 
/**
 
 * Widgets stacked on top of each other.
 
 * @param tp Kind of stacking, must be either #NWID_SELECTION or #NWID_LAYERED.
 
 */
 
NWidgetStacked::NWidgetStacked(WidgetType tp) : NWidgetContainer(tp)
 
{
 
}
 

	
 
int NWidgetStacked::ComputeMinimalSize()
 
{
 
	/* First sweep, recurse down and compute minimal size and filling. */
 
	int biggest_index = -1;
 
	this->min_x = 0;
 
	this->min_y = 0;
 
	this->fill_x = (this->head != NULL);
 
	this->fill_y = (this->head != NULL);
 
	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->ComputeMinimalSize();
 
		biggest_index = max(biggest_index, idx);
 

	
 
		this->min_x = max(this->min_x, child_wid->min_x + child_wid->padding_left + child_wid->padding_right);
 
		this->min_y = max(this->min_y, child_wid->min_y + child_wid->padding_top + child_wid->padding_bottom);
 
		this->fill_x &= child_wid->fill_x;
 
		this->fill_y &= child_wid->fill_y;
 
		this->resize_x = LeastCommonMultiple(this->resize_x, child_wid->resize_x);
 
		this->resize_y = LeastCommonMultiple(this->resize_y, child_wid->resize_y);
 
	}
 
	return biggest_index;
 
}
 

	
 
void NWidgetStacked::AssignMinimalPosition(uint x, uint y, uint given_width, uint given_height, bool allow_resize_x, bool allow_resize_y, bool rtl)
 
{
 
	assert(given_width >= this->min_x && given_height >= this->min_y);
 

	
 
	this->pos_x = x;
 
	this->pos_y = y;
 
	this->min_x = given_width;
 
	this->min_y = given_height;
 
	if (!allow_resize_x) this->resize_x = 0;
 
	if (!allow_resize_y) this->resize_y = 0;
 

	
 
	for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
 
		/* Decide about horizontal position and filling of the child. */
 
		uint child_width;
 
		int child_pos_x;
 
		if (child_wid->fill_x) {
 
			child_width = given_width - child_wid->padding_left - child_wid->padding_right;
 
			child_pos_x = (rtl ? child_wid->padding_right : child_wid->padding_left);
 
		} else {
 
			child_width = child_wid->min_x;
 
			child_pos_x = (given_width - child_wid->padding_left - child_wid->padding_right - child_width) / 2 + (rtl ? child_wid->padding_right : child_wid->padding_left);
 
		}
 

	
 
		/* Decide about vertical position and filling of the child. */
 
		uint child_height;
 
		int child_pos_y;
 
		if (child_wid->fill_y) {
 
			child_height = given_height - child_wid->padding_top - child_wid->padding_bottom;
 
			child_pos_y = 0;
 
		} else {
 
			child_height = child_wid->min_y;
 
			child_pos_y = (given_height - child_wid->padding_top - child_wid->padding_bottom - child_height) / 2;
 
		}
 
		child_wid->AssignMinimalPosition(x + child_pos_x, y + child_pos_y, child_width, child_height, (this->resize_x > 0), (this->resize_y > 0), rtl);
 
	}
 
}
 

	
 
void NWidgetStacked::StoreWidgets(Widget *widgets, int length, bool left_moving, bool top_moving, bool rtl)
 
{
 
	for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
 
		child_wid->StoreWidgets(widgets, length, left_moving, top_moving, rtl);
 
	}
 
}
 

	
 
NWidgetPIPContainer::NWidgetPIPContainer(WidgetType tp) : NWidgetContainer(tp)
 
{
 
}
 

	
 
/**
 
 * Set additional pre/inter/post space for the container.
 
 *
 
 * @param pip_pre   Additional space in front of the first child widget (above
 
@@ -904,7 +985,7 @@ void NWidgetContainer::Add(NWidgetBase *
 
 * @param pip_post  Additional space after the last child widget (below for the
 
 *                  vertical container, at the right for the horizontal container).
 
 */
 
void NWidgetContainer::SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post)
 
void NWidgetPIPContainer::SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post)
 
{
 
	this->pip_pre = pip_pre;
 
	this->pip_inter = pip_inter;
 
@@ -912,7 +993,7 @@ void NWidgetContainer::SetPIP(uint8 pip_
 
}
 

	
 
/** Horizontal container widget. */
 
NWidgetHorizontal::NWidgetHorizontal() : NWidgetContainer(NWID_HORIZONTAL)
 
NWidgetHorizontal::NWidgetHorizontal() : NWidgetPIPContainer(NWID_HORIZONTAL)
 
{
 
}
 

	
 
@@ -1037,7 +1118,7 @@ void NWidgetHorizontalLTR::StoreWidgets(
 
}
 

	
 
/** Vertical container widget. */
 
NWidgetVertical::NWidgetVertical() : NWidgetContainer(NWID_VERTICAL)
 
NWidgetVertical::NWidgetVertical() : NWidgetPIPContainer(NWID_VERTICAL)
 
{
 
}
 

	
 
@@ -1169,7 +1250,7 @@ void NWidgetSpacer::StoreWidgets(Widget 
 
 *               vertical container will be inserted while adding the first
 
 *               child widget.
 
 */
 
NWidgetBackground::NWidgetBackground(WidgetType tp, Colours colour, int index, NWidgetContainer *child) : NWidgetCore(tp, colour, true, true, 0x0, STR_NULL)
 
NWidgetBackground::NWidgetBackground(WidgetType tp, Colours colour, int index, NWidgetPIPContainer *child) : NWidgetCore(tp, colour, true, true, 0x0, STR_NULL)
 
{
 
	this->SetIndex(index);
 
	assert(tp == WWT_PANEL || tp == WWT_INSET || tp == WWT_FRAME);
 
@@ -1487,6 +1568,14 @@ static int MakeNWidget(const NWidgetPart
 
				*fill_dest = false;
 
				break;
 

	
 
			case NWID_SELECTION:
 
			case NWID_LAYERED:
 
				if (*dest != NULL) return num_used;
 
				*dest = new NWidgetStacked(parts->type);
 
				*fill_dest = true;
 
				break;
 

	
 

	
 
			case WPT_RESIZE: {
 
				NWidgetResizeBase *nwrb = dynamic_cast<NWidgetResizeBase *>(*dest);
 
				if (nwrb != NULL) {
 
@@ -1559,7 +1648,7 @@ static int MakeNWidget(const NWidgetPart
 
			}
 

	
 
			case WPT_PIPSPACE: {
 
				NWidgetContainer *nwc = dynamic_cast<NWidgetContainer *>(*dest);
 
				NWidgetPIPContainer *nwc = dynamic_cast<NWidgetPIPContainer *>(*dest);
 
				if (nwc != NULL) nwc->SetPIP(parts->u.pip.pre,  parts->u.pip.inter, parts->u.pip.post);
 

	
 
				NWidgetBackground *nwb = dynamic_cast<NWidgetBackground *>(*dest);
 
@@ -1614,7 +1703,8 @@ static int MakeWidgetTree(const NWidgetP
 

	
 
		/* If sub-widget is a container, recursively fill that container. */
 
		WidgetType tp = sub_widget->type;
 
		if (fill_sub && (tp == NWID_HORIZONTAL || tp == NWID_HORIZONTAL_LTR || tp == NWID_VERTICAL || tp == WWT_PANEL || tp == WWT_FRAME || tp == WWT_INSET)) {
 
		if (fill_sub && (tp == NWID_HORIZONTAL || tp == NWID_HORIZONTAL_LTR || tp == NWID_VERTICAL
 
							|| tp == WWT_PANEL || tp == WWT_FRAME || tp == WWT_INSET || tp == NWID_SELECTION || tp == NWID_LAYERED)) {
 
			int num_used = MakeWidgetTree(parts, count - total_used, sub_widget);
 
			parts += num_used;
 
			total_used += num_used;
src/widget_type.h
Show inline comments
 
@@ -100,6 +100,8 @@ enum WidgetType {
 
	NWID_HORIZONTAL_LTR, ///< Horizontal container that doesn't change the order of the widgets for RTL languages.
 
	NWID_VERTICAL,       ///< Vertical container.
 
	NWID_SPACER,         ///< Invisible widget that takes some space.
 
	NWID_SELECTION,      ///< Stacked widgets, only one visible at a time (eg in a panel with tabs).
 
	NWID_LAYERED,        ///< Widgets layered on top of each other, all visible at the same time.
 

	
 
	/* Nested widget part types. */
 
	WPT_RESIZE,       ///< Widget part for specifying resizing.
 
@@ -214,23 +216,43 @@ public:
 
	~NWidgetContainer();
 

	
 
	void Add(NWidgetBase *wid);
 
	void SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post);
 

	
 
	/** Return whether the container is empty. */
 
	inline bool IsEmpty() { return head == NULL; };
 

	
 
protected:
 
	NWidgetBase *head; ///< Pointer to first widget in container.
 
	NWidgetBase *tail; ///< Pointer to last widget in container.
 
};
 

	
 
/** Stacked widgets, widgets all occupying the same space in the window.
 
 * @note the semantics difference between #NWID_SELECTION and #NWID_LAYERED is currently not used.
 
 */
 
class NWidgetStacked : public NWidgetContainer {
 
public:
 
	NWidgetStacked(WidgetType tp);
 

	
 
	int ComputeMinimalSize();
 
	void AssignMinimalPosition(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);
 
};
 

	
 
/** Container with pre/inter/post child space. */
 
class NWidgetPIPContainer : public NWidgetContainer {
 
public:
 
	NWidgetPIPContainer(WidgetType tp);
 

	
 
	void SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post);
 

	
 
protected:
 
	uint8 pip_pre;     ///< Amount of space before first widget.
 
	uint8 pip_inter;   ///< Amount of space between widgets.
 
	uint8 pip_post;    ///< Amount of space after last widget.
 

	
 
	NWidgetBase *head; ///< Pointer to first widget in container.
 
	NWidgetBase *tail; ///< Pointer to last widget in container.
 
};
 

	
 
/** Horizontal container.
 
 * @ingroup NestedWidgets */
 
class NWidgetHorizontal : public NWidgetContainer {
 
class NWidgetHorizontal : public NWidgetPIPContainer {
 
public:
 
	NWidgetHorizontal();
 

	
 
@@ -253,7 +275,7 @@ public:
 

	
 
/** Vertical container.
 
 * @ingroup NestedWidgets */
 
class NWidgetVertical : public NWidgetContainer {
 
class NWidgetVertical : public NWidgetPIPContainer {
 
public:
 
	NWidgetVertical();
 

	
 
@@ -278,7 +300,7 @@ public:
 
 * @ingroup NestedWidgets */
 
class NWidgetBackground : public NWidgetCore {
 
public:
 
	NWidgetBackground(WidgetType tp, Colours colour, int index, NWidgetContainer *child = NULL);
 
	NWidgetBackground(WidgetType tp, Colours colour, int index, NWidgetPIPContainer *child = NULL);
 
	~NWidgetBackground();
 

	
 
	void Add(NWidgetBase *nwid);
 
@@ -289,7 +311,7 @@ public:
 

	
 
	void StoreWidgets(Widget *widgets, int length, bool left_moving, bool top_moving, bool rtl);
 
private:
 
	NWidgetContainer *child; ///< Child widget.
 
	NWidgetPIPContainer *child; ///< Child widget.
 
};
 

	
 
/** Leaf widget.
 
@@ -333,6 +355,10 @@ bool CompareWidgetArrays(const Widget *o
 
 *   the child widgets (it has no meaning for the compiler but it makes the widget parts easier to read).
 
 *   Below the last child widget, use an #EndContainer part. This part should be aligned with the #NWidget part that started the container.
 
 *
 
 * - Stacked widgets #NWidgetStacked map each of their childs onto the same space. It behaves like a container, except there is no pre/inter/post space,
 
 *   so the widget does not support #SetPIP. #SetPadding is allowed though.
 
 *   Like the other container widgets, below the last child widgets, a #EndContainer part should be used to denote the end of the stacked widget.
 
 *
 
 * - Background widgets #NWidgetBackground start with a #NWidget(WidgetType tp, Colours col, int16 idx) part.
 
 *   What follows depends on how the widget is used.
 
 *   - If the widget is used as a leaf widget, that is, to create some space in the window to display a viewport or some text, use the properties of the
 
@@ -589,7 +615,7 @@ static inline NWidgetPart NWidget(Widget
 

	
 
/**
 
 * Widget part function for starting a new horizontal container, vertical container, or spacer widget.
 
 * @param tp Type of the new nested widget, #NWID_HORIZONTAL(_LTR), #NWID_VERTICAL, or #NWID_SPACER
 
 * @param tp Type of the new nested widget, #NWID_HORIZONTAL(_LTR), #NWID_VERTICAL, #NWID_SPACER, #NWID_SELECTION, or #NWID_LAYERED.
 
 * @ingroup NestedWidgetParts
 
 */
 
static inline NWidgetPart NWidget(WidgetType tp)
0 comments (0 inline, 0 general)