changeset 12101:dc6c0caea002 draft

(svn r16514) -Codechange: Add widget flags, and drawing and invalidating.
author alberth <alberth@openttd.org>
date Wed, 03 Jun 2009 21:13:13 +0000
parents be22d89e79ae
children a381834fd694
files src/widget.cpp src/widget_type.h src/window.cpp src/window_gui.h
diffstat 4 files changed, 325 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/src/widget.cpp
+++ b/src/widget.cpp
@@ -504,6 +504,11 @@
  */
 void Window::DrawWidgets() const
 {
+	if (this->nested_root != NULL) {
+		this->nested_root->Draw(this);
+		return;
+	}
+
 	const DrawPixelInfo *dpi = _cur_dpi;
 
 	for (uint i = 0; i < this->widget_count; i++) {
@@ -741,8 +746,16 @@
 	if (state == SBS_OFF) return;
 
 	int offset = this->IsWidgetLowered(widget) ? 1 : 0;
-	int base = offset + (_dynlang.text_dir == TD_LTR ? this->widget[widget].right - 11 : this->widget[widget].left);
-	DrawString(base, base + 11, this->widget[widget].top + 1 + offset, state == SBS_DOWN ? DOWNARROW : UPARROW, TC_BLACK, SA_CENTER);
+	int base, top;
+	if (this->widget != NULL) {
+		base = offset + (_dynlang.text_dir == TD_LTR ? this->widget[widget].right - 11 : this->widget[widget].left);
+		top = this->widget[widget].top;
+	} else {
+		assert(this->nested_array != NULL);
+		base = offset + this->nested_array[widget]->pos_x + (_dynlang.text_dir == TD_LTR ? this->nested_array[widget]->current_x - 11 : 0);
+		top = this->nested_array[widget]->pos_y;
+	}
+	DrawString(base, base + 11, top + 1 + offset, state == SBS_DOWN ? DOWNARROW : UPARROW, TC_BLACK, SA_CENTER);
 }
 
 
@@ -883,6 +896,23 @@
  */
 
 /**
+ * @fn void Draw(const Window *w)
+ * Draw the widgets of the tree.
+ * @param w Window that owns the tree.
+ */
+
+/**
+ * Mark the widget as 'dirty' (in need of repaint).
+ * @param w Window owning the widget.
+ */
+void NWidgetBase::Invalidate(const Window *w) const
+{
+	int abs_left = w->left + this->pos_x;
+	int abs_top = w->top + this->pos_y;
+	SetDirtyBlocks(abs_left, abs_top, abs_left + this->current_x, abs_top + this->current_y);
+}
+
+/**
  * Constructor for resizable nested widgets.
  * @param tp     Nested widget type.
  * @param fill_x Allow horizontal filling from initial size.
@@ -1151,6 +1181,15 @@
 	}
 }
 
+void NWidgetStacked::Draw(const Window *w)
+{
+	assert(this->type == NWID_LAYERED); // Currently, NWID_SELECTION is not supported.
+	/* Render from back to front. */
+	for (NWidgetBase *child_wid = this->tail; child_wid != NULL; child_wid = child_wid->prev) {
+		child_wid->Draw(w);
+	}
+}
+
 NWidgetPIPContainer::NWidgetPIPContainer(WidgetType tp) : NWidgetContainer(tp)
 {
 }
@@ -1171,6 +1210,13 @@
 	this->pip_post = pip_post;
 }
 
+void NWidgetPIPContainer::Draw(const Window *w)
+{
+	for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
+		child_wid->Draw(w);
+	}
+}
+
 /** Horizontal container widget. */
 NWidgetHorizontal::NWidgetHorizontal() : NWidgetPIPContainer(NWID_HORIZONTAL)
 {
@@ -1447,6 +1493,16 @@
 	/* Spacer widgets are never stored in the widget array. */
 }
 
