OpenTTD Source 20250529-master-g10c159a79f
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 "table/strings.h"
43
44#include "safeguards.h"
45
53
55static Window *_mouseover_last_w = nullptr;
56static Window *_last_scroll_window = nullptr;
57
59WindowList _z_windows;
60
62/* static */ std::vector<Window *> Window::closed_windows;
63
67/* static */ void Window::DeleteClosedWindows()
68{
69 for (Window *w : Window::closed_windows) delete w;
71
72 /* Remove dead entries from the window list */
73 _z_windows.remove(nullptr);
74}
75
78
79/*
80 * Window that currently has focus. - The main purpose is to generate
81 * #FocusLost events, not to give next window in z-order focus when a
82 * window is closed.
83 */
84Window *_focused_window;
85
86Point _cursorpos_drag_start;
87
88int _scrollbar_start_pos;
89int _scrollbar_size;
90uint8_t _scroller_click_timeout = 0;
91
94
96
101std::vector<WindowDesc*> *_window_descs = nullptr;
102
104std::string _windows_file;
105
107WindowDesc::WindowDesc(WindowPosition def_pos, std::string_view ini_key, int16_t def_width_trad, int16_t def_height_trad,
108 WindowClass window_class, WindowClass parent_class, WindowDefaultFlags flags,
109 const std::span<const NWidgetPart> nwid_parts, HotkeyList *hotkeys,
110 const std::source_location location) :
111 source_location(location),
112 default_pos(def_pos),
113 cls(window_class),
114 parent_cls(parent_class),
115 ini_key(ini_key),
116 flags(flags),
117 nwid_parts(nwid_parts),
118 hotkeys(hotkeys),
119 default_width_trad(def_width_trad),
120 default_height_trad(def_height_trad)
121{
122 if (_window_descs == nullptr) _window_descs = new std::vector<WindowDesc*>();
123 _window_descs->push_back(this);
124}
125
126WindowDesc::~WindowDesc()
127{
128 _window_descs->erase(std::ranges::find(*_window_descs, this));
129}
130
137{
138 return this->pref_width != 0 ? this->pref_width : ScaleGUITrad(this->default_width_trad);
139}
140
147{
148 return this->pref_height != 0 ? this->pref_height : ScaleGUITrad(this->default_height_trad);
149}
150
155{
156 IniFile ini;
158 for (WindowDesc *wd : *_window_descs) {
159 if (wd->ini_key.empty()) continue;
160 IniLoadWindowSettings(ini, wd->ini_key, wd);
161 }
162}
163
167static bool DescSorter(WindowDesc * const &a, WindowDesc * const &b)
168{
169 return a->ini_key < b->ini_key;
170}
171
176{
177 /* Sort the stuff to get a nice ini file on first write */
178 std::sort(_window_descs->begin(), _window_descs->end(), DescSorter);
179
180 IniFile ini;
182 for (WindowDesc *wd : *_window_descs) {
183 if (wd->ini_key.empty()) continue;
184 IniSaveWindowSettings(ini, wd->ini_key, wd);
185 }
187}
188
193{
194 if (this->nested_root != nullptr && this->nested_root->GetWidgetOfType(WWT_STICKYBOX) != nullptr) {
196 } else {
197 /* There is no stickybox; clear the preference in case someone tried to be funny */
198 this->window_desc.pref_sticky = false;
199 }
200}
201
211int Window::GetRowFromWidget(int clickpos, WidgetID widget, int padding, int line_height) const
212{
213 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(widget);
214 if (line_height < 0) line_height = wid->resize_y;
215 if (clickpos < wid->pos_y + padding) return INT_MAX;
216 return (clickpos - wid->pos_y - padding) / line_height;
217}
218
223{
224 for (auto &pair : this->widget_lookup) {
225 NWidgetBase *nwid = pair.second;
226 if (nwid->IsHighlighted()) {
227 nwid->SetHighlighted(TC_INVALID);
228 nwid->SetDirty(this);
229 }
230 }
231
233}
234
240void Window::SetWidgetHighlight(WidgetID widget_index, TextColour highlighted_colour)
241{
242 NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget_index);
243 if (nwid == nullptr) return;
244
245 nwid->SetHighlighted(highlighted_colour);
246 nwid->SetDirty(this);
247
248 if (highlighted_colour != TC_INVALID) {
249 /* If we set a highlight, the window has a highlight */
251 } else {
252 /* If we disable a highlight, check all widgets if anyone still has a highlight */
253 bool valid = false;
254 for (const auto &pair : this->widget_lookup) {
255 nwid = pair.second;
256 if (!nwid->IsHighlighted()) continue;
257
258 valid = true;
259 }
260 /* If nobody has a highlight, disable the flag on the window */
261 if (!valid) this->flags.Reset(WindowFlag::Highlighted);
262 }
263}
264
270bool Window::IsWidgetHighlighted(WidgetID widget_index) const
271{
272 const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget_index);
273 if (nwid == nullptr) return false;
274
275 return nwid->IsHighlighted();
276}
277
285void Window::OnDropdownClose(Point pt, WidgetID widget, int index, int click_result, bool instant_close)
286{
287 if (widget < 0) return;
288
289 if (instant_close) {
290 /* Send event for selected option if we're still
291 * on the parent button of the dropdown (behaviour of the dropdowns in the main toolbar). */
292 if (GetWidgetFromPos(this, pt.x, pt.y) == widget) {
293 this->OnDropdownSelect(widget, index, click_result);
294 }
295 }
296
297 /* Raise the dropdown button */
298 NWidgetCore *nwi2 = this->GetWidget<NWidgetCore>(widget);
299 if ((nwi2->type & WWT_MASK) == NWID_BUTTON_DROPDOWN) {
301 } else {
302 this->RaiseWidget(widget);
303 }
304 this->SetWidgetDirty(widget);
305}
306
313{
314 return this->GetWidget<NWidgetScrollbar>(widnum);
315}
316
323{
324 return this->GetWidget<NWidgetScrollbar>(widnum);
325}
326
333{
334 auto query = this->querystrings.find(widnum);
335 return query != this->querystrings.end() ? query->second : nullptr;
336}
337
344{
345 auto query = this->querystrings.find(widnum);
346 return query != this->querystrings.end() ? query->second : nullptr;
347}
348
353{
354 for (auto &qs : this->querystrings) {
355 qs.second->text.UpdateSize();
356 }
357}
358
363/* virtual */ const Textbuf *Window::GetFocusedTextbuf() const
364{
365 if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX) {
366 return &this->GetQueryString(this->nested_focus->GetIndex())->text;
367 }
368
369 return nullptr;
370}
371
376/* virtual */ Point Window::GetCaretPosition() const
377{
378 if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX && !this->querystrings.empty()) {
379 return this->GetQueryString(this->nested_focus->GetIndex())->GetCaretPosition(this, this->nested_focus->GetIndex());
380 }
381
382 Point pt = {0, 0};
383 return pt;
384}
385
392/* virtual */ Rect Window::GetTextBoundingRect(size_t from, size_t to) const
393{
394 if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX) {
395 return this->GetQueryString(this->nested_focus->GetIndex())->GetBoundingRect(this, this->nested_focus->GetIndex(), from, to);
396 }
397
398 Rect r = {0, 0, 0, 0};
399 return r;
400}
401
407/* virtual */ ptrdiff_t Window::GetTextCharacterAtPosition(const Point &pt) const
408{
409 if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX) {
410 return this->GetQueryString(this->nested_focus->GetIndex())->GetCharAtPosition(this, this->nested_focus->GetIndex(), pt);
411 }
412
413 return -1;
414}
415
421{
422 if (_focused_window == w) return;
423
424 /* Don't focus a tooltip */
425 if (w != nullptr && w->window_class == WC_TOOLTIPS) return;
426
427 /* Invalidate focused widget */
428 if (_focused_window != nullptr) {
429 if (_focused_window->nested_focus != nullptr) _focused_window->nested_focus->SetDirty(_focused_window);
430 }
431
432 /* Remember which window was previously focused */
433 Window *old_focused = _focused_window;
434 _focused_window = w;
435
436 /* So we can inform it that it lost focus */
437 if (old_focused != nullptr) old_focused->OnFocusLost(false);
438 if (_focused_window != nullptr) _focused_window->OnFocus();
439}
440
447{
448 if (_focused_window == nullptr) return false;
449
450 /* The console does not have an edit box so a special case is needed. */
451 if (_focused_window->window_class == WC_CONSOLE) return true;
452
453 return _focused_window->nested_focus != nullptr && _focused_window->nested_focus->type == WWT_EDITBOX;
454}
455
461{
462 return _focused_window && _focused_window->window_class == WC_CONSOLE;
463}
464
469{
470 if (this->nested_focus != nullptr) {
472
473 /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */
474 this->nested_focus->SetDirty(this);
475 this->nested_focus = nullptr;
476 }
477}
478
485{
486 NWidgetCore *widget = this->GetWidget<NWidgetCore>(widget_index);
487 assert(widget != nullptr); /* Setting focus to a non-existing widget is a bad idea. */
488
489 if (this->nested_focus != nullptr) {
490 /* Do nothing if widget_index is already focused. */
491 if (widget == this->nested_focus) return false;
492
493 /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */
494 this->nested_focus->SetDirty(this);
496 }
497
498 this->nested_focus = widget;
500 return true;
501}
502
503std::string Window::GetWidgetString([[maybe_unused]] WidgetID widget, StringID stringid) const
504{
505 if (stringid == STR_NULL) return {};
506 return GetString(stringid);
507}
508
513{
515}
516
521{
523}
524
529void Window::RaiseButtons(bool autoraise)
530{
531 for (auto &pair : this->widget_lookup) {
532 WidgetType type = pair.second->type;
533 NWidgetCore *wid = dynamic_cast<NWidgetCore *>(pair.second);
534 if (wid != nullptr && ((type & ~WWB_PUSHBUTTON) < WWT_LAST || type == NWID_PUSHBUTTON_DROPDOWN) &&
535 (!autoraise || (type & WWB_PUSHBUTTON) || type == WWT_EDITBOX) && wid->IsLowered()) {
536 wid->SetLowered(false);
537 wid->SetDirty(this);
538 }
539 }
540
541 /* Special widgets without widget index */
542 {
543 NWidgetCore *wid = this->nested_root != nullptr ? dynamic_cast<NWidgetCore *>(this->nested_root->GetWidgetOfType(WWT_DEFSIZEBOX)) : nullptr;
544 if (wid != nullptr) {
545 wid->SetLowered(false);
546 wid->SetDirty(this);
547 }
548 }
549}
550
555void Window::SetWidgetDirty(WidgetID widget_index) const
556{
557 /* Sometimes this function is called before the window is even fully initialized */
558 auto it = this->widget_lookup.find(widget_index);
559 if (it == std::end(this->widget_lookup)) return;
560
561 it->second->SetDirty(this);
562}
563
570{
571 if (hotkey < 0) return ES_NOT_HANDLED;
572
573 NWidgetCore *nw = this->GetWidget<NWidgetCore>(hotkey);
574 if (nw == nullptr || nw->IsDisabled()) return ES_NOT_HANDLED;
575
576 if (nw->type == WWT_EDITBOX) {
577 if (this->IsShaded()) return ES_NOT_HANDLED;
578
579 /* Focus editbox */
580 this->SetFocusedWidget(hotkey);
581 SetFocusedWindow(this);
582 } else {
583 /* Click button */
584 this->OnClick(Point(), hotkey, 1);
585 }
586 return ES_HANDLED;
587}
588
595{
596 this->LowerWidget(widget);
597 this->SetTimeout();
598 this->SetWidgetDirty(widget);
599}
600
601static void StartWindowDrag(Window *w);
602static void StartWindowSizing(Window *w, bool to_left);
603
611static void DispatchLeftClickEvent(Window *w, int x, int y, int click_count)
612{
613 NWidgetCore *nw = w->nested_root->GetWidgetFromPos(x, y);
614 WidgetType widget_type = (nw != nullptr) ? nw->type : WWT_EMPTY;
615
616 /* Allow dropdown close flag detection to work. */
618
619 bool focused_widget_changed = false;
620 /* If clicked on a window that previously did not have focus */
621 if (_focused_window != w && // We already have focus, right?
622 !w->window_desc.flags.Test(WindowDefaultFlag::NoFocus) && // Don't lose focus to toolbars
623 widget_type != WWT_CLOSEBOX) { // Don't change focused window if 'X' (close button) was clicked
624 focused_widget_changed = true;
626 }
627
628 if (nw == nullptr) return; // exit if clicked outside of widgets
629
630 /* don't allow any interaction if the button has been disabled */
631 if (nw->IsDisabled()) return;
632
633 WidgetID widget_index = nw->GetIndex();
634
635 /* Clicked on a widget that is not disabled.
636 * So unless the clicked widget is the caption bar, change focus to this widget.
637 * Exception: In the OSK we always want the editbox to stay focused. */
638 if (widget_index >= 0 && widget_type != WWT_CAPTION && w->window_class != WC_OSK) {
639 /* focused_widget_changed is 'now' only true if the window this widget
640 * is in gained focus. In that case it must remain true, also if the
641 * local widget focus did not change. As such it's the logical-or of
642 * both changed states.
643 *
644 * If this is not preserved, then the OSK window would be opened when
645 * a user has the edit box focused and then click on another window and
646 * then back again on the edit box (to type some text).
647 */
648 focused_widget_changed |= w->SetFocusedWidget(widget_index);
649 }
650
651 /* Dropdown window of this widget was closed so don't process click this time. */
653
654 if ((widget_type & ~WWB_PUSHBUTTON) < WWT_LAST && (widget_type & WWB_PUSHBUTTON)) w->HandleButtonClick(widget_index);
655
656 Point pt = { x, y };
657
658 switch (widget_type) {
659 case NWID_VSCROLLBAR:
660 case NWID_HSCROLLBAR:
661 ScrollbarClickHandler(w, nw, x, y);
662 break;
663
664 case WWT_EDITBOX: {
665 QueryString *query = w->GetQueryString(widget_index);
666 if (query != nullptr) query->ClickEditBox(w, pt, widget_index, click_count, focused_widget_changed);
667 break;
668 }
669
670 case WWT_CLOSEBOX: // 'X'
671 w->Close();
672 return;
673
674 case WWT_CAPTION: // 'Title bar'
676 return;
677
678 case WWT_RESIZEBOX:
679 /* When the resize widget is on the left size of the window
680 * we assume that that button is used to resize to the left. */
681 StartWindowSizing(w, nw->pos_x < (w->width / 2));
682 nw->SetDirty(w);
683 return;
684
685 case WWT_DEFSIZEBOX: {
686 if (_ctrl_pressed) {
687 if (click_count > 1) {
688 w->window_desc.pref_width = 0;
690 } else {
693 }
694 } else {
695 int16_t def_width = std::max<int16_t>(std::min<int16_t>(w->window_desc.GetDefaultWidth(), _screen.width), w->nested_root->smallest_x);
696 int16_t def_height = std::max<int16_t>(std::min<int16_t>(w->window_desc.GetDefaultHeight(), _screen.height - 50), w->nested_root->smallest_y);
697
698 int dx = (w->resize.step_width == 0) ? 0 : def_width - w->width;
699 int dy = (w->resize.step_height == 0) ? 0 : def_height - w->height;
700 /* dx and dy has to go by step.. calculate it.
701 * The cast to int is necessary else dx/dy are implicitly casted to unsigned int, which won't work. */
702 if (w->resize.step_width > 1) dx -= dx % (int)w->resize.step_width;
703 if (w->resize.step_height > 1) dy -= dy % (int)w->resize.step_height;
704 ResizeWindow(w, dx, dy, false);
705 }
706
707 nw->SetLowered(true);
708 nw->SetDirty(w);
709 w->SetTimeout();
710 break;
711 }
712
713 case WWT_DEBUGBOX:
715 break;
716
717 case WWT_SHADEBOX:
718 nw->SetDirty(w);
719 w->SetShaded(!w->IsShaded());
720 return;
721
722 case WWT_STICKYBOX:
724 nw->SetDirty(w);
726 return;
727
728 default:
729 break;
730 }
731
732 /* Widget has no index, so the window is not interested in it. */
733 if (widget_index < 0) return;
734
735 /* Check if the widget is highlighted; if so, disable highlight and dispatch an event to the GameScript */
736 if (w->IsWidgetHighlighted(widget_index)) {
737 w->SetWidgetHighlight(widget_index, TC_INVALID);
738 Game::NewEvent(new ScriptEventWindowWidgetClick((ScriptWindow::WindowClass)w->window_class, w->window_number, widget_index));
739 }
740
741 w->OnClick(pt, widget_index, click_count);
742}
743
750static void DispatchRightClickEvent(Window *w, int x, int y)
751{
752 NWidgetCore *wid = w->nested_root->GetWidgetFromPos(x, y);
753 if (wid == nullptr) return;
754
755 Point pt = { x, y };
756
757 /* No widget to handle, or the window is not interested in it. */
758 if (wid->GetIndex() >= 0) {
759 if (w->OnRightClick(pt, wid->GetIndex())) return;
760 }
761
762 /* Right-click close is enabled and there is a closebox. */
764 w->Close();
766 /* Right-click close is enabled, but excluding sticky windows. */
767 w->Close();
768 } else if (_settings_client.gui.hover_delay_ms == 0 && !w->OnTooltip(pt, wid->GetIndex(), TCC_RIGHT_CLICK) && wid->GetToolTip() != STR_NULL) {
769 GuiShowTooltips(w, GetEncodedString(wid->GetToolTip()), TCC_RIGHT_CLICK);
770 }
771}
772
779static void DispatchHoverEvent(Window *w, int x, int y)
780{
781 NWidgetCore *wid = w->nested_root->GetWidgetFromPos(x, y);
782
783 /* No widget to handle */
784 if (wid == nullptr) return;
785
786 Point pt = { x, y };
787
788 /* Show the tooltip if there is any */
789 if (!w->OnTooltip(pt, wid->GetIndex(), TCC_HOVER) && wid->GetToolTip() != STR_NULL) {
790 GuiShowTooltips(w, GetEncodedString(wid->GetToolTip()), TCC_HOVER);
791 return;
792 }
793
794 /* Widget has no index, so the window is not interested in it. */
795 if (wid->GetIndex() < 0) return;
796
797 w->OnHover(pt, wid->GetIndex());
798}
799
807static void DispatchMouseWheelEvent(Window *w, NWidgetCore *nwid, int wheel)
808{
809 if (nwid == nullptr) return;
810
811 /* Using wheel on caption/shade-box shades or unshades the window. */
812 if (nwid->type == WWT_CAPTION || nwid->type == WWT_SHADEBOX) {
813 w->SetShaded(wheel < 0);
814 return;
815 }
816
817 /* Wheeling a vertical scrollbar. */
818 if (nwid->type == NWID_VSCROLLBAR) {
819 NWidgetScrollbar *sb = static_cast<NWidgetScrollbar *>(nwid);
820 if (sb->GetCount() > sb->GetCapacity()) {
821 if (sb->UpdatePosition(wheel)) {
822 w->OnScrollbarScroll(nwid->GetIndex());
823 w->SetDirty();
824 }
825 }
826 return;
827 }
828
829 /* Scroll the widget attached to the scrollbar. */
830 Scrollbar *sb = (nwid->GetScrollbarIndex() >= 0 ? w->GetScrollbar(nwid->GetScrollbarIndex()) : nullptr);
831 if (sb != nullptr && sb->GetCount() > sb->GetCapacity()) {
832 if (sb->UpdatePosition(wheel)) {
834 w->SetDirty();
835 }
836 }
837}
838
844static bool MayBeShown(const Window *w)
845{
846 /* If we're not modal, everything is okay. */
847 if (!HasModalProgress()) return true;
848
849 switch (w->window_class) {
850 case WC_MAIN_WINDOW:
851 case WC_MODAL_PROGRESS:
853 return true;
854
855 default:
856 return false;
857 }
858}
859
872static void DrawOverlappedWindow(Window *w, int left, int top, int right, int bottom)
873{
875 ++it;
876 for (; !it.IsEnd(); ++it) {
877 const Window *v = *it;
878 if (MayBeShown(v) &&
879 right > v->left &&
880 bottom > v->top &&
881 left < v->left + v->width &&
882 top < v->top + v->height) {
883 /* v and rectangle intersect with each other */
884 int x;
885
886 if (left < (x = v->left)) {
887 DrawOverlappedWindow(w, left, top, x, bottom);
888 DrawOverlappedWindow(w, x, top, right, bottom);
889 return;
890 }
891
892 if (right > (x = v->left + v->width)) {
893 DrawOverlappedWindow(w, left, top, x, bottom);
894 DrawOverlappedWindow(w, x, top, right, bottom);
895 return;
896 }
897
898 if (top < (x = v->top)) {
899 DrawOverlappedWindow(w, left, top, right, x);
900 DrawOverlappedWindow(w, left, x, right, bottom);
901 return;
902 }
903
904 if (bottom > (x = v->top + v->height)) {
905 DrawOverlappedWindow(w, left, top, right, x);
906 DrawOverlappedWindow(w, left, x, right, bottom);
907 return;
908 }
909
910 return;
911 }
912 }
913
914 /* Setup blitter, and dispatch a repaint event to window *wz */
915 DrawPixelInfo *dp = _cur_dpi;
916 dp->width = right - left;
917 dp->height = bottom - top;
918 dp->left = left - w->left;
919 dp->top = top - w->top;
920 dp->pitch = _screen.pitch;
921 dp->dst_ptr = BlitterFactory::GetCurrentBlitter()->MoveTo(_screen.dst_ptr, left, top);
922 dp->zoom = ZoomLevel::Min;
923 w->OnPaint();
924}
925
934void DrawOverlappedWindowForAll(int left, int top, int right, int bottom)
935{
936 DrawPixelInfo bk;
937 AutoRestoreBackup dpi_backup(_cur_dpi, &bk);
938
939 for (Window *w : Window::IterateFromBack()) {
940 if (MayBeShown(w) &&
941 right > w->left &&
942 bottom > w->top &&
943 left < w->left + w->width &&
944 top < w->top + w->height) {
945 /* Window w intersects with the rectangle => needs repaint */
946 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));
947 }
948 }
949}
950
956{
957 AddDirtyBlock(this->left, this->top, this->left + this->width, this->top + this->height);
958}
959
967void Window::ReInit(int rx, int ry, bool reposition)
968{
969 this->SetDirty(); // Mark whole current window as dirty.
970
971 /* Save current size. */
972 int window_width = this->width * _gui_scale / this->scale;
973 int window_height = this->height * _gui_scale / this->scale;
974 this->scale = _gui_scale;
975
976 this->OnInit();
977 /* Re-initialize window smallest size. */
978 this->nested_root->SetupSmallestSize(this);
979 this->nested_root->AssignSizePosition(ST_SMALLEST, 0, 0, this->nested_root->smallest_x, this->nested_root->smallest_y, _current_text_dir == TD_RTL);
980 this->width = this->nested_root->smallest_x;
981 this->height = this->nested_root->smallest_y;
982 this->resize.step_width = this->nested_root->resize_x;
983 this->resize.step_height = this->nested_root->resize_y;
984
985 /* Resize as close to the original size + requested resize as possible. */
986 window_width = std::max(window_width + rx, this->width);
987 window_height = std::max(window_height + ry, this->height);
988 int dx = (this->resize.step_width == 0) ? 0 : window_width - this->width;
989 int dy = (this->resize.step_height == 0) ? 0 : window_height - this->height;
990 /* dx and dy has to go by step.. calculate it.
991 * The cast to int is necessary else dx/dy are implicitly casted to unsigned int, which won't work. */
992 if (this->resize.step_width > 1) dx -= dx % (int)this->resize.step_width;
993 if (this->resize.step_height > 1) dy -= dy % (int)this->resize.step_height;
994
995 if (reposition) {
996 Point pt = this->OnInitialPosition(this->nested_root->smallest_x, this->nested_root->smallest_y, window_number);
997 this->InitializePositionSize(pt.x, pt.y, this->nested_root->smallest_x, this->nested_root->smallest_y);
998 this->FindWindowPlacementAndResize(this->window_desc.GetDefaultWidth(), this->window_desc.GetDefaultHeight(), false);
999 }
1000
1001 ResizeWindow(this, dx, dy, true, false);
1002 /* ResizeWindow() does this->SetDirty() already, no need to do it again here. */
1003}
1004
1010void Window::SetShaded(bool make_shaded)
1011{
1012 if (this->shade_select == nullptr) return;
1013
1014 int desired = make_shaded ? SZSP_HORIZONTAL : 0;
1015 if (this->shade_select->shown_plane != desired) {
1016 if (make_shaded) {
1017 if (this->nested_focus != nullptr) this->UnfocusFocusedWidget();
1018 this->unshaded_size.width = this->width;
1019 this->unshaded_size.height = this->height;
1020 this->shade_select->SetDisplayedPlane(desired);
1021 this->ReInit(0, -this->height);
1022 } else {
1023 this->shade_select->SetDisplayedPlane(desired);
1024 int dx = ((int)this->unshaded_size.width > this->width) ? (int)this->unshaded_size.width - this->width : 0;
1025 int dy = ((int)this->unshaded_size.height > this->height) ? (int)this->unshaded_size.height - this->height : 0;
1026 this->ReInit(dx, dy);
1027 }
1028 }
1029}
1030
1037{
1038 for (Window *v : Window::Iterate()) {
1039 if ((wc == WC_INVALID || wc == v->window_class) && v->parent == this) return v;
1040 }
1041
1042 return nullptr;
1043}
1044
1052{
1053 for (Window *v : Window::Iterate()) {
1054 if (wc == v->window_class && number == v->window_number && v->parent == this) return v;
1055 }
1056
1057 return nullptr;
1058}
1059
1065{
1066 Window *child = this->FindChildWindow(wc);
1067 while (child != nullptr) {
1068 child->Close();
1069 child = this->FindChildWindow(wc);
1070 }
1071}
1072
1073
1080{
1081 Window *child = this->FindChildWindowById(wc, number);
1082 while (child != nullptr) {
1083 child->Close();
1084 child = this->FindChildWindowById(wc, number);
1085 }
1086}
1087
1091void Window::Close([[maybe_unused]] int data)
1092{
1093 /* Don't close twice. */
1094 if (*this->z_position == nullptr) return;
1095
1096 *this->z_position = nullptr;
1097
1098 if (_thd.window_class == this->window_class &&
1099 _thd.window_number == this->window_number) {
1101 }
1102
1103 /* Prevent Mouseover() from resetting mouse-over coordinates on a non-existing window */
1104 if (_mouseover_last_w == this) _mouseover_last_w = nullptr;
1105
1106 /* We can't scroll the window when it's closed. */
1107 if (_last_scroll_window == this) _last_scroll_window = nullptr;
1108
1109 /* Make sure we don't try to access non-existing query strings. */
1110 this->querystrings.clear();
1111
1112 /* Make sure we don't try to access this window as the focused window when it doesn't exist anymore. */
1113 if (_focused_window == this) {
1114 this->OnFocusLost(true);
1115 _focused_window = nullptr;
1116 }
1117
1118 this->CloseChildWindows();
1119
1120 this->SetDirty();
1121
1122 Window::closed_windows.push_back(this);
1123}
1124
1129{
1130 /* Make sure the window is closed, deletion is allowed only in Window::DeleteClosedWindows(). */
1131 assert(*this->z_position == nullptr);
1132}
1133
1141{
1142 for (Window *w : Window::Iterate()) {
1143 if (w->window_class == cls && w->window_number == number) return w;
1144 }
1145
1146 return nullptr;
1147}
1148
1156{
1157 for (Window *w : Window::Iterate()) {
1158 if (w->window_class == cls) return w;
1159 }
1160
1161 return nullptr;
1162}
1163
1170{
1172 assert(w != nullptr);
1173 return w;
1174}
1175
1182void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
1183{
1184 Window *w = FindWindowById(cls, number);
1185 if (w != nullptr && (force || !w->flags.Test(WindowFlag::Sticky))) {
1186 w->Close(data);
1187 }
1188}
1189
1195{
1196 /* Note: the container remains stable, even when deleting windows. */
1197 for (Window *w : Window::Iterate()) {
1198 if (w->window_class == cls) {
1199 w->Close(data);
1200 }
1201 }
1202}
1203
1211{
1212 /* Note: the container remains stable, even when deleting windows. */
1213 for (Window *w : Window::Iterate()) {
1214 if (w->owner == id) {
1215 w->Close();
1216 }
1217 }
1218
1219 /* Also delete the company specific windows that don't have a company-colour. */
1221}
1222
1230void ChangeWindowOwner(Owner old_owner, Owner new_owner)
1231{
1232 for (Window *w : Window::Iterate()) {
1233 if (w->owner != old_owner) continue;
1234
1235 switch (w->window_class) {
1236 case WC_COMPANY_COLOUR:
1237 case WC_FINANCES:
1238 case WC_STATION_LIST:
1239 case WC_TRAINS_LIST:
1240 case WC_ROADVEH_LIST:
1241 case WC_SHIPS_LIST:
1242 case WC_AIRCRAFT_LIST:
1243 case WC_BUY_COMPANY:
1244 case WC_COMPANY:
1246 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().
1247 continue;
1248
1249 default:
1250 w->owner = new_owner;
1251 break;
1252 }
1253 }
1254}
1255
1256static void BringWindowToFront(Window *w, bool dirty = true);
1257
1266{
1267 Window *w = FindWindowById(cls, number);
1268
1269 if (w != nullptr) {
1270 if (w->IsShaded()) w->SetShaded(false); // Restore original window size if it was shaded.
1271
1272 w->SetWhiteBorder();
1274 w->SetDirty();
1275 }
1276
1277 return w;
1278}
1279
1280static inline bool IsVitalWindow(const Window *w)
1281{
1282 switch (w->window_class) {
1283 case WC_MAIN_TOOLBAR:
1284 case WC_STATUS_BAR:
1285 case WC_NEWS_WINDOW:
1287 return true;
1288
1289 default:
1290 return false;
1291 }
1292}
1293
1303{
1304 assert(wc != WC_INVALID);
1305
1306 uint z_priority = 0;
1307
1308 switch (wc) {
1309 case WC_TOOLTIPS:
1310 ++z_priority;
1311 [[fallthrough]];
1312
1313 case WC_ERRMSG:
1315 ++z_priority;
1316 [[fallthrough]];
1317
1318 case WC_ENDSCREEN:
1319 ++z_priority;
1320 [[fallthrough]];
1321
1322 case WC_HIGHSCORE:
1323 ++z_priority;
1324 [[fallthrough]];
1325
1326 case WC_DROPDOWN_MENU:
1327 ++z_priority;
1328 [[fallthrough]];
1329
1330 case WC_MAIN_TOOLBAR:
1331 case WC_STATUS_BAR:
1332 ++z_priority;
1333 [[fallthrough]];
1334
1335 case WC_OSK:
1336 ++z_priority;
1337 [[fallthrough]];
1338
1339 case WC_QUERY_STRING:
1341 ++z_priority;
1342 [[fallthrough]];
1343
1345 case WC_MODAL_PROGRESS:
1347 case WC_SAVE_PRESET:
1348 ++z_priority;
1349 [[fallthrough]];
1350
1352 case WC_SAVELOAD:
1353 case WC_GAME_OPTIONS:
1354 case WC_CUSTOM_CURRENCY:
1355 case WC_NETWORK_WINDOW:
1356 case WC_GRF_PARAMETERS:
1357 case WC_SCRIPT_LIST:
1358 case WC_SCRIPT_SETTINGS:
1359 case WC_TEXTFILE:
1360 ++z_priority;
1361 [[fallthrough]];
1362
1363 case WC_CONSOLE:
1364 ++z_priority;
1365 [[fallthrough]];
1366
1367 case WC_NEWS_WINDOW:
1368 ++z_priority;
1369 [[fallthrough]];
1370
1371 default:
1372 ++z_priority;
1373 [[fallthrough]];
1374
1375 case WC_MAIN_WINDOW:
1376 return z_priority;
1377 }
1378}
1379
1386static void BringWindowToFront(Window *w, bool dirty)
1387{
1388 auto priority = GetWindowZPriority(w->window_class);
1389 WindowList::iterator dest = _z_windows.begin();
1390 while (dest != _z_windows.end() && (*dest == nullptr || GetWindowZPriority((*dest)->window_class) <= priority)) ++dest;
1391
1392 if (dest != w->z_position) {
1393 _z_windows.splice(dest, _z_windows, w->z_position);
1394 }
1395
1396 if (dirty) w->SetDirty();
1397}
1398
1407{
1408 /* Set up window properties; some of them are needed to set up smallest size below */
1409 this->window_class = this->window_desc.cls;
1410 this->SetWhiteBorder();
1412 this->owner = INVALID_OWNER;
1413 this->nested_focus = nullptr;
1414 this->window_number = window_number;
1415
1416 this->OnInit();
1417 /* Initialize smallest size. */
1418 this->nested_root->SetupSmallestSize(this);
1419 /* Initialize to smallest size. */
1420 this->nested_root->AssignSizePosition(ST_SMALLEST, 0, 0, this->nested_root->smallest_x, this->nested_root->smallest_y, _current_text_dir == TD_RTL);
1421
1422 /* Further set up window properties,
1423 * this->left, this->top, this->width, this->height, this->resize.width, and this->resize.height are initialized later. */
1424 this->resize.step_width = this->nested_root->resize_x;
1425 this->resize.step_height = this->nested_root->resize_y;
1426
1427 /* Give focus to the opened window unless a dropdown menu has focus or a text box of the focused window has focus
1428 * (so we don't interrupt typing) unless the new window has a text box. */
1429 bool dropdown_active = _focused_window != nullptr && _focused_window->window_class == WC_DROPDOWN_MENU;
1430 bool editbox_active = EditBoxInGlobalFocus() && this->nested_root->GetWidgetOfType(WWT_EDITBOX) == nullptr;
1431 if (!dropdown_active && !editbox_active) SetFocusedWindow(this);
1432
1433 /* Insert the window into the correct location in the z-ordering. */
1434 BringWindowToFront(this, false);
1435}
1436
1444void Window::InitializePositionSize(int x, int y, int sm_width, int sm_height)
1445{
1446 this->left = x;
1447 this->top = y;
1448 this->width = sm_width;
1449 this->height = sm_height;
1450}
1451
1463void Window::FindWindowPlacementAndResize(int def_width, int def_height, bool allow_resize)
1464{
1465 if (allow_resize) {
1466 def_width = std::max(def_width, this->width); // Don't allow default size to be smaller than smallest size
1467 def_height = std::max(def_height, this->height);
1468 /* Try to make windows smaller when our window is too small.
1469 * w->(width|height) is normally the same as min_(width|height),
1470 * but this way the GUIs can be made a little more dynamic;
1471 * one can use the same spec for multiple windows and those
1472 * can then determine the real minimum size of the window. */
1473 if (this->width != def_width || this->height != def_height) {
1474 /* Think about the overlapping toolbars when determining the minimum window size */
1475 int free_height = _screen.height;
1476 const Window *wt = FindWindowById(WC_STATUS_BAR, 0);
1477 if (wt != nullptr) free_height -= wt->height;
1479 if (wt != nullptr) free_height -= wt->height;
1480
1481 int enlarge_x = std::max(std::min(def_width - this->width, _screen.width - this->width), 0);
1482 int enlarge_y = std::max(std::min(def_height - this->height, free_height - this->height), 0);
1483
1484 /* X and Y has to go by step.. calculate it.
1485 * The cast to int is necessary else x/y are implicitly casted to
1486 * unsigned int, which won't work. */
1487 if (this->resize.step_width > 1) enlarge_x -= enlarge_x % (int)this->resize.step_width;
1488 if (this->resize.step_height > 1) enlarge_y -= enlarge_y % (int)this->resize.step_height;
1489
1490 ResizeWindow(this, enlarge_x, enlarge_y, true, false);
1491 /* ResizeWindow() calls this->OnResize(). */
1492 } else {
1493 /* Always call OnResize; that way the scrollbars and matrices get initialized. */
1494 this->OnResize();
1495 }
1496 }
1497
1498 int nx = this->left;
1499 int ny = this->top;
1500
1501 if (nx + this->width > _screen.width) nx -= (nx + this->width - _screen.width);
1502
1503 const Window *wt = FindWindowById(WC_MAIN_TOOLBAR, 0);
1504 ny = std::max(ny, (wt == nullptr || this == wt || this->top == 0) ? 0 : wt->height);
1505 nx = std::max(nx, 0);
1506
1507 if (this->viewport != nullptr) {
1508 this->viewport->left += nx - this->left;
1509 this->viewport->top += ny - this->top;
1510 }
1511 this->left = nx;
1512 this->top = ny;
1513
1514 this->SetDirty();
1515}
1516
1529static bool IsGoodAutoPlace1(int left, int top, int width, int height, int toolbar_y, Point &pos)
1530{
1531 int right = width + left;
1532 int bottom = height + top;
1533
1534 if (left < 0 || top < toolbar_y || right > _screen.width || bottom > _screen.height) return false;
1535
1536 /* Make sure it is not obscured by any window. */
1537 for (const Window *w : Window::Iterate()) {
1538 if (w->window_class == WC_MAIN_WINDOW) continue;
1539
1540 if (right > w->left &&
1541 w->left + w->width > left &&
1542 bottom > w->top &&
1543 w->top + w->height > top) {
1544 return false;
1545 }
1546 }
1547
1548 pos.x = left;
1549 pos.y = top;
1550 return true;
1551}
1552
1565static bool IsGoodAutoPlace2(int left, int top, int width, int height, int toolbar_y, Point &pos)
1566{
1567 bool rtl = _current_text_dir == TD_RTL;
1568
1569 /* Left part of the rectangle may be at most 1/4 off-screen,
1570 * right part of the rectangle may be at most 1/2 off-screen
1571 */
1572 if (rtl) {
1573 if (left < -(width >> 1) || left > _screen.width - (width >> 2)) return false;
1574 } else {
1575 if (left < -(width >> 2) || left > _screen.width - (width >> 1)) return false;
1576 }
1577
1578 /* Bottom part of the rectangle may be at most 1/4 off-screen */
1579 if (top < toolbar_y || top > _screen.height - (height >> 2)) return false;
1580
1581 /* Make sure it is not obscured by any window. */
1582 for (const Window *w : Window::Iterate()) {
1583 if (w->window_class == WC_MAIN_WINDOW) continue;
1584
1585 if (left + width > w->left &&
1586 w->left + w->width > left &&
1587 top + height > w->top &&
1588 w->top + w->height > top) {
1589 return false;
1590 }
1591 }
1592
1593 pos.x = left;
1594 pos.y = top;
1595 return true;
1596}
1597
1604static Point GetAutoPlacePosition(int width, int height)
1605{
1606 Point pt;
1607
1608 bool rtl = _current_text_dir == TD_RTL;
1609
1610 /* First attempt, try top-left of the screen */
1611 const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR);
1612 const int toolbar_y = main_toolbar != nullptr ? main_toolbar->height : 0;
1613 if (IsGoodAutoPlace1(rtl ? _screen.width - width : 0, toolbar_y, width, height, toolbar_y, pt)) return pt;
1614
1615 /* Second attempt, try around all existing windows.
1616 * The new window must be entirely on-screen, and not overlap with an existing window.
1617 * Eight starting points are tried, two at each corner.
1618 */
1619 for (const Window *w : Window::Iterate()) {
1620 if (w->window_class == WC_MAIN_WINDOW) continue;
1621
1622 if (IsGoodAutoPlace1(w->left + w->width, w->top, width, height, toolbar_y, pt)) return pt;
1623 if (IsGoodAutoPlace1(w->left - width, w->top, width, height, toolbar_y, pt)) return pt;
1624 if (IsGoodAutoPlace1(w->left, w->top + w->height, width, height, toolbar_y, pt)) return pt;
1625 if (IsGoodAutoPlace1(w->left, w->top - height, width, height, toolbar_y, pt)) return pt;
1626 if (IsGoodAutoPlace1(w->left + w->width, w->top + w->height - height, width, height, toolbar_y, pt)) return pt;
1627 if (IsGoodAutoPlace1(w->left - width, w->top + w->height - height, width, height, toolbar_y, pt)) return pt;
1628 if (IsGoodAutoPlace1(w->left + w->width - width, w->top + w->height, width, height, toolbar_y, pt)) return pt;
1629 if (IsGoodAutoPlace1(w->left + w->width - width, w->top - height, width, height, toolbar_y, pt)) return pt;
1630 }
1631
1632 /* Third attempt, try around all existing windows.
1633 * The new window may be partly off-screen, and must not overlap with an existing window.
1634 * Only four starting points are tried.
1635 */
1636 for (const Window *w : Window::Iterate()) {
1637 if (w->window_class == WC_MAIN_WINDOW) continue;
1638
1639 if (IsGoodAutoPlace2(w->left + w->width, w->top, width, height, toolbar_y, pt)) return pt;
1640 if (IsGoodAutoPlace2(w->left - width, w->top, width, height, toolbar_y, pt)) return pt;
1641 if (IsGoodAutoPlace2(w->left, w->top + w->height, width, height, toolbar_y, pt)) return pt;
1642 if (IsGoodAutoPlace2(w->left, w->top - height, width, height, toolbar_y, pt)) return pt;
1643 }
1644
1645 /* Fourth and final attempt, put window at diagonal starting from (0, toolbar_y), try multiples
1646 * of the closebox
1647 */
1648 int left = rtl ? _screen.width - width : 0, top = toolbar_y;
1649 int offset_x = rtl ? -(int)NWidgetLeaf::closebox_dimension.width : (int)NWidgetLeaf::closebox_dimension.width;
1650 int offset_y = std::max<int>(NWidgetLeaf::closebox_dimension.height, GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.captiontext.Vertical());
1651
1652restart:
1653 for (const Window *w : Window::Iterate()) {
1654 if (w->left == left && w->top == top) {
1655 left += offset_x;
1656 top += offset_y;
1657 goto restart;
1658 }
1659 }
1660
1661 pt.x = left;
1662 pt.y = top;
1663 return pt;
1664}
1665
1673{
1674 const Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0);
1675 assert(w != nullptr);
1676 Point pt = { _current_text_dir == TD_RTL ? w->left : (w->left + w->width) - window_width, w->top + w->height };
1677 return pt;
1678}
1679
1697static Point LocalGetWindowPlacement(const WindowDesc &desc, int16_t sm_width, int16_t sm_height, int window_number)
1698{
1699 Point pt;
1700 const Window *w;
1701
1702 int16_t default_width = std::max(desc.GetDefaultWidth(), sm_width);
1703 int16_t default_height = std::max(desc.GetDefaultHeight(), sm_height);
1704
1705 if (desc.parent_cls != WC_NONE && (w = FindWindowById(desc.parent_cls, window_number)) != nullptr) {
1706 bool rtl = _current_text_dir == TD_RTL;
1707 if (desc.parent_cls == WC_BUILD_TOOLBAR || desc.parent_cls == WC_SCEN_LAND_GEN) {
1708 pt.x = w->left + (rtl ? w->width - default_width : 0);
1709 pt.y = w->top + w->height;
1710 return pt;
1711 } else {
1712 /* Position child window with offset of closebox, but make sure that either closebox or resizebox is visible
1713 * - Y position: closebox of parent + closebox of child + statusbar
1714 * - X position: closebox on left/right, resizebox on right/left (depending on ltr/rtl)
1715 */
1716 int indent_y = std::max<int>(NWidgetLeaf::closebox_dimension.height, GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.captiontext.Vertical());
1717 if (w->top + 3 * indent_y < _screen.height) {
1718 pt.y = w->top + indent_y;
1719 int indent_close = NWidgetLeaf::closebox_dimension.width;
1720 int indent_resize = NWidgetLeaf::resizebox_dimension.width;
1721 if (_current_text_dir == TD_RTL) {
1722 pt.x = std::max(w->left + w->width - default_width - indent_close, 0);
1723 if (pt.x + default_width >= indent_close && pt.x + indent_resize <= _screen.width) return pt;
1724 } else {
1725 pt.x = std::min(w->left + indent_close, _screen.width - default_width);
1726 if (pt.x + default_width >= indent_resize && pt.x + indent_close <= _screen.width) return pt;
1727 }
1728 }
1729 }
1730 }
1731
1732 switch (desc.default_pos) {
1733 case WDP_ALIGN_TOOLBAR: // Align to the toolbar
1734 return GetToolbarAlignedWindowPosition(default_width);
1735
1736 case WDP_AUTO: // Find a good automatic position for the window
1737 return GetAutoPlacePosition(default_width, default_height);
1738
1739 case WDP_CENTER: // Centre the window horizontally
1740 pt.x = (_screen.width - default_width) / 2;
1741 pt.y = (_screen.height - default_height) / 2;
1742 break;
1743
1744 case WDP_MANUAL:
1745 pt.x = 0;
1746 pt.y = 0;
1747 break;
1748
1749 default:
1750 NOT_REACHED();
1751 }
1752
1753 return pt;
1754}
1755
1756/* virtual */ Point Window::OnInitialPosition([[maybe_unused]]int16_t sm_width, [[maybe_unused]]int16_t sm_height, [[maybe_unused]]int window_number)
1757{
1758 return LocalGetWindowPlacement(this->window_desc, sm_width, sm_height, window_number);
1759}
1760
1769{
1770 this->nested_root = MakeWindowNWidgetTree(this->window_desc.nwid_parts, &this->shade_select);
1771 this->nested_root->FillWidgetLookup(this->widget_lookup);
1772}
1773
1779{
1780 this->InitializeData(window_number);
1781 this->ApplyDefaults();
1782 Point pt = this->OnInitialPosition(this->nested_root->smallest_x, this->nested_root->smallest_y, window_number);
1783 this->InitializePositionSize(pt.x, pt.y, this->nested_root->smallest_x, this->nested_root->smallest_y);
1784 this->FindWindowPlacementAndResize(this->window_desc.GetDefaultWidth(), this->window_desc.GetDefaultHeight(), true);
1785}
1786
1792{
1793 this->CreateNestedTree();
1794 this->FinishInitNested(window_number);
1795}
1796
1801Window::Window(WindowDesc &desc) : window_desc(desc), scale(_gui_scale), mouse_capture_widget(-1)
1802{
1803 this->z_position = _z_windows.insert(_z_windows.end(), this);
1804}
1805
1814{
1815 for (Window *w : Window::IterateFromFront()) {
1816 if (MayBeShown(w) && IsInsideBS(x, w->left, w->width) && IsInsideBS(y, w->top, w->height)) {
1817 return w;
1818 }
1819 }
1820
1821 return nullptr;
1822}
1823
1828{
1829 IConsoleClose();
1830
1831 _focused_window = nullptr;
1832 _mouseover_last_w = nullptr;
1833 _last_scroll_window = nullptr;
1834 _scrolling_viewport = false;
1835 _mouse_hovering = false;
1836
1838 NWidgetLeaf::InvalidateDimensionCache(); // Reset cached sizes of several widgets.
1839 NWidgetScrollbar::InvalidateDimensionCache();
1840
1842
1844}
1845
1850{
1852
1853 for (Window *w : Window::Iterate()) w->Close();
1854
1856
1857 assert(_z_windows.empty());
1858}
1859
1864{
1867 _thd.Reset();
1868}
1869
1870static void DecreaseWindowCounters()
1871{
1872 if (_scroller_click_timeout != 0) _scroller_click_timeout--;
1873
1874 for (Window *w : Window::Iterate()) {
1875 if (_scroller_click_timeout == 0) {
1876 /* Unclick scrollbar buttons if they are pressed. */
1877 for (auto &pair : w->widget_lookup) {
1878 NWidgetBase *nwid = pair.second;
1879 if (nwid->type == NWID_HSCROLLBAR || nwid->type == NWID_VSCROLLBAR) {
1880 NWidgetScrollbar *sb = static_cast<NWidgetScrollbar*>(nwid);
1881 if (sb->disp_flags.Any({NWidgetDisplayFlag::ScrollbarUp, NWidgetDisplayFlag::ScrollbarDown})) {
1883 w->mouse_capture_widget = -1;
1884 sb->SetDirty(w);
1885 }
1886 }
1887 }
1888 }
1889
1890 /* Handle editboxes */
1891 for (auto &pair : w->querystrings) {
1892 pair.second->HandleEditBox(w, pair.first);
1893 }
1894
1895 w->OnMouseLoop();
1896 }
1897
1898 for (Window *w : Window::Iterate()) {
1899 if (w->flags.Test(WindowFlag::Timeout) && --w->timeout_timer == 0) {
1901
1902 w->OnTimeout();
1903 w->RaiseButtons(true);
1904 }
1905 }
1906}
1907
1908static void HandlePlacePresize()
1909{
1910 if (_special_mouse_mode != WSM_PRESIZE) return;
1911
1912 Window *w = _thd.GetCallbackWnd();
1913 if (w == nullptr) return;
1914
1915 Point pt = GetTileBelowCursor();
1916 if (pt.x == -1) {
1917 _thd.selend.x = -1;
1918 return;
1919 }
1920
1921 w->OnPlacePresize(pt, TileVirtXY(pt.x, pt.y));
1922}
1923
1929{
1931
1932 if (_left_button_down && _cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED; // Dragging, but the mouse did not move.
1933
1934 Window *w = _thd.GetCallbackWnd();
1935 if (w != nullptr) {
1936 /* Send an event in client coordinates. */
1937 Point pt;
1938 pt.x = _cursor.pos.x - w->left;
1939 pt.y = _cursor.pos.y - w->top;
1940 if (_left_button_down) {
1941 w->OnMouseDrag(pt, GetWidgetFromPos(w, pt.x, pt.y));
1942 } else {
1943 w->OnDragDrop(pt, GetWidgetFromPos(w, pt.x, pt.y));
1944 }
1945 }
1946
1947 if (!_left_button_down) ResetObjectToPlace(); // Button released, finished dragging.
1948 return ES_HANDLED;
1949}
1950
1952static void HandleMouseOver()
1953{
1954 Window *w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y);
1955
1956 /* We changed window, put an OnMouseOver event to the last window */
1957 if (_mouseover_last_w != nullptr && _mouseover_last_w != w) {
1958 /* Reset mouse-over coordinates of previous window */
1959 Point pt = { -1, -1 };
1961 }
1962
1963 /* _mouseover_last_w will get reset when the window is deleted, see DeleteWindow() */
1965
1966 if (w != nullptr) {
1967 /* send an event in client coordinates. */
1968 Point pt = { _cursor.pos.x - w->left, _cursor.pos.y - w->top };
1969 const NWidgetCore *widget = w->nested_root->GetWidgetFromPos(pt.x, pt.y);
1970 if (widget != nullptr) w->OnMouseOver(pt, widget->GetIndex());
1971 }
1972}
1973
1979
1990static void PreventHiding(int *nx, int *ny, const Rect &rect, const Window *v, int px, PreventHideDirection dir)
1991{
1992 if (v == nullptr) return;
1993
1994 const int min_visible = rect.Height();
1995
1996 int v_bottom = v->top + v->height - 1;
1997 int v_right = v->left + v->width - 1;
1998 int safe_y = (dir == PHD_UP) ? (v->top - min_visible - rect.top) : (v_bottom + min_visible - rect.bottom); // Compute safe vertical position.
1999
2000 if (*ny + rect.top <= v->top - min_visible) return; // Above v is enough space
2001 if (*ny + rect.bottom >= v_bottom + min_visible) return; // Below v is enough space
2002
2003 /* Vertically, the rectangle is hidden behind v. */
2004 if (*nx + rect.left + min_visible < v->left) { // At left of v.
2005 if (v->left < min_visible) *ny = safe_y; // But enough room, force it to a safe position.
2006 return;
2007 }
2008 if (*nx + rect.right - min_visible > v_right) { // At right of v.
2009 if (v_right > _screen.width - min_visible) *ny = safe_y; // Not enough room, force it to a safe position.
2010 return;
2011 }
2012
2013 /* Horizontally also hidden, force movement to a safe area. */
2014 if (px + rect.left < v->left && v->left >= min_visible) { // Coming from the left, and enough room there.
2015 *nx = v->left - min_visible - rect.left;
2016 } else if (px + rect.right > v_right && v_right <= _screen.width - min_visible) { // Coming from the right, and enough room there.
2017 *nx = v_right + min_visible - rect.right;
2018 } else {
2019 *ny = safe_y;
2020 }
2021}
2022
2030static void EnsureVisibleCaption(Window *w, int nx, int ny)
2031{
2032 /* Search for the title bar rectangle. */
2033 const NWidgetBase *caption = w->nested_root->GetWidgetOfType(WWT_CAPTION);
2034 if (caption != nullptr) {
2035 const Rect caption_rect = caption->GetCurrentRect();
2036
2037 const int min_visible = caption_rect.Height();
2038
2039 /* Make sure the window doesn't leave the screen */
2040 nx = Clamp(nx, min_visible - caption_rect.right, _screen.width - min_visible - caption_rect.left);
2041 ny = Clamp(ny, 0, _screen.height - min_visible);
2042
2043 /* Make sure the title bar isn't hidden behind the main tool bar or the status bar. */
2044 PreventHiding(&nx, &ny, caption_rect, FindWindowById(WC_MAIN_TOOLBAR, 0), w->left, PHD_DOWN);
2045 PreventHiding(&nx, &ny, caption_rect, FindWindowById(WC_STATUS_BAR, 0), w->left, PHD_UP);
2046 }
2047
2048 if (w->viewport != nullptr) {
2049 w->viewport->left += nx - w->left;
2050 w->viewport->top += ny - w->top;
2051 }
2052
2053 w->left = nx;
2054 w->top = ny;
2055}
2056
2067void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen, bool schedule_resize)
2068{
2069 if (delta_x != 0 || delta_y != 0) {
2070 if (clamp_to_screen) {
2071 /* Determine the new right/bottom position. If that is outside of the bounds of
2072 * the resolution clamp it in such a manner that it stays within the bounds. */
2073 int new_right = w->left + w->width + delta_x;
2074 int new_bottom = w->top + w->height + delta_y;
2075 if (new_right >= (int)_screen.width) delta_x -= Ceil(new_right - _screen.width, std::max(1U, w->nested_root->resize_x));
2076 if (new_bottom >= (int)_screen.height) delta_y -= Ceil(new_bottom - _screen.height, std::max(1U, w->nested_root->resize_y));
2077 }
2078
2079 w->SetDirty();
2080
2081 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);
2082 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);
2083 assert(w->nested_root->resize_x == 0 || new_xinc % w->nested_root->resize_x == 0);
2084 assert(w->nested_root->resize_y == 0 || new_yinc % w->nested_root->resize_y == 0);
2085
2086 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);
2087 w->width = w->nested_root->current_x;
2088 w->height = w->nested_root->current_y;
2089 }
2090
2091 EnsureVisibleCaption(w, w->left, w->top);
2092
2093 /* Schedule OnResize to make sure everything is initialised correctly if it needs to be. */
2094 if (schedule_resize) {
2095 w->ScheduleResize();
2096 } else {
2097 w->OnResize();
2098 }
2099 w->SetDirty();
2100}
2101
2108{
2110 return (w == nullptr) ? 0 : w->top + w->height;
2111}
2112
2119{
2121 return (w == nullptr) ? _screen.height : w->top;
2122}
2123
2124static bool _dragging_window;
2125
2131{
2132 /* Get out immediately if no window is being dragged at all. */
2133 if (!_dragging_window) return ES_NOT_HANDLED;
2134
2135 /* If button still down, but cursor hasn't moved, there is nothing to do. */
2136 if (_left_button_down && _cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED;
2137
2138 /* Otherwise find the window... */
2139 for (Window *w : Window::Iterate()) {
2141 /* Stop the dragging if the left mouse button was released */
2142 if (!_left_button_down) {
2144 break;
2145 }
2146
2147 w->SetDirty();
2148
2149 int x = _cursor.pos.x + _drag_delta.x;
2150 int y = _cursor.pos.y + _drag_delta.y;
2151 int nx = x;
2152 int ny = y;
2153
2157 int delta;
2158
2159 for (const Window *v : Window::Iterate()) {
2160 if (v == w) continue; // Don't snap at yourself
2161
2162 if (y + w->height > v->top && y < v->top + v->height) {
2163 /* Your left border <-> other right border */
2164 delta = abs(v->left + v->width - x);
2165 if (delta <= hsnap) {
2166 nx = v->left + v->width;
2167 hsnap = delta;
2168 }
2169
2170 /* Your right border <-> other left border */
2171 delta = abs(v->left - x - w->width);
2172 if (delta <= hsnap) {
2173 nx = v->left - w->width;
2174 hsnap = delta;
2175 }
2176 }
2177
2178 if (w->top + w->height >= v->top && w->top <= v->top + v->height) {
2179 /* Your left border <-> other left border */
2180 delta = abs(v->left - x);
2181 if (delta <= hsnap) {
2182 nx = v->left;
2183 hsnap = delta;
2184 }
2185
2186 /* Your right border <-> other right border */
2187 delta = abs(v->left + v->width - x - w->width);
2188 if (delta <= hsnap) {
2189 nx = v->left + v->width - w->width;
2190 hsnap = delta;
2191 }
2192 }
2193
2194 if (x + w->width > v->left && x < v->left + v->width) {
2195 /* Your top border <-> other bottom border */
2196 delta = abs(v->top + v->height - y);
2197 if (delta <= vsnap) {
2198 ny = v->top + v->height;
2199 vsnap = delta;
2200 }
2201
2202 /* Your bottom border <-> other top border */
2203 delta = abs(v->top - y - w->height);
2204 if (delta <= vsnap) {
2205 ny = v->top - w->height;
2206 vsnap = delta;
2207 }
2208 }
2209
2210 if (w->left + w->width >= v->left && w->left <= v->left + v->width) {
2211 /* Your top border <-> other top border */
2212 delta = abs(v->top - y);
2213 if (delta <= vsnap) {
2214 ny = v->top;
2215 vsnap = delta;
2216 }
2217
2218 /* Your bottom border <-> other bottom border */
2219 delta = abs(v->top + v->height - y - w->height);
2220 if (delta <= vsnap) {
2221 ny = v->top + v->height - w->height;
2222 vsnap = delta;
2223 }
2224 }
2225 }
2226 }
2227
2228 EnsureVisibleCaption(w, nx, ny);
2229
2230 w->SetDirty();
2231 return ES_HANDLED;
2233 /* Stop the sizing if the left mouse button was released */
2234 if (!_left_button_down) {
2237 w->SetDirty();
2238 break;
2239 }
2240
2241 /* Compute difference in pixels between cursor position and reference point in the window.
2242 * If resizing the left edge of the window, moving to the left makes the window bigger not smaller.
2243 */
2244 int x, y = _cursor.pos.y - _drag_delta.y;
2246 x = _drag_delta.x - _cursor.pos.x;
2247 } else {
2248 x = _cursor.pos.x - _drag_delta.x;
2249 }
2250
2251 /* resize.step_width and/or resize.step_height may be 0, which means no resize is possible. */
2252 if (w->resize.step_width == 0) x = 0;
2253 if (w->resize.step_height == 0) y = 0;
2254
2255 /* Check the resize button won't go past the bottom of the screen */
2256 if (w->top + w->height + y > _screen.height) {
2257 y = _screen.height - w->height - w->top;
2258 }
2259
2260 /* X and Y has to go by step.. calculate it.
2261 * The cast to int is necessary else x/y are implicitly casted to
2262 * unsigned int, which won't work. */
2263 if (w->resize.step_width > 1) x -= x % (int)w->resize.step_width;
2264 if (w->resize.step_height > 1) y -= y % (int)w->resize.step_height;
2265
2266 /* Check that we don't go below the minimum set size */
2267 if ((int)w->width + x < (int)w->nested_root->smallest_x) {
2268 x = w->nested_root->smallest_x - w->width;
2269 }
2270 if ((int)w->height + y < (int)w->nested_root->smallest_y) {
2271 y = w->nested_root->smallest_y - w->height;
2272 }
2273
2274 /* Window already on size */
2275 if (x == 0 && y == 0) return ES_HANDLED;
2276
2277 /* Now find the new cursor pos.. this is NOT _cursor, because we move in steps. */
2278 _drag_delta.y += y;
2279 if (w->flags.Test(WindowFlag::SizingLeft) && x != 0) {
2280 _drag_delta.x -= x; // x > 0 -> window gets longer -> left-edge moves to left -> subtract x to get new position.
2281 w->SetDirty();
2282 w->left -= x; // If dragging left edge, move left window edge in opposite direction by the same amount.
2283 /* ResizeWindow() below ensures marking new position as dirty. */
2284 } else {
2285 _drag_delta.x += x;
2286 }
2287
2288 /* ResizeWindow sets both pre- and after-size to dirty for redrawal */
2289 ResizeWindow(w, x, y);
2290 return ES_HANDLED;
2291 }
2292 }
2293
2294 _dragging_window = false;
2295 return ES_HANDLED;
2296}
2297
2303{
2306 _dragging_window = true;
2307
2308 _drag_delta.x = w->left - _cursor.pos.x;
2309 _drag_delta.y = w->top - _cursor.pos.y;
2310
2312}
2313
2319static void StartWindowSizing(Window *w, bool to_left)
2320{
2323 _dragging_window = true;
2324
2325 _drag_delta.x = _cursor.pos.x;
2326 _drag_delta.y = _cursor.pos.y;
2327
2329}
2330
2336{
2337 int i;
2339 bool rtl = false;
2340
2341 if (sb->type == NWID_HSCROLLBAR) {
2342 i = _cursor.pos.x - _cursorpos_drag_start.x;
2343 rtl = _current_text_dir == TD_RTL;
2344 } else {
2345 i = _cursor.pos.y - _cursorpos_drag_start.y;
2346 }
2347
2348 if (sb->disp_flags.Any({NWidgetDisplayFlag::ScrollbarUp, NWidgetDisplayFlag::ScrollbarDown})) {
2349 if (_scroller_click_timeout == 1) {
2350 _scroller_click_timeout = 3;
2351 if (sb->UpdatePosition(rtl == sb->disp_flags.Test(NWidgetDisplayFlag::ScrollbarUp) ? 1 : -1)) {
2353 w->SetDirty();
2354 }
2355 }
2356 return;
2357 }
2358
2359 /* Find the item we want to move to. SetPosition will make sure it's inside bounds. */
2360 int range = sb->GetCount() - sb->GetCapacity();
2361 if (range <= 0) return;
2362
2363 int pos = RoundDivSU((i + _scrollbar_start_pos) * range, std::max(1, _scrollbar_size));
2364 if (rtl) pos = range - pos;
2365 if (sb->SetPosition(pos)) {
2367 w->SetDirty();
2368 }
2369}
2370
2376{
2377 for (Window *w : Window::Iterate()) {
2378 if (w->mouse_capture_widget >= 0) {
2379 /* Abort if no button is clicked any more. */
2380 if (!_left_button_down) {
2382 w->mouse_capture_widget = -1;
2383 return ES_HANDLED;
2384 }
2385
2386 /* Handle scrollbar internally, or dispatch click event */
2388 if (type == NWID_VSCROLLBAR || type == NWID_HSCROLLBAR) {
2390 } else {
2391 /* If cursor hasn't moved, there is nothing to do. */
2392 if (_cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED;
2393
2394 Point pt = { _cursor.pos.x - w->left, _cursor.pos.y - w->top };
2395 w->OnClick(pt, w->mouse_capture_widget, 0);
2396 }
2397 return ES_HANDLED;
2398 }
2399 }
2400
2401 return ES_NOT_HANDLED;
2402}
2403
2409{
2410 bool scrollwheel_scrolling = _settings_client.gui.scrollwheel_scrolling == SWS_SCROLL_MAP && _cursor.wheel_moved;
2411
2413
2414 /* When we don't have a last scroll window we are starting to scroll.
2415 * When the last scroll window and this are not the same we went
2416 * outside of the window and should not left-mouse scroll anymore. */
2417 if (_last_scroll_window == nullptr) _last_scroll_window = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y);
2418
2420 _cursor.fix_at = false;
2421 _scrolling_viewport = false;
2422 _last_scroll_window = nullptr;
2423 return ES_NOT_HANDLED;
2424 }
2425
2426 if (_last_scroll_window == GetMainWindow() && _last_scroll_window->viewport->follow_vehicle != VehicleID::Invalid()) {
2427 /* If the main window is following a vehicle, then first let go of it! */
2428 const Vehicle *veh = Vehicle::Get(_last_scroll_window->viewport->follow_vehicle);
2429 ScrollMainWindowTo(veh->x_pos, veh->y_pos, veh->z_pos, true); // This also resets follow_vehicle
2430 return ES_NOT_HANDLED;
2431 }
2432
2433 Point delta;
2434 if (scrollwheel_scrolling) {
2435 /* We are using scrollwheels for scrolling */
2436 /* Use the integer part for movement */
2437 delta.x = static_cast<int>(_cursor.h_wheel);
2438 delta.y = static_cast<int>(_cursor.v_wheel);
2439 /* Keep the fractional part so that subtle movement is accumulated */
2440 float temp;
2441 _cursor.v_wheel = std::modf(_cursor.v_wheel, &temp);
2442 _cursor.h_wheel = std::modf(_cursor.h_wheel, &temp);
2443 } else {
2445 delta.x = -_cursor.delta.x;
2446 delta.y = -_cursor.delta.y;
2447 } else {
2448 delta.x = _cursor.delta.x;
2449 delta.y = _cursor.delta.y;
2450 }
2451 }
2452
2453 /* Create a scroll-event and send it to the window */
2454 if (delta.x != 0 || delta.y != 0) _last_scroll_window->OnScroll(delta);
2455
2456 _cursor.delta.x = 0;
2457 _cursor.delta.y = 0;
2458 _cursor.wheel_moved = false;
2459 return ES_HANDLED;
2460}
2461
2473{
2474 bool bring_to_front = false;
2475
2476 if (w->window_class == WC_MAIN_WINDOW ||
2477 IsVitalWindow(w) ||
2478 w->window_class == WC_TOOLTIPS ||
2480 return true;
2481 }
2482
2483 /* Use unshaded window size rather than current size for shaded windows. */
2484 int w_width = w->width;
2485 int w_height = w->height;
2486 if (w->IsShaded()) {
2487 w_width = w->unshaded_size.width;
2488 w_height = w->unshaded_size.height;
2489 }
2490
2492 ++it;
2493 for (; !it.IsEnd(); ++it) {
2494 Window *u = *it;
2495 /* A modal child will prevent the activation of the parent window */
2497 u->SetWhiteBorder();
2498 u->SetDirty();
2499 return false;
2500 }
2501
2502 if (u->window_class == WC_MAIN_WINDOW ||
2503 IsVitalWindow(u) ||
2504 u->window_class == WC_TOOLTIPS ||
2506 continue;
2507 }
2508
2509 /* Window sizes don't interfere, leave z-order alone */
2510 if (w->left + w_width <= u->left ||
2511 u->left + u->width <= w->left ||
2512 w->top + w_height <= u->top ||
2513 u->top + u->height <= w->top) {
2514 continue;
2515 }
2516
2517 bring_to_front = true;
2518 }
2519
2520 if (bring_to_front) BringWindowToFront(w);
2521 return true;
2522}
2523
2532EventState Window::HandleEditBoxKey(WidgetID wid, char32_t key, uint16_t keycode)
2533{
2534 QueryString *query = this->GetQueryString(wid);
2535 if (query == nullptr) return ES_NOT_HANDLED;
2536
2537 int action = QueryString::ACTION_NOTHING;
2538
2539 switch (query->text.HandleKeyPress(key, keycode)) {
2540 case HKPR_EDITING:
2541 this->SetWidgetDirty(wid);
2542 this->OnEditboxChanged(wid);
2543 break;
2544
2545 case HKPR_CURSOR:
2546 this->SetWidgetDirty(wid);
2547 /* For the OSK also invalidate the parent window */
2548 if (this->window_class == WC_OSK) this->InvalidateData();
2549 break;
2550
2551 case HKPR_CONFIRM:
2552 if (this->window_class == WC_OSK) {
2553 this->OnClick(Point(), WID_OSK_OK, 1);
2554 } else if (query->ok_button >= 0) {
2555 this->OnClick(Point(), query->ok_button, 1);
2556 } else {
2557 action = query->ok_button;
2558 }
2559 break;
2560
2561 case HKPR_CANCEL:
2562 if (this->window_class == WC_OSK) {
2563 this->OnClick(Point(), WID_OSK_CANCEL, 1);
2564 } else if (query->cancel_button >= 0) {
2565 this->OnClick(Point(), query->cancel_button, 1);
2566 } else {
2567 action = query->cancel_button;
2568 }
2569 break;
2570
2571 case HKPR_NOT_HANDLED:
2572 return ES_NOT_HANDLED;
2573
2574 default: break;
2575 }
2576
2577 switch (action) {
2579 this->UnfocusFocusedWidget();
2580 break;
2581
2583 if (query->text.GetText().empty()) {
2584 /* If already empty, unfocus instead */
2585 this->UnfocusFocusedWidget();
2586 } else {
2587 query->text.DeleteAll();
2588 this->SetWidgetDirty(wid);
2589 this->OnEditboxChanged(wid);
2590 }
2591 break;
2592
2593 default:
2594 break;
2595 }
2596
2597 return ES_HANDLED;
2598}
2599
2604void HandleToolbarHotkey(int hotkey)
2605{
2606 assert(HasModalProgress() || IsLocalCompany());
2607
2609 if (w != nullptr) {
2610 if (w->window_desc.hotkeys != nullptr) {
2611 if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return;
2612 }
2613 }
2614}
2615
2621void HandleKeypress(uint keycode, char32_t key)
2622{
2623 /* World generation is multithreaded and messes with companies.
2624 * But there is no company related window open anyway, so _current_company is not used. */
2625 assert(HasModalProgress() || IsLocalCompany());
2626
2627 /*
2628 * The Unicode standard defines an area called the private use area. Code points in this
2629 * area are reserved for private use and thus not portable between systems. For instance,
2630 * Apple defines code points for the arrow keys in this area, but these are only printable
2631 * on a system running OS X. We don't want these keys to show up in text fields and such,
2632 * and thus we have to clear the unicode character when we encounter such a key.
2633 */
2634 if (key >= 0xE000 && key <= 0xF8FF) key = 0;
2635
2636 /*
2637 * If both key and keycode is zero, we don't bother to process the event.
2638 */
2639 if (key == 0 && keycode == 0) return;
2640
2641 /* Check if the focused window has a focused editbox */
2642 if (EditBoxInGlobalFocus()) {
2643 /* All input will in this case go to the focused editbox */
2644 if (_focused_window->window_class == WC_CONSOLE) {
2645 if (_focused_window->OnKeyPress(key, keycode) == ES_HANDLED) return;
2646 } else {
2647 if (_focused_window->HandleEditBoxKey(_focused_window->nested_focus->GetIndex(), key, keycode) == ES_HANDLED) return;
2648 }
2649 }
2650
2651 /* Call the event, start with the uppermost window, but ignore the toolbar. */
2652 for (Window *w : Window::IterateFromFront()) {
2653 if (w->window_class == WC_MAIN_TOOLBAR) continue;
2654 if (w->window_desc.hotkeys != nullptr) {
2655 int hotkey = w->window_desc.hotkeys->CheckMatch(keycode);
2656 if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return;
2657 }
2658 if (w->OnKeyPress(key, keycode) == ES_HANDLED) return;
2659 }
2660
2662 /* When there is no toolbar w is null, check for that */
2663 if (w != nullptr) {
2664 if (w->window_desc.hotkeys != nullptr) {
2665 int hotkey = w->window_desc.hotkeys->CheckMatch(keycode);
2666 if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return;
2667 }
2668 if (w->OnKeyPress(key, keycode) == ES_HANDLED) return;
2669 }
2670
2671 HandleGlobalHotkeys(key, keycode);
2672}
2673
2678{
2679 /* Call the event, start with the uppermost window. */
2680 for (Window *w : Window::IterateFromFront()) {
2681 if (w->OnCTRLStateChange() == ES_HANDLED) return;
2682 }
2683}
2684
2690/* virtual */ void Window::InsertTextString(WidgetID wid, std::string_view str, bool marked, std::optional<size_t> caret, std::optional<size_t> insert_location, std::optional<size_t> replacement_end)
2691{
2692 QueryString *query = this->GetQueryString(wid);
2693 if (query == nullptr) return;
2694
2695 if (query->text.InsertString(str, marked, caret, insert_location, replacement_end) || marked) {
2696 this->SetWidgetDirty(wid);
2697 this->OnEditboxChanged(wid);
2698 }
2699}
2700
2707void HandleTextInput(std::string_view str, bool marked, std::optional<size_t> caret, std::optional<size_t> insert_location, std::optional<size_t> replacement_end)
2708{
2709 if (!EditBoxInGlobalFocus()) return;
2710
2711 _focused_window->InsertTextString(_focused_window->window_class == WC_CONSOLE ? 0 : _focused_window->nested_focus->GetIndex(), str, marked, caret, insert_location, replacement_end);
2712}
2713
2718static void HandleAutoscroll()
2719{
2720 if (_game_mode == GM_MENU || HasModalProgress()) return;
2722 if (_settings_client.gui.auto_scrolling == VA_MAIN_VIEWPORT_FULLSCREEN && !_fullscreen) return;
2723
2724 int x = _cursor.pos.x;
2725 int y = _cursor.pos.y;
2726 Window *w = FindWindowFromPt(x, y);
2727 if (w == nullptr || w->flags.Test(WindowFlag::DisableVpScroll)) return;
2729
2730 Viewport *vp = IsPtInWindowViewport(w, x, y);
2731 if (vp == nullptr) return;
2732
2733 x -= vp->left;
2734 y -= vp->top;
2735
2736 /* here allows scrolling in both x and y axis */
2737 /* If we succeed at scrolling in any direction, stop following a vehicle. */
2738 static const int SCROLLSPEED = 3;
2739 if (x - 15 < 0) {
2740 w->viewport->CancelFollow(*w);
2741 w->viewport->dest_scrollpos_x += ScaleByZoom((x - 15) * SCROLLSPEED, vp->zoom);
2742 } else if (15 - (vp->width - x) > 0) {
2743 w->viewport->CancelFollow(*w);
2744 w->viewport->dest_scrollpos_x += ScaleByZoom((15 - (vp->width - x)) * SCROLLSPEED, vp->zoom);
2745 }
2746 if (y - 15 < 0) {
2747 w->viewport->CancelFollow(*w);
2748 w->viewport->dest_scrollpos_y += ScaleByZoom((y - 15) * SCROLLSPEED, vp->zoom);
2749 } else if (15 - (vp->height - y) > 0) {
2750 w->viewport->CancelFollow(*w);
2751 w->viewport->dest_scrollpos_y += ScaleByZoom((15 - (vp->height - y)) * SCROLLSPEED, vp->zoom);
2752 }
2753}
2754
2755enum MouseClick : uint8_t {
2756 MC_NONE = 0,
2757 MC_LEFT,
2758 MC_RIGHT,
2759 MC_DOUBLE_LEFT,
2760 MC_HOVER,
2761};
2762
2763static constexpr int MAX_OFFSET_DOUBLE_CLICK = 5;
2764static constexpr int MAX_OFFSET_HOVER = 5;
2765
2767
2768const std::chrono::milliseconds TIME_BETWEEN_DOUBLE_CLICK(500);
2769
2770static void ScrollMainViewport(int x, int y)
2771{
2772 if (_game_mode != GM_MENU && _game_mode != GM_BOOTSTRAP) {
2773 Window *w = GetMainWindow();
2774 w->viewport->dest_scrollpos_x += ScaleByZoom(x, w->viewport->zoom);
2775 w->viewport->dest_scrollpos_y += ScaleByZoom(y, w->viewport->zoom);
2776 }
2777}
2778
2788static const int8_t scrollamt[16][2] = {
2789 { 0, 0},
2790 {-2, 0},
2791 { 0, -2},
2792 {-2, -1},
2793 { 2, 0},
2794 { 0, 0},
2795 { 2, -1},
2796 { 0, -2},
2797 { 0, 2},
2798 {-2, 1},
2799 { 0, 0},
2800 {-2, 0},
2801 { 2, 1},
2802 { 0, 2},
2803 { 2, 0},
2804 { 0, 0},
2805};
2806
2807static void HandleKeyScrolling()
2808{
2809 /*
2810 * Check that any of the dirkeys is pressed and that the focused window
2811 * doesn't have an edit-box as focused widget.
2812 */
2813 if (_dirkeys && !EditBoxInGlobalFocus()) {
2814 int factor = _shift_pressed ? 50 : 10;
2815
2816 if (_game_mode != GM_MENU && _game_mode != GM_BOOTSTRAP) {
2817 /* Key scrolling stops following a vehicle. */
2818 Window *main_window = GetMainWindow();
2819 main_window->viewport->CancelFollow(*main_window);
2820 }
2821
2822 ScrollMainViewport(scrollamt[_dirkeys][0] * factor, scrollamt[_dirkeys][1] * factor);
2823 }
2824}
2825
2826static void MouseLoop(MouseClick click, int mousewheel)
2827{
2828 /* World generation is multithreaded and messes with companies.
2829 * But there is no company related window open anyway, so _current_company is not used. */
2830 assert(HasModalProgress() || IsLocalCompany());
2831
2832 HandlePlacePresize();
2834
2835 if (VpHandlePlaceSizingDrag() == ES_HANDLED) return;
2836 if (HandleMouseDragDrop() == ES_HANDLED) return;
2837 if (HandleWindowDragging() == ES_HANDLED) return;
2838 if (HandleActiveWidget() == ES_HANDLED) return;
2839 if (HandleViewportScroll() == ES_HANDLED) return;
2840
2842
2843 bool scrollwheel_scrolling = _settings_client.gui.scrollwheel_scrolling == SWS_SCROLL_MAP && _cursor.wheel_moved;
2844 if (click == MC_NONE && mousewheel == 0 && !scrollwheel_scrolling) return;
2845
2846 int x = _cursor.pos.x;
2847 int y = _cursor.pos.y;
2848 Window *w = FindWindowFromPt(x, y);
2849 if (w == nullptr) return;
2850
2851 if (click != MC_HOVER && !MaybeBringWindowToFront(w)) return;
2852 Viewport *vp = IsPtInWindowViewport(w, x, y);
2853
2854 /* Don't allow any action in a viewport if either in menu or when having a modal progress window */
2855 if (vp != nullptr && (_game_mode == GM_MENU || HasModalProgress())) return;
2856
2857 if (mousewheel != 0) {
2858 /* Send mousewheel event to window, unless we're scrolling a viewport or the map */
2859 if (!scrollwheel_scrolling || (vp == nullptr && w->window_class != WC_SMALLMAP)) {
2860 if (NWidgetCore *nwid = w->nested_root->GetWidgetFromPos(x - w->left, y - w->top); nwid != nullptr) {
2861 w->OnMouseWheel(mousewheel, nwid->GetIndex());
2862 }
2863 }
2864
2865 /* Dispatch a MouseWheelEvent for widgets if it is not a viewport */
2866 if (vp == nullptr) DispatchMouseWheelEvent(w, w->nested_root->GetWidgetFromPos(x - w->left, y - w->top), mousewheel);
2867 }
2868
2869 if (vp != nullptr) {
2870 if (scrollwheel_scrolling && !w->flags.Test(WindowFlag::DisableVpScroll)) {
2871 _scrolling_viewport = true;
2872 _cursor.fix_at = true;
2873 return;
2874 }
2875
2876 switch (click) {
2877 case MC_DOUBLE_LEFT:
2878 case MC_LEFT:
2879 if (HandleViewportClicked(*vp, x, y)) return;
2882 _scrolling_viewport = true;
2883 _cursor.fix_at = false;
2884 return;
2885 }
2886 break;
2887
2888 case MC_RIGHT:
2891 _scrolling_viewport = true;
2894 DispatchRightClickEvent(w, x - w->left, y - w->top);
2895 return;
2896 }
2897 break;
2898
2899 default:
2900 break;
2901 }
2902 }
2903
2904 switch (click) {
2905 case MC_LEFT:
2906 case MC_DOUBLE_LEFT:
2907 DispatchLeftClickEvent(w, x - w->left, y - w->top, click == MC_DOUBLE_LEFT ? 2 : 1);
2908 return;
2909
2910 default:
2911 if (!scrollwheel_scrolling || w == nullptr || w->window_class != WC_SMALLMAP) break;
2912 /* We try to use the scrollwheel to scroll since we didn't touch any of the buttons.
2913 * Simulate a right button click so we can get started. */
2914 [[fallthrough]];
2915
2916 case MC_RIGHT:
2917 DispatchRightClickEvent(w, x - w->left, y - w->top);
2918 return;
2919
2920 case MC_HOVER:
2921 DispatchHoverEvent(w, x - w->left, y - w->top);
2922 break;
2923 }
2924
2925 /* We're not doing anything with 2D scrolling, so reset the value. */
2926 _cursor.h_wheel = 0.0f;
2927 _cursor.v_wheel = 0.0f;
2928 _cursor.wheel_moved = false;
2929}
2930
2935{
2936 /* World generation is multithreaded and messes with companies.
2937 * But there is no company related window open anyway, so _current_company is not used. */
2938 assert(HasModalProgress() || IsLocalCompany());
2939
2940 static std::chrono::steady_clock::time_point double_click_time = {};
2941 static Point double_click_pos = {0, 0};
2942
2943 /* Mouse event? */
2944 MouseClick click = MC_NONE;
2946 click = MC_LEFT;
2947 if (std::chrono::steady_clock::now() <= double_click_time + TIME_BETWEEN_DOUBLE_CLICK &&
2948 double_click_pos.x != 0 && abs(_cursor.pos.x - double_click_pos.x) < MAX_OFFSET_DOUBLE_CLICK &&
2949 double_click_pos.y != 0 && abs(_cursor.pos.y - double_click_pos.y) < MAX_OFFSET_DOUBLE_CLICK) {
2950 click = MC_DOUBLE_LEFT;
2951 }
2952 double_click_time = std::chrono::steady_clock::now();
2953 double_click_pos = _cursor.pos;
2954 _left_button_clicked = true;
2955 } else if (_right_button_clicked) {
2956 _right_button_clicked = false;
2957 click = MC_RIGHT;
2958 }
2959
2960 int mousewheel = 0;
2961 if (_cursor.wheel) {
2962 mousewheel = _cursor.wheel;
2963 _cursor.wheel = 0;
2964 }
2965
2966 static std::chrono::steady_clock::time_point hover_time = {};
2967 static Point hover_pos = {0, 0};
2968
2970 if (!_cursor.in_window || click != MC_NONE || mousewheel != 0 || _left_button_down || _right_button_down ||
2971 hover_pos.x == 0 || abs(_cursor.pos.x - hover_pos.x) >= MAX_OFFSET_HOVER ||
2972 hover_pos.y == 0 || abs(_cursor.pos.y - hover_pos.y) >= MAX_OFFSET_HOVER) {
2973 hover_pos = _cursor.pos;
2974 hover_time = std::chrono::steady_clock::now();
2975 _mouse_hovering = false;
2976 } else if (!_mouse_hovering) {
2977 if (std::chrono::steady_clock::now() > hover_time + std::chrono::milliseconds(_settings_client.gui.hover_delay_ms)) {
2978 click = MC_HOVER;
2979 _mouse_hovering = true;
2980 hover_time = std::chrono::steady_clock::now();
2981 }
2982 }
2983 }
2984
2985 if (click == MC_LEFT && _newgrf_debug_sprite_picker.mode == SPM_WAIT_CLICK) {
2986 /* Mark whole screen dirty, and wait for the next realtime tick, when drawing is finished. */
2988 _newgrf_debug_sprite_picker.clicked_pixel = blitter->MoveTo(_screen.dst_ptr, _cursor.pos.x, _cursor.pos.y);
2990 _newgrf_debug_sprite_picker.mode = SPM_REDRAW;
2992 } else {
2993 MouseLoop(click, mousewheel);
2994 }
2995
2996 /* We have moved the mouse the required distance,
2997 * no need to move it at any later time. */
2998 _cursor.delta.x = 0;
2999 _cursor.delta.y = 0;
3000}
3001
3005static void CheckSoftLimit()
3006{
3007 if (_settings_client.gui.window_soft_limit == 0) return;
3008
3009 for (;;) {
3010 uint deletable_count = 0;
3011 Window *last_deletable = nullptr;
3012 for (Window *w : Window::IterateFromFront()) {
3013 if (w->window_class == WC_MAIN_WINDOW || IsVitalWindow(w) || w->flags.Test(WindowFlag::Sticky)) continue;
3014
3015 last_deletable = w;
3016 deletable_count++;
3017 }
3018
3019 /* We've not reached the soft limit yet. */
3020 if (deletable_count <= _settings_client.gui.window_soft_limit) break;
3021
3022 assert(last_deletable != nullptr);
3023 last_deletable->Close();
3024 }
3025}
3026
3031{
3032 /* World generation is multithreaded and messes with companies.
3033 * But there is no company related window open anyway, so _current_company is not used. */
3034 assert(HasModalProgress() || IsLocalCompany());
3035
3037
3038 /* Process scheduled window deletion. */
3040
3041 /* HandleMouseEvents was already called for this tick */
3043}
3044
3045static std::chrono::time_point<std::chrono::steady_clock> _realtime_tick_start;
3046
3047bool CanContinueRealtimeTick()
3048{
3049 auto now = std::chrono::steady_clock::now();
3050 return std::chrono::duration_cast<std::chrono::milliseconds>(now - _realtime_tick_start).count() < (MILLISECONDS_PER_TICK * 3 / 4);
3051}
3052
3057{
3058 _realtime_tick_start = std::chrono::steady_clock::now();
3059 for (Window *w : Window::Iterate()) {
3060 w->OnRealtimeTick(delta_ms);
3061 }
3062}
3063
3065static const IntervalTimer<TimerWindow> window_interval(std::chrono::milliseconds(30), [](auto) {
3066 extern int _caret_timer;
3067 _caret_timer += 3;
3068 CursorTick();
3069
3070 HandleKeyScrolling();
3072 DecreaseWindowCounters();
3073});
3074
3076static const IntervalTimer<TimerWindow> highlight_interval(std::chrono::milliseconds(450), [](auto) {
3078});
3079
3081static const IntervalTimer<TimerWindow> white_border_interval(std::chrono::milliseconds(30), [](auto) {
3082 if (_network_dedicated) return;
3083
3084 for (Window *w : Window::Iterate()) {
3087 w->SetDirty();
3088 }
3089 }
3090});
3091
3096{
3097 static auto last_time = std::chrono::steady_clock::now();
3098 auto now = std::chrono::steady_clock::now();
3099 auto delta_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now - last_time);
3100
3101 if (delta_ms.count() == 0) return;
3102
3103 last_time = now;
3104
3107
3109
3111 CallWindowRealtimeTickEvent(delta_ms.count());
3112
3113 /* Process invalidations before anything else. */
3114 for (Window *w : Window::Iterate()) {
3118 }
3119
3120 /* Skip the actual drawing on dedicated servers without screen.
3121 * But still empty the invalidation queues above. */
3122 if (_network_dedicated) return;
3123
3125
3126 for (Window *w : Window::Iterate()) {
3127 /* Update viewport only if window is not shaded. */
3128 if (w->viewport != nullptr && !w->IsShaded()) UpdateViewportPosition(w, delta_ms.count());
3129 }
3131 /* Redraw mouse cursor in case it was hidden */
3132 DrawMouseCursor();
3133
3134 if (_newgrf_debug_sprite_picker.mode == SPM_REDRAW) {
3135 /* We are done with the last draw-frame, so we know what sprites we
3136 * clicked on. Reset the picker mode and invalidate the window. */
3139 }
3140}
3141
3148{
3149 for (const Window *w : Window::Iterate()) {
3150 if (w->window_class == cls && w->window_number == number) w->SetDirty();
3151 }
3152}
3153
3161{
3162 for (const Window *w : Window::Iterate()) {
3163 if (w->window_class == cls && w->window_number == number) {
3164 w->SetWidgetDirty(widget_index);
3165 }
3166 }
3167}
3168
3174{
3175 for (const Window *w : Window::Iterate()) {
3176 if (w->window_class == cls) w->SetDirty();
3177 }
3178}
3179
3184{
3185 this->scheduled_resize = true;
3186}
3187
3192{
3193 /* Sometimes OnResize() resizes the window again, in which case we can reprocess immediately. */
3194 while (this->scheduled_resize) {
3195 this->scheduled_resize = false;
3196 this->OnResize();
3197 }
3198}
3199
3205void Window::InvalidateData(int data, bool gui_scope)
3206{
3207 this->SetDirty();
3208 if (!gui_scope) {
3209 /* Schedule GUI-scope invalidation for next redraw. */
3210 this->scheduled_invalidation_data.push_back(data);
3211 }
3212 this->OnInvalidateData(data, gui_scope);
3213}
3214
3219{
3220 for (int data : this->scheduled_invalidation_data) {
3221 if (this->window_class == WC_INVALID) break;
3222 this->OnInvalidateData(data, true);
3223 }
3224 this->scheduled_invalidation_data.clear();
3225}
3226
3231{
3232 if (!this->flags.Test(WindowFlag::Highlighted)) return;
3233
3234 for (const auto &pair : this->widget_lookup) {
3235 if (pair.second->IsHighlighted()) pair.second->SetDirty(this);
3236 }
3237}
3238
3265void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
3266{
3267 for (Window *w : Window::Iterate()) {
3268 if (w->window_class == cls && w->window_number == number) {
3269 w->InvalidateData(data, gui_scope);
3270 }
3271 }
3272}
3273
3282void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
3283{
3284 for (Window *w : Window::Iterate()) {
3285 if (w->window_class == cls) {
3286 w->InvalidateData(data, gui_scope);
3287 }
3288 }
3289}
3290
3295{
3296 for (Window *w : Window::Iterate()) {
3297 w->OnGameTick();
3298 }
3299}
3300
3308{
3309 /* Note: the container remains stable, even when deleting windows. */
3310 for (Window *w : Window::Iterate()) {
3312 !w->flags.Test(WindowFlag::Sticky)) { // do not delete windows which are 'pinned'
3313
3314 w->Close();
3315 }
3316 }
3317}
3318
3327{
3328 /* Note: the container remains stable, even when closing windows. */
3329 for (Window *w : Window::Iterate()) {
3331 w->Close();
3332 }
3333 }
3334}
3335
3340{
3342 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_NEWS_DELETED); // invalidate the statusbar
3343 InvalidateWindowData(WC_MESSAGE_HISTORY, 0); // invalidate the message history
3344 CloseWindowById(WC_NEWS_WINDOW, 0); // close newspaper or general message window if shown
3345}
3346
3352{
3353 /* Note: the container remains stable, even when deleting windows. */
3354 for (Window *w : Window::Iterate()) {
3356 w->Close();
3357 }
3358 }
3359
3360 for (const Window *w : Window::Iterate()) w->SetDirty();
3361}
3362
3369
3370void ReInitWindow(Window *w, bool zoom_changed)
3371{
3372 if (w == nullptr) return;
3373 if (zoom_changed) {
3374 w->nested_root->AdjustPaddingForZoom();
3376 }
3377 w->ReInit();
3378}
3379
3381void ReInitAllWindows(bool zoom_changed)
3382{
3384 NWidgetLeaf::InvalidateDimensionCache(); // Reset cached sizes of several widgets.
3385 NWidgetScrollbar::InvalidateDimensionCache();
3386
3388
3389 /* When _gui_zoom has changed, we need to resize toolbar and statusbar first,
3390 * so EnsureVisibleCaption uses the updated size information. */
3391 ReInitWindow(FindWindowById(WC_MAIN_TOOLBAR, 0), zoom_changed);
3392 ReInitWindow(FindWindowById(WC_STATUS_BAR, 0), zoom_changed);
3393 for (Window *w : Window::Iterate()) {
3394 if (w->window_class == WC_MAIN_TOOLBAR || w->window_class == WC_STATUS_BAR) continue;
3395 ReInitWindow(w, zoom_changed);
3396 }
3397
3400
3401 /* Make sure essential parts of all windows are visible */
3402 RelocateAllWindows(_screen.width, _screen.height);
3404}
3405
3413static int PositionWindow(Window *w, WindowClass clss, int setting)
3414{
3415 if (w == nullptr || w->window_class != clss) {
3416 w = FindWindowById(clss, 0);
3417 }
3418 if (w == nullptr) return 0;
3419
3420 int old_left = w->left;
3421 switch (setting) {
3422 case 1: w->left = (_screen.width - w->width) / 2; break;
3423 case 2: w->left = _screen.width - w->width; break;
3424 default: w->left = 0; break;
3425 }
3426 if (w->viewport != nullptr) w->viewport->left += w->left - old_left;
3427 AddDirtyBlock(0, w->top, _screen.width, w->top + w->height); // invalidate the whole row
3428 return w->left;
3429}
3430
3437{
3438 Debug(misc, 5, "Repositioning Main Toolbar...");
3440}
3441
3448{
3449 Debug(misc, 5, "Repositioning statusbar...");
3451}
3452
3459{
3460 Debug(misc, 5, "Repositioning news message...");
3462}
3463
3470{
3471 Debug(misc, 5, "Repositioning network chat window...");
3473}
3474
3475
3482{
3483 for (const Window *w : Window::Iterate()) {
3484 if (w->viewport != nullptr && w->viewport->follow_vehicle == from_index) {
3485 w->viewport->follow_vehicle = to_index;
3486 w->SetDirty();
3487 }
3488 }
3489}
3490
3491
3497void RelocateAllWindows(int neww, int newh)
3498{
3500
3501 /* Reposition toolbar then status bar before other all windows. */
3502 if (Window *wt = FindWindowById(WC_MAIN_TOOLBAR, 0); wt != nullptr) {
3503 ResizeWindow(wt, std::min<uint>(neww, _toolbar_width) - wt->width, 0, false);
3504 wt->left = PositionMainToolbar(wt);
3505 }
3506
3507 if (Window *ws = FindWindowById(WC_STATUS_BAR, 0); ws != nullptr) {
3508 ResizeWindow(ws, std::min<uint>(neww, _toolbar_width) - ws->width, 0, false);
3509 ws->top = newh - ws->height;
3510 ws->left = PositionStatusbar(ws);
3511 }
3512
3513 for (Window *w : Window::Iterate()) {
3514 int left, top;
3515 /* XXX - this probably needs something more sane. For example specifying
3516 * in a 'backup'-desc that the window should always be centered. */
3517 switch (w->window_class) {
3518 case WC_MAIN_WINDOW:
3519 case WC_BOOTSTRAP:
3520 case WC_HIGHSCORE:
3521 case WC_ENDSCREEN:
3522 ResizeWindow(w, neww, newh);
3523 continue;
3524
3525 case WC_MAIN_TOOLBAR:
3526 case WC_STATUS_BAR:
3527 continue;
3528
3529 case WC_NEWS_WINDOW:
3530 top = newh - w->height;
3531 left = PositionNewsMessage(w);
3532 break;
3533
3535 ResizeWindow(w, std::min<uint>(neww, _toolbar_width) - w->width, 0, false);
3536
3537 top = newh - w->height - FindWindowById(WC_STATUS_BAR, 0)->height;
3538 left = PositionNetworkChatWindow(w);
3539 break;
3540
3541 case WC_CONSOLE:
3542 IConsoleResize(w);
3543 continue;
3544
3545 default: {
3546 if (w->flags.Test(WindowFlag::Centred)) {
3547 top = (newh - w->height) >> 1;
3548 left = (neww - w->width) >> 1;
3549 break;
3550 }
3551
3552 left = w->left;
3553 if (left + (w->width >> 1) >= neww) left = neww - w->width;
3554 if (left < 0) left = 0;
3555
3556 top = w->top;
3557 if (top + (w->height >> 1) >= newh) top = newh - w->height;
3558 break;
3559 }
3560 }
3561
3562 EnsureVisibleCaption(w, left, top);
3563 }
3564}
3565
3570void PickerWindowBase::Close([[maybe_unused]] int data)
3571{
3573 this->Window::Close();
3574}
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Reset()
Reset all bits.
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.
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
Definition factory.hpp:136
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:938
WidgetType type
Type of the widget / nested widget.
int pos_y
Vertical position of top-left corner of the widget in the window.
int pos_x
Horizontal position of top-left corner of the widget in the window.
uint resize_y
Vertical resize step (0 means not resizable).
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:1267
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:1276
StringID GetToolTip() const
Get the tool tip of the nested widget.
Definition widget.cpp:1240
void SetLowered(bool lowered)
Lower or raise the widget.
bool IsLowered() const
Return whether the widget is lowered.
static void InvalidateDimensionCache()
Reset the cached dimensions.
Definition widget.cpp:2699
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:1443
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:3570
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:30
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:251
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:302
static const uint MILLISECONDS_PER_TICK
The number of milliseconds per game tick.
Definition gfx_type.h:365
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:3450
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition window.cpp:955
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:1502
void DrawDirtyBlocks()
Repaints the rectangle blocks which are marked as 'dirty'.
Definition gfx.cpp:1438
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1535
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:688
bool _networking
are we in networking mode?
Definition network.cpp:67
bool _network_dedicated
are we a dedicated server?
Definition network.cpp:70
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.
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, std::string_view grpname, WindowDesc *desc)
Load a WindowDesc from config.
Definition settings.cpp:873
void IniSaveWindowSettings(IniFile &ini, std::string_view grpname, WindowDesc *desc)
Save a WindowDesc to config.
Definition settings.cpp:884
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
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.
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:91
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:415
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:57
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:129
Point pos
logical mouse position
Definition gfx_type.h:126
bool in_window
mouse inside this window, determines drawing logic
Definition gfx_type.h:148
int wheel
mouse wheel movement
Definition gfx_type.h:128
Point delta
relative mouse movement in this tick
Definition gfx_type.h:127
Data about how and where to blit pixels.
Definition gfx_type.h:158
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:301
Ini file that supports both loading and saving.
Definition ini_type.h:86
bool SaveToDisk(const std::string &filename)
Save the Ini file's data to the disk.
Definition ini.cpp:42
void LoadFromDisk(std::string_view 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)
FlatSet< 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:846
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:788
Rect GetBoundingRect(const Window *w, WidgetID wid, size_t from, size_t to) const
Get the bounding rectangle for a range of the query string.
Definition misc_gui.cpp:816
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:212
uint step_width
Step-size of width resize changes.
Definition window_gui.h:211
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
std::string_view GetText() const
Get the current text.
Definition textbuf.cpp:284
bool InsertString(std::string_view str, bool marked, std::optional< size_t > caret=std::nullopt, std::optional< size_t > insert_location=std::nullopt, std::optional< size_t > replacement_end=std::nullopt)
Insert a string into the text buffer.
Definition textbuf.cpp:157
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.
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:167
int16_t GetDefaultWidth() const
Determine default width of window.
Definition window.cpp:136
static void SaveToConfig()
Save all WindowDesc settings to _windows_file.
Definition window.cpp:175
int16_t pref_width
User-preferred width of the window. Zero if unset.
Definition window_gui.h:186
const WindowPosition default_pos
Preferred position of the window.
Definition window_gui.h:177
bool pref_sticky
Preferred stickyness.
Definition window_gui.h:185
int16_t pref_height
User-preferred height of the window. Zero if unset.
Definition window_gui.h:187
int16_t GetDefaultHeight() const
Determine default height of window.
Definition window.cpp:146
const int16_t default_height_trad
Preferred initial height of the window (pixels at 1x zoom).
Definition window_gui.h:197
const int16_t default_width_trad
Preferred initial width of the window (pixels at 1x zoom).
Definition window_gui.h:196
const WindowClass cls
Class of the window,.
Definition window_gui.h:178
const std::string_view ini_key
Key to store window defaults in openttd.cfg. An empty string if nothing shall be stored.
Definition window_gui.h:180
const WindowDefaultFlags flags
Flags.
Definition window_gui.h:181
static void LoadFromConfig()
Load all WindowDesc settings from _windows_file.
Definition window.cpp:154
const WindowClass parent_cls
Class of the parent window.
Definition window_gui.h:179
const HotkeyList * hotkeys
Hotkeys for the window.
Definition window_gui.h:183
WindowDesc(WindowPosition default_pos, std::string_view 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:107
const std::span< const NWidgetPart > nwid_parts
Span of nested widget parts describing the window.
Definition window_gui.h:182
Number to differentiate different windows of the same class.
Iterator to iterate all valid Windows.
Definition window_gui.h:874
Data structure for an opened window.
Definition window_gui.h:273
virtual const struct Textbuf * GetFocusedTextbuf() const
Get the current input text buffer.
Definition window.cpp:363
void SetWidgetHighlight(WidgetID widget_index, TextColour highlighted_colour)
Sets the highlighted status of a widget.
Definition window.cpp:240
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition window.cpp:967
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1091
virtual void OnInvalidateData(int data=0, bool gui_scope=true)
Some data on this window has become invalid.
Definition window_gui.h:792
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1778
std::map< WidgetID, QueryString * > querystrings
QueryString associated to WWT_EDITBOX widgets.
Definition window_gui.h:320
virtual void ApplyDefaults()
Read default values from WindowDesc configuration an apply them to the window.
Definition window.cpp:192
uint8_t white_border_timer
Timer value of the WindowFlag::WhiteBorder for flags.
Definition window_gui.h:307
NWidgetStacked * shade_select
Selection widget (NWID_SELECTION) to use for shading the window. If nullptr, window cannot shade.
Definition window_gui.h:323
void InitializePositionSize(int x, int y, int min_width, int min_height)
Set the position and smallest size of the window.
Definition window.cpp:1444
Dimension unshaded_size
Last known unshaded size (only valid while shaded).
Definition window_gui.h:324
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition window.cpp:3205
virtual EventState OnKeyPress(char32_t key, uint16_t keycode)
A key has been pressed.
Definition window_gui.h:650
Window * parent
Parent window.
Definition window_gui.h:328
AllWindows< false > IterateFromBack
Iterate all windows in Z order from back to front.
Definition window_gui.h:933
virtual ~Window()
Remove window and all its child windows from the window stack.
Definition window.cpp:1128
void RaiseWidget(WidgetID widget_index)
Marks a widget as raised.
Definition window_gui.h:469
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:555
uint8_t timeout_timer
Timer value of the WindowFlag::Timeout for flags.
Definition window_gui.h:306
std::unique_ptr< ViewportData > viewport
Pointer to viewport data, if present.
Definition window_gui.h:318
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:503
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:326
virtual void OnGameTick()
Called once per (game) tick.
Definition window_gui.h:745
virtual void ShowNewGRFInspectWindow() const
Show the NewGRF inspection window.
Definition window_gui.h:867
virtual bool OnRightClick(Point pt, WidgetID widget)
A click with the right mouse button has been made on the window.
Definition window_gui.h:677
virtual void OnScrollbarScroll(WidgetID widget)
Notify window that a scrollbar position has been updated.
Definition window_gui.h:719
virtual void OnDropdownSelect(WidgetID widget, int index, int click_result)
A dropdown option associated to this window has been selected.
Definition window_gui.h:769
void ProcessScheduledInvalidations()
Process all scheduled invalidations.
Definition window.cpp:3218
void CloseChildWindows(WindowClass wc=WC_INVALID) const
Close all children a window might have in a head-recursive manner.
Definition window.cpp:1064
ResizeInfo resize
Resize information.
Definition window_gui.h:314
void UnfocusFocusedWidget()
Makes no widget on this window have focus.
Definition window.cpp:468
virtual void OnMouseLoop()
Called for every mouse loop run, which is at least once per (game) tick.
Definition window_gui.h:740
void SetShaded(bool make_shaded)
Set the shaded state of the window to make_shaded.
Definition window.cpp:1010
int scale
Scale of this window – used to determine how to resize.
Definition window_gui.h:304
void ScheduleResize()
Mark this window as resized and in need of OnResize() event.
Definition window.cpp:3183
virtual void OnPaint()
The window must be repainted.
Definition window_gui.h:595
virtual void OnDragDrop(Point pt, WidgetID widget)
A dragged 'object' has been released.
Definition window_gui.h:706
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1768
WindowDesc & window_desc
Window description.
Definition window_gui.h:299
WindowClass window_class
Window class.
Definition window_gui.h:301
virtual void OnRealtimeTick(uint delta_ms)
Called periodically.
Definition window_gui.h:750
virtual void OnMouseWheel(int wheel, WidgetID widget)
The mouse wheel has been turned.
Definition window_gui.h:734
AllWindows< true > IterateFromFront
Iterate all windows in Z order from front to back.
Definition window_gui.h:934
void CloseChildWindowById(WindowClass wc, WindowNumber number) const
Close all children a window might have in a head-recursive manner.
Definition window.cpp:1079
void SetWhiteBorder()
Set the timeout flag of the window and initiate the timer.
Definition window_gui.h:364
bool SetFocusedWidget(WidgetID widget_index)
Set focus within this window to the given widget.
Definition window.cpp:484
virtual void OnFocusLost(bool closing)
The window has lost focus.
Definition window.cpp:520
static std::vector< Window * > closed_windows
List of closed windows to delete.
Definition window_gui.h:275
void RaiseButtons(bool autoraise=false)
Raise the buttons of the window.
Definition window.cpp:529
virtual Point OnInitialPosition(int16_t sm_width, int16_t sm_height, int window_number)
Compute the initial position of the window.
Definition window.cpp:1756
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
Definition window_gui.h:316
virtual Point GetCaretPosition() const
Get the current caret position if an edit box has the focus.
Definition window.cpp:376
virtual void FindWindowPlacementAndResize(int def_width, int def_height, bool allow_resize)
Resize window towards the default size.
Definition window.cpp:1463
virtual void OnDropdownClose(Point pt, WidgetID widget, int index, int click_result, bool instant_close)
A dropdown window associated to this window has been closed.
Definition window.cpp:285
virtual void InsertTextString(WidgetID wid, std::string_view str, bool marked, std::optional< size_t > caret, std::optional< size_t > insert_location, std::optional< size_t > replacement_end)
Insert a text string at the cursor position into the edit box widget.
Definition window.cpp:2690
int left
x position of left edge of the window
Definition window_gui.h:309
bool IsShaded() const
Is window shaded currently?
Definition window_gui.h:559
Window * FindChildWindow(WindowClass wc=WC_INVALID) const
Find the Window whose parent pointer points to this window.
Definition window.cpp:1036
void SetTimeout()
Set the timeout flag of the window and initiate the timer.
Definition window_gui.h:355
const NWidgetCore * nested_focus
Currently focused nested widget, or nullptr if no nested widget has focus.
Definition window_gui.h:319
virtual void OnEditboxChanged(WidgetID widget)
The text in an editbox has been edited.
Definition window_gui.h:777
void UpdateQueryStringSize()
Update size of all QueryStrings of this window.
Definition window.cpp:352
virtual void OnScroll(Point delta)
Handle the request for (viewport) scrolling.
Definition window_gui.h:712
int top
y position of top edge of the window
Definition window_gui.h:310
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:668
const QueryString * GetQueryString(WidgetID widnum) const
Return the querystring associated to a editbox.
Definition window.cpp:332
WidgetLookup widget_lookup
Indexed access to the nested widget tree. Do not access directly, use Window::GetWidget() instead.
Definition window_gui.h:322
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:407
std::vector< int > scheduled_invalidation_data
Data of scheduled OnInvalidateData() calls.
Definition window_gui.h:282
void InitializeData(WindowNumber window_number)
Initializes the data (except the position and initial size) of a new Window.
Definition window.cpp:1406
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:727
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition window.cpp:1801
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:211
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:982
virtual bool OnTooltip(Point pt, WidgetID widget, TooltipCloseCondition close_cond)
Event to display a custom tooltip.
Definition window_gui.h:692
void LowerWidget(WidgetID widget_index)
Marks a widget as lowered.
Definition window_gui.h:460
virtual EventState OnCTRLStateChange()
The state of the control key has changed.
Definition window_gui.h:659
void ProcessScheduledResize()
Process scheduled OnResize() event.
Definition window.cpp:3191
EventState HandleEditBoxKey(WidgetID wid, char32_t key, uint16_t keycode)
Process keypress for editbox widget.
Definition window.cpp:2532
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:699
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:594
virtual void OnResize()
Called after the window got resized.
Definition window_gui.h:762
Window * FindChildWindowById(WindowClass wc, WindowNumber number) const
Find the Window whose parent pointer points to this window.
Definition window.cpp:1051
virtual void OnFocus()
The window has gained focus.
Definition window.cpp:512
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1791
virtual void OnTimeout()
Called when this window's timeout has been reached.
Definition window_gui.h:755
WindowFlags flags
Window flags.
Definition window_gui.h:300
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:312
void ProcessHighlightedInvalidations()
Process all invalidation of highlighted widgets.
Definition window.cpp:3230
virtual EventState OnHotkey(int hotkey)
A hotkey has been pressed.
Definition window.cpp:569
static void DeleteClosedWindows()
Delete all closed windows.
Definition window.cpp:67
std::unique_ptr< NWidgetBase > nested_root
Root of the nested tree.
Definition window_gui.h:321
bool scheduled_resize
Set if window has been resized.
Definition window_gui.h:283
virtual Rect GetTextBoundingRect(size_t from, size_t to) const
Get the bounding rectangle for a text range if an edit box has the focus.
Definition window.cpp:392
bool IsWidgetHighlighted(WidgetID widget_index) const
Gets the highlighted status of a widget.
Definition window.cpp:270
void DisableAllWidgetHighlight()
Disable the highlighted status of all widgets.
Definition window.cpp:222
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:851
AllWindows< false > Iterate
Iterate all windows in whatever order is easiest.
Definition window_gui.h:932
int height
Height of the window (number of pixels down in y direction)
Definition window_gui.h:312
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:684
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:311
virtual void OnInit()
Notification that the nested widget tree gets initialized.
Definition window_gui.h:578
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:302
std::vector< WindowDesc * > * _window_descs
List of WindowDescs.
Definition window.cpp:101
@ 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:408
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:80
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:283
void ScrollbarClickHandler(Window *w, NWidgetCore *nw, int x, int y)
Special handling for the scrollbar widget type.
Definition widget.cpp:259
static RectPadding ScaleGUITrad(const RectPadding &r)
Scale a RectPadding to GUI zoom level.
Definition widget.cpp:49
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:75
@ WWT_EDITBOX
a textbox for typing
Definition widget_type.h:63
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition widget_type.h:58
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition widget_type.h:56
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:53
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:77
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:61
@ 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:64
@ NWID_HSCROLLBAR
Horizontal scrollbar.
Definition widget_type.h:76
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:60
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:57
@ WWT_DEBUGBOX
NewGRF debug box (at top-right of a window, between WWT_CAPTION and WWT_SHADEBOX)
Definition widget_type.h:55
@ 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.
static const IntervalTimer< TimerWindow > highlight_interval(std::chrono::milliseconds(450), [](auto) { _window_highlight_colour=!_window_highlight_colour;})
Blink the window highlight colour constantly.
int PositionStatusbar(Window *w)
(Re)position statusbar window at the screen.
Definition window.cpp:3447
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:1990
static bool _dragging_window
A window is being dragged or resized.
Definition window.cpp:2124
static const 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.
void CloseConstructionWindows()
Close all windows that are used for construction of vehicle etc.
Definition window.cpp:3351
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:1182
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:1697
Window * GetMainWindow()
Get the main window, i.e.
Definition window.cpp:1169
static Point _drag_delta
delta between mouse cursor and upper left corner of dragged window
Definition window.cpp:54
static bool MayBeShown(const Window *w)
Returns whether a window may be shown or not.
Definition window.cpp:844
void CloseCompanyWindows(CompanyID id)
Close all windows of a company.
Definition window.cpp:1210
void HandleCtrlChanged()
State of CONTROL key has changed.
Definition window.cpp:2677
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:872
bool _scrolling_viewport
A viewport is being scrolled with the mouse.
Definition window.cpp:92
void InputLoop()
Regular call from the global game loop.
Definition window.cpp:3030
void UpdateWindows()
Update the continuously changing contents of the windows, such as the viewports.
Definition window.cpp:3095
int PositionMainToolbar(Window *w)
(Re)position main toolbar window at the screen.
Definition window.cpp:3436
void CloseNonVitalWindows()
Try to close a non-vital window.
Definition window.cpp:3307
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:934
void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen, bool schedule_resize)
Resize the window.
Definition window.cpp:2067
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:1565
int PositionNetworkChatWindow(Window *w)
(Re)position network chat window at the screen.
Definition window.cpp:3469
static void StartWindowSizing(Window *w, bool to_left)
Start resizing a window.
Definition window.cpp:2319
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:1604
PreventHideDirection
Direction for moving the window.
Definition window.cpp:1975
@ PHD_DOWN
Below v is a safe position.
Definition window.cpp:1977
@ PHD_UP
Above v is a safe position.
Definition window.cpp:1976
static void HandleAutoscroll()
If needed and switched on, perform auto scrolling (automatically moving window contents when mouse is...
Definition window.cpp:2718
bool _window_highlight_colour
If false, highlight is white, otherwise the by the widget defined colour.
Definition window.cpp:77
void HandleToolbarHotkey(int hotkey)
Handle Toolbar hotkey events - can come from a source like the MacBook Touch Bar.
Definition window.cpp:2604
static int PositionWindow(Window *w, WindowClass clss, int setting)
(Re)position a window at the screen.
Definition window.cpp:3413
void SetFocusedWindow(Window *w)
Set the window that has the focus.
Definition window.cpp:420
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:1529
static constexpr int MAX_OFFSET_DOUBLE_CLICK
How much the mouse is allowed to move to call it a double click.
Definition window.cpp:2763
Window * FindWindowByClass(WindowClass cls)
Find any window by its class.
Definition window.cpp:1155
void ChangeVehicleViewports(VehicleID from_index, VehicleID to_index)
Switches viewports following vehicles, which get autoreplaced.
Definition window.cpp:3481
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:2408
static void DispatchMouseWheelEvent(Window *w, NWidgetCore *nwid, int wheel)
Dispatch the mousewheel-action to the window.
Definition window.cpp:807
static void DispatchLeftClickEvent(Window *w, int x, int y, int click_count)
Dispatch left mouse-button (possibly double) click in window.
Definition window.cpp:611
Window * FindWindowFromPt(int x, int y)
Do a search for a window at specific coordinates.
Definition window.cpp:1813
void DeleteAllMessages()
Delete all messages and close their corresponding window (if any).
Definition window.cpp:3339
static Window * _last_scroll_window
Window of the last scroll event.
Definition window.cpp:56
int GetMainViewTop()
Return the top of the main view available for general use.
Definition window.cpp:2107
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:1386
void ReInitAllWindows(bool zoom_changed)
Re-initialize all windows.
Definition window.cpp:3381
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:2030
void CloseWindowByClass(WindowClass cls, int data)
Close all windows of a given class.
Definition window.cpp:1194
void HandleMouseEvents()
Handle a mouse event from the video driver.
Definition window.cpp:2934
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:1672
static EventState HandleWindowDragging()
Handle dragging/resizing of a window.
Definition window.cpp:2130
int PositionNewsMessage(Window *w)
(Re)position news message window at the screen.
Definition window.cpp:3458
int GetMainViewBottom()
Return the bottom of the main view available for general use.
Definition window.cpp:2118
static void DispatchHoverEvent(Window *w, int x, int y)
Dispatch hover of the mouse over a window.
Definition window.cpp:779
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:1230
void HandleKeypress(uint keycode, char32_t key)
Handle keyboard input.
Definition window.cpp:2621
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition window.cpp:3173
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:2764
bool FocusedWindowIsConsole()
Check if a console is focused.
Definition window.cpp:460
void ResetWindowSystem()
Reset the windowing system, by means of shutting it down followed by re-initialization.
Definition window.cpp:1863
static uint GetWindowZPriority(WindowClass wc)
Get the z-priority for a given window.
Definition window.cpp:1302
bool EditBoxInGlobalFocus()
Check if an edit box is in global focus.
Definition window.cpp:446
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:3265
void HideVitalWindows()
Close all always on-top windows to get an empty screen.
Definition window.cpp:3364
static bool DescSorter(WindowDesc *const &a, WindowDesc *const &b)
Sort WindowDesc by ini_key.
Definition window.cpp:167
Window * BringWindowToFrontById(WindowClass cls, WindowNumber number)
Find a window and make it the relative top-window on the screen.
Definition window.cpp:1265
void RelocateAllWindows(int neww, int newh)
Relocate all windows to fit the new size of the game application screen.
Definition window.cpp:3497
std::string _windows_file
Config file to store WindowDesc.
Definition window.cpp:104
static void HandleScrollbarScrolling(Window *w)
Handle scrollbar scrolling with the mouse.
Definition window.cpp:2335
bool _mouse_hovering
The mouse is hovering over the same point.
Definition window.cpp:93
static void StartWindowDrag(Window *w)
Start window dragging.
Definition window.cpp:2302
void CallWindowGameTickEvent()
Dispatch OnGameTick event over all windows.
Definition window.cpp:3294
static EventState HandleActiveWidget()
Handle active widget (mouse draggin on widget) with the mouse.
Definition window.cpp:2375
std::vector< WindowDesc * > * _window_descs
List of all WindowDescs.
Definition window.cpp:101
static void DispatchRightClickEvent(Window *w, int x, int y)
Dispatch right mouse-button click in window.
Definition window.cpp:750
ViewportAutoscrolling
Values for _settings_client.gui.auto_scrolling.
Definition window.cpp:47
@ VA_MAIN_VIEWPORT_FULLSCREEN
Scroll main viewport at edge when using fullscreen.
Definition window.cpp:49
@ VA_MAIN_VIEWPORT
Scroll main viewport at edge.
Definition window.cpp:50
@ VA_EVERY_VIEWPORT
Scroll all viewports at their edges.
Definition window.cpp:51
@ VA_DISABLED
Do not autoscroll when mouse is at edge of viewport.
Definition window.cpp:48
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:2788
static bool MaybeBringWindowToFront(Window *w)
Check if a window can be made relative top-most window, and if so do it.
Definition window.cpp:2472
WindowList _z_windows
List of windows opened at the screen sorted from the front to back.
Definition window.cpp:59
void CallWindowRealtimeTickEvent(uint delta_ms)
Dispatch OnRealtimeTick event over all windows.
Definition window.cpp:3056
SpecialMouseMode _special_mouse_mode
Mode of the mouse.
Definition window.cpp:95
static EventState HandleMouseDragDrop()
Handle dragging and dropping in mouse dragging mode (WSM_DRAGDROP).
Definition window.cpp:1928
void CloseAllNonVitalWindows()
It is possible that a stickied window gets to a position where the 'close' button is outside the gami...
Definition window.cpp:3326
static void HandleMouseOver()
Report position of the mouse to the underlying window.
Definition window.cpp:1952
static const 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 Window * _mouseover_last_w
Window of the last OnMouseOver event.
Definition window.cpp:55
static void CheckSoftLimit()
Check the soft limit of deletable (non vital, non sticky) windows.
Definition window.cpp:3005
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1140
void UnInitWindowSystem()
Close down the windowing system.
Definition window.cpp:1849
void InitWindowSystem()
(re)initialize the windowing system
Definition window.cpp:1827
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:3160
void HandleTextInput(std::string_view str, bool marked, std::optional< size_t > caret, std::optional< size_t > insert_location, std::optional< size_t > replacement_end)
Handle text input.
Definition window.cpp:2707
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3147
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:3282
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:420
@ 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:283
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:142
@ WDP_CENTER
Center the window.
Definition window_gui.h:145
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:144
@ WDP_ALIGN_TOOLBAR
Align toward the toolbar.
Definition window_gui.h:146
@ WDP_MANUAL
Manually align the window (so no automatic location finding)
Definition window_gui.h:143
WindowList _z_windows
List of windows opened at the screen sorted from the front to back.
Definition window.cpp:59
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 > ZoomLevel::Min) When shifting right,...
Definition zoom_func.h:22
@ Min
Minimum zoom level.