changeset 14040:869eedf8fbc5 draft

(svn r18583) -Codechange: Add WWT_SHADEBOX widget and its functions (heavily based on code by erikjanp).
author alberth <alberth@openttd.org>
date Mon, 21 Dec 2009 16:06:20 +0000
parents 2c25eefdf464
children b231a976136b
files src/lang/english.txt src/widget.cpp src/widget_type.h src/window.cpp src/window_gui.h
diffstat 5 files changed, 109 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -229,6 +229,7 @@
 
 STR_TOOLTIP_CLOSE_WINDOW                                        :{BLACK}Close window
 STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS                              :{BLACK}Window title - drag this to move window
+STR_TOOLTIP_SHADE                                               :{BLACK}Shade window - Only show the titlebar
 STR_TOOLTIP_STICKY                                              :{BLACK}Mark this window as uncloseable by the 'Close All Windows' key
 STR_TOOLTIP_RESIZE                                              :{BLACK}Click and drag to resize this window
 STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW                           :{BLACK}Toggle large/small window size
--- a/src/widget.cpp
+++ b/src/widget.cpp
@@ -453,6 +453,18 @@
 }
 
 /**
+ * Draw a shade box.
+ * @param r       Rectangle of the box.
+ * @param colour  Colour of the shade box.
+ * @param clicked Box is lowered.
+ */
+static inline void DrawShadeBox(const Rect &r, Colours colour, bool clicked)
+{
+	DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE);
+	DrawSprite((clicked) ? SPR_WINDOW_SHADE : SPR_WINDOW_UNSHADE, PAL_NONE, r.left + WD_SHADEBOX_LEFT + clicked, r.top + WD_SHADEBOX_TOP + clicked);
+}
+
+/**
  * Draw a sticky box.
  * @param r       Rectangle of the box.
  * @param colour  Colour of the sticky box.
@@ -1673,11 +1685,13 @@
 /** Reset the cached dimensions. */
 /* static */ void NWidgetLeaf::InvalidateDimensionCache()
 {
+	shadebox_dimension.width  = shadebox_dimension.height  = 0;
 	stickybox_dimension.width = stickybox_dimension.height = 0;
 	resizebox_dimension.width = resizebox_dimension.height = 0;
 	closebox_dimension.width  = closebox_dimension.height  = 0;
 }
 
+Dimension NWidgetLeaf::shadebox_dimension  = {0, 0};
 Dimension NWidgetLeaf::stickybox_dimension = {0, 0};
 Dimension NWidgetLeaf::resizebox_dimension = {0, 0};
 Dimension NWidgetLeaf::closebox_dimension  = {0, 0};
@@ -1692,7 +1706,7 @@
  */
 NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint16 data, StringID tip) : NWidgetCore(tp, colour, 1, 1, data, tip)
 {
-	assert(index >= 0 || tp == WWT_LABEL || tp == WWT_TEXT || tp == WWT_CAPTION || tp == WWT_RESIZEBOX || tp == WWT_STICKYBOX || tp == WWT_CLOSEBOX);
+	assert(index >= 0 || tp == WWT_LABEL || tp == WWT_TEXT || tp == WWT_CAPTION || tp == WWT_RESIZEBOX || tp == WWT_SHADEBOX || tp == WWT_STICKYBOX || tp == WWT_CLOSEBOX);
 	if (index >= 0) this->SetIndex(index);
 	this->SetMinimalSize(0, 0);
 	this->SetResize(0, 0);
@@ -1751,6 +1765,12 @@
 			this->SetDataTip(STR_NULL, STR_TOOLTIP_STICKY);
 			break;
 
+		case WWT_SHADEBOX:
+			this->SetFill(0, 0);
+			this->SetMinimalSize(WD_SHADEBOX_TOP, 14);
+			this->SetDataTip(STR_NULL, STR_TOOLTIP_SHADE);
+			break;
+
 		case WWT_RESIZEBOX:
 			this->SetFill(0, 0);
 			this->SetMinimalSize(WD_RESIZEBOX_WIDTH, 12);
@@ -1799,6 +1819,17 @@
 			padding = &extra;
 			break;
 		}