+void NWidgetSpacer::Draw(const Window *w)
+{
+	/* Spacer widget is never visible. */
+}
+
+void NWidgetSpacer::Invalidate(const Window *w) const
+{
+	/* Spacer widget never need repainting. */
+}
+
 /**
  * Constructor parent nested widgets.
  * @param tp     Type of parent widget.
@@ -1547,6 +1603,44 @@
 	if (this->child != NULL) this->child->FillNestedArray(array, length);
 }
 
+void NWidgetBackground::Draw(const Window *w)
+{
+	if (this->current_x == 0 || this->current_y == 0) return;
+
+	Rect r;
+	r.left = this->pos_x;
+	r.right = this->pos_x + this->current_x - 1;
+	r.top = this->pos_y;
+	r.bottom = this->pos_y + this->current_y - 1;
+
+	const DrawPixelInfo *dpi = _cur_dpi;
+	if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top) return;
+
+	switch (this->type) {
+		case WWT_PANEL:
+			assert(this->widget_data == 0);
+			DrawFrameRect(r.left, r.top, r.right, r.bottom, this->colour, this->IsLowered() ? FR_LOWERED : FR_NONE);
+			break;
+
+		case WWT_FRAME:
+			DrawFrame(r, this->colour, this->widget_data);
+			break;
+
+		case WWT_INSET:
+			DrawInset(r, this->colour, this->widget_data);
+			break;
+
+		default:
+			NOT_REACHED();
+	}
+
+	if (this->child != NULL) this->child->Draw(w);
+
+	if (this->IsDisabled()) {
+		GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER);
+	}
+}
+
 /**
  * Nested leaf widget.
  * @param tp     Type of leaf widget.
@@ -1635,6 +1729,116 @@
 	}
 }
 
+void NWidgetLeaf::Draw(const Window *w)
+{
+	if (this->current_x == 0 || this->current_y == 0) return;
+
+	Rect r;
+	r.left = this->pos_x;
+	r.right = this->pos_x + this->current_x - 1;
+	r.top = this->pos_y;
+	r.bottom = this->pos_y + this->current_y - 1;
+
+	const DrawPixelInfo *dpi = _cur_dpi;
+	if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top) return;
+
+	bool clicked = this->IsLowered();
+	switch (this->type) {
+		case WWT_EMPTY:
+			break;
+
+		case WWT_PUSHBTN:
+			assert(this->widget_data == 0);
+			DrawFrameRect(r.left, r.top, r.right, r.bottom, this->colour, (clicked) ? FR_LOWERED : FR_NONE);
+			break;
+
+		case WWT_IMGBTN:
+		case WWT_PUSHIMGBTN:
+		case WWT_IMGBTN_2:
+			DrawImageButtons(r, this->type,this->colour, clicked, this->widget_data);
+			break;
+
+		case WWT_TEXTBTN:
+		case WWT_PUSHTXTBTN:
+		case WWT_TEXTBTN_2:
+			DrawFrameRect(r.left, r.top, r.right, r.bottom, this->colour, (clicked) ? FR_LOWERED : FR_NONE);
+			DrawLabel(r, this->type, clicked, this->widget_data);
+			break;
+
+		case WWT_LABEL:
+			DrawLabel(r, this->type, clicked, this->widget_data);
+			break;
+
+		case WWT_TEXT:
+			DrawText(r, (TextColour)this->colour, this->widget_data);
+			break;
+
+		case WWT_MATRIX:
+			DrawMatrix(r, this->colour, clicked, this->widget_data);
+			break;
+
+		case WWT_EDITBOX:
+			DrawFrameRect(r.left, r.top, r.right, r.bottom, this->colour, FR_LOWERED | FR_DARKENED);
+			break;
+
+		case WWT_SCROLLBAR:
+			assert(this->widget_data == 0);
+			DrawVerticalScrollbar(r, this->colour, (w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_UP,
+								(w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_MIDDLE,
+								(w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_DOWN, &w->vscroll);
+			break;
+
+		case WWT_SCROLL2BAR:
+			assert(this->widget_data == 0);
+			DrawVerticalScrollbar(r, this->colour, (w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_UP | WF_SCROLL2),
+								(w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_MIDDLE | WF_SCROLL2),
+								(w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_DOWN | WF_SCROLL2), &w->vscroll2);
+			break;
+
+		case WWT_CAPTION:
+			DrawCaption(r, this->colour, w->owner, this->widget_data);
+			break;
+
+		case WWT_HSCROLLBAR:
+			assert(this->widget_data == 0);
+			DrawHorizontalScrollbar(r, this->colour, (w->flags4 & (WF_SCROLL_UP | WF_HSCROLL)) == (WF_SCROLL_UP | WF_HSCROLL),
+								(w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL)) == (WF_SCROLL_MIDDLE | WF_HSCROLL),
+								(w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL)) == (WF_SCROLL_DOWN | WF_HSCROLL), &w->hscroll);
+			break;
+
+		case WWT_STICKYBOX:
+			assert(this->widget_data == 0);
+			DrawStickyBox(r, this->colour, !!(w->flags4 & WF_STICKY));
+			break;
+
+		case WWT_RESIZEBOX:
+			assert(this->widget_data == 0);
+			DrawResizeBox(r, this->colour, this->pos_x < (uint)(w->width / 2), !!(w->flags4 & WF_SIZING));
+			break;
+
+		case WWT_CLOSEBOX:
+			DrawCloseBox(r, this->colour, this->widget_data);
+			break;
+
+		case WWT_DROPDOWN:
+			DrawDropdown(r, this->colour, clicked, this->widget_data);
+			break;
+
+		default:
+			NOT_REACHED();
+	}
+
+	if (this->IsDisabled()) {
+		GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER);
+	}
+}
+
+void NWidgetLeaf::Invalidate(const Window *w) const
+{
+	if (this->type == WWT_EMPTY) return; // Don't repaint dummy widgets.
+	NWidgetBase::Invalidate(w);
+}
+
 /**
  * Intialize nested widget tree and convert to widget array.
  * @param nwid Nested widget tree.
--- a/src/widget_type.h
+++ b/src/widget_type.h
@@ -188,6 +188,9 @@
 	inline uint GetHorizontalStepSize(SizingType sizing) const;
 	inline uint GetVerticalStepSize(SizingType sizing) const;
 
+	virtual void Draw(const Window *w) = 0;
+	virtual void Invalidate(const Window *w) const;
+
 	WidgetType type;      ///< Type of the widget / nested widget.
 	bool fill_x;          ///< Allow horizontal filling from initial size.
 	bool fill_y;          ///< Allow vertical filling from initial size.
@@ -253,6 +256,16 @@
 	uint min_y; ///< Minimal vertical size of only this widget.
 };
 
+/** Nested widget flags that affect display and interaction withe 'real' widgets. */
+enum NWidgetDisplay {
+	NDB_LOWERED  = 0, ///< Widget is lowered (pressed down) bit.
+	NDB_DISABLED = 1, ///< Widget is disabled (greyed out) bit.
+
+	ND_LOWERED  = 1 << NDB_LOWERED,  ///< Bit value of the lowered flag.
+	ND_DISABLED = 1 << NDB_DISABLED, ///< Bit value of the disabled flag.
+};
+DECLARE_ENUM_AS_BIT_SET(NWidgetDisplay);
+
 /** Base class for a 'real' widget.
  * @ingroup NestedWidgets */
 class NWidgetCore : public NWidgetResizeBase {
@@ -262,16 +275,53 @@
 	void SetIndex(int index);
 	void SetDataTip(uint16 widget_data, StringID tool_tip);
 
+	inline void SetLowered(bool lowered);
+	inline bool IsLowered();
+	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);
 
