4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
10 /** @file widget_type.h Definitions about widgets. */
15 #include "core/alloc_type.hpp"
16 #include "core/bitmath_func.hpp"
17 #include "core/math_func.hpp"
18 #include "strings_type.h"
20 #include "window_type.h"
22 static const int WIDGET_LIST_END
= -1; ///< indicate the end of widgets' list for vararg functions
24 /** Bits of the #WWT_MATRIX widget data. */
25 enum MatrixWidgetValues
{
26 /* Number of column bits of the WWT_MATRIX widget data. */
27 MAT_COL_START
= 0, ///< Lowest bit of the number of columns.
28 MAT_COL_BITS
= 8, ///< Number of bits for the number of columns in the matrix.
30 /* Number of row bits of the WWT_MATRIX widget data. */
31 MAT_ROW_START
= 8, ///< Lowest bit of the number of rows.
32 MAT_ROW_BITS
= 8, ///< Number of bits for the number of rows in the matrix.
35 /** Values for an arrow widget */
36 enum ArrowWidgetValues
{
37 AWV_DECREASE
, ///< Arrow to the left or in case of RTL to the right
38 AWV_INCREASE
, ///< Arrow to the right or in case of RTL to the left
39 AWV_LEFT
, ///< Force the arrow to the left
40 AWV_RIGHT
, ///< Force the arrow to the right
44 * Window widget types, nested widget types, and nested widget part types.
47 /* Window widget types. */
48 WWT_EMPTY
, ///< Empty widget, place holder to reserve space in widget array
50 WWT_PANEL
, ///< Simple depressed panel
51 WWT_INSET
, ///< Pressed (inset) panel, most commonly used as combo box _text_ area
52 WWT_IMGBTN
, ///< (Toggle) Button with image
53 WWT_IMGBTN_2
, ///< (Toggle) Button with diff image when clicked
54 WWT_ARROWBTN
, ///< (Toggle) Button with an arrow
55 WWT_TEXTBTN
, ///< (Toggle) Button with text
56 WWT_TEXTBTN_2
, ///< (Toggle) Button with diff text when clicked
57 WWT_LABEL
, ///< Centered label
58 WWT_TEXT
, ///< Pure simple text
59 WWT_MATRIX
, ///< Grid of rows and columns. @see MatrixWidgetValues
61 WWT_CAPTION
, ///< Window caption (window title between closebox and stickybox)
63 WWT_DEBUGBOX
, ///< NewGRF debug box (at top-right of a window, between WWT_CAPTION and WWT_SHADEBOX)
64 WWT_SHADEBOX
, ///< Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
65 WWT_DEFSIZEBOX
, ///< Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
66 WWT_STICKYBOX
, ///< Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
68 WWT_RESIZEBOX
, ///< Resize box (normally at bottom-right of a window)
69 WWT_CLOSEBOX
, ///< Close box (at top-left of a window)
70 WWT_DROPDOWN
, ///< Drop down list
71 WWT_EDITBOX
, ///< a textbox for typing
72 WWT_LAST
, ///< Last Item. use WIDGETS_END to fill up padding!!
74 /* Nested widget types. */
75 NWID_HORIZONTAL
, ///< Horizontal container.
76 NWID_HORIZONTAL_LTR
, ///< Horizontal container that doesn't change the order of the widgets for RTL languages.
77 NWID_VERTICAL
, ///< Vertical container.
78 NWID_MATRIX
, ///< Matrix container.
79 NWID_SPACER
, ///< Invisible widget that takes some space.
80 NWID_SELECTION
, ///< Stacked widgets, only one visible at a time (eg in a panel with tabs).
81 NWID_VIEWPORT
, ///< Nested widget containing a viewport.
82 NWID_BUTTON_DROPDOWN
, ///< Button with a drop-down.
83 NWID_HSCROLLBAR
, ///< Horizontal scrollbar
84 NWID_VSCROLLBAR
, ///< Vertical scrollbar
86 /* Nested widget part types. */
87 WPT_RESIZE
, ///< Widget part for specifying resizing.
88 WPT_MINSIZE
, ///< Widget part for specifying minimal size.
89 WPT_MINTEXTLINES
, ///< Widget part for specifying minimal number of lines of text.
90 WPT_FILL
, ///< Widget part for specifying fill.
91 WPT_DATATIP
, ///< Widget part for specifying data and tooltip.
92 WPT_PADDING
, ///< Widget part for specifying a padding.
93 WPT_PIPSPACE
, ///< Widget part for specifying pre/inter/post space for containers.
94 WPT_ENDCONTAINER
, ///< Widget part to denote end of a container.
95 WPT_FUNCTION
, ///< Widget part for calling a user function.
96 WPT_SCROLLBAR
, ///< Widget part for attaching a scrollbar.
98 /* Pushable window widget types. */
101 WWB_PUSHBUTTON
= 1 << 7,
103 WWT_PUSHBTN
= WWT_PANEL
| WWB_PUSHBUTTON
, ///< Normal push-button (no toggle button) with custom drawing
104 WWT_PUSHTXTBTN
= WWT_TEXTBTN
| WWB_PUSHBUTTON
, ///< Normal push-button (no toggle button) with text caption
105 WWT_PUSHIMGBTN
= WWT_IMGBTN
| WWB_PUSHBUTTON
, ///< Normal push-button (no toggle button) with image caption
106 WWT_PUSHARROWBTN
= WWT_ARROWBTN
| WWB_PUSHBUTTON
, ///< Normal push-button (no toggle button) with arrow caption
107 NWID_PUSHBUTTON_DROPDOWN
= NWID_BUTTON_DROPDOWN
| WWB_PUSHBUTTON
,
110 /** Different forms of sizing nested widgets, using NWidgetBase::AssignSizePosition() */
112 ST_SMALLEST
, ///< Initialize nested widget tree to smallest size. Also updates \e current_x and \e current_y.
113 ST_RESIZE
, ///< Resize the nested widget tree.
116 /* Forward declarations. */
121 * Baseclass for nested widgets.
122 * @invariant After initialization, \f$current\_x = smallest\_x + n * resize\_x, for n \geq 0\f$.
123 * @invariant After initialization, \f$current\_y = smallest\_y + m * resize\_y, for m \geq 0\f$.
124 * @ingroup NestedWidgets
126 class NWidgetBase
: public ZeroedMemoryAllocator
{
128 NWidgetBase(WidgetType tp
);
130 virtual void SetupSmallestSize(Window
*w
, bool init_array
) = 0;
131 virtual void AssignSizePosition(SizingType sizing
, uint x
, uint y
, uint given_width
, uint given_height
, bool rtl
) = 0;
133 virtual void FillNestedArray(NWidgetBase
**array
, uint length
) = 0;
135 virtual NWidgetCore
*GetWidgetFromPos(int x
, int y
) = 0;
136 virtual NWidgetBase
*GetWidgetOfType(WidgetType tp
);
138 virtual bool IsHighlighted() const { return false; }
139 virtual TextColour
GetHighlightColour() const { return TC_INVALID
; }
140 virtual void SetHighlighted(TextColour highlight_colour
) {}
143 * Set additional space (padding) around the widget.
144 * @param top Amount of additional space above the widget.
145 * @param right Amount of additional space right of the widget.
146 * @param bottom Amount of additional space below the widget.
147 * @param left Amount of additional space left of the widget.
149 inline void SetPadding(uint8 top
, uint8 right
, uint8 bottom
, uint8 left
)
151 this->padding_top
= top
;
152 this->padding_right
= right
;
153 this->padding_bottom
= bottom
;
154 this->padding_left
= left
;
157 inline uint
GetHorizontalStepSize(SizingType sizing
) const;
158 inline uint
GetVerticalStepSize(SizingType sizing
) const;
160 int GetRow (int clickpos
, int padding
, int line_height
) const;
162 virtual void Draw (BlitArea
*dpi
, const Window
*w
) = 0;
163 virtual void SetDirty(const Window
*w
) const;
165 WidgetType type
; ///< Type of the widget / nested widget.
166 uint fill_x
; ///< Horizontal fill stepsize (from initial size, \c 0 means not resizable).
167 uint fill_y
; ///< Vertical fill stepsize (from initial size, \c 0 means not resizable).
168 uint resize_x
; ///< Horizontal resize step (\c 0 means not resizable).
169 uint resize_y
; ///< Vertical resize step (\c 0 means not resizable).
170 /* Size of the widget in the smallest window possible.
171 * Computed by #SetupSmallestSize() followed by #AssignSizePosition().
173 uint smallest_x
; ///< Smallest horizontal size of the widget in a filled window.
174 uint smallest_y
; ///< Smallest vertical size of the widget in a filled window.
175 /* Current widget size (that is, after resizing). */
176 uint current_x
; ///< Current horizontal size (after resizing).
177 uint current_y
; ///< Current vertical size (after resizing).
179 uint pos_x
; ///< Horizontal position of top-left corner of the widget in the window.
180 uint pos_y
; ///< Vertical position of top-left corner of the widget in the window.
182 NWidgetBase
*next
; ///< Pointer to next widget in container. Managed by parent container widget.
183 NWidgetBase
*prev
; ///< Pointer to previous widget in container. Managed by parent container widget.
185 uint8 padding_top
; ///< Paddings added to the top of the widget. Managed by parent container widget.
186 uint8 padding_right
; ///< Paddings added to the right of the widget. Managed by parent container widget. (parent container may swap this with padding_left for RTL)
187 uint8 padding_bottom
; ///< Paddings added to the bottom of the widget. Managed by parent container widget.
188 uint8 padding_left
; ///< Paddings added to the left of the widget. Managed by parent container widget. (parent container may swap this with padding_right for RTL)
191 inline void StoreSizePosition(SizingType sizing
, uint x
, uint y
, uint given_width
, uint given_height
);
195 * Get the horizontal sizing step.
196 * @param sizing Type of resize being performed.
198 inline uint
NWidgetBase::GetHorizontalStepSize(SizingType sizing
) const
200 return (sizing
== ST_RESIZE
) ? this->resize_x
: this->fill_x
;
204 * Get the vertical sizing step.
205 * @param sizing Type of resize being performed.
207 inline uint
NWidgetBase::GetVerticalStepSize(SizingType sizing
) const
209 return (sizing
== ST_RESIZE
) ? this->resize_y
: this->fill_y
;
213 * Store size and position.
214 * @param sizing Type of resizing to perform.
215 * @param x Horizontal offset of the widget relative to the left edge of the window.
216 * @param y Vertical offset of the widget relative to the top edge of the window.
217 * @param given_width Width allocated to the widget.
218 * @param given_height Height allocated to the widget.
220 inline void NWidgetBase::StoreSizePosition(SizingType sizing
, uint x
, uint y
, uint given_width
, uint given_height
)
224 if (sizing
== ST_SMALLEST
) {
225 this->smallest_x
= given_width
;
226 this->smallest_y
= given_height
;
228 this->current_x
= given_width
;
229 this->current_y
= given_height
;
234 * Base class for a resizable nested widget.
235 * @ingroup NestedWidgets
237 class NWidgetResizeBase
: public NWidgetBase
{
239 NWidgetResizeBase(WidgetType tp
, uint fill_x
, uint fill_y
);
241 void SetMinimalSize(uint min_x
, uint min_y
);
242 void SetMinimalTextLines(uint8 min_lines
, uint8 spacing
, FontSize size
);
243 void SetFill(uint fill_x
, uint fill_y
);
244 void SetResize(uint resize_x
, uint resize_y
);
246 void AssignSizePosition(SizingType sizing
, uint x
, uint y
, uint given_width
, uint given_height
, bool rtl
);
248 uint min_x
; ///< Minimal horizontal size of only this widget.
249 uint min_y
; ///< Minimal vertical size of only this widget.
252 /** Nested widget flags that affect display and interaction withe 'real' widgets. */
253 enum NWidgetDisplay
{
255 NDB_LOWERED
= 0, ///< Widget is lowered (pressed down) bit.
256 NDB_DISABLED
= 1, ///< Widget is disabled (greyed out) bit.
257 /* Viewport widget. */
258 NDB_NO_TRANSPARENCY
= 2, ///< Viewport is never transparent.
259 NDB_SHADE_GREY
= 3, ///< Shade viewport to grey-scale.
260 NDB_SHADE_DIMMED
= 4, ///< Display dimmed colours in the viewport.
261 /* Button dropdown widget. */
262 NDB_DROPDOWN_ACTIVE
= 5, ///< Dropdown menu of the button dropdown widget is active. @see #NWID_BUTTON_DRPDOWN
263 /* Scrollbar widget. */
264 NDB_SCROLLBAR_UP
= 6, ///< Up-button is lowered bit.
265 NDB_SCROLLBAR_DOWN
= 7, ///< Down-button is lowered bit.
267 NDB_HIGHLIGHT
= 8, ///< Highlight of widget is on.
269 ND_LOWERED
= 1 << NDB_LOWERED
, ///< Bit value of the lowered flag.
270 ND_DISABLED
= 1 << NDB_DISABLED
, ///< Bit value of the disabled flag.
271 ND_HIGHLIGHT
= 1 << NDB_HIGHLIGHT
, ///< Bit value of the highlight flag.
272 ND_NO_TRANSPARENCY
= 1 << NDB_NO_TRANSPARENCY
, ///< Bit value of the 'no transparency' flag.
273 ND_SHADE_GREY
= 1 << NDB_SHADE_GREY
, ///< Bit value of the 'shade to grey' flag.
274 ND_SHADE_DIMMED
= 1 << NDB_SHADE_DIMMED
, ///< Bit value of the 'dimmed colours' flag.
275 ND_DROPDOWN_ACTIVE
= 1 << NDB_DROPDOWN_ACTIVE
, ///< Bit value of the 'dropdown active' flag.
276 ND_SCROLLBAR_UP
= 1 << NDB_SCROLLBAR_UP
, ///< Bit value of the 'scrollbar up' flag.
277 ND_SCROLLBAR_DOWN
= 1 << NDB_SCROLLBAR_DOWN
, ///< Bit value of the 'scrollbar down' flag.
278 ND_SCROLLBAR_BTN
= ND_SCROLLBAR_UP
| ND_SCROLLBAR_DOWN
, ///< Bit value of the 'scrollbar up' or 'scrollbar down' flag.
280 DECLARE_ENUM_AS_BIT_SET(NWidgetDisplay
)
283 * Base class for a 'real' widget.
284 * @ingroup NestedWidgets
286 class NWidgetCore
: public NWidgetResizeBase
{
288 NWidgetCore(WidgetType tp
, Colours colour
, uint fill_x
, uint fill_y
, uint32 widget_data
, StringID tool_tip
);
290 void SetIndex(int index
);
291 void SetDataTip(uint32 widget_data
, StringID tool_tip
);
293 inline void SetLowered(bool lowered
);
294 inline bool IsLowered() const;
295 inline void SetDisabled(bool disabled
);
296 inline bool IsDisabled() const;
298 /* virtual */ void FillNestedArray(NWidgetBase
**array
, uint length
);
299 /* virtual */ NWidgetCore
*GetWidgetFromPos(int x
, int y
);
300 /* virtual */ bool IsHighlighted() const;
301 /* virtual */ TextColour
GetHighlightColour() const;
302 /* virtual */ void SetHighlighted(TextColour highlight_colour
);
304 NWidgetDisplay disp_flags
; ///< Flags that affect display and interaction with the widget.
305 Colours colour
; ///< Colour of this widget.
306 int index
; ///< Index of the nested widget in the widget array of the window (\c -1 means 'not used').
307 uint32 widget_data
; ///< Data of the widget. @see Widget::data
308 StringID tool_tip
; ///< Tooltip of the widget. @see Widget::tootips
309 int scrollbar_index
; ///< Index of an attached scrollbar.
310 TextColour highlight_colour
; ///< Colour of highlight.
314 * Highlight the widget or not.
315 * @param highlight_colour Widget must be highlighted (blink).
317 inline void NWidgetCore::SetHighlighted(TextColour highlight_colour
)
319 this->disp_flags
= highlight_colour
!= TC_INVALID
? SETBITS(this->disp_flags
, ND_HIGHLIGHT
) : CLRBITS(this->disp_flags
, ND_HIGHLIGHT
);
320 this->highlight_colour
= highlight_colour
;
323 /** Return whether the widget is highlighted. */
324 inline bool NWidgetCore::IsHighlighted() const
326 return HasBit(this->disp_flags
, NDB_HIGHLIGHT
);
329 /** Return the colour of the highlight. */
330 inline TextColour
NWidgetCore::GetHighlightColour() const
332 return this->highlight_colour
;
336 * Lower or raise the widget.
337 * @param lowered Widget must be lowered (drawn pressed down).
339 inline void NWidgetCore::SetLowered(bool lowered
)
341 this->disp_flags
= lowered
? SETBITS(this->disp_flags
, ND_LOWERED
) : CLRBITS(this->disp_flags
, ND_LOWERED
);
344 /** Return whether the widget is lowered. */
345 inline bool NWidgetCore::IsLowered() const
347 return HasBit(this->disp_flags
, NDB_LOWERED
);
351 * Disable (grey-out) or enable the widget.
352 * @param disabled Widget must be disabled.
354 inline void NWidgetCore::SetDisabled(bool disabled
)
356 this->disp_flags
= disabled
? SETBITS(this->disp_flags
, ND_DISABLED
) : CLRBITS(this->disp_flags
, ND_DISABLED
);
359 /** Return whether the widget is disabled. */
360 inline bool NWidgetCore::IsDisabled() const
362 return HasBit(this->disp_flags
, NDB_DISABLED
);
367 * Baseclass for container widgets.
368 * @ingroup NestedWidgets
370 class NWidgetContainer
: public NWidgetBase
{
372 NWidgetContainer(WidgetType tp
);
375 void Add(NWidgetBase
*wid
);
376 /* virtual */ void FillNestedArray(NWidgetBase
**array
, uint length
);
378 /** Return whether the container is empty. */
379 inline bool IsEmpty() { return head
== NULL
; }
381 /* virtual */ NWidgetBase
*GetWidgetOfType(WidgetType tp
);
384 NWidgetBase
*head
; ///< Pointer to first widget in container.
385 NWidgetBase
*tail
; ///< Pointer to last widget in container.
388 /** Display planes with zero size for #NWidgetStacked. */
389 enum StackedZeroSizePlanes
{
390 SZSP_VERTICAL
= INT_MAX
/ 2, ///< Display plane with zero size horizontally, and filling and resizing vertically.
391 SZSP_HORIZONTAL
, ///< Display plane with zero size vertically, and filling and resizing horizontally.
392 SZSP_NONE
, ///< Display plane with zero size in both directions (none filling and resizing).
394 SZSP_BEGIN
= SZSP_VERTICAL
, ///< First zero-size plane.
398 * Stacked widgets, widgets all occupying the same space in the window.
399 * #NWID_SELECTION allows for selecting one of several panels (planes) to tbe displayed. All planes must have the same size.
400 * Since all planes are also initialized, switching between different planes can be done while the window is displayed.
402 * There are also a number of special planes (defined in #StackedZeroSizePlanes) that have zero size in one direction (and are stretchable in
403 * the other direction) or have zero size in both directions. They are used to make all child planes of the widget disappear.
404 * Unlike switching between the regular display planes (that all have the same size), switching from or to one of the zero-sized planes means that
405 * a #Windows::ReInit() is needed to re-initialize the window since its size changes.
407 class NWidgetStacked
: public NWidgetContainer
{
411 void SetIndex(int index
);
413 void SetupSmallestSize(Window
*w
, bool init_array
);
414 void AssignSizePosition(SizingType sizing
, uint x
, uint y
, uint given_width
, uint given_height
, bool rtl
);
415 /* virtual */ void FillNestedArray(NWidgetBase
**array
, uint length
);
417 void Draw (BlitArea
*dpi
, const Window
*w
) OVERRIDE
;
418 /* virtual */ NWidgetCore
*GetWidgetFromPos(int x
, int y
);
420 void SetDisplayedPlane(int plane
);
422 int shown_plane
; ///< Plane being displayed (for #NWID_SELECTION only).
423 int index
; ///< If non-negative, index in the #Window::nested_array.
426 /** Nested widget container flags, */
427 enum NWidContainerFlags
{
428 NCB_EQUALSIZE
= 0, ///< Containers should keep all their (resizing) children equally large.
430 NC_NONE
= 0, ///< All flags cleared.
431 NC_EQUALSIZE
= 1 << NCB_EQUALSIZE
, ///< Value of the #NCB_EQUALSIZE flag.
433 DECLARE_ENUM_AS_BIT_SET(NWidContainerFlags
)
435 /** Container with pre/inter/post child space. */
436 class NWidgetPIPContainer
: public NWidgetContainer
{
438 NWidgetPIPContainer(WidgetType tp
, NWidContainerFlags flags
= NC_NONE
);
440 void SetPIP(uint8 pip_pre
, uint8 pip_inter
, uint8 pip_post
);
442 void Draw (BlitArea
*dpi
, const Window
*w
) OVERRIDE
;
443 /* virtual */ NWidgetCore
*GetWidgetFromPos(int x
, int y
);
446 NWidContainerFlags flags
; ///< Flags of the container.
447 uint8 pip_pre
; ///< Amount of space before first widget.
448 uint8 pip_inter
; ///< Amount of space between widgets.
449 uint8 pip_post
; ///< Amount of space after last widget.
453 * Horizontal container.
454 * @ingroup NestedWidgets
456 class NWidgetHorizontal
: public NWidgetPIPContainer
{
458 NWidgetHorizontal(NWidContainerFlags flags
= NC_NONE
);
460 void SetupSmallestSize(Window
*w
, bool init_array
);
461 void AssignSizePosition(SizingType sizing
, uint x
, uint y
, uint given_width
, uint given_height
, bool rtl
);
465 * Horizontal container that doesn't change the direction of the widgets for RTL languages.
466 * @ingroup NestedWidgets
468 class NWidgetHorizontalLTR
: public NWidgetHorizontal
{
470 NWidgetHorizontalLTR(NWidContainerFlags flags
= NC_NONE
);
472 void AssignSizePosition(SizingType sizing
, uint x
, uint y
, uint given_width
, uint given_height
, bool rtl
);
476 * Vertical container.
477 * @ingroup NestedWidgets
479 class NWidgetVertical
: public NWidgetPIPContainer
{
481 NWidgetVertical(NWidContainerFlags flags
= NC_NONE
);
483 void SetupSmallestSize(Window
*w
, bool init_array
);
484 void AssignSizePosition(SizingType sizing
, uint x
, uint y
, uint given_width
, uint given_height
, bool rtl
);
488 * Matrix container with implicitly equal sized (virtual) sub-widgets.
489 * This widget must have exactly one sub-widget. After that this sub-widget
490 * is used to draw all of the data within the matrix piece by piece.
491 * DrawWidget and OnClick calls will be done to that sub-widget, where the
492 * 16 high bits are used to encode the index into the matrix.
493 * @ingroup NestedWidgets
495 class NWidgetMatrix
: public NWidgetPIPContainer
{
499 void SetIndex(int index
);
500 void SetColour(Colours colour
);
501 void SetClicked(int clicked
);
502 void SetCount(int count
);
503 void SetScrollbar(Scrollbar
*sb
);
505 void SetupSmallestSize(Window
*w
, bool init_array
);
506 void AssignSizePosition(SizingType sizing
, uint x
, uint y
, uint given_width
, uint given_height
, bool rtl
);
507 /* virtual */ void FillNestedArray(NWidgetBase
**array
, uint length
);
509 /* virtual */ NWidgetCore
*GetWidgetFromPos(int x
, int y
);
510 void Draw (BlitArea
*dpi
, const Window
*w
) OVERRIDE
;
512 int index
; ///< If non-negative, index in the #Window::nested_array.
513 Colours colour
; ///< Colour of this widget.
514 int clicked
; ///< The currently clicked widget.
515 int count
; ///< Amount of valid widgets.
516 Scrollbar
*sb
; ///< The scrollbar we're associated with.
518 int widget_w
; ///< The width of the child widget including inter spacing.
519 int widget_h
; ///< The height of the child widget including inter spacing.
520 int widgets_x
; ///< The number of visible widgets in horizontal direction.
521 int widgets_y
; ///< The number of visible widgets in vertical direction.
523 void GetScrollOffsets(int &start_x
, int &start_y
, int &base_offs_x
, int &base_offs_y
);
529 * @ingroup NestedWidgets
531 class NWidgetSpacer
: public NWidgetResizeBase
{
533 NWidgetSpacer(int length
, int height
);
535 void SetupSmallestSize(Window
*w
, bool init_array
);
536 /* virtual */ void FillNestedArray(NWidgetBase
**array
, uint length
);
538 void Draw (BlitArea
*dpi
, const Window
*w
) OVERRIDE
;
539 /* virtual */ void SetDirty(const Window
*w
) const;
540 /* virtual */ NWidgetCore
*GetWidgetFromPos(int x
, int y
);
544 * Nested widget with a child.
545 * @ingroup NestedWidgets
547 class NWidgetBackground
: public NWidgetCore
{
549 NWidgetBackground(WidgetType tp
, Colours colour
, int index
, NWidgetPIPContainer
*child
= NULL
);
550 ~NWidgetBackground();
552 void Add(NWidgetBase
*nwid
);
553 void SetPIP(uint8 pip_pre
, uint8 pip_inter
, uint8 pip_post
);
555 void SetupSmallestSize(Window
*w
, bool init_array
);
556 void AssignSizePosition(SizingType sizing
, uint x
, uint y
, uint given_width
, uint given_height
, bool rtl
);
558 /* virtual */ void FillNestedArray(NWidgetBase
**array
, uint length
);
560 void Draw (BlitArea
*dpi
, const Window
*w
) OVERRIDE
;
561 /* virtual */ NWidgetCore
*GetWidgetFromPos(int x
, int y
);
562 /* virtual */ NWidgetBase
*GetWidgetOfType(WidgetType tp
);
565 NWidgetPIPContainer
*child
; ///< Child widget.
569 * Nested widget to display a viewport in a window.
570 * After initializing the nested widget tree, call #InitializeViewport(). After changing the window size,
571 * call #UpdateViewportCoordinates() eg from Window::OnResize().
572 * If the #display_flags field contains the #ND_NO_TRANSPARENCY bit, the viewport will disable transparency.
573 * Shading to grey-scale is controlled with the #ND_SHADE_GREY bit (used for B&W news papers), the #ND_SHADE_DIMMED gives dimmed colours (for colour news papers).
574 * @todo Class derives from #NWidgetCore, but does not use #colour, #widget_data, or #tool_tip.
575 * @ingroup NestedWidgets
577 class NWidgetViewport
: public NWidgetCore
{
579 NWidgetViewport(int index
);
581 /* virtual */ void SetupSmallestSize(Window
*w
, bool init_array
);
582 void Draw (BlitArea
*dpi
, const Window
*w
) OVERRIDE
;
584 void InitializeViewport(Window
*w
, uint32 follow_flags
, ZoomLevel zoom
);
585 void UpdateViewportCoordinates(Window
*w
);
589 * Scrollbar data structure
593 const bool is_vertical
; ///< Scrollbar has vertical orientation.
594 uint16 count
; ///< Number of elements in the list.
595 uint16 cap
; ///< Number of visible elements of the scroll bar.
596 uint16 pos
; ///< Index of first visible item of the list.
597 uint16 stepsize
; ///< Distance to scroll, when pressing the buttons or using the wheel.
600 /** Stepping sizes when scrolling */
601 enum ScrollbarStepping
{
602 SS_RAW
, ///< Step in single units.
603 SS_SMALL
, ///< Step in #stepsize units.
604 SS_BIG
, ///< Step in #cap units.
607 Scrollbar(bool is_vertical
) : is_vertical(is_vertical
), stepsize(1)
612 * Gets the number of elements in the list
613 * @return the number of elements
615 inline uint16
GetCount() const
621 * Gets the number of visible elements of the scrollbar
622 * @return the number of visible elements
624 inline uint16
GetCapacity() const
630 * Gets the position of the first visible element in the list
631 * @return the position of the element
633 inline uint16
GetPosition() const
639 * Checks whether given current item is visible in the list
640 * @param item to check
641 * @return true iff the item is visible
643 inline bool IsVisible(uint16 item
) const
645 return IsInsideBS(item
, this->GetPosition(), this->GetCapacity());
649 * Is the scrollbar vertical or not?
650 * @return True iff the scrollbar is vertical.
652 inline bool IsVertical() const
654 return this->is_vertical
;
658 * Set the distance to scroll when using the buttons or the wheel.
659 * @param stepsize Scrolling speed.
661 void SetStepSize(uint16 stepsize
)
663 assert(stepsize
> 0);
664 this->stepsize
= stepsize
;
668 * Sets the number of elements in the list
669 * @param num the number of elements in the list
670 * @note updates the position if needed
672 void SetCount(int num
)
675 assert(num
<= MAX_UVALUE(uint16
));
679 if (num
< 0) num
= 0;
680 if (num
< this->pos
) this->pos
= num
;
684 * Set the capacity of visible elements.
685 * @param capacity the new capacity
686 * @note updates the position if needed
688 void SetCapacity(int capacity
)
690 assert(capacity
> 0);
691 assert(capacity
<= MAX_UVALUE(uint16
));
693 this->cap
= capacity
;
694 if (this->cap
+ this->pos
> this->count
) this->pos
= max(0, this->count
- this->cap
);
697 void SetCapacityFromWidget(Window
*w
, int widget
, int padding
= 0);
700 * Sets the position of the first visible element
701 * @param position the position of the element
703 void SetPosition(int position
)
705 assert(position
>= 0);
706 assert(this->count
<= this->cap
? (position
== 0) : (position
+ this->cap
<= this->count
));
707 this->pos
= position
;
711 * Updates the position of the first visible element by the given amount.
712 * If the position would be too low or high it will be clamped appropriately
713 * @param difference the amount of change requested
714 * @param unit The stepping unit of \a difference
716 void UpdatePosition(int difference
, ScrollbarStepping unit
= SS_SMALL
)
718 if (difference
== 0) return;
720 case SS_SMALL
: difference
*= this->stepsize
; break;
721 case SS_BIG
: difference
*= this->cap
; break;
724 this->SetPosition(Clamp(this->pos
+ difference
, 0, max(this->count
- this->cap
, 0)));
728 * Scroll towards the given position; if the item is visible nothing
729 * happens, otherwise it will be shown either at the bottom or top of
730 * the window depending on where in the list it was.
731 * @param position the position to scroll towards.
733 void ScrollTowards(int position
)
735 if (position
< this->GetPosition()) {
736 /* scroll up to the item */
737 this->SetPosition(position
);
738 } else if (position
>= this->GetPosition() + this->GetCapacity()) {
739 /* scroll down so that the item is at the bottom */
740 this->SetPosition(position
- this->GetCapacity() + 1);
744 int GetScrolledRowFromWidget(int clickpos
, const Window
* const w
, int widget
, int padding
= 0, int line_height
= -1) const;
748 * Nested widget to display and control a scrollbar in a window.
749 * Also assign the scrollbar to other widgets using #SetScrollbar() to make the mousewheel work.
750 * @ingroup NestedWidgets
752 class NWidgetScrollbar
: public NWidgetCore
, public Scrollbar
{
754 NWidgetScrollbar(WidgetType tp
, Colours colour
, int index
);
756 /* virtual */ void SetupSmallestSize(Window
*w
, bool init_array
);
757 void Draw (BlitArea
*dpi
, const Window
*w
) OVERRIDE
;
759 static void InvalidateDimensionCache();
760 static Dimension
GetVerticalDimension();
761 static Dimension
GetHorizontalDimension();
764 static Dimension vertical_dimension
; ///< Cached size of vertical scrollbar button.
765 static Dimension horizontal_dimension
; ///< Cached size of horizontal scrollbar button.
770 * @ingroup NestedWidgets
772 class NWidgetLeaf
: public NWidgetCore
{
774 NWidgetLeaf(WidgetType tp
, Colours colour
, int index
, uint32 data
, StringID tip
);
776 /* virtual */ void SetupSmallestSize(Window
*w
, bool init_array
);
777 void Draw (BlitArea
*dpi
, const Window
*w
) OVERRIDE
;
779 bool ButtonHit(const Point
&pt
);
781 static void InvalidateDimensionCache();
783 static Dimension dropdown_dimension
; ///< Cached size of a dropdown widget.
784 static Dimension resizebox_dimension
; ///< Cached size of a resizebox widget.
785 static Dimension closebox_dimension
; ///< Cached size of a closebox widget.
787 static Dimension shadebox_dimension
; ///< Cached size of a shadebox widget.
788 static Dimension debugbox_dimension
; ///< Cached size of a debugbox widget.
789 static Dimension defsizebox_dimension
; ///< Cached size of a defsizebox widget.
790 static Dimension stickybox_dimension
; ///< Cached size of a stickybox widget.
794 * Return the biggest possible size of a nested widget.
795 * @param base Base size of the widget.
796 * @param max_space Available space for the widget.
797 * @param step Stepsize of the widget.
798 * @return Biggest possible size of the widget, assuming that \a base may only be incremented by \a step size steps.
800 static inline uint
ComputeMaxSize(uint base
, uint max_space
, uint step
)
802 if (base
>= max_space
|| step
== 0) return base
;
803 if (step
== 1) return max_space
;
804 uint increment
= max_space
- base
;
805 increment
-= increment
% step
;
806 return base
+ increment
;
810 * @defgroup NestedWidgetParts Hierarchical widget parts
811 * To make nested widgets easier to enter, nested widget parts have been created. They allow the tree to be defined in a flat array of parts.
813 * - Leaf widgets start with a #NWidget(WidgetType tp, Colours col, int16 idx) part.
814 * Next, specify its properties with one or more of
815 * - #SetMinimalSize Define the minimal size of the widget.
816 * - #SetFill Define how the widget may grow to make it nicely.
817 * - #SetDataTip Define the data and the tooltip of the widget.
818 * - #SetResize Define how the widget may resize.
819 * - #SetPadding Create additional space around the widget.
821 * - To insert a nested widget tree from an external source, nested widget part #NWidgetFunction exists.
822 * For further customization, the #SetPadding part may be used.
824 * - Space widgets (#NWidgetSpacer) start with a #NWidget(WidgetType tp), followed by one or more of
825 * - #SetMinimalSize Define the minimal size of the widget.
826 * - #SetFill Define how the widget may grow to make it nicely.
827 * - #SetResize Define how the widget may resize.
828 * - #SetPadding Create additional space around the widget.
830 * - Container widgets #NWidgetHorizontal, #NWidgetHorizontalLTR, #NWidgetVertical, and #NWidgetMatrix, start with a #NWidget(WidgetType tp) part.
831 * Their properties are derived from the child widgets so they cannot be specified.
832 * You can however use
833 * - #SetPadding Define additional padding around the container.
834 * - #SetPIP Set additional pre/inter/post child widget space.
836 * Underneath these properties, all child widgets of the container must be defined. To denote that they are childs, add an indent before the nested widget parts of
837 * the child widgets (it has no meaning for the compiler but it makes the widget parts easier to read).
838 * Below the last child widget, use an #EndContainer part. This part should be aligned with the #NWidget part that started the container.
840 * - Stacked widgets #NWidgetStacked map each of their children onto the same space. It behaves like a container, except there is no pre/inter/post space,
841 * so the widget does not support #SetPIP. #SetPadding is allowed though.
842 * Like the other container widgets, below the last child widgets, a #EndContainer part should be used to denote the end of the stacked widget.
844 * - Background widgets #NWidgetBackground start with a #NWidget(WidgetType tp, Colours col, int16 idx) part.
845 * What follows depends on how the widget is used.
846 * - 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
847 * leaf widgets to define how it behaves.
848 * - If the widget is used a background behind other widgets, it is considered to be a container widgets. Use the properties listed there to define its
851 * In both cases, the background widget \b MUST end with a #EndContainer widget part.
857 * Widget part for storing data and tooltip information.
858 * @ingroup NestedWidgetParts
860 struct NWidgetPartDataTip
{
861 uint32 data
; ///< Data value of the widget.
862 StringID tooltip
; ///< Tooltip of the widget.
866 * Widget part for storing basic widget information.
867 * @ingroup NestedWidgetParts
869 struct NWidgetPartWidget
{
870 Colours colour
; ///< Widget colour.
871 int16 index
; ///< Widget index in the widget array.
875 * Widget part for storing padding.
876 * @ingroup NestedWidgetParts
878 struct NWidgetPartPaddings
{
879 uint8 top
, right
, bottom
, left
; ///< Paddings for all directions.
883 * Widget part for storing pre/inter/post spaces.
884 * @ingroup NestedWidgetParts
886 struct NWidgetPartPIP
{
887 uint8 pre
, inter
, post
; ///< Amount of space before/between/after child widgets.
891 * Widget part for storing minimal text line data.
892 * @ingroup NestedWidgetParts
894 struct NWidgetPartTextLines
{
895 uint8 lines
; ///< Number of text lines.
896 uint8 spacing
; ///< Extra spacing around lines.
897 FontSize size
; ///< Font size of text lines.
901 * Pointer to function returning a nested widget.
902 * @param biggest_index Pointer to storage for collecting the biggest index used in the nested widget.
903 * @return Nested widget (tree).
904 * @post \c *biggest_index must contain the value of the biggest index in the returned tree.
906 typedef NWidgetBase
*NWidgetFunctionType(int *biggest_index
);
909 * Partial widget specification to allow NWidgets to be written nested.
910 * @ingroup NestedWidgetParts
913 WidgetType type
; ///< Type of the part. @see NWidgetPartType.
915 Point xy
; ///< Part with an x/y size.
916 NWidgetPartDataTip data_tip
; ///< Part with a data/tooltip.
917 NWidgetPartWidget widget
; ///< Part with a start of a widget.
918 NWidgetPartPaddings padding
; ///< Part with paddings.
919 NWidgetPartPIP pip
; ///< Part with pre/inter/post spaces.
920 NWidgetPartTextLines text_lines
; ///< Part with text line data.
921 NWidgetFunctionType
*func_ptr
; ///< Part with a function call.
922 NWidContainerFlags cont_flags
; ///< Part with container flags.
927 * Widget part function for setting the resize step.
928 * @param dx Horizontal resize step. 0 means no horizontal resizing.
929 * @param dy Vertical resize step. 0 means no vertical resizing.
930 * @ingroup NestedWidgetParts
932 static inline NWidgetPart
SetResize(int16 dx
, int16 dy
)
936 part
.type
= WPT_RESIZE
;
944 * Widget part function for setting the minimal size.
945 * @param x Horizontal minimal size.
946 * @param y Vertical minimal size.
947 * @ingroup NestedWidgetParts
949 static inline NWidgetPart
SetMinimalSize(int16 x
, int16 y
)
953 part
.type
= WPT_MINSIZE
;
961 * Widget part function for setting the minimal text lines.
962 * @param lines Number of text lines.
963 * @param spacing Extra spacing required.
964 * @param size Font size of text.
965 * @ingroup NestedWidgetParts
967 static inline NWidgetPart
SetMinimalTextLines(uint8 lines
, uint8 spacing
, FontSize size
= FS_NORMAL
)
971 part
.type
= WPT_MINTEXTLINES
;
972 part
.u
.text_lines
.lines
= lines
;
973 part
.u
.text_lines
.spacing
= spacing
;
974 part
.u
.text_lines
.size
= size
;
980 * Widget part function for setting filling.
981 * @param fill_x Horizontal filling step from minimal size.
982 * @param fill_y Vertical filling step from minimal size.
983 * @ingroup NestedWidgetParts
985 static inline NWidgetPart
SetFill(uint fill_x
, uint fill_y
)
989 part
.type
= WPT_FILL
;
990 part
.u
.xy
.x
= fill_x
;
991 part
.u
.xy
.y
= fill_y
;
997 * Widget part function for denoting the end of a container
998 * (horizontal, vertical, WWT_FRAME, WWT_INSET, or WWT_PANEL).
999 * @ingroup NestedWidgetParts
1001 static inline NWidgetPart
EndContainer()
1005 part
.type
= WPT_ENDCONTAINER
;
1011 * Widget part function for setting the data and tooltip.
1012 * @param data Data of the widget.
1013 * @param tip Tooltip of the widget.
1014 * @ingroup NestedWidgetParts
1016 static inline NWidgetPart
SetDataTip(uint32 data
, StringID tip
)
1020 part
.type
= WPT_DATATIP
;
1021 part
.u
.data_tip
.data
= data
;
1022 part
.u
.data_tip
.tooltip
= tip
;
1028 * Widget part function for setting the data and tooltip of WWT_MATRIX widgets
1029 * @param cols Number of columns. \c 0 means to use draw columns with width according to the resize step size.
1030 * @param rows Number of rows. \c 0 means to use draw rows with height according to the resize step size.
1031 * @param tip Tooltip of the widget.
1032 * @ingroup NestedWidgetParts
1034 static inline NWidgetPart
SetMatrixDataTip(uint8 cols
, uint8 rows
, StringID tip
)
1036 return SetDataTip((rows
<< MAT_ROW_START
) | (cols
<< MAT_COL_START
), tip
);
1040 * Widget part function for setting additional space around a widget.
1041 * Parameters start above the widget, and are specified in clock-wise direction.
1042 * @param top The padding above the widget.
1043 * @param right The padding right of the widget.
1044 * @param bottom The padding below the widget.
1045 * @param left The padding left of the widget.
1046 * @ingroup NestedWidgetParts
1048 static inline NWidgetPart
SetPadding(uint8 top
, uint8 right
, uint8 bottom
, uint8 left
)
1052 part
.type
= WPT_PADDING
;
1053 part
.u
.padding
.top
= top
;
1054 part
.u
.padding
.right
= right
;
1055 part
.u
.padding
.bottom
= bottom
;
1056 part
.u
.padding
.left
= left
;
1062 * Widget part function for setting a padding.
1063 * @param padding The padding to use for all directions.
1064 * @ingroup NestedWidgetParts
1066 static inline NWidgetPart
SetPadding(uint8 padding
)
1068 return SetPadding(padding
, padding
, padding
, padding
);
1072 * Widget part function for setting a pre/inter/post spaces.
1073 * @param pre The amount of space before the first widget.
1074 * @param inter The amount of space between widgets.
1075 * @param post The amount of space after the last widget.
1076 * @ingroup NestedWidgetParts
1078 static inline NWidgetPart
SetPIP(uint8 pre
, uint8 inter
, uint8 post
)
1082 part
.type
= WPT_PIPSPACE
;
1083 part
.u
.pip
.pre
= pre
;
1084 part
.u
.pip
.inter
= inter
;
1085 part
.u
.pip
.post
= post
;
1091 * Attach a scrollbar to a widget.
1092 * The scrollbar is controlled when using the mousewheel on the widget.
1093 * Multiple widgets can refer to the same scrollbar to make the mousewheel work in all of them.
1094 * @param index Widget index of the scrollbar.
1095 * @ingroup NestedWidgetParts
1097 static inline NWidgetPart
SetScrollbar(int index
)
1101 part
.type
= WPT_SCROLLBAR
;
1102 part
.u
.widget
.index
= index
;
1108 * Widget part function for starting a new 'real' widget.
1109 * @param tp Type of the new nested widget.
1110 * @param col Colour of the new widget.
1111 * @param idx Index of the widget in the widget array.
1112 * @note with #WWT_PANEL, #WWT_FRAME, #WWT_INSET, a new container is started.
1113 * Child widgets must have a index bigger than the parent index.
1114 * @ingroup NestedWidgetParts
1116 static inline NWidgetPart
NWidget(WidgetType tp
, Colours col
, int16 idx
= -1)
1121 part
.u
.widget
.colour
= col
;
1122 part
.u
.widget
.index
= idx
;
1128 * Widget part function for starting a new horizontal container, vertical container, or spacer widget.
1129 * @param tp Type of the new nested widget, #NWID_HORIZONTAL(_LTR), #NWID_VERTICAL, #NWID_SPACER, #NWID_SELECTION, and #NWID_MATRIX.
1130 * @param cont_flags Flags for the containers (#NWID_HORIZONTAL(_LTR) and #NWID_VERTICAL).
1131 * @ingroup NestedWidgetParts
1133 static inline NWidgetPart
NWidget(WidgetType tp
, NWidContainerFlags cont_flags
= NC_NONE
)
1138 part
.u
.cont_flags
= cont_flags
;
1144 * Obtain a nested widget (sub)tree from an external source.
1145 * @param func_ptr Pointer to function that returns the tree.
1146 * @ingroup NestedWidgetParts
1148 static inline NWidgetPart
NWidgetFunction(NWidgetFunctionType
*func_ptr
)
1152 part
.type
= WPT_FUNCTION
;
1153 part
.u
.func_ptr
= func_ptr
;
1158 NWidgetContainer
*MakeNWidgets(const NWidgetPart
*parts
, int count
, int *biggest_index
, NWidgetContainer
*container
);
1159 NWidgetContainer
*MakeWindowNWidgetTree(const NWidgetPart
*parts
, int count
, int *biggest_index
, NWidgetStacked
**shade_select
);
1161 NWidgetBase
*MakeCompanyButtonRows(int *biggest_index
, int widget_first
, int widget_last
, int max_length
, StringID button_tooltip
);
1163 #endif /* WIDGET_TYPE_H */