+		case WWT_SHADEBOX: {
+			static const Dimension extra = {WD_SHADEBOX_LEFT + WD_SHADEBOX_RIGHT, WD_SHADEBOX_TOP + WD_SHADEBOX_BOTTOM};
+			padding = &extra;
+			if (NWidgetLeaf::shadebox_dimension.width == 0) {
+				NWidgetLeaf::shadebox_dimension = maxdim(GetSpriteSize(SPR_WINDOW_SHADE), GetSpriteSize(SPR_WINDOW_UNSHADE));
+				NWidgetLeaf::shadebox_dimension.width += extra.width;
+				NWidgetLeaf::shadebox_dimension.height += extra.height;
+			}
+			size = maxdim(size, NWidgetLeaf::shadebox_dimension);
+			break;
+		}
 		case WWT_STICKYBOX: {
 			static const Dimension extra = {WD_STICKYBOX_LEFT + WD_STICKYBOX_RIGHT, WD_STICKYBOX_TOP + WD_STICKYBOX_BOTTOM};
 			padding = &extra;
@@ -2010,6 +2041,11 @@
 								(w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL)) == (WF_SCROLL_DOWN | WF_HSCROLL), &w->hscroll);
 			break;
 
+		case WWT_SHADEBOX:
+			assert(this->widget_data == 0);
+			DrawShadeBox(r, this->colour, w->IsShaded());
+			break;
+
 		case WWT_STICKYBOX:
 			assert(this->widget_data == 0);
 			DrawStickyBox(r, this->colour, !!(w->flags4 & WF_STICKY));
--- a/src/widget_type.h
+++ b/src/widget_type.h
@@ -61,6 +61,7 @@
 	WWT_CAPTION,    ///< Window caption (window title between closebox and stickybox)
 
 	WWT_HSCROLLBAR, ///< Horizontal scrollbar
+	WWT_SHADEBOX,   ///< Shade box (at top-right of a window, between caption and stickybox)
 	WWT_STICKYBOX,  ///< Sticky box (normally at top-right of a window)
 	WWT_SCROLL2BAR, ///< 2nd vertical scrollbar
 	WWT_RESIZEBOX,  ///< Resize box (normally at bottom-right of a window)
@@ -468,6 +469,7 @@
 
 	static void InvalidateDimensionCache();
 private:
+	static Dimension shadebox_dimension;  ///< Cached size of a shadebox widget.
 	static Dimension stickybox_dimension; ///< Cached size of a stickybox widget.
 	static Dimension resizebox_dimension; ///< Cached size of a resizebox widget.
 	static Dimension closebox_dimension;  ///< Cached size of a closebox widget.
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -333,6 +333,11 @@
 			nw->SetDirty(w);
 			return;
 
+		case WWT_SHADEBOX:
+			nw->SetDirty(w);
+			w->SetShaded(!w->IsShaded());
+			return;
+
 		case WWT_STICKYBOX:
 			w->flags4 ^= WF_STICKY;
 			nw->SetDirty(w);