-	Colours colour;     ///< Colour of this widget.
-	int index;          ///< Index of the nested widget in the widget array of the window (\c -1 means 'not used').
-	uint16 widget_data; ///< Data of the widget. @see Widget::data
-	StringID tool_tip;  ///< Tooltip of the widget. @see Widget::tootips
+	NWidgetDisplay disp_flags; ///< Flags that affect display and interaction with the widget.
+	Colours colour;            ///< Colour of this widget.
+	int index;                 ///< Index of the nested widget in the widget array of the window (\c -1 means 'not used').
+	uint16 widget_data;        ///< Data of the widget. @see Widget::data
+	StringID tool_tip;         ///< Tooltip of the widget. @see Widget::tootips
 };
 
+/**
+ * Lower or raise the widget.
+ * @param lowered Widget must be lowered (drawn pressed down).
+ */
+inline void NWidgetCore::SetLowered(bool lowered)
+{
+	this->disp_flags = lowered ? SETBITS(this->disp_flags, ND_LOWERED) : CLRBITS(this->disp_flags, ND_LOWERED);
+}
+
+/** Return whether the widget is lowered. */
+inline bool NWidgetCore::IsLowered()
+{
+	return HasBit(this->disp_flags, NDB_LOWERED);
+}
+
+/**
+ * Disable (grey-out) or enable the widget.
+ * @param disabled Widget must be disabled.
+ */
+inline void NWidgetCore::SetDisabled(bool disabled)
+{
+	this->disp_flags = disabled ? SETBITS(this->disp_flags, ND_DISABLED) : CLRBITS(this->disp_flags, ND_DISABLED);
+}
+
+/** Return whether the widget is disabled. */
+inline bool NWidgetCore::IsDisabled()
+{
+	return HasBit(this->disp_flags, NDB_DISABLED);
+}
+
+
 /** Baseclass for container widgets.
  * @ingroup NestedWidgets */
 class NWidgetContainer : public NWidgetBase {
@@ -300,6 +350,8 @@
 	int SetupSmallestSize();
 	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);
