OpenTTD Source 20250312-master-gcdcc6b491d
window.cpp
Go to the documentation of this file.
1/*
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/>.
6 */
7
10#include "stdafx.h"
11#include "company_func.h"
12#include "gfx_func.h"
13#include "console_func.h"
14#include "console_gui.h"
15#include "viewport_func.h"
16#include "progress.h"
17#include "blitter/factory.hpp"
18#include "zoom_func.h"
19#include "vehicle_base.h"
20#include "depot_func.h"
21#include "window_func.h"
22#include "tilehighlight_func.h"
23#include "network/network.h"
24#include "querystring_gui.h"
25#include "strings_func.h"
26#include "settings_type.h"
27#include "settings_func.h"
28#include "ini_type.h"
29#include "newgrf_debug.h"
30#include "hotkeys.h"
31#include "toolbar_gui.h"
32#include "statusbar_gui.h"
33#include "error.h"
34#include "game/game.hpp"
36#include "framerate_type.h"
38#include "news_func.h"
39#include "timer/timer.h"
40#include "timer/timer_window.h"
41
42#include "safeguards.h"
43
51
53static Window *_mouseover_last_w = nullptr;
54static Window *_last_scroll_window = nullptr;
55
57WindowList _z_windows;
58
60/* static */ std::vector<Window *> Window::closed_windows;
61
65/* static */ void Window::DeleteClosedWindows()
66{
67 for (Window *w : Window::closed_windows) delete w;
69
70 /* Remove dead entries from the window list */
71 _z_windows.remove(nullptr);
72}
73
76
77/*
78 * Window that currently has focus. - The main purpose is to generate
79 * #FocusLost events, not to give next window in z-order focus when a
80 * window is closed.
81 */
82Window *_focused_window;
83
84Point _cursorpos_drag_start;
85
86int _scrollbar_start_pos;
87int _scrollbar_size;
88uint8_t _scroller_click_timeout = 0;
89
92
94
99std::vector<WindowDesc*> *_window_descs = nullptr;
100
102std::string _windows_file;
103
105WindowDesc::WindowDesc(WindowPosition def_pos, const char *ini_key, int16_t def_width_trad, int16_t def_height_trad,
106 WindowClass window_class, WindowClass parent_class, WindowDefaultFlags flags,
107 const std::span<const NWidgetPart> nwid_parts, HotkeyList *hotkeys,
108 const std::source_location location) :
109 source_location(location),
110 default_pos(def_pos),
111 cls(window_class),
112 parent_cls(parent_class),
113 ini_key(ini_key),
114 flags(flags),
115 nwid_parts(nwid_parts),
116 hotkeys(hotkeys),
117 default_width_trad(def_width_trad),
118 default_height_trad(def_height_trad)
119{
120 if (_window_descs == nullptr) _window_descs = new std::vector<WindowDesc*>();
121 _window_descs->push_back(this);
122}
123
124WindowDesc::~WindowDesc()
125{
126 _window_descs->erase(std::ranges::find(*_window_descs, this));
127}
128
135{
136 return this->pref_width != 0 ? this->pref_width : ScaleGUITrad(this->default_width_trad);
137}
138
145{
146 return this->pref_height != 0 ? this->pref_height : ScaleGUITrad(this->default_height_trad);
147}
148
153{
154 IniFile ini;
156 for (WindowDesc *wd : *_window_descs) {
157 if (wd->ini_key == nullptr) continue;
158 IniLoadWindowSettings(ini, wd->ini_key, wd);
159 }
160}
161
165static bool DescSorter(WindowDesc * const &a, WindowDesc * const &b)
166{
167 if (a->ini_key != nullptr && b->ini_key != nullptr) return strcmp(a->ini_key, b->ini_key) < 0;
168 return a->ini_key != nullptr;
169}
170
175{
176 /* Sort the stuff to get a nice ini file on first write */
177 std::sort(_window_descs->begin(), _window_descs->end(), DescSorter);
178
179 IniFile ini;
181 for (WindowDesc *wd : *_window_descs) {
182 if (wd->ini_key == nullptr) continue;
183 IniSaveWindowSettings(ini, wd->ini_key, wd);
184 }
186}
187
192{
193 if (this->nested_root != nullptr && this->nested_root->GetWidgetOfType(WWT_STICKYBOX) != nullptr) {
195 } else {
196 /* There is no stickybox; clear the preference in case someone tried to be funny */
197 this->window_desc.pref_sticky = false;
198 }
199}
200
210int Window::GetRowFromWidget(int clickpos, WidgetID widget, int padding, int line_height) const
211{
212 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(widget);
213 if (line_height < 0) line_height = wid->resize_y;
214 if (clickpos < wid->pos_y + padding) return INT_MAX;
215 return (clickpos - wid->pos_y - padding) / line_height;
216}
217
222{
223 for (auto &pair : this->widget_lookup) {
224 NWidgetBase *nwid = pair.second;
225 if (nwid->IsHighlighted()) {
226 nwid->SetHighlighted(TC_INVALID);
227 nwid->SetDirty(this);
228 }
229 }
230
232}
233
239void Window::SetWidgetHighlight(WidgetID widget_index, TextColour highlighted_colour)
240{
241 NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget_index);
242 if (nwid == nullptr) return;
243
244 nwid->SetHighlighted(highlighted_colour);
245 nwid->SetDirty(this);
246
247 if (highlighted_colour != TC_INVALID) {
248 /* If we set a highlight, the window has a highlight */
250 } else {
251 /* If we disable a highlight, check all widgets if anyone still has a highlight */
252 bool valid = false;
253 for (const auto &pair : this->widget_lookup) {
254 nwid = pair.second;
255 if (!nwid->IsHighlighted()) continue;
256
257 valid = true;
258 }
259 /* If nobody has a highlight, disable the flag on the window */
261 }
262}
263
269bool Window::IsWidgetHighlighted(WidgetID widget_index) const
270{
271 const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget_index);
272 if (nwid == nullptr) return false;
273
274 return nwid->IsHighlighted();
275}
276
284void Window::OnDropdownClose(Point pt, WidgetID widget, int index, bool instant_close)
285{
286 if (widget < 0) return;
287
288 if (instant_close) {
289 /* Send event for selected option if we're still
290 * on the parent button of the dropdown (behaviour of the dropdowns in the main toolbar). */
291 if (GetWidgetFromPos(this, pt.x, pt.y) == widget) {
292 this->OnDropdownSelect(widget, index);
293 }
294 }
295
296 /* Raise the dropdown button */
297 NWidgetCore *nwi2 = this->GetWidget<NWidgetCore>(widget);
298 if ((nwi2->type & WWT_MASK) == NWID_BUTTON_DROPDOWN) {
299 nwi2->disp_flags.Reset(NWidgetDisplayFlag::DropdownActive);
300 } else {
301 this->RaiseWidget(widget);
302 }
303 this->SetWidgetDirty(widget);
304}
305
312{
313 return this->GetWidget<NWidgetScrollbar>(widnum);
314}
315
322{
323 return this->GetWidget<NWidgetScrollbar>(widnum);
324}
325
332{
333 auto query = this->querystrings.find(widnum);
334 return query != this->querystrings.end() ? query->second : nullptr;
335}
336
343{
344 auto query = this->querystrings.find(widnum);
345 return query != this->querystrings.end() ? query->second : nullptr;
346}
347
352{
353 for (auto &qs : this->querystrings) {
354 qs.second->text.UpdateSize();
355 }
356}
357
362/* virtual */ const Textbuf *Window::GetFocusedTextbuf() const
363{
364 if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX) {
365 return &this->GetQueryString(this->nested_focus->GetIndex())->text;
366 }
367
368 return nullptr;
369}
370
375/* virtual */ Point Window::GetCaretPosition() const
376{
377 if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX && !this->querystrings.empty()) {
378 return this->GetQueryString(this->nested_focus->GetIndex())->GetCaretPosition(this, this->nested_focus->GetIndex());
379 }
380
381 Point pt = {0, 0};
382 return pt;
383}
384
391/* virtual */ Rect Window::GetTextBoundingRect(const char *from, const char *to) const
392{
393 if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX) {
394 return this->GetQueryString(this->nested_focus->GetIndex())->GetBoundingRect(this, this->nested_focus->GetIndex(), from, to);
395 }
396
397 Rect r = {0, 0, 0, 0};
398 return r;
399}
400
406/* virtual */ ptrdiff_t Window::GetTextCharacterAtPosition(const Point &pt) const
407{
408 if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX) {
409 return this->GetQueryString(this->nested_focus->GetIndex())->GetCharAtPosition(this, this->nested_focus->GetIndex(), pt);
410 }
411
412 return -1;
413}
414
420{
421 if (_focused_window == w) return;
422
423 /* Don't focus a tooltip */
424 if (w != nullptr && w->window_class == WC_TOOLTIPS) return;
425
426 /* Invalidate focused widget */
427 if (_focused_window != nullptr) {
428 if (_focused_window->nested_focus != nullptr) _focused_window->nested_focus->SetDirty(_focused_window);
429 }
430
431 /* Remember which window was previously focused */
432 Window *old_focused = _focused_window;
433 _focused_window = w;
434
435 /* So we can inform it that it lost focus */
436 if (old_focused != nullptr) old_focused->OnFocusLost(false);
437 if (_focused_window != nullptr) _focused_window->OnFocus();
438}
439
446{
447 if (_focused_window == nullptr) return false;
448
449 /* The console does not have an edit box so a special case is needed. */
450 if (_focused_window->window_class == WC_CONSOLE) return true;
451
452 return _focused_window->nested_focus != nullptr && _focused_window->nested_focus->type == WWT_EDITBOX;
453}
454
460{
461 return _focused_window && _focused_window->window_class == WC_CONSOLE;
462}
463
468{
469 if (this->nested_focus != nullptr) {
471
472 /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */
473 this->nested_focus->SetDirty(this);
474 this->nested_focus = nullptr;
475 }
476}
477
484{
485 NWidgetCore *widget = this->GetWidget<NWidgetCore>(widget_index);
486 assert(widget != nullptr); /* Setting focus to a non-existing widget is a bad idea. */
487
488 if (this->nested_focus != nullptr) {
489 /* Do nothing if widget_index is already focused. */
490 if (widget == this->nested_focus) return false;
491
492 /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */
493 this->nested_focus->SetDirty(this);
495 }
496
497 this->nested_focus = widget;
499 return true;
500}
501
502std::string Window::GetWidgetString([[maybe_unused]] WidgetID widget, StringID stringid) const
503{
504 if (stringid == STR_NULL) return {};
505 return GetString(stringid);
506}
507
512{
514}
515
520{
522}
523
528void Window::RaiseButtons(bool autoraise)
529{
530 for (auto &pair : this->widget_lookup) {
531 WidgetType type = pair.second->type;
532 NWidgetCore *wid = dynamic_cast<NWidgetCore *>(pair.second);
533 if (wid != nullptr && ((type & ~WWB_PUSHBUTTON) < WWT_LAST || type == NWID_PUSHBUTTON_DROPDOWN) &&
534 (!autoraise || (type & WWB_PUSHBUTTON) || type == WWT_EDITBOX) && wid->IsLowered()) {
535 wid->SetLowered(false);
536 wid->SetDirty(this);
537 }
538 }
539
540 /* Special widgets without widget index */
541 {
542 NWidgetCore *wid = this->nested_root != nullptr ? dynamic_cast<NWidgetCore *>(this->nested_root->GetWidgetOfType(WWT_DEFSIZEBOX)) : nullptr;
543 if (wid != nullptr) {
544 wid->SetLowered(false);
545 wid->SetDirty(this);
546 }
547 }
548}
549
554void Window::SetWidgetDirty(WidgetID widget_index) const
555{
556 /* Sometimes this function is called before the window is even fully initialized */
557 auto it = this->widget_lookup.find(widget_index);
558 if (it == std::end(this->widget_lookup)) return;
559
560 it->second->SetDirty(this);
561}
562
569{
570 if (hotkey < 0) return ES_NOT_HANDLED;
571
572 NWidgetCore *nw = this->GetWidget<NWidgetCore>(hotkey);
573 if (nw == nullptr || nw->IsDisabled()) return ES_NOT_HANDLED;
574
575 if (nw->type == WWT_EDITBOX) {
576 if (this->IsShaded()) return ES_NOT_HANDLED;
577
578 /* Focus editbox */
579 this->SetFocusedWidget(hotkey);
580 SetFocusedWindow(this);
581 } else {
582 /* Click button */
583 this->OnClick(Point(), hotkey, 1);
584 }
585 return ES_HANDLED;
586}
587
594{
595 this->LowerWidget(widget);
596 this->SetTimeout();
597 this->SetWidgetDirty(widget);
598}
599
600static void StartWindowDrag(Window *w);
601static void StartWindowSizing(Window *w, bool to_left);
602
610static void DispatchLeftClickEvent(Window *w, int x, int y, int click_count)
611{
612 NWidgetCore *nw = w->nested_root->GetWidgetFromPos(x, y);
613 WidgetType widget_type = (nw != nullptr) ? nw->type : WWT_EMPTY;
614
615 /* Allow dropdown close flag detection to work. */
617
618 bool focused_widget_changed = false;
619 /* If clicked on a window that previously did not have focus */
620 if (_focused_window != w && // We already have focus, right?
621 !w->window_desc.flags.Test(WindowDefaultFlag::NoFocus) && // Don't lose focus to toolbars
622 widget_type != WWT_CLOSEBOX) { // Don't change focused window if 'X' (close button) was clicked
623 focused_widget_changed = true;
625 }
626
627 if (nw == nullptr) return; // exit if clicked outside of widgets
628
629 /* don't allow any interaction if the button has been disabled */
630 if (nw->IsDisabled()) return;
631
632 WidgetID widget_index = nw->GetIndex();
633
634 /* Clicked on a widget that is not disabled.
635 * So unless the clicked widget is the caption bar, change focus to this widget.
636 * Exception: In the OSK we always want the editbox to stay focused. */
637 if (widget_index >= 0 && widget_type != WWT_CAPTION && w->window_class != WC_OSK) {
638 /* focused_widget_changed is 'now' only true if the window this widget
639 * is in gained focus. In that case it must remain true, also if the
640 * local widget focus did not change. As such it's the logical-or of
641 * both changed states.
642 *
643 * If this is not preserved, then the OSK window would be opened when
644 * a user has the edit box focused and then click on another window and
645 * then back again on the edit box (to type some text).
646 */
647 focused_widget_changed |= w->SetFocusedWidget(widget_index);
648 }
649
650 /* Dropdown window of this widget was closed so don't process click this time. */
652
653 if ((widget_type & ~WWB_PUSHBUTTON) < WWT_LAST && (widget_type & WWB_PUSHBUTTON)) w->HandleButtonClick(widget_index);
654
655 Point pt = { x, y };
656
657 switch (widget_type) {
658 case NWID_VSCROLLBAR:
659 case NWID_HSCROLLBAR:
660 ScrollbarClickHandler(w, nw, x, y);
661 break;
662
663 case WWT_EDITBOX: {
664 QueryString *query = w->GetQueryString(widget_index);
665 if (query != nullptr) query->ClickEditBox(w, pt, widget_index, click_count, focused_widget_changed);
666 break;
667 }
668
669 case WWT_CLOSEBOX: // 'X'
670 w->Close();
671 return;
672
673 case WWT_CAPTION: // 'Title bar'
675 return;
676
677 case WWT_RESIZEBOX:
678 /* When the resize widget is on the left size of the window
679 * we assume that that button is used to resize to the left. */
680 StartWindowSizing(w, nw->pos_x < (w->width / 2));
681 nw->SetDirty(w);
682 return;
683
684 case WWT_DEFSIZEBOX: {
685 if (_ctrl_pressed) {
688 } else {
689 int16_t def_width = std::max<int16_t>(std::min<int16_t>(w->window_desc.GetDefaultWidth(), _screen.width), w->nested_root->smallest_x);
690 int16_t def_height = std::max<int16_t>(std::min<int16_t>(w->window_desc.GetDefaultHeight(), _screen.height - 50), w->nested_root->smallest_y);
691
692 int dx = (w->resize.step_width == 0) ? 0 : def_width - w->width;
693 int dy = (w->resize.step_height == 0) ? 0 : def_height - w->height;
694 /* dx and dy has to go by step.. calculate it.
695 * The cast to int is necessary else dx/dy are implicitly casted to unsigned int, which won't work. */
696 if (w->resize.step_width > 1) dx -= dx % (int)w->resize.step_width;
697 if (w->resize.step_height > 1) dy -= dy % (int)w->resize.step_height;
698 ResizeWindow(w, dx, dy, false);
699 }
700
701 nw->SetLowered(true);
702 nw->SetDirty(w);
703 w->SetTimeout();
704 break;
705 }
706
707 case WWT_DEBUGBOX:
709 break;
710
711 case WWT_SHADEBOX:
712 nw->SetDirty(w);
713 w->SetShaded(!w->IsShaded());
714 return;
715
716 case WWT_STICKYBOX:
718 nw->SetDirty(w);
720 return;
721
722 default:
723 break;
724 }
725
726 /* Widget has no index, so the window is not interested in it. */
727 if (widget_index < 0) return;
728
729 /* Check if the widget is highlighted; if so, disable highlight and dispatch an event to the GameScript */
730 if (w->IsWidgetHighlighted(widget_index)) {
731 w->SetWidgetHighlight(widget_index, TC_INVALID);
732 Game::NewEvent(new ScriptEventWindowWidgetClick((ScriptWindow::WindowClass)w->window_class, w->window_number, widget_index));
733 }
734
735 w->OnClick(pt, widget_index, click_count);
736}
737
744static void DispatchRightClickEvent(Window *w, int x, int y)
745{
746 NWidgetCore *wid = w->nested_root->GetWidgetFromPos(x, y);
747 if (wid == nullptr) return;
748
749 Point pt = { x, y };
750
751 /* No widget to handle, or the window is not interested in it. */
752 if (wid->GetIndex() >= 0) {
753 if (w->OnRightClick(pt, wid->GetIndex())) return;
754 }
755
756 /* Right-click close is enabled and there is a closebox. */
758 w->Close();
760 /* Right-click close is enabled, but excluding sticky windows. */
761 w->Close();
762 } else if (_settings_client.gui.hover_delay_ms == 0 && !w->OnTooltip(pt, wid->GetIndex(), TCC_RIGHT_CLICK) && wid->GetToolTip() != STR_NULL) {
763 GuiShowTooltips(w, GetEncodedString(wid->GetToolTip()), TCC_RIGHT_CLICK);
764 }
765}
766
773static void DispatchHoverEvent(Window *w, int x, int y)
774{
775 NWidgetCore *wid = w->nested_root->GetWidgetFromPos(x, y);
776
777 /* No widget to handle */
778 if (wid == nullptr) return;
779
780 Point pt = { x, y };
781
782 /* Show the tooltip if there is any */
783 if (!w->OnTooltip(pt, wid->GetIndex(), TCC_HOVER) && wid->GetToolTip() != STR_NULL) {
784 GuiShowTooltips(w, GetEncodedString(wid->GetToolTip()), TCC_HOVER);
785 return;
786 }
787
788 /* Widget has no index, so the window is not interested in it. */
789 if (wid->GetIndex() < 0) return;
790
791 w->OnHover(pt, wid->GetIndex());
792}
793
801static void DispatchMouseWheelEvent(Window *w, NWidgetCore *nwid, int wheel)
802{
803 if (nwid == nullptr) return;
804
805 /* Using wheel on caption/shade-box shades or unshades the window. */
806 if (nwid->type == WWT_CAPTION || nwid->type == WWT_SHADEBOX) {
807 w->SetShaded(wheel < 0);
808 return;
809 }
810
811 /* Wheeling a vertical scrollbar. */
812 if (nwid->type == NWID_VSCROLLBAR) {
813 NWidgetScrollbar *sb = static_cast<NWidgetScrollbar *>(nwid);
814 if (sb->GetCount() > sb->GetCapacity()) {
815 if (sb->UpdatePosition(wheel)) w->SetDirty();
816 }
817 return;
818 }
819
820 /* Scroll the widget attached to the scrollbar. */
821 Scrollbar *sb = (nwid->GetScrollbarIndex() >= 0 ? w->GetScrollbar(nwid->GetScrollbarIndex()) : nullptr);
822 if (sb != nullptr && sb->GetCount() > sb->GetCapacity()) {
823 if (sb->UpdatePosition(wheel)) w->SetDirty();
824 }
825}
826
832static bool MayBeShown(const Window *w)
833{
834 /* If we're not modal, everything is okay. */
835 if (!HasModalProgress()) return true;
836
837 switch (w->window_class) {
838 case WC_MAIN_WINDOW:
839 case WC_MODAL_PROGRESS:
841 return true;
842
843 default:
844 return false;
845 }
846}
847
860static void DrawOverlappedWindow(Window *w, int left, int top, int right, int bottom)
861{
863 ++it;
864 for (; !it.IsEnd(); ++it) {
865 const Window *v = *it;
866 if (MayBeShown(v) &&
867 right > v->left &&
868 bottom > v->top &&
869 left < v->left + v->width &&
870 top < v->top + v->height) {
871 /* v and rectangle intersect with each other */
872 int x;
873
874 if (left < (x = v->left)) {
875 DrawOverlappedWindow(w, left, top, x, bottom);
876 DrawOverlappedWindow(w, x, top, right, bottom);
877 return;
878 }
879
880 if (right > (x = v->left + v->width)) {
881 DrawOverlappedWindow(w, left, top, x, bottom);
882 DrawOverlappedWindow(w, x, top, right, bottom);
883 return;
884 }
885
886 if (top < (x = v->top)) {
887 DrawOverlappedWindow(w, left, top, right, x);
888 DrawOverlappedWindow(w, left, x, right, bottom);
889 return;
890 }
891
892 if (bottom > (x = v->top + v->height)) {
893 DrawOverlappedWindow(w, left, top, right, x);
894 DrawOverlappedWindow(w, left, x, right, bottom);
895 return;
896 }
897
898 return;
899 }
900 }
901
902 /* Setup blitter, and dispatch a repaint event to window *wz */
903 DrawPixelInfo *dp = _cur_dpi;
904 dp->width = right - left;
905 dp->height = bottom - top;
906 dp->left = left - w->left;
907 dp->top = top - w->top;
908 dp->pitch = _screen.pitch;
909 dp->dst_ptr = BlitterFactory::GetCurrentBlitter()->MoveTo(_screen.dst_ptr, left, top);
910 dp->zoom = ZOOM_LVL_MIN;
911 w->OnPaint();
912}
913
922void DrawOverlappedWindowForAll(int left, int top, int right, int bottom)
923{
924 DrawPixelInfo bk;
925 AutoRestoreBackup dpi_backup(_cur_dpi, &bk);
926
927 for (Window *w : Window::IterateFromBack()) {
928 if (MayBeShown(w) &&
929 right > w->left &&
930 bottom > w->top &&
931 left < w->left + w->width &&
932 top < w->top + w->height) {
933 /* Window w intersects with the rectangle => needs repaint */
934 DrawOverlappedWindow(w, std::max(left, w->left), std::max(top, w->top), std::min(right, w->left + w->width), std::min(bottom, w->top + w->height));
935 }
936 }
937}
938
944{
945 AddDirtyBlock(this->left, this->top, this->left + this->width, this->top + this->height);
946}
947
955void Window::ReInit(int rx, int ry, bool reposition)
956{
957 this->SetDirty(); // Mark whole current window as dirty.
958
959 /* Save current size. */
960 int window_width = this->width * _gui_scale / this->scale;
961 int window_height = this->height * _gui_scale / this->scale;
962 this->scale = _gui_scale;
963
964 this->OnInit();
965 /* Re-initialize window smallest size. */
966 this->nested_root->SetupSmallestSize(this);
967 this->nested_root->AssignSizePosition(ST_SMALLEST, 0, 0, this->nested_root->smallest_x, this->nested_root->smallest_y, _current_text_dir == TD_RTL);
968 this->width = this->nested_root->smallest_x;
969 this->height = this->nested_root->smallest_y;
970 this->resize.step_width = this->nested_root->resize_x;
971 this->resize.step_height = this->nested_root->resize_y;
972
973 /* Resize as close to the original size + requested resize as possible. */
974 window_width = std::max(window_width + rx, this->width);
975 window_height = std::max(window_height + ry, this->height);
976 int dx = (this->resize.step_width == 0) ? 0 : window_width - this->width;
977 int dy = (this->resize.step_height == 0) ? 0 : window_height - this->height;
978 /* dx and dy has to go by step.. calculate it.
979 * The cast to int is necessary else dx/dy are implicitly casted to unsigned int, which won't work. */
980 if (this->resize.step_width > 1) dx -= dx % (int)this->resize.step_width;
981 if (this->resize.step_height > 1) dy -= dy % (int)this->resize.step_height;
982
983 if (reposition) {
984 Point pt = this->OnInitialPosition(this->nested_root->smallest_x, this->nested_root->smallest_y, window_number);
985 this->InitializePositionSize(pt.x, pt.y, this->nested_root->smallest_x, this->nested_root->smallest_y);
986 this->FindWindowPlacementAndResize(this->window_desc.GetDefaultWidth(), this->window_desc.GetDefaultHeight());
987 }
988
989 ResizeWindow(this, dx, dy, true, false);
990 /* ResizeWindow() does this->SetDirty() already, no need to do it again here. */
991}
992
998void Window::SetShaded(bool make_shaded)
999{
1000 if (this->shade_select == nullptr) return;
1001
1002 int desired = make_shaded ? SZSP_HORIZONTAL : 0;
1003 if (this->shade_select->shown_plane != desired) {
1004 if (make_shaded) {
1005 if (this->nested_focus != nullptr) this->UnfocusFocusedWidget();
1006 this->unshaded_size.width = this->width;
1007 this->unshaded_size.height = this->height;
1008 this->shade_select->SetDisplayedPlane(desired);
1009 this->ReInit(0, -this->height);
1010 } else {
1011 this->shade_select->SetDisplayedPlane(desired);
1012 int dx = ((int)this->unshaded_size.width > this->width) ? (int)this->unshaded_size.width - this->width : 0;
1013 int dy = ((int)this->unshaded_size.height > this->height) ? (int)this->unshaded_size.height - this->height : 0;
1014 this->ReInit(dx, dy);
1015 }
1016 }
1017}
1018
1026{
1027 for (Window *v : Window::Iterate()) {
1028 if ((wc == WC_INVALID || wc == v->window_class) && v->parent == this) return v;
1029 }
1030
1031 return nullptr;
1032}
1033
1039{
1040 Window *child = this->FindChildWindow(wc);
1041 while (child != nullptr) {
1042 child->Close();
1043 child = this->FindChildWindow(wc);
1044 }
1045}
1046
1050void Window::Close([[maybe_unused]] int data)
1051{
1052 /* Don't close twice. */
1053 if (*this->z_position == nullptr) return;
1054
1055 *this->z_position = nullptr;
1056
1057 if (_thd.window_class == this->window_class &&
1058 _thd.window_number == this->window_number) {
1060 }
1061
1062 /* Prevent Mouseover() from resetting mouse-over coordinates on a non-existing window */
1063 if (_mouseover_last_w == this) _mouseover_last_w = nullptr;
1064
1065 /* We can't scroll the window when it's closed. */
1066 if (_last_scroll_window == this) _last_scroll_window = nullptr;
1067
1068 /* Make sure we don't try to access non-existing query strings. */
1069 this->querystrings.clear();
1070
1071 /* Make sure we don't try to access this window as the focused window when it doesn't exist anymore. */
1072 if (_focused_window == this) {
1073 this->OnFocusLost(true);
1074 _focused_window = nullptr;
1075 }
1076
1077 this->CloseChildWindows();
1078
1079 this->SetDirty();
1080
1081 Window::closed_windows.push_back(this);
1082}
1083
1088{
1089 /* Make sure the window is closed, deletion is allowed only in Window::DeleteClosedWindows(). */
1090 assert(*this->z_position == nullptr);
1091
1092 if (this->viewport != nullptr) DeleteWindowViewport(this);
1093}
1094
1102{
1103 for (Window *w : Window::Iterate()) {
1104 if (w->window_class == cls && w->window_number == number) return w;
1105 }
1106
1107 return nullptr;
1108}
1109
1117{
1118 for (Window *w : Window::Iterate()) {
1119 if (w->window_class == cls) return w;
1120 }
1121
1122 return nullptr;
1123}
1124
1131{
1133 assert(w != nullptr);
1134 return w;
1135}
1136
1143void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
1144{
1145 Window *w = FindWindowById(cls, number);
1146 if (w != nullptr && (force || !w->flags.Test(WindowFlag::Sticky))) {
1147 w->Close(data);
1148 }
1149}
1150
1156{
1157 /* Note: the container remains stable, even when deleting windows. */
1158 for (Window *w : Window::Iterate()) {
1159 if (w->window_class == cls) {
1160 w->Close(data);
1161 }
1162 }
1163}
1164
1172{
1173 /* Note: the container remains stable, even when deleting windows. */
1174 for (Window *w : Window::Iterate()) {
1175 if (w->owner == id) {
1176 w->Close();
1177 }
1178 }
1179
1180 /* Also delete the company specific windows that don't have a company-colour. */
1182}
1183
1191void ChangeWindowOwner(Owner old_owner, Owner new_owner)
1192{
1193 for (Window *w : Window::Iterate()) {
1194 if (w->owner != old_owner) continue;
1195
1196 switch (w->window_class) {
1197 case WC_COMPANY_COLOUR:
1198 case WC_FINANCES:
1199 case WC_STATION_LIST:
1200 case WC_TRAINS_LIST:
1201 case WC_ROADVEH_LIST:
1202 case WC_SHIPS_LIST:
1203 case WC_AIRCRAFT_LIST:
1204 case WC_BUY_COMPANY:
1205 case WC_COMPANY:
1207 case WC_VEHICLE_ORDERS: // Changing owner would also require changing WindowDesc, which is not possible; however keeping the old one crashes because of missing widgets etc.. See ShowOrdersWindow().
1208 continue;
1209
1210 default:
1211 w->owner = new_owner;
1212 break;
1213 }
1214 }
1215}
1216
1217static void BringWindowToFront(Window *w, bool dirty = true);
1218
1227{
1228 Window *w = FindWindowById(cls, number);
1229
1230 if (w != nullptr) {
1231 if (w->IsShaded()) w->SetShaded(false); // Restore original window size if it was shaded.
1232
1233 w->SetWhiteBorder();
1235 w->SetDirty();
1236 }
1237
1238 return w;
1239}
1240
1241static inline bool IsVitalWindow(const Window *w)
1242{
1243 switch (w->window_class) {
1244 case WC_MAIN_TOOLBAR:
1245 case WC_STATUS_BAR:
1246 case WC_NEWS_WINDOW:
1248 return true;
1249
1250 default:
1251 return false;
1252 }
1253}
1254
1264{
1265 assert(wc != WC_INVALID);
1266
1267 uint z_priority = 0;
1268
1269 switch (wc) {
1270 case WC_TOOLTIPS:
1271 ++z_priority;
1272 [[fallthrough]];
1273
1274 case WC_ERRMSG:
1276 ++z_priority;
1277 [[fallthrough]];
1278
1279 case WC_ENDSCREEN:
1280 ++z_priority;
1281 [[fallthrough]];
1282
1283 case WC_HIGHSCORE:
1284 ++z_priority;
1285 [[fallthrough]];
1286
1287 case WC_DROPDOWN_MENU:
1288 ++z_priority;
1289 [[fallthrough]];
1290
1291 case WC_MAIN_TOOLBAR:
1292 case WC_STATUS_BAR:
1293 ++z_priority;
1294 [[fallthrough]];
1295
1296 case WC_OSK:
1297 ++z_priority;
1298 [[fallthrough]];
1299
1300 case WC_QUERY_STRING:
1302 ++z_priority;
1303 [[fallthrough]];
1304
1306 case WC_MODAL_PROGRESS:
1308 case WC_SAVE_PRESET:
1309 ++z_priority;
1310 [[fallthrough]];
1311
1313 case WC_SAVELOAD:
1314 case WC_GAME_OPTIONS:
1315 case WC_CUSTOM_CURRENCY:
1316 case WC_NETWORK_WINDOW:
1317 case WC_GRF_PARAMETERS:
1318 case WC_SCRIPT_LIST:
1319 case WC_SCRIPT_SETTINGS:
1320 case WC_TEXTFILE:
1321 ++z_priority;
1322 [[fallthrough]];
1323
1324 case WC_CONSOLE:
1325 ++z_priority;
1326 [[fallthrough]];
1327
1328 case WC_NEWS_WINDOW:
1329 ++z_priority;
1330 [[fallthrough]];
1331
1332 default:
1333 ++z_priority;
1334 [[fallthrough]];
1335
1336 case WC_MAIN_WINDOW:
1337 return z_priority;
1338 }
1339}
1340
1347static void BringWindowToFront(Window *w, bool dirty)
1348{
1349 auto priority = GetWindowZPriority(w->window_class);
1350 WindowList::iterator dest = _z_windows.begin();
1351 while (dest != _z_windows.end() && (*dest == nullptr || GetWindowZPriority((*dest)->window_class) <= priority)) ++dest;
1352
1353 if (dest != w->z_position) {
1354 _z_windows.splice(dest, _z_windows, w->z_position);
1355 }
1356
1357 if (dirty) w->SetDirty();
1358}
1359
1368{
1369 /* Set up window properties; some of them are needed to set up smallest size below */
1370 this->window_class = this->window_desc.cls;
1371 this->SetWhiteBorder();
1373 this->owner = INVALID_OWNER;
1374 this->nested_focus = nullptr;
1375 this->window_number = window_number;
1376
1377 this->OnInit();
1378 /* Initialize smallest size. */
1379 this->nested_root->SetupSmallestSize(this);
1380 /* Initialize to smallest size. */
1381 this->nested_root->AssignSizePosition(ST_SMALLEST, 0, 0, this->nested_root->smallest_x, this->nested_root->smallest_y, _current_text_dir == TD_RTL);
1382
1383 /* Further set up window properties,
1384 * this->left, this->top, this->width, this->height, this->resize.width, and this->resize.height are initialized later. */
1385 this->resize.step_width = this->nested_root->resize_x;
1386 this->resize.step_height = this->nested_root->resize_y;
1387
1388 /* Give focus to the opened window unless a dropdown menu has focus or a text box of the focused window has focus
1389 * (so we don't interrupt typing) unless the new window has a text box. */
1390 bool dropdown_active = _focused_window != nullptr && _focused_window->window_class == WC_DROPDOWN_MENU;
1391 bool editbox_active = EditBoxInGlobalFocus() && this->nested_root->GetWidgetOfType(WWT_EDITBOX) == nullptr;
1392 if (!dropdown_active && !editbox_active) SetFocusedWindow(this);
1393
1394 /* Insert the window into the correct location in the z-ordering. */
1395 BringWindowToFront(this, false);
1396}
1397
1405void Window::InitializePositionSize(int x, int y, int sm_width, int sm_height)
1406{
1407 this->left = x;
1408 this->top = y;
1409 this->width = sm_width;
1410 this->height = sm_height;
1411}
1412
1423void Window::FindWindowPlacementAndResize(int def_width, int def_height)
1424{
1425 def_width = std::max(def_width, this->width); // Don't allow default size to be smaller than smallest size
1426 def_height = std::max(def_height, this->height);
1427 /* Try to make windows smaller when our window is too small.
1428 * w->(width|height) is normally the same as min_(width|height),
1429 * but this way the GUIs can be made a little more dynamic;
1430 * one can use the same spec for multiple windows and those
1431 * can then determine the real minimum size of the window. */
1432 if (this->width != def_width || this->height != def_height) {
1433 /* Think about the overlapping toolbars when determining the minimum window size */
1434 int free_height = _screen.height;
1436 if (wt != nullptr) free_height -= wt->height;
1438 if (wt != nullptr) free_height -= wt->height;
1439
1440 int enlarge_x = std::max(std::min(def_width - this->width, _screen.width - this->width), 0);
1441 int enlarge_y = std::max(std::min(def_height - this->height, free_height - this->height), 0);
1442
1443 /* X and Y has to go by step.. calculate it.
1444 * The cast to int is necessary else x/y are implicitly casted to
1445 * unsigned int, which won't work. */
1446 if (this->resize.step_width > 1) enlarge_x -= enlarge_x % (int)this->resize.step_width;
1447 if (this->resize.step_height > 1) enlarge_y -= enlarge_y % (int)this->resize.step_height;
1448
1449 ResizeWindow(this, enlarge_x, enlarge_y, true, false);
1450 /* ResizeWindow() calls this->OnResize(). */
1451 } else {
1452 /* Always call OnResize; that way the scrollbars and matrices get initialized. */
1453 this->OnResize();
1454 }
1455
1456 int nx = this->left;
1457 int ny = this->top;
1458
1459 if (nx + this->width > _screen.width) nx -= (nx + this->width - _screen.width);
1460
1462 ny = std::max(ny, (wt == nullptr || this == wt || this->top == 0) ? 0 : wt->height);
1463 nx = std::max(nx, 0);
1464
1465 if (this->viewport != nullptr) {
1466 this->viewport->left += nx - this->left;
1467 this->viewport->top += ny - this->top;
1468 }
1469 this->left = nx;
1470 this->top = ny;
1471
1472 this->SetDirty();
1473}
1474
1487static bool IsGoodAutoPlace1(int left, int top, int width, int height, int toolbar_y, Point &pos)
1488{
1489 int right = width + left;
1490 int bottom = height + top;
1491
1492 if (left < 0 || top < toolbar_y || right > _screen.width || bottom > _screen.height) return false;
1493
1494 /* Make sure it is not obscured by any window. */
1495 for (const Window *w : Window::Iterate()) {
1496 if (w->window_class == WC_MAIN_WINDOW) continue;
1497
1498 if (right > w->left &&
1499 w->left + w->width > left &&
1500 bottom > w->top &&
1501 w->top + w->height > top) {
1502 return false;
1503 }
1504 }
1505
1506 pos.x = left;
1507 pos.y = top;
1508 return true;
1509}
1510
1523static bool IsGoodAutoPlace2(int left, int top, int width, int height, int toolbar_y, Point &pos)
1524{
1525 bool rtl = _current_text_dir == TD_RTL;
1526
1527 /* Left part of the rectangle may be at most 1/4 off-screen,
1528 * right part of the rectangle may be at most 1/2 off-screen
1529 */
1530 if (rtl) {
1531 if (left < -(width >> 1) || left > _screen.width - (width >> 2)) return false;
1532 } else {
1533 if (left < -(width >> 2) || left > _screen.width - (width >> 1)) return false;
1534 }
1535
1536 /* Bottom part of the rectangle may be at most 1/4 off-screen */
1537 if (top < toolbar_y || top > _screen.height - (height >> 2)) return false;
1538
1539 /* Make sure it is not obscured by any window. */
1540 for (const Window *w : Window::Iterate()) {
1541 if (w->window_class == WC_MAIN_WINDOW) continue;
1542
1543 if (left + width > w->left &&
1544 w->left + w->width > left &&
1545 top + height > w->top &&
1546 w->top + w->height > top) {
1547 return false;
1548 }
1549 }
1550
1551 pos.x = left;
1552 pos.y = top;
1553 return true;
1554}
1555
1562static Point GetAutoPlacePosition(int width, int height)
1563{
1564 Point pt;
1565
1566 bool rtl = _current_text_dir == TD_RTL;
1567
1568 /* First attempt, try top-left of the screen */
1569 const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR);
1570 const int toolbar_y = main_toolbar != nullptr ? main_toolbar->height : 0;
1571 if (IsGoodAutoPlace1(rtl ? _screen.width - width : 0, toolbar_y, width, height, toolbar_y, pt)) return pt;
1572
1573 /* Second attempt, try around all existing windows.
1574 * The new window must be entirely on-screen, and not overlap with an existing window.
1575 * Eight starting points are tried, two at each corner.
1576 */
1577 for (const Window *w : Window::Iterate()) {
1578 if (w->window_class == WC_MAIN_WINDOW) continue;
1579
1580 if (IsGoodAutoPlace1(w->left + w->width, w->top, width, height, toolbar_y, pt)) return pt;
1581 if (IsGoodAutoPlace1(w->left - width, w->top, width, height, toolbar_y, pt)) return pt;
1582 if (IsGoodAutoPlace1(w->left, w->top + w->height, width, height, toolbar_y, pt)) return pt;
1583 if (IsGoodAutoPlace1(w->left, w->top - height, width, height, toolbar_y, pt)) return pt;
1584 if (IsGoodAutoPlace1(w->left + w->width, w->top + w->height - height, width, height, toolbar_y, pt)) return pt;
1585 if (IsGoodAutoPlace1(w->left - width, w->top + w->height - height, width, height, toolbar_y, pt)) return pt;
1586 if (IsGoodAutoPlace1(w->left + w->width - width, w->top + w->height, width, height, toolbar_y, pt)) return pt;
1587 if (IsGoodAutoPlace1(w->left + w->width - width, w->top - height, width, height, toolbar_y, pt)) return pt;
1588 }
1589
1590 /* Third attempt, try around all existing windows.
1591 * The new window may be partly off-screen, and must not overlap with an existing window.
1592 * Only four starting points are tried.
1593 */
1594 for (const Window *w : Window::Iterate()) {
1595 if (w->window_class == WC_MAIN_WINDOW) continue;
1596
1597 if (IsGoodAutoPlace2(w->left + w->width, w->top, width, height, toolbar_y, pt)) return pt;
1598 if (IsGoodAutoPlace2(w->left - width, w->top, width, height, toolbar_y, pt)) return pt;
1599 if (IsGoodAutoPlace2(w->left, w->top + w->height, width, height, toolbar_y, pt)) return pt;
1600 if (IsGoodAutoPlace2(w->left, w->top - height, width, height, toolbar_y, pt)) return pt;
1601 }
1602
1603 /* Fourth and final attempt, put window at diagonal starting from (0, toolbar_y), try multiples
1604 * of the closebox
1605 */
1606 int left = rtl ? _screen.width - width : 0, top = toolbar_y;
1607 int offset_x = rtl ? -(int)NWidgetLeaf::closebox_dimension.width : (int)NWidgetLeaf::closebox_dimension.width;
1608 int offset_y = std::max<int>(NWidgetLeaf::closebox_dimension.height, GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.captiontext.Vertical());
1609
1610restart:
1611 for (const Window *w : Window::Iterate()) {
1612 if (w->left == left && w->top == top) {
1613 left += offset_x;
1614 top += offset_y;
1615 goto restart;
1616 }
1617 }
1618
1619 pt.x = left;
1620 pt.y = top;
1621 return pt;
1622}
1623
1631{
1632 const Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0);
1633 assert(w != nullptr);
1634 Point pt = { _current_text_dir == TD_RTL ? w->left : (w->left + w->width) - window_width, w->top + w->height };
1635 return pt;
1636}
1637
1655static Point LocalGetWindowPlacement(const WindowDesc &desc, int16_t sm_width, int16_t sm_height, int window_number)
1656{
1657 Point pt;
1658 const Window *w;
1659
1660 int16_t default_width = std::max(desc.GetDefaultWidth(), sm_width);
1661 int16_t default_height = std::max(desc.GetDefaultHeight(), sm_height);
1662
1663 if (desc.parent_cls != WC_NONE && (w = FindWindowById(desc.parent_cls, window_number)) != nullptr) {
1664 bool rtl = _current_text_dir == TD_RTL;
1665 if (desc.parent_cls == WC_BUILD_TOOLBAR || desc.parent_cls == WC_SCEN_LAND_GEN) {
1666 pt.x = w->left + (rtl ? w->width - default_width : 0);
1667 pt.y = w->top + w->height;
1668 return pt;
1669 } else {
1670 /* Position child window with offset of closebox, but make sure that either closebox or resizebox is visible
1671 * - Y position: closebox of parent + closebox of child + statusbar
1672 * - X position: closebox on left/right, resizebox on right/left (depending on ltr/rtl)
1673 */
1674 int indent_y = std::max<int>(NWidgetLeaf::closebox_dimension.height, GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.captiontext.Vertical());
1675 if (w->top + 3 * indent_y < _screen.height) {
1676 pt.y = w->top + indent_y;
1677 int indent_close = NWidgetLeaf::closebox_dimension.width;
1678 int indent_resize = NWidgetLeaf::resizebox_dimension.width;
1679 if (_current_text_dir == TD_RTL) {
1680 pt.x = std::max(w->left + w->width - default_width - indent_close, 0);
1681 if (pt.x + default_width >= indent_close && pt.x + indent_resize <= _screen.width) return pt;
1682 } else {
1683 pt.x = std::min(w->left + indent_close, _screen.width - default_width);
1684 if (pt.x + default_width >= indent_resize && pt.x + indent_close <= _screen.width) return pt;
1685 }
1686 }
1687 }
1688 }
1689
1690 switch (desc.default_pos) {
1691 case WDP_ALIGN_TOOLBAR: // Align to the toolbar
1692 return GetToolbarAlignedWindowPosition(default_width);
1693
1694 case WDP_AUTO: // Find a good automatic position for the window
1695 return GetAutoPlacePosition(default_width, default_height);
1696
1697 case WDP_CENTER: // Centre the window horizontally
1698 pt.x = (_screen.width - default_width) / 2;
1699 pt.y = (_screen.height - default_height) / 2;
1700 break;
1701
1702 case WDP_MANUAL:
1703 pt.x = 0;
1704 pt.y = 0;
1705 break;
1706
1707 default:
1708 NOT_REACHED();
1709 }
1710
1711 return pt;
1712}
1713
1714/* virtual */ Point Window::OnInitialPosition([[maybe_unused]]int16_t sm_width, [[maybe_unused]]int16_t sm_height, [[maybe_unused]]int window_number)
1715{
1717}
1718
1727{
1728 this->nested_root = MakeWindowNWidgetTree(this->window_desc.nwid_parts, &this->shade_select);
1729 this->nested_root->FillWidgetLookup(this->widget_lookup);
1730}
1731
1737{
1738 this->InitializeData(window_number);
1739 this->ApplyDefaults();
1740 Point pt = this->OnInitialPosition(this->nested_root->smallest_x, this->nested_root->smallest_y, window_number);
1741 this->InitializePositionSize(pt.x, pt.y, this->nested_root->smallest_x, this->nested_root->smallest_y);
1742 this->FindWindowPlacementAndResize(this->window_desc.GetDefaultWidth(), this->window_desc.GetDefaultHeight());
1743}
1744
1750{
1751 this->CreateNestedTree();
1752 this->FinishInitNested(window_number);
1753}
1754
1759Window::Window(WindowDesc &desc) : window_desc(desc), scale(_gui_scale), mouse_capture_widget(-1)
1760{
1761 this->z_position = _z_windows.insert(_z_windows.end(), this);
1762}
1763
1772{
1773 for (Window *w : Window::IterateFromFront()) {
1774 if (MayBeShown(w) && IsInsideBS(x, w->left, w->width) && IsInsideBS(y, w->top, w->height)) {
1775 return w;
1776 }
1777 }
1778
1779 return nullptr;
1780}
1781
1786{
1787 IConsoleClose();
1788
1789 _focused_window = nullptr;
1790 _mouseover_last_w = nullptr;
1791 _last_scroll_window = nullptr;
1792 _scrolling_viewport = false;
1793 _mouse_hovering = false;
1794
1796 NWidgetLeaf::InvalidateDimensionCache(); // Reset cached sizes of several widgets.
1797 NWidgetScrollbar::InvalidateDimensionCache();
1798
1800
1802}
1803
1808{
1810
1811 for (Window *w : Window::Iterate()) w->Close();
1812
1814
1815 assert(_z_windows.empty());
1816}
1817
1822{
1825 _thd.Reset();
1826}
1827
1828static void DecreaseWindowCounters()
1829{
1830 if (_scroller_click_timeout != 0) _scroller_click_timeout--;
1831
1832 for (Window *w : Window::Iterate()) {
1833 if (_scroller_click_timeout == 0) {
1834 /* Unclick scrollbar buttons if they are pressed. */
1835 for (auto &pair : w->widget_lookup) {
1836 NWidgetBase *nwid = pair.second;
1837 if (nwid->type == NWID_HSCROLLBAR || nwid->type == NWID_VSCROLLBAR) {
1838 NWidgetScrollbar *sb = static_cast<NWidgetScrollbar*>(nwid);
1839 if (sb->disp_flags.Any({NWidgetDisplayFlag::ScrollbarUp, NWidgetDisplayFlag::ScrollbarDown})) {
1841 w->mouse_capture_widget = -1;
1842 sb->SetDirty(w);
1843 }
1844 }
1845 }
1846 }
1847
1848 /* Handle editboxes */
1849 for (auto &pair : w->querystrings) {
1850 pair.second->HandleEditBox(w, pair.first);
1851 }
1852
1853 w->OnMouseLoop();
1854 }
1855
1856 for (Window *w : Window::Iterate()) {
1857 if (w->flags.Test(WindowFlag::Timeout) && --w->timeout_timer == 0) {
1859
1860 w->OnTimeout();
1861 w->RaiseButtons(true);
1862 }
1863 }
1864}
1865
1866static void HandlePlacePresize()
1867{
1868 if (_special_mouse_mode != WSM_PRESIZE) return;
1869
1870 Window *w = _thd.GetCallbackWnd();
1871 if (w == nullptr) return;
1872
1873 Point pt = GetTileBelowCursor();
1874 if (pt.x == -1) {
1875 _thd.selend.x = -1;
1876 return;
1877 }
1878
1879 w->OnPlacePresize(pt, TileVirtXY(pt.x, pt.y));
1880}
1881
1887{
1889
1890 if (_left_button_down && _cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED; // Dragging, but the mouse did not move.
1891
1892 Window *w = _thd.GetCallbackWnd();
1893 if (w != nullptr) {
1894 /* Send an event in client coordinates. */
1895 Point pt;
1896 pt.x = _cursor.pos.x - w->left;
1897 pt.y = _cursor.pos.y - w->top;
1898 if (_left_button_down) {
1899 w->OnMouseDrag(pt, GetWidgetFromPos(w, pt.x, pt.y));
1900 } else {
1901 w->OnDragDrop(pt, GetWidgetFromPos(w, pt.x, pt.y));
1902 }
1903 }
1904
1905 if (!_left_button_down) ResetObjectToPlace(); // Button released, finished dragging.
1906 return ES_HANDLED;
1907}
1908
1910static void HandleMouseOver()
1911{
1912 Window *w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y);
1913
1914 /* We changed window, put an OnMouseOver event to the last window */
1915 if (_mouseover_last_w != nullptr && _mouseover_last_w != w) {
1916 /* Reset mouse-over coordinates of previous window */
1917 Point pt = { -1, -1 };
1919 }
1920
1921 /* _mouseover_last_w will get reset when the window is deleted, see DeleteWindow() */
1923
1924 if (w != nullptr) {
1925 /* send an event in client coordinates. */
1926 Point pt = { _cursor.pos.x - w->left, _cursor.pos.y - w->top };
1927 const NWidgetCore *widget = w->nested_root->GetWidgetFromPos(pt.x, pt.y);
1928 if (widget != nullptr) w->OnMouseOver(pt, widget->GetIndex());
1929 }
1930}
1931
1937
1948static void PreventHiding(int *nx, int *ny, const Rect &rect, const Window *v, int px, PreventHideDirection dir)
1949{
1950 if (v == nullptr) return;
1951
1952 const int min_visible = rect.Height();
1953
1954 int v_bottom = v->top + v->height - 1;
1955 int v_right = v->left + v->width - 1;
1956 int safe_y = (dir == PHD_UP) ? (v->top - min_visible - rect.top) : (v_bottom + min_visible - rect.bottom); // Compute safe vertical position.
1957
1958 if (*ny + rect.top <= v->top - min_visible) return; // Above v is enough space
1959 if (*ny + rect.bottom >= v_bottom + min_visible) return; // Below v is enough space
1960
1961 /* Vertically, the rectangle is hidden behind v. */
1962 if (*nx + rect.left + min_visible < v->left) { // At left of v.
1963 if (v->left < min_visible) *ny = safe_y; // But enough room, force it to a safe position.
1964 return;
1965 }
1966 if (*nx + rect.right - min_visible > v_right) { // At right of v.
1967 if (v_right > _screen.width - min_visible) *ny = safe_y; // Not enough room, force it to a safe position.
1968 return;
1969 }
1970
1971 /* Horizontally also hidden, force movement to a safe area. */
1972 if (px + rect.left < v->left && v->left >= min_visible) { // Coming from the left, and enough room there.
1973 *nx = v->left - min_visible - rect.left;
1974 } else if (px + rect.right > v_right && v_right <= _screen.width - min_visible) { // Coming from the right, and enough room there.
1975 *nx = v_right + min_visible - rect.right;
1976 } else {
1977 *ny = safe_y;
1978 }
1979}
1980
1988static void EnsureVisibleCaption(Window *w, int nx, int ny)
1989{
1990 /* Search for the title bar rectangle. */
1991 const NWidgetBase *caption = w->nested_root->GetWidgetOfType(WWT_CAPTION);
1992 if (caption != nullptr) {
1993 const Rect caption_rect = caption->GetCurrentRect();
1994
1995 const int min_visible = caption_rect.Height();
1996
1997 /* Make sure the window doesn't leave the screen */
1998 nx = Clamp(nx, min_visible - caption_rect.right, _screen.width - min_visible - caption_rect.left);
1999 ny = Clamp(ny, 0, _screen.height - min_visible);
2000
2001 /* Make sure the title bar isn't hidden behind the main tool bar or the status bar. */
2002 PreventHiding(&nx, &ny, caption_rect, FindWindowById(WC_MAIN_TOOLBAR, 0), w->left, PHD_DOWN);
2003 PreventHiding(&nx, &ny, caption_rect, FindWindowById(WC_STATUS_BAR, 0), w->left, PHD_UP);
2004 }
2005
2006 if (w->viewport != nullptr) {
2007 w->viewport->left += nx - w->left;
2008 w->viewport->top += ny - w->top;
2009 }
2010
2011 w->left = nx;
2012 w->top = ny;
2013}
2014
2025void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen, bool schedule_resize)
2026{
2027 if (delta_x != 0 || delta_y != 0) {
2028 if (clamp_to_screen) {
2029 /* Determine the new right/bottom position. If that is outside of the bounds of
2030 * the resolution clamp it in such a manner that it stays within the bounds. */
2031 int new_right = w->left + w->width + delta_x;
2032 int new_bottom = w->top + w->height + delta_y;
2033 if (new_right >= (int)_screen.width) delta_x -= Ceil(new_right - _screen.width, std::max(1U, w->nested_root->resize_x));
2034 if (new_bottom >= (int)_screen.height) delta_y -= Ceil(new_bottom - _screen.height, std::max(1U, w->nested_root->resize_y));
2035 }
2036
2037 w->SetDirty();
2038
2039 uint new_xinc = std::max(0, (w->nested_root->resize_x == 0) ? 0 : (int)(w->nested_root->current_x - w->nested_root->smallest_x) + delta_x);
2040 uint new_yinc = std::max(0, (w->nested_root->resize_y == 0) ? 0 : (int)(w->nested_root->current_y - w->nested_root->smallest_y) + delta_y);
2041 assert(w->nested_root->resize_x == 0 || new_xinc % w->nested_root->resize_x == 0);
2042 assert(w->nested_root->resize_y == 0 || new_yinc % w->nested_root->resize_y == 0);
2043
2044 w->nested_root->AssignSizePosition(ST_RESIZE, 0, 0, w->nested_root->smallest_x + new_xinc, w->nested_root->smallest_y + new_yinc, _current_text_dir == TD_RTL);
2045 w->width = w->nested_root->current_x;
2046 w->height = w->nested_root->current_y;
2047 }
2048
2049 EnsureVisibleCaption(w, w->left, w->top);
2050
2051 /* Schedule OnResize to make sure everything is initialised correctly if it needs to be. */
2052 if (schedule_resize) {
2053 w->ScheduleResize();
2054 } else {
2055 w->OnResize();
2056 }
2057 w->SetDirty();
2058}
2059
2066{
2068 return (w == nullptr) ? 0 : w->top + w->height;
2069}
2070
2077{
2079 return (w == nullptr) ? _screen.height : w->top;
2080}
2081
2082static bool _dragging_window;
2083
2089{
2090 /* Get out immediately if no window is being dragged at all. */
2091 if (!_dragging_window) return ES_NOT_HANDLED;
2092
2093 /* If button still down, but cursor hasn't moved, there is nothing to do. */
2094 if (_left_button_down && _cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED;
2095
2096 /* Otherwise find the window... */
2097 for (Window *w : Window::Iterate()) {
2099 /* Stop the dragging if the left mouse button was released */
2100 if (!_left_button_down) {
2102 break;
2103 }
2104
2105 w->SetDirty();
2106
2107 int x = _cursor.pos.x + _drag_delta.x;
2108 int y = _cursor.pos.y + _drag_delta.y;
2109 int nx = x;
2110 int ny = y;
2111
2115 int delta;
2116
2117 for (const Window *v : Window::Iterate()) {
2118 if (v == w) continue; // Don't snap at yourself
2119
2120 if (y + w->height > v->top && y < v->top + v->height) {
2121 /* Your left border <-> other right border */
2122 delta = abs(v->left + v->width - x);
2123 if (delta <= hsnap) {
2124 nx = v->left + v->width;
2125 hsnap = delta;
2126 }
2127
2128 /* Your right border <-> other left border */
2129 delta = abs(v->left - x - w->width);
2130 if (delta <= hsnap) {
2131 nx = v->left - w->width;
2132 hsnap = delta;
2133 }
2134 }
2135
2136 if (w->top + w->height >= v->top && w->top <= v->top + v->height) {
2137 /* Your left border <-> other left border */
2138 delta = abs(v->left - x);
2139 if (delta <= hsnap) {
2140 nx = v->left;
2141 hsnap = delta;
2142 }
2143
2144 /* Your right border <-> other right border */
2145 delta = abs(v->left + v->width - x - w->width);
2146 if (delta <= hsnap) {
2147 nx = v->left + v->width - w->width;
2148 hsnap = delta;
2149 }
2150 }
2151
2152 if (x + w->width > v->left && x < v->left + v->width) {
2153 /* Your top border <-> other bottom border */
2154 delta = abs(v->top + v->height - y);
2155 if (delta <= vsnap) {
2156 ny = v->top + v->height;
2157 vsnap = delta;
2158 }
2159
2160 /* Your bottom border <-> other top border */
2161 delta = abs(v->top - y - w->height);
2162 if (delta <= vsnap) {
2163 ny = v->top - w->height;
2164 vsnap = delta;
2165 }
2166 }
2167
2168 if (w->left + w->width >= v->left && w->left <= v->left + v->width) {
2169 /* Your top border <-> other top border */
2170 delta = abs(v->top - y);
2171 if (delta <= vsnap) {
2172 ny = v->top;
2173 vsnap = delta;
2174 }
2175
2176 /* Your bottom border <-> other bottom border */
2177 delta = abs(v->top + v->height - y - w->height);
2178 if (delta <= vsnap) {
2179 ny = v->top + v->height - w->height;
2180 vsnap = delta;
2181 }
2182 }
2183 }
2184 }
2185
2186 EnsureVisibleCaption(w, nx, ny);
2187
2188 w->SetDirty();
2189 return ES_HANDLED;
2191 /* Stop the sizing if the left mouse button was released */
2192 if (!_left_button_down) {
2195 w->SetDirty();
2196 break;
2197 }
2198
2199 /* Compute difference in pixels between cursor position and reference point in the window.
2200 * If resizing the left edge of the window, moving to the left makes the window bigger not smaller.
2201 */
2202 int x, y = _cursor.pos.y - _drag_delta.y;
2204 x = _drag_delta.x - _cursor.pos.x;
2205 } else {
2206 x = _cursor.pos.x - _drag_delta.x;
2207 }
2208
2209 /* resize.step_width and/or resize.step_height may be 0, which means no resize is possible. */
2210 if (w->resize.step_width == 0) x = 0;
2211 if (w->resize.step_height == 0) y = 0;
2212
2213 /* Check the resize button won't go past the bottom of the screen */
2214 if (w->top + w->height + y > _screen.height) {
2215 y = _screen.height - w->height - w->top;
2216 }
2217
2218 /* X and Y has to go by step.. calculate it.
2219 * The cast to int is necessary else x/y are implicitly casted to
2220 * unsigned int, which won't work. */
2221 if (w->resize.step_width > 1) x -= x % (int)w->resize.step_width;
2222 if (w->resize.step_height > 1) y -= y % (int)w->resize.step_height;
2223
2224 /* Check that we don't go below the minimum set size */
2225 if ((int)w->width + x < (int)w->nested_root->smallest_x) {
2226 x = w->nested_root->smallest_x - w->width;
2227 }
2228 if ((int)w->height + y < (int)w->nested_root->smallest_y) {
2229 y = w->nested_root->smallest_y - w->height;
2230 }
2231
2232 /* Window already on size */
2233 if (x == 0 && y == 0) return ES_HANDLED;
2234
2235 /* Now find the new cursor pos.. this is NOT _cursor, because we move in steps. */
2236 _drag_delta.y += y;
2237 if (w->flags.Test(WindowFlag::SizingLeft) && x != 0) {
2238 _drag_delta.x -= x; // x > 0 -> window gets longer -> left-edge moves to left -> subtract x to get new position.
2239 w->SetDirty();
2240 w->left -= x; // If dragging left edge, move left window edge in opposite direction by the same amount.
2241 /* ResizeWindow() below ensures marking new position as dirty. */
2242 } else {
2243 _drag_delta.x += x;
2244 }
2245
2246 /* ResizeWindow sets both pre- and after-size to dirty for redrawal */
2247 ResizeWindow(w, x, y);
2248 return ES_HANDLED;
2249 }
2250 }
2251
2252 _dragging_window = false;
2253 return ES_HANDLED;
2254}
2255
2261{
2264 _dragging_window = true;
2265
2266 _drag_delta.x = w->left - _cursor.pos.x;
2267 _drag_delta.y = w->top - _cursor.pos.y;
2268
2270}
2271
2277static void StartWindowSizing(Window *w, bool to_left)
2278{
2281 _dragging_window = true;
2282
2283 _drag_delta.x = _cursor.pos.x;
2284 _drag_delta.y = _cursor.pos.y;
2285
2287}
2288
2294{
2295 int i;
2297 bool rtl = false;
2298
2299 if (sb->type == NWID_HSCROLLBAR) {
2300 i = _cursor.pos.x - _cursorpos_drag_start.x;
2301 rtl = _current_text_dir == TD_RTL;
2302 } else {
2303 i = _cursor.pos.y - _cursorpos_drag_start.y;
2304 }
2305
2306 if (sb->disp_flags.Any({NWidgetDisplayFlag::ScrollbarUp, NWidgetDisplayFlag::ScrollbarDown})) {
2307 if (_scroller_click_timeout == 1) {
2308 _scroller_click_timeout = 3;
2309 if (sb->UpdatePosition(rtl == sb->disp_flags.Test(NWidgetDisplayFlag::ScrollbarUp) ? 1 : -1)) w->SetDirty();
2310 }
2311 return;
2312 }
2313
2314 /* Find the item we want to move to. SetPosition will make sure it's inside bounds. */
2315 int range = sb->GetCount() - sb->GetCapacity();
2316 if (range <= 0) return;
2317
2318 int pos = RoundDivSU((i + _scrollbar_start_pos) * range, _scrollbar_size);
2319 if (rtl) pos = range - pos;
2320 if (sb->SetPosition(pos)) w->SetDirty();
2321}
2322
2328{
2329 for (Window *w : Window::Iterate()) {
2330 if (w->mouse_capture_widget >= 0) {
2331 /* Abort if no button is clicked any more. */
2332 if (!_left_button_down) {
2334 w->mouse_capture_widget = -1;
2335 return ES_HANDLED;
2336 }
2337
2338 /* Handle scrollbar internally, or dispatch click event */
2340 if (type == NWID_VSCROLLBAR || type == NWID_HSCROLLBAR) {
2342 } else {
2343 /* If cursor hasn't moved, there is nothing to do. */
2344 if (_cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED;
2345
2346 Point pt = { _cursor.pos.x - w->left, _cursor.pos.y - w->top };
2347 w->OnClick(pt, w->mouse_capture_widget, 0);
2348 }
2349 return ES_HANDLED;
2350 }
2351 }
2352
2353 return ES_NOT_HANDLED;
2354}
2355
2361{
2362 bool scrollwheel_scrolling = _settings_client.gui.scrollwheel_scrolling == SWS_SCROLL_MAP && _cursor.wheel_moved;
2363
2365
2366 /* When we don't have a last scroll window we are starting to scroll.
2367 * When the last scroll window and this are not the same we went
2368 * outside of the window and should not left-mouse scroll anymore. */
2369 if (_last_scroll_window == nullptr) _last_scroll_window = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y);
2370
2372 _cursor.fix_at = false;
2373 _scrolling_viewport = false;
2374 _last_scroll_window = nullptr;
2375 return ES_NOT_HANDLED;
2376 }
2377
2378 if (_last_scroll_window == GetMainWindow() && _last_scroll_window->viewport->follow_vehicle != VehicleID::Invalid()) {
2379 /* If the main window is following a vehicle, then first let go of it! */
2381 ScrollMainWindowTo(veh->x_pos, veh->y_pos, veh->z_pos, true); // This also resets follow_vehicle
2382 return ES_NOT_HANDLED;
2383 }
2384
2385 Point delta;
2386 if (scrollwheel_scrolling) {
2387 /* We are using scrollwheels for scrolling */
2388 /* Use the integer part for movement */
2389 delta.x = static_cast<int>(_cursor.h_wheel);
2390 delta.y = static_cast<int>(_cursor.v_wheel);
2391 /* Keep the fractional part so that subtle movement is accumulated */
2392 float temp;
2393 _cursor.v_wheel = std::modf(_cursor.v_wheel, &temp);
2394 _cursor.h_wheel = std::modf(_cursor.h_wheel, &temp);
2395 } else {
2397 delta.x = -_cursor.delta.x;
2398 delta.y = -_cursor.delta.y;
2399 } else {
2400 delta.x = _cursor.delta.x;
2401 delta.y = _cursor.delta.y;
2402 }
2403 }
2404
2405 /* Create a scroll-event and send it to the window */
2406 if (delta.x != 0 || delta.y != 0) _last_scroll_window->OnScroll(delta);
2407
2408 _cursor.delta.x = 0;
2409 _cursor.delta.y = 0;
2410 _cursor.wheel_moved = false;
2411 return ES_HANDLED;
2412}
2413
2425{
2426 bool bring_to_front = false;
2427
2428 if (w->window_class == WC_MAIN_WINDOW ||
2429 IsVitalWindow(w) ||
2430 w->window_class == WC_TOOLTIPS ||
2432 return true;
2433 }
2434
2435 /* Use unshaded window size rather than current size for shaded windows. */
2436 int w_width = w->width;
2437 int w_height = w->height;
2438 if (w->IsShaded()) {
2439 w_width = w->unshaded_size.width;
2440 w_height = w->unshaded_size.height;
2441 }
2442
2444 ++it;
2445 for (; !it.IsEnd(); ++it) {
2446 Window *u = *it;
2447 /* A modal child will prevent the activation of the parent window */
2449 u->SetWhiteBorder();
2450 u->SetDirty();
2451 return false;
2452 }
2453
2454 if (u->window_class == WC_MAIN_WINDOW ||
2455 IsVitalWindow(u) ||
2456 u->window_class == WC_TOOLTIPS ||
2458 continue;
2459 }
2460
2461 /* Window sizes don't interfere, leave z-order alone */
2462 if (w->left + w_width <= u->left ||
2463 u->left + u->width <= w->left ||
2464 w->top + w_height <= u->top ||
2465 u->top + u->height <= w->top) {
2466 continue;
2467 }
2468
2469 bring_to_front = true;
2470 }
2471
2472 if (bring_to_front) BringWindowToFront(w);
2473 return true;
2474}
2475
2484EventState Window::HandleEditBoxKey(WidgetID wid, char32_t key, uint16_t keycode)
2485{
2486 QueryString *query = this->GetQueryString(wid);
2487 if (query == nullptr) return ES_NOT_HANDLED;
2488
2489 int action = QueryString::ACTION_NOTHING;
2490
2491 switch (query->text.HandleKeyPress(key, keycode)) {
2492 case HKPR_EDITING:
2493 this->SetWidgetDirty(wid);
2494 this->OnEditboxChanged(wid);
2495 break;
2496
2497 case HKPR_CURSOR:
2498 this->SetWidgetDirty(wid);
2499 /* For the OSK also invalidate the parent window */
2500 if (this->window_class == WC_OSK) this->InvalidateData();
2501 break;
2502
2503 case HKPR_CONFIRM:
2504 if (this->window_class == WC_OSK) {
2505 this->OnClick(Point(), WID_OSK_OK, 1);
2506 } else if (query->ok_button >= 0) {
2507 this->OnClick(Point(), query->ok_button, 1);
2508 } else {
2509 action = query->ok_button;
2510 }
2511 break;
2512
2513 case HKPR_CANCEL:
2514 if (this->window_class == WC_OSK) {
2515 this->OnClick(Point(), WID_OSK_CANCEL, 1);
2516 } else if (query->cancel_button >= 0) {
2517 this->OnClick(Point(), query->cancel_button, 1);
2518 } else {
2519 action = query->cancel_button;
2520 }
2521 break;
2522
2523 case HKPR_NOT_HANDLED:
2524 return ES_NOT_HANDLED;
2525
2526 default: break;
2527 }
2528
2529 switch (action) {
2531 this->UnfocusFocusedWidget();
2532 break;
2533
2535 if (StrEmpty(query->text.GetText())) {
2536 /* If already empty, unfocus instead */
2537 this->UnfocusFocusedWidget();
2538 } else {
2539 query->text.DeleteAll();
2540 this->SetWidgetDirty(wid);
2541 this->OnEditboxChanged(wid);
2542 }
2543 break;
2544
2545 default:
2546 break;
2547 }
2548
2549 return ES_HANDLED;
2550}
2551
2556void HandleToolbarHotkey(int hotkey)
2557{
2558 assert(HasModalProgress() || IsLocalCompany());
2559
2561 if (w != nullptr) {
2562 if (w->window_desc.hotkeys != nullptr) {
2563 if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return;
2564 }
2565 }
2566}
2567
2573void HandleKeypress(uint keycode, char32_t key)
2574{
2575 /* World generation is multithreaded and messes with companies.
2576 * But there is no company related window open anyway, so _current_company is not used. */
2577 assert(HasModalProgress() || IsLocalCompany());
2578
2579 /*
2580 * The Unicode standard defines an area called the private use area. Code points in this
2581 * area are reserved for private use and thus not portable between systems. For instance,
2582 * Apple defines code points for the arrow keys in this area, but these are only printable
2583 * on a system running OS X. We don't want these keys to show up in text fields and such,
2584 * and thus we have to clear the unicode character when we encounter such a key.
2585 */
2586 if (key >= 0xE000 && key <= 0xF8FF) key = 0;
2587
2588 /*
2589 * If both key and keycode is zero, we don't bother to process the event.
2590 */
2591 if (key == 0 && keycode == 0) return;
2592
2593 /* Check if the focused window has a focused editbox */
2594 if (EditBoxInGlobalFocus()) {
2595 /* All input will in this case go to the focused editbox */
2596 if (_focused_window->window_class == WC_CONSOLE) {
2597 if (_focused_window->OnKeyPress(key, keycode) == ES_HANDLED) return;
2598 } else {
2599 if (_focused_window->HandleEditBoxKey(_focused_window->nested_focus->GetIndex(), key, keycode) == ES_HANDLED) return;
2600 }
2601 }
2602
2603 /* Call the event, start with the uppermost window, but ignore the toolbar. */
2604 for (Window *w : Window::IterateFromFront()) {
2605 if (w->window_class == WC_MAIN_TOOLBAR) continue;
2606 if (w->window_desc.hotkeys != nullptr) {
2607 int hotkey = w->window_desc.hotkeys->CheckMatch(keycode);
2608 if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return;
2609 }
2610 if (w->OnKeyPress(key, keycode) == ES_HANDLED) return;
2611 }
2612
2614 /* When there is no toolbar w is null, check for that */
2615 if (w != nullptr) {
2616 if (w->window_desc.hotkeys != nullptr) {
2617 int hotkey = w->window_desc.hotkeys->CheckMatch(keycode);
2618 if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return;
2619 }
2620 if (w->OnKeyPress(key, keycode) == ES_HANDLED) return;
2621 }
2622
2623 HandleGlobalHotkeys(key, keycode);
2624}
2625
2630{
2631 /* Call the event, start with the uppermost window. */
2632 for (Window *w : Window::IterateFromFront()) {
2633 if (w->OnCTRLStateChange() == ES_HANDLED) return;
2634 }
2635}
2636
2642/* virtual */ void Window::InsertTextString(WidgetID wid, const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end)
2643{
2644 QueryString *query = this->GetQueryString(wid);
2645 if (query == nullptr) return;
2646
2647 if (query->text.InsertString(str, marked, caret, insert_location, replacement_end) || marked) {
2648 this->SetWidgetDirty(wid);
2649 this->OnEditboxChanged(wid);
2650 }
2651}
2652
2659void HandleTextInput(const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end)
2660{
2661 if (!EditBoxInGlobalFocus()) return;
2662
2663 _focused_window->InsertTextString(_focused_window->window_class == WC_CONSOLE ? 0 : _focused_window->nested_focus->GetIndex(), str, marked, caret, insert_location, replacement_end);
2664}
2665
2673
2678static void HandleAutoscroll()
2679{
2680 if (_game_mode == GM_MENU || HasModalProgress()) return;
2682 if (_settings_client.gui.auto_scrolling == VA_MAIN_VIEWPORT_FULLSCREEN && !_fullscreen) return;
2683
2684 int x = _cursor.pos.x;
2685 int y = _cursor.pos.y;
2686 Window *w = FindWindowFromPt(x, y);
2687 if (w == nullptr || w->flags.Test(WindowFlag::DisableVpScroll)) return;
2689
2690 Viewport *vp = IsPtInWindowViewport(w, x, y);
2691 if (vp == nullptr) return;
2692
2693 x -= vp->left;
2694 y -= vp->top;
2695
2696 /* here allows scrolling in both x and y axis */
2697 /* If we succeed at scrolling in any direction, stop following a vehicle. */
2698 static const int SCROLLSPEED = 3;
2699 if (x - 15 < 0) {
2700 w->viewport->CancelFollow(*w);
2701 w->viewport->dest_scrollpos_x += ScaleByZoom((x - 15) * SCROLLSPEED, vp->zoom);
2702 } else if (15 - (vp->width - x) > 0) {
2703 w->viewport->CancelFollow(*w);
2704 w->viewport->dest_scrollpos_x += ScaleByZoom((15 - (vp->width - x)) * SCROLLSPEED, vp->zoom);
2705 }
2706 if (y - 15 < 0) {
2707 w->viewport->CancelFollow(*w);
2708 w->viewport->dest_scrollpos_y += ScaleByZoom((y - 15) * SCROLLSPEED, vp->zoom);
2709 } else if (15 - (vp->height - y) > 0) {
2710 w->viewport->CancelFollow(*w);
2711 w->viewport->dest_scrollpos_y += ScaleByZoom((15 - (vp->height - y)) * SCROLLSPEED, vp->zoom);
2712 }
2713}
2714
2715enum MouseClick : uint8_t {
2716 MC_NONE = 0,
2717 MC_LEFT,
2718 MC_RIGHT,
2719 MC_DOUBLE_LEFT,
2720 MC_HOVER,
2721};
2722
2723static constexpr int MAX_OFFSET_DOUBLE_CLICK = 5;
2724static constexpr int MAX_OFFSET_HOVER = 5;
2725
2727
2728const std::chrono::milliseconds TIME_BETWEEN_DOUBLE_CLICK(500);
2729
2730static void ScrollMainViewport(int x, int y)
2731{
2732 if (_game_mode != GM_MENU && _game_mode != GM_BOOTSTRAP) {
2733 Window *w = GetMainWindow();
2736 }
2737}
2738
2748static const int8_t scrollamt[16][2] = {
2749 { 0, 0},
2750 {-2, 0},
2751 { 0, -2},
2752 {-2, -1},
2753 { 2, 0},
2754 { 0, 0},
2755 { 2, -1},
2756 { 0, -2},
2757 { 0, 2},
2758 {-2, 1},
2759 { 0, 0},
2760 {-2, 0},
2761 { 2, 1},
2762 { 0, 2},
2763 { 2, 0},
2764 { 0, 0},
2765};
2766
2767static void HandleKeyScrolling()
2768{
2769 /*
2770 * Check that any of the dirkeys is pressed and that the focused window
2771 * doesn't have an edit-box as focused widget.
2772 */
2773 if (_dirkeys && !EditBoxInGlobalFocus()) {
2774 int factor = _shift_pressed ? 50 : 10;
2775
2776 if (_game_mode != GM_MENU && _game_mode != GM_BOOTSTRAP) {
2777 /* Key scrolling stops following a vehicle. */
2778 Window *main_window = GetMainWindow();
2779 main_window->viewport->CancelFollow(*main_window);
2780 }
2781
2782 ScrollMainViewport(scrollamt[_dirkeys][0] * factor, scrollamt[_dirkeys][1] * factor);
2783 }
2784}
2785
2786static void MouseLoop(MouseClick click, int mousewheel)
2787{
2788 /* World generation is multithreaded and messes with companies.
2789 * But there is no company related window open anyway, so _current_company is not used. */
2790 assert(HasModalProgress() || IsLocalCompany());
2791
2792 HandlePlacePresize();
2794
2795 if (VpHandlePlaceSizingDrag() == ES_HANDLED) return;
2796 if (HandleMouseDragDrop() == ES_HANDLED) return;
2797 if (HandleWindowDragging() == ES_HANDLED) return;
2798 if (HandleActiveWidget() == ES_HANDLED) return;
2799 if (HandleViewportScroll() == ES_HANDLED) return;
2800
2802
2803 bool scrollwheel_scrolling = _settings_client.gui.scrollwheel_scrolling == SWS_SCROLL_MAP && _cursor.wheel_moved;
2804 if (click == MC_NONE && mousewheel == 0 && !scrollwheel_scrolling) return;
2805
2806 int x = _cursor.pos.x;
2807 int y = _cursor.pos.y;
2808 Window *w = FindWindowFromPt(x, y);
2809 if (w == nullptr) return;
2810
2811 if (click != MC_HOVER && !MaybeBringWindowToFront(w)) return;
2812 Viewport *vp = IsPtInWindowViewport(w, x, y);
2813
2814 /* Don't allow any action in a viewport if either in menu or when having a modal progress window */
2815 if (vp != nullptr && (_game_mode == GM_MENU || HasModalProgress())) return;
2816
2817 if (mousewheel != 0) {
2818 /* Send mousewheel event to window, unless we're scrolling a viewport or the map */
2819 if (!scrollwheel_scrolling || (vp == nullptr && w->window_class != WC_SMALLMAP)) w->OnMouseWheel(mousewheel);
2820
2821 /* Dispatch a MouseWheelEvent for widgets if it is not a viewport */
2822 if (vp == nullptr) DispatchMouseWheelEvent(w, w->nested_root->GetWidgetFromPos(x - w->left, y - w->top), mousewheel);
2823 }
2824
2825 if (vp != nullptr) {
2826 if (scrollwheel_scrolling && !w->flags.Test(WindowFlag::DisableVpScroll)) {
2827 _scrolling_viewport = true;
2828 _cursor.fix_at = true;
2829 return;
2830 }
2831
2832 switch (click) {
2833 case MC_DOUBLE_LEFT:
2834 case MC_LEFT:
2835 if (HandleViewportClicked(vp, x, y)) return;
2838 _scrolling_viewport = true;
2839 _cursor.fix_at = false;
2840 return;
2841 }
2842 break;
2843
2844 case MC_RIGHT:
2847 _scrolling_viewport = true;
2850 DispatchRightClickEvent(w, x - w->left, y - w->top);
2851 return;
2852 }
2853 break;
2854
2855 default:
2856 break;
2857 }
2858 }
2859
2860 switch (click) {
2861 case MC_LEFT:
2862 case MC_DOUBLE_LEFT:
2863 DispatchLeftClickEvent(w, x - w->left, y - w->top, click == MC_DOUBLE_LEFT ? 2 : 1);
2864 return;
2865
2866 default:
2867 if (!scrollwheel_scrolling || w == nullptr || w->window_class != WC_SMALLMAP) break;
2868 /* We try to use the scrollwheel to scroll since we didn't touch any of the buttons.
2869 * Simulate a right button click so we can get started. */
2870 [[fallthrough]];
2871
2872 case MC_RIGHT:
2873 DispatchRightClickEvent(w, x - w->left, y - w->top);
2874 return;
2875
2876 case MC_HOVER:
2877 DispatchHoverEvent(w, x - w->left, y - w->top);
2878 break;
2879 }
2880
2881 /* We're not doing anything with 2D scrolling, so reset the value. */
2882 _cursor.h_wheel = 0.0f;
2883 _cursor.v_wheel = 0.0f;
2884 _cursor.wheel_moved = false;
2885}
2886
2891{
2892 /* World generation is multithreaded and messes with companies.
2893 * But there is no company related window open anyway, so _current_company is not used. */
2894 assert(HasModalProgress() || IsLocalCompany());
2895
2896 /* Handle sprite picker before any GUI interaction */
2897 if (_newgrf_debug_sprite_picker.mode == SPM_REDRAW && _input_events_this_tick == 0) {
2898 /* We are done with the last draw-frame, so we know what sprites we
2899 * clicked on. Reset the picker mode and invalidate the window. */
2902 }
2903
2904 static std::chrono::steady_clock::time_point double_click_time = {};
2905 static Point double_click_pos = {0, 0};
2906
2907 /* Mouse event? */
2908 MouseClick click = MC_NONE;
2910 click = MC_LEFT;
2911 if (std::chrono::steady_clock::now() <= double_click_time + TIME_BETWEEN_DOUBLE_CLICK &&
2912 double_click_pos.x != 0 && abs(_cursor.pos.x - double_click_pos.x) < MAX_OFFSET_DOUBLE_CLICK &&
2913 double_click_pos.y != 0 && abs(_cursor.pos.y - double_click_pos.y) < MAX_OFFSET_DOUBLE_CLICK) {
2914 click = MC_DOUBLE_LEFT;
2915 }
2916 double_click_time = std::chrono::steady_clock::now();
2917 double_click_pos = _cursor.pos;
2918 _left_button_clicked = true;
2920 } else if (_right_button_clicked) {
2921 _right_button_clicked = false;
2922 click = MC_RIGHT;
2924 }
2925
2926 int mousewheel = 0;
2927 if (_cursor.wheel) {
2928 mousewheel = _cursor.wheel;
2929 _cursor.wheel = 0;
2931 }
2932
2933 static std::chrono::steady_clock::time_point hover_time = {};
2934 static Point hover_pos = {0, 0};
2935
2937 if (!_cursor.in_window || click != MC_NONE || mousewheel != 0 || _left_button_down || _right_button_down ||
2938 hover_pos.x == 0 || abs(_cursor.pos.x - hover_pos.x) >= MAX_OFFSET_HOVER ||
2939 hover_pos.y == 0 || abs(_cursor.pos.y - hover_pos.y) >= MAX_OFFSET_HOVER) {
2940 hover_pos = _cursor.pos;
2941 hover_time = std::chrono::steady_clock::now();
2942 _mouse_hovering = false;
2943 } else if (!_mouse_hovering) {
2944 if (std::chrono::steady_clock::now() > hover_time + std::chrono::milliseconds(_settings_client.gui.hover_delay_ms)) {
2945 click = MC_HOVER;
2947 _mouse_hovering = true;
2948 hover_time = std::chrono::steady_clock::now();
2949 }
2950 }
2951 }
2952
2953 if (click == MC_LEFT && _newgrf_debug_sprite_picker.mode == SPM_WAIT_CLICK) {
2954 /* Mark whole screen dirty, and wait for the next realtime tick, when drawing is finished. */
2956 _newgrf_debug_sprite_picker.clicked_pixel = blitter->MoveTo(_screen.dst_ptr, _cursor.pos.x, _cursor.pos.y);
2958 _newgrf_debug_sprite_picker.mode = SPM_REDRAW;
2960 } else {
2961 MouseLoop(click, mousewheel);
2962 }
2963
2964 /* We have moved the mouse the required distance,
2965 * no need to move it at any later time. */
2966 _cursor.delta.x = 0;
2967 _cursor.delta.y = 0;
2968}
2969
2973static void CheckSoftLimit()
2974{
2975 if (_settings_client.gui.window_soft_limit == 0) return;
2976
2977 for (;;) {
2978 uint deletable_count = 0;
2979 Window *last_deletable = nullptr;
2980 for (Window *w : Window::IterateFromFront()) {
2981 if (w->window_class == WC_MAIN_WINDOW || IsVitalWindow(w) || w->flags.Test(WindowFlag::Sticky)) continue;
2982
2983 last_deletable = w;
2984 deletable_count++;
2985 }
2986
2987 /* We've not reached the soft limit yet. */
2988 if (deletable_count <= _settings_client.gui.window_soft_limit) break;
2989
2990 assert(last_deletable != nullptr);
2991 last_deletable->Close();
2992 }
2993}
2994
2999{
3000 /* World generation is multithreaded and messes with companies.
3001 * But there is no company related window open anyway, so _current_company is not used. */
3002 assert(HasModalProgress() || IsLocalCompany());
3003
3005
3006 /* Process scheduled window deletion. */
3008
3009 if (_input_events_this_tick != 0) {
3010 /* The input loop is called only once per GameLoop() - so we can clear the counter here */
3012 /* there were some inputs this tick, don't scroll ??? */
3013 return;
3014 }
3015
3016 /* HandleMouseEvents was already called for this tick */
3018}
3019
3024{
3025 for (Window *w : Window::Iterate()) {
3026 w->OnRealtimeTick(delta_ms);
3027 }
3028}
3029
3031static IntervalTimer<TimerWindow> window_interval(std::chrono::milliseconds(30), [](auto) {
3032 extern int _caret_timer;
3033 _caret_timer += 3;
3034 CursorTick();
3035
3036 HandleKeyScrolling();
3038 DecreaseWindowCounters();
3039});
3040
3042static IntervalTimer<TimerWindow> highlight_interval(std::chrono::milliseconds(450), [](auto) {
3044});
3045
3047static IntervalTimer<TimerWindow> white_border_interval(std::chrono::milliseconds(30), [](auto) {
3048 if (_network_dedicated) return;
3049
3050 for (Window *w : Window::Iterate()) {
3053 w->SetDirty();
3054 }
3055 }
3056});
3057
3062{
3063 static auto last_time = std::chrono::steady_clock::now();
3064 auto now = std::chrono::steady_clock::now();
3065 auto delta_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now - last_time);
3066
3067 if (delta_ms.count() == 0) return;
3068
3069 last_time = now;
3070
3073
3075
3077 CallWindowRealtimeTickEvent(delta_ms.count());
3078
3079 /* Process invalidations before anything else. */
3080 for (Window *w : Window::Iterate()) {
3084 }
3085
3086 /* Skip the actual drawing on dedicated servers without screen.
3087 * But still empty the invalidation queues above. */
3088 if (_network_dedicated) return;
3089
3091
3092 for (Window *w : Window::Iterate()) {
3093 /* Update viewport only if window is not shaded. */
3094 if (w->viewport != nullptr && !w->IsShaded()) UpdateViewportPosition(w, delta_ms.count());
3095 }
3097 /* Redraw mouse cursor in case it was hidden */
3098 DrawMouseCursor();
3099}
3100
3107{
3108 for (const Window *w : Window::Iterate()) {
3109 if (w->window_class == cls && w->window_number == number) w->SetDirty();
3110 }
3111}
3112
3120{
3121 for (const Window *w : Window::Iterate()) {
3122 if (w->window_class == cls && w->window_number == number) {
3123 w->SetWidgetDirty(widget_index);
3124 }
3125 }
3126}
3127
3133{
3134 for (const Window *w : Window::Iterate()) {
3135 if (w->window_class == cls) w->SetDirty();
3136 }
3137}
3138
3143{
3144 this->scheduled_resize = true;
3145}
3146
3151{
3152 /* Sometimes OnResize() resizes the window again, in which case we can reprocess immediately. */
3153 while (this->scheduled_resize) {
3154 this->scheduled_resize = false;
3155 this->OnResize();
3156 }
3157}
3158
3164void Window::InvalidateData(int data, bool gui_scope)
3165{
3166 this->SetDirty();
3167 if (!gui_scope) {
3168 /* Schedule GUI-scope invalidation for next redraw. */
3169 this->scheduled_invalidation_data.push_back(data);
3170 }
3171 this->OnInvalidateData(data, gui_scope);
3172}
3173
3178{
3179 for (int data : this->scheduled_invalidation_data) {
3180 if (this->window_class == WC_INVALID) break;
3181 this->OnInvalidateData(data, true);
3182 }
3183 this->scheduled_invalidation_data.clear();
3184}
3185
3190{
3191 if (!this->flags.Test(WindowFlag::Highlighted)) return;
3192
3193 for (const auto &pair : this->widget_lookup) {
3194 if (pair.second->IsHighlighted()) pair.second->SetDirty(this);
3195 }
3196}
3197
3224void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
3225{
3226 for (Window *w : Window::Iterate()) {
3227 if (w->window_class == cls && w->window_number == number) {
3228 w->InvalidateData(data, gui_scope);
3229 }
3230 }
3231}
3232
3241void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
3242{
3243 for (Window *w : Window::Iterate()) {
3244 if (w->window_class == cls) {
3245 w->InvalidateData(data, gui_scope);
3246 }
3247 }
3248}
3249
3254{
3255 for (Window *w : Window::Iterate()) {
3256 w->OnGameTick();
3257 }
3258}
3259
3267{
3268 /* Note: the container remains stable, even when deleting windows. */
3269 for (Window *w : Window::Iterate()) {
3271 !w->flags.Test(WindowFlag::Sticky)) { // do not delete windows which are 'pinned'
3272
3273 w->Close();
3274 }
3275 }
3276}
3277
3286{
3287 /* Note: the container remains stable, even when closing windows. */
3288 for (Window *w : Window::Iterate()) {
3290 w->Close();
3291 }
3292 }
3293}
3294
3299{
3301 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_NEWS_DELETED); // invalidate the statusbar
3302 InvalidateWindowData(WC_MESSAGE_HISTORY, 0); // invalidate the message history
3303 CloseWindowById(WC_NEWS_WINDOW, 0); // close newspaper or general message window if shown
3304}
3305
3311{
3312 /* Note: the container remains stable, even when deleting windows. */
3313 for (Window *w : Window::Iterate()) {
3315 w->Close();
3316 }
3317 }
3318
3319 for (const Window *w : Window::Iterate()) w->SetDirty();
3320}
3321
3328
3329void ReInitWindow(Window *w, bool zoom_changed)
3330{
3331 if (w == nullptr) return;
3332 if (zoom_changed) {
3333 w->nested_root->AdjustPaddingForZoom();
3335 }
3336 w->ReInit();
3337}
3338
3340void ReInitAllWindows(bool zoom_changed)
3341{
3343 NWidgetLeaf::InvalidateDimensionCache(); // Reset cached sizes of several widgets.
3344 NWidgetScrollbar::InvalidateDimensionCache();
3345
3347
3348 /* When _gui_zoom has changed, we need to resize toolbar and statusbar first,
3349 * so EnsureVisibleCaption uses the updated size information. */
3350 ReInitWindow(FindWindowById(WC_MAIN_TOOLBAR, 0), zoom_changed);
3351 ReInitWindow(FindWindowById(WC_STATUS_BAR, 0), zoom_changed);
3352 for (Window *w : Window::Iterate()) {
3353 if (w->window_class == WC_MAIN_TOOLBAR || w->window_class == WC_STATUS_BAR) continue;
3354 ReInitWindow(w, zoom_changed);
3355 }
3356
3359
3360 /* Make sure essential parts of all windows are visible */
3361 RelocateAllWindows(_screen.width, _screen.height);
3363}
3364
3372static int PositionWindow(Window *w, WindowClass clss, int setting)
3373{
3374 if (w == nullptr || w->window_class != clss) {
3375 w = FindWindowById(clss, 0);
3376 }
3377 if (w == nullptr) return 0;
3378
3379 int old_left = w->left;
3380 switch (setting) {
3381 case 1: w->left = (_screen.width - w->width) / 2; break;
3382 case 2: w->left = _screen.width - w->width; break;
3383 default: w->left = 0; break;
3384 }
3385 if (w->viewport != nullptr) w->viewport->left += w->left - old_left;
3386 AddDirtyBlock(0, w->top, _screen.width, w->top + w->height); // invalidate the whole row
3387 return w->left;
3388}
3389
3396{
3397 Debug(misc, 5, "Repositioning Main Toolbar...");
3399}
3400
3407{
3408 Debug(misc, 5, "Repositioning statusbar...");
3410}
3411
3418{
3419 Debug(misc, 5, "Repositioning news message...");
3421}
3422
3429{
3430 Debug(misc, 5, "Repositioning network chat window...");
3432}
3433
3434
3441{
3442 for (const Window *w : Window::Iterate()) {
3443 if (w->viewport != nullptr && w->viewport->follow_vehicle == from_index) {
3444 w->viewport->follow_vehicle = to_index;
3445 w->SetDirty();
3446 }
3447 }
3448}
3449
3450
3456void RelocateAllWindows(int neww, int newh)
3457{
3459
3460 /* Reposition toolbar then status bar before other all windows. */
3461 if (Window *wt = FindWindowById(WC_MAIN_TOOLBAR, 0); wt != nullptr) {
3462 ResizeWindow(wt, std::min<uint>(neww, _toolbar_width) - wt->width, 0, false);
3463 wt->left = PositionMainToolbar(wt);
3464 }
3465
3466 if (Window *ws = FindWindowById(WC_STATUS_BAR, 0); ws != nullptr) {
3467 ResizeWindow(ws, std::min<uint>(neww, _toolbar_width) - ws->width, 0, false);
3468 ws->top = newh - ws->height;
3469 ws->left = PositionStatusbar(ws);
3470 }
3471
3472 for (Window *w : Window::Iterate()) {
3473 int left, top;
3474 /* XXX - this probably needs something more sane. For example specifying
3475 * in a 'backup'-desc that the window should always be centered. */
3476 switch (w->window_class) {
3477 case WC_MAIN_WINDOW:
3478 case WC_BOOTSTRAP:
3479 case WC_HIGHSCORE:
3480 case WC_ENDSCREEN:
3481 ResizeWindow(w, neww, newh);
3482 continue;
3483
3484 case WC_MAIN_TOOLBAR:
3485 case WC_STATUS_BAR:
3486 continue;
3487
3488 case WC_NEWS_WINDOW:
3489 top = newh - w->height;
3490 left = PositionNewsMessage(w);
3491 break;
3492
3494 ResizeWindow(w, std::min<uint>(neww, _toolbar_width) - w->width, 0, false);
3495
3496 top = newh - w->height - FindWindowById(WC_STATUS_BAR, 0)->height;
3497 left = PositionNetworkChatWindow(w);
3498 break;
3499
3500 case WC_CONSOLE:
3501 IConsoleResize(w);
3502 continue;
3503
3504 default: {
3505 if (w->flags.Test(WindowFlag::Centred)) {
3506 top = (newh - w->height) >> 1;
3507 left = (neww - w->width) >> 1;
3508 break;
3509 }
3510
3511 left = w->left;
3512 if (left + (w->width >> 1) >= neww) left = neww - w->width;
3513 if (left < 0) left = 0;
3514
3515 top = w->top;
3516 if (top + (w->height >> 1) >= newh) top = newh - w->height;
3517 break;
3518 }
3519 }
3520
3521 EnsureVisibleCaption(w, left, top);
3522 }
3523}
3524
3529void PickerWindowBase::Close([[maybe_unused]] int data)
3530{
3532 this->Window::Close();
3533}
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Flip(Tvalue_type value)
Flip the value-th bit.
constexpr Timpl & Set()
Set all bits.
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
constexpr Timpl & Reset(Tvalue_type value)
Reset the value-th bit.
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
Definition factory.hpp:138
How all blitters should look like.
Definition base.hpp:29
virtual void * MoveTo(void *video, int x, int y)=0
Move the destination pointer the requested amount x and y, keeping in mind any pitch and bpp of the r...
Enum-as-bit-set wrapper.
static void NewEvent(class ScriptEvent *event)
Queue a new event for a Game Script.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
Baseclass for nested widgets.
virtual void SetDirty(const Window *w) const
Mark the widget as 'dirty' (in need of repaint).
Definition widget.cpp:905
WidgetType type
Type of the widget / nested widget.
int pos_x
Horizontal position of top-left corner of the widget in the window.
Base class for a 'real' widget.
bool IsDisabled() const
Return whether the widget is disabled.
WidgetID GetIndex() const
Get the WidgetID of this nested widget.
Definition widget.cpp:1234
NWidgetDisplayFlags disp_flags
Flags that affect display and interaction with the widget.
WidgetID GetScrollbarIndex() const
Get the WidgetID of this nested widget's scrollbar.
Definition widget.cpp:1243
StringID GetToolTip() const
Get the tool tip of the nested widget.
Definition widget.cpp:1207
void SetLowered(bool lowered)
Lower or raise the widget.
static void InvalidateDimensionCache()
Reset the cached dimensions.
Definition widget.cpp:2664
static Dimension resizebox_dimension
Cached size of a resizebox widget.
static Dimension closebox_dimension
Cached size of a closebox widget.
Nested widget to display and control a scrollbar in a window.
int shown_plane
Plane being displayed (for NWID_SELECTION only).
bool SetDisplayedPlane(int plane)
Select which plane to show (for NWID_SELECTION only).
Definition widget.cpp:1410
static void Reset(PerformanceElement elem)
Store the previous accumulator value and reset for a new cycle of accumulating measurements.
RAII class for measuring simple elements of performance.
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:3529
Scrollbar data structure.
size_type GetCapacity() const
Gets the number of visible elements of the scrollbar.
bool UpdatePosition(int difference, ScrollbarStepping unit=SS_SMALL)
Updates the position of the first visible element by the given amount.
bool SetPosition(size_type position)
Sets the position of the first visible element.
size_type GetCount() const
Gets the number of elements in the list.
static bool Elapsed(TElapsed value)
Called when time for this timer elapsed.
virtual void EditBoxLostFocus()
An edit box lost the input focus.
static VideoDriver * GetInstance()
Get the currently active instance of the video driver.
virtual void EditBoxGainedFocus()
An edit box gained the input focus.
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:29
Functions related to companies.
bool IsLocalCompany()
Is the current company the local company?
static constexpr Owner INVALID_OWNER
An invalid owner.
Console functions used outside of the console code.
void IConsoleClose()
Close the in-game console.
void IConsoleResize(Window *w)
Change the size of the in-game console window after the screen size changed, or the window state chan...
GUI related functions in the console.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
Functions related to depots.
void InitDepotWindowBlockSizes()
Set the size of the blocks in the window so we can be sure that they are big enough for the vehicle s...
Functions related to errors.
void UnshowCriticalError()
Unshow the critical error.
void ShowFirstError()
Show the first error of the queue.
Factory to 'query' all available blitters.
@ NO_DIRECTORY
A path without any base directory.
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:77
void ProcessPendingPerformanceMeasurements()
This drains the PFE_SOUND measurement data queue into _pf_data.
Types for recording game performance data.
@ PFE_DRAWING
Speed of drawing world and GUI.
@ PFE_DRAWWORLD
Time spent drawing world viewports in GUI.
Base functions for all Games.
bool _shift_pressed
Is Shift pressed?
Definition gfx.cpp:39
bool _left_button_down
Is left mouse button pressed?
Definition gfx.cpp:41
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:38
uint8_t _dirkeys
1 = left, 2 = up, 4 = right, 8 = down
Definition gfx.cpp:34
bool _left_button_clicked
Is left mouse button clicked?
Definition gfx.cpp:42
bool _right_button_clicked
Is right mouse button clicked?
Definition gfx.cpp:44
bool _right_button_down
Is right mouse button pressed?
Definition gfx.cpp:43
int _gui_scale
GUI scale, 100 is 100%.
Definition gfx.cpp:63
Functions related to the gfx engine.
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:243
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:294
std::unique_ptr< NWidgetBase > MakeWindowNWidgetTree(std::span< const NWidgetPart > nwid_parts, NWidgetStacked **shade_select)
Make a nested widget tree for a window from a parts array.
Definition widget.cpp:3378
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition window.cpp:943
void AddDirtyBlock(int left, int top, int right, int bottom)
Extend the internal _invalid_rect rectangle to contain the rectangle defined by the given parameters.
Definition gfx.cpp:1467
void DrawDirtyBlocks()
Repaints the rectangle blocks which are marked as 'dirty'.
Definition gfx.cpp:1403
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1500
Hotkey related functions.
Types related to reading/writing '*.ini' files.
static debug_inline TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition map_func.h:403
constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
Checks if a value is between a window started at some base point.
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
constexpr int RoundDivSU(int a, uint b)
Computes round(a / b) for signed a and unsigned b.
constexpr uint Ceil(uint a, uint b)
Computes ceil(a / b) * b for non-negative a and b.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
void GuiShowTooltips(Window *parent, EncodedString &&text, TooltipCloseCondition close_tooltip)
Shows a tooltip.
Definition misc_gui.cpp:690
bool _networking
are we in networking mode?
Definition network.cpp:65
bool _network_dedicated
are we a dedicated server?
Definition network.cpp:68
Basic functions/variables used all over the place.
void NetworkDrawChatMessage()
Draw the chat message-box.
void NetworkReInitChatBoxSize()
Initialize all font-dependent chat box sizes.
void NetworkUndrawChatMessage()
Hide the chatbox.
Network functions used by other parts of OpenTTD.
Functions/types related to NewGRF debugging.
NewGrfDebugSpritePicker _newgrf_debug_sprite_picker
The sprite picker.
uint8_t valid
Bits indicating what variable is valid (for each bit, 0 is invalid, 1 is valid).
Functions related to news.
void InitNewsItemStructs()
Initialize the news-items data structures.
Definition news_gui.cpp:716
@ WID_OSK_CANCEL
Cancel key.
Definition osk_widget.h:17
@ WID_OSK_OK
Ok key.
Definition osk_widget.h:18
Functions related to modal progress.
bool HasModalProgress()
Check if we are currently in a modal progress state.
Definition progress.h:17
Base for the GUIs that have an edit box in them.
A number of safeguards to prevent using unsafe methods.
void IniLoadWindowSettings(IniFile &ini, const char *grpname, void *desc)
Load a WindowDesc from config.
Definition settings.cpp:880
void IniSaveWindowSettings(IniFile &ini, const char *grpname, void *desc)
Save a WindowDesc to config.
Definition settings.cpp:891
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:57
Functions related to setting/changing the settings.
Types related to global configuration settings.
@ VSM_VIEWPORT_RMB_FIXED
Viewport moves with mouse movement on holding right mouse button, cursor position is fixed.
@ VSM_MAP_RMB_FIXED
Map moves with mouse movement on holding right mouse button, cursor position is fixed.
@ VSM_MAP_LMB
Map moves with mouse movement on holding left mouse button, cursor moves.
@ SWS_SCROLL_MAP
Scroll wheel scrolls the map.
bool ScrollMainWindowTo(int x, int y, int z, bool instant)
Scrolls the main window to given coordinates.
Functions, definitions and such used only by the GUI.
@ SBI_NEWS_DELETED
abort current news display (active news were deleted)
Definition of base types and functions in a cross-platform compatible way.
bool StrEmpty(const char *s)
Check if a string buffer is empty.
Definition string_func.h:57
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:426
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:56
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
@ TD_RTL
Text is written right-to-left by default.
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
GUISettings gui
settings related to the GUI
bool fix_at
mouse is moving, but cursor is not (used for scrolling)
Definition gfx_type.h:127
Point pos
logical mouse position
Definition gfx_type.h:124
bool in_window
mouse inside this window, determines drawing logic
Definition gfx_type.h:146
int wheel
mouse wheel movement
Definition gfx_type.h:126
Point delta
relative mouse movement in this tick
Definition gfx_type.h:125
Data about how and where to blit pixels.
Definition gfx_type.h:156
uint8_t window_snap_radius
windows snap at each other if closer than this
uint16_t hover_delay_ms
time required to activate a hover event, in milliseconds
uint8_t auto_scrolling
scroll when moving mouse to the edge (see ViewportAutoscrolling)
uint8_t scroll_mode
viewport scroll mode
RightClickClose right_click_wnd_close
close window with right click
uint8_t window_soft_limit
soft limit of maximum number of non-stickied non-vital windows (0 = no limit)
uint8_t toolbar_pos
position of toolbars, 0=left, 1=center, 2=right
uint8_t statusbar_pos
position of statusbar, 0=left, 1=center, 2=right
uint8_t scrollwheel_scrolling
scrolling using the scroll wheel?
List of hotkeys for a window.
Definition hotkeys.h:37
int CheckMatch(uint16_t keycode, bool global_only=false) const
Check if a keycode is bound to something.
Definition hotkeys.cpp:309
Ini file that supports both loading and saving.
Definition ini_type.h:88
bool SaveToDisk(const std::string &filename)
Save the Ini file's data to the disk.
Definition ini.cpp:42
void LoadFromDisk(const std::string &filename, Subdirectory subdir)
Load the Ini file's data from the disk.
Definition ini_load.cpp:186
NewGrfDebugSpritePickerMode mode
Current state.
void * clicked_pixel
Clicked pixel (pointer to blitter buffer)
std::vector< SpriteID > sprites
Sprites found.
Coordinates of a point in 2D.
static Titem * Get(auto index)
Returns Titem with given index.
Data stored about a string that can be modified in the GUI.
int ok_button
Widget button of parent window to simulate when pressing OK in OSK.
static const int ACTION_DESELECT
Deselect editbox.
int cancel_button
Widget button of parent window to simulate when pressing CANCEL in OSK.
ptrdiff_t GetCharAtPosition(const Window *w, WidgetID wid, const Point &pt) const
Get the character that is rendered at a position.
Definition misc_gui.cpp:848
Rect GetBoundingRect(const Window *w, WidgetID wid, const char *from, const char *to) const
Get the bounding rectangle for a range of the query string.
Definition misc_gui.cpp:818
static const int ACTION_NOTHING
Nothing.
static const int ACTION_CLEAR
Clear editbox.
Point GetCaretPosition(const Window *w, WidgetID wid) const
Get the current caret position.
Definition misc_gui.cpp:790
Specification of a rectangle with absolute coordinates of all edges.
int Height() const
Get height of Rect.
uint step_height
Step-size of height resize changes.
Definition window_gui.h:213
uint step_width
Step-size of width resize changes.
Definition window_gui.h:212
Helper/buffer for input fields.
void UpdateSize()
Update Textbuf type with its actual physical character and screenlength Get the count of characters i...
Definition textbuf.cpp:445
void DeleteAll()
Delete every character in the textbuffer.
Definition textbuf.cpp:112
bool InsertString(const char *str, bool marked, const char *caret=nullptr, const char *insert_location=nullptr, const char *replacement_end=nullptr)
Insert a string into the text buffer.
Definition textbuf.cpp:159
const char * GetText() const
Get the current text.
Definition textbuf.cpp:286
Window * GetCallbackWnd()
Get the window that started the current highlighting.
WindowClass window_class
The WindowClass of the window that is responsible for the selection mode.
void Reset()
Reset tile highlighting.
Point selend
The location where the drag currently ends.
WindowNumber window_number
The WindowNumber of the window that is responsible for the selection mode.
Vehicle data structure.
int32_t z_pos
z coordinate.
int32_t y_pos
y coordinate.
int32_t x_pos
x coordinate.
void CancelFollow(const Window &viewport_window)
Cancel viewport vehicle following, and raise follow location widget if needed.
int32_t dest_scrollpos_y
Current destination y coordinate to display (virtual screen coordinate of topleft corner of the viewp...
Definition window_gui.h:256
int32_t dest_scrollpos_x
Current destination x coordinate to display (virtual screen coordinate of topleft corner of the viewp...
Definition window_gui.h:255
VehicleID follow_vehicle
VehicleID to follow if following a vehicle, VehicleID::Invalid() otherwise.
Definition window_gui.h:252
Data structure for viewport, display of a part of the world.
int top
Screen coordinate top edge of the viewport.
int width
Screen width of the viewport.
ZoomLevel zoom
The zoom level of the viewport.
int left
Screen coordinate left edge of the viewport.
int height
Screen height of the viewport.
High level window description.
Definition window_gui.h:168
int16_t GetDefaultWidth() const
Determine default width of window.
Definition window.cpp:134
static void SaveToConfig()
Save all WindowDesc settings to _windows_file.
Definition window.cpp:174
int16_t pref_width
User-preferred width of the window. Zero if unset.
Definition window_gui.h:187
const WindowPosition default_pos
Preferred position of the window.
Definition window_gui.h:178
bool pref_sticky
Preferred stickyness.
Definition window_gui.h:186
int16_t pref_height
User-preferred height of the window. Zero if unset.
Definition window_gui.h:188
int16_t GetDefaultHeight() const
Determine default height of window.
Definition window.cpp:144
const int16_t default_height_trad
Preferred initial height of the window (pixels at 1x zoom).
Definition window_gui.h:198
const int16_t default_width_trad
Preferred initial width of the window (pixels at 1x zoom).
Definition window_gui.h:197
WindowDesc(WindowPosition default_pos, const char *ini_key, int16_t def_width_trad, int16_t def_height_trad, WindowClass window_class, WindowClass parent_class, WindowDefaultFlags flags, const std::span< const NWidgetPart > nwid_parts, HotkeyList *hotkeys=nullptr, const std::source_location location=std::source_location::current())
Window description constructor.
Definition window.cpp:105
const WindowClass cls
Class of the window,.
Definition window_gui.h:179
const char * ini_key
Key to store window defaults in openttd.cfg. nullptr if nothing shall be stored.
Definition window_gui.h:181
const WindowDefaultFlags flags
Flags.
Definition window_gui.h:182
static void LoadFromConfig()
Load all WindowDesc settings from _windows_file.
Definition window.cpp:152
const WindowClass parent_cls
Class of the parent window.
Definition window_gui.h:180
const HotkeyList * hotkeys
Hotkeys for the window.
Definition window_gui.h:184
const std::span< const NWidgetPart > nwid_parts
Span of nested widget parts describing the window.
Definition window_gui.h:183
Number to differentiate different windows of the same class.
Iterator to iterate all valid Windows.
Definition window_gui.h:865
Data structure for an opened window.
Definition window_gui.h:274
virtual const struct Textbuf * GetFocusedTextbuf() const
Get the current input text buffer.
Definition window.cpp:362
void SetWidgetHighlight(WidgetID widget_index, TextColour highlighted_colour)
Sets the highlighted status of a widget.
Definition window.cpp:239
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition window.cpp:955
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1050
virtual void OnInvalidateData(int data=0, bool gui_scope=true)
Some data on this window has become invalid.
Definition window_gui.h:783
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1736
std::map< WidgetID, QueryString * > querystrings
QueryString associated to WWT_EDITBOX widgets.
Definition window_gui.h:321
virtual void ApplyDefaults()
Read default values from WindowDesc configuration an apply them to the window.
Definition window.cpp:191
uint8_t white_border_timer
Timer value of the WindowFlag::WhiteBorder for flags.
Definition window_gui.h:308
NWidgetStacked * shade_select
Selection widget (NWID_SELECTION) to use for shading the window. If nullptr, window cannot shade.
Definition window_gui.h:324
void InitializePositionSize(int x, int y, int min_width, int min_height)
Set the position and smallest size of the window.
Definition window.cpp:1405
Dimension unshaded_size
Last known unshaded size (only valid while shaded).
Definition window_gui.h:325
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition window.cpp:3164
virtual EventState OnKeyPress(char32_t key, uint16_t keycode)
A key has been pressed.
Definition window_gui.h:649
Window * parent
Parent window.
Definition window_gui.h:329
AllWindows< false > IterateFromBack
Iterate all windows in Z order from back to front.
Definition window_gui.h:924
virtual ~Window()
Remove window and all its child windows from the window stack.
Definition window.cpp:1087
void RaiseWidget(WidgetID widget_index)
Marks a widget as raised.
Definition window_gui.h:470
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:554
uint8_t timeout_timer
Timer value of the WindowFlag::Timeout for flags.
Definition window_gui.h:307
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:502
WidgetID mouse_capture_widget
ID of current mouse capture widget (e.g. dragged scrollbar). -1 if no widget has mouse capture.
Definition window_gui.h:327
virtual void OnGameTick()
Called once per (game) tick.
Definition window_gui.h:736
virtual void ShowNewGRFInspectWindow() const
Show the NewGRF inspection window.
Definition window_gui.h:858
virtual bool OnRightClick(Point pt, WidgetID widget)
A click with the right mouse button has been made on the window.
Definition window_gui.h:676
void ProcessScheduledInvalidations()
Process all scheduled invalidations.
Definition window.cpp:3177
void CloseChildWindows(WindowClass wc=WC_INVALID) const
Close all children a window might have in a head-recursive manner.
Definition window.cpp:1038
ResizeInfo resize
Resize information.
Definition window_gui.h:315
void UnfocusFocusedWidget()
Makes no widget on this window have focus.
Definition window.cpp:467
virtual void OnMouseLoop()
Called for every mouse loop run, which is at least once per (game) tick.
Definition window_gui.h:731
void SetShaded(bool make_shaded)
Set the shaded state of the window to make_shaded.
Definition window.cpp:998
int scale
Scale of this window – used to determine how to resize.
Definition window_gui.h:305
void ScheduleResize()
Mark this window as resized and in need of OnResize() event.
Definition window.cpp:3142
virtual void OnPaint()
The window must be repainted.
Definition window_gui.h:594
virtual void OnDragDrop(Point pt, WidgetID widget)
A dragged 'object' has been released.
Definition window_gui.h:705
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1726
WindowDesc & window_desc
Window description.
Definition window_gui.h:300
WindowClass window_class
Window class.
Definition window_gui.h:302
virtual void OnRealtimeTick(uint delta_ms)
Called periodically.
Definition window_gui.h:741
AllWindows< true > IterateFromFront
Iterate all windows in Z order from front to back.
Definition window_gui.h:925
ViewportData * viewport
Pointer to viewport data, if present.
Definition window_gui.h:319
void SetWhiteBorder()
Set the timeout flag of the window and initiate the timer.
Definition window_gui.h:365
bool SetFocusedWidget(WidgetID widget_index)
Set focus within this window to the given widget.
Definition window.cpp:483
virtual void OnFocusLost(bool closing)
The window has lost focus.
Definition window.cpp:519
virtual void OnDropdownClose(Point pt, WidgetID widget, int index, bool instant_close)
A dropdown window associated to this window has been closed.
Definition window.cpp:284
static std::vector< Window * > closed_windows
List of closed windows to delete.
Definition window_gui.h:276
void RaiseButtons(bool autoraise=false)
Raise the buttons of the window.
Definition window.cpp:528
virtual Point OnInitialPosition(int16_t sm_width, int16_t sm_height, int window_number)
Compute the initial position of the window.
Definition window.cpp:1714
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
Definition window_gui.h:317
virtual void OnDropdownSelect(WidgetID widget, int index)
A dropdown option associated to this window has been selected.
Definition window_gui.h:760
virtual void OnMouseWheel(int wheel)
The mouse wheel has been turned.
Definition window_gui.h:725
virtual Point GetCaretPosition() const
Get the current caret position if an edit box has the focus.
Definition window.cpp:375
int left
x position of left edge of the window
Definition window_gui.h:310
bool IsShaded() const
Is window shaded currently?
Definition window_gui.h:558
Window * FindChildWindow(WindowClass wc=WC_INVALID) const
Find the Window whose parent pointer points to this window.
Definition window.cpp:1025
void SetTimeout()
Set the timeout flag of the window and initiate the timer.
Definition window_gui.h:356
const NWidgetCore * nested_focus
Currently focused nested widget, or nullptr if no nested widget has focus.
Definition window_gui.h:320
virtual void OnEditboxChanged(WidgetID widget)
The text in an editbox has been edited.
Definition window_gui.h:768
void UpdateQueryStringSize()
Update size of all QueryStrings of this window.
Definition window.cpp:351
virtual void OnScroll(Point delta)
Handle the request for (viewport) scrolling.
Definition window_gui.h:711
int top
y position of top edge of the window
Definition window_gui.h:311
virtual void OnClick(Point pt, WidgetID widget, int click_count)
A click with the left mouse button has been made on the window.
Definition window_gui.h:667
const QueryString * GetQueryString(WidgetID widnum) const
Return the querystring associated to a editbox.
Definition window.cpp:331
WidgetLookup widget_lookup
Indexed access to the nested widget tree. Do not access directly, use Window::GetWidget() instead.
Definition window_gui.h:323
virtual ptrdiff_t GetTextCharacterAtPosition(const Point &pt) const
Get the character that is rendered at a position by the focused edit box.
Definition window.cpp:406
std::vector< int > scheduled_invalidation_data
Data of scheduled OnInvalidateData() calls.
Definition window_gui.h:283
void InitializeData(WindowNumber window_number)
Initializes the data (except the position and initial size) of a new Window.
Definition window.cpp:1367
virtual void OnMouseOver(Point pt, WidgetID widget)
The mouse is currently moving over the window or has just moved outside of the window.
Definition window_gui.h:719
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition window.cpp:1759
int GetRowFromWidget(int clickpos, WidgetID widget, int padding, int line_height=-1) const
Compute the row of a widget that a user clicked in.
Definition window.cpp:210
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:973
virtual bool OnTooltip(Point pt, WidgetID widget, TooltipCloseCondition close_cond)
Event to display a custom tooltip.
Definition window_gui.h:691
void LowerWidget(WidgetID widget_index)
Marks a widget as lowered.
Definition window_gui.h:461
virtual EventState OnCTRLStateChange()
The state of the control key has changed.
Definition window_gui.h:658
void ProcessScheduledResize()
Process scheduled OnResize() event.
Definition window.cpp:3150
EventState HandleEditBoxKey(WidgetID wid, char32_t key, uint16_t keycode)
Process keypress for editbox widget.
Definition window.cpp:2484
virtual void InsertTextString(WidgetID wid, const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end)
Insert a text string at the cursor position into the edit box widget.
Definition window.cpp:2642
virtual void OnMouseDrag(Point pt, WidgetID widget)
An 'object' is being dragged at the provided position, highlight the target if possible.
Definition window_gui.h:698
void HandleButtonClick(WidgetID widget)
Do all things to make a button look clicked and mark it to be unclicked in a few ticks.
Definition window.cpp:593
virtual void OnResize()
Called after the window got resized.
Definition window_gui.h:753
virtual void OnFocus()
The window has gained focus.
Definition window.cpp:511
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1749
virtual void OnTimeout()
Called when this window's timeout has been reached.
Definition window_gui.h:746
WindowFlags flags
Window flags.
Definition window_gui.h:301
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:311
void ProcessHighlightedInvalidations()
Process all invalidation of highlighted widgets.
Definition window.cpp:3189
virtual Rect GetTextBoundingRect(const char *from, const char *to) const
Get the bounding rectangle for a text range if an edit box has the focus.
Definition window.cpp:391
virtual EventState OnHotkey(int hotkey)
A hotkey has been pressed.
Definition window.cpp:568
static void DeleteClosedWindows()
Delete all closed windows.
Definition window.cpp:65
std::unique_ptr< NWidgetBase > nested_root
Root of the nested tree.
Definition window_gui.h:322
bool scheduled_resize
Set if window has been resized.
Definition window_gui.h:284
bool IsWidgetHighlighted(WidgetID widget_index) const
Gets the highlighted status of a widget.
Definition window.cpp:269
void DisableAllWidgetHighlight()
Disable the highlighted status of all widgets.
Definition window.cpp:221
virtual void OnPlacePresize(Point pt, TileIndex tile)
The user moves over the map when a tile highlight mode has been set when the special mouse mode has b...
Definition window_gui.h:842
AllWindows< false > Iterate
Iterate all windows in whatever order is easiest.
Definition window_gui.h:923
int height
Height of the window (number of pixels down in y direction)
Definition window_gui.h:313
virtual void OnHover(Point pt, WidgetID widget)
The mouse is hovering over a widget in the window, perform an action for it.
Definition window_gui.h:683
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:312
virtual void OnInit()
Notification that the nested widget tree gets initialized.
Definition window_gui.h:577
virtual void FindWindowPlacementAndResize(int def_width, int def_height)
Resize window towards the default size.
Definition window.cpp:1423
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:303
std::vector< WindowDesc * > * _window_descs
List of WindowDescs.
Definition window.cpp:99
@ HKPR_NOT_HANDLED
Key does not affect editboxes.
@ HKPR_CANCEL
Escape key pressed.
@ HKPR_EDITING
Textbuf content changed.
@ HKPR_CONFIRM
Return or enter key pressed.
@ HKPR_CURSOR
Non-text change, e.g. cursor position.
Functions related to tile highlights.
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows).
void UpdateTileSelection()
Updates tile highlighting for all cases.
Definition of Interval and OneShot timers.
Definition of the Window system.
uint _toolbar_width
Width of the toolbar, shared by statusbar.
Stuff related to the (main) toolbar.
Base class for all vehicles.
Base of all video drivers.
Viewport * IsPtInWindowViewport(const Window *w, int x, int y)
Is a xy position inside the viewport of the window?
Definition viewport.cpp:413
void UpdateViewportPosition(Window *w, uint32_t delta_ms)
Update the viewport position being displayed.
Functions related to (drawing on) viewports.
void SetupWidgetDimensions()
Set up pre-scaled versions of Widget Dimensions.
Definition widget.cpp:79
WidgetID GetWidgetFromPos(const Window *w, int x, int y)
Returns the index for the widget located at the given position relative to the window.
Definition widget.cpp:281
void ScrollbarClickHandler(Window *w, NWidgetCore *nw, int x, int y)
Special handling for the scrollbar widget type.
Definition widget.cpp:257
static RectPadding ScaleGUITrad(const RectPadding &r)
Scale a RectPadding to GUI zoom level.
Definition widget.cpp:48
WidgetType
Window widget types, nested widget types, and nested widget part types.
Definition widget_type.h:36
@ NWID_BUTTON_DROPDOWN
Button with a drop-down.
Definition widget_type.h:73
@ WWT_EDITBOX
a textbox for typing
Definition widget_type.h:61
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition widget_type.h:56
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition widget_type.h:54
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:51
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:75
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:59
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:38
@ WWT_LAST
Last Item. use WIDGETS_END to fill up padding!!
Definition widget_type.h:62
@ NWID_HSCROLLBAR
Horizontal scrollbar.
Definition widget_type.h:74
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:58
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:55
@ WWT_DEBUGBOX
NewGRF debug box (at top-right of a window, between WWT_CAPTION and WWT_SHADEBOX)
Definition widget_type.h:53
@ DropdownClosed
Dropdown menu of the dropdown widget has closed.
@ ScrollbarDown
Down-button is lowered bit.
@ ScrollbarUp
Up-button is lowered bit.
@ DropdownActive
Dropdown menu of the button dropdown widget is active.
@ SZSP_HORIZONTAL
Display plane with zero size vertically, and filling and resizing horizontally.
@ ST_RESIZE
Resize the nested widget tree.
@ ST_SMALLEST
Initialize nested widget tree to smallest size. Also updates current_x and current_y.
int PositionStatusbar(Window *w)
(Re)position statusbar window at the screen.
Definition window.cpp:3406
static void PreventHiding(int *nx, int *ny, const Rect &rect, const Window *v, int px, PreventHideDirection dir)
Do not allow hiding of the rectangle with base coordinates nx and ny behind window v.
Definition window.cpp:1948
static bool _dragging_window
A window is being dragged or resized.
Definition window.cpp:2082
void CloseConstructionWindows()
Close all windows that are used for construction of vehicle etc.
Definition window.cpp:3310
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition window.cpp:1143
static Point LocalGetWindowPlacement(const WindowDesc &desc, int16_t sm_width, int16_t sm_height, int window_number)
Compute the position of the top-left corner of a new window that is opened.
Definition window.cpp:1655
Window * GetMainWindow()
Get the main window, i.e.
Definition window.cpp:1130
static Point _drag_delta
delta between mouse cursor and upper left corner of dragged window
Definition window.cpp:52
static bool MayBeShown(const Window *w)
Returns whether a window may be shown or not.
Definition window.cpp:832
void CloseCompanyWindows(CompanyID id)
Close all windows of a company.
Definition window.cpp:1171
void HandleCtrlChanged()
State of CONTROL key has changed.
Definition window.cpp:2629
static void DrawOverlappedWindow(Window *w, int left, int top, int right, int bottom)
Generate repaint events for the visible part of window w within the rectangle.
Definition window.cpp:860
bool _scrolling_viewport
A viewport is being scrolled with the mouse.
Definition window.cpp:90
void InputLoop()
Regular call from the global game loop.
Definition window.cpp:2998
void UpdateWindows()
Update the continuously changing contents of the windows, such as the viewports.
Definition window.cpp:3061
int PositionMainToolbar(Window *w)
(Re)position main toolbar window at the screen.
Definition window.cpp:3395
void CloseNonVitalWindows()
Try to close a non-vital window.
Definition window.cpp:3266
void DrawOverlappedWindowForAll(int left, int top, int right, int bottom)
From a rectangle that needs redrawing, find the windows that intersect with the rectangle.
Definition window.cpp:922
void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen, bool schedule_resize)
Resize the window.
Definition window.cpp:2025
static bool IsGoodAutoPlace2(int left, int top, int width, int height, int toolbar_y, Point &pos)
Decide whether a given rectangle is a good place to open a mostly visible new window.
Definition window.cpp:1523
int PositionNetworkChatWindow(Window *w)
(Re)position network chat window at the screen.
Definition window.cpp:3428
static void StartWindowSizing(Window *w, bool to_left)
Start resizing a window.
Definition window.cpp:2277
static Point GetAutoPlacePosition(int width, int height)
Find a good place for opening a new window of a given width and height.
Definition window.cpp:1562
PreventHideDirection
Direction for moving the window.
Definition window.cpp:1933
@ PHD_DOWN
Below v is a safe position.
Definition window.cpp:1935
@ PHD_UP
Above v is a safe position.
Definition window.cpp:1934
static void HandleAutoscroll()
If needed and switched on, perform auto scrolling (automatically moving window contents when mouse is...
Definition window.cpp:2678
bool _window_highlight_colour
If false, highlight is white, otherwise the by the widget defined colour.
Definition window.cpp:75
void HandleToolbarHotkey(int hotkey)
Handle Toolbar hotkey events - can come from a source like the MacBook Touch Bar.
Definition window.cpp:2556
static int PositionWindow(Window *w, WindowClass clss, int setting)
(Re)position a window at the screen.
Definition window.cpp:3372
void SetFocusedWindow(Window *w)
Set the window that has the focus.
Definition window.cpp:419
static bool IsGoodAutoPlace1(int left, int top, int width, int height, int toolbar_y, Point &pos)
Decide whether a given rectangle is a good place to open a completely visible new window.
Definition window.cpp:1487
static constexpr int MAX_OFFSET_DOUBLE_CLICK
How much the mouse is allowed to move to call it a double click.
Definition window.cpp:2723
static int _input_events_this_tick
Local counter that is incremented each time an mouse input event is detected.
Definition window.cpp:2672
Window * FindWindowByClass(WindowClass cls)
Find any window by its class.
Definition window.cpp:1116
void ChangeVehicleViewports(VehicleID from_index, VehicleID to_index)
Switches viewports following vehicles, which get autoreplaced.
Definition window.cpp:3440
const std::chrono::milliseconds TIME_BETWEEN_DOUBLE_CLICK(500)
Time between 2 left clicks before it becoming a double click.
static EventState HandleViewportScroll()
Handle viewport scrolling with the mouse.
Definition window.cpp:2360
static void DispatchMouseWheelEvent(Window *w, NWidgetCore *nwid, int wheel)
Dispatch the mousewheel-action to the window.
Definition window.cpp:801
static void DispatchLeftClickEvent(Window *w, int x, int y, int click_count)
Dispatch left mouse-button (possibly double) click in window.
Definition window.cpp:610
Window * FindWindowFromPt(int x, int y)
Do a search for a window at specific coordinates.
Definition window.cpp:1771
static IntervalTimer< TimerWindow > highlight_interval(std::chrono::milliseconds(450), [](auto) { _window_highlight_colour=!_window_highlight_colour;})
Blink the window highlight colour constantly.
void DeleteAllMessages()
Delete all messages and close their corresponding window (if any).
Definition window.cpp:3298
static Window * _last_scroll_window
Window of the last scroll event.
Definition window.cpp:54
int GetMainViewTop()
Return the top of the main view available for general use.
Definition window.cpp:2065
static void BringWindowToFront(Window *w, bool dirty=true)
On clicking on a window, make it the frontmost window of all windows with an equal or lower z-priorit...
Definition window.cpp:1347
void ReInitAllWindows(bool zoom_changed)
Re-initialize all windows.
Definition window.cpp:3340
static void EnsureVisibleCaption(Window *w, int nx, int ny)
Make sure at least a part of the caption bar is still visible by moving the window if necessary.
Definition window.cpp:1988
void CloseWindowByClass(WindowClass cls, int data)
Close all windows of a given class.
Definition window.cpp:1155
void HandleMouseEvents()
Handle a mouse event from the video driver.
Definition window.cpp:2890
Point GetToolbarAlignedWindowPosition(int window_width)
Computer the position of the top-left corner of a window to be opened right under the toolbar.
Definition window.cpp:1630
static EventState HandleWindowDragging()
Handle dragging/resizing of a window.
Definition window.cpp:2088
int PositionNewsMessage(Window *w)
(Re)position news message window at the screen.
Definition window.cpp:3417
int GetMainViewBottom()
Return the bottom of the main view available for general use.
Definition window.cpp:2076
static void DispatchHoverEvent(Window *w, int x, int y)
Dispatch hover of the mouse over a window.
Definition window.cpp:773
void ChangeWindowOwner(Owner old_owner, Owner new_owner)
Change the owner of all the windows one company can take over from another company in the case of a c...
Definition window.cpp:1191
void HandleKeypress(uint keycode, char32_t key)
Handle keyboard input.
Definition window.cpp:2573
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition window.cpp:3132
void HandleTextInput(const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end)
Handle text input.
Definition window.cpp:2659
EventState VpHandlePlaceSizingDrag()
Handle the mouse while dragging for placement/resizing.
static constexpr int MAX_OFFSET_HOVER
Maximum mouse movement before stopping a hover event.
Definition window.cpp:2724
bool FocusedWindowIsConsole()
Check if a console is focused.
Definition window.cpp:459
void ResetWindowSystem()
Reset the windowing system, by means of shutting it down followed by re-initialization.
Definition window.cpp:1821
static uint GetWindowZPriority(WindowClass wc)
Get the z-priority for a given window.
Definition window.cpp:1263
bool EditBoxInGlobalFocus()
Check if an edit box is in global focus.
Definition window.cpp:445
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
Definition window.cpp:3224
void HideVitalWindows()
Close all always on-top windows to get an empty screen.
Definition window.cpp:3323
static IntervalTimer< TimerWindow > window_interval(std::chrono::milliseconds(30), [](auto) { extern int _caret_timer;_caret_timer+=3;CursorTick();HandleKeyScrolling();HandleAutoscroll();DecreaseWindowCounters();})
Update various of window-related information on a regular interval.
static bool DescSorter(WindowDesc *const &a, WindowDesc *const &b)
Sort WindowDesc by ini_key.
Definition window.cpp:165
static IntervalTimer< TimerWindow > white_border_interval(std::chrono::milliseconds(30), [](auto) { if(_network_dedicated) return;for(Window *w :Window::Iterate()) { if(w->flags.Test(WindowFlag::WhiteBorder) &&--w->white_border_timer==0) { w->flags.Reset(WindowFlag::WhiteBorder);w->SetDirty();} } })
Blink all windows marked with a white border.
Window * BringWindowToFrontById(WindowClass cls, WindowNumber number)
Find a window and make it the relative top-window on the screen.
Definition window.cpp:1226
void RelocateAllWindows(int neww, int newh)
Relocate all windows to fit the new size of the game application screen.
Definition window.cpp:3456
std::string _windows_file
Config file to store WindowDesc.
Definition window.cpp:102
static void HandleScrollbarScrolling(Window *w)
Handle scrollbar scrolling with the mouse.
Definition window.cpp:2293
bool _mouse_hovering
The mouse is hovering over the same point.
Definition window.cpp:91
static void StartWindowDrag(Window *w)
Start window dragging.
Definition window.cpp:2260
void CallWindowGameTickEvent()
Dispatch OnGameTick event over all windows.
Definition window.cpp:3253
static EventState HandleActiveWidget()
Handle active widget (mouse draggin on widget) with the mouse.
Definition window.cpp:2327
std::vector< WindowDesc * > * _window_descs
List of all WindowDescs.
Definition window.cpp:99
static void DispatchRightClickEvent(Window *w, int x, int y)
Dispatch right mouse-button click in window.
Definition window.cpp:744
ViewportAutoscrolling
Values for _settings_client.gui.auto_scrolling.
Definition window.cpp:45
@ VA_MAIN_VIEWPORT_FULLSCREEN
Scroll main viewport at edge when using fullscreen.
Definition window.cpp:47
@ VA_MAIN_VIEWPORT
Scroll main viewport at edge.
Definition window.cpp:48
@ VA_EVERY_VIEWPORT
Scroll all viewports at their edges.
Definition window.cpp:49
@ VA_DISABLED
Do not autoscroll when mouse is at edge of viewport.
Definition window.cpp:46
static const int8_t scrollamt[16][2]
Describes all the different arrow key combinations the game allows when it is in scrolling mode.
Definition window.cpp:2748
static bool MaybeBringWindowToFront(Window *w)
Check if a window can be made relative top-most window, and if so do it.
Definition window.cpp:2424
WindowList _z_windows
List of windows opened at the screen sorted from the front to back.
Definition window.cpp:57
void CallWindowRealtimeTickEvent(uint delta_ms)
Dispatch OnRealtimeTick event over all windows.
Definition window.cpp:3023
SpecialMouseMode _special_mouse_mode
Mode of the mouse.
Definition window.cpp:93
static EventState HandleMouseDragDrop()
Handle dragging and dropping in mouse dragging mode (WSM_DRAGDROP).
Definition window.cpp:1886
void CloseAllNonVitalWindows()
It is possible that a stickied window gets to a position where the 'close' button is outside the gami...
Definition window.cpp:3285
static void HandleMouseOver()
Report position of the mouse to the underlying window.
Definition window.cpp:1910
static Window * _mouseover_last_w
Window of the last OnMouseOver event.
Definition window.cpp:53
static void CheckSoftLimit()
Check the soft limit of deletable (non vital, non sticky) windows.
Definition window.cpp:2973
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1101
void UnInitWindowSystem()
Close down the windowing system.
Definition window.cpp:1807
void InitWindowSystem()
(re)initialize the windowing system
Definition window.cpp:1785
void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, WidgetID widget_index)
Mark a particular widget in a particular window as dirty (in need of repainting)
Definition window.cpp:3119
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3106
void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
Mark window data of all windows of a given class as invalid (in need of re-computing) Note that by de...
Definition window.cpp:3241
Window functions not directly related to making/drawing windows.
@ Construction
This window is used for construction; close it whenever changing company.
@ NoClose
This window can't be interactively closed.
@ NoFocus
This window won't get focus/make any other window lose focus when click.
@ Modal
The window is a modal child of some other window, meaning the parent is 'inactive'.
void SetFocusedWindow(Window *w)
Set the window that has the focus.
Definition window.cpp:419
@ SizingLeft
Window is being resized towards the left.
@ DisableVpScroll
Window does not do autoscroll,.
@ Highlighted
Window has a widget that has a highlight.
@ Centred
Window is centered and shall stay centered after ReInit.
@ Dragging
Window is being dragged.
@ SizingRight
Window is being resized towards the right.
@ WhiteBorder
Window white border counter bit mask.
@ Timeout
Window timeout counter.
@ Sticky
Window is made sticky by user.
WidgetID GetWidgetFromPos(const Window *w, int x, int y)
Returns the index for the widget located at the given position relative to the window.
Definition widget.cpp:281
SpecialMouseMode
Mouse modes.
@ WSM_DRAGDROP
Drag&drop an object.
@ WSM_PRESIZE
Presizing mode (docks, tunnels).
WindowPosition
How do we the window to be placed?
Definition window_gui.h:143
@ WDP_CENTER
Center the window.
Definition window_gui.h:146
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:145
@ WDP_ALIGN_TOOLBAR
Align toward the toolbar.
Definition window_gui.h:147
@ WDP_MANUAL
Manually align the window (so no automatic location finding)
Definition window_gui.h:144
WindowList _z_windows
List of windows opened at the screen sorted from the front to back.
Definition window.cpp:57
int WidgetID
Widget ID.
Definition window_type.h:20
EventState
State of handling an event.
@ ES_HANDLED
The passed event is handled.
@ ES_NOT_HANDLED
The passed event is not handled.
WindowClass
Window classes.
Definition window_type.h:46
@ WC_INVALID
Invalid window.
@ WC_OSK
On Screen Keyboard; Window numbers:
@ WC_CONSOLE
Console; Window numbers:
@ WC_NEWS_WINDOW
News window; Window numbers:
@ WC_HIGHSCORE
Highscore; Window numbers:
@ WC_BUY_COMPANY
Buyout company (merger); Window numbers:
@ WC_SPRITE_ALIGNER
Sprite aligner (debug); Window numbers:
@ WC_COMPANY_INFRASTRUCTURE
Company infrastructure overview; Window numbers:
@ WC_ENDSCREEN
Endscreen; Window numbers:
@ WC_COMPANY_COLOUR
Company colour selection; Window numbers:
@ WC_STATION_LIST
Station list; Window numbers:
@ WC_ROADVEH_LIST
Road vehicle list; Window numbers:
@ WC_STATUS_BAR
Statusbar (at the bottom of your screen); Window numbers:
Definition window_type.h:66
@ WC_VEHICLE_ORDERS
Vehicle orders; Window numbers:
@ WC_SEND_NETWORK_MSG
Chatbox; Window numbers:
@ WC_ERRMSG
Error message; Window numbers:
@ WC_BUILD_TOOLBAR
Build toolbar; Window numbers:
Definition window_type.h:75
@ WC_NETWORK_ASK_RELAY
Network ask relay window; Window numbers:
@ WC_SCRIPT_SETTINGS
Script settings; Window numbers:
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:47
@ WC_SCEN_LAND_GEN
Landscape generation (in Scenario Editor); Window numbers:
@ WC_SCRIPT_LIST
Scripts list; Window numbers:
@ WC_SAVE_PRESET
Save preset; Window numbers:
@ WC_SHIPS_LIST
Ships list; Window numbers:
@ WC_MESSAGE_HISTORY
News history list; Window numbers:
@ WC_CONFIRM_POPUP_QUERY
Popup with confirm question; Window numbers:
@ WC_GENERATE_LANDSCAPE
Generate landscape (newgame); Window numbers:
@ WC_CUSTOM_CURRENCY
Custom currency; Window numbers:
@ WC_MAIN_WINDOW
Main window; Window numbers:
Definition window_type.h:53
@ WC_TRAINS_LIST
Trains list; Window numbers:
@ WC_GAME_OPTIONS
Game options window; Window numbers:
@ WC_NETWORK_WINDOW
Network window; Window numbers:
@ WC_FINANCES
Finances of a company; Window numbers:
@ WC_TEXTFILE
textfile; Window numbers:
@ WC_DROPDOWN_MENU
Drop down menu; Window numbers:
@ WC_QUERY_STRING
Query string window; Window numbers:
@ WC_SMALLMAP
Small map; Window numbers:
@ WC_BOOTSTRAP
Bootstrap; Window numbers:
@ WC_SAVELOAD
Saveload window; Window numbers:
@ WC_GRF_PARAMETERS
NewGRF parameters; Window numbers:
@ WC_MODAL_PROGRESS
Progress report of landscape generation; Window numbers:
@ WC_MAIN_TOOLBAR
Main toolbar (the long bar at the top); Window numbers:
Definition window_type.h:60
@ WC_TOOLTIPS
Tooltip window; Window numbers:
@ WC_COMPANY
Company view; Window numbers:
@ WC_NETWORK_STATUS_WINDOW
Network status window; Window numbers:
@ WC_AIRCRAFT_LIST
Aircraft list; Window numbers:
Functions related to zooming.
int ScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift left (when zoom > ZOOM_LVL_MIN) When shifting right,...
Definition zoom_func.h:22
@ ZOOM_LVL_MIN
Minimum zoom level.
Definition zoom_type.h:41