@@ -391,6 +396,13 @@
 {
 	if (nwid == NULL) return;
 
+	/* Using wheel on caption/shade-box shades or unshades the window. */
+	if (nwid->type == WWT_CAPTION || nwid->type == WWT_SHADEBOX) {
+		w->SetShaded(!w->IsShaded());
+		return;
+	}
+
+	/* Scroll the widget attached to the scrollbar. */
 	Scrollbar *sb = nwid->FindScrollbar(w);
 	if (sb != NULL && sb->GetCount() > sb->GetCapacity()) {
 		sb->UpdatePosition(wheel);
@@ -532,6 +544,30 @@
 	this->SetDirty();
 }
 
+/** Set the shaded state of the window to \a make_shaded.
+ * @param make_shaded If \c true, shade the window (roll up until just the title bar is visible), else unshade/unroll the window to its original size.
+ * @note The method uses #Window::ReInit(), thus after the call, the whole window should be considered changed.
+ */
+void Window::SetShaded(bool make_shaded)
+{
+	if (this->shade_select == NULL) return;
+
+	int desired = make_shaded ? STACKED_SELECTION_ZERO_SIZE : 0;
+	if (this->shade_select->shown_plane != desired) {
+		if (make_shaded) {
+			this->unshaded_size.width  = this->width;
+			this->unshaded_size.height = this->height;
+			this->shade_select->SetDisplayedPlane(desired);
+			this->ReInit();
+		} else {
+			this->shade_select->SetDisplayedPlane(desired);
+			int dx = ((int)this->unshaded_size.width  > this->width)  ? (int)this->unshaded_size.width  - this->width  : 0;
+			int dy = ((int)this->unshaded_size.height > this->height) ? (int)this->unshaded_size.height - this->height : 0;
+			this->ReInit(dx, dy);
+		}
+	}
+}
+
 /** Find the Window whose parent pointer points to this window
  * @param w parent Window to find child of
  * @param wc Window class of the window to remove; WC_INVALID if class does not matter
@@ -711,8 +747,8 @@
 
 static void BringWindowToFront(Window *w);
 
-/** Find a window and make it the top-window on the screen. The window
- * gets a white border for a brief period of time to visualize its "activation"
+/** Find a window and make it the top-window on the screen.
+ * The window gets unshaded if it was shaded, and a white border is drawn at its edges for a brief period of time to visualize its "activation".
  * @param cls WindowClass of the window to activate
  * @param number WindowNumber of the window to activate
  * @return a pointer to the window thus activated */
@@ -721,6 +757,8 @@
 	Window *w = FindWindowById(cls, number);
 
 	if (w != NULL) {
+		if (w->IsShaded()) w->SetShaded(false); // Restore original window size if it was shaded.
+
 		w->flags4 |= WF_WHITE_BORDER_MASK;
 		BringWindowToFront(w);
 		w->SetDirty();
@@ -1787,6 +1825,14 @@
 		return true;
 	}
 
+	/* Use unshaded window size rather than current size for shaded windows. */
+	int w_width  = w->width;
+	int w_height = w->height;
+	if (w->IsShaded()) {
+		w_width  = w->unshaded_size.width;
+		w_height = w->unshaded_size.height;
+	}
+
 	Window *u;
 	FOR_ALL_WINDOWS_FROM_BACK_FROM(u, w->z_front) {
 		/* A modal child will prevent the activation of the parent window */
@@ -1804,9 +1850,9 @@
 		}
 
 		/* Window sizes don't interfere, leave z-order alone */
-		if (w->left + w->width <= u->left ||
+		if (w->left + w_width <= u->left ||
 				u->left + u->width <= w->left ||
-				w->top  + w->height <= u->top ||
+				w->top  + w_height <= u->top ||
 				u->top + u->height <= w->top) {
 			continue;
 		}
@@ -2233,7 +2279,8 @@
 	DrawDirtyBlocks();
 
 	FOR_ALL_WINDOWS_FROM_BACK(w) {
-		if (w->viewport != NULL) UpdateViewportPosition(w);
+		/* Update viewport only if window is not shaded. */
+		if (w->viewport != NULL && !w->IsShaded()) UpdateViewportPosition(w);
 	}
 	NetworkDrawChatMessage();
 	/* Redraw mouse cursor in case it was hidden */
--- a/src/window_gui.h
+++ b/src/window_gui.h
@@ -74,6 +74,13 @@
 	WD_MATRIX_TOP    = 3,       ///< Offset at top of a matrix cell.
 	WD_MATRIX_BOTTOM = 1,       ///< Offset at bottom of a matrix cell.
 
+	/* WWT_SHADEBOX */
+	WD_SHADEBOX_WIDTH  = 12,    ///< Width of a standard shade box widget.
+	WD_SHADEBOX_LEFT   = 2,     ///< Left offset of shade sprite.
+	WD_SHADEBOX_RIGHT  = 2,     ///< Right offset of shade sprite.
+	WD_SHADEBOX_TOP    = 3,     ///< Top offset of shade sprite.
+	WD_SHADEBOX_BOTTOM = 3,     ///< Bottom offset of shade sprite.
+
 	/* WWT_STICKYBOX */
 	WD_STICKYBOX_WIDTH  = 12,   ///< Width of a standard sticky box widget.
 	WD_STICKYBOX_LEFT   = 2,    ///< Left offset of sticky sprite.
@@ -381,6 +388,8 @@
 	NWidgetBase *nested_root;        ///< Root of the nested tree.
 	NWidgetBase **nested_array;      ///< Array of pointers into the tree. Do not access directly, use #Window::GetWidget() instead.
 	uint nested_array_size;          ///< Size of the nested array.
+	NWidgetStacked *shade_select;    ///< Selection widget (#NWID_SELECTION) to use for shading the window. If \c NULL, window cannot shade.
+	Dimension unshaded_size;         ///< Last known unshaded size (only valid while shaded).
 
 	Window *parent;                  ///< Parent window.
 	Window *z_front;                 ///< The window in front of us in z-order.
@@ -528,6 +537,14 @@
 	void SetDirty() const;
 	void ReInit(int rx = 0, int ry = 0);
 
+	/** Is window shaded currently? */
+	inline bool IsShaded() const
+	{
+		return this->shade_select != NULL && this->shade_select->shown_plane == STACKED_SELECTION_ZERO_SIZE;
+	}
+
+	void SetShaded(bool make_shaded);
+
 	/**
 	 * Mark this window's data as invalid (in need of re-computing)
 	 * @param data The data to invalidate with