# HG changeset patch # User alberth # Date 1261411580 0 # Node ID 869eedf8fbc51f410fe0d40971300c65f4e5655d # Parent 2c25eefdf464a02154f7a25a83bef765a306016d (svn r18583) -Codechange: Add WWT_SHADEBOX widget and its functions (heavily based on code by erikjanp). diff --git a/src/lang/english.txt b/src/lang/english.txt --- 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 diff --git a/src/widget.cpp b/src/widget.cpp --- 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)); diff --git a/src/widget_type.h b/src/widget_type.h --- 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. diff --git a/src/window.cpp b/src/window.cpp --- 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 */ diff --git a/src/window_gui.h b/src/window_gui.h --- 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