2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
8 /** @file window_gui.h Functions, definitions and such used only by the GUI. */
13 #include "vehiclelist.h"
14 #include "vehicle_type.h"
15 #include "viewport_type.h"
16 #include "company_type.h"
17 #include "tile_type.h"
18 #include "widget_type.h"
19 #include "string_type.h"
22 * Flags to describe the look of the frame
26 FR_TRANSPARENT
= 1 << 0, ///< Makes the background transparent if set
27 FR_BORDERONLY
= 1 << 4, ///< Draw border only, no background
28 FR_LOWERED
= 1 << 5, ///< If set the frame is lowered and the background colour brighter (ie. buttons when pressed)
29 FR_DARKENED
= 1 << 6, ///< If set the background is darker, allows for lowered frames with normal background colour when used with FR_LOWERED (ie. dropdown boxes)
32 DECLARE_ENUM_AS_BIT_SET(FrameFlags
)
34 class WidgetDimensions
{
36 RectPadding imgbtn
; ///< Padding around image button image.
37 RectPadding inset
; ///< Padding inside inset container.
38 RectPadding vscrollbar
; ///< Padding inside vertical scrollbar buttons.
39 RectPadding hscrollbar
; ///< Padding inside horizontal scrollbar buttons.
40 RectPadding bevel
; ///< Bevel thickness, affected by "scaled bevels" game option.
41 RectPadding fullbevel
; ///< Always-scaled bevel thickness.
42 RectPadding framerect
; ///< Standard padding inside many panels.
43 RectPadding frametext
; ///< Padding inside frame with text.
44 RectPadding matrix
; ///< Padding of WWT_MATRIX items.
45 RectPadding shadebox
; ///< Padding around image in shadebox widget.
46 RectPadding stickybox
; ///< Padding around image in stickybox widget.
47 RectPadding debugbox
; ///< Padding around image in debugbox widget.
48 RectPadding defsizebox
; ///< Padding around image in defsizebox widget.
49 RectPadding resizebox
; ///< Padding around image in resizebox widget.
50 RectPadding closebox
; ///< Padding around image in closebox widget.
51 RectPadding captiontext
; ///< Padding for text within caption widget.
52 RectPadding dropdowntext
; ///< Padding of drop down list item.
53 RectPadding dropdownlist
; ///< Padding of complete drop down list.
54 RectPadding modalpopup
; ///< Spacing for popup warning/information windows.
55 RectPadding picker
; ///< Padding for a picker (dock, station, etc) window.
56 RectPadding sparse
; ///< Padding used for 'sparse' widget window, usually containing multiple frames.
57 RectPadding sparse_resize
; ///< Padding used for a resizeable 'sparse' widget window, usually containing multiple frames.
59 int vsep_picker
; ///< Vertical spacing of picker-window widgets.
60 int vsep_normal
; ///< Normal vertical spacing.
61 int vsep_sparse
; ///< Normal vertical spacing for 'sparse' widget window.
62 int vsep_wide
; ///< Wide vertical spacing.
63 int hsep_normal
; ///< Normal horizontal spacing.
64 int hsep_wide
; ///< Wide horizontal spacing.
65 int hsep_indent
; ///< Width of identation for tree layouts.
67 static const WidgetDimensions unscaled
; ///< Unscaled widget dimensions.
68 static WidgetDimensions scaled
; ///< Widget dimensions scaled for current zoom level.
70 static constexpr float ASPECT_LOCATION
= 12.f
/ 14.f
;
71 static constexpr float ASPECT_RENAME
= 12.f
/ 14.f
;
72 static constexpr float ASPECT_SETTINGS_BUTTON
= 21.f
/ 12.f
;
73 static constexpr float ASPECT_TOGGLE_SIZE
= 12.f
/ 14.f
;
74 static constexpr float ASPECT_LEFT_RIGHT_BUTTON
= 8.f
/ 12.f
;
75 static constexpr float ASPECT_UP_DOWN_BUTTON
= 11.f
/ 12.f
;
76 static constexpr float ASPECT_VEHICLE_ICON
= 15.f
/ 12.f
;
77 static constexpr float ASPECT_VEHICLE_FLAG
= 11.f
/ 12.f
;
81 * Distances used in drawing widgets.
82 * These constants should not be used elsewhere, use scaled/unscaled WidgetDimensions instead.
84 static constexpr uint WD_SHADEBOX_WIDTH
= 12; ///< Minimum width of a standard shade box widget.
85 static constexpr uint WD_STICKYBOX_WIDTH
= 12; ///< Minimum width of a standard sticky box widget.
86 static constexpr uint WD_DEBUGBOX_WIDTH
= 12; ///< Minimum width of a standard debug box widget.
87 static constexpr uint WD_DEFSIZEBOX_WIDTH
= 12; ///< Minimum width of a standard defsize box widget.
88 static constexpr uint WD_RESIZEBOX_WIDTH
= 12; ///< Minimum width of a resize box widget.
89 static constexpr uint WD_CLOSEBOX_WIDTH
= 11; ///< Minimum width of a close box widget.
90 static constexpr uint WD_CAPTION_HEIGHT
= 14; ///< Minimum height of a title bar.
91 static constexpr uint WD_DROPDOWN_HEIGHT
= 12; ///< Minimum height of a drop down widget.
96 inline constexpr WidgetDimensions
WidgetDimensions::unscaled
= {
97 .imgbtn
= { .left
= 1, .top
= 1, .right
= 1, .bottom
= 1},
98 .inset
= { .left
= 2, .top
= 1, .right
= 2, .bottom
= 1},
99 .vscrollbar
= { .left
= 2, .top
= 3, .right
= 2, .bottom
= 3},
100 .hscrollbar
= { .left
= 3, .top
= 2, .right
= 3, .bottom
= 2},
101 .bevel
= { .left
= 1, .top
= 1, .right
= 1, .bottom
= 1},
102 .fullbevel
= { .left
= 1, .top
= 1, .right
= 1, .bottom
= 1},
103 .framerect
= { .left
= 2, .top
= 1, .right
= 2, .bottom
= 1},
104 .frametext
= { .left
= 6, .top
= 6, .right
= 6, .bottom
= 6},
105 .matrix
= { .left
= 2, .top
= 3, .right
= 2, .bottom
= 1},
106 .shadebox
= { .left
= 2, .top
= 3, .right
= 2, .bottom
= 3},
107 .stickybox
= { .left
= 2, .top
= 3, .right
= 2, .bottom
= 3},
108 .debugbox
= { .left
= 2, .top
= 3, .right
= 2, .bottom
= 3},
109 .defsizebox
= { .left
= 2, .top
= 3, .right
= 2, .bottom
= 3},
110 .resizebox
= { .left
= 2, .top
= 2, .right
= 2, .bottom
= 2},
111 .closebox
= { .left
= 2, .top
= 2, .right
= 1, .bottom
= 2},
112 .captiontext
= { .left
= 2, .top
= 2, .right
= 2, .bottom
= 2},
113 .dropdowntext
= { .left
= 2, .top
= 1, .right
= 2, .bottom
= 1},
114 .dropdownlist
= { .left
= 1, .top
= 2, .right
= 1, .bottom
= 2},
115 .modalpopup
= { .left
= 20, .top
= 10, .right
= 20, .bottom
= 10},
116 .picker
= { .left
= 3, .top
= 3, .right
= 3, .bottom
= 3},
117 .sparse
= { .left
= 10, .top
= 8, .right
= 10, .bottom
= 8},
118 .sparse_resize
= { .left
= 10, .top
= 8, .right
= 10, .bottom
= 0},
129 void DrawFrameRect(int left
, int top
, int right
, int bottom
, Colours colour
, FrameFlags flags
);
131 inline void DrawFrameRect(const Rect
&r
, Colours colour
, FrameFlags flags
)
133 DrawFrameRect(r
.left
, r
.top
, r
.right
, r
.bottom
, colour
, flags
);
136 void DrawCaption(const Rect
&r
, Colours colour
, Owner owner
, TextColour text_colour
, StringID str
, StringAlignment align
, FontSize fs
);
139 using WindowList
= std::list
<Window
*>;
140 extern WindowList _z_windows
;
141 extern Window
*_focused_window
;
144 /** How do we the window to be placed? */
145 enum WindowPosition
{
146 WDP_MANUAL
, ///< Manually align the window (so no automatic location finding)
147 WDP_AUTO
, ///< Find a place automatically
148 WDP_CENTER
, ///< Center the window
149 WDP_ALIGN_TOOLBAR
, ///< Align toward the toolbar
152 Point
GetToolbarAlignedWindowPosition(int window_width
);
157 * High level window description
159 struct WindowDesc
: ZeroedMemoryAllocator
{
161 WindowDesc(WindowPosition default_pos
, const char *ini_key
, int16_t def_width_trad
, int16_t def_height_trad
,
162 WindowClass window_class
, WindowClass parent_class
, uint32_t flags
,
163 const std::span
<const NWidgetPart
> nwid_parts
, HotkeyList
*hotkeys
= nullptr,
164 const std::source_location location
= std::source_location::current());
168 const std::source_location source_location
; ///< Source location of this definition
169 WindowPosition default_pos
; ///< Preferred position of the window. @see WindowPosition()
170 WindowClass cls
; ///< Class of the window, @see WindowClass.
171 WindowClass parent_cls
; ///< Class of the parent window. @see WindowClass
172 const char *ini_key
; ///< Key to store window defaults in openttd.cfg. \c nullptr if nothing shall be stored.
173 uint32_t flags
; ///< Flags. @see WindowDefaultFlag
174 const std::span
<const NWidgetPart
> nwid_parts
; ///< Span of nested widget parts describing the window.
175 HotkeyList
*hotkeys
; ///< Hotkeys for the window.
177 bool pref_sticky
; ///< Preferred stickyness.
178 int16_t pref_width
; ///< User-preferred width of the window. Zero if unset.
179 int16_t pref_height
; ///< User-preferred height of the window. Zero if unset.
181 int16_t GetDefaultWidth() const;
182 int16_t GetDefaultHeight() const;
184 static void LoadFromConfig();
185 static void SaveToConfig();
188 int16_t default_width_trad
; ///< Preferred initial width of the window (pixels at 1x zoom).
189 int16_t default_height_trad
; ///< Preferred initial height of the window (pixels at 1x zoom).
192 * Delete copy constructor to prevent compilers from
193 * copying the structure, which fails due to _window_descs.
195 WindowDesc(const WindowDesc
&) = delete;
196 WindowDesc
& operator=(const WindowDesc
&) = delete;
200 * Window default widget/window handling flags
202 enum WindowDefaultFlag
{
203 WDF_CONSTRUCTION
= 1 << 0, ///< This window is used for construction; close it whenever changing company.
204 WDF_MODAL
= 1 << 1, ///< The window is a modal child of some other window, meaning the parent is 'inactive'
205 WDF_NO_FOCUS
= 1 << 2, ///< This window won't get focus/make any other window lose focus when click
206 WDF_NO_CLOSE
= 1 << 3, ///< This window can't be interactively closed
210 * Data structure for resizing a window
213 uint step_width
; ///< Step-size of width resize changes
214 uint step_height
; ///< Step-size of height resize changes
217 /** State of a sort direction button. */
218 enum SortButtonState
{
219 SBS_OFF
, ///< Do not sort (with this button).
220 SBS_DOWN
, ///< Sort ascending.
221 SBS_UP
, ///< Sort descending.
228 WF_TIMEOUT
= 1 << 0, ///< Window timeout counter.
230 WF_DRAGGING
= 1 << 3, ///< Window is being dragged.
231 WF_SIZING_RIGHT
= 1 << 4, ///< Window is being resized towards the right.
232 WF_SIZING_LEFT
= 1 << 5, ///< Window is being resized towards the left.
233 WF_SIZING
= WF_SIZING_RIGHT
| WF_SIZING_LEFT
, ///< Window is being resized.
234 WF_STICKY
= 1 << 6, ///< Window is made sticky by user
235 WF_DISABLE_VP_SCROLL
= 1 << 7, ///< Window does not do autoscroll, @see HandleAutoscroll().
236 WF_WHITE_BORDER
= 1 << 8, ///< Window white border counter bit mask.
237 WF_HIGHLIGHTED
= 1 << 9, ///< Window has a widget that has a highlight.
238 WF_CENTERED
= 1 << 10, ///< Window is centered and shall stay centered after ReInit.
240 DECLARE_ENUM_AS_BIT_SET(WindowFlags
)
242 static const int TIMEOUT_DURATION
= 7; ///< The initial timeout value for WF_TIMEOUT.
243 static const int WHITE_BORDER_DURATION
= 3; ///< The initial timeout value for WF_WHITE_BORDER.
246 * Data structure for a window viewport.
247 * A viewport is either following a vehicle (its id in then in #follow_vehicle), or it aims to display a specific
248 * location #dest_scrollpos_x, #dest_scrollpos_y (#follow_vehicle is then #INVALID_VEHICLE).
249 * The actual location being shown is #scrollpos_x, #scrollpos_y.
250 * @see InitializeViewport(), UpdateViewportPosition(), UpdateViewportCoordinates().
252 struct ViewportData
: Viewport
{
253 VehicleID follow_vehicle
; ///< VehicleID to follow if following a vehicle, #INVALID_VEHICLE otherwise.
254 int32_t scrollpos_x
; ///< Currently shown x coordinate (virtual screen coordinate of topleft corner of the viewport).
255 int32_t scrollpos_y
; ///< Currently shown y coordinate (virtual screen coordinate of topleft corner of the viewport).
256 int32_t dest_scrollpos_x
; ///< Current destination x coordinate to display (virtual screen coordinate of topleft corner of the viewport).
257 int32_t dest_scrollpos_y
; ///< Current destination y coordinate to display (virtual screen coordinate of topleft corner of the viewport).
263 enum TooltipCloseCondition
{
271 * Data structure for an opened window
273 struct Window
: ZeroedMemoryAllocator
{
275 static std::vector
<Window
*> closed_windows
;
278 void InitializeData(WindowNumber window_number
);
279 void InitializePositionSize(int x
, int y
, int min_width
, int min_height
);
280 virtual void FindWindowPlacementAndResize(int def_width
, int def_height
);
282 std::vector
<int> scheduled_invalidation_data
; ///< Data of scheduled OnInvalidateData() calls.
283 bool scheduled_resize
; ///< Set if window has been resized.
285 /* Protected to prevent deletion anywhere outside Window::DeleteClosedWindows(). */
289 Window(WindowDesc
&desc
);
292 * Helper allocation function to disallow something.
293 * Don't allow arrays; arrays of Windows are pointless as you need
294 * to destruct them all at the same time too, which is kinda hard.
295 * @param size the amount of space not to allocate
297 inline void *operator new[](size_t size
) = delete;
299 WindowDesc
&window_desc
; ///< Window description
300 WindowFlags flags
; ///< Window flags
301 WindowClass window_class
; ///< Window class
302 WindowNumber window_number
; ///< Window number within the window class
304 int scale
; ///< Scale of this window -- used to determine how to resize.
306 uint8_t timeout_timer
; ///< Timer value of the WF_TIMEOUT for flags.
307 uint8_t white_border_timer
; ///< Timer value of the WF_WHITE_BORDER for flags.
309 int left
; ///< x position of left edge of the window
310 int top
; ///< y position of top edge of the window
311 int width
; ///< width of the window (number of pixels to the right in x direction)
312 int height
; ///< Height of the window (number of pixels down in y direction)
314 ResizeInfo resize
; ///< Resize information
316 Owner owner
; ///< The owner of the content shown in this window. Company colour is acquired from this variable.
318 ViewportData
*viewport
; ///< Pointer to viewport data, if present.
319 const NWidgetCore
*nested_focus
; ///< Currently focused nested widget, or \c nullptr if no nested widget has focus.
320 std::map
<WidgetID
, QueryString
*> querystrings
; ///< QueryString associated to WWT_EDITBOX widgets.
321 std::unique_ptr
<NWidgetBase
> nested_root
; ///< Root of the nested tree.
322 WidgetLookup widget_lookup
; ///< Indexed access to the nested widget tree. Do not access directly, use #Window::GetWidget() instead.
323 NWidgetStacked
*shade_select
; ///< Selection widget (#NWID_SELECTION) to use for shading the window. If \c nullptr, window cannot shade.
324 Dimension unshaded_size
; ///< Last known unshaded size (only valid while shaded).
326 WidgetID mouse_capture_widget
; ///< ID of current mouse capture widget (e.g. dragged scrollbar). -1 if no widget has mouse capture.
328 Window
*parent
; ///< Parent window.
329 WindowList::iterator z_position
;
331 template <class NWID
>
332 inline const NWID
*GetWidget(WidgetID widnum
) const;
333 template <class NWID
>
334 inline NWID
*GetWidget(WidgetID widnum
);
336 const Scrollbar
*GetScrollbar(WidgetID widnum
) const;
337 Scrollbar
*GetScrollbar(WidgetID widnum
);
339 const QueryString
*GetQueryString(WidgetID widnum
) const;
340 QueryString
*GetQueryString(WidgetID widnum
);
341 void UpdateQueryStringSize();
343 virtual const struct Textbuf
*GetFocusedTextbuf() const;
344 virtual Point
GetCaretPosition() const;
345 virtual Rect
GetTextBoundingRect(const char *from
, const char *to
) const;
346 virtual ptrdiff_t GetTextCharacterAtPosition(const Point
&pt
) const;
348 void InitNested(WindowNumber number
= 0);
349 void CreateNestedTree();
350 void FinishInitNested(WindowNumber window_number
= 0);
352 template<typename T
, std::enable_if_t
<std::is_base_of
<StrongTypedefBase
, T
>::value
, int> = 0>
353 void FinishInitNested(T number
)
355 this->FinishInitNested(number
.base());
359 * Set the timeout flag of the window and initiate the timer.
361 inline void SetTimeout()
363 this->flags
|= WF_TIMEOUT
;
364 this->timeout_timer
= TIMEOUT_DURATION
;
368 * Set the timeout flag of the window and initiate the timer.
370 inline void SetWhiteBorder()
372 this->flags
|= WF_WHITE_BORDER
;
373 this->white_border_timer
= WHITE_BORDER_DURATION
;
376 void DisableAllWidgetHighlight();
377 void SetWidgetHighlight(WidgetID widget_index
, TextColour highlighted_colour
);
378 bool IsWidgetHighlighted(WidgetID widget_index
) const;
381 * Sets the enabled/disabled status of a widget.
382 * By default, widgets are enabled.
383 * On certain conditions, they have to be disabled.
384 * @param widget_index index of this widget in the window
385 * @param disab_stat status to use ie: disabled = true, enabled = false
387 inline void SetWidgetDisabledState(WidgetID widget_index
, bool disab_stat
)
389 NWidgetCore
*nwid
= this->GetWidget
<NWidgetCore
>(widget_index
);
390 if (nwid
!= nullptr) nwid
->SetDisabled(disab_stat
);
394 * Sets a widget to disabled.
395 * @param widget_index index of this widget in the window
397 inline void DisableWidget(WidgetID widget_index
)
399 SetWidgetDisabledState(widget_index
, true);
403 * Sets a widget to Enabled.
404 * @param widget_index index of this widget in the window
406 inline void EnableWidget(WidgetID widget_index
)
408 SetWidgetDisabledState(widget_index
, false);
412 * Gets the enabled/disabled status of a widget.
413 * @param widget_index index of this widget in the window
414 * @return status of the widget ie: disabled = true, enabled = false
416 inline bool IsWidgetDisabled(WidgetID widget_index
) const
418 return this->GetWidget
<NWidgetCore
>(widget_index
)->IsDisabled();
422 * Check if given widget is focused within this window
423 * @param widget_index : index of the widget in the window to check
424 * @return true if given widget is the focused window in this window
426 inline bool IsWidgetFocused(WidgetID widget_index
) const
428 return this->nested_focus
!= nullptr && this->nested_focus
->index
== widget_index
;
432 * Check if given widget has user input focus. This means that both the window
433 * has focus and that the given widget has focus within the window.
434 * @param widget_index : index of the widget in the window to check
435 * @return true if given widget is the focused window in this window and this window has focus
437 inline bool IsWidgetGloballyFocused(WidgetID widget_index
) const
439 return _focused_window
== this && IsWidgetFocused(widget_index
);
443 * Sets the lowered/raised status of a widget.
444 * @param widget_index index of this widget in the window
445 * @param lowered_stat status to use ie: lowered = true, raised = false
447 inline void SetWidgetLoweredState(WidgetID widget_index
, bool lowered_stat
)
449 this->GetWidget
<NWidgetCore
>(widget_index
)->SetLowered(lowered_stat
);
453 * Invert the lowered/raised status of a widget.
454 * @param widget_index index of this widget in the window
456 inline void ToggleWidgetLoweredState(WidgetID widget_index
)
458 bool lowered_state
= this->GetWidget
<NWidgetCore
>(widget_index
)->IsLowered();
459 this->GetWidget
<NWidgetCore
>(widget_index
)->SetLowered(!lowered_state
);
463 * Marks a widget as lowered.
464 * @param widget_index index of this widget in the window
466 inline void LowerWidget(WidgetID widget_index
)
468 SetWidgetLoweredState(widget_index
, true);
472 * Marks a widget as raised.
473 * @param widget_index index of this widget in the window
475 inline void RaiseWidget(WidgetID widget_index
)
477 SetWidgetLoweredState(widget_index
, false);
481 * Marks a widget as raised and dirty (redraw), when it is marked as lowered.
482 * @param widget_index index of this widget in the window
484 inline void RaiseWidgetWhenLowered(WidgetID widget_index
)
486 if (this->IsWidgetLowered(widget_index
)) {
487 this->RaiseWidget(widget_index
);
488 this->SetWidgetDirty(widget_index
);
493 * Gets the lowered state of a widget.
494 * @param widget_index index of this widget in the window
495 * @return status of the widget ie: lowered = true, raised= false
497 inline bool IsWidgetLowered(WidgetID widget_index
) const
499 return this->GetWidget
<NWidgetCore
>(widget_index
)->IsLowered();
502 void UnfocusFocusedWidget();
503 bool SetFocusedWidget(WidgetID widget_index
);
505 EventState
HandleEditBoxKey(WidgetID wid
, char32_t key
, uint16_t keycode
);
506 virtual void InsertTextString(WidgetID wid
, const char *str
, bool marked
, const char *caret
, const char *insert_location
, const char *replacement_end
);
508 void HandleButtonClick(WidgetID widget
);
509 int GetRowFromWidget(int clickpos
, WidgetID widget
, int padding
, int line_height
= -1) const;
511 void RaiseButtons(bool autoraise
= false);
514 * Sets the enabled/disabled status of a list of widgets.
515 * By default, widgets are enabled.
516 * On certain conditions, they have to be disabled.
517 * @param disab_stat status to use ie: disabled = true, enabled = false
518 * @param widgets list of widgets
520 template<typename
... Args
>
521 void SetWidgetsDisabledState(bool disab_stat
, Args
... widgets
)
523 (SetWidgetDisabledState(widgets
, disab_stat
), ...);
527 * Sets the lowered/raised status of a list of widgets.
528 * @param lowered_stat status to use ie: lowered = true, raised = false
529 * @param widgets list of widgets
531 template<typename
... Args
>
532 void SetWidgetsLoweredState(bool lowered_stat
, Args
... widgets
)
534 (SetWidgetLoweredState(widgets
, lowered_stat
), ...);
538 * Raises the widgets and sets widgets dirty that are lowered.
539 * @param widgets list of widgets
541 template<typename
... Args
>
542 void RaiseWidgetsWhenLowered(Args
... widgets
)
544 (this->RaiseWidgetWhenLowered(widgets
), ...);
547 void SetWidgetDirty(WidgetID widget_index
) const;
549 void DrawWidgets() const;
550 void DrawViewport() const;
551 void DrawSortButtonState(WidgetID widget
, SortButtonState state
) const;
552 static int SortButtonWidth();
554 Window
*FindChildWindow(WindowClass wc
= WC_INVALID
) const;
555 void CloseChildWindows(WindowClass wc
= WC_INVALID
) const;
556 virtual void Close(int data
= 0);
557 static void DeleteClosedWindows();
559 void SetDirty() const;
560 void ReInit(int rx
= 0, int ry
= 0, bool reposition
= false);
562 /** Is window shaded currently? */
563 inline bool IsShaded() const
565 return this->shade_select
!= nullptr && this->shade_select
->shown_plane
== SZSP_HORIZONTAL
;
568 void SetShaded(bool make_shaded
);
570 void ScheduleResize();
571 void ProcessScheduledResize();
572 void InvalidateData(int data
= 0, bool gui_scope
= true);
573 void ProcessScheduledInvalidations();
574 void ProcessHighlightedInvalidations();
576 /*** Event handling ***/
579 * Notification that the nested widget tree gets initialized. The event can be used to perform general computations.
580 * @note #nested_root and/or #widget_lookup (normally accessed via #GetWidget()) may not exist during this call.
582 virtual void OnInit() { }
584 virtual void ApplyDefaults();
587 * Compute the initial position of the window.
588 * @param sm_width Smallest width of the window.
589 * @param sm_height Smallest height of the window.
590 * @param window_number The window number of the new window.
591 * @return Initial position of the top-left corner of the window.
593 virtual Point
OnInitialPosition(int16_t sm_width
, int16_t sm_height
, int window_number
);
596 * The window must be repainted.
597 * @note This method should not change any state, it should only use drawing functions.
599 virtual void OnPaint()
605 * Draw the contents of a nested widget.
606 * @param r Rectangle occupied by the widget.
607 * @param widget Number of the widget to draw.
608 * @note This method may not change any state, it may only use drawing functions.
610 virtual void DrawWidget([[maybe_unused
]] const Rect
&r
, [[maybe_unused
]] WidgetID widget
) const {}
613 * Update size and resize step of a widget in the window.
614 * After retrieval of the minimal size and the resize-steps of a widget, this function is called to allow further refinement,
615 * typically by computing the real maximal size of the content. Afterwards, \a size is taken to be the minimal size of the widget
616 * and \a resize is taken to contain the resize steps. For the convenience of the callee, \a padding contains the amount of
617 * padding between the content and the edge of the widget. This should be added to the returned size.
618 * @param widget Widget number.
619 * @param[in,out] size Size of the widget.
620 * @param padding Recommended amount of space between the widget content and the widget edge.
621 * @param[in,out] fill Fill step of the widget.
622 * @param[in,out] resize Resize step of the widget.
624 virtual void UpdateWidgetSize([[maybe_unused
]] WidgetID widget
, [[maybe_unused
]] Dimension
&size
, [[maybe_unused
]] const Dimension
&padding
, [[maybe_unused
]] Dimension
&fill
, [[maybe_unused
]] Dimension
&resize
) {}
627 * Initialize string parameters for a widget.
628 * Calls to this function are made during initialization to measure the size (that is as part of #InitNested()), during drawing,
629 * and while re-initializing the window. Only for widgets that render text initializing is requested.
630 * @param widget Widget number.
632 virtual void SetStringParameters([[maybe_unused
]] WidgetID widget
) const {}
635 * The window has gained focus.
637 virtual void OnFocus();
640 * The window has lost focus.
641 * @param closing True iff the window has lost focus in the process of closing.
643 virtual void OnFocusLost(bool closing
);
646 * A key has been pressed.
647 * @param key the Unicode value of the key.
648 * @param keycode the untranslated key code including shift state.
649 * @return #ES_HANDLED if the key press has been handled and no other
650 * window should receive the event.
652 virtual EventState
OnKeyPress([[maybe_unused
]] char32_t key
, [[maybe_unused
]] uint16_t keycode
) { return ES_NOT_HANDLED
; }
654 virtual EventState
OnHotkey(int hotkey
);
657 * The state of the control key has changed
658 * @return #ES_HANDLED if the change has been handled and no other
659 * window should receive the event.
661 virtual EventState
OnCTRLStateChange() { return ES_NOT_HANDLED
; }
665 * A click with the left mouse button has been made on the window.
666 * @param pt the point inside the window that has been clicked.
667 * @param widget the clicked widget.
668 * @param click_count Number of fast consecutive clicks at same position
670 virtual void OnClick([[maybe_unused
]] Point pt
, [[maybe_unused
]] WidgetID widget
, [[maybe_unused
]] int click_count
) {}
673 * A click with the right mouse button has been made on the window.
674 * @param pt the point inside the window that has been clicked.
675 * @param widget the clicked widget.
676 * @return true if the click was actually handled, i.e. do not show a
677 * tooltip if tooltip-on-right-click is enabled.
679 virtual bool OnRightClick([[maybe_unused
]] Point pt
, [[maybe_unused
]] WidgetID widget
) { return false; }
682 * The mouse is hovering over a widget in the window, perform an action for it.
683 * @param pt The point where the mouse is hovering.
684 * @param widget The widget where the mouse is hovering.
686 virtual void OnHover([[maybe_unused
]] Point pt
, [[maybe_unused
]] WidgetID widget
) {}
689 * Event to display a custom tooltip.
690 * @param pt The point where the mouse is located.
691 * @param widget The widget where the mouse is located.
692 * @return True if the event is handled, false if it is ignored.
694 virtual bool OnTooltip([[maybe_unused
]] Point pt
, [[maybe_unused
]] WidgetID widget
, [[maybe_unused
]] TooltipCloseCondition close_cond
) { return false; }
697 * An 'object' is being dragged at the provided position, highlight the target if possible.
698 * @param pt The point inside the window that the mouse hovers over.
699 * @param widget The widget the mouse hovers over.
701 virtual void OnMouseDrag([[maybe_unused
]] Point pt
, [[maybe_unused
]] WidgetID widget
) {}
704 * A dragged 'object' has been released.
705 * @param pt the point inside the window where the release took place.
706 * @param widget the widget where the release took place.
708 virtual void OnDragDrop([[maybe_unused
]] Point pt
, [[maybe_unused
]] WidgetID widget
) {}
711 * Handle the request for (viewport) scrolling.
712 * @param delta the amount the viewport must be scrolled.
714 virtual void OnScroll([[maybe_unused
]] Point delta
) {}
717 * The mouse is currently moving over the window or has just moved outside
718 * of the window. In the latter case pt is (-1, -1).
719 * @param pt the point inside the window that the mouse hovers over.
720 * @param widget the widget the mouse hovers over.
722 virtual void OnMouseOver([[maybe_unused
]] Point pt
, [[maybe_unused
]] WidgetID widget
) {}
725 * The mouse wheel has been turned.
726 * @param wheel the amount of movement of the mouse wheel.
728 virtual void OnMouseWheel([[maybe_unused
]] int wheel
) {}
732 * Called for every mouse loop run, which is at least once per (game) tick.
734 virtual void OnMouseLoop() {}
737 * Called once per (game) tick.
739 virtual void OnGameTick() {}
742 * Called periodically.
744 virtual void OnRealtimeTick([[maybe_unused
]] uint delta_ms
) {}
747 * Called when this window's timeout has been reached.
749 virtual void OnTimeout() {}
753 * Called after the window got resized.
754 * For nested windows with a viewport, call NWidgetViewport::UpdateViewportCoordinates.
756 virtual void OnResize() {}
759 * A dropdown option associated to this window has been selected.
760 * @param widget the widget (button) that the dropdown is associated with.
761 * @param index the element in the dropdown that is selected.
763 virtual void OnDropdownSelect([[maybe_unused
]] WidgetID widget
, [[maybe_unused
]] int index
) {}
765 virtual void OnDropdownClose(Point pt
, WidgetID widget
, int index
, bool instant_close
);
768 * The text in an editbox has been edited.
769 * @param widget The widget of the editbox.
771 virtual void OnEditboxChanged([[maybe_unused
]] WidgetID widget
) {}
774 * The query window opened from this window has closed.
775 * @param str the new value of the string, \c std::nullopt if the window
776 * was cancelled or an empty string when the default
777 * button was pressed, i.e. \c str->empty().
779 virtual void OnQueryTextFinished([[maybe_unused
]] std::optional
<std::string
> str
) {}
782 * Some data on this window has become invalid.
783 * @param data information about the changed data.
784 * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
786 virtual void OnInvalidateData([[maybe_unused
]] int data
= 0, [[maybe_unused
]] bool gui_scope
= true) {}
789 * The user clicked some place on the map when a tile highlight mode
791 * @param pt the exact point on the map that has been clicked.
792 * @param tile the tile on the map that has been clicked.
794 virtual void OnPlaceObject([[maybe_unused
]] Point pt
, [[maybe_unused
]] TileIndex tile
) {}
797 * The user clicked on a vehicle while HT_VEHICLE has been set.
798 * @param v clicked vehicle
799 * @return true if the click is handled, false if it is ignored
800 * @pre v->IsPrimaryVehicle() == true
802 virtual bool OnVehicleSelect([[maybe_unused
]] const struct Vehicle
*v
) { return false; }
805 * The user clicked on a vehicle while HT_VEHICLE has been set.
806 * @param v clicked vehicle
807 * @return True if the click is handled, false if it is ignored
808 * @pre v->IsPrimaryVehicle() == true
810 virtual bool OnVehicleSelect([[maybe_unused
]] VehicleList::const_iterator begin
, [[maybe_unused
]] VehicleList::const_iterator end
) { return false; }
813 * The user cancelled a tile highlight mode that has been set.
815 virtual void OnPlaceObjectAbort() {}
819 * The user is dragging over the map when the tile highlight mode
821 * @param select_method the method of selection (allowed directions)
822 * @param select_proc what will be created when the drag is over.
823 * @param pt the exact point on the map where the mouse is.
825 virtual void OnPlaceDrag([[maybe_unused
]] ViewportPlaceMethod select_method
, [[maybe_unused
]] ViewportDragDropSelectionProcess select_proc
, [[maybe_unused
]] Point pt
) {}
828 * The user has dragged over the map when the tile highlight mode
830 * @param select_method the method of selection (allowed directions)
831 * @param select_proc what should be created.
832 * @param pt the exact point on the map where the mouse was released.
833 * @param start_tile the begin tile of the drag.
834 * @param end_tile the end tile of the drag.
836 virtual void OnPlaceMouseUp([[maybe_unused
]] ViewportPlaceMethod select_method
, [[maybe_unused
]] ViewportDragDropSelectionProcess select_proc
, [[maybe_unused
]] Point pt
, [[maybe_unused
]] TileIndex start_tile
, [[maybe_unused
]] TileIndex end_tile
) {}
839 * The user moves over the map when a tile highlight mode has been set
840 * when the special mouse mode has been set to 'PRESIZE' mode. An
841 * example of this is the tile highlight for dock building.
842 * @param pt the exact point on the map where the mouse is.
843 * @param tile the tile on the map where the mouse is.
845 virtual void OnPlacePresize([[maybe_unused
]] Point pt
, [[maybe_unused
]] TileIndex tile
) {}
847 /*** End of the event handling ***/
850 * Is the data related to this window NewGRF inspectable?
851 * @return true iff it is inspectable.
853 virtual bool IsNewGRFInspectable() const { return false; }
856 * Show the NewGRF inspection window. When this function is called it is
857 * up to the window to call and pass the right parameters to the
858 * ShowInspectWindow function.
859 * @pre this->IsNewGRFInspectable()
861 virtual void ShowNewGRFInspectWindow() const { NOT_REACHED(); }
864 * Iterator to iterate all valid Windows
865 * @tparam TtoBack whether we iterate towards the back.
867 template <bool TtoBack
>
868 struct WindowIterator
{
869 typedef Window
*value_type
;
870 typedef value_type
*pointer
;
871 typedef value_type
&reference
;
872 typedef size_t difference_type
;
873 typedef std::forward_iterator_tag iterator_category
;
875 explicit WindowIterator(WindowList::iterator start
) : it(start
)
879 explicit WindowIterator(const Window
*w
) : it(w
->z_position
) {}
881 bool operator==(const WindowIterator
&other
) const { return this->it
== other
.it
; }
882 bool operator!=(const WindowIterator
&other
) const { return !(*this == other
); }
883 Window
* operator*() const { return *this->it
; }
884 WindowIterator
& operator++() { this->Next(); this->Validate(); return *this; }
886 bool IsEnd() const { return this->it
== _z_windows
.end(); }
889 WindowList::iterator it
;
892 while (!this->IsEnd() && *this->it
== nullptr) this->Next();
896 if constexpr (!TtoBack
) {
898 } else if (this->it
== _z_windows
.begin()) {
899 this->it
= _z_windows
.end();
905 using IteratorToFront
= WindowIterator
<false>; //!< Iterate in Z order towards front.
906 using IteratorToBack
= WindowIterator
<true>; //!< Iterate in Z order towards back.
909 * Iterable ensemble of all valid Windows
910 * @tparam Tfront Wether we iterate from front
912 template <bool Tfront
>
915 WindowIterator
<Tfront
> begin()
917 if constexpr (Tfront
) {
918 auto back
= _z_windows
.end();
919 if (back
!= _z_windows
.begin()) --back
;
920 return WindowIterator
<Tfront
>(back
);
922 return WindowIterator
<Tfront
>(_z_windows
.begin());
925 WindowIterator
<Tfront
> end() { return WindowIterator
<Tfront
>(_z_windows
.end()); }
927 using Iterate
= AllWindows
<false>; //!< Iterate all windows in whatever order is easiest.
928 using IterateFromBack
= AllWindows
<false>; //!< Iterate all windows in Z order from back to front.
929 using IterateFromFront
= AllWindows
<true>; //!< Iterate all windows in Z order from front to back.
933 * Generic helper function that checks if all elements of the range are equal with respect to the given predicate.
934 * @param begin The start of the range.
935 * @param end The end of the range.
936 * @param pred The predicate to use.
937 * @return True if all elements are equal, false otherwise.
939 template <class It
, class Pred
>
940 inline bool AllEqual(It begin
, It end
, Pred pred
)
942 return std::adjacent_find(begin
, end
, std::not_fn(pred
)) == end
;
946 * Get the nested widget with number \a widnum from the nested widget tree.
947 * @tparam NWID Type of the nested widget.
948 * @param widnum Widget number of the widget to retrieve.
949 * @return The requested widget if it is instantiated, \c nullptr otherwise.
951 template <class NWID
>
952 inline NWID
*Window::GetWidget(WidgetID widnum
)
954 auto it
= this->widget_lookup
.find(widnum
);
955 if (it
== std::end(this->widget_lookup
)) return nullptr;
956 NWID
*nwid
= dynamic_cast<NWID
*>(it
->second
);
957 assert(nwid
!= nullptr);
961 /** Specialized case of #Window::GetWidget for the nested widget base class. */
963 inline const NWidgetBase
*Window::GetWidget
<NWidgetBase
>(WidgetID widnum
) const
965 auto it
= this->widget_lookup
.find(widnum
);
966 if (it
== std::end(this->widget_lookup
)) return nullptr;
971 * Get the nested widget with number \a widnum from the nested widget tree.
972 * @tparam NWID Type of the nested widget.
973 * @param widnum Widget number of the widget to retrieve.
974 * @return The requested widget if it is instantiated, \c nullptr otherwise.
976 template <class NWID
>
977 inline const NWID
*Window::GetWidget(WidgetID widnum
) const
979 return const_cast<Window
*>(this)->GetWidget
<NWID
>(widnum
);
984 * Base class for windows opened from a toolbar.
986 class PickerWindowBase
: public Window
{
989 PickerWindowBase(WindowDesc
&desc
, Window
*parent
) : Window(desc
)
991 this->parent
= parent
;
994 void Close([[maybe_unused
]] int data
= 0) override
;
997 Window
*BringWindowToFrontById(WindowClass cls
, WindowNumber number
);
998 Window
*FindWindowFromPt(int x
, int y
);
1000 template<typename T
, std::enable_if_t
<std::is_base_of
<StrongTypedefBase
, T
>::value
, int> = 0>
1001 Window
*BringWindowToFrontById(WindowClass cls
, T number
)
1003 return BringWindowToFrontById(cls
, number
.base());
1007 * Open a new window.
1008 * @tparam Wcls %Window class to use if the window does not exist.
1009 * @param desc The pointer to the WindowDesc to be created
1010 * @param window_number the window number of the new window
1011 * @param return_existing If set, also return the window if it already existed.
1012 * @return %Window pointer of the newly created window, or the existing one if \a return_existing is set, or \c nullptr.
1014 template <typename Wcls
>
1015 Wcls
*AllocateWindowDescFront(WindowDesc
&desc
, int window_number
, bool return_existing
= false)
1017 Wcls
*w
= static_cast<Wcls
*>(BringWindowToFrontById(desc
.cls
, window_number
));
1018 if (w
!= nullptr) return return_existing
? w
: nullptr;
1019 return new Wcls(desc
, window_number
);
1022 void RelocateAllWindows(int neww
, int newh
);
1024 void GuiShowTooltips(Window
*parent
, StringID str
, TooltipCloseCondition close_tooltip
, uint paramcount
= 0);
1027 WidgetID
GetWidgetFromPos(const Window
*w
, int x
, int y
);
1029 extern Point _cursorpos_drag_start
;
1031 extern int _scrollbar_start_pos
;
1032 extern int _scrollbar_size
;
1033 extern uint8_t _scroller_click_timeout
;
1035 extern bool _scrolling_viewport
;
1036 extern bool _mouse_hovering
;
1039 enum SpecialMouseMode
{
1040 WSM_NONE
, ///< No special mouse mode.
1041 WSM_DRAGDROP
, ///< Drag&drop an object.
1042 WSM_SIZING
, ///< Sizing mode.
1043 WSM_PRESIZE
, ///< Presizing mode (docks, tunnels).
1044 WSM_DRAGGING
, ///< Dragging mode (trees).
1046 extern SpecialMouseMode _special_mouse_mode
;
1048 void SetFocusedWindow(Window
*w
);
1050 void ScrollbarClickHandler(Window
*w
, NWidgetCore
*nw
, int x
, int y
);
1051 Rect
ScrollRect(Rect r
, const Scrollbar
&sb
, int resize_step
= 1);
1053 #endif /* WINDOW_GUI_H */