+
+	/* virtual */ void Draw(const Window *w);
 };
 
 /** Container with pre/inter/post child space. */
@@ -309,6 +361,7 @@
 
 	void SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post);
 
+	/* virtual */ void Draw(const Window *w);
 protected:
 	uint8 pip_pre;     ///< Amount of space before first widget.
 	uint8 pip_inter;   ///< Amount of space between widgets.
@@ -360,6 +413,9 @@
 	int SetupSmallestSize();
 	void StoreWidgets(Widget *widgets, int length, bool left_moving, bool top_moving, bool rtl);
 	/* virtual */ void FillNestedArray(NWidgetCore **array, uint length);
+
+	/* virtual */ void Draw(const Window *w);
+	/* virtual */ void Invalidate(const Window *w) const;
 };
 
 /** Nested widget with a child.
@@ -378,6 +434,8 @@
 	void StoreWidgets(Widget *widgets, int length, bool left_moving, bool top_moving, bool rtl);
 	/* virtual */ void FillNestedArray(NWidgetCore **array, uint length);
 
+	/* virtual */ void Draw(const Window *w);
+
 private:
 	NWidgetPIPContainer *child; ///< Child widget.
 };
@@ -387,6 +445,9 @@
 class NWidgetLeaf : public NWidgetCore {
 public:
 	NWidgetLeaf(WidgetType tp, Colours colour, int index, uint16 data, StringID tip);
+
+	/* virtual */ void Draw(const Window *w);
+	/* virtual */ void Invalidate(const Window *w) const;
 };
 
 Widget *InitializeNWidgets(NWidgetBase *nwid, bool rtl = false);
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -191,10 +191,20 @@
  */
 void Window::RaiseButtons()
 {
-	for (uint i = 0; i < this->widget_count; i++) {
-		if (this->IsWidgetLowered(i)) {
-			this->RaiseWidget(i);
-			this->InvalidateWidget(i);
+	if (this->widget != NULL) {
+		for (uint i = 0; i < this->widget_count; i++) {
+			if (this->IsWidgetLowered(i)) {
+				this->RaiseWidget(i);
+				this->InvalidateWidget(i);
+			}
+		}
+	}
+	if (this->nested_array != NULL) {
+		for (uint i = 0; i < this->nested_array_size; i++) {
+			if (this->IsWidgetLowered(i)) {
+				this->RaiseWidget(i);
+				this->InvalidateWidget(i);
+			}
 		}
 	}
 }
@@ -205,12 +215,15 @@
  */
 void Window::InvalidateWidget(byte widget_index) const
 {
-	const Widget *wi = &this->widget[widget_index];
+	if (this->widget != NULL) {
+		const Widget *wi = &this->widget[widget_index];
 
-	/* Don't redraw the window if the widget is invisible or of no-type */
-	if (wi->type == WWT_EMPTY || IsWidgetHidden(widget_index)) return;
+		/* Don't redraw the window if the widget is invisible or of no-type */
+		if (wi->type == WWT_EMPTY || IsWidgetHidden(widget_index)) return;
 
-	SetDirtyBlocks(this->left + wi->left, this->top + wi->top, this->left + wi->right + 1, this->top + wi->bottom + 1);
+		SetDirtyBlocks(this->left + wi->left, this->top + wi->top, this->left + wi->right + 1, this->top + wi->bottom + 1);
+	}
+	if (this->nested_array != NULL) this->nested_array[widget_index]->Invalidate(this);
 }
 
 /**
--- a/src/window_gui.h
+++ b/src/window_gui.h
@@ -191,8 +191,14 @@
 	 */
 	inline void SetWidgetDisabledState(byte widget_index, bool disab_stat)
 	{
-		assert(widget_index < this->widget_count);
-		SB(this->widget[widget_index].display_flags, WIDG_DISABLED, 1, !!disab_stat);
+		if (this->widget != NULL) {
+			assert(widget_index < this->widget_count);
+			SB(this->widget[widget_index].display_flags, WIDG_DISABLED, 1, !!disab_stat);
+		}
+		if (this->nested_array != NULL) {
+			assert(widget_index < this->nested_array_size);
+			this->nested_array[widget_index]->SetDisabled(disab_stat);
+		}
 	}
 
 	/**
@@ -220,6 +226,10 @@
 	 */
 	inline bool IsWidgetDisabled(byte widget_index) const
 	{
+		if (this->nested_array != NULL) {
+			assert(widget_index < this->nested_array_size);
+			return this->nested_array[widget_index]->IsDisabled();
+		}
 		assert(widget_index < this->widget_count);
 		return HasBit(this->widget[widget_index].display_flags, WIDG_DISABLED);
 	}
@@ -313,8 +323,14 @@
 	 */
 	inline void SetWidgetLoweredState(byte widget_index, bool lowered_stat)
 	{
-		assert(widget_index < this->widget_count);
-		SB(this->widget[widget_index].display_flags, WIDG_LOWERED, 1, !!lowered_stat);
+		if (this->widget != NULL) {
+			assert(widget_index < this->widget_count);
+			SB(this->widget[widget_index].display_flags, WIDG_LOWERED, 1, !!lowered_stat);
+		}
+		if (this->nested_array != NULL) {
+			assert(widget_index < this->nested_array_size);
+			this->nested_array[widget_index]->SetLowered(lowered_stat);
+		}
 	}
 
 	/**
@@ -323,8 +339,15 @@
 	 */
 	inline void ToggleWidgetLoweredState(byte widget_index)
 	{
-		assert(widget_index < this->widget_count);
-		ToggleBit(this->widget[widget_index].display_flags, WIDG_LOWERED);
+		if (this->widget != NULL) {
+			assert(widget_index < this->widget_count);
+			ToggleBit(this->widget[widget_index].display_flags, WIDG_LOWERED);
+		}
+		if (this->nested_array != NULL) {
+			assert(widget_index < this->nested_array_size);
+			bool lowered_state = this->nested_array[widget_index]->IsLowered();
+			this->nested_array[widget_index]->SetLowered(!lowered_state);
+		}
 	}
 
 	/**
@@ -352,6 +375,10 @@
 	 */
 	inline bool IsWidgetLowered(byte widget_index) const
 	{
+		if (this->nested_array != NULL) {
+			assert(widget_index < this->nested_array_size);
+			return this->nested_array[widget_index]->IsLowered();
+		}
 		assert(widget_index < this->widget_count);
 		return HasBit(this->widget[widget_index].display_flags, WIDG_LOWERED);
 	}