diff --git a/CMakeLists.txt b/CMakeLists.txt
index 38a7072f10..1a20eed63d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -69,9 +69,9 @@ set(TITLE_SEQUENCE_VERSION "0.4.14")
set(TITLE_SEQUENCE_URL "https://github.com/OpenRCT2/title-sequences/releases/download/v${TITLE_SEQUENCE_VERSION}/title-sequences.zip")
set(TITLE_SEQUENCE_SHA1 "6c04781b959b468e1f65ec2d2f21f5aaa5e5724d")
-set(OBJECTS_VERSION "1.5.0")
+set(OBJECTS_VERSION "1.5.1")
set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v${OBJECTS_VERSION}/objects.zip")
-set(OBJECTS_SHA1 "90c26f416ddaeb0c35490b7af89f4c6f9d6351f3")
+set(OBJECTS_SHA1 "e922b9fd779e7752176f1d0d8766c2ee6ad1e41b")
set(OPENSFX_VERSION "1.0.5")
set(OPENSFX_URL "https://github.com/OpenRCT2/OpenSoundEffects/releases/download/v${OPENSFX_VERSION}/opensound.zip")
@@ -81,9 +81,9 @@ set(OPENMSX_VERSION "1.6")
set(OPENMSX_URL "https://github.com/OpenRCT2/OpenMusic/releases/download/v${OPENMSX_VERSION}/openmusic.zip")
set(OPENMSX_SHA1 "ba170fa6d777b309c15420f4b6eb3fa25082a9d1")
-set(REPLAYS_VERSION "0.0.85")
+set(REPLAYS_VERSION "0.0.86")
set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v${REPLAYS_VERSION}/replays.zip")
-set(REPLAYS_SHA1 "2B0939953A41D2CE82809CB7C21FC3883578383F")
+set(REPLAYS_SHA1 "637E73F20C03DCD52ACA36FAEE15DADB31797FE0")
option(FORCE32 "Force 32-bit build. It will add `-m32` to compiler flags.")
option(WITH_TESTS "Build tests")
diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt
index af3b4df569..7bc26d4c2c 100644
--- a/data/language/en-GB.txt
+++ b/data/language/en-GB.txt
@@ -2169,7 +2169,6 @@ STR_3136 :Warning: This design will be built with an alternative vehicle type
STR_3137 :Select Nearby Scenery
STR_3138 :Reset Selection
STR_3139 :Cable lift unable to work in this operating mode
-STR_3140 :Cable lift hill must start immediately after station
STR_3141 :Multi-circuit per ride not possible with cable lift hill
STR_3142 :{WINDOW_COLOUR_2}Capacity: {BLACK}{STRINGID}
STR_3143 :Show people on map
@@ -3790,5 +3789,8 @@ STR_6723 :At least one entertainer peep animations object must be selected
STR_6724 :Scenario Texts
STR_6725 :X:
STR_6726 :Y:
-STR_6727 :Export emscripten data
-STR_6728 :Import emscripten data
+STR_6727 :Dive Loop (left)
+STR_6728 :Dive Loop (right)
+STR_6729 :Cable lift hill must start immediately after station or block brake
+STR_6730 :Export emscripten data
+STR_6731 :Import emscripten data
diff --git a/data/language/ko-KR.txt b/data/language/ko-KR.txt
index 8407e0017f..c6663f8fdc 100644
--- a/data/language/ko-KR.txt
+++ b/data/language/ko-KR.txt
@@ -2610,7 +2610,7 @@ STR_5368 :충돌 이력 제거
STR_5371 :오브젝트 선택
STR_5372 :마우스 오른쪽 드래그 시 좌우 반전
STR_5373 :이름 {STRINGID}
-STR_5374 :날짜 {STRINGID}
+STR_5374 :수정 날짜 {STRINGID}
STR_5375 :▲
STR_5376 :▼
STR_5404 :이미 존재하는 이름입니다
@@ -3506,9 +3506,9 @@ STR_6437 :보이기
STR_6438 :{MOVE_X}{2}👁
STR_6439 :칸 조사 창: 감춤 여부
STR_6440 :물 투명하게 보기
-STR_6441 :최소 하나 이상의 일반 보도 바닥 오브젝트를 선택해야 합니다.
-STR_6442 :최소 하나 이상의 대기 줄 보도 바닥 오브젝트를 선택해야 합니다.
-STR_6443 :최소 하나 이상의 보도 난간 오브젝트를 선택해야 합니다.
+STR_6441 :최소 하나 이상의 일반 보도 바닥 오브젝트를 선택해야 합니다
+STR_6442 :최소 하나 이상의 대기 줄 보도 바닥 오브젝트를 선택해야 합니다
+STR_6443 :최소 하나 이상의 보도 난간 오브젝트를 선택해야 합니다
STR_6444 :보도 바닥
STR_6445 :보도 난간
STR_6446 :{WINDOW_COLOUR_2}바닥 이름: {BLACK}{STRINGID}
@@ -3775,3 +3775,19 @@ STR_6707 :(선택 안 함)
STR_6708 :부드러움 강도
STR_6709 :부드러움 강도를 {COMMA16}∼{COMMA16} 사이의 값으로 입력하세요
STR_6710 :안정된 정렬
+STR_6711 :파일 이름:
+STR_6712 :저장
+STR_6713 :{COMMA32} {STRINGID}
+STR_6714 :파일 이름
+STR_6715 :수정 날짜
+STR_6716 :파일 크기
+STR_6717 :파일 크기 {STRINGID}
+STR_6718 :손님 애니메이션
+STR_6719 :최소 하나 이상의 손님 애니메이션 오브젝트를 선택해야 합니다
+STR_6720 :최소 하나 이상의 미화원 애니메이션 오브젝트를 선택해야 합니다
+STR_6721 :최소 하나 이상의 정비기술자 애니메이션 오브젝트를 선택해야 합니다
+STR_6722 :최소 하나 이상의 경비원 애니메이션 오브젝트를 선택해야 합니다
+STR_6723 :최소 하나 이상의 엔터테이너 애니메이션 오브젝트를 선택해야 합니다
+STR_6724 :시나리오 텍스트
+STR_6725 :X:
+STR_6726 :Y:
diff --git a/data/language/nl-NL.txt b/data/language/nl-NL.txt
index a653cdeb36..589f087900 100644
--- a/data/language/nl-NL.txt
+++ b/data/language/nl-NL.txt
@@ -2607,7 +2607,7 @@ STR_5368 :Crashstatus weg
STR_5371 :Objectselectie
STR_5372 :Sleeprichting van rechtermuisknop omkeren
STR_5373 :Naam {STRINGID}
-STR_5374 :Datum {STRINGID}
+STR_5374 :Gewijzigd {STRINGID}
STR_5375 :▲
STR_5376 :▼
STR_5404 :Naam bestaat al
@@ -3773,3 +3773,8 @@ STR_6709 :Voer een afrondsterkte in tussen {COMMA16} en {COMMA16}
STR_6710 :Stabiel sorteren
STR_6711 :Bestandsnaam:
STR_6712 :Opslaan
+STR_6713 :{COMMA32} {STRINGID}
+STR_6714 :Naam
+STR_6715 :Gewijzigd
+STR_6716 :Grootte
+STR_6717 :Grootte {STRINGID}
diff --git a/data/language/pl-PL.txt b/data/language/pl-PL.txt
index aec3b5cae6..c9eec9dbcb 100644
--- a/data/language/pl-PL.txt
+++ b/data/language/pl-PL.txt
@@ -1093,7 +1093,7 @@ STR_1698 :Można to umieścić jedynie na ścieżce kolejki
STR_1699 :Za dużo ludzi w grze
STR_1700 :Zatrudnij dozorcę
STR_1701 :Zatrudnij mechanika
-STR_1702 :Zatrudnij ochroniarza
+STR_1702 :Zatrudnij strażnika
STR_1703 :Zatrudnij komika
STR_1704 :Nie można zatrudnić nowych pracowników…
STR_1705 :Zwolnij pracownika
@@ -2000,7 +2000,7 @@ STR_2804 :Podświetl tych pracowników na mapie
STR_2805 :Pokaż plan parku
STR_2806 :{RED}Goście skarżą się na fatalny stan ścieżek w twoim parku{NEWLINE}Sprawdź gdzie znajdują się twoi dozorcy i rozważ lepszą organizacje ich pracy
STR_2807 :{RED}Goście skarżą się na śmieci leżące na ziemi w twoim parku{NEWLINE}Sprawdź gdzie znajdują się twoi dozorcy i rozważ lepszą organizację ich pracy
-STR_2808 :{RED}Goście skarzą się na wandalizm w twoim parku{NEWLINE}Sprawdź gdzie znajdują się twoi ochroniarze i rozważ poprawę organizacji ich pracy
+STR_2808 :{RED}Goście skarzą się na wandalizm w twoim parku{NEWLINE}Sprawdź gdzie znajdują się twoi strażnicy i rozważ poprawę organizacji ich pracy
STR_2809 :{RED}Goście są głodni i nie mogą znaleźć miejsca gdzie mogliby kupić coś do jedzenia
STR_2810 :{RED}Goście są spragnieni i nie mogą znaleźć miejsca gdzie mogliby kupić jakieś napoje
STR_2811 :{RED}Goście się skarżą, że w twoim parku bardzo ciężko jest znaleźć toaletę
@@ -2201,7 +2201,7 @@ STR_3188 :Znaki drogowe
STR_3189 :Klasyczne ścieżki
STR_3190 :Dodatki drogowe
STR_3191 :Grupa scenerii
-STR_3192 :Wejście do parku
+STR_3192 :Wejścia do parku
STR_3193 :Woda
STR_3195 :Lista wynalazków
STR_3196 :{WINDOW_COLOUR_2}Grupa badawcza: {BLACK}{STRINGID}
@@ -3736,8 +3736,8 @@ STR_6671 :Pokazuj „prawdziwe” imiona pracowników
STR_6672 :Przełącz między pokazywaniem imion pracowników a numerami
STR_6673 :Przezroczyste
STR_6674 :{MONTH}, Rok {COMMA16}
-STR_6675 :Imiona gości
-STR_6676 :Co najmniej jeden obiekt z nazwami gości musi być wybrany
+STR_6675 :Imiona postaci
+STR_6676 :Należy wybrać co najmniej jeden obiekt z nazwami postaci
STR_6677 :Dodaj plaże wokół zbiorników wodnych
STR_6678 :Źródło mapy wysokości:
STR_6679 :Równina
@@ -3779,3 +3779,12 @@ STR_6714 :Nazwa pliku
STR_6715 :Data modyfikacji
STR_6716 :Rozmiar pliku
STR_6717 :Rozmiar {STRINGID}
+STR_6718 :Animacje postaci
+STR_6719 :Należy wybrać co najmniej jeden obiekt animacji gościa
+STR_6720 :Należy wybrać co najmniej jeden obiekt animacji dozorcy
+STR_6721 :Należy wybrać co najmniej jeden obiekt animacji mechanika
+STR_6722 :Należy wybrać co najmniej jeden obiekt animacji strażnika
+STR_6723 :Należy wybrać co najmniej jeden obiekt animacji komika
+STR_6724 :Teksty scenariuszy
+STR_6725 :X:
+STR_6726 :Y:
diff --git a/data/language/pt-BR.txt b/data/language/pt-BR.txt
index f5dddab6c8..5ce468928b 100644
--- a/data/language/pt-BR.txt
+++ b/data/language/pt-BR.txt
@@ -2201,7 +2201,7 @@ STR_3188 :Placa para Caminho
STR_3189 :Calçadas Obsoletas
STR_3190 :Caminhos Extras
STR_3191 :Grupo de Cenários
-STR_3192 :Entrada do Parque
+STR_3192 :Entradas dos Parques
STR_3193 :Água
STR_3195 :Lista de Invenções
STR_3196 :{WINDOW_COLOUR_2}Grupo de Pesquisa: {BLACK}{STRINGID}
@@ -3785,3 +3785,6 @@ STR_6720 :Ao menos um objeto de animação de pessoinha de faxineiro deve ser
STR_6721 :Ao menos um objeto de animação de pessoinha de mecânico deve ser selecionado
STR_6722 :Ao menos um objeto de animação de pessoinha de segurança deve ser selecionado
STR_6723 :Ao menos um objeto de animação de pessoinha de animador deve ser selecionado
+STR_6724 :Textos dos Cenários
+STR_6725 :X:
+STR_6726 :Y:
diff --git a/data/language/ru-RU.txt b/data/language/ru-RU.txt
index d6b62380b7..3897aa8241 100644
--- a/data/language/ru-RU.txt
+++ b/data/language/ru-RU.txt
@@ -2162,7 +2162,6 @@ STR_3136 :Внимание: Этот дизайн будет построен
STR_3137 :Выберите Ближайший Пейзаж
STR_3138 :Сброс Выбора
STR_3139 :Кабельный лифт не может работать в этом режиме
-STR_3140 :Кабельный лифт должен начинаться сразу после станции
STR_3141 :Мульти-кольца невозможны с кабельным лифтом
STR_3142 :{WINDOW_COLOUR_2}Вместимость: {BLACK}{STRINGID}
STR_3143 :Показать людей на карте
@@ -2194,7 +2193,7 @@ STR_3188 :Знаки
STR_3189 :Дорожки
STR_3190 :Доп. пути
STR_3191 :Группы пейзажа
-STR_3192 :Вход в парк
+STR_3192 :Входы в парк
STR_3193 :Вода
STR_3195 :Изобретения
STR_3196 :{WINDOW_COLOUR_2} Разработка: {BLACK}{STRINGID}
@@ -3773,3 +3772,7 @@ STR_6720 :Нужно выбрать хотя бы один объект ан
STR_6721 :Нужно выбрать хотя бы один объект анимации механиков
STR_6722 :Нужно выбрать хотя бы один объект анимации охранников
STR_6723 :Нужно выбрать хотя бы один объект анимации развлекателей
+STR_6724 :Тексты сценариев
+STR_6725 :X:
+STR_6726 :Y:
+STR_6729 :Кабельный лифт должен начинаться сразу после станции или блок-тормоза
diff --git a/distribution/changelog.txt b/distribution/changelog.txt
index bf3503ffd9..93c5199f49 100644
--- a/distribution/changelog.txt
+++ b/distribution/changelog.txt
@@ -1,13 +1,19 @@
0.4.19 (in development)
------------------------------------------------------------------------
- Feature: [#23328] Introducing peep animation objects, enabling custom entertainer costumes.
+- Feature: [#23569] Add large diagonal flat to steep and dive loop track pieces.
+- Improved: [#20683] Allow Giga Coaster cable lift to start after block brake section.
- Improved: [#23328] The costume list in the staff window is now ordered alphabetically.
- Improved: [#23540] The file browser now optionally shows a file size column.
- Change: [#23328] All RCT2 entertainer costumes are now available in legacy parks.
+- Fix: [#1479] Incorrect values provided by the in game console “get location” command.
- Fix: [#21794] Lay-down coaster cars reverse on first frames of downwards corkscrew.
+- Fix: [#23368] Incorrect refund amount when deleting track pieces at or above 96m.
- Fix: [#23508] Simultaneous virtual floors shown for ride and footpath.
+- Fix: [#23512] Holding brakes are skipped if they’re too close together.
- Fix: [#23581] [Plugin] Food/drink items given to guests have no consumption duration set.
- Fix: [#23591] “Install new track” button in Track Designs Manager is misaligned.
+- Fix: [#23618] Can no longer build diagonal brakes & block brakes on Steeplechase, Inverted Lay-down, & Inverted Multi-Dim roller coasters.
0.4.18 (2025-01-08)
------------------------------------------------------------------------
diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts
index 24b36a1244..a9bf7f0c80 100644
--- a/distribution/openrct2.d.ts
+++ b/distribution/openrct2.d.ts
@@ -4874,6 +4874,9 @@ declare global {
frameBase: number;
frameCount?: number;
frameDuration?: number;
+ primaryColour?: number;
+ secondaryColour?: number;
+ tertiaryColour?: number;
offset?: ScreenCoordsXY;
}
diff --git a/distribution/windows/readme.md b/distribution/windows/readme.md
index 573a74915b..d684897d39 100644
--- a/distribution/windows/readme.md
+++ b/distribution/windows/readme.md
@@ -1,6 +1,4 @@
# Windows Installer
This directory contains the script and resources for the Windows installer. The installer is created using [Nullsoft Scriptable Install System (NSIS)](http://nsis.sourceforge.net) version v3.0a0+.
-As there is currently only a 32 bit version of OpenRCT2 available, the architecture and windows version checks have been disabled. These will be re-enabled once OpenRCT2 is a stand alone executable.
-
Code based on [OpenTTD](http://openttd.org) installer.
diff --git a/openrct2.proj b/openrct2.proj
index 4ec99e95d6..179c9a9f12 100644
--- a/openrct2.proj
+++ b/openrct2.proj
@@ -45,14 +45,14 @@
9984c1e317dcfb3aaf8e17f1db2ebb0f771e2373
https://github.com/OpenRCT2/title-sequences/releases/download/v0.4.14/title-sequences.zip
6c04781b959b468e1f65ec2d2f21f5aaa5e5724d
- https://github.com/OpenRCT2/objects/releases/download/v1.5.0/objects.zip
- 90c26f416ddaeb0c35490b7af89f4c6f9d6351f3
+ https://github.com/OpenRCT2/objects/releases/download/v1.5.1/objects.zip
+ e922b9fd779e7752176f1d0d8766c2ee6ad1e41b
https://github.com/OpenRCT2/OpenSoundEffects/releases/download/v1.0.5/opensound.zip
b1b1f1b241d2cbff63a1889c4dc5a09bdf769bfb
https://github.com/OpenRCT2/OpenMusic/releases/download/v1.6/openmusic.zip
ba170fa6d777b309c15420f4b6eb3fa25082a9d1
- https://github.com/OpenRCT2/replays/releases/download/v0.0.85/replays.zip
- 2B0939953A41D2CE82809CB7C21FC3883578383F
+ https://github.com/OpenRCT2/replays/releases/download/v0.0.86/replays.zip
+ 637E73F20C03DCD52ACA36FAEE15DADB31797FE0
diff --git a/readme.md b/readme.md
index c592acc44f..dba893e4e3 100644
--- a/readme.md
+++ b/readme.md
@@ -226,7 +226,7 @@ OpenRCT2 requires original files of RollerCoaster Tycoon 2 to play. It can be bo
---
# 4. Contributing
-OpenRCT2 uses the [gitflow workflow](https://www.atlassian.com/git/tutorials/comparing-workflows#gitflow-workflow). If you are implementing a new feature or logic from the original game, please branch off and perform pull requests to ```develop```. If you are fixing a bug for the next release, please branch off and perform pull requests to the correct release branch. ```master``` only contains tagged releases, you should never branch off this.
+OpenRCT2 uses the [gitflow workflow](https://www.atlassian.com/git/tutorials/comparing-workflows#gitflow-workflow). If you are implementing a new feature or fixing a bug, please branch off and perform pull requests to ```develop```. ```master``` only contains tagged releases, you should never branch off this.
Please read our [contributing guidelines](https://github.com/OpenRCT2/OpenRCT2/blob/develop/CONTRIBUTING.md) for information.
diff --git a/resources/g2/sprites.json b/resources/g2/sprites.json
index 4137a78b68..b9842c0b7d 100644
--- a/resources/g2/sprites.json
+++ b/resources/g2/sprites.json
@@ -6597,6 +6597,342 @@
"y": -22,
"palette": "keep"
},
+ {
+ "path": "track/lattice_triangle/flat_to_steep_up_diag_1_1.png",
+ "x": -32,
+ "y": -6,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/flat_to_steep_up_diag_1_2.png",
+ "x": -32,
+ "y": -25,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/flat_to_steep_up_diag_1_3.png",
+ "x": -32,
+ "y": -44,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/flat_to_steep_up_diag_2_1.png",
+ "x": -8,
+ "y": -10,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/flat_to_steep_up_diag_2_2.png",
+ "x": 0,
+ "y": 0,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/flat_to_steep_up_diag_2_3.png",
+ "x": -8,
+ "y": -26,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/flat_to_steep_up_diag_3_1.png",
+ "x": -32,
+ "y": -6,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/flat_to_steep_up_diag_3_2.png",
+ "x": -32,
+ "y": -25,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/flat_to_steep_up_diag_3_3.png",
+ "x": -32,
+ "y": -44,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/flat_to_steep_up_diag_4_1.png",
+ "x": -8,
+ "y": -16,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/flat_to_steep_up_diag_4_2.png",
+ "x": -8,
+ "y": -48,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/flat_to_steep_up_diag_4_3.png",
+ "x": -8,
+ "y": -89,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/steep_to_flat_up_diag_1_1.png",
+ "x": -32,
+ "y": -47,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/steep_to_flat_up_diag_1_2.png",
+ "x": -32,
+ "y": -20,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/steep_to_flat_up_diag_1_3.png",
+ "x": -32,
+ "y": -5,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/steep_to_flat_up_diag_2_1.png",
+ "x": 0,
+ "y": 0,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/steep_to_flat_up_diag_2_2.png",
+ "x": 0,
+ "y": 0,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/steep_to_flat_up_diag_2_3.png",
+ "x": -8,
+ "y": -14,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/steep_to_flat_up_diag_3_1.png",
+ "x": -32,
+ "y": -47,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/steep_to_flat_up_diag_3_2.png",
+ "x": -32,
+ "y": -20,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/steep_to_flat_up_diag_3_3.png",
+ "x": -32,
+ "y": -5,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/steep_to_flat_up_diag_4_1.png",
+ "x": -8,
+ "y": -32,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/steep_to_flat_up_diag_4_2.png",
+ "x": -8,
+ "y": -72,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/steep_to_flat_up_diag_4_3.png",
+ "x": -8,
+ "y": -42,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_left_1_1.png",
+ "x": -32,
+ "y": -31,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_left_1_2.png",
+ "x": -32,
+ "y": -41,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_left_1_3.png",
+ "x": -31,
+ "y": -41,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_left_1_4.png",
+ "x": -18,
+ "y": -23,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_left_2_1.png",
+ "x": -8,
+ "y": 12,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_left_2_2.png",
+ "x": -7,
+ "y": -27,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_left_2_3.png",
+ "x": -25,
+ "y": -25,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_left_2_4.png",
+ "x": -28,
+ "y": -13,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_left_3_1.png",
+ "x": 0,
+ "y": -33,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_left_3_2.png",
+ "x": -14,
+ "y": -27,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_left_3_3.png",
+ "x": -24,
+ "y": -21,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_left_3_4.png",
+ "x": -22,
+ "y": -14,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_left_4_1.png",
+ "x": -11,
+ "y": -32,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_left_4_2.png",
+ "x": -45,
+ "y": -83,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_left_4_3.png",
+ "x": -24,
+ "y": -40,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_left_4_4.png",
+ "x": -22,
+ "y": -23,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_right_1_1.png",
+ "x": -32,
+ "y": -33,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_right_1_2.png",
+ "x": -32,
+ "y": -27,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_right_1_3.png",
+ "x": -28,
+ "y": -21,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_right_1_4.png",
+ "x": -32,
+ "y": -14,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_right_2_1.png",
+ "x": -9,
+ "y": 12,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_right_2_2.png",
+ "x": -20,
+ "y": -27,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_right_2_3.png",
+ "x": -11,
+ "y": -25,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_right_2_4.png",
+ "x": -22,
+ "y": -13,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_right_3_1.png",
+ "x": 0,
+ "y": -31,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_right_3_2.png",
+ "x": -12,
+ "y": -41,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_right_3_3.png",
+ "x": -24,
+ "y": -41,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_right_3_4.png",
+ "x": -22,
+ "y": -23,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_right_4_1.png",
+ "x": -8,
+ "y": -32,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_right_4_2.png",
+ "x": -4,
+ "y": -83,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_right_4_3.png",
+ "x": -30,
+ "y": -40,
+ "palette": "keep"
+ },
+ {
+ "path": "track/lattice_triangle/dive_loop_45_right_4_4.png",
+ "x": -23,
+ "y": -23,
+ "palette": "keep"
+ },
{
"path": "track/mini/booster_1.png",
"x": -22,
@@ -8741,6 +9077,342 @@
"y": -29,
"palette": "keep"
},
+ {
+ "path": "track/bm/flat_to_steep_up_diag_1_1.png",
+ "x": -32,
+ "y": -7,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/flat_to_steep_up_diag_1_2.png",
+ "x": -32,
+ "y": -27,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/flat_to_steep_up_diag_1_3.png",
+ "x": -32,
+ "y": -46,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/flat_to_steep_up_diag_2_1.png",
+ "x": -13,
+ "y": -9,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/flat_to_steep_up_diag_2_2.png",
+ "x": 0,
+ "y": 0,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/flat_to_steep_up_diag_2_3.png",
+ "x": -13,
+ "y": -24,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/flat_to_steep_up_diag_3_1.png",
+ "x": -32,
+ "y": -7,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/flat_to_steep_up_diag_3_2.png",
+ "x": -32,
+ "y": -26,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/flat_to_steep_up_diag_3_3.png",
+ "x": -32,
+ "y": -45,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/flat_to_steep_up_diag_4_1.png",
+ "x": -13,
+ "y": -16,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/flat_to_steep_up_diag_4_2.png",
+ "x": -13,
+ "y": -48,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/flat_to_steep_up_diag_4_3.png",
+ "x": -13,
+ "y": -88,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/steep_to_flat_up_diag_1_1.png",
+ "x": -32,
+ "y": -49,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/steep_to_flat_up_diag_1_2.png",
+ "x": -32,
+ "y": -21,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/steep_to_flat_up_diag_1_3.png",
+ "x": -32,
+ "y": -7,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/steep_to_flat_up_diag_2_1.png",
+ "x": 0,
+ "y": 0,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/steep_to_flat_up_diag_2_2.png",
+ "x": 0,
+ "y": 0,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/steep_to_flat_up_diag_2_3.png",
+ "x": -13,
+ "y": -13,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/steep_to_flat_up_diag_3_1.png",
+ "x": -32,
+ "y": -48,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/steep_to_flat_up_diag_3_2.png",
+ "x": -32,
+ "y": -21,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/steep_to_flat_up_diag_3_3.png",
+ "x": -32,
+ "y": -7,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/steep_to_flat_up_diag_4_1.png",
+ "x": -13,
+ "y": -32,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/steep_to_flat_up_diag_4_2.png",
+ "x": -13,
+ "y": -72,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/steep_to_flat_up_diag_4_3.png",
+ "x": -13,
+ "y": -41,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_left_1_1.png",
+ "x": -32,
+ "y": -32,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_left_1_2.png",
+ "x": -32,
+ "y": -47,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_left_1_3.png",
+ "x": -32,
+ "y": -44,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_left_1_4.png",
+ "x": -20,
+ "y": -22,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_left_2_1.png",
+ "x": -13,
+ "y": 12,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_left_2_2.png",
+ "x": -12,
+ "y": -27,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_left_2_3.png",
+ "x": -26,
+ "y": -23,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_left_2_4.png",
+ "x": -27,
+ "y": -12,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_left_3_1.png",
+ "x": 0,
+ "y": -36,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_left_3_2.png",
+ "x": -19,
+ "y": -29,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_left_3_3.png",
+ "x": -37,
+ "y": -20,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_left_3_4.png",
+ "x": -26,
+ "y": -12,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_left_4_1.png",
+ "x": -16,
+ "y": -32,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_left_4_2.png",
+ "x": -60,
+ "y": -96,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_left_4_3.png",
+ "x": -28,
+ "y": -40,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_left_4_4.png",
+ "x": -25,
+ "y": -22,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_right_1_1.png",
+ "x": -32,
+ "y": -37,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_right_1_2.png",
+ "x": -32,
+ "y": -30,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_right_1_3.png",
+ "x": -30,
+ "y": -21,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_right_1_4.png",
+ "x": -32,
+ "y": -12,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_right_2_1.png",
+ "x": -15,
+ "y": 12,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_right_2_2.png",
+ "x": -25,
+ "y": -27,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_right_2_3.png",
+ "x": -13,
+ "y": -23,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_right_2_4.png",
+ "x": -26,
+ "y": -12,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_right_3_1.png",
+ "x": 0,
+ "y": -31,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_right_3_2.png",
+ "x": -14,
+ "y": -45,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_right_3_3.png",
+ "x": -28,
+ "y": -43,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_right_3_4.png",
+ "x": -25,
+ "y": -22,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_right_4_1.png",
+ "x": -13,
+ "y": -32,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_right_4_2.png",
+ "x": -9,
+ "y": -89,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_right_4_3.png",
+ "x": -31,
+ "y": -40,
+ "palette": "keep"
+ },
+ {
+ "path": "track/bm/dive_loop_45_right_4_4.png",
+ "x": -24,
+ "y": -22,
+ "palette": "keep"
+ },
{
"path": "track/railway/quarter_turn_3_tiles_sw_se_part_3.png",
"x": -8,
@@ -19212,6 +19884,342 @@
"y": -25,
"palette": "keep"
},
+ {
+ "path": "track/corkscrew/flat_to_steep_up_diag_1_1.png",
+ "x": -32,
+ "y": -6,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/flat_to_steep_up_diag_1_2.png",
+ "x": -32,
+ "y": -26,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/flat_to_steep_up_diag_1_3.png",
+ "x": -32,
+ "y": -44,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/flat_to_steep_up_diag_2_1.png",
+ "x": -14,
+ "y": -8,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/flat_to_steep_up_diag_2_2.png",
+ "x": 0,
+ "y": 0,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/flat_to_steep_up_diag_2_3.png",
+ "x": -14,
+ "y": -25,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/flat_to_steep_up_diag_3_1.png",
+ "x": -32,
+ "y": -6,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/flat_to_steep_up_diag_3_2.png",
+ "x": -32,
+ "y": -26,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/flat_to_steep_up_diag_3_3.png",
+ "x": -32,
+ "y": -44,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/flat_to_steep_up_diag_4_1.png",
+ "x": -14,
+ "y": -16,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/flat_to_steep_up_diag_4_2.png",
+ "x": -14,
+ "y": -48,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/flat_to_steep_up_diag_4_3.png",
+ "x": -14,
+ "y": -88,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/steep_to_flat_up_diag_1_1.png",
+ "x": -32,
+ "y": -48,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/steep_to_flat_up_diag_1_2.png",
+ "x": -32,
+ "y": -20,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/steep_to_flat_up_diag_1_3.png",
+ "x": -32,
+ "y": -6,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/steep_to_flat_up_diag_2_1.png",
+ "x": 0,
+ "y": 0,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/steep_to_flat_up_diag_2_2.png",
+ "x": 0,
+ "y": 0,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/steep_to_flat_up_diag_2_3.png",
+ "x": -14,
+ "y": -13,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/steep_to_flat_up_diag_3_1.png",
+ "x": -32,
+ "y": -48,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/steep_to_flat_up_diag_3_2.png",
+ "x": -32,
+ "y": -20,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/steep_to_flat_up_diag_3_3.png",
+ "x": -32,
+ "y": -6,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/steep_to_flat_up_diag_4_1.png",
+ "x": -14,
+ "y": -32,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/steep_to_flat_up_diag_4_2.png",
+ "x": -14,
+ "y": -72,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/steep_to_flat_up_diag_4_3.png",
+ "x": -14,
+ "y": -40,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_left_1_1.png",
+ "x": -32,
+ "y": -30,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_left_1_2.png",
+ "x": -32,
+ "y": -46,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_left_1_3.png",
+ "x": -32,
+ "y": -44,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_left_1_4.png",
+ "x": -21,
+ "y": -17,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_left_2_1.png",
+ "x": -14,
+ "y": 12,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_left_2_2.png",
+ "x": -13,
+ "y": -27,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_left_2_3.png",
+ "x": -27,
+ "y": -20,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_left_2_4.png",
+ "x": -26,
+ "y": -10,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_left_3_1.png",
+ "x": 0,
+ "y": -35,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_left_3_2.png",
+ "x": -19,
+ "y": -31,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_left_3_3.png",
+ "x": -40,
+ "y": -15,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_left_3_4.png",
+ "x": -24,
+ "y": -8,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_left_4_1.png",
+ "x": -17,
+ "y": -32,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_left_4_2.png",
+ "x": -55,
+ "y": -90,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_left_4_3.png",
+ "x": -28,
+ "y": -40,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_left_4_4.png",
+ "x": -24,
+ "y": -17,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_right_1_1.png",
+ "x": -32,
+ "y": -35,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_right_1_2.png",
+ "x": -32,
+ "y": -31,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_right_1_3.png",
+ "x": -31,
+ "y": -15,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_right_1_4.png",
+ "x": -32,
+ "y": -8,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_right_2_1.png",
+ "x": -15,
+ "y": 12,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_right_2_2.png",
+ "x": -24,
+ "y": -27,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_right_2_3.png",
+ "x": -13,
+ "y": -20,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_right_2_4.png",
+ "x": -24,
+ "y": -10,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_right_3_1.png",
+ "x": 0,
+ "y": -30,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_right_3_2.png",
+ "x": -14,
+ "y": -46,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_right_3_3.png",
+ "x": -28,
+ "y": -44,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_right_3_4.png",
+ "x": -24,
+ "y": -17,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_right_4_1.png",
+ "x": -14,
+ "y": -32,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_right_4_2.png",
+ "x": -10,
+ "y": -82,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_right_4_3.png",
+ "x": -27,
+ "y": -40,
+ "palette": "keep"
+ },
+ {
+ "path": "track/corkscrew/dive_loop_45_right_4_4.png",
+ "x": -21,
+ "y": -17,
+ "palette": "keep"
+ },
{
"path": "track/lim/barrel_roll_left_1_1.png",
"x": -22,
@@ -35479,6 +36487,342 @@
"y": -15,
"palette": "keep"
},
+ {
+ "path": "track/raptor/flat_to_steep_up_diag_1_1.png",
+ "x": -32,
+ "y": 0,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/flat_to_steep_up_diag_1_2.png",
+ "x": -32,
+ "y": -20,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/flat_to_steep_up_diag_1_3.png",
+ "x": -32,
+ "y": -39,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/flat_to_steep_up_diag_2_1.png",
+ "x": -3,
+ "y": -6,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/flat_to_steep_up_diag_2_2.png",
+ "x": 0,
+ "y": 0,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/flat_to_steep_up_diag_2_3.png",
+ "x": -3,
+ "y": -22,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/flat_to_steep_up_diag_3_1.png",
+ "x": -32,
+ "y": 0,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/flat_to_steep_up_diag_3_2.png",
+ "x": -32,
+ "y": -20,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/flat_to_steep_up_diag_3_3.png",
+ "x": -32,
+ "y": -39,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/flat_to_steep_up_diag_4_1.png",
+ "x": -3,
+ "y": -16,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/flat_to_steep_up_diag_4_2.png",
+ "x": -3,
+ "y": -48,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/flat_to_steep_up_diag_4_3.png",
+ "x": -3,
+ "y": -85,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/steep_to_flat_up_diag_1_1.png",
+ "x": -32,
+ "y": -42,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/steep_to_flat_up_diag_1_2.png",
+ "x": -32,
+ "y": -14,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/steep_to_flat_up_diag_1_3.png",
+ "x": -32,
+ "y": 1,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/steep_to_flat_up_diag_2_1.png",
+ "x": 0,
+ "y": 0,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/steep_to_flat_up_diag_2_2.png",
+ "x": 0,
+ "y": 0,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/steep_to_flat_up_diag_2_3.png",
+ "x": -3,
+ "y": -10,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/steep_to_flat_up_diag_3_1.png",
+ "x": -32,
+ "y": -42,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/steep_to_flat_up_diag_3_2.png",
+ "x": -32,
+ "y": -14,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/steep_to_flat_up_diag_3_3.png",
+ "x": -32,
+ "y": 1,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/steep_to_flat_up_diag_4_1.png",
+ "x": -3,
+ "y": -32,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/steep_to_flat_up_diag_4_2.png",
+ "x": -3,
+ "y": -72,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/steep_to_flat_up_diag_4_3.png",
+ "x": -3,
+ "y": -37,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_left_1_1.png",
+ "x": -32,
+ "y": -26,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_left_1_2.png",
+ "x": -32,
+ "y": -37,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_left_1_3.png",
+ "x": -27,
+ "y": -38,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_left_1_4.png",
+ "x": -14,
+ "y": -13,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_left_2_1.png",
+ "x": -3,
+ "y": 12,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_left_2_2.png",
+ "x": -1,
+ "y": -24,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_left_2_3.png",
+ "x": -20,
+ "y": -16,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_left_2_4.png",
+ "x": -23,
+ "y": -4,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_left_3_1.png",
+ "x": 0,
+ "y": -26,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_left_3_2.png",
+ "x": -12,
+ "y": -23,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_left_3_3.png",
+ "x": -16,
+ "y": -12,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_left_3_4.png",
+ "x": -18,
+ "y": -3,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_left_4_1.png",
+ "x": -7,
+ "y": -32,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_left_4_2.png",
+ "x": -24,
+ "y": -46,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_left_4_3.png",
+ "x": -24,
+ "y": -38,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_left_4_4.png",
+ "x": -18,
+ "y": -13,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_right_1_1.png",
+ "x": -32,
+ "y": -26,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_right_1_2.png",
+ "x": -32,
+ "y": -23,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_right_1_3.png",
+ "x": -24,
+ "y": -12,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_right_1_4.png",
+ "x": -32,
+ "y": -3,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_right_2_1.png",
+ "x": -5,
+ "y": 12,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_right_2_2.png",
+ "x": -19,
+ "y": -24,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_right_2_3.png",
+ "x": -11,
+ "y": -16,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_right_2_4.png",
+ "x": -18,
+ "y": -4,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_right_3_1.png",
+ "x": 0,
+ "y": -26,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_right_3_2.png",
+ "x": -11,
+ "y": -37,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_right_3_3.png",
+ "x": -22,
+ "y": -38,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_right_3_4.png",
+ "x": -18,
+ "y": -13,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_right_4_1.png",
+ "x": -3,
+ "y": -32,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_right_4_2.png",
+ "x": -1,
+ "y": -80,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_right_4_3.png",
+ "x": -23,
+ "y": -38,
+ "palette": "keep"
+ },
+ {
+ "path": "track/raptor/dive_loop_45_right_4_4.png",
+ "x": -14,
+ "y": -13,
+ "palette": "keep"
+ },
{
"path": "track/raptor/flat_lift_1.png",
"x": -18,
diff --git a/resources/g2/track/bm/dive_loop_45_left_1_1.png b/resources/g2/track/bm/dive_loop_45_left_1_1.png
new file mode 100644
index 0000000000..79f3cbe28c
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_1_1.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_left_1_2.png b/resources/g2/track/bm/dive_loop_45_left_1_2.png
new file mode 100644
index 0000000000..8859b18970
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_1_2.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_left_1_3.png b/resources/g2/track/bm/dive_loop_45_left_1_3.png
new file mode 100644
index 0000000000..9771a16644
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_1_3.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_left_1_4.png b/resources/g2/track/bm/dive_loop_45_left_1_4.png
new file mode 100644
index 0000000000..7e3a09d563
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_1_4.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_left_2_1.png b/resources/g2/track/bm/dive_loop_45_left_2_1.png
new file mode 100644
index 0000000000..54df52b812
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_2_1.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_left_2_2.png b/resources/g2/track/bm/dive_loop_45_left_2_2.png
new file mode 100644
index 0000000000..2cb8cafd64
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_2_2.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_left_2_3.png b/resources/g2/track/bm/dive_loop_45_left_2_3.png
new file mode 100644
index 0000000000..d3bf497762
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_2_3.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_left_2_4.png b/resources/g2/track/bm/dive_loop_45_left_2_4.png
new file mode 100644
index 0000000000..361d40b67d
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_2_4.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_left_3_1.png b/resources/g2/track/bm/dive_loop_45_left_3_1.png
new file mode 100644
index 0000000000..b7cfb80ee4
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_3_1.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_left_3_2.png b/resources/g2/track/bm/dive_loop_45_left_3_2.png
new file mode 100644
index 0000000000..2bfc6b3957
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_3_2.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_left_3_3.png b/resources/g2/track/bm/dive_loop_45_left_3_3.png
new file mode 100644
index 0000000000..b45bd199f4
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_3_3.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_left_3_4.png b/resources/g2/track/bm/dive_loop_45_left_3_4.png
new file mode 100644
index 0000000000..67994bc37b
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_3_4.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_left_4_1.png b/resources/g2/track/bm/dive_loop_45_left_4_1.png
new file mode 100644
index 0000000000..756ce82f2b
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_4_1.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_left_4_2.png b/resources/g2/track/bm/dive_loop_45_left_4_2.png
new file mode 100644
index 0000000000..3628fce680
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_4_2.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_left_4_3.png b/resources/g2/track/bm/dive_loop_45_left_4_3.png
new file mode 100644
index 0000000000..df09479226
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_4_3.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_left_4_4.png b/resources/g2/track/bm/dive_loop_45_left_4_4.png
new file mode 100644
index 0000000000..578e26e77f
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_4_4.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_right_1_1.png b/resources/g2/track/bm/dive_loop_45_right_1_1.png
new file mode 100644
index 0000000000..bcf98c201a
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_1_1.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_right_1_2.png b/resources/g2/track/bm/dive_loop_45_right_1_2.png
new file mode 100644
index 0000000000..8403b18d43
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_1_2.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_right_1_3.png b/resources/g2/track/bm/dive_loop_45_right_1_3.png
new file mode 100644
index 0000000000..7679e76035
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_1_3.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_right_1_4.png b/resources/g2/track/bm/dive_loop_45_right_1_4.png
new file mode 100644
index 0000000000..633cfd3c55
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_1_4.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_right_2_1.png b/resources/g2/track/bm/dive_loop_45_right_2_1.png
new file mode 100644
index 0000000000..ac3cbf9c06
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_2_1.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_right_2_2.png b/resources/g2/track/bm/dive_loop_45_right_2_2.png
new file mode 100644
index 0000000000..a12088fe86
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_2_2.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_right_2_3.png b/resources/g2/track/bm/dive_loop_45_right_2_3.png
new file mode 100644
index 0000000000..a3b7c671d0
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_2_3.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_right_2_4.png b/resources/g2/track/bm/dive_loop_45_right_2_4.png
new file mode 100644
index 0000000000..18c42fd1a7
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_2_4.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_right_3_1.png b/resources/g2/track/bm/dive_loop_45_right_3_1.png
new file mode 100644
index 0000000000..053095da0e
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_3_1.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_right_3_2.png b/resources/g2/track/bm/dive_loop_45_right_3_2.png
new file mode 100644
index 0000000000..a2dbc61cf7
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_3_2.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_right_3_3.png b/resources/g2/track/bm/dive_loop_45_right_3_3.png
new file mode 100644
index 0000000000..d1d342be73
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_3_3.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_right_3_4.png b/resources/g2/track/bm/dive_loop_45_right_3_4.png
new file mode 100644
index 0000000000..122ab9dffa
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_3_4.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_right_4_1.png b/resources/g2/track/bm/dive_loop_45_right_4_1.png
new file mode 100644
index 0000000000..a7d9e9be5b
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_4_1.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_right_4_2.png b/resources/g2/track/bm/dive_loop_45_right_4_2.png
new file mode 100644
index 0000000000..ad3a0436ff
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_4_2.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_right_4_3.png b/resources/g2/track/bm/dive_loop_45_right_4_3.png
new file mode 100644
index 0000000000..c35ad2b7f4
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_4_3.png differ
diff --git a/resources/g2/track/bm/dive_loop_45_right_4_4.png b/resources/g2/track/bm/dive_loop_45_right_4_4.png
new file mode 100644
index 0000000000..786fbcdbc5
Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_4_4.png differ
diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_1_1.png b/resources/g2/track/bm/flat_to_steep_up_diag_1_1.png
new file mode 100644
index 0000000000..07a4ac05ed
Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_1_1.png differ
diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_1_2.png b/resources/g2/track/bm/flat_to_steep_up_diag_1_2.png
new file mode 100644
index 0000000000..d7f3b0de9c
Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_1_2.png differ
diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_1_3.png b/resources/g2/track/bm/flat_to_steep_up_diag_1_3.png
new file mode 100644
index 0000000000..c0ad64d04b
Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_1_3.png differ
diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_2_1.png b/resources/g2/track/bm/flat_to_steep_up_diag_2_1.png
new file mode 100644
index 0000000000..43ad8945e6
Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_2_1.png differ
diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_2_2.png b/resources/g2/track/bm/flat_to_steep_up_diag_2_2.png
new file mode 100644
index 0000000000..251476d353
Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_2_2.png differ
diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_2_3.png b/resources/g2/track/bm/flat_to_steep_up_diag_2_3.png
new file mode 100644
index 0000000000..0c089d227d
Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_2_3.png differ
diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_3_1.png b/resources/g2/track/bm/flat_to_steep_up_diag_3_1.png
new file mode 100644
index 0000000000..c4aa940153
Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_3_1.png differ
diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_3_2.png b/resources/g2/track/bm/flat_to_steep_up_diag_3_2.png
new file mode 100644
index 0000000000..b46e224440
Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_3_2.png differ
diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_3_3.png b/resources/g2/track/bm/flat_to_steep_up_diag_3_3.png
new file mode 100644
index 0000000000..425f7ea904
Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_3_3.png differ
diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_4_1.png b/resources/g2/track/bm/flat_to_steep_up_diag_4_1.png
new file mode 100644
index 0000000000..40f1070761
Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_4_1.png differ
diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_4_2.png b/resources/g2/track/bm/flat_to_steep_up_diag_4_2.png
new file mode 100644
index 0000000000..7b9b96bf82
Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_4_2.png differ
diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_4_3.png b/resources/g2/track/bm/flat_to_steep_up_diag_4_3.png
new file mode 100644
index 0000000000..afbe70371c
Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_4_3.png differ
diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_1_1.png b/resources/g2/track/bm/steep_to_flat_up_diag_1_1.png
new file mode 100644
index 0000000000..59f9c84cc9
Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_1_1.png differ
diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_1_2.png b/resources/g2/track/bm/steep_to_flat_up_diag_1_2.png
new file mode 100644
index 0000000000..de21ddfb91
Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_1_2.png differ
diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_1_3.png b/resources/g2/track/bm/steep_to_flat_up_diag_1_3.png
new file mode 100644
index 0000000000..093080da19
Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_1_3.png differ
diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_2_1.png b/resources/g2/track/bm/steep_to_flat_up_diag_2_1.png
new file mode 100644
index 0000000000..251476d353
Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_2_1.png differ
diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_2_2.png b/resources/g2/track/bm/steep_to_flat_up_diag_2_2.png
new file mode 100644
index 0000000000..251476d353
Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_2_2.png differ
diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_2_3.png b/resources/g2/track/bm/steep_to_flat_up_diag_2_3.png
new file mode 100644
index 0000000000..3cf5dfbf46
Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_2_3.png differ
diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_3_1.png b/resources/g2/track/bm/steep_to_flat_up_diag_3_1.png
new file mode 100644
index 0000000000..c5812256ce
Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_3_1.png differ
diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_3_2.png b/resources/g2/track/bm/steep_to_flat_up_diag_3_2.png
new file mode 100644
index 0000000000..1f53d098cc
Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_3_2.png differ
diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_3_3.png b/resources/g2/track/bm/steep_to_flat_up_diag_3_3.png
new file mode 100644
index 0000000000..0c3ab55bb3
Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_3_3.png differ
diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_4_1.png b/resources/g2/track/bm/steep_to_flat_up_diag_4_1.png
new file mode 100644
index 0000000000..a24caad65b
Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_4_1.png differ
diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_4_2.png b/resources/g2/track/bm/steep_to_flat_up_diag_4_2.png
new file mode 100644
index 0000000000..19a700bfdf
Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_4_2.png differ
diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_4_3.png b/resources/g2/track/bm/steep_to_flat_up_diag_4_3.png
new file mode 100644
index 0000000000..4136a1e253
Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_4_3.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_1_1.png b/resources/g2/track/corkscrew/dive_loop_45_left_1_1.png
new file mode 100644
index 0000000000..8cb5ff2ef5
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_1_1.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_1_2.png b/resources/g2/track/corkscrew/dive_loop_45_left_1_2.png
new file mode 100644
index 0000000000..0e2391b7a9
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_1_2.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_1_3.png b/resources/g2/track/corkscrew/dive_loop_45_left_1_3.png
new file mode 100644
index 0000000000..af3bf6b616
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_1_3.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_1_4.png b/resources/g2/track/corkscrew/dive_loop_45_left_1_4.png
new file mode 100644
index 0000000000..45ffb1e032
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_1_4.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_2_1.png b/resources/g2/track/corkscrew/dive_loop_45_left_2_1.png
new file mode 100644
index 0000000000..6625048328
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_2_1.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_2_2.png b/resources/g2/track/corkscrew/dive_loop_45_left_2_2.png
new file mode 100644
index 0000000000..5dcb878c5e
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_2_2.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_2_3.png b/resources/g2/track/corkscrew/dive_loop_45_left_2_3.png
new file mode 100644
index 0000000000..aba3d35f88
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_2_3.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_2_4.png b/resources/g2/track/corkscrew/dive_loop_45_left_2_4.png
new file mode 100644
index 0000000000..ccfa253960
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_2_4.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_3_1.png b/resources/g2/track/corkscrew/dive_loop_45_left_3_1.png
new file mode 100644
index 0000000000..612d1f22df
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_3_1.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_3_2.png b/resources/g2/track/corkscrew/dive_loop_45_left_3_2.png
new file mode 100644
index 0000000000..803a116aa9
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_3_2.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_3_3.png b/resources/g2/track/corkscrew/dive_loop_45_left_3_3.png
new file mode 100644
index 0000000000..c04d7b2576
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_3_3.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_3_4.png b/resources/g2/track/corkscrew/dive_loop_45_left_3_4.png
new file mode 100644
index 0000000000..f1c32079a2
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_3_4.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_4_1.png b/resources/g2/track/corkscrew/dive_loop_45_left_4_1.png
new file mode 100644
index 0000000000..1a3dc4d0d7
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_4_1.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_4_2.png b/resources/g2/track/corkscrew/dive_loop_45_left_4_2.png
new file mode 100644
index 0000000000..250848444f
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_4_2.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_4_3.png b/resources/g2/track/corkscrew/dive_loop_45_left_4_3.png
new file mode 100644
index 0000000000..aa78cfc363
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_4_3.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_4_4.png b/resources/g2/track/corkscrew/dive_loop_45_left_4_4.png
new file mode 100644
index 0000000000..7d26dd6729
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_4_4.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_1_1.png b/resources/g2/track/corkscrew/dive_loop_45_right_1_1.png
new file mode 100644
index 0000000000..445b0bb646
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_1_1.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_1_2.png b/resources/g2/track/corkscrew/dive_loop_45_right_1_2.png
new file mode 100644
index 0000000000..815a430ded
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_1_2.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_1_3.png b/resources/g2/track/corkscrew/dive_loop_45_right_1_3.png
new file mode 100644
index 0000000000..2622af83ff
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_1_3.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_1_4.png b/resources/g2/track/corkscrew/dive_loop_45_right_1_4.png
new file mode 100644
index 0000000000..1bfff83e6c
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_1_4.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_2_1.png b/resources/g2/track/corkscrew/dive_loop_45_right_2_1.png
new file mode 100644
index 0000000000..e315319b6a
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_2_1.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_2_2.png b/resources/g2/track/corkscrew/dive_loop_45_right_2_2.png
new file mode 100644
index 0000000000..d7d8c5cd83
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_2_2.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_2_3.png b/resources/g2/track/corkscrew/dive_loop_45_right_2_3.png
new file mode 100644
index 0000000000..71ea002df3
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_2_3.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_2_4.png b/resources/g2/track/corkscrew/dive_loop_45_right_2_4.png
new file mode 100644
index 0000000000..85981cc046
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_2_4.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_3_1.png b/resources/g2/track/corkscrew/dive_loop_45_right_3_1.png
new file mode 100644
index 0000000000..5215a11f80
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_3_1.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_3_2.png b/resources/g2/track/corkscrew/dive_loop_45_right_3_2.png
new file mode 100644
index 0000000000..97aa99080f
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_3_2.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_3_3.png b/resources/g2/track/corkscrew/dive_loop_45_right_3_3.png
new file mode 100644
index 0000000000..e31fec77d1
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_3_3.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_3_4.png b/resources/g2/track/corkscrew/dive_loop_45_right_3_4.png
new file mode 100644
index 0000000000..f492fbd7f8
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_3_4.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_4_1.png b/resources/g2/track/corkscrew/dive_loop_45_right_4_1.png
new file mode 100644
index 0000000000..5c98c16bee
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_4_1.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_4_2.png b/resources/g2/track/corkscrew/dive_loop_45_right_4_2.png
new file mode 100644
index 0000000000..0c58e41a72
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_4_2.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_4_3.png b/resources/g2/track/corkscrew/dive_loop_45_right_4_3.png
new file mode 100644
index 0000000000..553f56cadd
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_4_3.png differ
diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_4_4.png b/resources/g2/track/corkscrew/dive_loop_45_right_4_4.png
new file mode 100644
index 0000000000..43d6268eaa
Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_4_4.png differ
diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_1_1.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_1_1.png
new file mode 100644
index 0000000000..561925a0d3
Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_1_1.png differ
diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_1_2.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_1_2.png
new file mode 100644
index 0000000000..176eb715e6
Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_1_2.png differ
diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_1_3.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_1_3.png
new file mode 100644
index 0000000000..541356ccd9
Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_1_3.png differ
diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_2_1.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_2_1.png
new file mode 100644
index 0000000000..b6b6198aa5
Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_2_1.png differ
diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_2_2.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_2_2.png
new file mode 100644
index 0000000000..251476d353
Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_2_2.png differ
diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_2_3.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_2_3.png
new file mode 100644
index 0000000000..bc433a3f14
Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_2_3.png differ
diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_3_1.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_3_1.png
new file mode 100644
index 0000000000..6b6b25fdb2
Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_3_1.png differ
diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_3_2.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_3_2.png
new file mode 100644
index 0000000000..ee37da31e1
Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_3_2.png differ
diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_3_3.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_3_3.png
new file mode 100644
index 0000000000..4deb0d906b
Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_3_3.png differ
diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_4_1.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_4_1.png
new file mode 100644
index 0000000000..a41f1609f9
Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_4_1.png differ
diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_4_2.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_4_2.png
new file mode 100644
index 0000000000..2faff9e99e
Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_4_2.png differ
diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_4_3.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_4_3.png
new file mode 100644
index 0000000000..1cbc517eb4
Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_4_3.png differ
diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_1_1.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_1_1.png
new file mode 100644
index 0000000000..1623eae794
Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_1_1.png differ
diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_1_2.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_1_2.png
new file mode 100644
index 0000000000..988fe0305a
Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_1_2.png differ
diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_1_3.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_1_3.png
new file mode 100644
index 0000000000..fa3c5cf89c
Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_1_3.png differ
diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_2_1.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_2_1.png
new file mode 100644
index 0000000000..251476d353
Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_2_1.png differ
diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_2_2.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_2_2.png
new file mode 100644
index 0000000000..251476d353
Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_2_2.png differ
diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_2_3.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_2_3.png
new file mode 100644
index 0000000000..a067ad3ab1
Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_2_3.png differ
diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_3_1.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_3_1.png
new file mode 100644
index 0000000000..7fc02542b0
Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_3_1.png differ
diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_3_2.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_3_2.png
new file mode 100644
index 0000000000..c14b9af2cf
Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_3_2.png differ
diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_3_3.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_3_3.png
new file mode 100644
index 0000000000..ee64cfc951
Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_3_3.png differ
diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_4_1.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_4_1.png
new file mode 100644
index 0000000000..470d05a186
Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_4_1.png differ
diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_4_2.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_4_2.png
new file mode 100644
index 0000000000..7799b7031e
Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_4_2.png differ
diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_4_3.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_4_3.png
new file mode 100644
index 0000000000..f477d80e44
Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_4_3.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_1_1.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_1_1.png
new file mode 100644
index 0000000000..8f478d8ef6
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_1_1.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_1_2.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_1_2.png
new file mode 100644
index 0000000000..aa24fdf9b5
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_1_2.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_1_3.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_1_3.png
new file mode 100644
index 0000000000..1c684f2260
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_1_3.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_1_4.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_1_4.png
new file mode 100644
index 0000000000..f8a81dd2e5
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_1_4.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_2_1.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_2_1.png
new file mode 100644
index 0000000000..97f8ef0234
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_2_1.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_2_2.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_2_2.png
new file mode 100644
index 0000000000..42264ab4a3
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_2_2.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_2_3.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_2_3.png
new file mode 100644
index 0000000000..df3f24391a
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_2_3.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_2_4.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_2_4.png
new file mode 100644
index 0000000000..b035c0167a
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_2_4.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_3_1.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_3_1.png
new file mode 100644
index 0000000000..e4f8f78fe7
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_3_1.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_3_2.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_3_2.png
new file mode 100644
index 0000000000..a8eef697af
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_3_2.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_3_3.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_3_3.png
new file mode 100644
index 0000000000..c03c8c6dc6
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_3_3.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_3_4.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_3_4.png
new file mode 100644
index 0000000000..2977332e8c
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_3_4.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_4_1.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_4_1.png
new file mode 100644
index 0000000000..a1d06ce79d
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_4_1.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_4_2.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_4_2.png
new file mode 100644
index 0000000000..d464f23ca1
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_4_2.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_4_3.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_4_3.png
new file mode 100644
index 0000000000..8ae8b59d8e
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_4_3.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_4_4.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_4_4.png
new file mode 100644
index 0000000000..75f652c5f1
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_4_4.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_1_1.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_1_1.png
new file mode 100644
index 0000000000..4ca2ebb0d7
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_1_1.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_1_2.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_1_2.png
new file mode 100644
index 0000000000..72c3c7da5c
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_1_2.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_1_3.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_1_3.png
new file mode 100644
index 0000000000..60de80df48
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_1_3.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_1_4.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_1_4.png
new file mode 100644
index 0000000000..a2e1a7cbe6
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_1_4.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_2_1.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_2_1.png
new file mode 100644
index 0000000000..4a0e3770aa
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_2_1.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_2_2.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_2_2.png
new file mode 100644
index 0000000000..4e00758aeb
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_2_2.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_2_3.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_2_3.png
new file mode 100644
index 0000000000..ede5b32f5e
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_2_3.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_2_4.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_2_4.png
new file mode 100644
index 0000000000..ad075d87fc
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_2_4.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_3_1.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_3_1.png
new file mode 100644
index 0000000000..885e484993
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_3_1.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_3_2.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_3_2.png
new file mode 100644
index 0000000000..8bb2351a92
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_3_2.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_3_3.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_3_3.png
new file mode 100644
index 0000000000..9554ebd3da
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_3_3.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_3_4.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_3_4.png
new file mode 100644
index 0000000000..fe27833ff3
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_3_4.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_4_1.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_4_1.png
new file mode 100644
index 0000000000..f12d14010f
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_4_1.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_4_2.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_4_2.png
new file mode 100644
index 0000000000..d7e1a292de
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_4_2.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_4_3.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_4_3.png
new file mode 100644
index 0000000000..d2359800f7
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_4_3.png differ
diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_4_4.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_4_4.png
new file mode 100644
index 0000000000..f36c597135
Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_4_4.png differ
diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1.png
new file mode 100644
index 0000000000..2baabe084f
Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1.png differ
diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1_1.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1_1.png
new file mode 100644
index 0000000000..d669dd9f97
Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1_1.png differ
diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1_2.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1_2.png
new file mode 100644
index 0000000000..1b3643c62d
Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1_2.png differ
diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1_3.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1_3.png
new file mode 100644
index 0000000000..3f5b5456fe
Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1_3.png differ
diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2.png
new file mode 100644
index 0000000000..0ba5517dfc
Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2.png differ
diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2_1.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2_1.png
new file mode 100644
index 0000000000..463e2bfc6d
Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2_1.png differ
diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2_2.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2_2.png
new file mode 100644
index 0000000000..251476d353
Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2_2.png differ
diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2_3.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2_3.png
new file mode 100644
index 0000000000..e9e5ab4309
Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2_3.png differ
diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3.png
new file mode 100644
index 0000000000..4010677473
Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3.png differ
diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3_1.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3_1.png
new file mode 100644
index 0000000000..0ba55b01cb
Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3_1.png differ
diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3_2.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3_2.png
new file mode 100644
index 0000000000..614d2f09e8
Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3_2.png differ
diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3_3.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3_3.png
new file mode 100644
index 0000000000..5b93eac8cb
Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3_3.png differ
diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4.png
new file mode 100644
index 0000000000..c2e8c0ec08
Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4.png differ
diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4_1.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4_1.png
new file mode 100644
index 0000000000..38cdae0ad1
Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4_1.png differ
diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4_2.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4_2.png
new file mode 100644
index 0000000000..3e7a847eef
Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4_2.png differ
diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4_3.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4_3.png
new file mode 100644
index 0000000000..3fbe6d2fdc
Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4_3.png differ
diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1.png
new file mode 100644
index 0000000000..9d9a5293b3
Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1.png differ
diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1_1.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1_1.png
new file mode 100644
index 0000000000..d8b6a5e1ed
Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1_1.png differ
diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1_2.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1_2.png
new file mode 100644
index 0000000000..794989b338
Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1_2.png differ
diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1_3.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1_3.png
new file mode 100644
index 0000000000..008b824b96
Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1_3.png differ
diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2.png
new file mode 100644
index 0000000000..89adb42c83
Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2.png differ
diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2_1.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2_1.png
new file mode 100644
index 0000000000..251476d353
Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2_1.png differ
diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2_2.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2_2.png
new file mode 100644
index 0000000000..251476d353
Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2_2.png differ
diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2_3.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2_3.png
new file mode 100644
index 0000000000..65e0af16ce
Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2_3.png differ
diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3.png
new file mode 100644
index 0000000000..902291d2d1
Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3.png differ
diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3_1.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3_1.png
new file mode 100644
index 0000000000..5ee268aa98
Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3_1.png differ
diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3_2.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3_2.png
new file mode 100644
index 0000000000..74fe35a864
Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3_2.png differ
diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3_3.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3_3.png
new file mode 100644
index 0000000000..aa5ab044ca
Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3_3.png differ
diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4.png
new file mode 100644
index 0000000000..25ef9abfc1
Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4.png differ
diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4_1.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4_1.png
new file mode 100644
index 0000000000..0565b4a0f8
Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4_1.png differ
diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4_2.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4_2.png
new file mode 100644
index 0000000000..03774bfe05
Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4_2.png differ
diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4_3.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4_3.png
new file mode 100644
index 0000000000..f86d6d448e
Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4_3.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_left_1_1.png b/resources/g2/track/raptor/dive_loop_45_left_1_1.png
new file mode 100644
index 0000000000..5d2f718d29
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_1_1.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_left_1_2.png b/resources/g2/track/raptor/dive_loop_45_left_1_2.png
new file mode 100644
index 0000000000..484709162c
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_1_2.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_left_1_3.png b/resources/g2/track/raptor/dive_loop_45_left_1_3.png
new file mode 100644
index 0000000000..9bb92939ff
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_1_3.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_left_1_4.png b/resources/g2/track/raptor/dive_loop_45_left_1_4.png
new file mode 100644
index 0000000000..0e11cee76e
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_1_4.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_left_2_1.png b/resources/g2/track/raptor/dive_loop_45_left_2_1.png
new file mode 100644
index 0000000000..4a0e419411
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_2_1.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_left_2_2.png b/resources/g2/track/raptor/dive_loop_45_left_2_2.png
new file mode 100644
index 0000000000..02e1c54b82
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_2_2.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_left_2_3.png b/resources/g2/track/raptor/dive_loop_45_left_2_3.png
new file mode 100644
index 0000000000..6519f9d6a9
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_2_3.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_left_2_4.png b/resources/g2/track/raptor/dive_loop_45_left_2_4.png
new file mode 100644
index 0000000000..3db7ea3e7c
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_2_4.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_left_3_1.png b/resources/g2/track/raptor/dive_loop_45_left_3_1.png
new file mode 100644
index 0000000000..7e7cfdc974
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_3_1.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_left_3_2.png b/resources/g2/track/raptor/dive_loop_45_left_3_2.png
new file mode 100644
index 0000000000..4d8b636b46
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_3_2.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_left_3_3.png b/resources/g2/track/raptor/dive_loop_45_left_3_3.png
new file mode 100644
index 0000000000..1f6f884952
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_3_3.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_left_3_4.png b/resources/g2/track/raptor/dive_loop_45_left_3_4.png
new file mode 100644
index 0000000000..5de1d63638
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_3_4.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_left_4_1.png b/resources/g2/track/raptor/dive_loop_45_left_4_1.png
new file mode 100644
index 0000000000..abc870d056
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_4_1.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_left_4_2.png b/resources/g2/track/raptor/dive_loop_45_left_4_2.png
new file mode 100644
index 0000000000..cbd0950af1
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_4_2.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_left_4_3.png b/resources/g2/track/raptor/dive_loop_45_left_4_3.png
new file mode 100644
index 0000000000..06dc35064f
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_4_3.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_left_4_4.png b/resources/g2/track/raptor/dive_loop_45_left_4_4.png
new file mode 100644
index 0000000000..3054197c87
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_4_4.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_right_1_1.png b/resources/g2/track/raptor/dive_loop_45_right_1_1.png
new file mode 100644
index 0000000000..6b5fa23877
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_1_1.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_right_1_2.png b/resources/g2/track/raptor/dive_loop_45_right_1_2.png
new file mode 100644
index 0000000000..6ebae3dff6
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_1_2.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_right_1_3.png b/resources/g2/track/raptor/dive_loop_45_right_1_3.png
new file mode 100644
index 0000000000..138b7647bc
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_1_3.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_right_1_4.png b/resources/g2/track/raptor/dive_loop_45_right_1_4.png
new file mode 100644
index 0000000000..5cdf7ef0be
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_1_4.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_right_2_1.png b/resources/g2/track/raptor/dive_loop_45_right_2_1.png
new file mode 100644
index 0000000000..cb3af11960
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_2_1.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_right_2_2.png b/resources/g2/track/raptor/dive_loop_45_right_2_2.png
new file mode 100644
index 0000000000..c46bbdea77
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_2_2.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_right_2_3.png b/resources/g2/track/raptor/dive_loop_45_right_2_3.png
new file mode 100644
index 0000000000..09dccfb770
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_2_3.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_right_2_4.png b/resources/g2/track/raptor/dive_loop_45_right_2_4.png
new file mode 100644
index 0000000000..d9eeeb4957
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_2_4.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_right_3_1.png b/resources/g2/track/raptor/dive_loop_45_right_3_1.png
new file mode 100644
index 0000000000..6821ff11d0
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_3_1.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_right_3_2.png b/resources/g2/track/raptor/dive_loop_45_right_3_2.png
new file mode 100644
index 0000000000..4c5493434b
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_3_2.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_right_3_3.png b/resources/g2/track/raptor/dive_loop_45_right_3_3.png
new file mode 100644
index 0000000000..13a4d7fd7e
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_3_3.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_right_3_4.png b/resources/g2/track/raptor/dive_loop_45_right_3_4.png
new file mode 100644
index 0000000000..5fa7251e3a
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_3_4.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_right_4_1.png b/resources/g2/track/raptor/dive_loop_45_right_4_1.png
new file mode 100644
index 0000000000..cea656296e
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_4_1.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_right_4_2.png b/resources/g2/track/raptor/dive_loop_45_right_4_2.png
new file mode 100644
index 0000000000..8898578c76
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_4_2.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_right_4_3.png b/resources/g2/track/raptor/dive_loop_45_right_4_3.png
new file mode 100644
index 0000000000..8a834884b8
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_4_3.png differ
diff --git a/resources/g2/track/raptor/dive_loop_45_right_4_4.png b/resources/g2/track/raptor/dive_loop_45_right_4_4.png
new file mode 100644
index 0000000000..75608f1f57
Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_4_4.png differ
diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_1_1.png b/resources/g2/track/raptor/flat_to_steep_up_diag_1_1.png
new file mode 100644
index 0000000000..ff14b77d7a
Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_1_1.png differ
diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_1_2.png b/resources/g2/track/raptor/flat_to_steep_up_diag_1_2.png
new file mode 100644
index 0000000000..f7e40fe3f9
Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_1_2.png differ
diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_1_3.png b/resources/g2/track/raptor/flat_to_steep_up_diag_1_3.png
new file mode 100644
index 0000000000..3c78b4c5ba
Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_1_3.png differ
diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_2_1.png b/resources/g2/track/raptor/flat_to_steep_up_diag_2_1.png
new file mode 100644
index 0000000000..3da2ad8e69
Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_2_1.png differ
diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_2_2.png b/resources/g2/track/raptor/flat_to_steep_up_diag_2_2.png
new file mode 100644
index 0000000000..251476d353
Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_2_2.png differ
diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_2_3.png b/resources/g2/track/raptor/flat_to_steep_up_diag_2_3.png
new file mode 100644
index 0000000000..3f240a661b
Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_2_3.png differ
diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_3_1.png b/resources/g2/track/raptor/flat_to_steep_up_diag_3_1.png
new file mode 100644
index 0000000000..8a1cb8df81
Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_3_1.png differ
diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_3_2.png b/resources/g2/track/raptor/flat_to_steep_up_diag_3_2.png
new file mode 100644
index 0000000000..a53813c501
Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_3_2.png differ
diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_3_3.png b/resources/g2/track/raptor/flat_to_steep_up_diag_3_3.png
new file mode 100644
index 0000000000..76d7fcb7a2
Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_3_3.png differ
diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_4_1.png b/resources/g2/track/raptor/flat_to_steep_up_diag_4_1.png
new file mode 100644
index 0000000000..1ee8c16476
Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_4_1.png differ
diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_4_2.png b/resources/g2/track/raptor/flat_to_steep_up_diag_4_2.png
new file mode 100644
index 0000000000..89da8414eb
Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_4_2.png differ
diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_4_3.png b/resources/g2/track/raptor/flat_to_steep_up_diag_4_3.png
new file mode 100644
index 0000000000..cafb747651
Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_4_3.png differ
diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_1_1.png b/resources/g2/track/raptor/steep_to_flat_up_diag_1_1.png
new file mode 100644
index 0000000000..4f3d08defc
Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_1_1.png differ
diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_1_2.png b/resources/g2/track/raptor/steep_to_flat_up_diag_1_2.png
new file mode 100644
index 0000000000..5a26edb65a
Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_1_2.png differ
diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_1_3.png b/resources/g2/track/raptor/steep_to_flat_up_diag_1_3.png
new file mode 100644
index 0000000000..b888b93b16
Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_1_3.png differ
diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_2_1.png b/resources/g2/track/raptor/steep_to_flat_up_diag_2_1.png
new file mode 100644
index 0000000000..251476d353
Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_2_1.png differ
diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_2_2.png b/resources/g2/track/raptor/steep_to_flat_up_diag_2_2.png
new file mode 100644
index 0000000000..251476d353
Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_2_2.png differ
diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_2_3.png b/resources/g2/track/raptor/steep_to_flat_up_diag_2_3.png
new file mode 100644
index 0000000000..66f30a8b96
Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_2_3.png differ
diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_3_1.png b/resources/g2/track/raptor/steep_to_flat_up_diag_3_1.png
new file mode 100644
index 0000000000..374d1edd6b
Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_3_1.png differ
diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_3_2.png b/resources/g2/track/raptor/steep_to_flat_up_diag_3_2.png
new file mode 100644
index 0000000000..07931052a5
Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_3_2.png differ
diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_3_3.png b/resources/g2/track/raptor/steep_to_flat_up_diag_3_3.png
new file mode 100644
index 0000000000..5c67bcb43d
Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_3_3.png differ
diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_4_1.png b/resources/g2/track/raptor/steep_to_flat_up_diag_4_1.png
new file mode 100644
index 0000000000..9885f187c3
Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_4_1.png differ
diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_4_2.png b/resources/g2/track/raptor/steep_to_flat_up_diag_4_2.png
new file mode 100644
index 0000000000..39de02f4ae
Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_4_2.png differ
diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_4_3.png b/resources/g2/track/raptor/steep_to_flat_up_diag_4_3.png
new file mode 100644
index 0000000000..4d57c5bf00
Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_4_3.png differ
diff --git a/src/openrct2-ui/UiStringIds.h b/src/openrct2-ui/UiStringIds.h
index 8e2c15c7db..17b476d976 100644
--- a/src/openrct2-ui/UiStringIds.h
+++ b/src/openrct2-ui/UiStringIds.h
@@ -1103,8 +1103,8 @@ namespace OpenRCT2
STR_DRAWING_ENGINE_TIP = 5876,
STR_EARLY_COMPLETION_TIP = 6227,
STR_EDIT_ASSET_PACKS_BUTTON = 6640,
- STR_EXPORT_EMSCRIPTEN = 6727,
- STR_IMPORT_EMSCRIPTEN = 6728,
+ STR_EXPORT_EMSCRIPTEN = 6730,
+ STR_IMPORT_EMSCRIPTEN = 6731,
STR_EDIT_THEMES_BUTTON = 5153,
STR_EDIT_THEMES_BUTTON_TIP = 5837,
STR_EFFECTS_GROUP = 6256,
diff --git a/src/openrct2-ui/WindowManager.cpp b/src/openrct2-ui/WindowManager.cpp
index 7db0f6aede..ae8f33e839 100644
--- a/src/openrct2-ui/WindowManager.cpp
+++ b/src/openrct2-ui/WindowManager.cpp
@@ -420,7 +420,7 @@ public:
{
auto rideIndex = intent.GetUIntExtra(INTENT_EXTRA_RIDE_ID);
auto w = FindByClass(WindowClass::RideConstruction);
- if (w == nullptr || w->number != rideIndex)
+ if (w == nullptr || w->number != static_cast(rideIndex))
{
WindowCloseConstructionWindows();
_currentRideIndex = RideId::FromUnderlying(rideIndex);
@@ -713,7 +713,7 @@ public:
if (w->flags & WF_NO_BACKGROUND)
{
auto widgetIndex = FindWidgetFromPoint(*w.get(), screenCoords);
- if (widgetIndex == -1)
+ if (widgetIndex == kWidgetIndexNull)
continue;
}
@@ -736,14 +736,10 @@ public:
w.OnPrepareDraw();
// Find the widget at point x, y
- WidgetIndex widget_index = -1;
- for (int32_t i = 0;; i++)
+ WidgetIndex widget_index = kWidgetIndexNull;
+ for (auto i = 0u; i < w.widgets.size(); i++)
{
const auto& widget = w.widgets[i];
- if (widget.type == WindowWidgetType::Last)
- {
- break;
- }
if (widget.type != WindowWidgetType::Empty && widget.IsVisible())
{
@@ -756,7 +752,7 @@ public:
}
// Return next widget if a dropdown
- if (widget_index != -1)
+ if (widget_index != kWidgetIndexNull)
{
const auto& widget = w.widgets[widget_index];
if (widget.type == WindowWidgetType::DropdownMenu)
diff --git a/src/openrct2-ui/input/MouseInput.cpp b/src/openrct2-ui/input/MouseInput.cpp
index c7c06bd2e1..f824c01d6a 100644
--- a/src/openrct2-ui/input/MouseInput.cpp
+++ b/src/openrct2-ui/input/MouseInput.cpp
@@ -41,1705 +41,1709 @@
#include
#include
-using namespace OpenRCT2;
-using namespace OpenRCT2::Ui;
-using namespace OpenRCT2::Ui::Windows;
-
-struct RCTMouseData
+namespace OpenRCT2
{
- uint32_t x;
- uint32_t y;
- MouseState state;
-};
+ using namespace OpenRCT2::Ui;
+ using namespace OpenRCT2::Ui::Windows;
-static RCTMouseData _mouseInputQueue[64];
-static uint8_t _mouseInputQueueReadIndex = 0;
-static uint8_t _mouseInputQueueWriteIndex = 0;
+ struct RCTMouseData
+ {
+ uint32_t x;
+ uint32_t y;
+ MouseState state;
+ };
-static std::optional _ticksSinceDragStart;
-static WidgetRef _dragWidget;
-static uint8_t _dragScrollIndex;
-static int32_t _originalWindowWidth;
-static int32_t _originalWindowHeight;
+ static RCTMouseData _mouseInputQueue[64];
+ static uint8_t _mouseInputQueueReadIndex = 0;
+ static uint8_t _mouseInputQueueWriteIndex = 0;
-static uint8_t _currentScrollIndex;
-static uint8_t _currentScrollArea;
+ static std::optional _ticksSinceDragStart;
+ static WidgetRef _dragWidget;
+ static uint8_t _dragScrollIndex;
+ static int32_t _originalWindowWidth;
+ static int32_t _originalWindowHeight;
-ScreenCoordsXY gInputDragLast;
+ static uint8_t _currentScrollIndex;
+ static uint8_t _currentScrollArea;
-uint32_t gTooltipCloseTimeout;
-WidgetRef gTooltipWidget;
-ScreenCoordsXY gTooltipCursor;
+ ScreenCoordsXY gInputDragLast;
-static std::optional _clickRepeatTicks;
+ uint32_t gTooltipCloseTimeout;
+ WidgetRef gTooltipWidget;
+ ScreenCoordsXY gTooltipCursor;
-static MouseState GameGetNextInput(ScreenCoordsXY& screenCoords);
-static void InputWidgetOver(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex);
-static void InputWidgetOverChangeCheck(WindowClass windowClass, rct_windownumber windowNumber, WidgetIndex widgetIndex);
-static void InputWidgetOverFlatbuttonInvalidate();
-void ProcessMouseOver(const ScreenCoordsXY& screenCoords);
-void ProcessMouseTool(const ScreenCoordsXY& screenCoords);
-void InvalidateScroll();
-static RCTMouseData* GetMouseInput();
-void TileElementRightClick(int32_t type, TileElement* tileElement, const ScreenCoordsXY& screenCoords);
-static void GameHandleInputMouse(const ScreenCoordsXY& screenCoords, MouseState state);
-static void InputWidgetLeft(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex);
-void InputStateWidgetPressed(
- const ScreenCoordsXY& screenCoords, MouseState state, WidgetIndex widgetIndex, WindowBase* w, Widget* widget);
-void SetCursor(CursorID cursor_id);
-static void InputWindowPositionContinue(
- WindowBase& w, const ScreenCoordsXY& lastScreenCoords, const ScreenCoordsXY& newScreenCoords);
-static void InputWindowPositionEnd(WindowBase& w, const ScreenCoordsXY& screenCoords);
-static void InputWindowResizeBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords);
-static void InputWindowResizeContinue(WindowBase& w, const ScreenCoordsXY& screenCoords);
-static void InputWindowResizeEnd();
-static void InputViewportDragBegin(WindowBase& w);
-static void InputViewportDragContinue();
-static void InputViewportDragEnd();
-static void InputScrollBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords);
-static void InputScrollContinue(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords);
-static void InputScrollEnd();
-static void InputScrollPartUpdateHThumb(WindowBase& w, WidgetIndex widgetIndex, int32_t x, int32_t scroll_id);
-static void InputScrollPartUpdateHLeft(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id);
-static void InputScrollPartUpdateHRight(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id);
-static void InputScrollPartUpdateVThumb(WindowBase& w, WidgetIndex widgetIndex, int32_t y, int32_t scroll_id);
-static void InputScrollPartUpdateVTop(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id);
-static void InputScrollPartUpdateVBottom(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id);
-static void InputUpdateTooltip(WindowBase* w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords);
+ static std::optional _clickRepeatTicks;
+
+ static MouseState GameGetNextInput(ScreenCoordsXY& screenCoords);
+ static void InputWidgetOver(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex);
+ static void InputWidgetOverChangeCheck(WindowClass windowClass, rct_windownumber windowNumber, WidgetIndex widgetIndex);
+ static void InputWidgetOverFlatbuttonInvalidate();
+ void ProcessMouseOver(const ScreenCoordsXY& screenCoords);
+ void ProcessMouseTool(const ScreenCoordsXY& screenCoords);
+ void InvalidateScroll();
+ static RCTMouseData* GetMouseInput();
+ void TileElementRightClick(int32_t type, TileElement* tileElement, const ScreenCoordsXY& screenCoords);
+ static void GameHandleInputMouse(const ScreenCoordsXY& screenCoords, MouseState state);
+ static void InputWidgetLeft(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex);
+ void InputStateWidgetPressed(
+ const ScreenCoordsXY& screenCoords, MouseState state, WidgetIndex widgetIndex, WindowBase* w, Widget* widget);
+ void SetCursor(CursorID cursor_id);
+ static void InputWindowPositionContinue(
+ WindowBase& w, const ScreenCoordsXY& lastScreenCoords, const ScreenCoordsXY& newScreenCoords);
+ static void InputWindowPositionEnd(WindowBase& w, const ScreenCoordsXY& screenCoords);
+ static void InputWindowResizeBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords);
+ static void InputWindowResizeContinue(WindowBase& w, const ScreenCoordsXY& screenCoords);
+ static void InputWindowResizeEnd();
+ static void InputViewportDragBegin(WindowBase& w);
+ static void InputViewportDragContinue();
+ static void InputViewportDragEnd();
+ static void InputScrollBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords);
+ static void InputScrollContinue(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords);
+ static void InputScrollEnd();
+ static void InputScrollPartUpdateHThumb(WindowBase& w, WidgetIndex widgetIndex, int32_t x, int32_t scroll_id);
+ static void InputScrollPartUpdateHLeft(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id);
+ static void InputScrollPartUpdateHRight(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id);
+ static void InputScrollPartUpdateVThumb(WindowBase& w, WidgetIndex widgetIndex, int32_t y, int32_t scroll_id);
+ static void InputScrollPartUpdateVTop(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id);
+ static void InputScrollPartUpdateVBottom(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id);
+ static void InputUpdateTooltip(WindowBase* w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords);
#pragma region Mouse input
-/**
- *
- * rct2: 0x006EA627
- */
-void GameHandleInput()
-{
- InvalidateAllWindowsAfterInput();
-
- MouseState state;
- ScreenCoordsXY screenCoords;
- while ((state = GameGetNextInput(screenCoords)) != MouseState::Released)
+ /**
+ *
+ * rct2: 0x006EA627
+ */
+ void GameHandleInput()
{
- GameHandleInputMouse(screenCoords, state);
+ InvalidateAllWindowsAfterInput();
+
+ MouseState state;
+ ScreenCoordsXY screenCoords;
+ while ((state = GameGetNextInput(screenCoords)) != MouseState::Released)
+ {
+ GameHandleInputMouse(screenCoords, state);
+ }
+
+ if (_inputFlags & INPUT_FLAG_5)
+ {
+ GameHandleInputMouse(screenCoords, state);
+ }
+ else
+ {
+ int32_t screenWidth = ContextGetWidth();
+ int32_t screenHeight = ContextGetHeight();
+ screenCoords.x = std::clamp(screenCoords.x, 0, screenWidth - 1);
+ screenCoords.y = std::clamp(screenCoords.y, 0, screenHeight - 1);
+
+ GameHandleInputMouse(screenCoords, state);
+ ProcessMouseOver(screenCoords);
+ ProcessMouseTool(screenCoords);
+ }
}
- if (_inputFlags & INPUT_FLAG_5)
+ /**
+ *
+ * rct2: 0x006E83C7
+ */
+ static MouseState GameGetNextInput(ScreenCoordsXY& screenCoords)
{
- GameHandleInputMouse(screenCoords, state);
- }
- else
- {
- int32_t screenWidth = ContextGetWidth();
- int32_t screenHeight = ContextGetHeight();
- screenCoords.x = std::clamp(screenCoords.x, 0, screenWidth - 1);
- screenCoords.y = std::clamp(screenCoords.y, 0, screenHeight - 1);
+ RCTMouseData* input = GetMouseInput();
+ if (input == nullptr)
+ {
+ const CursorState* cursorState = ContextGetCursorState();
+ screenCoords = cursorState->position;
+ return MouseState::Released;
+ }
- GameHandleInputMouse(screenCoords, state);
- ProcessMouseOver(screenCoords);
- ProcessMouseTool(screenCoords);
- }
-}
-
-/**
- *
- * rct2: 0x006E83C7
- */
-static MouseState GameGetNextInput(ScreenCoordsXY& screenCoords)
-{
- RCTMouseData* input = GetMouseInput();
- if (input == nullptr)
- {
- const CursorState* cursorState = ContextGetCursorState();
- screenCoords = cursorState->position;
- return MouseState::Released;
+ screenCoords.x = input->x;
+ screenCoords.y = input->y;
+ return input->state;
}
- screenCoords.x = input->x;
- screenCoords.y = input->y;
- return input->state;
-}
-
-/**
- *
- * rct2: 0x00407074
- */
-static RCTMouseData* GetMouseInput()
-{
- // Check if that location has been written to yet
- if (_mouseInputQueueReadIndex == _mouseInputQueueWriteIndex)
+ /**
+ *
+ * rct2: 0x00407074
+ */
+ static RCTMouseData* GetMouseInput()
{
- return nullptr;
+ // Check if that location has been written to yet
+ if (_mouseInputQueueReadIndex == _mouseInputQueueWriteIndex)
+ {
+ return nullptr;
+ }
+
+ RCTMouseData* result = &_mouseInputQueue[_mouseInputQueueReadIndex];
+ _mouseInputQueueReadIndex = (_mouseInputQueueReadIndex + 1) % std::size(_mouseInputQueue);
+ return result;
}
- RCTMouseData* result = &_mouseInputQueue[_mouseInputQueueReadIndex];
- _mouseInputQueueReadIndex = (_mouseInputQueueReadIndex + 1) % std::size(_mouseInputQueue);
- return result;
-}
-
-/**
- *
- * rct2: 0x006E957F
- */
-static void InputScrollDragBegin(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex)
-{
- _inputState = InputState::ScrollRight;
- gInputDragLast = screenCoords;
- _dragWidget.window_classification = w->classification;
- _dragWidget.window_number = w->number;
- _dragWidget.widget_index = widgetIndex;
- _ticksSinceDragStart = gCurrentRealTimeTicks;
-
- _dragScrollIndex = WindowGetScrollDataIndex(*w, widgetIndex);
- ContextHideCursor();
-}
-
-/**
- * Based on (heavily changed)
- * rct2: 0x006E9E0E, 0x006E9ED0
- */
-static void InputScrollDragContinue(const ScreenCoordsXY& screenCoords, WindowBase* w)
-{
- WidgetIndex widgetIndex = _dragWidget.widget_index;
- uint8_t scrollIndex = _dragScrollIndex;
-
- const auto& widget = w->widgets[widgetIndex];
- auto& scroll = w->scrolls[scrollIndex];
-
- ScreenCoordsXY differentialCoords = screenCoords - gInputDragLast;
- if (differentialCoords.x == 0 && differentialCoords.y == 0)
- return;
-
- if (scroll.flags & HSCROLLBAR_VISIBLE)
+ /**
+ *
+ * rct2: 0x006E957F
+ */
+ static void InputScrollDragBegin(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex)
{
- int16_t size = widget.width() - 1;
- if (scroll.flags & VSCROLLBAR_VISIBLE)
- size -= 11;
- size = std::max(0, scroll.contentWidth - size);
- scroll.contentOffsetX = std::min(std::max(0, scroll.contentOffsetX + differentialCoords.x), size);
+ _inputState = InputState::ScrollRight;
+ gInputDragLast = screenCoords;
+ _dragWidget.window_classification = w->classification;
+ _dragWidget.window_number = w->number;
+ _dragWidget.widget_index = widgetIndex;
+ _ticksSinceDragStart = gCurrentRealTimeTicks;
+
+ _dragScrollIndex = WindowGetScrollDataIndex(*w, widgetIndex);
+ ContextHideCursor();
}
- if (scroll.flags & VSCROLLBAR_VISIBLE)
+ /**
+ * Based on (heavily changed)
+ * rct2: 0x006E9E0E, 0x006E9ED0
+ */
+ static void InputScrollDragContinue(const ScreenCoordsXY& screenCoords, WindowBase* w)
{
- int16_t size = widget.height() - 1;
+ WidgetIndex widgetIndex = _dragWidget.widget_index;
+ uint8_t scrollIndex = _dragScrollIndex;
+
+ const auto& widget = w->widgets[widgetIndex];
+ auto& scroll = w->scrolls[scrollIndex];
+
+ ScreenCoordsXY differentialCoords = screenCoords - gInputDragLast;
+ if (differentialCoords.x == 0 && differentialCoords.y == 0)
+ return;
+
if (scroll.flags & HSCROLLBAR_VISIBLE)
- size -= 11;
- size = std::max(0, scroll.contentHeight - size);
- scroll.contentOffsetY = std::min(std::max(0, scroll.contentOffsetY + differentialCoords.y), size);
+ {
+ int16_t size = widget.width() - 1;
+ if (scroll.flags & VSCROLLBAR_VISIBLE)
+ size -= 11;
+ size = std::max(0, scroll.contentWidth - size);
+ scroll.contentOffsetX = std::min(std::max(0, scroll.contentOffsetX + differentialCoords.x), size);
+ }
+
+ if (scroll.flags & VSCROLLBAR_VISIBLE)
+ {
+ int16_t size = widget.height() - 1;
+ if (scroll.flags & HSCROLLBAR_VISIBLE)
+ size -= 11;
+ size = std::max(0, scroll.contentHeight - size);
+ scroll.contentOffsetY = std::min(std::max(0, scroll.contentOffsetY + differentialCoords.y), size);
+ }
+
+ WidgetScrollUpdateThumbs(*w, widgetIndex);
+ WindowInvalidateByNumber(w->classification, w->number);
+
+ ScreenCoordsXY fixedCursorPosition = {
+ static_cast(std::ceil(gInputDragLast.x * Config::Get().general.WindowScale)),
+ static_cast(std::ceil(gInputDragLast.y * Config::Get().general.WindowScale))
+ };
+
+ ContextSetCursorPosition(fixedCursorPosition);
}
- WidgetScrollUpdateThumbs(*w, widgetIndex);
- WindowInvalidateByNumber(w->classification, w->number);
-
- ScreenCoordsXY fixedCursorPosition = {
- static_cast(std::ceil(gInputDragLast.x * Config::Get().general.WindowScale)),
- static_cast(std::ceil(gInputDragLast.y * Config::Get().general.WindowScale))
- };
-
- ContextSetCursorPosition(fixedCursorPosition);
-}
-
-/**
- *
- * rct2: 0x006E8ACB
- */
-static void InputScrollRight(const ScreenCoordsXY& screenCoords, MouseState state)
-{
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- WindowBase* w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number);
- if (w == nullptr)
+ /**
+ *
+ * rct2: 0x006E8ACB
+ */
+ static void InputScrollRight(const ScreenCoordsXY& screenCoords, MouseState state)
{
- ContextShowCursor();
- _inputState = InputState::Reset;
- return;
- }
-
- switch (state)
- {
- case MouseState::Released:
- if (screenCoords.x != 0 || screenCoords.y != 0)
- {
- _ticksSinceDragStart = std::nullopt;
- InputScrollDragContinue(screenCoords, w);
- }
- break;
- case MouseState::RightRelease:
- _inputState = InputState::Reset;
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ WindowBase* w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number);
+ if (w == nullptr)
+ {
ContextShowCursor();
- break;
- case MouseState::LeftPress:
- case MouseState::LeftRelease:
- case MouseState::RightPress:
- // Function only handles right button, so it's the only one relevant
- break;
- }
-}
+ _inputState = InputState::Reset;
+ return;
+ }
-/**
- *
- * rct2: 0x006E8655
- */
-static void GameHandleInputMouse(const ScreenCoordsXY& screenCoords, MouseState state)
-{
- WindowBase* w;
- Widget* widget;
- WidgetIndex widgetIndex;
-
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
-
- // Get window and widget under cursor position
- w = windowMgr->FindFromPoint(screenCoords);
- widgetIndex = w == nullptr ? -1 : windowMgr->FindWidgetFromPoint(*w, screenCoords);
- widget = widgetIndex == -1 ? nullptr : &w->widgets[widgetIndex];
-
- switch (_inputState)
- {
- case InputState::Reset:
- WindowTooltipReset(screenCoords);
- // fall-through
- case InputState::Normal:
- switch (state)
- {
- case MouseState::Released:
- InputWidgetOver(screenCoords, w, widgetIndex);
- break;
- case MouseState::LeftPress:
- InputWidgetLeft(screenCoords, w, widgetIndex);
- break;
- case MouseState::RightPress:
- WindowCloseByClass(WindowClass::Tooltip);
-
- if (w != nullptr)
- {
- w = WindowBringToFront(*w);
- }
-
- if (widgetIndex != -1)
- {
- switch (widget->type)
- {
- case WindowWidgetType::Viewport:
- if (!(gScreenFlags & (SCREEN_FLAGS_TRACK_MANAGER | SCREEN_FLAGS_TITLE_DEMO)))
- {
- InputViewportDragBegin(*w);
- }
- break;
- case WindowWidgetType::Scroll:
- InputScrollDragBegin(screenCoords, w, widgetIndex);
- break;
- default:
- break;
- }
- }
- break;
- case MouseState::LeftRelease:
- case MouseState::RightRelease:
- // In this switch only button presses are relevant
- break;
- }
- break;
- case InputState::WidgetPressed:
- InputStateWidgetPressed(screenCoords, state, widgetIndex, w, widget);
- break;
- case InputState::PositioningWindow:
- w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number);
- if (w == nullptr)
- {
- _inputState = InputState::Reset;
- }
- else
- {
- InputWindowPositionContinue(*w, gInputDragLast, screenCoords);
- if (state == MouseState::LeftRelease)
+ switch (state)
+ {
+ case MouseState::Released:
+ if (screenCoords.x != 0 || screenCoords.y != 0)
{
- InputWindowPositionEnd(*w, screenCoords);
+ _ticksSinceDragStart = std::nullopt;
+ InputScrollDragContinue(screenCoords, w);
}
- }
- break;
- case InputState::ViewportRight:
- if (state == MouseState::Released)
- {
- InputViewportDragContinue();
- }
- else if (state == MouseState::RightRelease)
- {
- InputViewportDragEnd();
- if (_ticksSinceDragStart.has_value() && gCurrentRealTimeTicks - _ticksSinceDragStart.value() < 500)
- {
- // If the user pressed the right mouse button for less than 500 ticks, interpret as right click
- ViewportInteractionRightClick(screenCoords);
- }
- }
- break;
- case InputState::DropdownActive:
- InputStateWidgetPressed(screenCoords, state, widgetIndex, w, widget);
- break;
- case InputState::ViewportLeft:
- w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number);
- if (w == nullptr)
- {
- _inputState = InputState::Reset;
break;
- }
+ case MouseState::RightRelease:
+ _inputState = InputState::Reset;
+ ContextShowCursor();
+ break;
+ case MouseState::LeftPress:
+ case MouseState::LeftRelease:
+ case MouseState::RightPress:
+ // Function only handles right button, so it's the only one relevant
+ break;
+ }
+ }
- switch (state)
- {
- case MouseState::Released:
- if (w->viewport == nullptr)
- {
- _inputState = InputState::Reset;
+ /**
+ *
+ * rct2: 0x006E8655
+ */
+ static void GameHandleInputMouse(const ScreenCoordsXY& screenCoords, MouseState state)
+ {
+ WindowBase* w;
+ Widget* widget;
+ WidgetIndex widgetIndex;
+
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+
+ // Get window and widget under cursor position
+ w = windowMgr->FindFromPoint(screenCoords);
+ widgetIndex = w == nullptr ? -1 : windowMgr->FindWidgetFromPoint(*w, screenCoords);
+ widget = widgetIndex == kWidgetIndexNull ? nullptr : &w->widgets[widgetIndex];
+
+ switch (_inputState)
+ {
+ case InputState::Reset:
+ WindowTooltipReset(screenCoords);
+ // fall-through
+ case InputState::Normal:
+ switch (state)
+ {
+ case MouseState::Released:
+ InputWidgetOver(screenCoords, w, widgetIndex);
break;
- }
-
- if (!InputTestFlag(INPUT_FLAG_4))
+ case MouseState::LeftPress:
+ InputWidgetLeft(screenCoords, w, widgetIndex);
break;
+ case MouseState::RightPress:
+ WindowCloseByClass(WindowClass::Tooltip);
- if (w->classification != _dragWidget.window_classification || w->number != _dragWidget.window_number
- || !(_inputFlags & INPUT_FLAG_TOOL_ACTIVE))
- {
- break;
- }
-
- w = windowMgr->FindByNumber(gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number);
- if (w == nullptr)
- {
- break;
- }
-
- w->OnToolDrag(gCurrentToolWidget.widget_index, screenCoords);
- break;
- case MouseState::LeftRelease:
- _inputState = InputState::Reset;
- if (_dragWidget.window_number == w->number)
- {
- if ((_inputFlags & INPUT_FLAG_TOOL_ACTIVE))
+ if (w != nullptr)
{
- w = windowMgr->FindByNumber(
- gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number);
- if (w != nullptr)
+ w = WindowBringToFront(*w);
+ }
+
+ if (widgetIndex != kWidgetIndexNull)
+ {
+ switch (widget->type)
{
- w->OnToolUp(gCurrentToolWidget.widget_index, screenCoords);
+ case WindowWidgetType::Viewport:
+ if (!(gScreenFlags & (SCREEN_FLAGS_TRACK_MANAGER | SCREEN_FLAGS_TITLE_DEMO)))
+ {
+ InputViewportDragBegin(*w);
+ }
+ break;
+ case WindowWidgetType::Scroll:
+ InputScrollDragBegin(screenCoords, w, widgetIndex);
+ break;
+ default:
+ break;
}
}
- else if (!(_inputFlags & INPUT_FLAG_4))
- {
- ViewportInteractionLeftClick(screenCoords);
- }
+ break;
+ case MouseState::LeftRelease:
+ case MouseState::RightRelease:
+ // In this switch only button presses are relevant
+ break;
+ }
+ break;
+ case InputState::WidgetPressed:
+ InputStateWidgetPressed(screenCoords, state, widgetIndex, w, widget);
+ break;
+ case InputState::PositioningWindow:
+ w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number);
+ if (w == nullptr)
+ {
+ _inputState = InputState::Reset;
+ }
+ else
+ {
+ InputWindowPositionContinue(*w, gInputDragLast, screenCoords);
+ if (state == MouseState::LeftRelease)
+ {
+ InputWindowPositionEnd(*w, screenCoords);
}
- break;
- case MouseState::LeftPress:
- case MouseState::RightPress:
- case MouseState::RightRelease:
- // In this switch only left button release is relevant
- break;
- }
- break;
- case InputState::ScrollLeft:
- switch (state)
- {
- case MouseState::Released:
- InputScrollContinue(*w, widgetIndex, screenCoords);
- break;
- case MouseState::LeftRelease:
- InputScrollEnd();
- break;
- case MouseState::LeftPress:
- case MouseState::RightPress:
- case MouseState::RightRelease:
- // In this switch only left button release is relevant
- break;
- }
- break;
- case InputState::Resizing:
- w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number);
- if (w == nullptr)
- {
- _inputState = InputState::Reset;
- }
- else
- {
- if (state == MouseState::LeftRelease)
- {
- InputWindowResizeEnd();
}
- if (state == MouseState::Released || state == MouseState::LeftRelease)
+ break;
+ case InputState::ViewportRight:
+ if (state == MouseState::Released)
{
- InputWindowResizeContinue(*w, screenCoords);
+ InputViewportDragContinue();
}
- }
- break;
- case InputState::ScrollRight:
- InputScrollRight(screenCoords, state);
- break;
+ else if (state == MouseState::RightRelease)
+ {
+ InputViewportDragEnd();
+ if (_ticksSinceDragStart.has_value() && gCurrentRealTimeTicks - _ticksSinceDragStart.value() < 500)
+ {
+ // If the user pressed the right mouse button for less than 500 ticks, interpret as right click
+ ViewportInteractionRightClick(screenCoords);
+ }
+ }
+ break;
+ case InputState::DropdownActive:
+ InputStateWidgetPressed(screenCoords, state, widgetIndex, w, widget);
+ break;
+ case InputState::ViewportLeft:
+ w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number);
+ if (w == nullptr)
+ {
+ _inputState = InputState::Reset;
+ break;
+ }
+
+ switch (state)
+ {
+ case MouseState::Released:
+ if (w->viewport == nullptr)
+ {
+ _inputState = InputState::Reset;
+ break;
+ }
+
+ if (!InputTestFlag(INPUT_FLAG_4))
+ break;
+
+ if (w->classification != _dragWidget.window_classification || w->number != _dragWidget.window_number
+ || !(_inputFlags & INPUT_FLAG_TOOL_ACTIVE))
+ {
+ break;
+ }
+
+ w = windowMgr->FindByNumber(gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number);
+ if (w == nullptr)
+ {
+ break;
+ }
+
+ w->OnToolDrag(gCurrentToolWidget.widget_index, screenCoords);
+ break;
+ case MouseState::LeftRelease:
+ _inputState = InputState::Reset;
+ if (_dragWidget.window_number == w->number)
+ {
+ if ((_inputFlags & INPUT_FLAG_TOOL_ACTIVE))
+ {
+ w = windowMgr->FindByNumber(
+ gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number);
+ if (w != nullptr)
+ {
+ w->OnToolUp(gCurrentToolWidget.widget_index, screenCoords);
+ }
+ }
+ else if (!(_inputFlags & INPUT_FLAG_4))
+ {
+ ViewportInteractionLeftClick(screenCoords);
+ }
+ }
+ break;
+ case MouseState::LeftPress:
+ case MouseState::RightPress:
+ case MouseState::RightRelease:
+ // In this switch only left button release is relevant
+ break;
+ }
+ break;
+ case InputState::ScrollLeft:
+ switch (state)
+ {
+ case MouseState::Released:
+ InputScrollContinue(*w, widgetIndex, screenCoords);
+ break;
+ case MouseState::LeftRelease:
+ InputScrollEnd();
+ break;
+ case MouseState::LeftPress:
+ case MouseState::RightPress:
+ case MouseState::RightRelease:
+ // In this switch only left button release is relevant
+ break;
+ }
+ break;
+ case InputState::Resizing:
+ w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number);
+ if (w == nullptr)
+ {
+ _inputState = InputState::Reset;
+ }
+ else
+ {
+ if (state == MouseState::LeftRelease)
+ {
+ InputWindowResizeEnd();
+ }
+ if (state == MouseState::Released || state == MouseState::LeftRelease)
+ {
+ InputWindowResizeContinue(*w, screenCoords);
+ }
+ }
+ break;
+ case InputState::ScrollRight:
+ InputScrollRight(screenCoords, state);
+ break;
+ }
}
-}
#pragma region Window positioning / resizing
-void InputWindowPositionBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
-{
- _inputState = InputState::PositioningWindow;
- gInputDragLast = screenCoords - w.windowPos;
- _dragWidget.window_classification = w.classification;
- _dragWidget.window_number = w.number;
- _dragWidget.widget_index = widgetIndex;
-}
-
-static void InputWindowPositionContinue(
- WindowBase& w, const ScreenCoordsXY& lastScreenCoords, const ScreenCoordsXY& newScreenCoords)
-{
- int32_t snapProximity;
-
- snapProximity = (w.flags & WF_NO_SNAPPING) ? 0 : Config::Get().general.WindowSnapProximity;
- WindowMoveAndSnap(w, newScreenCoords - lastScreenCoords, snapProximity);
-}
-
-static void InputWindowPositionEnd(WindowBase& w, const ScreenCoordsXY& screenCoords)
-{
- _inputState = InputState::Normal;
- gTooltipCloseTimeout = 0;
- gTooltipWidget = _dragWidget;
- w.OnMoved(screenCoords);
-}
-
-static void InputWindowResizeBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
-{
- _inputState = InputState::Resizing;
- gInputDragLast = screenCoords;
- _dragWidget.window_classification = w.classification;
- _dragWidget.window_number = w.number;
- _dragWidget.widget_index = widgetIndex;
- _originalWindowWidth = w.width;
- _originalWindowHeight = w.height;
-}
-
-static void InputWindowResizeContinue(WindowBase& w, const ScreenCoordsXY& screenCoords)
-{
- if (screenCoords.y < static_cast(ContextGetHeight()) - 2)
+ void InputWindowPositionBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
{
- auto differentialCoords = screenCoords - gInputDragLast;
- int32_t targetWidth = _originalWindowWidth + differentialCoords.x - w.width;
- int32_t targetHeight = _originalWindowHeight + differentialCoords.y - w.height;
-
- WindowResize(w, targetWidth, targetHeight);
+ _inputState = InputState::PositioningWindow;
+ gInputDragLast = screenCoords - w.windowPos;
+ _dragWidget.window_classification = w.classification;
+ _dragWidget.window_number = w.number;
+ _dragWidget.widget_index = widgetIndex;
}
-}
-static void InputWindowResizeEnd()
-{
- _inputState = InputState::Normal;
- gTooltipCloseTimeout = 0;
- gTooltipWidget = _dragWidget;
-}
+ static void InputWindowPositionContinue(
+ WindowBase& w, const ScreenCoordsXY& lastScreenCoords, const ScreenCoordsXY& newScreenCoords)
+ {
+ int32_t snapProximity;
+
+ snapProximity = (w.flags & WF_NO_SNAPPING) ? 0 : Config::Get().general.WindowSnapProximity;
+ WindowMoveAndSnap(w, newScreenCoords - lastScreenCoords, snapProximity);
+ }
+
+ static void InputWindowPositionEnd(WindowBase& w, const ScreenCoordsXY& screenCoords)
+ {
+ _inputState = InputState::Normal;
+ gTooltipCloseTimeout = 0;
+ gTooltipWidget = _dragWidget;
+ w.OnMoved(screenCoords);
+ }
+
+ static void InputWindowResizeBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
+ {
+ _inputState = InputState::Resizing;
+ gInputDragLast = screenCoords;
+ _dragWidget.window_classification = w.classification;
+ _dragWidget.window_number = w.number;
+ _dragWidget.widget_index = widgetIndex;
+ _originalWindowWidth = w.width;
+ _originalWindowHeight = w.height;
+ }
+
+ static void InputWindowResizeContinue(WindowBase& w, const ScreenCoordsXY& screenCoords)
+ {
+ if (screenCoords.y < static_cast(ContextGetHeight()) - 2)
+ {
+ auto differentialCoords = screenCoords - gInputDragLast;
+ int32_t targetWidth = _originalWindowWidth + differentialCoords.x - w.width;
+ int32_t targetHeight = _originalWindowHeight + differentialCoords.y - w.height;
+
+ WindowResize(w, targetWidth, targetHeight);
+ }
+ }
+
+ static void InputWindowResizeEnd()
+ {
+ _inputState = InputState::Normal;
+ gTooltipCloseTimeout = 0;
+ gTooltipWidget = _dragWidget;
+ }
#pragma endregion
#pragma region Viewport dragging
-static void InputViewportDragBegin(WindowBase& w)
-{
- w.flags &= ~WF_SCROLLING_TO_LOCATION;
- _inputState = InputState::ViewportRight;
- _dragWidget.window_classification = w.classification;
- _dragWidget.window_number = w.number;
- _ticksSinceDragStart = gCurrentRealTimeTicks;
- auto cursorPosition = ContextGetCursorPosition();
- gInputDragLast = cursorPosition;
- if (!Config::Get().general.InvertViewportDrag)
+ static void InputViewportDragBegin(WindowBase& w)
{
- ContextHideCursor();
- }
-
- WindowUnfollowSprite(w);
- // gInputFlags |= INPUT_FLAG_5;
-}
-
-static void InputViewportDragContinue()
-{
- WindowBase* w;
- Viewport* viewport;
-
- auto newDragCoords = ContextGetCursorPosition();
-
- auto differentialCoords = newDragCoords - gInputDragLast;
- if (differentialCoords.x == 0 && differentialCoords.y == 0)
- return;
-
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number);
-
- // #3294: Window can be closed during a drag session, so just finish
- // the session if the window no longer exists
- if (w == nullptr)
- {
- InputViewportDragEnd();
- return;
- }
-
- viewport = w->viewport;
- if (viewport == nullptr)
- {
- ContextShowCursor();
- _inputState = InputState::Reset;
- }
- else if (differentialCoords.x != 0 || differentialCoords.y != 0)
- {
- if (!(w->flags & WF_NO_SCROLLING))
+ w.flags &= ~WF_SCROLLING_TO_LOCATION;
+ _inputState = InputState::ViewportRight;
+ _dragWidget.window_classification = w.classification;
+ _dragWidget.window_number = w.number;
+ _ticksSinceDragStart = gCurrentRealTimeTicks;
+ auto cursorPosition = ContextGetCursorPosition();
+ gInputDragLast = cursorPosition;
+ if (!Config::Get().general.InvertViewportDrag)
{
- // User dragged a scrollable viewport
+ ContextHideCursor();
+ }
- // If the drag time is less than 500 the "drag" is usually interpreted as a right click.
- // As the user moved the mouse, don't interpret it as right click in any case.
- _ticksSinceDragStart = std::nullopt;
+ WindowUnfollowSprite(w);
+ // gInputFlags |= INPUT_FLAG_5;
+ }
- // applying the zoom only with negative values avoids a "deadzone" effect where small positive value round to zero.
- const bool posX = differentialCoords.x > 0;
- const bool posY = differentialCoords.y > 0;
- differentialCoords.x = (viewport->zoom + 1).ApplyTo(-std::abs(differentialCoords.x));
- differentialCoords.y = (viewport->zoom + 1).ApplyTo(-std::abs(differentialCoords.y));
- differentialCoords.x = posX ? -differentialCoords.x : differentialCoords.x;
- differentialCoords.y = posY ? -differentialCoords.y : differentialCoords.y;
+ static void InputViewportDragContinue()
+ {
+ WindowBase* w;
+ Viewport* viewport;
- if (Config::Get().general.InvertViewportDrag)
+ auto newDragCoords = ContextGetCursorPosition();
+
+ auto differentialCoords = newDragCoords - gInputDragLast;
+ if (differentialCoords.x == 0 && differentialCoords.y == 0)
+ return;
+
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number);
+
+ // #3294: Window can be closed during a drag session, so just finish
+ // the session if the window no longer exists
+ if (w == nullptr)
+ {
+ InputViewportDragEnd();
+ return;
+ }
+
+ viewport = w->viewport;
+ if (viewport == nullptr)
+ {
+ ContextShowCursor();
+ _inputState = InputState::Reset;
+ }
+ else if (differentialCoords.x != 0 || differentialCoords.y != 0)
+ {
+ if (!(w->flags & WF_NO_SCROLLING))
{
- w->savedViewPos -= differentialCoords;
- }
- else
- {
- w->savedViewPos += differentialCoords;
+ // User dragged a scrollable viewport
+
+ // If the drag time is less than 500 the "drag" is usually interpreted as a right click.
+ // As the user moved the mouse, don't interpret it as right click in any case.
+ _ticksSinceDragStart = std::nullopt;
+
+ // applying the zoom only with negative values avoids a "deadzone" effect where small positive value round to
+ // zero.
+ const bool posX = differentialCoords.x > 0;
+ const bool posY = differentialCoords.y > 0;
+ differentialCoords.x = (viewport->zoom + 1).ApplyTo(-std::abs(differentialCoords.x));
+ differentialCoords.y = (viewport->zoom + 1).ApplyTo(-std::abs(differentialCoords.y));
+ differentialCoords.x = posX ? -differentialCoords.x : differentialCoords.x;
+ differentialCoords.y = posY ? -differentialCoords.y : differentialCoords.y;
+
+ if (Config::Get().general.InvertViewportDrag)
+ {
+ w->savedViewPos -= differentialCoords;
+ }
+ else
+ {
+ w->savedViewPos += differentialCoords;
+ }
}
}
- }
#ifndef __EMSCRIPTEN__
- const CursorState* cursorState = ContextGetCursorState();
- if (cursorState->touch || Config::Get().general.InvertViewportDrag)
- {
- gInputDragLast = newDragCoords;
- }
- else
- {
- ContextSetCursorPosition(gInputDragLast);
- }
+ const CursorState* cursorState = ContextGetCursorState();
+ if (cursorState->touch || Config::Get().general.InvertViewportDrag)
+ {
+ gInputDragLast = newDragCoords;
+ }
+ else
+ {
+ ContextSetCursorPosition(gInputDragLast);
+ }
#else
- gInputDragLast = newDragCoords;
+ gInputDragLast = newDragCoords;
#endif
-}
+ }
-static void InputViewportDragEnd()
-{
- _inputState = InputState::Reset;
- ContextShowCursor();
-}
+ static void InputViewportDragEnd()
+ {
+ _inputState = InputState::Reset;
+ ContextShowCursor();
+ }
#pragma endregion
#pragma region Scroll bars
-static void InputScrollBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
-{
- const auto& widget = w.widgets[widgetIndex];
-
- _inputState = InputState::ScrollLeft;
- gPressedWidget.window_classification = w.classification;
- gPressedWidget.window_number = w.number;
- gPressedWidget.widget_index = widgetIndex;
- gTooltipCursor = screenCoords;
-
- int32_t scroll_area, scroll_id;
- ScreenCoordsXY scrollCoords;
- scroll_id = 0; // safety
- WidgetScrollGetPart(w, &widget, screenCoords, scrollCoords, &scroll_area, &scroll_id);
-
- _currentScrollArea = scroll_area;
- _currentScrollIndex = scroll_id;
- w.OnScrollSelect(scroll_id, scroll_area);
- if (scroll_area == SCROLL_PART_VIEW)
+ static void InputScrollBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
{
- w.OnScrollMouseDown(scroll_id, scrollCoords);
- return;
- }
+ const auto& widget = w.widgets[widgetIndex];
- const auto& widg = w.widgets[widgetIndex];
- auto& scroll = w.scrolls[scroll_id];
+ _inputState = InputState::ScrollLeft;
+ gPressedWidget.window_classification = w.classification;
+ gPressedWidget.window_number = w.number;
+ gPressedWidget.widget_index = widgetIndex;
+ gTooltipCursor = screenCoords;
- int32_t widget_width = widg.width() - 1;
- if (scroll.flags & VSCROLLBAR_VISIBLE)
- widget_width -= kScrollBarWidth + 1;
- int32_t widget_content_width = std::max(scroll.contentWidth - widget_width, 0);
+ int32_t scroll_area, scroll_id;
+ ScreenCoordsXY scrollCoords;
+ scroll_id = 0; // safety
+ WidgetScrollGetPart(w, &widget, screenCoords, scrollCoords, &scroll_area, &scroll_id);
- int32_t widget_height = widg.bottom - widg.top - 1;
- if (scroll.flags & HSCROLLBAR_VISIBLE)
- widget_height -= kScrollBarWidth + 1;
- int32_t widget_content_height = std::max(scroll.contentHeight - widget_height, 0);
+ _currentScrollArea = scroll_area;
+ _currentScrollIndex = scroll_id;
+ w.OnScrollSelect(scroll_id, scroll_area);
+ if (scroll_area == SCROLL_PART_VIEW)
+ {
+ w.OnScrollMouseDown(scroll_id, scrollCoords);
+ return;
+ }
- switch (scroll_area)
- {
- case SCROLL_PART_HSCROLLBAR_LEFT:
- scroll.contentOffsetX = std::max(scroll.contentOffsetX - 3, 0);
- break;
- case SCROLL_PART_HSCROLLBAR_RIGHT:
- scroll.contentOffsetX = std::min(scroll.contentOffsetX + 3, widget_content_width);
- break;
- case SCROLL_PART_HSCROLLBAR_LEFT_TROUGH:
- scroll.contentOffsetX = std::max(scroll.contentOffsetX - widget_width, 0);
- break;
- case SCROLL_PART_HSCROLLBAR_RIGHT_TROUGH:
- scroll.contentOffsetX = std::min(scroll.contentOffsetX + widget_width, widget_content_width);
- break;
- case SCROLL_PART_VSCROLLBAR_TOP:
- scroll.contentOffsetY = std::max(scroll.contentOffsetY - 3, 0);
- break;
- case SCROLL_PART_VSCROLLBAR_BOTTOM:
- scroll.contentOffsetY = std::min(scroll.contentOffsetY + 3, widget_content_height);
- break;
- case SCROLL_PART_VSCROLLBAR_TOP_TROUGH:
- scroll.contentOffsetY = std::max(scroll.contentOffsetY - widget_height, 0);
- break;
- case SCROLL_PART_VSCROLLBAR_BOTTOM_TROUGH:
- scroll.contentOffsetY = std::min(scroll.contentOffsetY + widget_height, widget_content_height);
- break;
- default:
- break;
- }
- WidgetScrollUpdateThumbs(w, widgetIndex);
- WindowInvalidateByNumber(w.classification, w.number);
-}
-
-static void InputScrollContinue(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
-{
- int32_t scroll_part, scroll_id;
-
- const auto& widget = w.widgets[widgetIndex];
- if (w.classification != gPressedWidget.window_classification || w.number != gPressedWidget.window_number
- || widgetIndex != gPressedWidget.widget_index)
- {
- InvalidateScroll();
- return;
- }
-
- ScreenCoordsXY newScreenCoords;
- WidgetScrollGetPart(w, &widget, screenCoords, newScreenCoords, &scroll_part, &scroll_id);
-
- if (_currentScrollArea == SCROLL_PART_HSCROLLBAR_THUMB)
- {
- int32_t originalTooltipCursorX = gTooltipCursor.x;
- gTooltipCursor.x = screenCoords.x;
- InputScrollPartUpdateHThumb(w, widgetIndex, screenCoords.x - originalTooltipCursorX, scroll_id);
- return;
- }
-
- if (_currentScrollArea == SCROLL_PART_VSCROLLBAR_THUMB)
- {
- int32_t originalTooltipCursorY = gTooltipCursor.y;
- gTooltipCursor.y = screenCoords.y;
- InputScrollPartUpdateVThumb(w, widgetIndex, screenCoords.y - originalTooltipCursorY, scroll_id);
- return;
- }
-
- if (scroll_part != _currentScrollArea)
- {
- InvalidateScroll();
- return;
- }
-
- switch (scroll_part)
- {
- case SCROLL_PART_VIEW:
- w.OnScrollMouseDrag(scroll_id, newScreenCoords);
- break;
- case SCROLL_PART_HSCROLLBAR_LEFT:
- InputScrollPartUpdateHLeft(w, widgetIndex, scroll_id);
- break;
- case SCROLL_PART_HSCROLLBAR_RIGHT:
- InputScrollPartUpdateHRight(w, widgetIndex, scroll_id);
- break;
- case SCROLL_PART_VSCROLLBAR_TOP:
- InputScrollPartUpdateVTop(w, widgetIndex, scroll_id);
- break;
- case SCROLL_PART_VSCROLLBAR_BOTTOM:
- InputScrollPartUpdateVBottom(w, widgetIndex, scroll_id);
- break;
- }
-}
-
-static void InputScrollEnd()
-{
- _inputState = InputState::Reset;
- InvalidateScroll();
-}
-
-/**
- *
- * rct2: 0x006E98F2
- */
-static void InputScrollPartUpdateHThumb(WindowBase& w, WidgetIndex widgetIndex, int32_t x, int32_t scroll_id)
-{
- const auto& widget = w.widgets[widgetIndex];
- auto& scroll = w.scrolls[scroll_id];
-
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- if (windowMgr->FindByNumber(w.classification, w.number) != nullptr)
- {
- int32_t newLeft;
- newLeft = scroll.contentWidth;
- newLeft *= x;
- x = widget.width() - 21;
- if (scroll.flags & VSCROLLBAR_VISIBLE)
- x -= kScrollBarWidth + 1;
- newLeft /= x;
- x = newLeft;
- scroll.flags |= HSCROLLBAR_THUMB_PRESSED;
- newLeft = scroll.contentOffsetX;
- newLeft += x;
- if (newLeft < 0)
- newLeft = 0;
- x = widget.width() - 1;
- if (scroll.flags & VSCROLLBAR_VISIBLE)
- x -= kScrollBarWidth + 1;
- x *= -1;
- x += scroll.contentWidth;
- if (x < 0)
- x = 0;
- if (newLeft > x)
- newLeft = x;
- scroll.contentOffsetX = newLeft;
- WidgetScrollUpdateThumbs(w, widgetIndex);
- WidgetInvalidateByNumber(w.classification, w.number, widgetIndex);
- }
-}
-
-/**
- *
- * rct2: 0x006E99A9
- */
-static void InputScrollPartUpdateVThumb(WindowBase& w, WidgetIndex widgetIndex, int32_t y, int32_t scroll_id)
-{
- const auto& widget = w.widgets[widgetIndex];
- auto& scroll = w.scrolls[scroll_id];
-
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- if (windowMgr->FindByNumber(w.classification, w.number) != nullptr)
- {
- int32_t newTop;
- newTop = scroll.contentHeight;
- newTop *= y;
- y = widget.height() - 21;
- if (scroll.flags & HSCROLLBAR_VISIBLE)
- y -= kScrollBarWidth + 1;
- newTop /= y;
- y = newTop;
- scroll.flags |= VSCROLLBAR_THUMB_PRESSED;
- newTop = scroll.contentOffsetY;
- newTop += y;
- if (newTop < 0)
- newTop = 0;
- y = widget.height() - 1;
- if (scroll.flags & HSCROLLBAR_VISIBLE)
- y -= kScrollBarWidth + 1;
- y *= -1;
- y += scroll.contentHeight;
- if (y < 0)
- y = 0;
- if (newTop > y)
- newTop = y;
- scroll.contentOffsetY = newTop;
- WidgetScrollUpdateThumbs(w, widgetIndex);
- WidgetInvalidateByNumber(w.classification, w.number, widgetIndex);
- }
-}
-
-/**
- *
- * rct2: 0x006E9A60
- */
-static void InputScrollPartUpdateHLeft(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id)
-{
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- if (windowMgr->FindByNumber(w.classification, w.number) != nullptr)
- {
+ const auto& widg = w.widgets[widgetIndex];
auto& scroll = w.scrolls[scroll_id];
- scroll.flags |= HSCROLLBAR_LEFT_PRESSED;
- if (scroll.contentOffsetX >= 3)
- scroll.contentOffsetX -= 3;
- WidgetScrollUpdateThumbs(w, widgetIndex);
- WidgetInvalidateByNumber(w.classification, w.number, widgetIndex);
- }
-}
-/**
- *
- * rct2: 0x006E9ABF
- */
-static void InputScrollPartUpdateHRight(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id)
-{
- const auto& widget = w.widgets[widgetIndex];
-
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- if (windowMgr->FindByNumber(w.classification, w.number) != nullptr)
- {
- auto& scroll = w.scrolls[scroll_id];
- scroll.flags |= HSCROLLBAR_RIGHT_PRESSED;
- scroll.contentOffsetX += 3;
- int32_t newLeft = widget.width() - 1;
+ int32_t widget_width = widg.width() - 1;
if (scroll.flags & VSCROLLBAR_VISIBLE)
- newLeft -= kScrollBarWidth + 1;
- newLeft *= -1;
- newLeft += scroll.contentWidth;
- if (newLeft < 0)
- newLeft = 0;
- if (scroll.contentOffsetX > newLeft)
+ widget_width -= kScrollBarWidth + 1;
+ int32_t widget_content_width = std::max(scroll.contentWidth - widget_width, 0);
+
+ int32_t widget_height = widg.bottom - widg.top - 1;
+ if (scroll.flags & HSCROLLBAR_VISIBLE)
+ widget_height -= kScrollBarWidth + 1;
+ int32_t widget_content_height = std::max(scroll.contentHeight - widget_height, 0);
+
+ switch (scroll_area)
+ {
+ case SCROLL_PART_HSCROLLBAR_LEFT:
+ scroll.contentOffsetX = std::max(scroll.contentOffsetX - 3, 0);
+ break;
+ case SCROLL_PART_HSCROLLBAR_RIGHT:
+ scroll.contentOffsetX = std::min(scroll.contentOffsetX + 3, widget_content_width);
+ break;
+ case SCROLL_PART_HSCROLLBAR_LEFT_TROUGH:
+ scroll.contentOffsetX = std::max(scroll.contentOffsetX - widget_width, 0);
+ break;
+ case SCROLL_PART_HSCROLLBAR_RIGHT_TROUGH:
+ scroll.contentOffsetX = std::min(scroll.contentOffsetX + widget_width, widget_content_width);
+ break;
+ case SCROLL_PART_VSCROLLBAR_TOP:
+ scroll.contentOffsetY = std::max(scroll.contentOffsetY - 3, 0);
+ break;
+ case SCROLL_PART_VSCROLLBAR_BOTTOM:
+ scroll.contentOffsetY = std::min(scroll.contentOffsetY + 3, widget_content_height);
+ break;
+ case SCROLL_PART_VSCROLLBAR_TOP_TROUGH:
+ scroll.contentOffsetY = std::max(scroll.contentOffsetY - widget_height, 0);
+ break;
+ case SCROLL_PART_VSCROLLBAR_BOTTOM_TROUGH:
+ scroll.contentOffsetY = std::min(scroll.contentOffsetY + widget_height, widget_content_height);
+ break;
+ default:
+ break;
+ }
+ WidgetScrollUpdateThumbs(w, widgetIndex);
+ WindowInvalidateByNumber(w.classification, w.number);
+ }
+
+ static void InputScrollContinue(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
+ {
+ int32_t scroll_part, scroll_id;
+
+ const auto& widget = w.widgets[widgetIndex];
+ if (w.classification != gPressedWidget.window_classification || w.number != gPressedWidget.window_number
+ || widgetIndex != gPressedWidget.widget_index)
+ {
+ InvalidateScroll();
+ return;
+ }
+
+ ScreenCoordsXY newScreenCoords;
+ WidgetScrollGetPart(w, &widget, screenCoords, newScreenCoords, &scroll_part, &scroll_id);
+
+ if (_currentScrollArea == SCROLL_PART_HSCROLLBAR_THUMB)
+ {
+ int32_t originalTooltipCursorX = gTooltipCursor.x;
+ gTooltipCursor.x = screenCoords.x;
+ InputScrollPartUpdateHThumb(w, widgetIndex, screenCoords.x - originalTooltipCursorX, scroll_id);
+ return;
+ }
+
+ if (_currentScrollArea == SCROLL_PART_VSCROLLBAR_THUMB)
+ {
+ int32_t originalTooltipCursorY = gTooltipCursor.y;
+ gTooltipCursor.y = screenCoords.y;
+ InputScrollPartUpdateVThumb(w, widgetIndex, screenCoords.y - originalTooltipCursorY, scroll_id);
+ return;
+ }
+
+ if (scroll_part != _currentScrollArea)
+ {
+ InvalidateScroll();
+ return;
+ }
+
+ switch (scroll_part)
+ {
+ case SCROLL_PART_VIEW:
+ w.OnScrollMouseDrag(scroll_id, newScreenCoords);
+ break;
+ case SCROLL_PART_HSCROLLBAR_LEFT:
+ InputScrollPartUpdateHLeft(w, widgetIndex, scroll_id);
+ break;
+ case SCROLL_PART_HSCROLLBAR_RIGHT:
+ InputScrollPartUpdateHRight(w, widgetIndex, scroll_id);
+ break;
+ case SCROLL_PART_VSCROLLBAR_TOP:
+ InputScrollPartUpdateVTop(w, widgetIndex, scroll_id);
+ break;
+ case SCROLL_PART_VSCROLLBAR_BOTTOM:
+ InputScrollPartUpdateVBottom(w, widgetIndex, scroll_id);
+ break;
+ }
+ }
+
+ static void InputScrollEnd()
+ {
+ _inputState = InputState::Reset;
+ InvalidateScroll();
+ }
+
+ /**
+ *
+ * rct2: 0x006E98F2
+ */
+ static void InputScrollPartUpdateHThumb(WindowBase& w, WidgetIndex widgetIndex, int32_t x, int32_t scroll_id)
+ {
+ const auto& widget = w.widgets[widgetIndex];
+ auto& scroll = w.scrolls[scroll_id];
+
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ if (windowMgr->FindByNumber(w.classification, w.number) != nullptr)
+ {
+ int32_t newLeft;
+ newLeft = scroll.contentWidth;
+ newLeft *= x;
+ x = widget.width() - 21;
+ if (scroll.flags & VSCROLLBAR_VISIBLE)
+ x -= kScrollBarWidth + 1;
+ newLeft /= x;
+ x = newLeft;
+ scroll.flags |= HSCROLLBAR_THUMB_PRESSED;
+ newLeft = scroll.contentOffsetX;
+ newLeft += x;
+ if (newLeft < 0)
+ newLeft = 0;
+ x = widget.width() - 1;
+ if (scroll.flags & VSCROLLBAR_VISIBLE)
+ x -= kScrollBarWidth + 1;
+ x *= -1;
+ x += scroll.contentWidth;
+ if (x < 0)
+ x = 0;
+ if (newLeft > x)
+ newLeft = x;
scroll.contentOffsetX = newLeft;
- WidgetScrollUpdateThumbs(w, widgetIndex);
- WidgetInvalidateByNumber(w.classification, w.number, widgetIndex);
+ WidgetScrollUpdateThumbs(w, widgetIndex);
+ WidgetInvalidateByNumber(w.classification, w.number, widgetIndex);
+ }
}
-}
-/**
- *
- * rct2: 0x006E9C37
- */
-static void InputScrollPartUpdateVTop(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id)
-{
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- if (windowMgr->FindByNumber(w.classification, w.number) != nullptr)
+ /**
+ *
+ * rct2: 0x006E99A9
+ */
+ static void InputScrollPartUpdateVThumb(WindowBase& w, WidgetIndex widgetIndex, int32_t y, int32_t scroll_id)
{
+ const auto& widget = w.widgets[widgetIndex];
auto& scroll = w.scrolls[scroll_id];
- scroll.flags |= VSCROLLBAR_UP_PRESSED;
- if (scroll.contentOffsetY >= 3)
- scroll.contentOffsetY -= 3;
- WidgetScrollUpdateThumbs(w, widgetIndex);
- WidgetInvalidateByNumber(w.classification, w.number, widgetIndex);
- }
-}
-/**
- *
- * rct2: 0x006E9C96
- */
-static void InputScrollPartUpdateVBottom(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id)
-{
- const auto& widget = w.widgets[widgetIndex];
-
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- if (windowMgr->FindByNumber(w.classification, w.number) != nullptr)
- {
- auto& scroll = w.scrolls[scroll_id];
- scroll.flags |= VSCROLLBAR_DOWN_PRESSED;
- scroll.contentOffsetY += 3;
- int32_t newTop = widget.height() - 1;
- if (scroll.flags & HSCROLLBAR_VISIBLE)
- newTop -= kScrollBarWidth + 1;
- newTop *= -1;
- newTop += scroll.contentHeight;
- if (newTop < 0)
- newTop = 0;
- if (scroll.contentOffsetY > newTop)
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ if (windowMgr->FindByNumber(w.classification, w.number) != nullptr)
+ {
+ int32_t newTop;
+ newTop = scroll.contentHeight;
+ newTop *= y;
+ y = widget.height() - 21;
+ if (scroll.flags & HSCROLLBAR_VISIBLE)
+ y -= kScrollBarWidth + 1;
+ newTop /= y;
+ y = newTop;
+ scroll.flags |= VSCROLLBAR_THUMB_PRESSED;
+ newTop = scroll.contentOffsetY;
+ newTop += y;
+ if (newTop < 0)
+ newTop = 0;
+ y = widget.height() - 1;
+ if (scroll.flags & HSCROLLBAR_VISIBLE)
+ y -= kScrollBarWidth + 1;
+ y *= -1;
+ y += scroll.contentHeight;
+ if (y < 0)
+ y = 0;
+ if (newTop > y)
+ newTop = y;
scroll.contentOffsetY = newTop;
- WidgetScrollUpdateThumbs(w, widgetIndex);
- WidgetInvalidateByNumber(w.classification, w.number, widgetIndex);
+ WidgetScrollUpdateThumbs(w, widgetIndex);
+ WidgetInvalidateByNumber(w.classification, w.number, widgetIndex);
+ }
+ }
+
+ /**
+ *
+ * rct2: 0x006E9A60
+ */
+ static void InputScrollPartUpdateHLeft(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id)
+ {
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ if (windowMgr->FindByNumber(w.classification, w.number) != nullptr)
+ {
+ auto& scroll = w.scrolls[scroll_id];
+ scroll.flags |= HSCROLLBAR_LEFT_PRESSED;
+ if (scroll.contentOffsetX >= 3)
+ scroll.contentOffsetX -= 3;
+ WidgetScrollUpdateThumbs(w, widgetIndex);
+ WidgetInvalidateByNumber(w.classification, w.number, widgetIndex);
+ }
+ }
+
+ /**
+ *
+ * rct2: 0x006E9ABF
+ */
+ static void InputScrollPartUpdateHRight(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id)
+ {
+ const auto& widget = w.widgets[widgetIndex];
+
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ if (windowMgr->FindByNumber(w.classification, w.number) != nullptr)
+ {
+ auto& scroll = w.scrolls[scroll_id];
+ scroll.flags |= HSCROLLBAR_RIGHT_PRESSED;
+ scroll.contentOffsetX += 3;
+ int32_t newLeft = widget.width() - 1;
+ if (scroll.flags & VSCROLLBAR_VISIBLE)
+ newLeft -= kScrollBarWidth + 1;
+ newLeft *= -1;
+ newLeft += scroll.contentWidth;
+ if (newLeft < 0)
+ newLeft = 0;
+ if (scroll.contentOffsetX > newLeft)
+ scroll.contentOffsetX = newLeft;
+ WidgetScrollUpdateThumbs(w, widgetIndex);
+ WidgetInvalidateByNumber(w.classification, w.number, widgetIndex);
+ }
+ }
+
+ /**
+ *
+ * rct2: 0x006E9C37
+ */
+ static void InputScrollPartUpdateVTop(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id)
+ {
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ if (windowMgr->FindByNumber(w.classification, w.number) != nullptr)
+ {
+ auto& scroll = w.scrolls[scroll_id];
+ scroll.flags |= VSCROLLBAR_UP_PRESSED;
+ if (scroll.contentOffsetY >= 3)
+ scroll.contentOffsetY -= 3;
+ WidgetScrollUpdateThumbs(w, widgetIndex);
+ WidgetInvalidateByNumber(w.classification, w.number, widgetIndex);
+ }
+ }
+
+ /**
+ *
+ * rct2: 0x006E9C96
+ */
+ static void InputScrollPartUpdateVBottom(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id)
+ {
+ const auto& widget = w.widgets[widgetIndex];
+
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ if (windowMgr->FindByNumber(w.classification, w.number) != nullptr)
+ {
+ auto& scroll = w.scrolls[scroll_id];
+ scroll.flags |= VSCROLLBAR_DOWN_PRESSED;
+ scroll.contentOffsetY += 3;
+ int32_t newTop = widget.height() - 1;
+ if (scroll.flags & HSCROLLBAR_VISIBLE)
+ newTop -= kScrollBarWidth + 1;
+ newTop *= -1;
+ newTop += scroll.contentHeight;
+ if (newTop < 0)
+ newTop = 0;
+ if (scroll.contentOffsetY > newTop)
+ scroll.contentOffsetY = newTop;
+ WidgetScrollUpdateThumbs(w, widgetIndex);
+ WidgetInvalidateByNumber(w.classification, w.number, widgetIndex);
+ }
}
-}
#pragma endregion
#pragma region Widgets
-/**
- *
- * rct2: 0x006E9253
- */
-static void InputWidgetOver(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex)
-{
- WindowClass windowClass = WindowClass::Null;
- rct_windownumber windowNumber = 0;
- Widget* widget = nullptr;
-
- if (w != nullptr)
+ /**
+ *
+ * rct2: 0x006E9253
+ */
+ static void InputWidgetOver(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex)
{
- windowClass = w->classification;
- windowNumber = w->number;
- widget = &w->widgets[widgetIndex];
- }
+ WindowClass windowClass = WindowClass::Null;
+ rct_windownumber windowNumber = 0;
+ Widget* widget = nullptr;
- InputWidgetOverChangeCheck(windowClass, windowNumber, widgetIndex);
+ if (w != nullptr)
+ {
+ windowClass = w->classification;
+ windowNumber = w->number;
+ widget = &w->widgets[widgetIndex];
+ }
- if (w != nullptr && widgetIndex != -1 && widget->type == WindowWidgetType::Scroll)
- {
- int32_t scroll_part, scrollId;
- ScreenCoordsXY newScreenCoords;
- WidgetScrollGetPart(*w, widget, screenCoords, newScreenCoords, &scroll_part, &scrollId);
+ InputWidgetOverChangeCheck(windowClass, windowNumber, widgetIndex);
- if (scroll_part != SCROLL_PART_VIEW)
- WindowTooltipClose();
+ if (w != nullptr && widgetIndex != kWidgetIndexNull && widget->type == WindowWidgetType::Scroll)
+ {
+ int32_t scroll_part, scrollId;
+ ScreenCoordsXY newScreenCoords;
+ WidgetScrollGetPart(*w, widget, screenCoords, newScreenCoords, &scroll_part, &scrollId);
+
+ if (scroll_part != SCROLL_PART_VIEW)
+ WindowTooltipClose();
+ else
+ {
+ w->OnScrollMouseOver(scrollId, newScreenCoords);
+ InputUpdateTooltip(w, widgetIndex, screenCoords);
+ }
+ }
else
{
- w->OnScrollMouseOver(scrollId, newScreenCoords);
InputUpdateTooltip(w, widgetIndex, screenCoords);
}
}
- else
+
+ /**
+ *
+ * rct2: 0x006E9269
+ */
+ static void InputWidgetOverChangeCheck(WindowClass windowClass, rct_windownumber windowNumber, WidgetIndex widgetIndex)
{
- InputUpdateTooltip(w, widgetIndex, screenCoords);
- }
-}
+ // Prevents invalid widgets being clicked source of bug is elsewhere
+ if (widgetIndex == kWidgetIndexNull)
+ return;
-/**
- *
- * rct2: 0x006E9269
- */
-static void InputWidgetOverChangeCheck(WindowClass windowClass, rct_windownumber windowNumber, WidgetIndex widgetIndex)
-{
- // Prevents invalid widgets being clicked source of bug is elsewhere
- if (widgetIndex == -1)
- return;
-
- // Check if the widget that the cursor was over, has changed
- if (windowClass != gHoverWidget.window_classification || windowNumber != gHoverWidget.window_number
- || widgetIndex != gHoverWidget.widget_index)
- {
- // Invalidate last widget cursor was on if widget is a flat button
- InputWidgetOverFlatbuttonInvalidate();
-
- // Set new cursor over widget
- gHoverWidget.window_classification = windowClass;
- gHoverWidget.window_number = windowNumber;
- gHoverWidget.widget_index = widgetIndex;
-
- // Invalidate new widget cursor is on if widget is a flat button
- if (windowClass != WindowClass::Null)
+ // Check if the widget that the cursor was over, has changed
+ if (windowClass != gHoverWidget.window_classification || windowNumber != gHoverWidget.window_number
+ || widgetIndex != gHoverWidget.widget_index)
+ {
+ // Invalidate last widget cursor was on if widget is a flat button
InputWidgetOverFlatbuttonInvalidate();
- }
-}
-/**
- * Used to invalidate flat button widgets when the mouse leaves and enters them. This should be generalised so that all widgets
- * can use this in the future.
- */
-static void InputWidgetOverFlatbuttonInvalidate()
-{
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- WindowBase* w = windowMgr->FindByNumber(gHoverWidget.window_classification, gHoverWidget.window_number);
- if (w != nullptr)
- {
- w->OnPrepareDraw();
- if (w->widgets[gHoverWidget.widget_index].type == WindowWidgetType::FlatBtn)
- {
- WidgetInvalidateByNumber(gHoverWidget.window_classification, gHoverWidget.window_number, gHoverWidget.widget_index);
- }
- }
-}
+ // Set new cursor over widget
+ gHoverWidget.window_classification = windowClass;
+ gHoverWidget.window_number = windowNumber;
+ gHoverWidget.widget_index = widgetIndex;
-/**
- *
- * rct2: 0x006E95F9
- */
-static void InputWidgetLeft(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex)
-{
- WindowClass windowClass = WindowClass::Null;
- rct_windownumber windowNumber = 0;
-
- if (w != nullptr)
- {
- windowClass = w->classification;
- windowNumber = w->number;
- }
-
- WindowCloseByClass(WindowClass::Error);
- WindowCloseByClass(WindowClass::Tooltip);
-
- // Window might have changed position in the list, therefore find it again
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- w = windowMgr->FindByNumber(windowClass, windowNumber);
- if (w == nullptr)
- return;
-
- w = WindowBringToFront(*w);
- if (widgetIndex == -1)
- return;
-
- if (windowClass != GetCurrentTextBox().window.classification || windowNumber != GetCurrentTextBox().window.number
- || widgetIndex != GetCurrentTextBox().widget_index)
- {
- WindowCancelTextbox();
- }
-
- const auto& widget = w->widgets[widgetIndex];
-
- switch (widget.type)
- {
- case WindowWidgetType::Frame:
- case WindowWidgetType::Resize:
- if (WindowCanResize(*w)
- && (screenCoords.x >= w->windowPos.x + w->width - 19 && screenCoords.y >= w->windowPos.y + w->height - 19))
- InputWindowResizeBegin(*w, widgetIndex, screenCoords);
- break;
- case WindowWidgetType::Viewport:
- _inputState = InputState::ViewportLeft;
- gInputDragLast = screenCoords;
- _dragWidget.window_classification = windowClass;
- _dragWidget.window_number = windowNumber;
- if (_inputFlags & INPUT_FLAG_TOOL_ACTIVE)
- {
- w = windowMgr->FindByNumber(gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number);
- if (w != nullptr)
- {
- InputSetFlag(INPUT_FLAG_4, true);
- w->OnToolDown(gCurrentToolWidget.widget_index, screenCoords);
- }
- }
- break;
- case WindowWidgetType::Caption:
- InputWindowPositionBegin(*w, widgetIndex, screenCoords);
- break;
- case WindowWidgetType::Scroll:
- InputScrollBegin(*w, widgetIndex, screenCoords);
- break;
- case WindowWidgetType::Empty:
- case WindowWidgetType::LabelCentred:
- case WindowWidgetType::Label:
- case WindowWidgetType::Groupbox:
- case WindowWidgetType::ProgressBar:
- case WindowWidgetType::Placeholder:
- case WindowWidgetType::Last:
- // Non-interactive widget type
- break;
- case WindowWidgetType::ImgBtn:
- case WindowWidgetType::ColourBtn:
- case WindowWidgetType::TrnBtn:
- case WindowWidgetType::Tab:
- case WindowWidgetType::FlatBtn:
- case WindowWidgetType::Button:
- case WindowWidgetType::TableHeader:
- case WindowWidgetType::Spinner:
- case WindowWidgetType::DropdownMenu:
- case WindowWidgetType::CloseBox:
- case WindowWidgetType::Checkbox:
- case WindowWidgetType::TextBox:
- case WindowWidgetType::Custom:
- if (!WidgetIsDisabled(*w, widgetIndex))
- {
- OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click1, 0, w->windowPos.x + widget.midX());
-
- // Set new cursor down widget
- gPressedWidget.window_classification = windowClass;
- gPressedWidget.window_number = windowNumber;
- gPressedWidget.widget_index = widgetIndex;
- _inputFlags |= INPUT_FLAG_WIDGET_PRESSED;
- _inputState = InputState::WidgetPressed;
- _clickRepeatTicks = gCurrentRealTimeTicks;
-
- WidgetInvalidateByNumber(windowClass, windowNumber, widgetIndex);
- w->OnMouseDown(widgetIndex);
- }
- break;
- }
-}
-
-/**
- *
- * rct2: 0x006ED833
- */
-void ProcessMouseOver(const ScreenCoordsXY& screenCoords)
-{
- CursorID cursorId = CursorID::Arrow;
- auto ft = Formatter();
- ft.Add(STR_NONE);
- SetMapTooltip(ft);
-
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- WindowBase* window = windowMgr->FindFromPoint(screenCoords);
-
- if (window != nullptr)
- {
- WidgetIndex widgetId = windowMgr->FindWidgetFromPoint(*window, screenCoords);
- if (widgetId != -1)
- {
- switch (window->widgets[widgetId].type)
- {
- case WindowWidgetType::Viewport:
- if (!(_inputFlags & INPUT_FLAG_TOOL_ACTIVE))
- {
- if (ViewportInteractionLeftOver(screenCoords))
- {
- SetCursor(CursorID::HandPoint);
- return;
- }
- break;
- }
- cursorId = static_cast(gCurrentToolId);
- break;
-
- case WindowWidgetType::Frame:
- case WindowWidgetType::Resize:
- if (!(window->flags & WF_RESIZABLE))
- break;
-
- if (window->min_width == window->max_width && window->min_height == window->max_height)
- break;
-
- if (screenCoords.x < window->windowPos.x + window->width - 0x13)
- break;
-
- if (screenCoords.y < window->windowPos.y + window->height - 0x13)
- break;
-
- cursorId = CursorID::DiagonalArrows;
- break;
-
- case WindowWidgetType::Scroll:
- {
- int32_t output_scroll_area, scroll_id;
- ScreenCoordsXY scrollCoords;
- WidgetScrollGetPart(
- *window, &window->widgets[widgetId], screenCoords, scrollCoords, &output_scroll_area, &scroll_id);
- if (output_scroll_area != SCROLL_PART_VIEW)
- {
- cursorId = CursorID::Arrow;
- break;
- }
- // Same as default but with scroll_x/y
- cursorId = window->OnCursor(widgetId, scrollCoords, CursorID::Arrow);
- if (cursorId == CursorID::Undefined)
- cursorId = CursorID::Arrow;
- break;
- }
- default:
- cursorId = window->OnCursor(widgetId, screenCoords, CursorID::Arrow);
- if (cursorId == CursorID::Undefined)
- cursorId = CursorID::Arrow;
- break;
- }
+ // Invalidate new widget cursor is on if widget is a flat button
+ if (windowClass != WindowClass::Null)
+ InputWidgetOverFlatbuttonInvalidate();
}
}
- ViewportInteractionRightOver(screenCoords);
- SetCursor(cursorId);
-}
-
-/**
- *
- * rct2: 0x006ED801
- */
-void ProcessMouseTool(const ScreenCoordsXY& screenCoords)
-{
- if (_inputFlags & INPUT_FLAG_TOOL_ACTIVE)
+ /**
+ * Used to invalidate flat button widgets when the mouse leaves and enters them. This should be generalised so that all
+ * widgets can use this in the future.
+ */
+ static void InputWidgetOverFlatbuttonInvalidate()
{
auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- WindowBase* w = windowMgr->FindByNumber(gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number);
-
- if (w == nullptr)
- ToolCancel();
- else if (InputGetState() != InputState::ViewportRight)
- w->OnToolUpdate(gCurrentToolWidget.widget_index, screenCoords);
- }
-}
-
-const std::map kColourToTip = {
- { COLOUR_BLACK, STR_COLOUR_BLACK_TIP },
- { COLOUR_GREY, STR_COLOUR_GREY_TIP },
- { COLOUR_WHITE, STR_COLOUR_WHITE_TIP },
- { COLOUR_DARK_PURPLE, STR_COLOUR_DARK_PURPLE_TIP },
- { COLOUR_LIGHT_PURPLE, STR_COLOUR_LIGHT_PURPLE_TIP },
- { COLOUR_BRIGHT_PURPLE, STR_COLOUR_BRIGHT_PURPLE_TIP },
- { COLOUR_DARK_BLUE, STR_COLOUR_DARK_BLUE_TIP },
- { COLOUR_LIGHT_BLUE, STR_COLOUR_LIGHT_BLUE_TIP },
- { COLOUR_ICY_BLUE, STR_COLOUR_ICY_BLUE_TIP },
- { COLOUR_TEAL, STR_COLOUR_TEAL_TIP },
- { COLOUR_AQUAMARINE, STR_COLOUR_AQUAMARINE_TIP },
- { COLOUR_SATURATED_GREEN, STR_COLOUR_SATURATED_GREEN_TIP },
- { COLOUR_DARK_GREEN, STR_COLOUR_DARK_GREEN_TIP },
- { COLOUR_MOSS_GREEN, STR_COLOUR_MOSS_GREEN_TIP },
- { COLOUR_BRIGHT_GREEN, STR_COLOUR_BRIGHT_GREEN_TIP },
- { COLOUR_OLIVE_GREEN, STR_COLOUR_OLIVE_GREEN_TIP },
- { COLOUR_DARK_OLIVE_GREEN, STR_COLOUR_DARK_OLIVE_GREEN_TIP },
- { COLOUR_BRIGHT_YELLOW, STR_COLOUR_BRIGHT_YELLOW_TIP },
- { COLOUR_YELLOW, STR_COLOUR_YELLOW_TIP },
- { COLOUR_DARK_YELLOW, STR_COLOUR_DARK_YELLOW_TIP },
- { COLOUR_LIGHT_ORANGE, STR_COLOUR_LIGHT_ORANGE_TIP },
- { COLOUR_DARK_ORANGE, STR_COLOUR_DARK_ORANGE_TIP },
- { COLOUR_LIGHT_BROWN, STR_COLOUR_LIGHT_BROWN_TIP },
- { COLOUR_SATURATED_BROWN, STR_COLOUR_SATURATED_BROWN_TIP },
- { COLOUR_DARK_BROWN, STR_COLOUR_DARK_BROWN_TIP },
- { COLOUR_SALMON_PINK, STR_COLOUR_SALMON_PINK_TIP },
- { COLOUR_BORDEAUX_RED, STR_COLOUR_BORDEAUX_RED_TIP },
- { COLOUR_SATURATED_RED, STR_COLOUR_SATURATED_RED_TIP },
- { COLOUR_BRIGHT_RED, STR_COLOUR_BRIGHT_RED_TIP },
- { COLOUR_DARK_PINK, STR_COLOUR_DARK_PINK_TIP },
- { COLOUR_BRIGHT_PINK, STR_COLOUR_BRIGHT_PINK_TIP },
- { COLOUR_LIGHT_PINK, STR_COLOUR_LIGHT_PINK_TIP },
- { COLOUR_DARK_OLIVE_DARK, STR_COLOUR_DARK_OLIVE_DARK_TIP },
- { COLOUR_DARK_OLIVE_LIGHT, STR_COLOUR_DARK_OLIVE_LIGHT_TIP },
- { COLOUR_SATURATED_BROWN_LIGHT, STR_COLOUR_SATURATED_BROWN_LIGHT_TIP },
- { COLOUR_BORDEAUX_RED_DARK, STR_COLOUR_BORDEAUX_RED_DARK_TIP },
- { COLOUR_BORDEAUX_RED_LIGHT, STR_COLOUR_BORDEAUX_RED_LIGHT_TIP },
- { COLOUR_GRASS_GREEN_DARK, STR_COLOUR_GRASS_GREEN_DARK_TIP },
- { COLOUR_GRASS_GREEN_LIGHT, STR_COLOUR_GRASS_GREEN_LIGHT_TIP },
- { COLOUR_OLIVE_DARK, STR_COLOUR_OLIVE_DARK_TIP },
- { COLOUR_OLIVE_LIGHT, STR_COLOUR_OLIVE_LIGHT_TIP },
- { COLOUR_SATURATED_GREEN_LIGHT, STR_COLOUR_SATURATED_GREEN_LIGHT_TIP },
- { COLOUR_TAN_DARK, STR_COLOUR_TAN_DARK_TIP },
- { COLOUR_TAN_LIGHT, STR_COLOUR_TAN_LIGHT_TIP },
- { COLOUR_DULL_PURPLE_LIGHT, STR_COLOUR_DULL_PURPLE_LIGHT_TIP },
- { COLOUR_DULL_GREEN_DARK, STR_COLOUR_DULL_GREEN_DARK_TIP },
- { COLOUR_DULL_GREEN_LIGHT, STR_COLOUR_DULL_GREEN_LIGHT_TIP },
- { COLOUR_SATURATED_PURPLE_DARK, STR_COLOUR_SATURATED_PURPLE_DARK_TIP },
- { COLOUR_SATURATED_PURPLE_LIGHT, STR_COLOUR_SATURATED_PURPLE_LIGHT_TIP },
- { COLOUR_ORANGE_LIGHT, STR_COLOUR_ORANGE_LIGHT_TIP },
- { COLOUR_AQUA_DARK, STR_COLOUR_AQUA_DARK_TIP },
- { COLOUR_MAGENTA_LIGHT, STR_COLOUR_MAGENTA_LIGHT_TIP },
- { COLOUR_DULL_BROWN_DARK, STR_COLOUR_DULL_BROWN_DARK_TIP },
- { COLOUR_DULL_BROWN_LIGHT, STR_COLOUR_DULL_BROWN_LIGHT_TIP },
- { COLOUR_INVISIBLE, STR_COLOUR_INVISIBLE_TIP },
- { COLOUR_VOID, STR_COLOUR_VOID_TIP },
-};
-
-/**
- *
- * rct2: 0x006E8DA7
- */
-void InputStateWidgetPressed(
- const ScreenCoordsXY& screenCoords, MouseState state, WidgetIndex widgetIndex, WindowBase* w, Widget* widget)
-{
- WindowClass cursor_w_class;
- rct_windownumber cursor_w_number;
- cursor_w_class = gPressedWidget.window_classification;
- cursor_w_number = gPressedWidget.window_number;
- WidgetIndex cursor_widgetIndex = gPressedWidget.widget_index;
-
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- WindowBase* cursor_w = windowMgr->FindByNumber(cursor_w_class, cursor_w_number);
- if (cursor_w == nullptr)
- {
- _inputState = InputState::Reset;
- return;
- }
-
- if (w != nullptr && state == MouseState::LeftRelease)
- {
- if (w->widgets[widgetIndex].type == WindowWidgetType::CloseBox && cursor_w_class == w->classification
- && cursor_w_number == w->number && widgetIndex == cursor_widgetIndex)
+ WindowBase* w = windowMgr->FindByNumber(gHoverWidget.window_classification, gHoverWidget.window_number);
+ if (w != nullptr)
{
- auto& im = GetInputManager();
- if (im.IsModifierKeyPressed(ModifierKey::shift))
+ w->OnPrepareDraw();
+ if (w->widgets[gHoverWidget.widget_index].type == WindowWidgetType::FlatBtn)
{
- gLastCloseModifier.window.number = w->number;
- gLastCloseModifier.window.classification = w->classification;
- gLastCloseModifier.modifier = CloseWindowModifier::Shift;
- }
- else if (im.IsModifierKeyPressed(ModifierKey::ctrl))
- {
- gLastCloseModifier.window.number = w->number;
- gLastCloseModifier.window.classification = w->classification;
- gLastCloseModifier.modifier = CloseWindowModifier::Control;
+ WidgetInvalidateByNumber(
+ gHoverWidget.window_classification, gHoverWidget.window_number, gHoverWidget.widget_index);
}
}
}
- switch (state)
+ /**
+ *
+ * rct2: 0x006E95F9
+ */
+ static void InputWidgetLeft(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex)
{
- case MouseState::Released:
- if (w == nullptr || cursor_w_class != w->classification || cursor_w_number != w->number
- || widgetIndex != cursor_widgetIndex)
+ WindowClass windowClass = WindowClass::Null;
+ rct_windownumber windowNumber = 0;
+
+ if (w != nullptr)
+ {
+ windowClass = w->classification;
+ windowNumber = w->number;
+ }
+
+ WindowCloseByClass(WindowClass::Error);
+ WindowCloseByClass(WindowClass::Tooltip);
+
+ // Window might have changed position in the list, therefore find it again
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ w = windowMgr->FindByNumber(windowClass, windowNumber);
+ if (w == nullptr)
+ return;
+
+ w = WindowBringToFront(*w);
+ if (widgetIndex == kWidgetIndexNull)
+ return;
+
+ if (windowClass != GetCurrentTextBox().window.classification || windowNumber != GetCurrentTextBox().window.number
+ || widgetIndex != GetCurrentTextBox().widget_index)
+ {
+ WindowCancelTextbox();
+ }
+
+ const auto& widget = w->widgets[widgetIndex];
+
+ switch (widget.type)
+ {
+ case WindowWidgetType::Frame:
+ case WindowWidgetType::Resize:
+ if (WindowCanResize(*w)
+ && (screenCoords.x >= w->windowPos.x + w->width - 19 && screenCoords.y >= w->windowPos.y + w->height - 19))
+ InputWindowResizeBegin(*w, widgetIndex, screenCoords);
break;
-
- if (WidgetIsDisabled(*w, widgetIndex))
- break;
-
- // If this variable is non-zero then its the last tick the mouse down event was fired.
- if (_clickRepeatTicks.has_value())
- {
- // The initial amount of time in ticks to wait until the first click repeat.
- constexpr auto ticksUntilRepeats = 16U;
-
- // The amount of ticks between each click repeat.
- constexpr auto eventDelayInTicks = 3U;
-
- // The amount of ticks since the last click repeat.
- const auto clickRepeatsDelta = gCurrentRealTimeTicks - _clickRepeatTicks.value();
-
- // Handle click repeat, only start this when at least 16 ticks elapsed.
- if (clickRepeatsDelta >= ticksUntilRepeats && (clickRepeatsDelta & eventDelayInTicks) == 0)
+ case WindowWidgetType::Viewport:
+ _inputState = InputState::ViewportLeft;
+ gInputDragLast = screenCoords;
+ _dragWidget.window_classification = windowClass;
+ _dragWidget.window_number = windowNumber;
+ if (_inputFlags & INPUT_FLAG_TOOL_ACTIVE)
{
- if (WidgetIsHoldable(*w, widgetIndex))
+ w = windowMgr->FindByNumber(gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number);
+ if (w != nullptr)
{
- w->OnMouseDown(widgetIndex);
+ InputSetFlag(INPUT_FLAG_4, true);
+ w->OnToolDown(gCurrentToolWidget.widget_index, screenCoords);
}
+ }
+ break;
+ case WindowWidgetType::Caption:
+ InputWindowPositionBegin(*w, widgetIndex, screenCoords);
+ break;
+ case WindowWidgetType::Scroll:
+ InputScrollBegin(*w, widgetIndex, screenCoords);
+ break;
+ case WindowWidgetType::Empty:
+ case WindowWidgetType::LabelCentred:
+ case WindowWidgetType::Label:
+ case WindowWidgetType::Groupbox:
+ case WindowWidgetType::ProgressBar:
+ case WindowWidgetType::Placeholder:
+ // Non-interactive widget type
+ break;
+ case WindowWidgetType::ImgBtn:
+ case WindowWidgetType::ColourBtn:
+ case WindowWidgetType::TrnBtn:
+ case WindowWidgetType::Tab:
+ case WindowWidgetType::FlatBtn:
+ case WindowWidgetType::Button:
+ case WindowWidgetType::TableHeader:
+ case WindowWidgetType::Spinner:
+ case WindowWidgetType::DropdownMenu:
+ case WindowWidgetType::CloseBox:
+ case WindowWidgetType::Checkbox:
+ case WindowWidgetType::TextBox:
+ case WindowWidgetType::Custom:
+ if (!WidgetIsDisabled(*w, widgetIndex))
+ {
+ OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click1, 0, w->windowPos.x + widget.midX());
- // Subtract initial delay from here on we want the event each third tick.
- _clickRepeatTicks = gCurrentRealTimeTicks - ticksUntilRepeats;
+ // Set new cursor down widget
+ gPressedWidget.window_classification = windowClass;
+ gPressedWidget.window_number = windowNumber;
+ gPressedWidget.widget_index = widgetIndex;
+ _inputFlags |= INPUT_FLAG_WIDGET_PRESSED;
+ _inputState = InputState::WidgetPressed;
+ _clickRepeatTicks = gCurrentRealTimeTicks;
+
+ WidgetInvalidateByNumber(windowClass, windowNumber, widgetIndex);
+ w->OnMouseDown(widgetIndex);
+ }
+ break;
+ }
+ }
+
+ /**
+ *
+ * rct2: 0x006ED833
+ */
+ void ProcessMouseOver(const ScreenCoordsXY& screenCoords)
+ {
+ CursorID cursorId = CursorID::Arrow;
+ auto ft = Formatter();
+ ft.Add(STR_NONE);
+ SetMapTooltip(ft);
+
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ WindowBase* window = windowMgr->FindFromPoint(screenCoords);
+
+ if (window != nullptr)
+ {
+ WidgetIndex widgetId = windowMgr->FindWidgetFromPoint(*window, screenCoords);
+ if (widgetId != kWidgetIndexNull)
+ {
+ switch (window->widgets[widgetId].type)
+ {
+ case WindowWidgetType::Viewport:
+ if (!(_inputFlags & INPUT_FLAG_TOOL_ACTIVE))
+ {
+ if (ViewportInteractionLeftOver(screenCoords))
+ {
+ SetCursor(CursorID::HandPoint);
+ return;
+ }
+ break;
+ }
+ cursorId = static_cast(gCurrentToolId);
+ break;
+
+ case WindowWidgetType::Frame:
+ case WindowWidgetType::Resize:
+ if (!(window->flags & WF_RESIZABLE))
+ break;
+
+ if (window->min_width == window->max_width && window->min_height == window->max_height)
+ break;
+
+ if (screenCoords.x < window->windowPos.x + window->width - 0x13)
+ break;
+
+ if (screenCoords.y < window->windowPos.y + window->height - 0x13)
+ break;
+
+ cursorId = CursorID::DiagonalArrows;
+ break;
+
+ case WindowWidgetType::Scroll:
+ {
+ int32_t output_scroll_area, scroll_id;
+ ScreenCoordsXY scrollCoords;
+ WidgetScrollGetPart(
+ *window, &window->widgets[widgetId], screenCoords, scrollCoords, &output_scroll_area, &scroll_id);
+ if (output_scroll_area != SCROLL_PART_VIEW)
+ {
+ cursorId = CursorID::Arrow;
+ break;
+ }
+ // Same as default but with scroll_x/y
+ cursorId = window->OnCursor(widgetId, scrollCoords, CursorID::Arrow);
+ if (cursorId == CursorID::Undefined)
+ cursorId = CursorID::Arrow;
+ break;
+ }
+ default:
+ cursorId = window->OnCursor(widgetId, screenCoords, CursorID::Arrow);
+ if (cursorId == CursorID::Undefined)
+ cursorId = CursorID::Arrow;
+ break;
}
}
+ }
- if (_inputFlags & INPUT_FLAG_WIDGET_PRESSED)
+ ViewportInteractionRightOver(screenCoords);
+ SetCursor(cursorId);
+ }
+
+ /**
+ *
+ * rct2: 0x006ED801
+ */
+ void ProcessMouseTool(const ScreenCoordsXY& screenCoords)
+ {
+ if (_inputFlags & INPUT_FLAG_TOOL_ACTIVE)
+ {
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ WindowBase* w = windowMgr->FindByNumber(gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number);
+
+ if (w == nullptr)
+ ToolCancel();
+ else if (InputGetState() != InputState::ViewportRight)
+ w->OnToolUpdate(gCurrentToolWidget.widget_index, screenCoords);
+ }
+ }
+
+ const std::map kColourToTip = {
+ { COLOUR_BLACK, STR_COLOUR_BLACK_TIP },
+ { COLOUR_GREY, STR_COLOUR_GREY_TIP },
+ { COLOUR_WHITE, STR_COLOUR_WHITE_TIP },
+ { COLOUR_DARK_PURPLE, STR_COLOUR_DARK_PURPLE_TIP },
+ { COLOUR_LIGHT_PURPLE, STR_COLOUR_LIGHT_PURPLE_TIP },
+ { COLOUR_BRIGHT_PURPLE, STR_COLOUR_BRIGHT_PURPLE_TIP },
+ { COLOUR_DARK_BLUE, STR_COLOUR_DARK_BLUE_TIP },
+ { COLOUR_LIGHT_BLUE, STR_COLOUR_LIGHT_BLUE_TIP },
+ { COLOUR_ICY_BLUE, STR_COLOUR_ICY_BLUE_TIP },
+ { COLOUR_TEAL, STR_COLOUR_TEAL_TIP },
+ { COLOUR_AQUAMARINE, STR_COLOUR_AQUAMARINE_TIP },
+ { COLOUR_SATURATED_GREEN, STR_COLOUR_SATURATED_GREEN_TIP },
+ { COLOUR_DARK_GREEN, STR_COLOUR_DARK_GREEN_TIP },
+ { COLOUR_MOSS_GREEN, STR_COLOUR_MOSS_GREEN_TIP },
+ { COLOUR_BRIGHT_GREEN, STR_COLOUR_BRIGHT_GREEN_TIP },
+ { COLOUR_OLIVE_GREEN, STR_COLOUR_OLIVE_GREEN_TIP },
+ { COLOUR_DARK_OLIVE_GREEN, STR_COLOUR_DARK_OLIVE_GREEN_TIP },
+ { COLOUR_BRIGHT_YELLOW, STR_COLOUR_BRIGHT_YELLOW_TIP },
+ { COLOUR_YELLOW, STR_COLOUR_YELLOW_TIP },
+ { COLOUR_DARK_YELLOW, STR_COLOUR_DARK_YELLOW_TIP },
+ { COLOUR_LIGHT_ORANGE, STR_COLOUR_LIGHT_ORANGE_TIP },
+ { COLOUR_DARK_ORANGE, STR_COLOUR_DARK_ORANGE_TIP },
+ { COLOUR_LIGHT_BROWN, STR_COLOUR_LIGHT_BROWN_TIP },
+ { COLOUR_SATURATED_BROWN, STR_COLOUR_SATURATED_BROWN_TIP },
+ { COLOUR_DARK_BROWN, STR_COLOUR_DARK_BROWN_TIP },
+ { COLOUR_SALMON_PINK, STR_COLOUR_SALMON_PINK_TIP },
+ { COLOUR_BORDEAUX_RED, STR_COLOUR_BORDEAUX_RED_TIP },
+ { COLOUR_SATURATED_RED, STR_COLOUR_SATURATED_RED_TIP },
+ { COLOUR_BRIGHT_RED, STR_COLOUR_BRIGHT_RED_TIP },
+ { COLOUR_DARK_PINK, STR_COLOUR_DARK_PINK_TIP },
+ { COLOUR_BRIGHT_PINK, STR_COLOUR_BRIGHT_PINK_TIP },
+ { COLOUR_LIGHT_PINK, STR_COLOUR_LIGHT_PINK_TIP },
+ { COLOUR_DARK_OLIVE_DARK, STR_COLOUR_DARK_OLIVE_DARK_TIP },
+ { COLOUR_DARK_OLIVE_LIGHT, STR_COLOUR_DARK_OLIVE_LIGHT_TIP },
+ { COLOUR_SATURATED_BROWN_LIGHT, STR_COLOUR_SATURATED_BROWN_LIGHT_TIP },
+ { COLOUR_BORDEAUX_RED_DARK, STR_COLOUR_BORDEAUX_RED_DARK_TIP },
+ { COLOUR_BORDEAUX_RED_LIGHT, STR_COLOUR_BORDEAUX_RED_LIGHT_TIP },
+ { COLOUR_GRASS_GREEN_DARK, STR_COLOUR_GRASS_GREEN_DARK_TIP },
+ { COLOUR_GRASS_GREEN_LIGHT, STR_COLOUR_GRASS_GREEN_LIGHT_TIP },
+ { COLOUR_OLIVE_DARK, STR_COLOUR_OLIVE_DARK_TIP },
+ { COLOUR_OLIVE_LIGHT, STR_COLOUR_OLIVE_LIGHT_TIP },
+ { COLOUR_SATURATED_GREEN_LIGHT, STR_COLOUR_SATURATED_GREEN_LIGHT_TIP },
+ { COLOUR_TAN_DARK, STR_COLOUR_TAN_DARK_TIP },
+ { COLOUR_TAN_LIGHT, STR_COLOUR_TAN_LIGHT_TIP },
+ { COLOUR_DULL_PURPLE_LIGHT, STR_COLOUR_DULL_PURPLE_LIGHT_TIP },
+ { COLOUR_DULL_GREEN_DARK, STR_COLOUR_DULL_GREEN_DARK_TIP },
+ { COLOUR_DULL_GREEN_LIGHT, STR_COLOUR_DULL_GREEN_LIGHT_TIP },
+ { COLOUR_SATURATED_PURPLE_DARK, STR_COLOUR_SATURATED_PURPLE_DARK_TIP },
+ { COLOUR_SATURATED_PURPLE_LIGHT, STR_COLOUR_SATURATED_PURPLE_LIGHT_TIP },
+ { COLOUR_ORANGE_LIGHT, STR_COLOUR_ORANGE_LIGHT_TIP },
+ { COLOUR_AQUA_DARK, STR_COLOUR_AQUA_DARK_TIP },
+ { COLOUR_MAGENTA_LIGHT, STR_COLOUR_MAGENTA_LIGHT_TIP },
+ { COLOUR_DULL_BROWN_DARK, STR_COLOUR_DULL_BROWN_DARK_TIP },
+ { COLOUR_DULL_BROWN_LIGHT, STR_COLOUR_DULL_BROWN_LIGHT_TIP },
+ { COLOUR_INVISIBLE, STR_COLOUR_INVISIBLE_TIP },
+ { COLOUR_VOID, STR_COLOUR_VOID_TIP },
+ };
+
+ /**
+ *
+ * rct2: 0x006E8DA7
+ */
+ void InputStateWidgetPressed(
+ const ScreenCoordsXY& screenCoords, MouseState state, WidgetIndex widgetIndex, WindowBase* w, Widget* widget)
+ {
+ WindowClass cursor_w_class;
+ rct_windownumber cursor_w_number;
+ cursor_w_class = gPressedWidget.window_classification;
+ cursor_w_number = gPressedWidget.window_number;
+ WidgetIndex cursor_widgetIndex = gPressedWidget.widget_index;
+
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ WindowBase* cursor_w = windowMgr->FindByNumber(cursor_w_class, cursor_w_number);
+ if (cursor_w == nullptr)
+ {
+ _inputState = InputState::Reset;
+ return;
+ }
+
+ if (w != nullptr && state == MouseState::LeftRelease)
+ {
+ if (w->widgets[widgetIndex].type == WindowWidgetType::CloseBox && cursor_w_class == w->classification
+ && cursor_w_number == w->number && widgetIndex == cursor_widgetIndex)
{
+ auto& im = GetInputManager();
+ if (im.IsModifierKeyPressed(ModifierKey::shift))
+ {
+ gLastCloseModifier.window.number = w->number;
+ gLastCloseModifier.window.classification = w->classification;
+ gLastCloseModifier.modifier = CloseWindowModifier::Shift;
+ }
+ else if (im.IsModifierKeyPressed(ModifierKey::ctrl))
+ {
+ gLastCloseModifier.window.number = w->number;
+ gLastCloseModifier.window.classification = w->classification;
+ gLastCloseModifier.modifier = CloseWindowModifier::Control;
+ }
+ }
+ }
+
+ switch (state)
+ {
+ case MouseState::Released:
+ if (w == nullptr || cursor_w_class != w->classification || cursor_w_number != w->number
+ || widgetIndex != cursor_widgetIndex)
+ break;
+
+ if (WidgetIsDisabled(*w, widgetIndex))
+ break;
+
+ // If this variable is non-zero then its the last tick the mouse down event was fired.
+ if (_clickRepeatTicks.has_value())
+ {
+ // The initial amount of time in ticks to wait until the first click repeat.
+ constexpr auto ticksUntilRepeats = 16U;
+
+ // The amount of ticks between each click repeat.
+ constexpr auto eventDelayInTicks = 3U;
+
+ // The amount of ticks since the last click repeat.
+ const auto clickRepeatsDelta = gCurrentRealTimeTicks - _clickRepeatTicks.value();
+
+ // Handle click repeat, only start this when at least 16 ticks elapsed.
+ if (clickRepeatsDelta >= ticksUntilRepeats && (clickRepeatsDelta & eventDelayInTicks) == 0)
+ {
+ if (WidgetIsHoldable(*w, widgetIndex))
+ {
+ w->OnMouseDown(widgetIndex);
+ }
+
+ // Subtract initial delay from here on we want the event each third tick.
+ _clickRepeatTicks = gCurrentRealTimeTicks - ticksUntilRepeats;
+ }
+ }
+
+ if (_inputFlags & INPUT_FLAG_WIDGET_PRESSED)
+ {
+ if (_inputState == InputState::DropdownActive)
+ {
+ gDropdownHighlightedIndex = gDropdownDefaultIndex;
+ WindowInvalidateByClass(WindowClass::Dropdown);
+ }
+ return;
+ }
+
+ _inputFlags |= INPUT_FLAG_WIDGET_PRESSED;
+ WidgetInvalidateByNumber(cursor_w_class, cursor_w_number, widgetIndex);
+ return;
+ case MouseState::LeftRelease:
+ case MouseState::RightPress:
if (_inputState == InputState::DropdownActive)
{
- gDropdownHighlightedIndex = gDropdownDefaultIndex;
- WindowInvalidateByClass(WindowClass::Dropdown);
- }
- return;
- }
-
- _inputFlags |= INPUT_FLAG_WIDGET_PRESSED;
- WidgetInvalidateByNumber(cursor_w_class, cursor_w_number, widgetIndex);
- return;
- case MouseState::LeftRelease:
- case MouseState::RightPress:
- if (_inputState == InputState::DropdownActive)
- {
- if (w != nullptr)
- {
- auto wClass = w->classification;
- auto wNumber = w->number;
- int32_t dropdown_index = 0;
- bool dropdownCleanup = false;
-
- if (w->classification == WindowClass::Dropdown)
+ if (w != nullptr)
{
- dropdown_index = DropdownIndexFromPoint(screenCoords, w);
- dropdownCleanup = dropdown_index == -1
- || (dropdown_index < Dropdown::ItemsMaxSize && Dropdown::IsDisabled(dropdown_index))
- || gDropdownItems[dropdown_index].IsSeparator();
- w = nullptr; // To be closed right next
- }
- else
- {
- if (cursor_w_class != w->classification || cursor_w_number != w->number
- || widgetIndex != cursor_widgetIndex)
+ auto wClass = w->classification;
+ auto wNumber = w->number;
+ int32_t dropdown_index = 0;
+ bool dropdownCleanup = false;
+
+ if (w->classification == WindowClass::Dropdown)
{
- dropdownCleanup = true;
+ dropdown_index = DropdownIndexFromPoint(screenCoords, w);
+ dropdownCleanup = dropdown_index == -1
+ || (dropdown_index < Dropdown::ItemsMaxSize && Dropdown::IsDisabled(dropdown_index))
+ || gDropdownItems[dropdown_index].IsSeparator();
+ w = nullptr; // To be closed right next
}
else
{
- dropdown_index = -1;
- if (_inputFlags & INPUT_FLAG_DROPDOWN_STAY_OPEN)
+ if (cursor_w_class != w->classification || cursor_w_number != w->number
+ || widgetIndex != cursor_widgetIndex)
{
- if (!(_inputFlags & INPUT_FLAG_DROPDOWN_MOUSE_UP))
+ dropdownCleanup = true;
+ }
+ else
+ {
+ dropdown_index = -1;
+ if (_inputFlags & INPUT_FLAG_DROPDOWN_STAY_OPEN)
{
- _inputFlags |= INPUT_FLAG_DROPDOWN_MOUSE_UP;
- return;
+ if (!(_inputFlags & INPUT_FLAG_DROPDOWN_MOUSE_UP))
+ {
+ _inputFlags |= INPUT_FLAG_DROPDOWN_MOUSE_UP;
+ return;
+ }
}
}
}
- }
- WindowCloseByClass(WindowClass::Dropdown);
+ WindowCloseByClass(WindowClass::Dropdown);
- if (dropdownCleanup)
- {
- // Update w as it will be invalid after closing the dropdown window
- w = windowMgr->FindByNumber(wClass, wNumber);
- }
- else
- {
- cursor_w = windowMgr->FindByNumber(cursor_w_class, cursor_w_number);
- if (_inputFlags & INPUT_FLAG_WIDGET_PRESSED)
+ if (dropdownCleanup)
{
- _inputFlags &= ~INPUT_FLAG_WIDGET_PRESSED;
- WidgetInvalidateByNumber(cursor_w_class, cursor_w_number, cursor_widgetIndex);
+ // Update w as it will be invalid after closing the dropdown window
+ w = windowMgr->FindByNumber(wClass, wNumber);
}
-
- _inputState = InputState::Normal;
- gTooltipCloseTimeout = 0;
- gTooltipWidget.widget_index = cursor_widgetIndex;
- gTooltipWidget.window_classification = cursor_w_class;
- gTooltipWidget.window_number = cursor_w_number;
-
- if (dropdown_index == -1)
+ else
{
- if (!Dropdown::IsDisabled(gDropdownDefaultIndex))
+ cursor_w = windowMgr->FindByNumber(cursor_w_class, cursor_w_number);
+ if (_inputFlags & INPUT_FLAG_WIDGET_PRESSED)
{
- dropdown_index = gDropdownDefaultIndex;
+ _inputFlags &= ~INPUT_FLAG_WIDGET_PRESSED;
+ WidgetInvalidateByNumber(cursor_w_class, cursor_w_number, cursor_widgetIndex);
}
+
+ _inputState = InputState::Normal;
+ gTooltipCloseTimeout = 0;
+ gTooltipWidget.widget_index = cursor_widgetIndex;
+ gTooltipWidget.window_classification = cursor_w_class;
+ gTooltipWidget.window_number = cursor_w_number;
+
+ if (dropdown_index == -1)
+ {
+ if (!Dropdown::IsDisabled(gDropdownDefaultIndex))
+ {
+ dropdown_index = gDropdownDefaultIndex;
+ }
+ }
+ cursor_w->OnDropdown(cursor_widgetIndex, dropdown_index);
}
- cursor_w->OnDropdown(cursor_widgetIndex, dropdown_index);
}
}
+
+ _inputState = InputState::Normal;
+
+ if (state == MouseState::RightPress)
+ {
+ return;
+ }
+
+ gTooltipCloseTimeout = 0;
+ gTooltipWidget.widget_index = cursor_widgetIndex;
+
+ if (w == nullptr)
+ break;
+
+ if (widget == nullptr)
+ break;
+
+ {
+ int32_t mid_point_x = widget->midX() + w->windowPos.x;
+ OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click2, 0, mid_point_x);
+ }
+ if (cursor_w_class != w->classification || cursor_w_number != w->number || widgetIndex != cursor_widgetIndex)
+ break;
+
+ if (WidgetIsDisabled(*w, widgetIndex))
+ break;
+
+ WidgetInvalidateByNumber(cursor_w_class, cursor_w_number, widgetIndex);
+ w->OnMouseUp(widgetIndex);
+ return;
+
+ default:
+ return;
+ }
+
+ _clickRepeatTicks = std::nullopt;
+ if (_inputState != InputState::DropdownActive)
+ {
+ // Hold down widget and drag outside of area??
+ if (_inputFlags & INPUT_FLAG_WIDGET_PRESSED)
+ {
+ _inputFlags &= ~INPUT_FLAG_WIDGET_PRESSED;
+ WidgetInvalidateByNumber(cursor_w_class, cursor_w_number, cursor_widgetIndex);
}
+ return;
+ }
+ else if (gDropdownIsColour)
+ {
+ // This is ordinarily covered in InputWidgetOver but the dropdown with colours is a special case.
+ InputUpdateTooltip(w, widgetIndex, screenCoords);
+ }
- _inputState = InputState::Normal;
+ gDropdownHighlightedIndex = -1;
+ WindowInvalidateByClass(WindowClass::Dropdown);
+ if (w == nullptr)
+ {
+ return;
+ }
- if (state == MouseState::RightPress)
+ if (w->classification == WindowClass::Dropdown)
+ {
+ int32_t dropdown_index = DropdownIndexFromPoint(screenCoords, w);
+ if (dropdown_index == -1)
{
return;
}
- gTooltipCloseTimeout = 0;
- gTooltipWidget.widget_index = cursor_widgetIndex;
-
- if (w == nullptr)
- break;
-
- if (widget == nullptr)
- break;
-
+ if (gDropdownIsColour && gDropdownLastColourHover != dropdown_index)
{
- int32_t mid_point_x = widget->midX() + w->windowPos.x;
- OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click2, 0, mid_point_x);
+ gDropdownLastColourHover = dropdown_index;
+ WindowTooltipClose();
+
+ WindowTooltipShow(
+ OpenRCT2String{ kColourToTip.at(ColourDropDownIndexToColour(dropdown_index)), {} }, screenCoords);
}
- if (cursor_w_class != w->classification || cursor_w_number != w->number || widgetIndex != cursor_widgetIndex)
- break;
- if (WidgetIsDisabled(*w, widgetIndex))
- break;
-
- WidgetInvalidateByNumber(cursor_w_class, cursor_w_number, widgetIndex);
- w->OnMouseUp(widgetIndex);
- return;
-
- default:
- return;
- }
-
- _clickRepeatTicks = std::nullopt;
- if (_inputState != InputState::DropdownActive)
- {
- // Hold down widget and drag outside of area??
- if (_inputFlags & INPUT_FLAG_WIDGET_PRESSED)
- {
- _inputFlags &= ~INPUT_FLAG_WIDGET_PRESSED;
- WidgetInvalidateByNumber(cursor_w_class, cursor_w_number, cursor_widgetIndex);
- }
- return;
- }
- else if (gDropdownIsColour)
- {
- // This is ordinarily covered in InputWidgetOver but the dropdown with colours is a special case.
- InputUpdateTooltip(w, widgetIndex, screenCoords);
- }
-
- gDropdownHighlightedIndex = -1;
- WindowInvalidateByClass(WindowClass::Dropdown);
- if (w == nullptr)
- {
- return;
- }
-
- if (w->classification == WindowClass::Dropdown)
- {
- int32_t dropdown_index = DropdownIndexFromPoint(screenCoords, w);
- if (dropdown_index == -1)
- {
- return;
- }
-
- if (gDropdownIsColour && gDropdownLastColourHover != dropdown_index)
- {
- gDropdownLastColourHover = dropdown_index;
- WindowTooltipClose();
-
- WindowTooltipShow(OpenRCT2String{ kColourToTip.at(ColourDropDownIndexToColour(dropdown_index)), {} }, screenCoords);
- }
-
- if (dropdown_index < Dropdown::ItemsMaxSize && Dropdown::IsDisabled(dropdown_index))
- {
- return;
- }
-
- if (gDropdownItems[dropdown_index].IsSeparator())
- {
- return;
- }
-
- gDropdownHighlightedIndex = dropdown_index;
- WindowInvalidateByClass(WindowClass::Dropdown);
- }
- else
- {
- gDropdownLastColourHover = -1;
- WindowTooltipClose();
- }
-}
-
-static void InputUpdateTooltip(WindowBase* w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
-{
- if (gTooltipWidget.window_classification == WindowClass::Null)
- {
- if (gTooltipCursor == screenCoords)
- {
- if (gCurrentRealTimeTicks >= _tooltipNotShownTimeout && w != nullptr && WidgetIsVisible(*w, widgetIndex))
+ if (dropdown_index < Dropdown::ItemsMaxSize && Dropdown::IsDisabled(dropdown_index))
{
- gTooltipCloseTimeout = gCurrentRealTimeTicks + 8000;
- WindowTooltipOpen(w, widgetIndex, screenCoords);
+ return;
}
+
+ if (gDropdownItems[dropdown_index].IsSeparator())
+ {
+ return;
+ }
+
+ gDropdownHighlightedIndex = dropdown_index;
+ WindowInvalidateByClass(WindowClass::Dropdown);
}
else
{
- ResetTooltipNotShown();
- }
-
- gTooltipCloseTimeout = gCurrentRealTimeTicks + 8000;
- gTooltipCursor = screenCoords;
- }
- else
- {
- gTooltipCursor = screenCoords;
- ResetTooltipNotShown();
-
- if (w == nullptr || gTooltipWidget.window_classification != w->classification
- || gTooltipWidget.window_number != w->number || gTooltipWidget.widget_index != widgetIndex
- || !WidgetIsVisible(*w, widgetIndex))
- {
+ gDropdownLastColourHover = -1;
WindowTooltipClose();
}
+ }
- if (gCurrentRealTimeTicks >= gTooltipCloseTimeout)
+ static void InputUpdateTooltip(WindowBase* w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
+ {
+ if (gTooltipWidget.window_classification == WindowClass::Null)
{
- WindowCloseByClass(WindowClass::Tooltip);
+ if (gTooltipCursor == screenCoords)
+ {
+ if (gCurrentRealTimeTicks >= _tooltipNotShownTimeout && w != nullptr && WidgetIsVisible(*w, widgetIndex))
+ {
+ gTooltipCloseTimeout = gCurrentRealTimeTicks + 8000;
+ WindowTooltipOpen(w, widgetIndex, screenCoords);
+ }
+ }
+ else
+ {
+ ResetTooltipNotShown();
+ }
+
+ gTooltipCloseTimeout = gCurrentRealTimeTicks + 8000;
+ gTooltipCursor = screenCoords;
+ }
+ else
+ {
+ gTooltipCursor = screenCoords;
+ ResetTooltipNotShown();
+
+ if (w == nullptr || gTooltipWidget.window_classification != w->classification
+ || gTooltipWidget.window_number != w->number || gTooltipWidget.widget_index != widgetIndex
+ || !WidgetIsVisible(*w, widgetIndex))
+ {
+ WindowTooltipClose();
+ }
+
+ if (gCurrentRealTimeTicks >= gTooltipCloseTimeout)
+ {
+ WindowCloseByClass(WindowClass::Tooltip);
+ }
}
}
-}
#pragma endregion
-/**
- *
- * rct2: 0x006ED990
- */
-void SetCursor(CursorID cursor_id)
-{
- assert(cursor_id != CursorID::Undefined);
- if (_inputState == InputState::Resizing)
+ /**
+ *
+ * rct2: 0x006ED990
+ */
+ void SetCursor(CursorID cursor_id)
{
- cursor_id = CursorID::DiagonalArrows;
+ assert(cursor_id != CursorID::Undefined);
+ if (_inputState == InputState::Resizing)
+ {
+ cursor_id = CursorID::DiagonalArrows;
+ }
+ ContextSetCurrentCursor(cursor_id);
}
- ContextSetCurrentCursor(cursor_id);
-}
-/**
- *
- * rct2: 0x006E876D
- */
-void InvalidateScroll()
-{
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- WindowBase* w = windowMgr->FindByNumber(gPressedWidget.window_classification, gPressedWidget.window_number);
- if (w != nullptr)
+ /**
+ *
+ * rct2: 0x006E876D
+ */
+ void InvalidateScroll()
{
- // Reset to basic scroll
- w->scrolls[_currentScrollIndex].flags &= 0xFF11;
- WindowInvalidateByNumber(gPressedWidget.window_classification, gPressedWidget.window_number);
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ WindowBase* w = windowMgr->FindByNumber(gPressedWidget.window_classification, gPressedWidget.window_number);
+ if (w != nullptr)
+ {
+ // Reset to basic scroll
+ w->scrolls[_currentScrollIndex].flags &= 0xFF11;
+ WindowInvalidateByNumber(gPressedWidget.window_classification, gPressedWidget.window_number);
+ }
}
-}
-/**
- * rct2: 0x00406C96
- */
-void StoreMouseInput(MouseState state, const ScreenCoordsXY& screenCoords)
-{
- uint32_t writeIndex = _mouseInputQueueWriteIndex;
- uint32_t nextWriteIndex = (writeIndex + 1) % std::size(_mouseInputQueue);
-
- // Check if the queue is full
- if (nextWriteIndex != _mouseInputQueueReadIndex)
+ /**
+ * rct2: 0x00406C96
+ */
+ void StoreMouseInput(MouseState state, const ScreenCoordsXY& screenCoords)
{
- RCTMouseData* item = &_mouseInputQueue[writeIndex];
- item->x = screenCoords.x;
- item->y = screenCoords.y;
- item->state = state;
+ uint32_t writeIndex = _mouseInputQueueWriteIndex;
+ uint32_t nextWriteIndex = (writeIndex + 1) % std::size(_mouseInputQueue);
- _mouseInputQueueWriteIndex = nextWriteIndex;
+ // Check if the queue is full
+ if (nextWriteIndex != _mouseInputQueueReadIndex)
+ {
+ RCTMouseData* item = &_mouseInputQueue[writeIndex];
+ item->x = screenCoords.x;
+ item->y = screenCoords.y;
+ item->state = state;
+
+ _mouseInputQueueWriteIndex = nextWriteIndex;
+ }
}
-}
-void GameHandleEdgeScroll()
-{
- WindowBase* mainWindow;
- int32_t scrollX, scrollY;
-
- mainWindow = WindowGetMain();
- if (mainWindow == nullptr)
- return;
- if ((mainWindow->flags & WF_NO_SCROLLING) || (gScreenFlags & (SCREEN_FLAGS_TRACK_MANAGER | SCREEN_FLAGS_TITLE_DEMO)))
- return;
- if (mainWindow->viewport == nullptr)
- return;
- if (!ContextHasFocus())
- return;
-
- scrollX = 0;
- scrollY = 0;
-
- // Scroll left / right
- const CursorState* cursorState = ContextGetCursorState();
- if (cursorState->position.x == 0)
- scrollX = -1;
- else if (cursorState->position.x >= ContextGetWidth() - 1)
- scrollX = 1;
-
- // Scroll up / down
- if (cursorState->position.y == 0)
- scrollY = -1;
- else if (cursorState->position.y >= ContextGetHeight() - 1)
- scrollY = 1;
-
- InputScrollViewport(ScreenCoordsXY(scrollX, scrollY));
-}
-
-void InputScrollViewport(const ScreenCoordsXY& scrollScreenCoords)
-{
- WindowBase* mainWindow = WindowGetMain();
- if (mainWindow == nullptr)
- return;
-
- Viewport* viewport = mainWindow->viewport;
- if (viewport == nullptr)
- return;
-
- const int32_t speed = Config::Get().general.EdgeScrollingSpeed;
-
- int32_t multiplier = viewport->zoom.ApplyTo(speed);
- int32_t dx = scrollScreenCoords.x * multiplier;
- int32_t dy = scrollScreenCoords.y * multiplier;
-
- if (scrollScreenCoords.x != 0)
+ void GameHandleEdgeScroll()
{
- // Speed up scrolling horizontally when at the edge of the map
- // so that the speed is consistent with vertical edge scrolling.
- int32_t x = mainWindow->savedViewPos.x + viewport->ViewWidth() / 2 + dx;
- int32_t y = mainWindow->savedViewPos.y + viewport->ViewHeight() / 2;
- int32_t y_dy = mainWindow->savedViewPos.y + viewport->ViewHeight() / 2 + dy;
+ WindowBase* mainWindow;
+ int32_t scrollX, scrollY;
- auto mapCoord = ViewportPosToMapPos({ x, y }, 0, viewport->rotation);
- auto mapCoord_dy = ViewportPosToMapPos({ x, y_dy }, 0, viewport->rotation);
+ mainWindow = WindowGetMain();
+ if (mainWindow == nullptr)
+ return;
+ if ((mainWindow->flags & WF_NO_SCROLLING) || (gScreenFlags & (SCREEN_FLAGS_TRACK_MANAGER | SCREEN_FLAGS_TITLE_DEMO)))
+ return;
+ if (mainWindow->viewport == nullptr)
+ return;
+ if (!ContextHasFocus())
+ return;
- // Check if we're crossing the boundary
- // Clamp to the map minimum value
- int32_t at_map_edge = 0;
- int32_t at_map_edge_dy = 0;
- if (mapCoord.x < kMapMinimumXY || mapCoord.y < kMapMinimumXY)
- {
- at_map_edge = 1;
- }
- if (mapCoord_dy.x < kMapMinimumXY || mapCoord_dy.y < kMapMinimumXY)
- {
- at_map_edge_dy = 1;
- }
+ scrollX = 0;
+ scrollY = 0;
- // Clamp to the map maximum value (scenario specific)
- auto mapSizeMinus2 = GetMapSizeMinus2();
- if (mapCoord.x > mapSizeMinus2.x || mapCoord.y > mapSizeMinus2.y)
- {
- at_map_edge = 1;
- }
- if (mapCoord_dy.x > mapSizeMinus2.x || mapCoord_dy.y > mapSizeMinus2.y)
- {
- at_map_edge_dy = 1;
- }
+ // Scroll left / right
+ const CursorState* cursorState = ContextGetCursorState();
+ if (cursorState->position.x == 0)
+ scrollX = -1;
+ else if (cursorState->position.x >= ContextGetWidth() - 1)
+ scrollX = 1;
- // If we crossed the boundary, multiply the distance by 2
- if (at_map_edge && at_map_edge_dy)
- {
- dx *= 2;
- }
+ // Scroll up / down
+ if (cursorState->position.y == 0)
+ scrollY = -1;
+ else if (cursorState->position.y >= ContextGetHeight() - 1)
+ scrollY = 1;
- mainWindow->savedViewPos.x += dx;
- _inputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING;
+ InputScrollViewport(ScreenCoordsXY(scrollX, scrollY));
}
- if (scrollScreenCoords.y != 0)
+
+ void InputScrollViewport(const ScreenCoordsXY& scrollScreenCoords)
{
- mainWindow->savedViewPos.y += dy;
- _inputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING;
+ WindowBase* mainWindow = WindowGetMain();
+ if (mainWindow == nullptr)
+ return;
+
+ Viewport* viewport = mainWindow->viewport;
+ if (viewport == nullptr)
+ return;
+
+ const int32_t speed = Config::Get().general.EdgeScrollingSpeed;
+
+ int32_t multiplier = viewport->zoom.ApplyTo(speed);
+ int32_t dx = scrollScreenCoords.x * multiplier;
+ int32_t dy = scrollScreenCoords.y * multiplier;
+
+ if (scrollScreenCoords.x != 0)
+ {
+ // Speed up scrolling horizontally when at the edge of the map
+ // so that the speed is consistent with vertical edge scrolling.
+ int32_t x = mainWindow->savedViewPos.x + viewport->ViewWidth() / 2 + dx;
+ int32_t y = mainWindow->savedViewPos.y + viewport->ViewHeight() / 2;
+ int32_t y_dy = mainWindow->savedViewPos.y + viewport->ViewHeight() / 2 + dy;
+
+ auto mapCoord = ViewportPosToMapPos({ x, y }, 0, viewport->rotation);
+ auto mapCoord_dy = ViewportPosToMapPos({ x, y_dy }, 0, viewport->rotation);
+
+ // Check if we're crossing the boundary
+ // Clamp to the map minimum value
+ int32_t at_map_edge = 0;
+ int32_t at_map_edge_dy = 0;
+ if (mapCoord.x < kMapMinimumXY || mapCoord.y < kMapMinimumXY)
+ {
+ at_map_edge = 1;
+ }
+ if (mapCoord_dy.x < kMapMinimumXY || mapCoord_dy.y < kMapMinimumXY)
+ {
+ at_map_edge_dy = 1;
+ }
+
+ // Clamp to the map maximum value (scenario specific)
+ auto mapSizeMinus2 = GetMapSizeMinus2();
+ if (mapCoord.x > mapSizeMinus2.x || mapCoord.y > mapSizeMinus2.y)
+ {
+ at_map_edge = 1;
+ }
+ if (mapCoord_dy.x > mapSizeMinus2.x || mapCoord_dy.y > mapSizeMinus2.y)
+ {
+ at_map_edge_dy = 1;
+ }
+
+ // If we crossed the boundary, multiply the distance by 2
+ if (at_map_edge && at_map_edge_dy)
+ {
+ dx *= 2;
+ }
+
+ mainWindow->savedViewPos.x += dx;
+ _inputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING;
+ }
+ if (scrollScreenCoords.y != 0)
+ {
+ mainWindow->savedViewPos.y += dy;
+ _inputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING;
+ }
}
-}
+} // namespace OpenRCT2
diff --git a/src/openrct2-ui/input/MouseInput.h b/src/openrct2-ui/input/MouseInput.h
index 14bfda2f66..4fe8a5e99b 100644
--- a/src/openrct2-ui/input/MouseInput.h
+++ b/src/openrct2-ui/input/MouseInput.h
@@ -11,21 +11,24 @@
#include
-enum class MouseState : uint32_t
+namespace OpenRCT2
{
- Released,
- LeftPress,
- LeftRelease,
- RightPress,
- RightRelease
-};
+ enum class MouseState : uint32_t
+ {
+ Released,
+ LeftPress,
+ LeftRelease,
+ RightPress,
+ RightRelease
+ };
-extern ScreenCoordsXY gInputDragLast;
+ extern ScreenCoordsXY gInputDragLast;
-void InputWindowPositionBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords);
-void GameHandleInput();
-void GameHandleEdgeScroll();
+ void InputWindowPositionBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords);
+ void GameHandleInput();
+ void GameHandleEdgeScroll();
-void StoreMouseInput(MouseState state, const ScreenCoordsXY& screenCoords);
+ void StoreMouseInput(MouseState state, const ScreenCoordsXY& screenCoords);
-void InputScrollViewport(const ScreenCoordsXY& screenCoords);
+ void InputScrollViewport(const ScreenCoordsXY& screenCoords);
+} // namespace OpenRCT2
diff --git a/src/openrct2-ui/interface/LandTool.h b/src/openrct2-ui/interface/LandTool.h
index 936667197b..e7cac0c701 100644
--- a/src/openrct2-ui/interface/LandTool.h
+++ b/src/openrct2-ui/interface/LandTool.h
@@ -10,6 +10,7 @@
#pragma once
#include
+#include
constexpr uint16_t kLandToolMinimumSize = 1;
constexpr uint16_t kLandToolMaximumSize = 64;
diff --git a/src/openrct2-ui/interface/Widget.cpp b/src/openrct2-ui/interface/Widget.cpp
index 240b482fd6..50ef0d8234 100644
--- a/src/openrct2-ui/interface/Widget.cpp
+++ b/src/openrct2-ui/interface/Widget.cpp
@@ -9,6 +9,7 @@
#include "Widget.h"
+#include
#include
#include
#include
@@ -939,9 +940,11 @@ namespace OpenRCT2::Ui
int32_t* output_scroll_area, int32_t* scroll_id)
{
*scroll_id = 0;
- for (Widget* iterator = w.widgets; iterator != widget; iterator++)
+ auto itLast = std::find_if(
+ w.widgets.begin(), w.widgets.end(), [&](auto& otherWidget) { return &otherWidget == widget; });
+ for (auto it = w.widgets.begin(); it != itLast; it++)
{
- if (iterator->type == WindowWidgetType::Scroll)
+ if (it->type == WindowWidgetType::Scroll)
{
*scroll_id += 1;
}
@@ -1044,20 +1047,13 @@ namespace OpenRCT2::Ui
Widget* GetWidgetByIndex(const WindowBase& w, WidgetIndex widgetIndex)
{
- // Make sure we don't go out of bounds if we are given a bad widget index
- WidgetIndex index = 0;
- for (auto* widget = w.widgets; widget->type != WindowWidgetType::Last; widget++)
+ if (widgetIndex >= w.widgets.size())
{
- if (index == widgetIndex)
- {
- return widget;
- }
- index++;
+ LOG_ERROR("Widget index %i out of bounds for window class %u", widgetIndex, w.classification);
}
- LOG_ERROR("Widget index %i out of bounds for window class %u", widgetIndex, w.classification);
-
- return nullptr;
+ // FIXME: This const_cast is bad.
+ return const_cast(w.widgets.data() + widgetIndex);
}
static void SafeSetWidgetFlag(WindowBase& w, WidgetIndex widgetIndex, WidgetFlags mask, bool value)
diff --git a/src/openrct2-ui/interface/Widget.h b/src/openrct2-ui/interface/Widget.h
index 8a085ffae5..1442f79f1f 100644
--- a/src/openrct2-ui/interface/Widget.h
+++ b/src/openrct2-ui/interface/Widget.h
@@ -30,7 +30,6 @@ namespace OpenRCT2::Ui
ImageId GetColourButtonImage(colour_t colour);
Widget* GetWidgetByIndex(const WindowBase& w, WidgetIndex widgetIndex);
- constexpr auto kWidgetsEnd = Widget{ WindowWidgetType::Last, 0, 0, 0, 0, 0, 0, 0 };
constexpr uint32_t kWidgetContentEmpty = 0xFFFFFFFF;
constexpr auto kBarBlink = (1u << 31);
constexpr uint8_t kScrollBarWidth = 10;
diff --git a/src/openrct2-ui/interface/Window.cpp b/src/openrct2-ui/interface/Window.cpp
index 51a81ae9f6..c22f6ecb4e 100644
--- a/src/openrct2-ui/interface/Window.cpp
+++ b/src/openrct2-ui/interface/Window.cpp
@@ -32,697 +32,699 @@
#include
#include
-using namespace OpenRCT2;
-using namespace OpenRCT2::Ui;
-
-// The amount of pixels to scroll per wheel click
-constexpr int32_t WindowScrollPixels = 17;
-
-static int32_t _previousAbsoluteWheel = 0;
-
-static bool WindowFitsBetweenOthers(const ScreenCoordsXY& loc, int32_t width, int32_t height)
+namespace OpenRCT2
{
- for (auto& w : g_window_list)
+ using namespace OpenRCT2::Ui;
+
+ // The amount of pixels to scroll per wheel click
+ constexpr int32_t WindowScrollPixels = 17;
+
+ static int32_t _previousAbsoluteWheel = 0;
+
+ static bool WindowFitsBetweenOthers(const ScreenCoordsXY& loc, int32_t width, int32_t height)
{
- if (w->flags & WF_DEAD)
- continue;
- if (w->flags & WF_STICK_TO_BACK)
- continue;
-
- if (loc.x + width <= w->windowPos.x)
- continue;
- if (loc.x >= w->windowPos.x + w->width)
- continue;
- if (loc.y + height <= w->windowPos.y)
- continue;
- if (loc.y >= w->windowPos.y + w->height)
- continue;
- return false;
- }
-
- return true;
-}
-
-static bool WindowFitsWithinSpace(const ScreenCoordsXY& loc, int32_t width, int32_t height)
-{
- if (loc.x < 0)
- return false;
- if (loc.y <= kTopToolbarHeight && !(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO))
- return false;
- if (loc.x + width > ContextGetWidth())
- return false;
- if (loc.y + height > ContextGetHeight())
- return false;
- return WindowFitsBetweenOthers(loc, width, height);
-}
-
-static bool WindowFitsOnScreen(const ScreenCoordsXY& loc, int32_t width, int32_t height)
-{
- uint16_t screenWidth = ContextGetWidth();
- uint16_t screenHeight = ContextGetHeight();
- int32_t unk;
-
- unk = -(width / 4);
- if (loc.x < unk)
- return false;
- unk = screenWidth + (unk * 2);
- if (loc.x > unk)
- return false;
- if (loc.y <= kTopToolbarHeight && !(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO))
- return false;
- unk = screenHeight - (height / 4);
- if (loc.y > unk)
- return false;
- return WindowFitsBetweenOthers(loc, width, height);
-}
-
-static ScreenCoordsXY ClampWindowToScreen(
- const ScreenCoordsXY& pos, const int32_t screenWidth, const int32_t screenHeight, const int32_t width, const int32_t height)
-{
- auto screenPos = pos;
- if (width > screenWidth || screenPos.x < 0)
- screenPos.x = 0;
- else if (screenPos.x + width > screenWidth)
- screenPos.x = screenWidth - width;
-
- auto toolbarAllowance = (gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) ? 0 : (kTopToolbarHeight + 1);
- if (height - toolbarAllowance > screenHeight || screenPos.y < toolbarAllowance)
- screenPos.y = toolbarAllowance;
- else if (screenPos.y + height - toolbarAllowance > screenHeight)
- screenPos.y = screenHeight + toolbarAllowance - height;
-
- return screenPos;
-}
-
-static ScreenCoordsXY GetAutoPositionForNewWindow(int32_t width, int32_t height)
-{
- auto uiContext = GetContext()->GetUiContext();
- auto screenWidth = uiContext->GetWidth();
- auto screenHeight = uiContext->GetHeight();
-
- // Place window in an empty corner of the screen
- const ScreenCoordsXY cornerPositions[] = {
- { 0, 30 }, // topLeft
- { screenWidth - width, 30 }, // topRight
- { 0, screenHeight - 34 - height }, // bottomLeft
- { screenWidth - width, screenHeight - 34 - height }, // bottomRight
- };
-
- for (const auto& cornerPos : cornerPositions)
- {
- if (WindowFitsWithinSpace(cornerPos, width, height))
+ for (auto& w : g_window_list)
{
- return ClampWindowToScreen(cornerPos, screenWidth, screenHeight, width, height);
+ if (w->flags & WF_DEAD)
+ continue;
+ if (w->flags & WF_STICK_TO_BACK)
+ continue;
+
+ if (loc.x + width <= w->windowPos.x)
+ continue;
+ if (loc.x >= w->windowPos.x + w->width)
+ continue;
+ if (loc.y + height <= w->windowPos.y)
+ continue;
+ if (loc.y >= w->windowPos.y + w->height)
+ continue;
+ return false;
}
+
+ return true;
}
- // Place window next to another
- for (auto& w : g_window_list)
+ static bool WindowFitsWithinSpace(const ScreenCoordsXY& loc, int32_t width, int32_t height)
{
- if (w->flags & WF_DEAD)
- continue;
- if (w->flags & WF_STICK_TO_BACK)
- continue;
+ if (loc.x < 0)
+ return false;
+ if (loc.y <= kTopToolbarHeight && !(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO))
+ return false;
+ if (loc.x + width > ContextGetWidth())
+ return false;
+ if (loc.y + height > ContextGetHeight())
+ return false;
+ return WindowFitsBetweenOthers(loc, width, height);
+ }
- const ScreenCoordsXY offsets[] = {
- { w->width + 2, 0 },
- { -w->width - 2, 0 },
- { 0, w->height + 2 },
- { 0, -w->height - 2 },
- { w->width + 2, -w->height - 2 },
- { -w->width - 2, -w->height - 2 },
- { w->width + 2, w->height + 2 },
- { -w->width - 2, w->height + 2 },
+ static bool WindowFitsOnScreen(const ScreenCoordsXY& loc, int32_t width, int32_t height)
+ {
+ uint16_t screenWidth = ContextGetWidth();
+ uint16_t screenHeight = ContextGetHeight();
+ int32_t unk;
+
+ unk = -(width / 4);
+ if (loc.x < unk)
+ return false;
+ unk = screenWidth + (unk * 2);
+ if (loc.x > unk)
+ return false;
+ if (loc.y <= kTopToolbarHeight && !(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO))
+ return false;
+ unk = screenHeight - (height / 4);
+ if (loc.y > unk)
+ return false;
+ return WindowFitsBetweenOthers(loc, width, height);
+ }
+
+ static ScreenCoordsXY ClampWindowToScreen(
+ const ScreenCoordsXY& pos, const int32_t screenWidth, const int32_t screenHeight, const int32_t width,
+ const int32_t height)
+ {
+ auto screenPos = pos;
+ if (width > screenWidth || screenPos.x < 0)
+ screenPos.x = 0;
+ else if (screenPos.x + width > screenWidth)
+ screenPos.x = screenWidth - width;
+
+ auto toolbarAllowance = (gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) ? 0 : (kTopToolbarHeight + 1);
+ if (height - toolbarAllowance > screenHeight || screenPos.y < toolbarAllowance)
+ screenPos.y = toolbarAllowance;
+ else if (screenPos.y + height - toolbarAllowance > screenHeight)
+ screenPos.y = screenHeight + toolbarAllowance - height;
+
+ return screenPos;
+ }
+
+ static ScreenCoordsXY GetAutoPositionForNewWindow(int32_t width, int32_t height)
+ {
+ auto uiContext = GetContext()->GetUiContext();
+ auto screenWidth = uiContext->GetWidth();
+ auto screenHeight = uiContext->GetHeight();
+
+ // Place window in an empty corner of the screen
+ const ScreenCoordsXY cornerPositions[] = {
+ { 0, 30 }, // topLeft
+ { screenWidth - width, 30 }, // topRight
+ { 0, screenHeight - 34 - height }, // bottomLeft
+ { screenWidth - width, screenHeight - 34 - height }, // bottomRight
};
- for (const auto& offset : offsets)
+ for (const auto& cornerPos : cornerPositions)
{
- auto screenPos = w->windowPos + offset;
- if (WindowFitsWithinSpace(screenPos, width, height))
+ if (WindowFitsWithinSpace(cornerPos, width, height))
{
- return ClampWindowToScreen(screenPos, screenWidth, screenHeight, width, height);
+ return ClampWindowToScreen(cornerPos, screenWidth, screenHeight, width, height);
}
}
- }
- // Overlap
- for (auto& w : g_window_list)
- {
- if (w->flags & WF_DEAD)
- continue;
- if (w->flags & WF_STICK_TO_BACK)
- continue;
-
- const ScreenCoordsXY offsets[] = {
- { w->width + 2, 0 },
- { -w->width - 2, 0 },
- { 0, w->height + 2 },
- { 0, -w->height - 2 },
- };
-
- for (const auto& offset : offsets)
+ // Place window next to another
+ for (auto& w : g_window_list)
{
- auto screenPos = w->windowPos + offset;
- if (WindowFitsOnScreen(screenPos, width, height))
+ if (w->flags & WF_DEAD)
+ continue;
+ if (w->flags & WF_STICK_TO_BACK)
+ continue;
+
+ const ScreenCoordsXY offsets[] = {
+ { w->width + 2, 0 },
+ { -w->width - 2, 0 },
+ { 0, w->height + 2 },
+ { 0, -w->height - 2 },
+ { w->width + 2, -w->height - 2 },
+ { -w->width - 2, -w->height - 2 },
+ { w->width + 2, w->height + 2 },
+ { -w->width - 2, w->height + 2 },
+ };
+
+ for (const auto& offset : offsets)
{
- return ClampWindowToScreen(screenPos, screenWidth, screenHeight, width, height);
+ auto screenPos = w->windowPos + offset;
+ if (WindowFitsWithinSpace(screenPos, width, height))
+ {
+ return ClampWindowToScreen(screenPos, screenWidth, screenHeight, width, height);
+ }
}
}
- }
- // Cascade
- auto screenPos = ScreenCoordsXY{ 0, 30 };
- for (auto& w : g_window_list)
- {
- if (screenPos == w->windowPos)
+ // Overlap
+ for (auto& w : g_window_list)
{
- screenPos.x += 5;
- screenPos.y += 5;
+ if (w->flags & WF_DEAD)
+ continue;
+ if (w->flags & WF_STICK_TO_BACK)
+ continue;
+
+ const ScreenCoordsXY offsets[] = {
+ { w->width + 2, 0 },
+ { -w->width - 2, 0 },
+ { 0, w->height + 2 },
+ { 0, -w->height - 2 },
+ };
+
+ for (const auto& offset : offsets)
+ {
+ auto screenPos = w->windowPos + offset;
+ if (WindowFitsOnScreen(screenPos, width, height))
+ {
+ return ClampWindowToScreen(screenPos, screenWidth, screenHeight, width, height);
+ }
+ }
}
+
+ // Cascade
+ auto screenPos = ScreenCoordsXY{ 0, 30 };
+ for (auto& w : g_window_list)
+ {
+ if (screenPos == w->windowPos)
+ {
+ screenPos.x += 5;
+ screenPos.y += 5;
+ }
+ }
+
+ return ClampWindowToScreen(screenPos, screenWidth, screenHeight, width, height);
}
- return ClampWindowToScreen(screenPos, screenWidth, screenHeight, width, height);
-}
-
-static ScreenCoordsXY GetCentrePositionForNewWindow(int32_t width, int32_t height)
-{
- auto uiContext = GetContext()->GetUiContext();
- auto screenWidth = uiContext->GetWidth();
- auto screenHeight = uiContext->GetHeight();
- return ScreenCoordsXY{ (screenWidth - width) / 2, std::max(kTopToolbarHeight + 1, (screenHeight - height) / 2) };
-}
-
-static int32_t WindowGetWidgetIndex(const WindowBase& w, Widget* widget)
-{
- int32_t i = 0;
- for (Widget* widget2 = w.widgets; widget2->type != WindowWidgetType::Last; widget2++, i++)
- if (widget == widget2)
- return i;
- return -1;
-}
-
-static int32_t WindowGetScrollIndex(const WindowBase& w, int32_t targetWidgetIndex)
-{
- if (w.widgets[targetWidgetIndex].type != WindowWidgetType::Scroll)
- return -1;
-
- int32_t scrollIndex = 0;
- WidgetIndex widgetIndex = 0;
- for (Widget* widget = w.widgets; widget->type != WindowWidgetType::Last; widget++, widgetIndex++)
+ static ScreenCoordsXY GetCentrePositionForNewWindow(int32_t width, int32_t height)
{
- if (widgetIndex == targetWidgetIndex)
- break;
- if (widget->type == WindowWidgetType::Scroll)
- scrollIndex++;
+ auto uiContext = GetContext()->GetUiContext();
+ auto screenWidth = uiContext->GetWidth();
+ auto screenHeight = uiContext->GetHeight();
+ return ScreenCoordsXY{ (screenWidth - width) / 2, std::max(kTopToolbarHeight + 1, (screenHeight - height) / 2) };
}
- return scrollIndex;
-}
-
-static Widget* WindowGetScrollWidget(const WindowBase& w, int32_t scrollIndex)
-{
- for (Widget* widget = w.widgets; widget->type != WindowWidgetType::Last; widget++)
+ static int32_t WindowGetWidgetIndex(const WindowBase& w, Widget* widget)
{
- if (widget->type != WindowWidgetType::Scroll)
- continue;
-
- if (scrollIndex == 0)
- return widget;
- scrollIndex--;
+ const auto it = std::find_if(
+ w.widgets.begin(), w.widgets.end(), [&](auto& otherWidget) { return &otherWidget == widget; });
+ if (it == w.widgets.end())
+ return -1;
+ return std::distance(w.widgets.begin(), it);
}
- return nullptr;
-}
-
-/**
- *
- * rct2: 0x006E78E3
- */
-static void WindowScrollWheelInput(WindowBase& w, int32_t scrollIndex, int32_t wheel)
-{
- auto& scroll = w.scrolls[scrollIndex];
- Widget* widget = WindowGetScrollWidget(w, scrollIndex);
- WidgetIndex widgetIndex = WindowGetWidgetIndex(w, widget);
-
- if (scroll.flags & VSCROLLBAR_VISIBLE)
+ static int32_t WindowGetScrollIndex(const WindowBase& w, int32_t targetWidgetIndex)
{
- int32_t size = widget->height() - 1;
- if (scroll.flags & HSCROLLBAR_VISIBLE)
- size -= 11;
- size = std::max(0, scroll.contentHeight - size);
- scroll.contentOffsetY = std::min(std::max(0, scroll.contentOffsetY + wheel), size);
+ if (w.widgets[targetWidgetIndex].type != WindowWidgetType::Scroll)
+ return -1;
+
+ int32_t scrollIndex = 0;
+ for (WidgetIndex widgetIndex = 0; widgetIndex < w.widgets.size(); widgetIndex++)
+ {
+ if (widgetIndex == targetWidgetIndex)
+ break;
+ auto& widget = w.widgets[widgetIndex];
+ if (widget.type == WindowWidgetType::Scroll)
+ scrollIndex++;
+ }
+
+ return scrollIndex;
}
- else
+
+ static Widget* WindowGetScrollWidget(const WindowBase& w, int32_t scrollIndex)
{
- int32_t size = widget->width() - 1;
+ for (WidgetIndex widgetIndex = 0; widgetIndex < w.widgets.size(); widgetIndex++)
+ {
+ auto& widget = w.widgets[widgetIndex];
+ if (widget.type != WindowWidgetType::Scroll)
+ continue;
+
+ if (scrollIndex == 0)
+ return const_cast(&widget);
+ scrollIndex--;
+ }
+
+ return nullptr;
+ }
+
+ /**
+ *
+ * rct2: 0x006E78E3
+ */
+ static void WindowScrollWheelInput(WindowBase& w, int32_t scrollIndex, int32_t wheel)
+ {
+ auto& scroll = w.scrolls[scrollIndex];
+ Widget* widget = WindowGetScrollWidget(w, scrollIndex);
+ WidgetIndex widgetIndex = WindowGetWidgetIndex(w, widget);
+
if (scroll.flags & VSCROLLBAR_VISIBLE)
- size -= 11;
- size = std::max(0, scroll.contentWidth - size);
- scroll.contentOffsetX = std::min(std::max(0, scroll.contentOffsetX + wheel), size);
- }
-
- WidgetScrollUpdateThumbs(w, widgetIndex);
- WidgetInvalidate(w, widgetIndex);
-}
-
-/**
- *
- * rct2: 0x006E793B
- */
-static int32_t WindowWheelInput(WindowBase& w, int32_t wheel)
-{
- int32_t i = 0;
- for (Widget* widget = w.widgets; widget->type != WindowWidgetType::Last; widget++)
- {
- if (widget->type != WindowWidgetType::Scroll)
- continue;
-
- // Originally always checked first scroll view, bug maybe?
- const auto& scroll = w.scrolls[i];
- if (scroll.flags & (HSCROLLBAR_VISIBLE | VSCROLLBAR_VISIBLE))
{
- WindowScrollWheelInput(w, i, wheel);
- return 1;
- }
- i++;
- }
-
- return 0;
-}
-
-/**
- *
- * rct2: 0x006E79FB
- */
-static void WindowViewportWheelInput(WindowBase& w, int32_t wheel)
-{
- if (gScreenFlags & (SCREEN_FLAGS_TRACK_MANAGER | SCREEN_FLAGS_TITLE_DEMO))
- return;
-
- if (wheel < 0)
- Windows::WindowZoomIn(w, true);
- else if (wheel > 0)
- Windows::WindowZoomOut(w, true);
-}
-
-static bool isSpinnerGroup(WindowBase& w, WidgetIndex index, WindowWidgetType buttonType)
-{
- const auto& widgets = w.widgets;
-
- if (widgets[index].type != WindowWidgetType::Spinner && widgets[index].type != WindowWidgetType::ImgBtn)
- return false;
-
- if (widgets[index + 1].type != buttonType)
- return false;
-
- if (widgets[index + 2].type != buttonType)
- return false;
-
- return true;
-}
-
-static std::optional getSpinnerGroupWidgetIndex(WindowBase& w, WidgetIndex startIndex)
-{
- // We only iterate 3 times as we might be at the spinner or one of its buttons.
- for (WidgetIndex index = 0; index < 3; index++)
- {
- const auto reverseIndex = startIndex - index;
- if (reverseIndex < 0)
- {
- break;
- }
-
- if (isSpinnerGroup(w, reverseIndex, WindowWidgetType::TrnBtn))
- {
- return reverseIndex;
- }
-
- if (isSpinnerGroup(w, reverseIndex, WindowWidgetType::Button))
- {
- return reverseIndex;
- }
- }
-
- return std::nullopt;
-}
-
-// Allow mouse wheel scrolling to manipulate spinner widgets and tool sizes
-static bool WindowOtherWheelInput(WindowBase& w, WidgetIndex widgetIndex, int32_t wheel)
-{
- // HACK: Until we have a new window system that allows us to add new events like mouse wheel easily,
- // this selective approach will have to do.
-
- const auto spinnerGroupIndex = getSpinnerGroupWidgetIndex(w, widgetIndex);
- if (!spinnerGroupIndex.has_value())
- {
- return false;
- }
-
- const auto entryWidgetType = w.widgets[*spinnerGroupIndex].type;
- auto targetWidgetIndex = *spinnerGroupIndex;
-
- if (entryWidgetType == WindowWidgetType::ImgBtn)
- {
- auto expectedContent1 = ImageId(SPR_LAND_TOOL_DECREASE, FilterPaletteID::PaletteNull);
- auto expectedContent2 = ImageId(SPR_LAND_TOOL_INCREASE, FilterPaletteID::PaletteNull);
-
- auto button1Image = w.widgets[*spinnerGroupIndex + 1].image;
- auto button2Image = w.widgets[*spinnerGroupIndex + 2].image;
- if (button1Image != expectedContent1 || button2Image != expectedContent2)
- {
- return false;
- }
-
- // Expected widget order: decrease, increase
- targetWidgetIndex += wheel < 0 ? 2 : 1;
- }
- else if (entryWidgetType == WindowWidgetType::Spinner)
- {
- auto button1StringId = w.widgets[*spinnerGroupIndex + 1].text;
- auto button2StringId = w.widgets[*spinnerGroupIndex + 2].text;
- if (button1StringId != STR_NUMERIC_UP || button2StringId != STR_NUMERIC_DOWN)
- {
- return false;
- }
-
- // Expected widget order: increase, decrease
- targetWidgetIndex += wheel < 0 ? 1 : 2;
- }
-
- if (WidgetIsDisabled(w, targetWidgetIndex))
- {
- return false;
- }
-
- w.OnMouseDown(targetWidgetIndex);
- return true;
-}
-
-/**
- *
- * rct2: 0x006E7868
- */
-void WindowAllWheelInput()
-{
- // Get wheel value
- auto cursorState = ContextGetCursorState();
- int32_t absolute_wheel = cursorState->wheel;
- int32_t relative_wheel = absolute_wheel - _previousAbsoluteWheel;
- int32_t pixel_scroll = relative_wheel * WindowScrollPixels;
- _previousAbsoluteWheel = absolute_wheel;
-
- if (relative_wheel == 0)
- return;
-
- // Check window cursor is over
- if (!(InputTestFlag(INPUT_FLAG_5)))
- {
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- WindowBase* w = windowMgr->FindFromPoint(cursorState->position);
- if (w != nullptr)
- {
- // Check if main window
- if (w->classification == WindowClass::MainWindow || w->classification == WindowClass::Viewport)
- {
- WindowViewportWheelInput(*w, relative_wheel);
- return;
- }
-
- // Check scroll view, cursor is over
- WidgetIndex widgetIndex = windowMgr->FindWidgetFromPoint(*w, cursorState->position);
- if (widgetIndex != -1)
- {
- const auto& widget = w->widgets[widgetIndex];
- if (widget.type == WindowWidgetType::Scroll)
- {
- int32_t scrollIndex = WindowGetScrollIndex(*w, widgetIndex);
- const auto& scroll = w->scrolls[scrollIndex];
- if (scroll.flags & (HSCROLLBAR_VISIBLE | VSCROLLBAR_VISIBLE))
- {
- WindowScrollWheelInput(*w, WindowGetScrollIndex(*w, widgetIndex), pixel_scroll);
- return;
- }
- }
- else
- {
- if (WindowOtherWheelInput(*w, widgetIndex, pixel_scroll))
- {
- return;
- }
- }
-
- // Check other scroll views on window
- if (WindowWheelInput(*w, pixel_scroll))
- return;
- }
- }
- }
-}
-
-void ApplyScreenSaverLockSetting()
-{
- Config::Get().general.DisableScreensaver ? SDL_DisableScreenSaver() : SDL_EnableScreenSaver();
-}
-
-/**
- *
- * rct2: 0x006EA776
- */
-static void WindowInvalidatePressedImageButton(const WindowBase& w)
-{
- WidgetIndex widgetIndex;
- Widget* widget;
-
- widgetIndex = 0;
- for (widget = w.widgets; widget->type != WindowWidgetType::Last; widget++, widgetIndex++)
- {
- if (widget->type != WindowWidgetType::ImgBtn)
- continue;
-
- if (WidgetIsPressed(w, widgetIndex) || isToolActive(w, widgetIndex))
- GfxSetDirtyBlocks({ w.windowPos, w.windowPos + ScreenCoordsXY{ w.width, w.height } });
- }
-}
-
-void Window::ScrollToViewport()
-{
- if (viewport == nullptr || !focus.has_value())
- return;
-
- CoordsXYZ newCoords = focus.value().GetPos();
-
- auto mainWindow = WindowGetMain();
- if (mainWindow != nullptr)
- WindowScrollToLocation(*mainWindow, newCoords);
-}
-
-void Window::OnDraw(DrawPixelInfo& dpi)
-{
- Windows::WindowDrawWidgets(*this, dpi);
-}
-
-void Window::OnDrawWidget(WidgetIndex widgetIndex, DrawPixelInfo& dpi)
-{
- WidgetDraw(dpi, *this, widgetIndex);
-}
-
-void Window::InitScrollWidgets()
-{
- Windows::WindowInitScrollWidgets(*this);
-}
-
-void Window::InvalidateWidget(WidgetIndex widgetIndex)
-{
- WidgetInvalidate(*this, widgetIndex);
-}
-
-bool Window::IsWidgetDisabled(WidgetIndex widgetIndex) const
-{
- return WidgetIsDisabled(*this, widgetIndex);
-}
-
-bool Window::IsWidgetPressed(WidgetIndex widgetIndex) const
-{
- return WidgetIsPressed(*this, widgetIndex);
-}
-
-void Window::SetWidgetEnabled(WidgetIndex widgetIndex, bool value)
-{
- WidgetSetEnabled(*this, widgetIndex, value);
-}
-
-void Window::SetWidgetDisabled(WidgetIndex widgetIndex, bool value)
-{
- WidgetSetDisabled(*this, widgetIndex, value);
-}
-
-void Window::SetWidgetDisabledAndInvalidate(WidgetIndex widgetIndex, bool value)
-{
- bool oldState = IsWidgetDisabled(widgetIndex);
- if (oldState != value)
- {
- WidgetSetDisabled(*this, widgetIndex, value);
- InvalidateWidget(widgetIndex);
- }
-}
-
-void Window::SetWidgetPressed(WidgetIndex widgetIndex, bool value)
-{
- WidgetSetPressed(*this, widgetIndex, value);
-}
-
-void Window::SetCheckboxValue(WidgetIndex widgetIndex, bool value)
-{
- SetWidgetPressed(widgetIndex, value);
-}
-
-void Window::DrawWidgets(DrawPixelInfo& dpi)
-{
- Windows::WindowDrawWidgets(*this, dpi);
-}
-
-void Window::Close()
-{
- CloseWindowModifier modifier = GetCloseModifier();
-
- if (modifier == CloseWindowModifier::Shift)
- {
- CloseOthers();
- }
- else if (modifier == CloseWindowModifier::Control)
- {
- CloseOthersOfThisClass();
- }
- else
- {
- WindowClose(*this);
- }
-}
-
-void Window::CloseOthers()
-{
- WindowCloseAllExceptNumberAndClass(number, classification);
-}
-
-void Window::CloseOthersOfThisClass()
-{
- WindowCloseByClass(classification);
-}
-
-CloseWindowModifier Window::GetCloseModifier()
-{
- CloseWindowModifier lastModifier = CloseWindowModifier::None;
-
- if (gLastCloseModifier.window.number == number && gLastCloseModifier.window.classification == classification)
- {
- lastModifier = gLastCloseModifier.modifier;
- }
-
- gLastCloseModifier.modifier = CloseWindowModifier::None;
-
- return lastModifier;
-}
-
-void Window::TextInputOpen(
- WidgetIndex callWidget, StringId title, StringId description, const Formatter& descriptionArgs, StringId existingText,
- uintptr_t existingArgs, int32_t maxLength)
-{
- OpenRCT2::Ui::Windows::WindowTextInputOpen(
- this, callWidget, title, description, descriptionArgs, existingText, existingArgs, maxLength);
-}
-
-void Window::ResizeFrame()
-{
- // Frame
- widgets[0].right = width - 1;
- widgets[0].bottom = height - 1;
- // Title
- widgets[1].right = width - 2;
- // Close button
- if (Config::Get().interface.WindowButtonsOnTheLeft)
- {
- widgets[2].left = 2;
- widgets[2].right = 2 + kCloseButtonWidth;
- }
- else
- {
- widgets[2].left = width - 3 - kCloseButtonWidth;
- widgets[2].right = width - 3;
- }
-}
-
-void Window::ResizeFrameWithPage()
-{
- ResizeFrame();
- // Page background
- widgets[3].right = width - 1;
- widgets[3].bottom = height - 1;
-}
-
-void Window::ResizeSpinner(WidgetIndex widgetIndex, const ScreenCoordsXY& origin, const ScreenSize& size)
-{
- auto right = origin.x + size.width - 1;
- auto bottom = origin.y + size.height - 1;
- widgets[widgetIndex].left = origin.x;
- widgets[widgetIndex].top = origin.y;
- widgets[widgetIndex].right = right;
- widgets[widgetIndex].bottom = bottom;
-
- widgets[widgetIndex + 1].left = right - size.height; // subtract height to maintain aspect ratio
- widgets[widgetIndex + 1].top = origin.y + 1;
- widgets[widgetIndex + 1].right = right - 1;
- widgets[widgetIndex + 1].bottom = bottom - 1;
-
- widgets[widgetIndex + 2].left = right - size.height * 2;
- widgets[widgetIndex + 2].top = origin.y + 1;
- widgets[widgetIndex + 2].right = right - size.height - 1;
- widgets[widgetIndex + 2].bottom = bottom - 1;
-}
-
-void Window::ResizeDropdown(WidgetIndex widgetIndex, const ScreenCoordsXY& origin, const ScreenSize& size)
-{
- auto right = origin.x + size.width - 1;
- auto bottom = origin.y + size.height - 1;
- widgets[widgetIndex].left = origin.x;
- widgets[widgetIndex].top = origin.y;
- widgets[widgetIndex].right = right;
- widgets[widgetIndex].bottom = bottom;
-
- widgets[widgetIndex + 1].left = right - size.height + 1; // subtract height to maintain aspect ratio
- widgets[widgetIndex + 1].top = origin.y + 1;
- widgets[widgetIndex + 1].right = right - 1;
- widgets[widgetIndex + 1].bottom = bottom - 1;
-}
-
-void WindowAlignTabs(WindowBase* w, WidgetIndex start_tab_id, WidgetIndex end_tab_id)
-{
- int32_t i, x = w->widgets[start_tab_id].left;
- int32_t tab_width = w->widgets[start_tab_id].width();
-
- for (i = start_tab_id; i <= end_tab_id; i++)
- {
- auto& widget = w->widgets[i];
- if (!WidgetIsDisabled(*w, i))
- {
- widget.left = x;
- widget.right = x + tab_width;
- x += tab_width + 1;
+ int32_t size = widget->height() - 1;
+ if (scroll.flags & HSCROLLBAR_VISIBLE)
+ size -= 11;
+ size = std::max(0, scroll.contentHeight - size);
+ scroll.contentOffsetY = std::min(std::max(0, scroll.contentOffsetY + wheel), size);
}
else
{
- // Workaround #20535: Avoid disabled widgets from sharing the same space as active ones, otherwise
- // WindowFindWidgetFromPoint could return the disabled one, causing issues.
- widget.left = 0;
- widget.right = 0;
+ int32_t size = widget->width() - 1;
+ if (scroll.flags & VSCROLLBAR_VISIBLE)
+ size -= 11;
+ size = std::max(0, scroll.contentWidth - size);
+ scroll.contentOffsetX = std::min(std::max(0, scroll.contentOffsetX + wheel), size);
+ }
+
+ WidgetScrollUpdateThumbs(w, widgetIndex);
+ WidgetInvalidate(w, widgetIndex);
+ }
+
+ /**
+ *
+ * rct2: 0x006E793B
+ */
+ static int32_t WindowWheelInput(WindowBase& w, int32_t wheel)
+ {
+ int32_t scrollIndex = 0;
+ for (WidgetIndex widgetIndex = 0; widgetIndex < w.widgets.size(); widgetIndex++)
+ {
+ const auto& widget = w.widgets[widgetIndex];
+ if (widget.type != WindowWidgetType::Scroll)
+ continue;
+
+ // Originally always checked first scroll view, bug maybe?
+ const auto& scroll = w.scrolls[scrollIndex];
+ if (scroll.flags & (HSCROLLBAR_VISIBLE | VSCROLLBAR_VISIBLE))
+ {
+ WindowScrollWheelInput(w, scrollIndex, wheel);
+ return 1;
+ }
+ scrollIndex++;
+ }
+
+ return 0;
+ }
+
+ /**
+ *
+ * rct2: 0x006E79FB
+ */
+ static void WindowViewportWheelInput(WindowBase& w, int32_t wheel)
+ {
+ if (gScreenFlags & (SCREEN_FLAGS_TRACK_MANAGER | SCREEN_FLAGS_TITLE_DEMO))
+ return;
+
+ if (wheel < 0)
+ Windows::WindowZoomIn(w, true);
+ else if (wheel > 0)
+ Windows::WindowZoomOut(w, true);
+ }
+
+ static bool isSpinnerGroup(WindowBase& w, WidgetIndex index, WindowWidgetType buttonType)
+ {
+ const auto& widgets = w.widgets;
+
+ if (widgets[index].type != WindowWidgetType::Spinner && widgets[index].type != WindowWidgetType::ImgBtn)
+ return false;
+
+ if (widgets[index + 1].type != buttonType)
+ return false;
+
+ if (widgets[index + 2].type != buttonType)
+ return false;
+
+ return true;
+ }
+
+ static std::optional getSpinnerGroupWidgetIndex(WindowBase& w, WidgetIndex startIndex)
+ {
+ // We only iterate 3 times as we might be at the spinner or one of its buttons.
+ for (WidgetIndex index = 0; index < 3; index++)
+ {
+ const auto reverseIndex = startIndex - index;
+ if (reverseIndex < 0)
+ {
+ break;
+ }
+
+ if (isSpinnerGroup(w, reverseIndex, WindowWidgetType::TrnBtn))
+ {
+ return reverseIndex;
+ }
+
+ if (isSpinnerGroup(w, reverseIndex, WindowWidgetType::Button))
+ {
+ return reverseIndex;
+ }
+ }
+
+ return std::nullopt;
+ }
+
+ // Allow mouse wheel scrolling to manipulate spinner widgets and tool sizes
+ static bool WindowOtherWheelInput(WindowBase& w, WidgetIndex widgetIndex, int32_t wheel)
+ {
+ // HACK: Until we have a new window system that allows us to add new events like mouse wheel easily,
+ // this selective approach will have to do.
+
+ const auto spinnerGroupIndex = getSpinnerGroupWidgetIndex(w, widgetIndex);
+ if (!spinnerGroupIndex.has_value())
+ {
+ return false;
+ }
+
+ const auto entryWidgetType = w.widgets[*spinnerGroupIndex].type;
+ auto targetWidgetIndex = *spinnerGroupIndex;
+
+ if (entryWidgetType == WindowWidgetType::ImgBtn)
+ {
+ auto expectedContent1 = ImageId(SPR_LAND_TOOL_DECREASE, FilterPaletteID::PaletteNull);
+ auto expectedContent2 = ImageId(SPR_LAND_TOOL_INCREASE, FilterPaletteID::PaletteNull);
+
+ auto button1Image = w.widgets[*spinnerGroupIndex + 1].image;
+ auto button2Image = w.widgets[*spinnerGroupIndex + 2].image;
+ if (button1Image != expectedContent1 || button2Image != expectedContent2)
+ {
+ return false;
+ }
+
+ // Expected widget order: decrease, increase
+ targetWidgetIndex += wheel < 0 ? 2 : 1;
+ }
+ else if (entryWidgetType == WindowWidgetType::Spinner)
+ {
+ auto button1StringId = w.widgets[*spinnerGroupIndex + 1].text;
+ auto button2StringId = w.widgets[*spinnerGroupIndex + 2].text;
+ if (button1StringId != STR_NUMERIC_UP || button2StringId != STR_NUMERIC_DOWN)
+ {
+ return false;
+ }
+
+ // Expected widget order: increase, decrease
+ targetWidgetIndex += wheel < 0 ? 1 : 2;
+ }
+
+ if (WidgetIsDisabled(w, targetWidgetIndex))
+ {
+ return false;
+ }
+
+ w.OnMouseDown(targetWidgetIndex);
+ return true;
+ }
+
+ /**
+ *
+ * rct2: 0x006E7868
+ */
+ void WindowAllWheelInput()
+ {
+ // Get wheel value
+ auto cursorState = ContextGetCursorState();
+ int32_t absolute_wheel = cursorState->wheel;
+ int32_t relative_wheel = absolute_wheel - _previousAbsoluteWheel;
+ int32_t pixel_scroll = relative_wheel * WindowScrollPixels;
+ _previousAbsoluteWheel = absolute_wheel;
+
+ if (relative_wheel == 0)
+ return;
+
+ // Check window cursor is over
+ if (!(InputTestFlag(INPUT_FLAG_5)))
+ {
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ WindowBase* w = windowMgr->FindFromPoint(cursorState->position);
+ if (w != nullptr)
+ {
+ // Check if main window
+ if (w->classification == WindowClass::MainWindow || w->classification == WindowClass::Viewport)
+ {
+ WindowViewportWheelInput(*w, relative_wheel);
+ return;
+ }
+
+ // Check scroll view, cursor is over
+ WidgetIndex widgetIndex = windowMgr->FindWidgetFromPoint(*w, cursorState->position);
+ if (widgetIndex != kWidgetIndexNull)
+ {
+ const auto& widget = w->widgets[widgetIndex];
+ if (widget.type == WindowWidgetType::Scroll)
+ {
+ int32_t scrollIndex = WindowGetScrollIndex(*w, widgetIndex);
+ const auto& scroll = w->scrolls[scrollIndex];
+ if (scroll.flags & (HSCROLLBAR_VISIBLE | VSCROLLBAR_VISIBLE))
+ {
+ WindowScrollWheelInput(*w, WindowGetScrollIndex(*w, widgetIndex), pixel_scroll);
+ return;
+ }
+ }
+ else
+ {
+ if (WindowOtherWheelInput(*w, widgetIndex, pixel_scroll))
+ {
+ return;
+ }
+ }
+
+ // Check other scroll views on window
+ if (WindowWheelInput(*w, pixel_scroll))
+ return;
+ }
+ }
}
}
-}
-ScreenCoordsXY WindowGetViewportSoundIconPos(WindowBase& w)
-{
- const uint8_t buttonOffset = (Config::Get().interface.WindowButtonsOnTheLeft) ? kCloseButtonWidth + 2 : 0;
- return w.windowPos + ScreenCoordsXY{ 2 + buttonOffset, 2 };
-}
+ void ApplyScreenSaverLockSetting()
+ {
+ Config::Get().general.DisableScreensaver ? SDL_DisableScreenSaver() : SDL_EnableScreenSaver();
+ }
+
+ /**
+ *
+ * rct2: 0x006EA776
+ */
+ static void WindowInvalidatePressedImageButton(const WindowBase& w)
+ {
+ for (WidgetIndex widgetIndex = 0; widgetIndex < w.widgets.size(); widgetIndex++)
+ {
+ auto& widget = w.widgets[widgetIndex];
+ if (widget.type != WindowWidgetType::ImgBtn)
+ continue;
+
+ if (WidgetIsPressed(w, widgetIndex) || isToolActive(w, widgetIndex))
+ GfxSetDirtyBlocks({ w.windowPos, w.windowPos + ScreenCoordsXY{ w.width, w.height } });
+ }
+ }
+
+ void Window::ScrollToViewport()
+ {
+ if (viewport == nullptr || !focus.has_value())
+ return;
+
+ CoordsXYZ newCoords = focus.value().GetPos();
+
+ auto mainWindow = WindowGetMain();
+ if (mainWindow != nullptr)
+ WindowScrollToLocation(*mainWindow, newCoords);
+ }
+
+ void Window::OnDraw(DrawPixelInfo& dpi)
+ {
+ Windows::WindowDrawWidgets(*this, dpi);
+ }
+
+ void Window::OnDrawWidget(WidgetIndex widgetIndex, DrawPixelInfo& dpi)
+ {
+ WidgetDraw(dpi, *this, widgetIndex);
+ }
+
+ void Window::InitScrollWidgets()
+ {
+ Windows::WindowInitScrollWidgets(*this);
+ }
+
+ void Window::InvalidateWidget(WidgetIndex widgetIndex)
+ {
+ WidgetInvalidate(*this, widgetIndex);
+ }
+
+ bool Window::IsWidgetDisabled(WidgetIndex widgetIndex) const
+ {
+ return WidgetIsDisabled(*this, widgetIndex);
+ }
+
+ bool Window::IsWidgetPressed(WidgetIndex widgetIndex) const
+ {
+ return WidgetIsPressed(*this, widgetIndex);
+ }
+
+ void Window::SetWidgetEnabled(WidgetIndex widgetIndex, bool value)
+ {
+ WidgetSetEnabled(*this, widgetIndex, value);
+ }
+
+ void Window::SetWidgetDisabled(WidgetIndex widgetIndex, bool value)
+ {
+ WidgetSetDisabled(*this, widgetIndex, value);
+ }
+
+ void Window::SetWidgetDisabledAndInvalidate(WidgetIndex widgetIndex, bool value)
+ {
+ bool oldState = IsWidgetDisabled(widgetIndex);
+ if (oldState != value)
+ {
+ WidgetSetDisabled(*this, widgetIndex, value);
+ InvalidateWidget(widgetIndex);
+ }
+ }
+
+ void Window::SetWidgetPressed(WidgetIndex widgetIndex, bool value)
+ {
+ WidgetSetPressed(*this, widgetIndex, value);
+ }
+
+ void Window::SetCheckboxValue(WidgetIndex widgetIndex, bool value)
+ {
+ SetWidgetPressed(widgetIndex, value);
+ }
+
+ void Window::DrawWidgets(DrawPixelInfo& dpi)
+ {
+ Windows::WindowDrawWidgets(*this, dpi);
+ }
+
+ void Window::Close()
+ {
+ CloseWindowModifier modifier = GetCloseModifier();
+
+ if (modifier == CloseWindowModifier::Shift)
+ {
+ CloseOthers();
+ }
+ else if (modifier == CloseWindowModifier::Control)
+ {
+ CloseOthersOfThisClass();
+ }
+ else
+ {
+ WindowClose(*this);
+ }
+ }
+
+ void Window::CloseOthers()
+ {
+ WindowCloseAllExceptNumberAndClass(number, classification);
+ }
+
+ void Window::CloseOthersOfThisClass()
+ {
+ WindowCloseByClass(classification);
+ }
+
+ CloseWindowModifier Window::GetCloseModifier()
+ {
+ CloseWindowModifier lastModifier = CloseWindowModifier::None;
+
+ if (gLastCloseModifier.window.number == number && gLastCloseModifier.window.classification == classification)
+ {
+ lastModifier = gLastCloseModifier.modifier;
+ }
+
+ gLastCloseModifier.modifier = CloseWindowModifier::None;
+
+ return lastModifier;
+ }
+
+ void Window::TextInputOpen(
+ WidgetIndex callWidget, StringId title, StringId description, const Formatter& descriptionArgs, StringId existingText,
+ uintptr_t existingArgs, int32_t maxLength)
+ {
+ OpenRCT2::Ui::Windows::WindowTextInputOpen(
+ this, callWidget, title, description, descriptionArgs, existingText, existingArgs, maxLength);
+ }
+
+ void Window::ResizeFrame()
+ {
+ // Frame
+ widgets[0].right = width - 1;
+ widgets[0].bottom = height - 1;
+ // Title
+ widgets[1].right = width - 2;
+ // Close button
+ if (Config::Get().interface.WindowButtonsOnTheLeft)
+ {
+ widgets[2].left = 2;
+ widgets[2].right = 2 + kCloseButtonWidth;
+ }
+ else
+ {
+ widgets[2].left = width - 3 - kCloseButtonWidth;
+ widgets[2].right = width - 3;
+ }
+ }
+
+ void Window::ResizeFrameWithPage()
+ {
+ ResizeFrame();
+ // Page background
+ widgets[3].right = width - 1;
+ widgets[3].bottom = height - 1;
+ }
+
+ void Window::ResizeSpinner(WidgetIndex widgetIndex, const ScreenCoordsXY& origin, const ScreenSize& size)
+ {
+ auto right = origin.x + size.width - 1;
+ auto bottom = origin.y + size.height - 1;
+ widgets[widgetIndex].left = origin.x;
+ widgets[widgetIndex].top = origin.y;
+ widgets[widgetIndex].right = right;
+ widgets[widgetIndex].bottom = bottom;
+
+ widgets[widgetIndex + 1].left = right - size.height; // subtract height to maintain aspect ratio
+ widgets[widgetIndex + 1].top = origin.y + 1;
+ widgets[widgetIndex + 1].right = right - 1;
+ widgets[widgetIndex + 1].bottom = bottom - 1;
+
+ widgets[widgetIndex + 2].left = right - size.height * 2;
+ widgets[widgetIndex + 2].top = origin.y + 1;
+ widgets[widgetIndex + 2].right = right - size.height - 1;
+ widgets[widgetIndex + 2].bottom = bottom - 1;
+ }
+
+ void Window::ResizeDropdown(WidgetIndex widgetIndex, const ScreenCoordsXY& origin, const ScreenSize& size)
+ {
+ auto right = origin.x + size.width - 1;
+ auto bottom = origin.y + size.height - 1;
+ widgets[widgetIndex].left = origin.x;
+ widgets[widgetIndex].top = origin.y;
+ widgets[widgetIndex].right = right;
+ widgets[widgetIndex].bottom = bottom;
+
+ widgets[widgetIndex + 1].left = right - size.height + 1; // subtract height to maintain aspect ratio
+ widgets[widgetIndex + 1].top = origin.y + 1;
+ widgets[widgetIndex + 1].right = right - 1;
+ widgets[widgetIndex + 1].bottom = bottom - 1;
+ }
+
+ void WindowAlignTabs(WindowBase* w, WidgetIndex start_tab_id, WidgetIndex end_tab_id)
+ {
+ int32_t i, x = w->widgets[start_tab_id].left;
+ int32_t tab_width = w->widgets[start_tab_id].width();
+
+ for (i = start_tab_id; i <= end_tab_id; i++)
+ {
+ auto& widget = w->widgets[i];
+ if (!WidgetIsDisabled(*w, i))
+ {
+ widget.left = x;
+ widget.right = x + tab_width;
+ x += tab_width + 1;
+ }
+ else
+ {
+ // Workaround #20535: Avoid disabled widgets from sharing the same space as active ones, otherwise
+ // WindowFindWidgetFromPoint could return the disabled one, causing issues.
+ widget.left = 0;
+ widget.right = 0;
+ }
+ }
+ }
+
+ ScreenCoordsXY WindowGetViewportSoundIconPos(WindowBase& w)
+ {
+ const uint8_t buttonOffset = (Config::Get().interface.WindowButtonsOnTheLeft) ? kCloseButtonWidth + 2 : 0;
+ return w.windowPos + ScreenCoordsXY{ 2 + buttonOffset, 2 };
+ }
+} // namespace OpenRCT2
namespace OpenRCT2::Ui::Windows
{
@@ -879,7 +881,7 @@ namespace OpenRCT2::Ui::Windows
{
WidgetInvalidate(*w, _currentTextBox.widget_index);
}
- _currentTextBox.widget_index = static_cast(WindowWidgetType::Last);
+ _currentTextBox.widget_index = kWidgetIndexNull;
}
}
@@ -958,14 +960,11 @@ namespace OpenRCT2::Ui::Windows
void WindowUpdateScrollWidgets(WindowBase& w)
{
int32_t scrollIndex, width, height, scrollPositionChanged;
- WidgetIndex widgetIndex;
- Widget* widget;
-
- widgetIndex = 0;
scrollIndex = 0;
- for (widget = w.widgets; widget->type != WindowWidgetType::Last; widget++, widgetIndex++)
+ for (WidgetIndex widgetIndex = 0; widgetIndex < w.widgets.size(); widgetIndex++)
{
- if (widget->type != WindowWidgetType::Scroll)
+ auto& widget = w.widgets[widgetIndex];
+ if (widget.type != WindowWidgetType::Scroll)
continue;
auto& scroll = w.scrolls[scrollIndex];
@@ -985,13 +984,13 @@ namespace OpenRCT2::Ui::Windows
height++;
scrollPositionChanged = 0;
- if ((widget->content & SCROLL_HORIZONTAL) && width != scroll.contentWidth)
+ if ((widget.content & SCROLL_HORIZONTAL) && width != scroll.contentWidth)
{
scrollPositionChanged = 1;
scroll.contentWidth = width;
}
- if ((widget->content & SCROLL_VERTICAL) && height != scroll.contentHeight)
+ if ((widget.content & SCROLL_VERTICAL) && height != scroll.contentHeight)
{
scrollPositionChanged = 1;
scroll.contentHeight = height;
@@ -1011,16 +1010,12 @@ namespace OpenRCT2::Ui::Windows
*/
void WindowInitScrollWidgets(WindowBase& w)
{
- Widget* widget;
- int32_t widget_index, scroll_index;
-
- widget_index = 0;
- scroll_index = 0;
- for (widget = w.widgets; widget->type != WindowWidgetType::Last; widget++)
+ int32_t scroll_index{};
+ for (WidgetIndex widgetIndex = 0; widgetIndex < w.widgets.size(); widgetIndex++)
{
- if (widget->type != WindowWidgetType::Scroll)
+ auto& widget = w.widgets[widgetIndex];
+ if (widget.type != WindowWidgetType::Scroll)
{
- widget_index++;
continue;
}
@@ -1032,14 +1027,12 @@ namespace OpenRCT2::Ui::Windows
scroll.contentOffsetY = 0;
scroll.contentHeight = scrollSize.height + 1;
- if (widget->content & SCROLL_HORIZONTAL)
+ if (widget.content & SCROLL_HORIZONTAL)
scroll.flags |= HSCROLLBAR_VISIBLE;
- if (widget->content & SCROLL_VERTICAL)
+ if (widget.content & SCROLL_VERTICAL)
scroll.flags |= VSCROLLBAR_VISIBLE;
- WidgetScrollUpdateThumbs(w, widget_index);
-
- widget_index++;
+ WidgetScrollUpdateThumbs(w, widgetIndex);
scroll_index++;
}
}
@@ -1312,30 +1305,27 @@ namespace OpenRCT2::Ui::Windows
*/
void WindowDrawWidgets(WindowBase& w, DrawPixelInfo& dpi)
{
- Widget* widget;
- WidgetIndex widgetIndex;
-
if ((w.flags & WF_TRANSPARENT) && !(w.flags & WF_NO_BACKGROUND))
GfxFilterRect(
dpi, { w.windowPos, w.windowPos + ScreenCoordsXY{ w.width - 1, w.height - 1 } }, FilterPaletteID::Palette51);
// todo: some code missing here? Between 006EB18C and 006EB260
-
- widgetIndex = 0;
- for (widget = w.widgets; widget->type != WindowWidgetType::Last; widget++)
+ for (WidgetIndex widgetIndex = 0; widgetIndex < w.widgets.size(); widgetIndex++)
{
- if (widget->IsVisible())
+ auto& widget = w.widgets[widgetIndex];
+ if (!widget.IsVisible())
{
- // Check if widget is outside the draw region
- if (w.windowPos.x + widget->left < dpi.x + dpi.width && w.windowPos.x + widget->right >= dpi.x)
+ continue;
+ }
+
+ // Check if widget is outside the draw region
+ if (w.windowPos.x + widget.left < dpi.x + dpi.width && w.windowPos.x + widget.right >= dpi.x)
+ {
+ if (w.windowPos.y + widget.top < dpi.y + dpi.height && w.windowPos.y + widget.bottom >= dpi.y)
{
- if (w.windowPos.y + widget->top < dpi.y + dpi.height && w.windowPos.y + widget->bottom >= dpi.y)
- {
- w.OnDrawWidget(widgetIndex, dpi);
- }
+ w.OnDrawWidget(widgetIndex, dpi);
}
}
- widgetIndex++;
}
// todo: something missing here too? Between 006EC32B and 006EC369
diff --git a/src/openrct2-ui/interface/Window.h b/src/openrct2-ui/interface/Window.h
index 6b2000da8c..d5003c07c0 100644
--- a/src/openrct2-ui/interface/Window.h
+++ b/src/openrct2-ui/interface/Window.h
@@ -14,41 +14,44 @@
struct TextInputSession;
-struct Window : WindowBase
+namespace OpenRCT2
{
- virtual void OnDraw(DrawPixelInfo& dpi) override;
- virtual void OnDrawWidget(WidgetIndex widgetIndex, DrawPixelInfo& dpi) override;
+ struct Window : WindowBase
+ {
+ void OnDraw(DrawPixelInfo& dpi) override;
+ void OnDrawWidget(WidgetIndex widgetIndex, DrawPixelInfo& dpi) override;
- void ScrollToViewport();
- void InitScrollWidgets();
- void InvalidateWidget(WidgetIndex widgetIndex);
- bool IsWidgetDisabled(WidgetIndex widgetIndex) const;
- bool IsWidgetPressed(WidgetIndex widgetIndex) const;
- void SetWidgetEnabled(WidgetIndex widgetIndex, bool value);
- void SetWidgetDisabled(WidgetIndex widgetIndex, bool value);
- void SetWidgetDisabledAndInvalidate(WidgetIndex widgetIndex, bool value);
- void SetWidgetPressed(WidgetIndex widgetIndex, bool value);
- void SetCheckboxValue(WidgetIndex widgetIndex, bool value);
- void DrawWidgets(DrawPixelInfo& dpi);
- void Close();
- void CloseOthers();
- void CloseOthersOfThisClass();
- CloseWindowModifier GetCloseModifier();
- void TextInputOpen(
- WidgetIndex callWidget, StringId title, StringId description, const Formatter& descriptionArgs, StringId existingText,
- uintptr_t existingArgs, int32_t maxLength);
+ void ScrollToViewport();
+ void InitScrollWidgets();
+ void InvalidateWidget(WidgetIndex widgetIndex);
+ bool IsWidgetDisabled(WidgetIndex widgetIndex) const;
+ bool IsWidgetPressed(WidgetIndex widgetIndex) const;
+ void SetWidgetEnabled(WidgetIndex widgetIndex, bool value);
+ void SetWidgetDisabled(WidgetIndex widgetIndex, bool value);
+ void SetWidgetDisabledAndInvalidate(WidgetIndex widgetIndex, bool value);
+ void SetWidgetPressed(WidgetIndex widgetIndex, bool value);
+ void SetCheckboxValue(WidgetIndex widgetIndex, bool value);
+ void DrawWidgets(DrawPixelInfo& dpi);
+ void Close();
+ void CloseOthers();
+ void CloseOthersOfThisClass();
+ CloseWindowModifier GetCloseModifier();
+ void TextInputOpen(
+ WidgetIndex callWidget, StringId title, StringId description, const Formatter& descriptionArgs,
+ StringId existingText, uintptr_t existingArgs, int32_t maxLength);
- void ResizeFrame();
- void ResizeFrameWithPage();
+ void ResizeFrame();
+ void ResizeFrameWithPage();
- void ResizeSpinner(WidgetIndex widgetIndex, const ScreenCoordsXY& origin, const ScreenSize& size);
- void ResizeDropdown(WidgetIndex widgetIndex, const ScreenCoordsXY& origin, const ScreenSize& size);
-};
+ void ResizeSpinner(WidgetIndex widgetIndex, const ScreenCoordsXY& origin, const ScreenSize& size);
+ void ResizeDropdown(WidgetIndex widgetIndex, const ScreenCoordsXY& origin, const ScreenSize& size);
+ };
-void WindowAllWheelInput();
-void ApplyScreenSaverLockSetting();
-void WindowAlignTabs(WindowBase* w, WidgetIndex start_tab_id, WidgetIndex end_tab_id);
-ScreenCoordsXY WindowGetViewportSoundIconPos(WindowBase& w);
+ void WindowAllWheelInput();
+ void ApplyScreenSaverLockSetting();
+ void WindowAlignTabs(WindowBase* w, WidgetIndex start_tab_id, WidgetIndex end_tab_id);
+ ScreenCoordsXY WindowGetViewportSoundIconPos(WindowBase& w);
+} // namespace OpenRCT2
namespace OpenRCT2::Ui::Windows
{
diff --git a/src/openrct2-ui/ride/Construction.h b/src/openrct2-ui/ride/Construction.h
index 14a732369c..519704e59f 100644
--- a/src/openrct2-ui/ride/Construction.h
+++ b/src/openrct2-ui/ride/Construction.h
@@ -132,6 +132,10 @@ namespace OpenRCT2
TrackElemType::LeftLargeZeroGRollDown,
TrackElemType::RightLargeZeroGRollUp,
TrackElemType::RightLargeZeroGRollDown,
+ TrackElemType::LeftEighthDiveLoopUpToOrthogonal,
+ TrackElemType::LeftEighthDiveLoopDownToDiag,
+ TrackElemType::RightEighthDiveLoopUpToOrthogonal,
+ TrackElemType::RightEighthDiveLoopDownToDiag,
TrackElemType::LeftFlyerLargeHalfLoopUninvertedUp,
TrackElemType::LeftFlyerLargeHalfLoopInvertedDown,
TrackElemType::LeftFlyerLargeHalfLoopInvertedUp,
@@ -144,7 +148,7 @@ namespace OpenRCT2
constexpr size_t DropdownLength = DropdownOrder.size();
// Update the magic number with the current number of track elements to silence
- static_assert(EnumValue(TrackElemType::Count) == 341, "Reminder to add new track element to special dropdown list");
+ static_assert(EnumValue(TrackElemType::Count) == 349, "Reminder to add new track element to special dropdown list");
constexpr bool TrackPieceDirectionIsDiagonal(const uint8_t direction)
{
diff --git a/src/openrct2-ui/scripting/CustomListView.cpp b/src/openrct2-ui/scripting/CustomListView.cpp
index 1e66098e52..c7841755d9 100644
--- a/src/openrct2-ui/scripting/CustomListView.cpp
+++ b/src/openrct2-ui/scripting/CustomListView.cpp
@@ -830,16 +830,17 @@ std::optional CustomListView::GetItemIndexAt(const ScreenCoordsXY& po
return result;
}
-Widget* CustomListView::GetWidget() const
+OpenRCT2::Widget* CustomListView::GetWidget() const
{
size_t scrollIndex = 0;
- for (auto widget = ParentWindow->widgets; widget->type != WindowWidgetType::Last; widget++)
+ for (WidgetIndex widgetIndex = 0; widgetIndex < ParentWindow->widgets.size(); widgetIndex++)
{
- if (widget->type == WindowWidgetType::Scroll)
+ auto& widget = ParentWindow->widgets[widgetIndex];
+ if (widget.type == WindowWidgetType::Scroll)
{
if (scrollIndex == ScrollIndex)
{
- return widget;
+ return &widget;
}
scrollIndex++;
}
diff --git a/src/openrct2-ui/scripting/CustomMenu.cpp b/src/openrct2-ui/scripting/CustomMenu.cpp
index cb2756ebc1..6b0548b0cc 100644
--- a/src/openrct2-ui/scripting/CustomMenu.cpp
+++ b/src/openrct2-ui/scripting/CustomMenu.cpp
@@ -272,9 +272,10 @@ namespace OpenRCT2::Scripting
auto toolbarWindow = windowMgr->FindByClass(WindowClass::TopToolbar);
if (toolbarWindow != nullptr)
{
- // Use a widget that does not exist on top toolbar but also make sure it isn't -1 as that
- // prevents abort from being called.
- WidgetIndex widgetIndex = -2;
+ // Use a widget that does not exist on top toolbar but also make sure it isn't
+ // kWidgetIndexNull, as that prevents abort from being called.
+ // TODO: refactor this to not leech on the top toolbar.
+ WidgetIndex widgetIndex = 0xFFFE;
ToolCancel();
ToolSet(*toolbarWindow, widgetIndex, static_cast(customTool.Cursor));
ActiveCustomTool = std::move(customTool);
diff --git a/src/openrct2-ui/scripting/CustomWindow.cpp b/src/openrct2-ui/scripting/CustomWindow.cpp
index c61a1ba233..c89f8ce91c 100644
--- a/src/openrct2-ui/scripting/CustomWindow.cpp
+++ b/src/openrct2-ui/scripting/CustomWindow.cpp
@@ -218,6 +218,21 @@ namespace OpenRCT2::Ui::Windows
result.imageFrameCount = AsOrDefault(dukImage["frameCount"], 0);
result.imageFrameDuration = AsOrDefault(dukImage["frameDuration"], 0);
+ if (dukImage["primaryColour"].type() == DukValue::Type::NUMBER)
+ {
+ result.imageFrameBase = result.imageFrameBase.WithPrimary(dukImage["primaryColour"].as_uint());
+
+ if (dukImage["secondaryColour"].type() == DukValue::Type::NUMBER)
+ {
+ result.imageFrameBase = result.imageFrameBase.WithSecondary(dukImage["secondaryColour"].as_uint());
+
+ if (dukImage["tertiaryColour"].type() == DukValue::Type::NUMBER)
+ {
+ result.imageFrameBase = result.imageFrameBase.WithTertiary(dukImage["tertiaryColour"].as_uint());
+ }
+ }
+ }
+
auto dukCoord = dukImage["offset"];
if (dukCoord.type() == DukValue::Type::OBJECT)
{
@@ -459,9 +474,9 @@ namespace OpenRCT2::Ui::Windows
// Since the plugin may alter widget positions and sizes during an update event,
// we need to force an update for all list view scrollbars
WidgetIndex widgetIndex = 0;
- for (auto widget = widgets; widget->type != WindowWidgetType::Last; widget++)
+ for (auto& widget : widgets)
{
- if (widget->type == WindowWidgetType::Scroll)
+ if (widget.type == WindowWidgetType::Scroll)
{
WidgetScrollUpdateThumbs(*this, widgetIndex);
}
@@ -496,13 +511,13 @@ namespace OpenRCT2::Ui::Windows
ft.Add(desc.Title.c_str());
size_t scrollIndex = 0;
- for (auto widget = widgets; widget->type != WindowWidgetType::Last; widget++)
+ for (const auto& widget : widgets)
{
- if (widget->type == WindowWidgetType::Scroll)
+ if (widget.type == WindowWidgetType::Scroll)
{
auto& listView = _info.ListViews[scrollIndex];
- auto wwidth = widget->width() + 1 - 2;
- auto wheight = widget->height() + 1 - 2;
+ auto wwidth = widget.width() + 1 - 2;
+ auto wheight = widget.height() + 1 - 2;
if (listView.GetScrollbars() == ScrollbarType::Horizontal
|| listView.GetScrollbars() == ScrollbarType::Both)
{
@@ -765,9 +780,9 @@ namespace OpenRCT2::Ui::Windows
std::optional GetViewportWidgetIndex()
{
WidgetIndex widgetIndex = 0;
- for (auto widget = widgets; widget->type != WindowWidgetType::Last; widget++)
+ for (auto& widget : widgets)
{
- if (widget->type == WindowWidgetType::Viewport)
+ if (widget.type == WindowWidgetType::Viewport)
{
return widgetIndex;
}
@@ -928,8 +943,7 @@ namespace OpenRCT2::Ui::Windows
}
}
- widgetList.push_back(kWidgetsEnd);
- widgets = widgetList.data();
+ SetWidgets(widgetList);
WindowInitScrollWidgets(*this);
UpdateViewport();
diff --git a/src/openrct2-ui/scripting/ScWidget.hpp b/src/openrct2-ui/scripting/ScWidget.hpp
index 4f9ec52734..aeb056e531 100644
--- a/src/openrct2-ui/scripting/ScWidget.hpp
+++ b/src/openrct2-ui/scripting/ScWidget.hpp
@@ -117,8 +117,6 @@ namespace OpenRCT2::Scripting
return "progress_bar";
case WindowWidgetType::Custom:
return "custom";
- case WindowWidgetType::Last:
- return "last";
}
}
return "unknown";
diff --git a/src/openrct2-ui/scripting/ScWindow.hpp b/src/openrct2-ui/scripting/ScWindow.hpp
index fee0966ba1..872ac02bd2 100644
--- a/src/openrct2-ui/scripting/ScWindow.hpp
+++ b/src/openrct2-ui/scripting/ScWindow.hpp
@@ -218,11 +218,9 @@ namespace OpenRCT2::Scripting
auto w = GetWindow();
if (w != nullptr)
{
- WidgetIndex widgetIndex = 0;
- for (auto widget = w->widgets; widget->type != WindowWidgetType::Last; widget++)
+ for (WidgetIndex widgetIndex = 0; widgetIndex < w->widgets.size(); widgetIndex++)
{
result.push_back(ScWidget::ToDukValue(ctx, w, widgetIndex));
- widgetIndex++;
}
}
return result;
diff --git a/src/openrct2-ui/windows/About.cpp b/src/openrct2-ui/windows/About.cpp
index 94996f277c..b85113f923 100644
--- a/src/openrct2-ui/windows/About.cpp
+++ b/src/openrct2-ui/windows/About.cpp
@@ -63,7 +63,7 @@ namespace OpenRCT2::Ui::Windows
MakeRemapWidget({ 94, 17 }, { 91, TABHEIGHT - 16 }, WindowWidgetType::Tab, WindowColour::Secondary, SPR_TAB_LARGE)
// clang-format off
- static Widget _windowAboutOpenRCT2Widgets[] = {
+ static constexpr Widget _windowAboutOpenRCT2Widgets[] = {
WIDGETS_MAIN,
MakeWidget({10, 60}, {WW - 20, 20}, WindowWidgetType::LabelCentred, WindowColour::Secondary, STR_ABOUT_OPENRCT2_DESCRIPTION), // Introduction
MakeWidget({30, 90}, {128, 128}, WindowWidgetType::Placeholder, WindowColour::Secondary, STR_NONE), // OpenRCT2 Logo
@@ -73,16 +73,14 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({168, 115 + 40}, {200, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_CHANGELOG_ELLIPSIS), // changelog button
MakeWidget({168, 115 + 60}, {200, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_JOIN_DISCORD ), // "join discord" button
MakeWidget({168, 115 + 80}, {200, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_CONTRIBUTORS_WINDOW_BUTTON), // "contributors" button
- kWidgetsEnd,
};
// clang-format on
- static Widget _windowAboutRCT2Widgets[] = {
+ static constexpr Widget _windowAboutRCT2Widgets[] = {
WIDGETS_MAIN,
- kWidgetsEnd,
};
- static Widget* _windowAboutPageWidgets[] = {
+ static constexpr std::span _windowAboutPageWidgets[] = {
_windowAboutOpenRCT2Widgets,
_windowAboutRCT2Widgets,
};
@@ -92,9 +90,6 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = _windowAboutOpenRCT2Widgets;
-
- WindowInitScrollWidgets(*this);
SetPage(WINDOW_ABOUT_PAGE_OPENRCT2);
}
@@ -174,7 +169,7 @@ namespace OpenRCT2::Ui::Windows
page = p;
frame_no = 0;
pressed_widgets = 0;
- widgets = _windowAboutPageWidgets[p];
+ SetWidgets(_windowAboutPageWidgets[p]);
switch (p)
{
@@ -186,7 +181,7 @@ namespace OpenRCT2::Ui::Windows
break;
}
- WindowInitScrollWidgets(*this);
+ InitScrollWidgets();
Invalidate();
}
@@ -215,7 +210,6 @@ namespace OpenRCT2::Ui::Windows
if (OpenRCT2::GetContext()->HasNewVersionInfo())
{
widgets[WIDX_NEW_VERSION].type = WindowWidgetType::Button;
- _windowAboutOpenRCT2Widgets[WIDX_NEW_VERSION].type = WindowWidgetType::Button;
}
// Draw the rest of the text
diff --git a/src/openrct2-ui/windows/AssetPacks.cpp b/src/openrct2-ui/windows/AssetPacks.cpp
index 622a80f3f3..5d0aa86878 100644
--- a/src/openrct2-ui/windows/AssetPacks.cpp
+++ b/src/openrct2-ui/windows/AssetPacks.cpp
@@ -40,7 +40,7 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget WindowAssetPacksWidgets[] = {
+ static constexpr Widget WindowAssetPacksWidgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({ 0, 0 }, { 0, 0 }, WindowWidgetType::LabelCentred, WindowColour::Secondary, STR_HIGH_PRIORITY),
MakeWidget({ 0, 0 }, { 0, 147 }, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL),
@@ -48,7 +48,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({ 0, 0 }, { 0, 0 }, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_G2_ARROW_UP), STR_INCREASE_PRIOTITY_TIP),
MakeWidget({ 0, 0 }, { 0, 0 }, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_G2_ARROW_DOWN), STR_DECREASE_PRIOTITY_TIP),
MakeWidget({ 0, 0 }, { 0, 0 }, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_G2_RELOAD), STR_RELOAD_ASSET_PACKS_TIP),
- kWidgetsEnd,
};
// clang-format on
@@ -63,7 +62,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = WindowAssetPacksWidgets;
+ SetWidgets(WindowAssetPacksWidgets);
WindowInitScrollWidgets(*this);
}
diff --git a/src/openrct2-ui/windows/Banner.cpp b/src/openrct2-ui/windows/Banner.cpp
index e94402770e..0d675ba2d5 100644
--- a/src/openrct2-ui/windows/Banner.cpp
+++ b/src/openrct2-ui/windows/Banner.cpp
@@ -63,7 +63,7 @@ namespace OpenRCT2::Ui::Windows
STR_TEXT_COLOUR_PALESILVER,
};
- static Widget window_banner_widgets[] = {
+ static constexpr Widget window_banner_widgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({ 3, 17}, {85, 60}, WindowWidgetType::Viewport, WindowColour::Secondary, 0x0FFFFFFFE ), // tab content panel
MakeWidget({WW - 25, 19}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_RENAME), STR_CHANGE_BANNER_TEXT_TIP ), // change banner button
@@ -72,7 +72,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({ 5, WH - 16}, {12, 12}, WindowWidgetType::ColourBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_SELECT_MAIN_SIGN_COLOUR_TIP), // high money
MakeWidget({ 43, WH - 16}, {39, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ), // high money
MakeWidget({ 70, WH - 15}, {11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_SELECT_TEXT_COLOUR_TIP ), // high money
- kWidgetsEnd,
};
// clang-format on
@@ -83,10 +82,10 @@ namespace OpenRCT2::Ui::Windows
void CreateViewport()
{
- Widget* viewportWidget = &window_banner_widgets[WIDX_VIEWPORT];
+ const auto& viewportWidget = window_banner_widgets[WIDX_VIEWPORT];
ViewportCreate(
- this, windowPos + ScreenCoordsXY{ viewportWidget->left + 1, viewportWidget->top + 1 },
- (viewportWidget->width()) - 1, (viewportWidget->height()) - 1, Focus(_bannerViewPos));
+ this, windowPos + ScreenCoordsXY{ viewportWidget.left + 1, viewportWidget.top + 1 },
+ (viewportWidget.width()) - 1, (viewportWidget.height()) - 1, Focus(_bannerViewPos));
if (viewport != nullptr)
viewport->flags = Config::Get().general.AlwaysShowGridlines ? VIEWPORT_FLAG_GRIDLINES : VIEWPORT_FLAG_NONE;
@@ -131,7 +130,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_banner_widgets;
+ SetWidgets(window_banner_widgets);
WindowInitScrollWidgets(*this);
}
@@ -279,13 +278,13 @@ namespace OpenRCT2::Ui::Windows
{
return;
}
- Widget* colourBtn = &window_banner_widgets[WIDX_MAIN_COLOUR];
- colourBtn->type = WindowWidgetType::Empty;
+ Widget& colourBtn = widgets[WIDX_MAIN_COLOUR];
+ colourBtn.type = WindowWidgetType::Empty;
auto* bannerEntry = OpenRCT2::ObjectManager::GetObjectEntry(banner->type);
if (bannerEntry != nullptr && (bannerEntry->flags & BANNER_ENTRY_FLAG_HAS_PRIMARY_COLOUR))
{
- colourBtn->type = WindowWidgetType::ColourBtn;
+ colourBtn.type = WindowWidgetType::ColourBtn;
}
pressed_widgets &= ~(1uLL << WIDX_BANNER_NO_ENTRY);
disabled_widgets &= ~(
@@ -296,9 +295,9 @@ namespace OpenRCT2::Ui::Windows
disabled_widgets |= (1uLL << WIDX_BANNER_TEXT) | (1uLL << WIDX_TEXT_COLOUR_DROPDOWN)
| (1uLL << WIDX_TEXT_COLOUR_DROPDOWN_BUTTON);
}
- colourBtn->image = GetColourButtonImage(banner->colour);
- Widget* dropDownWidget = &window_banner_widgets[WIDX_TEXT_COLOUR_DROPDOWN];
- dropDownWidget->text = BannerColouredTextFormats[banner->text_colour];
+ colourBtn.image = GetColourButtonImage(banner->colour);
+ Widget& dropDownWidget = widgets[WIDX_TEXT_COLOUR_DROPDOWN];
+ dropDownWidget.text = BannerColouredTextFormats[banner->text_colour];
}
void OnResize() override
diff --git a/src/openrct2-ui/windows/Changelog.cpp b/src/openrct2-ui/windows/Changelog.cpp
index 7de4e4703e..a77331bdbf 100644
--- a/src/openrct2-ui/windows/Changelog.cpp
+++ b/src/openrct2-ui/windows/Changelog.cpp
@@ -47,7 +47,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({0, 14}, {500, 382}, WindowWidgetType::Resize, WindowColour::Secondary ), // content panel
MakeWidget({3, 16}, {495, 366}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_BOTH ), // scroll area
MakeWidget({3, 473}, {300, 14}, WindowWidgetType::Placeholder, WindowColour::Secondary, STR_NEW_RELEASE_DOWNLOAD_PAGE), // changelog button
- kWidgetsEnd,
};
// clang-format on
@@ -125,7 +124,7 @@ namespace OpenRCT2::Ui::Windows
void OnOpen() override
{
- widgets = _windowChangelogWidgets;
+ SetWidgets(_windowChangelogWidgets);
WindowInitScrollWidgets(*this);
min_width = MIN_WW;
diff --git a/src/openrct2-ui/windows/Cheats.cpp b/src/openrct2-ui/windows/Cheats.cpp
index 91773863e4..f294b55ac6 100644
--- a/src/openrct2-ui/windows/Cheats.cpp
+++ b/src/openrct2-ui/windows/Cheats.cpp
@@ -219,7 +219,7 @@ static constexpr int32_t TAB_START = 3;
MakeTab ({158, 17}, STR_RIDE_CHEATS_TIP ), /* tab 4 */ \
MakeTab ({189, 17}, STR_WEATHER_NATURE_CHEATS_TIP ) /* tab 7 */
-static Widget window_cheats_money_widgets[] =
+static constexpr Widget window_cheats_money_widgets[] =
{
MAIN_CHEATS_WIDGETS,
MakeWidget ({ 11, 48}, CHEAT_BUTTON, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_MAKE_PARK_NO_MONEY), // No money
@@ -228,10 +228,9 @@ static Widget window_cheats_money_widgets[] =
MakeWidget ({ 11, 111}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_ADD_MONEY ), // add money
MakeWidget ({127, 111}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_SET_MONEY ), // set money
MakeWidget ({ 11, 145}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_CHEAT_CLEAR_LOAN ), // Clear loan
- kWidgetsEnd,
};
-static Widget window_cheats_date_widgets[] =
+static constexpr Widget window_cheats_date_widgets[] =
{
MAIN_CHEATS_WIDGETS,
MakeWidget ({ 5, 48}, {238, 99} , WindowWidgetType::Groupbox, WindowColour::Secondary, STR_DATE_SET ), // Date group
@@ -240,10 +239,9 @@ static Widget window_cheats_date_widgets[] =
MakeSpinnerWidgets({120, 103}, CHEAT_SPINNER, WindowWidgetType::Spinner, WindowColour::Secondary ), // Day box
MakeWidget ({ 11, 122}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_DATE_SET ), // Set Date
MakeWidget ({127, 122}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_DATE_RESET), // Reset Date
- kWidgetsEnd,
};
-static Widget window_cheats_guests_widgets[] =
+static constexpr Widget window_cheats_guests_widgets[] =
{
MAIN_CHEATS_WIDGETS,
MakeWidget({ 11, 48}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_CHEAT_LARGE_TRAM_GUESTS, STR_CHEAT_LARGE_TRAM_GUESTS_TIP), // large tram
@@ -278,11 +276,9 @@ static Widget window_cheats_guests_widgets[] =
MakeWidget({ 11, 380+1}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_IGNORE_PRICE, STR_CHEAT_IGNORE_PRICE_TIP ), // guests ignore price
MakeWidget({ 11, 397+1}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_DISABLE_VANDALISM, STR_CHEAT_DISABLE_VANDALISM_TIP), // disable vandalism
MakeWidget({ 11, 414+1}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_DISABLE_LITTERING, STR_CHEAT_DISABLE_LITTERING_TIP), // disable littering
-
- kWidgetsEnd,
};
-static Widget window_cheats_staff_widgets[] =
+static constexpr Widget window_cheats_staff_widgets[] =
{
MAIN_CHEATS_WIDGETS,
MakeWidget ({ 5, 357-309}, {238, 35}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_CHEAT_STAFF_GROUP ), // Staff group
@@ -296,11 +292,9 @@ static Widget window_cheats_staff_widgets[] =
MakeWidget ({127, 292-168}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_CHEAT_MOWED_GRASS ), // Mowed grass
MakeWidget ({ 11, 313-168}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_CHEAT_WATER_PLANTS ), // Water plants
MakeWidget ({ 11, 334-164}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_DISABLE_PLANT_AGING, STR_CHEAT_DISABLE_PLANT_AGING_TIP ), // Disable plant ageing
-
- kWidgetsEnd,
};
-static Widget window_cheats_park_widgets[] =
+static constexpr Widget window_cheats_park_widgets[] =
{
MAIN_CHEATS_WIDGETS,
MakeWidget ({ 5, 48}, {238, 60}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_CHEAT_GENERAL_GROUP ), // General group
@@ -319,11 +313,9 @@ static Widget window_cheats_park_widgets[] =
MakeWidget ({ 11, 207}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_BUILD_IN_PAUSE_MODE, STR_CHEAT_BUILD_IN_PAUSE_MODE_TIP ), // Build in pause mode
MakeWidget ({ 11, 224}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_ALLOW_PATH_AS_QUEUE, STR_CHEAT_ALLOW_PATH_AS_QUEUE_TIP ), // Allow regular footpaths as queue path
MakeWidget ({ 11, 241}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_ALLOW_SPECIAL_COLOUR_SCHEMES, STR_CHEAT_ALLOW_SPECIAL_COLOUR_SCHEMES_TIP), // Allow special colours in dropdown
-
- kWidgetsEnd,
};
-static Widget window_cheats_rides_widgets[] =
+static constexpr Widget window_cheats_rides_widgets[] =
{
MAIN_CHEATS_WIDGETS,
MakeWidget({ 11, 48}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_CHEAT_FIX_ALL_RIDES, STR_CHEAT_FIX_ALL_RIDES_TIP ), // Fix all rides
@@ -349,10 +341,9 @@ static Widget window_cheats_rides_widgets[] =
MakeWidget({ 11, 325}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_SHOW_VEHICLES_FROM_OTHER_TRACK_TYPES ), // Show vehicles from other track types
MakeWidget({ 11, 342}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_DISABLE_TRAIN_LENGTH_LIMIT, STR_CHEAT_DISABLE_TRAIN_LENGTH_LIMIT_TIP ), // Disable train length limits
MakeWidget({ 11, 359}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_IGNORE_RESEARCH_STATUS, STR_CHEAT_IGNORE_RESEARCH_STATUS_TIP ), // Ignore Research Status
- kWidgetsEnd,
};
-static Widget window_cheats_weather_widgets[] =
+static constexpr Widget window_cheats_weather_widgets[] =
{
MAIN_CHEATS_WIDGETS,
MakeWidget ({ 5, 48}, {238, 50}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_CHEAT_WEATHER_GROUP ), // Weather group
@@ -362,10 +353,9 @@ static Widget window_cheats_weather_widgets[] =
MakeWidget ({ 5, 102}, {238, 37}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_FAUNA ), // Fauna group
MakeWidget ({ 11, 115}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_CREATE_DUCKS, STR_CREATE_DUCKS_TIP ), // Create ducks
MakeWidget ({127, 115}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_REMOVE_DUCKS, STR_REMOVE_DUCKS_TIP ), // Remove ducks
- kWidgetsEnd,
};
-static Widget *window_cheats_page_widgets[] =
+static constexpr std::span window_cheats_page_widgets[] =
{
window_cheats_money_widgets,
window_cheats_date_widgets,
@@ -512,13 +502,6 @@ static StringId window_cheats_page_titles[] = {
void OnPrepareDraw() override
{
- auto* targetWidgets = window_cheats_page_widgets[page];
- if (widgets != targetWidgets)
- {
- widgets = targetWidgets;
- WindowInitScrollWidgets(*this);
- }
-
pressed_widgets = 0;
disabled_widgets = 0;
@@ -592,11 +575,16 @@ static StringId window_cheats_page_titles[] = {
}
// Current weather
- window_cheats_weather_widgets[WIDX_WEATHER].text = WeatherTypes[EnumValue(gameState.ClimateCurrent.Weather)];
+ if (page == WINDOW_CHEATS_PAGE_WEATHER)
+ {
+ widgets[WIDX_WEATHER].text = WeatherTypes[EnumValue(gameState.ClimateCurrent.Weather)];
+ }
// Staff speed
- window_cheats_staff_widgets[WIDX_STAFF_SPEED].text = _staffSpeedNames[EnumValue(
- gameState.Cheats.selectedStaffSpeed)];
+ if (page == WINDOW_CHEATS_PAGE_STAFF)
+ {
+ widgets[WIDX_STAFF_SPEED].text = _staffSpeedNames[EnumValue(gameState.Cheats.selectedStaffSpeed)];
+ }
if (gScreenFlags & SCREEN_FLAGS_EDITOR)
{
@@ -753,18 +741,18 @@ static StringId window_cheats_page_titles[] = {
hold_down_widgets = window_cheats_page_hold_down_widgets[p];
pressed_widgets = 0;
- widgets = window_cheats_page_widgets[p];
+ SetWidgets(window_cheats_page_widgets[p]);
auto maxY = 0;
- auto* widget = &widgets[WIDX_TAB_CONTENT];
- while (widget->type != WindowWidgetType::Last)
+ for (WidgetIndex widgetIdx = WIDX_TAB_CONTENT; widgetIdx < widgets.size(); widgetIdx++)
{
- maxY = std::max(maxY, widget->bottom);
- widget++;
+ auto& widget = widgets[widgetIdx];
+ maxY = std::max(maxY, widget.bottom);
}
maxY += 6;
Invalidate();
+ WindowInitScrollWidgets(*this);
height = maxY;
widgets[WIDX_BACKGROUND].bottom = maxY - 1;
widgets[WIDX_PAGE_BACKGROUND].bottom = maxY - 1;
diff --git a/src/openrct2-ui/windows/ClearScenery.cpp b/src/openrct2-ui/windows/ClearScenery.cpp
index 07340aa792..7749b36ef7 100644
--- a/src/openrct2-ui/windows/ClearScenery.cpp
+++ b/src/openrct2-ui/windows/ClearScenery.cpp
@@ -44,7 +44,7 @@ namespace OpenRCT2::Ui::Windows
static constexpr ScreenSize CLEAR_SCENERY_BUTTON = { 24, 24 };
- static Widget window_clear_scenery_widgets[] = {
+ static constexpr Widget window_clear_scenery_widgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget(
{ 27, 17 }, { 44, 32 }, WindowWidgetType::ImgBtn, WindowColour::Primary, SPR_LAND_TOOL_SIZE_0,
@@ -64,7 +64,6 @@ namespace OpenRCT2::Ui::Windows
MakeRemapWidget(
{ 67, 53 }, CLEAR_SCENERY_BUTTON, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_G2_BUTTON_FOOTPATH,
STR_CLEAR_SCENERY_REMOVE_FOOTPATHS_TIP), // footpaths
- kWidgetsEnd,
};
class CleanSceneryWindow final : public Window
@@ -78,7 +77,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_clear_scenery_widgets;
+ SetWidgets(window_clear_scenery_widgets);
hold_down_widgets = (1uLL << WIDX_INCREMENT) | (1uLL << WIDX_DECREMENT);
WindowInitScrollWidgets(*this);
WindowPushOthersBelow(*this);
@@ -178,7 +177,7 @@ namespace OpenRCT2::Ui::Windows
| (_clearLargeScenery ? (1uLL << WIDX_LARGE_SCENERY) : 0) | (_clearFootpath ? (1uLL << WIDX_FOOTPATH) : 0);
// Update the preview image (for tool sizes up to 7)
- window_clear_scenery_widgets[WIDX_PREVIEW].image = ImageId(LandTool::SizeToSpriteIndex(gLandToolSize));
+ widgets[WIDX_PREVIEW].image = ImageId(LandTool::SizeToSpriteIndex(gLandToolSize));
}
void OnDraw(DrawPixelInfo& dpi) override
@@ -186,8 +185,8 @@ namespace OpenRCT2::Ui::Windows
DrawWidgets(dpi);
// Draw number for tool sizes bigger than 7
- ScreenCoordsXY screenCoords = { windowPos.x + window_clear_scenery_widgets[WIDX_PREVIEW].midX(),
- windowPos.y + window_clear_scenery_widgets[WIDX_PREVIEW].midY() };
+ ScreenCoordsXY screenCoords = { windowPos.x + widgets[WIDX_PREVIEW].midX(),
+ windowPos.y + widgets[WIDX_PREVIEW].midY() };
if (gLandToolSize > kLandToolMaximumSizeWithSprite)
{
auto ft = Formatter();
@@ -202,8 +201,8 @@ namespace OpenRCT2::Ui::Windows
{
auto ft = Formatter();
ft.Add(_clearSceneryCost);
- screenCoords.x = window_clear_scenery_widgets[WIDX_PREVIEW].midX() + windowPos.x;
- screenCoords.y = window_clear_scenery_widgets[WIDX_PREVIEW].bottom + windowPos.y + 5 + 27;
+ screenCoords.x = widgets[WIDX_PREVIEW].midX() + windowPos.x;
+ screenCoords.y = widgets[WIDX_PREVIEW].bottom + windowPos.y + 5 + 27;
DrawTextBasic(dpi, screenCoords, STR_COST_AMOUNT, ft, { TextAlignment::CENTRE });
}
}
diff --git a/src/openrct2-ui/windows/CustomCurrency.cpp b/src/openrct2-ui/windows/CustomCurrency.cpp
index 8392d986fc..ef5ae15b85 100644
--- a/src/openrct2-ui/windows/CustomCurrency.cpp
+++ b/src/openrct2-ui/windows/CustomCurrency.cpp
@@ -45,7 +45,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({120, 50}, { 81, 11}, WindowWidgetType::Button, WindowColour::Secondary, STR_EMPTY ),
MakeWidget ({220, 50}, {131, 11}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ),
MakeWidget ({339, 51}, { 11, 9}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH ),
- kWidgetsEnd,
};
// clang-format on
@@ -54,7 +53,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_custom_currency_widgets;
+ SetWidgets(window_custom_currency_widgets);
hold_down_widgets = (1uLL << WIDX_RATE_UP) | (1uLL << WIDX_RATE_DOWN);
WindowInitScrollWidgets(*this);
colours[0] = COLOUR_LIGHT_BROWN;
@@ -208,15 +207,12 @@ namespace OpenRCT2::Ui::Windows
DrawTextBasic(dpi, screenCoords, STR_CURRENCY_SYMBOL_TEXT, {}, { colours[1] });
- screenCoords = windowPos
- + ScreenCoordsXY{ window_custom_currency_widgets[WIDX_SYMBOL_TEXT].left + 1,
- window_custom_currency_widgets[WIDX_SYMBOL_TEXT].top };
+ screenCoords = windowPos + ScreenCoordsXY{ widgets[WIDX_SYMBOL_TEXT].left + 1, widgets[WIDX_SYMBOL_TEXT].top };
DrawText(dpi, screenCoords, { colours[1] }, CurrencyDescriptors[EnumValue(CurrencyType::Custom)].symbol_unicode);
auto drawPos = windowPos
- + ScreenCoordsXY{ window_custom_currency_widgets[WIDX_AFFIX_DROPDOWN].left + 1,
- window_custom_currency_widgets[WIDX_AFFIX_DROPDOWN].top };
+ + ScreenCoordsXY{ widgets[WIDX_AFFIX_DROPDOWN].left + 1, widgets[WIDX_AFFIX_DROPDOWN].top };
StringId stringId = (CurrencyDescriptors[EnumValue(CurrencyType::Custom)].affix_unicode == CurrencyAffix::Prefix)
? STR_PREFIX
: STR_SUFFIX;
diff --git a/src/openrct2-ui/windows/DebugPaint.cpp b/src/openrct2-ui/windows/DebugPaint.cpp
index 50bdd1a302..0973e14888 100644
--- a/src/openrct2-ui/windows/DebugPaint.cpp
+++ b/src/openrct2-ui/windows/DebugPaint.cpp
@@ -34,7 +34,7 @@ namespace OpenRCT2::Ui::Windows
constexpr int32_t WINDOW_HEIGHT = 8 + (15 * 6) + 8;
// clang-format off
- static Widget window_debug_paint_widgets[] = {
+ static constexpr Widget window_debug_paint_widgets[] = {
MakeWidget({0, 0}, {WINDOW_WIDTH, WINDOW_HEIGHT}, WindowWidgetType::Frame, WindowColour::Primary ),
MakeWidget({8, 8 + 15 * 0}, { 185, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_DEBUG_PAINT_SHOW_WIDE_PATHS ),
MakeWidget({8, 8 + 15 * 1}, { 185, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_DEBUG_PAINT_SHOW_BLOCKED_TILES ),
@@ -42,7 +42,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({8, 8 + 15 * 3}, { 185, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_DEBUG_PAINT_SHOW_BOUND_BOXES ),
MakeWidget({8, 8 + 15 * 4}, { 185, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_DEBUG_PAINT_SHOW_DIRTY_VISUALS ),
MakeWidget({8, 8 + 15 * 5}, { 185, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_DEBUG_PAINT_STABLE_SORT ),
- kWidgetsEnd,
};
// clang-format on
@@ -54,7 +53,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_debug_paint_widgets;
+ SetWidgets(window_debug_paint_widgets);
InitScrollWidgets();
WindowPushOthersBelow(*this);
diff --git a/src/openrct2-ui/windows/DemolishRidePrompt.cpp b/src/openrct2-ui/windows/DemolishRidePrompt.cpp
index 2a5691fe19..1ae9cdc9b8 100644
--- a/src/openrct2-ui/windows/DemolishRidePrompt.cpp
+++ b/src/openrct2-ui/windows/DemolishRidePrompt.cpp
@@ -35,12 +35,11 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget window_ride_demolish_widgets[] =
+ static constexpr Widget window_ride_demolish_widgets[] =
{
WINDOW_SHIM_WHITE(STR_DEMOLISH_RIDE, WW, WH),
MakeWidget({ 10, WH - 22}, {85, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_DEMOLISH ),
MakeWidget({WW - 95, WH - 22}, {85, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_SAVE_PROMPT_CANCEL),
- kWidgetsEnd,
};
// clang-format on
@@ -57,7 +56,7 @@ namespace OpenRCT2::Ui::Windows
void OnOpen() override
{
- widgets = window_ride_demolish_widgets;
+ SetWidgets(window_ride_demolish_widgets);
WindowInitScrollWidgets(*this);
}
diff --git a/src/openrct2-ui/windows/Dropdown.cpp b/src/openrct2-ui/windows/Dropdown.cpp
index 34a87d4819..0a46a16f4c 100644
--- a/src/openrct2-ui/windows/Dropdown.cpp
+++ b/src/openrct2-ui/windows/Dropdown.cpp
@@ -41,9 +41,8 @@ namespace OpenRCT2::Ui::Windows
WIDX_BACKGROUND,
};
- static Widget window_dropdown_widgets[] = {
+ static constexpr Widget window_dropdown_widgets[] = {
MakeWidget({ 0, 0 }, { 1, 1 }, WindowWidgetType::ImgBtn, WindowColour::Primary),
- kWidgetsEnd,
};
int32_t gDropdownNumItems;
@@ -75,7 +74,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_dropdown_widgets;
+ SetWidgets(window_dropdown_widgets);
// Input state
gDropdownHighlightedIndex = -1;
@@ -295,8 +294,8 @@ namespace OpenRCT2::Ui::Windows
boundedScreenPos.x = std::max(0, screenWidth - ddWidth);
if (screenPos.y + ddHeight > screenHeight)
boundedScreenPos.y = std::max(0, screenHeight - ddHeight);
- window_dropdown_widgets[WIDX_BACKGROUND].right = ddWidth;
- window_dropdown_widgets[WIDX_BACKGROUND].bottom = ddHeight;
+ widgets[WIDX_BACKGROUND].right = ddWidth;
+ widgets[WIDX_BACKGROUND].bottom = ddHeight;
Invalidate();
width = ddWidth + 1;
diff --git a/src/openrct2-ui/windows/EditorBottomToolbar.cpp b/src/openrct2-ui/windows/EditorBottomToolbar.cpp
index 3d66604bf8..47ccc32949 100644
--- a/src/openrct2-ui/windows/EditorBottomToolbar.cpp
+++ b/src/openrct2-ui/windows/EditorBottomToolbar.cpp
@@ -38,12 +38,11 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget _editorBottomToolbarWidgets[] = {
+ static constexpr Widget _editorBottomToolbarWidgets[] = {
MakeWidget({ 0, 0}, {200, 34}, WindowWidgetType::ImgBtn, WindowColour::Primary),
MakeWidget({ 2, 2}, {196, 30}, WindowWidgetType::FlatBtn, WindowColour::Primary),
MakeWidget({440, 0}, {200, 34}, WindowWidgetType::ImgBtn, WindowColour::Primary),
MakeWidget({442, 2}, {196, 30}, WindowWidgetType::FlatBtn, WindowColour::Primary),
- kWidgetsEnd,
};
// clang-format on
@@ -62,7 +61,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = _editorBottomToolbarWidgets;
+ SetWidgets(_editorBottomToolbarWidgets);
InitScrollWidgets();
SetAllSceneryItemsInvented();
diff --git a/src/openrct2-ui/windows/EditorInventionsList.cpp b/src/openrct2-ui/windows/EditorInventionsList.cpp
index ca76110308..14819b9bc6 100644
--- a/src/openrct2-ui/windows/EditorInventionsList.cpp
+++ b/src/openrct2-ui/windows/EditorInventionsList.cpp
@@ -54,7 +54,7 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget _inventionListWidgets[] = {
+ static constexpr Widget _inventionListWidgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({ 0, 43}, {600, 357}, WindowWidgetType::Resize, WindowColour::Secondary ),
MakeTab ({ 3, 17} ),
@@ -64,12 +64,10 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({375, 343}, {220, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_MOVE_ALL_TOP ),
MakeWidget({375, 358}, {220, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_MOVE_ALL_BOTTOM ),
MakeWidget({375, 373}, {220, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_RANDOM_SHUFFLE, STR_RANDOM_SHUFFLE_TIP),
- kWidgetsEnd,
};
- static Widget _inventionListDragWidgets[] = {
+ static constexpr Widget _inventionListDragWidgets[] = {
MakeWidget({0, 0}, {150, 14}, WindowWidgetType::ImgBtn, WindowColour::Primary),
- kWidgetsEnd,
};
// clang-format on
@@ -154,7 +152,7 @@ namespace OpenRCT2::Ui::Windows
{
ResearchRidesSetup();
- widgets = _inventionListWidgets;
+ SetWidgets(_inventionListWidgets);
InitScrollWidgets();
selected_tab = 0;
_selectedResearchItem = nullptr;
@@ -611,7 +609,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = _inventionListDragWidgets;
+ SetWidgets(_inventionListDragWidgets);
colours[1] = COLOUR_WHITE;
}
diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp
index 4c19602a2f..092e3e7de2 100644
--- a/src/openrct2-ui/windows/EditorObjectSelection.cpp
+++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp
@@ -226,10 +226,8 @@ namespace OpenRCT2::Ui::Windows
validate_global_widx(WC_EDITOR_OBJECT_SELECTION, WIDX_TAB_1);
- static bool _window_editor_object_selection_widgets_initialised;
-
// clang-format off
- static std::vector _window_editor_object_selection_widgets = {
+ static constexpr Widget _window_editor_object_selection_widgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget ({ 0, 43}, {WW, 357}, WindowWidgetType::Resize, WindowColour::Secondary ),
MakeWidget ({ 4, 60}, {288, 277}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL ),
@@ -251,8 +249,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({700, 50}, { 24, 24}, WindowWidgetType::ImgBtn, WindowColour::Secondary, SPR_G2_RELOAD, STR_RELOAD_OBJECT_TIP ),
MakeTab ({ 3, 17}, STR_STRING_DEFINED_TOOLTIP ),
// Copied object type times...
-
- kWidgetsEnd,
};
// clang-format on
@@ -1138,20 +1134,20 @@ namespace OpenRCT2::Ui::Windows
}
private:
+ bool tabWidgetsInitialised = false;
+
void InitWidgets()
{
- auto& targetWidgets = _window_editor_object_selection_widgets;
- if (!_window_editor_object_selection_widgets_initialised)
+ SetWidgets(_window_editor_object_selection_widgets);
+ if (!tabWidgetsInitialised)
{
- _window_editor_object_selection_widgets_initialised = true;
- auto tabWidget = targetWidgets[targetWidgets.size() - 2];
+ tabWidgetsInitialised = true;
+ auto tabWidget = widgets[WIDX_TAB_1];
for (size_t i = 1; i < std::size(ObjectSelectionPages); i++)
{
- targetWidgets.insert(targetWidgets.end() - 1, tabWidget);
+ widgets.insert(widgets.end() - 1, tabWidget);
}
}
-
- widgets = targetWidgets.data();
}
void SetPage(int32_t _page)
diff --git a/src/openrct2-ui/windows/EditorObjectiveOptions.cpp b/src/openrct2-ui/windows/EditorObjectiveOptions.cpp
index 050ff211fb..d920650264 100644
--- a/src/openrct2-ui/windows/EditorObjectiveOptions.cpp
+++ b/src/openrct2-ui/windows/EditorObjectiveOptions.cpp
@@ -117,7 +117,7 @@ namespace OpenRCT2::Ui::Windows
MakeTab ({ 3, 17}, STR_SELECT_OBJECTIVE_AND_PARK_NAME_TIP ), \
MakeTab ({ 34, 17}, STR_SELECT_RIDES_TO_BE_PRESERVED_TIP )
- static Widget window_editor_objective_options_main_widgets[] = {
+ static constexpr Widget window_editor_objective_options_main_widgets[] = {
MAIN_OBJECTIVE_OPTIONS_WIDGETS,
MakeWidget ({ 98, 48}, {344, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_NONE, STR_SELECT_OBJECTIVE_FOR_THIS_SCENARIO_TIP ),
MakeWidget ({430, 49}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_SELECT_OBJECTIVE_FOR_THIS_SCENARIO_TIP ),
@@ -128,16 +128,14 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({ 98, 133}, {180, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_NONE, STR_SELECT_WHICH_GROUP_THIS_SCENARIO_APPEARS_IN),
MakeWidget ({266, 134}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_SELECT_WHICH_GROUP_THIS_SCENARIO_APPEARS_IN),
MakeWidget ({370, 150}, { 75, 12}, WindowWidgetType::Button, WindowColour::Secondary, STR_CHANGE, STR_CHANGE_DETAIL_NOTES_ABOUT_PARK_SCENARIO_TIP),
- kWidgetsEnd,
};
- static Widget window_editor_objective_options_rides_widgets[] = {
+ static constexpr Widget window_editor_objective_options_rides_widgets[] = {
MAIN_OBJECTIVE_OPTIONS_WIDGETS,
MakeWidget({ 3, 60}, {374, 161}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL),
- kWidgetsEnd,
};
- static Widget *window_editor_objective_options_widgets[] = {
+ static constexpr std::span window_editor_objective_options_widgets[] = {
window_editor_objective_options_main_widgets,
window_editor_objective_options_rides_widgets,
};
@@ -167,14 +165,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_editor_objective_options_main_widgets;
- pressed_widgets = 0;
- hold_down_widgets = window_editor_objective_options_page_hold_down_widgets
- [WINDOW_EDITOR_OBJECTIVE_OPTIONS_PAGE_MAIN];
- InitScrollWidgets();
- selected_tab = WINDOW_EDITOR_OBJECTIVE_OPTIONS_PAGE_MAIN;
- selected_list_item = -1;
- UpdateDisabledWidgets();
+ SetPage(WINDOW_EDITOR_OBJECTIVE_OPTIONS_PAGE_MAIN);
}
void OnMouseUp(WidgetIndex widgetIndex) override
@@ -313,15 +304,12 @@ namespace OpenRCT2::Ui::Windows
*/
void SetPage(int32_t newPage)
{
- if (page == newPage)
- return;
-
page = newPage;
frame_no = 0;
_rideableRides.clear();
selected_list_item = -1;
hold_down_widgets = window_editor_objective_options_page_hold_down_widgets[newPage];
- widgets = window_editor_objective_options_widgets[newPage];
+ SetWidgets(window_editor_objective_options_widgets[newPage]);
Invalidate();
UpdateDisabledWidgets();
OnResize();
@@ -819,12 +807,6 @@ namespace OpenRCT2::Ui::Windows
void OnPrepareDrawMain()
{
auto& gameState = GetGameState();
- auto widgetsToSet = window_editor_objective_options_widgets[page];
- if (widgets != widgetsToSet)
- {
- widgets = widgetsToSet;
- InitScrollWidgets();
- }
SetPressedTab();
@@ -832,12 +814,12 @@ namespace OpenRCT2::Ui::Windows
{
case OBJECTIVE_GUESTS_BY:
case OBJECTIVE_PARK_VALUE_BY:
- window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1].type = WindowWidgetType::Spinner;
- window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1_INCREASE].type = WindowWidgetType::Button;
- window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1_DECREASE].type = WindowWidgetType::Button;
- window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2].type = WindowWidgetType::Spinner;
- window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2_INCREASE].type = WindowWidgetType::Button;
- window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2_DECREASE].type = WindowWidgetType::Button;
+ widgets[WIDX_OBJECTIVE_ARG_1].type = WindowWidgetType::Spinner;
+ widgets[WIDX_OBJECTIVE_ARG_1_INCREASE].type = WindowWidgetType::Button;
+ widgets[WIDX_OBJECTIVE_ARG_1_DECREASE].type = WindowWidgetType::Button;
+ widgets[WIDX_OBJECTIVE_ARG_2].type = WindowWidgetType::Spinner;
+ widgets[WIDX_OBJECTIVE_ARG_2_INCREASE].type = WindowWidgetType::Button;
+ widgets[WIDX_OBJECTIVE_ARG_2_DECREASE].type = WindowWidgetType::Button;
break;
case OBJECTIVE_GUESTS_AND_RATING:
case OBJECTIVE_MONTHLY_RIDE_INCOME:
@@ -845,26 +827,25 @@ namespace OpenRCT2::Ui::Windows
case OBJECTIVE_FINISH_5_ROLLERCOASTERS:
case OBJECTIVE_REPAY_LOAN_AND_PARK_VALUE:
case OBJECTIVE_MONTHLY_FOOD_INCOME:
- window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1].type = WindowWidgetType::Spinner;
- window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1_INCREASE].type = WindowWidgetType::Button;
- window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1_DECREASE].type = WindowWidgetType::Button;
- window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2].type = WindowWidgetType::Empty;
- window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2_INCREASE].type = WindowWidgetType::Empty;
- window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2_DECREASE].type = WindowWidgetType::Empty;
+ widgets[WIDX_OBJECTIVE_ARG_1].type = WindowWidgetType::Spinner;
+ widgets[WIDX_OBJECTIVE_ARG_1_INCREASE].type = WindowWidgetType::Button;
+ widgets[WIDX_OBJECTIVE_ARG_1_DECREASE].type = WindowWidgetType::Button;
+ widgets[WIDX_OBJECTIVE_ARG_2].type = WindowWidgetType::Empty;
+ widgets[WIDX_OBJECTIVE_ARG_2_INCREASE].type = WindowWidgetType::Empty;
+ widgets[WIDX_OBJECTIVE_ARG_2_DECREASE].type = WindowWidgetType::Empty;
break;
default:
- window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1].type = WindowWidgetType::Empty;
- window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1_INCREASE].type = WindowWidgetType::Empty;
- window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1_DECREASE].type = WindowWidgetType::Empty;
- window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2].type = WindowWidgetType::Empty;
- window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2_INCREASE].type = WindowWidgetType::Empty;
- window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2_DECREASE].type = WindowWidgetType::Empty;
+ widgets[WIDX_OBJECTIVE_ARG_1].type = WindowWidgetType::Empty;
+ widgets[WIDX_OBJECTIVE_ARG_1_INCREASE].type = WindowWidgetType::Empty;
+ widgets[WIDX_OBJECTIVE_ARG_1_DECREASE].type = WindowWidgetType::Empty;
+ widgets[WIDX_OBJECTIVE_ARG_2].type = WindowWidgetType::Empty;
+ widgets[WIDX_OBJECTIVE_ARG_2_INCREASE].type = WindowWidgetType::Empty;
+ widgets[WIDX_OBJECTIVE_ARG_2_DECREASE].type = WindowWidgetType::Empty;
break;
}
- window_editor_objective_options_main_widgets[WIDX_CLOSE].type = (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR)
- ? WindowWidgetType::Empty
- : WindowWidgetType::CloseBox;
+ widgets[WIDX_CLOSE].type = (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) ? WindowWidgetType::Empty
+ : WindowWidgetType::CloseBox;
AnchorBorderWidgets();
}
@@ -1110,18 +1091,10 @@ namespace OpenRCT2::Ui::Windows
*/
void OnPrepareDrawRides()
{
- Widget* widgetsToSet = window_editor_objective_options_widgets[page];
- if (widgets != widgetsToSet)
- {
- widgets = widgetsToSet;
- InitScrollWidgets();
- }
-
SetPressedTab();
- window_editor_objective_options_main_widgets[WIDX_CLOSE].type = (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR)
- ? WindowWidgetType::Empty
- : WindowWidgetType::CloseBox;
+ widgets[WIDX_CLOSE].type = (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) ? WindowWidgetType::Empty
+ : WindowWidgetType::CloseBox;
AnchorBorderWidgets();
}
diff --git a/src/openrct2-ui/windows/EditorParkEntrance.cpp b/src/openrct2-ui/windows/EditorParkEntrance.cpp
index b316daccf9..90ef9fa509 100644
--- a/src/openrct2-ui/windows/EditorParkEntrance.cpp
+++ b/src/openrct2-ui/windows/EditorParkEntrance.cpp
@@ -63,7 +63,6 @@ namespace OpenRCT2::Ui::Windows
MakeTab ({ 3, 17 }, STR_NONE ),
MakeWidget ({ 2, 45 }, { kScrollWidth, kScrollHeight }, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL ),
MakeWidget ({ kWindowWidth - 26, 59 }, { 24, 24 }, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_ROTATE_ARROW), STR_ROTATE_OBJECTS_90 ),
- kWidgetsEnd,
};
// clang-format on
@@ -240,7 +239,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = _widgets;
+ SetWidgets(_widgets);
InitScrollWidgets();
InitParkEntranceItems();
diff --git a/src/openrct2-ui/windows/EditorScenarioOptions.cpp b/src/openrct2-ui/windows/EditorScenarioOptions.cpp
index b999ca04ef..e70fd52cec 100644
--- a/src/openrct2-ui/windows/EditorScenarioOptions.cpp
+++ b/src/openrct2-ui/windows/EditorScenarioOptions.cpp
@@ -123,7 +123,7 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget window_editor_scenario_options_financial_widgets[] = {
+ static constexpr Widget window_editor_scenario_options_financial_widgets[] = {
WINDOW_SHIM(STR_SCENARIO_OPTIONS_FINANCIAL, WW_FINANCIAL, WH_FINANCIAL),
MakeWidget ({ 0, 43}, { WW_FINANCIAL, 106}, WindowWidgetType::Resize, WindowColour::Secondary ),
MakeTab ({ 3, 17}, STR_SCENARIO_OPTIONS_FINANCIAL_TIP),
@@ -136,10 +136,9 @@ namespace OpenRCT2::Ui::Windows
MakeSpinnerWidgets({168, 116}, { 70, 12}, WindowWidgetType::Spinner, WindowColour::Secondary ), // NB: 3 widgets
MakeWidget ({ 8, 133}, {WW_FINANCIAL - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_FORBID_MARKETING, STR_FORBID_MARKETING_TIP ),
MakeWidget ({ 8, 116}, {WW_FINANCIAL - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_RCT1_INTEREST, STR_RCT1_INTEREST_TIP ),
- kWidgetsEnd,
};
- static Widget window_editor_scenario_options_guests_widgets[] = {
+ static constexpr Widget window_editor_scenario_options_guests_widgets[] = {
WINDOW_SHIM(STR_SCENARIO_OPTIONS_GUESTS, WW_GUESTS, WH_GUESTS),
MakeWidget ({ 0, 43}, { WW_GUESTS, 106}, WindowWidgetType::Resize, WindowColour::Secondary),
MakeRemapWidget ({ 3, 17}, { 31, 27}, WindowWidgetType::Tab, WindowColour::Secondary, SPR_TAB, STR_SCENARIO_OPTIONS_FINANCIAL_TIP ),
@@ -151,10 +150,9 @@ namespace OpenRCT2::Ui::Windows
MakeSpinnerWidgets({268, 99}, { 70, 12}, WindowWidgetType::Spinner, WindowColour::Secondary ), // NB: 3 widgets
MakeWidget ({ 8, 116}, {WW_GUESTS - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_GUESTS_PREFER_LESS_INTENSE_RIDES, STR_GUESTS_PREFER_LESS_INTENSE_RIDES_TIP),
MakeWidget ({ 8, 133}, {WW_GUESTS - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_GUESTS_PREFER_MORE_INTENSE_RIDES, STR_GUESTS_PREFER_MORE_INTENSE_RIDES_TIP),
- kWidgetsEnd,
};
- static Widget window_editor_scenario_options_park_widgets[] = {
+ static constexpr Widget window_editor_scenario_options_park_widgets[] = {
WINDOW_SHIM(STR_SCENARIO_OPTIONS_PARK, WW_PARK, WH_PARK),
MakeWidget ({ 0, 43}, { WW_PARK, 106}, WindowWidgetType::Resize, WindowColour::Secondary ),
MakeRemapWidget ({ 3, 17}, { 31, 27}, WindowWidgetType::Tab, WindowColour::Secondary, SPR_TAB, STR_SCENARIO_OPTIONS_FINANCIAL_TIP),
@@ -172,10 +170,9 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({ 8, 150}, {WW_PARK - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_FORBID_HIGH_CONSTRUCTION, STR_FORBID_HIGH_CONSTRUCTION_TIP ),
MakeWidget ({ 8, 167}, {WW_PARK - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_HARD_PARK_RATING, STR_HARD_PARK_RATING_TIP ),
MakeWidget ({ 8, 184}, {WW_PARK - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_HARD_GUEST_GENERATION, STR_HARD_GUEST_GENERATION_TIP ),
- kWidgetsEnd,
};
- static Widget *window_editor_scenario_options_widgets[] = {
+ static constexpr std::span window_editor_scenario_options_widgets[] = {
window_editor_scenario_options_financial_widgets,
window_editor_scenario_options_guests_widgets,
window_editor_scenario_options_park_widgets,
@@ -218,11 +215,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_editor_scenario_options_widgets[WINDOW_EDITOR_SCENARIO_OPTIONS_PAGE_FINANCIAL];
- hold_down_widgets = window_editor_scenario_options_page_hold_down_widgets
- [WINDOW_EDITOR_SCENARIO_OPTIONS_PAGE_FINANCIAL];
- WindowInitScrollWidgets(*this);
- page = 0;
+ SetPage(WINDOW_EDITOR_SCENARIO_OPTIONS_PAGE_FINANCIAL);
}
void OnMouseUp(WidgetIndex widgetIndex) override
@@ -355,17 +348,14 @@ namespace OpenRCT2::Ui::Windows
void SetPage(int32_t newPage)
{
- if (page == newPage)
- return;
-
page = newPage;
frame_no = 0;
hold_down_widgets = window_editor_scenario_options_page_hold_down_widgets[page];
- widgets = window_editor_scenario_options_widgets[page];
+ SetWidgets(window_editor_scenario_options_widgets[page]);
Invalidate();
OnResize();
OnPrepareDraw();
- WindowInitScrollWidgets(*this);
+ InitScrollWidgets();
Invalidate();
}
@@ -561,13 +551,6 @@ namespace OpenRCT2::Ui::Windows
void FinancialPrepareDraw()
{
- Widget* newWidgets = window_editor_scenario_options_widgets[page];
- if (widgets != newWidgets)
- {
- widgets = newWidgets;
- WindowInitScrollWidgets(*this);
- }
-
SetPressedTab();
auto& gameState = GetGameState();
@@ -841,13 +824,6 @@ namespace OpenRCT2::Ui::Windows
void GuestsPrepareDraw()
{
- Widget* newWidgets = window_editor_scenario_options_widgets[page];
- if (widgets != newWidgets)
- {
- widgets = newWidgets;
- WindowInitScrollWidgets(*this);
- }
-
SetPressedTab();
auto& gameState = GetGameState();
@@ -1147,13 +1123,6 @@ namespace OpenRCT2::Ui::Windows
void ParkPrepareDraw()
{
- Widget* newWidgets = window_editor_scenario_options_widgets[page];
- if (widgets != newWidgets)
- {
- widgets = newWidgets;
- WindowInitScrollWidgets(*this);
- }
-
SetPressedTab();
auto& gameState = GetGameState();
diff --git a/src/openrct2-ui/windows/Error.cpp b/src/openrct2-ui/windows/Error.cpp
index 4bc26497ac..47d8686099 100644
--- a/src/openrct2-ui/windows/Error.cpp
+++ b/src/openrct2-ui/windows/Error.cpp
@@ -30,9 +30,8 @@ namespace OpenRCT2::Ui::Windows
static constexpr auto kMaxWidth = 250;
static constexpr auto kPadding = 4;
- static Widget window_error_widgets[] = {
+ static constexpr Widget window_error_widgets[] = {
MakeWidget({ 0, 0 }, { 200, 42 }, WindowWidgetType::Frame, WindowColour::Primary),
- kWidgetsEnd,
};
class ErrorWindow final : public Window
@@ -53,10 +52,11 @@ namespace OpenRCT2::Ui::Windows
void OnOpen() override
{
- window_error_widgets[WIDX_BACKGROUND].right = width - 1;
- window_error_widgets[WIDX_BACKGROUND].bottom = height - 1;
+ SetWidgets(window_error_widgets);
+
+ widgets[WIDX_BACKGROUND].right = width - 1;
+ widgets[WIDX_BACKGROUND].bottom = height - 1;
- widgets = window_error_widgets;
_staleCount = 0;
if (!gDisableErrorWindowSound)
diff --git a/src/openrct2-ui/windows/Finances.cpp b/src/openrct2-ui/windows/Finances.cpp
index 2e4eb431f6..045214ed34 100644
--- a/src/openrct2-ui/windows/Finances.cpp
+++ b/src/openrct2-ui/windows/Finances.cpp
@@ -108,33 +108,29 @@ namespace OpenRCT2::Ui::Windows
MakeTab({ 127, 17 }, STR_FINANCES_SHOW_MARKETING_TAB_TIP), \
MakeTab({ 158, 17 }, STR_FINANCES_RESEARCH_TIP)
- static Widget _windowFinancesSummaryWidgets[] =
+ static constexpr Widget _windowFinancesSummaryWidgets[] =
{
MAIN_FINANCES_WIDGETS(STR_FINANCIAL_SUMMARY, RSW_OTHER_TABS, RSH_SUMMARY, WW_OTHER_TABS, WH_SUMMARY),
MakeWidget ({130, 50}, {391, 211}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_HORIZONTAL ),
MakeSpinnerWidgets({ 64, 279}, { 97, 14}, WindowWidgetType::Spinner, WindowColour::Secondary, STR_FINANCES_SUMMARY_LOAN_VALUE), // NB: 3 widgets.
- kWidgetsEnd,
};
- static Widget _windowFinancesCashWidgets[] =
+ static constexpr Widget _windowFinancesCashWidgets[] =
{
MAIN_FINANCES_WIDGETS(STR_FINANCIAL_GRAPH, RSW_OTHER_TABS, RSH_OTHER_TABS, WW_OTHER_TABS, WH_OTHER_TABS),
- kWidgetsEnd,
};
- static Widget _windowFinancesParkValueWidgets[] =
+ static constexpr Widget _windowFinancesParkValueWidgets[] =
{
MAIN_FINANCES_WIDGETS(STR_PARK_VALUE_GRAPH, RSW_OTHER_TABS, RSH_OTHER_TABS, WW_OTHER_TABS, WH_OTHER_TABS),
- kWidgetsEnd,
};
- static Widget _windowFinancesProfitWidgets[] =
+ static constexpr Widget _windowFinancesProfitWidgets[] =
{
MAIN_FINANCES_WIDGETS(STR_PROFIT_GRAPH, RSW_OTHER_TABS, RSH_OTHER_TABS, WW_OTHER_TABS, WH_OTHER_TABS),
- kWidgetsEnd,
};
- static Widget _windowFinancesMarketingWidgets[] =
+ static constexpr Widget _windowFinancesMarketingWidgets[] =
{
MAIN_FINANCES_WIDGETS(STR_MARKETING, RSW_OTHER_TABS, RSH_OTHER_TABS, WW_OTHER_TABS, WH_OTHER_TABS),
MakeWidget({3, 47}, { WW_OTHER_TABS - 6, 45}, WindowWidgetType::Groupbox, WindowColour::Tertiary , STR_MARKETING_CAMPAIGNS_IN_OPERATION ),
@@ -145,10 +141,9 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({8, 0}, {WW_OTHER_TABS - 16, 14}, WindowWidgetType::ImgBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_START_THIS_MARKETING_CAMPAIGN),
MakeWidget({8, 0}, {WW_OTHER_TABS - 16, 14}, WindowWidgetType::ImgBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_START_THIS_MARKETING_CAMPAIGN),
MakeWidget({8, 0}, {WW_OTHER_TABS - 16, 14}, WindowWidgetType::ImgBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_START_THIS_MARKETING_CAMPAIGN),
- kWidgetsEnd,
};
- static Widget _windowFinancesResearchWidgets[] =
+ static constexpr Widget _windowFinancesResearchWidgets[] =
{
MAIN_FINANCES_WIDGETS(STR_RESEARCH_FUNDING, RSW_RESEARCH, RSH_RESEARCH, WW_RESEARCH, WH_RESEARCH),
MakeWidget({ 3, 47}, { WW_RESEARCH - 6, 45}, WindowWidgetType::Groupbox, WindowColour::Tertiary, STR_RESEARCH_FUNDING_ ),
@@ -162,11 +157,10 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({ 8, 160}, {WW_RESEARCH - 14, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary, STR_RESEARCH_NEW_WATER_RIDES, STR_RESEARCH_NEW_WATER_RIDES_TIP ),
MakeWidget({ 8, 173}, {WW_RESEARCH - 14, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary, STR_RESEARCH_NEW_SHOPS_AND_STALLS, STR_RESEARCH_NEW_SHOPS_AND_STALLS_TIP ),
MakeWidget({ 8, 186}, {WW_RESEARCH - 14, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary, STR_RESEARCH_NEW_SCENERY_AND_THEMING, STR_RESEARCH_NEW_SCENERY_AND_THEMING_TIP ),
- kWidgetsEnd,
};
// clang-format on
- static Widget* _windowFinancesPageWidgets[] = {
+ static constexpr std::span _windowFinancesPageWidgets[] = {
_windowFinancesSummaryWidgets, // WINDOW_FINANCES_PAGE_SUMMARY
_windowFinancesCashWidgets, // WINDOW_FINANCES_PAGE_FINANCIAL_GRAPH
_windowFinancesParkValueWidgets, // WINDOW_FINANCES_PAGE_VALUE_GRAPH
@@ -314,14 +308,6 @@ namespace OpenRCT2::Ui::Windows
void OnPrepareDraw() override
{
- auto* targetWidgets = _windowFinancesPageWidgets[page];
-
- if (widgets != targetWidgets)
- {
- widgets = targetWidgets;
- WindowInitScrollWidgets(*this);
- }
-
WindowAlignTabs(this, WIDX_TAB_1, WIDX_TAB_6);
for (auto i = 0; i < WINDOW_FINANCES_PAGE_COUNT; i++)
@@ -345,17 +331,17 @@ namespace OpenRCT2::Ui::Windows
return;
case WINDOW_FINANCES_PAGE_VALUE_GRAPH:
- graphPageWidget = &_windowFinancesParkValueWidgets[WIDX_PAGE_BACKGROUND];
+ graphPageWidget = &widgets[WIDX_PAGE_BACKGROUND];
centredGraph = false;
_graphProps.series = GetGameState().Park.ValueHistory;
break;
case WINDOW_FINANCES_PAGE_PROFIT_GRAPH:
- graphPageWidget = &_windowFinancesProfitWidgets[WIDX_PAGE_BACKGROUND];
+ graphPageWidget = &widgets[WIDX_PAGE_BACKGROUND];
centredGraph = true;
_graphProps.series = GetGameState().WeeklyProfitHistory;
break;
case WINDOW_FINANCES_PAGE_FINANCIAL_GRAPH:
- graphPageWidget = &_windowFinancesCashWidgets[WIDX_PAGE_BACKGROUND];
+ graphPageWidget = &widgets[WIDX_PAGE_BACKGROUND];
centredGraph = true;
_graphProps.series = GetGameState().CashHistory;
break;
@@ -500,7 +486,7 @@ namespace OpenRCT2::Ui::Windows
hold_down_widgets = _windowFinancesPageHoldDownWidgets[p];
pressed_widgets = 0;
- widgets = _windowFinancesPageWidgets[p];
+ SetWidgets(_windowFinancesPageWidgets[p]);
SetDisabledTabs();
Invalidate();
@@ -533,8 +519,7 @@ namespace OpenRCT2::Ui::Windows
}
OnResize();
OnPrepareDraw();
-
- WindowInitScrollWidgets(*this);
+ InitScrollWidgets();
// Scroll summary all the way to the right, initially.
if (p == WINDOW_FINANCES_PAGE_SUMMARY)
@@ -688,14 +673,14 @@ namespace OpenRCT2::Ui::Windows
int32_t y = std::max(1, numActiveCampaigns) * kListRowHeight + 92;
// Update group box positions
- _windowFinancesMarketingWidgets[WIDX_ACTIVE_CAMPAIGNS_GROUP].bottom = y - 22;
- _windowFinancesMarketingWidgets[WIDX_CAMPAIGNS_AVAILABLE_GROUP].top = y - 13;
+ widgets[WIDX_ACTIVE_CAMPAIGNS_GROUP].bottom = y - 22;
+ widgets[WIDX_CAMPAIGNS_AVAILABLE_GROUP].top = y - 13;
// Update new campaign button visibility
y += 3;
for (int32_t i = 0; i < ADVERTISING_CAMPAIGN_COUNT; i++)
{
- auto campaignButton = &_windowFinancesMarketingWidgets[WIDX_CAMPAIGN_1 + i];
+ auto campaignButton = &widgets[WIDX_CAMPAIGN_1 + i];
auto marketingCampaign = MarketingGetCampaign(i);
if (marketingCampaign == nullptr && MarketingIsCampaignTypeApplicable(i))
{
diff --git a/src/openrct2-ui/windows/Footpath.cpp b/src/openrct2-ui/windows/Footpath.cpp
index 1161868fd8..05e5a3f302 100644
--- a/src/openrct2-ui/windows/Footpath.cpp
+++ b/src/openrct2-ui/windows/Footpath.cpp
@@ -124,7 +124,7 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget window_footpath_widgets[] = {
+ static constexpr Widget window_footpath_widgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW_WINDOW, WH_WINDOW),
// Type group
@@ -152,7 +152,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({ 3, 361}, {100, 54}, WindowWidgetType::Groupbox, WindowColour::Primary ),
MakeWidget({13, 372}, { 36, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_CONSTRUCTION_FOOTPATH_LAND), STR_CONSTRUCT_FOOTPATH_ON_LAND_TIP ),
MakeWidget({57, 372}, { 36, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_CONSTRUCTION_FOOTPATH_BRIDGE), STR_CONSTRUCT_BRIDGE_OR_TUNNEL_FOOTPATH_TIP ),
- kWidgetsEnd,
};
#pragma endregion
@@ -215,7 +214,7 @@ namespace OpenRCT2::Ui::Windows
void OnOpen() override
{
- widgets = window_footpath_widgets;
+ SetWidgets(window_footpath_widgets);
WindowInitScrollWidgets(*this);
WindowPushOthersRight(*this);
@@ -275,13 +274,13 @@ namespace OpenRCT2::Ui::Windows
switch (widgetIndex)
{
case WIDX_FOOTPATH_TYPE:
- WindowFootpathShowFootpathTypesDialog(&window_footpath_widgets[widgetIndex], false);
+ WindowFootpathShowFootpathTypesDialog(&widgets[widgetIndex], false);
break;
case WIDX_QUEUELINE_TYPE:
- WindowFootpathShowFootpathTypesDialog(&window_footpath_widgets[widgetIndex], true);
+ WindowFootpathShowFootpathTypesDialog(&widgets[widgetIndex], true);
break;
case WIDX_RAILINGS_TYPE:
- WindowFootpathShowRailingsTypesDialog(&window_footpath_widgets[widgetIndex]);
+ WindowFootpathShowRailingsTypesDialog(&widgets[widgetIndex]);
break;
case WIDX_DIRECTION_NW:
WindowFootpathMousedownDirection(0);
@@ -452,17 +451,17 @@ namespace OpenRCT2::Ui::Windows
: (1uLL << WIDX_FOOTPATH_TYPE);
// Enable / disable construct button
- window_footpath_widgets[WIDX_CONSTRUCT].type = _footpathConstructionMode == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL
+ widgets[WIDX_CONSTRUCT].type = _footpathConstructionMode == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL
? WindowWidgetType::ImgBtn
: WindowWidgetType::Empty;
if (gFootpathSelection.LegacyPath == OBJECT_ENTRY_INDEX_NULL)
{
- window_footpath_widgets[WIDX_RAILINGS_TYPE].type = WindowWidgetType::FlatBtn;
+ widgets[WIDX_RAILINGS_TYPE].type = WindowWidgetType::FlatBtn;
}
else
{
- window_footpath_widgets[WIDX_RAILINGS_TYPE].type = WindowWidgetType::Empty;
+ widgets[WIDX_RAILINGS_TYPE].type = WindowWidgetType::Empty;
}
}
@@ -517,22 +516,19 @@ namespace OpenRCT2::Ui::Windows
// Draw construction image
screenCoords = this->windowPos
- + ScreenCoordsXY{ window_footpath_widgets[WIDX_CONSTRUCT].midX(),
- window_footpath_widgets[WIDX_CONSTRUCT].bottom - 60 };
+ + ScreenCoordsXY{ widgets[WIDX_CONSTRUCT].midX(), widgets[WIDX_CONSTRUCT].bottom - 60 };
GfxDrawSprite(dpi, ImageId(image), screenCoords);
}
// Draw build this... label
screenCoords = this->windowPos
- + ScreenCoordsXY{ window_footpath_widgets[WIDX_CONSTRUCT].midX(),
- window_footpath_widgets[WIDX_CONSTRUCT].bottom - 23 };
+ + ScreenCoordsXY{ widgets[WIDX_CONSTRUCT].midX(), widgets[WIDX_CONSTRUCT].bottom - 23 };
DrawTextBasic(dpi, screenCoords, STR_BUILD_THIS, {}, { TextAlignment::CENTRE });
}
// Draw cost
screenCoords = this->windowPos
- + ScreenCoordsXY{ window_footpath_widgets[WIDX_CONSTRUCT].midX(),
- window_footpath_widgets[WIDX_CONSTRUCT].bottom - 12 };
+ + ScreenCoordsXY{ widgets[WIDX_CONSTRUCT].midX(), widgets[WIDX_CONSTRUCT].bottom - 12 };
if (_windowFootpathCost != kMoney64Undefined)
{
if (!(GetGameState().Park.Flags & PARK_FLAGS_NO_MONEY))
diff --git a/src/openrct2-ui/windows/GameBottomToolbar.cpp b/src/openrct2-ui/windows/GameBottomToolbar.cpp
index 495ad09782..636c64f942 100644
--- a/src/openrct2-ui/windows/GameBottomToolbar.cpp
+++ b/src/openrct2-ui/windows/GameBottomToolbar.cpp
@@ -52,7 +52,7 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget window_game_bottom_toolbar_widgets[] =
+ static constexpr Widget window_game_bottom_toolbar_widgets[] =
{
MakeWidget({ 0, 0}, {142, 34}, WindowWidgetType::ImgBtn, WindowColour::Primary ), // Left outset panel
MakeWidget({ 2, 2}, {138, 30}, WindowWidgetType::ImgBtn, WindowColour::Primary ), // Left inset panel
@@ -68,7 +68,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({498, 0}, {142, 34}, WindowWidgetType::ImgBtn, WindowColour::Primary ), // Right outset panel
MakeWidget({500, 2}, {138, 30}, WindowWidgetType::ImgBtn, WindowColour::Primary ), // Right inset panel
MakeWidget({500, 2}, {138, 12}, WindowWidgetType::FlatBtn, WindowColour::Primary ), // Date
- kWidgetsEnd,
};
// clang-format on
@@ -87,12 +86,10 @@ namespace OpenRCT2::Ui::Windows
void DrawLeftPanel(DrawPixelInfo& dpi)
{
- const auto topLeft = windowPos
- + ScreenCoordsXY{ window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET].left + 1,
- window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET].top + 1 };
- const auto bottomRight = windowPos
- + ScreenCoordsXY{ window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET].right - 1,
- window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET].bottom - 1 };
+ const auto& leftPanelWidget = widgets[WIDX_LEFT_OUTSET];
+
+ const auto topLeft = windowPos + ScreenCoordsXY{ leftPanelWidget.left + 1, leftPanelWidget.top + 1 };
+ const auto bottomRight = windowPos + ScreenCoordsXY{ leftPanelWidget.right - 1, leftPanelWidget.bottom - 1 };
// Draw green inset rectangle on panel
GfxFillRectInset(dpi, { topLeft, bottomRight }, colours[1], INSET_RECT_F_30);
@@ -104,7 +101,7 @@ namespace OpenRCT2::Ui::Windows
// Draw money
if (!(gameState.Park.Flags & PARK_FLAGS_NO_MONEY))
{
- Widget widget = window_game_bottom_toolbar_widgets[WIDX_MONEY];
+ const auto& widget = widgets[WIDX_MONEY];
auto screenCoords = ScreenCoordsXY{ windowPos.x + widget.midX(),
windowPos.y + widget.midY() - (line_height == 10 ? 5 : 6) };
@@ -129,7 +126,7 @@ namespace OpenRCT2::Ui::Windows
// Draw guests
{
- Widget widget = window_game_bottom_toolbar_widgets[WIDX_GUESTS];
+ const auto& widget = widgets[WIDX_GUESTS];
auto screenCoords = ScreenCoordsXY{ windowPos.x + widget.midX(), windowPos.y + widget.midY() - 6 };
StringId stringId = gameState.NumGuestsInPark == 1 ? _guestCountFormatsSingular[gameState.GuestChangeModifier]
@@ -142,7 +139,7 @@ namespace OpenRCT2::Ui::Windows
// Draw park rating
{
- Widget widget = window_game_bottom_toolbar_widgets[WIDX_PARK_RATING];
+ const auto& widget = widgets[WIDX_PARK_RATING];
auto screenCoords = windowPos + ScreenCoordsXY{ widget.left + 11, widget.midY() - 5 };
DrawParkRating(dpi, colours[3].colour, screenCoords, std::max(10, ((gameState.Park.Rating / 4) * 263) / 256));
@@ -171,20 +168,15 @@ namespace OpenRCT2::Ui::Windows
void DrawRightPanel(DrawPixelInfo& dpi)
{
- const auto topLeft = windowPos
- + ScreenCoordsXY{ window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].left + 1,
- window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].top + 1 };
- const auto bottomRight = windowPos
- + ScreenCoordsXY{ window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].right - 1,
- window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].bottom - 1 };
+ const auto& rightPanelWidget = widgets[WIDX_RIGHT_OUTSET];
+
+ const auto topLeft = windowPos + ScreenCoordsXY{ rightPanelWidget.left + 1, rightPanelWidget.top + 1 };
+ const auto bottomRight = windowPos + ScreenCoordsXY{ rightPanelWidget.right - 1, rightPanelWidget.bottom - 1 };
// Draw green inset rectangle on panel
GfxFillRectInset(dpi, { topLeft, bottomRight }, colours[1], INSET_RECT_F_30);
- auto screenCoords = ScreenCoordsXY{ (window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].left
- + window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].right)
- / 2
- + windowPos.x,
- window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].top + windowPos.y + 2 };
+ auto screenCoords = ScreenCoordsXY{ (rightPanelWidget.left + rightPanelWidget.right) / 2 + windowPos.x,
+ rightPanelWidget.top + windowPos.y + 2 };
// Date
auto& date = GetDate();
@@ -204,8 +196,7 @@ namespace OpenRCT2::Ui::Windows
uint32_t line_height = FontGetLineHeight(FontStyle::Medium);
// Temperature
- screenCoords = { windowPos.x + window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].left + 15,
- static_cast(screenCoords.y + line_height + 1) };
+ screenCoords = { windowPos.x + rightPanelWidget.left + 15, static_cast(screenCoords.y + line_height + 1) };
int32_t temperature = GetGameState().ClimateCurrent.Temperature;
StringId format = STR_CELSIUS_VALUE;
@@ -237,27 +228,26 @@ namespace OpenRCT2::Ui::Windows
void DrawNewsItem(DrawPixelInfo& dpi)
{
- auto* middleOutsetWidget = &window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET];
+ const auto& middleOutsetWidget = widgets[WIDX_MIDDLE_OUTSET];
auto* newsItem = News::GetItem(0);
// Current news item
GfxFillRectInset(
dpi,
- { windowPos + ScreenCoordsXY{ middleOutsetWidget->left + 1, middleOutsetWidget->top + 1 },
- windowPos + ScreenCoordsXY{ middleOutsetWidget->right - 1, middleOutsetWidget->bottom - 1 } },
+ { windowPos + ScreenCoordsXY{ middleOutsetWidget.left + 1, middleOutsetWidget.top + 1 },
+ windowPos + ScreenCoordsXY{ middleOutsetWidget.right - 1, middleOutsetWidget.bottom - 1 } },
colours[2], INSET_RECT_F_30);
// Text
- auto screenCoords = windowPos + ScreenCoordsXY{ middleOutsetWidget->midX(), middleOutsetWidget->top + 11 };
- int32_t itemWidth = middleOutsetWidget->width() - 62;
+ auto screenCoords = windowPos + ScreenCoordsXY{ middleOutsetWidget.midX(), middleOutsetWidget.top + 11 };
+ int32_t itemWidth = middleOutsetWidget.width() - 62;
DrawNewsTicker(
dpi, screenCoords, itemWidth, COLOUR_BRIGHT_GREEN, STR_BOTTOM_TOOLBAR_NEWS_TEXT, newsItem->Text,
newsItem->Ticks);
- screenCoords = windowPos
- + ScreenCoordsXY{ window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].left,
- window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].top };
+ const auto& newsSubjectWidget = widgets[WIDX_NEWS_SUBJECT];
+ screenCoords = windowPos + ScreenCoordsXY{ newsSubjectWidget.left, newsSubjectWidget.top };
switch (newsItem->Type)
{
case News::ItemType::Ride:
@@ -342,7 +332,7 @@ namespace OpenRCT2::Ui::Windows
void DrawMiddlePanel(DrawPixelInfo& dpi)
{
- Widget* middleOutsetWidget = &window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET];
+ Widget* middleOutsetWidget = &widgets[WIDX_MIDDLE_OUTSET];
GfxFillRectInset(
dpi,
@@ -411,14 +401,14 @@ namespace OpenRCT2::Ui::Windows
public:
GameBottomToolbar()
{
- widgets = window_game_bottom_toolbar_widgets;
+ SetWidgets(window_game_bottom_toolbar_widgets);
frame_no = 0;
InitScrollWidgets();
// Reset the middle widget to not show by default.
// If it is required to be shown news_update will reshow it.
- window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::Empty;
+ widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::Empty;
}
void OnMouseUp(WidgetIndex widgetIndex) override
@@ -536,56 +526,55 @@ namespace OpenRCT2::Ui::Windows
int32_t x = ContextGetWidth();
width = x;
x--;
- window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].right = x;
+ widgets[WIDX_RIGHT_OUTSET].right = x;
x -= 2;
- window_game_bottom_toolbar_widgets[WIDX_RIGHT_INSET].right = x;
+ widgets[WIDX_RIGHT_INSET].right = x;
x -= 137;
- window_game_bottom_toolbar_widgets[WIDX_RIGHT_INSET].left = x;
+ widgets[WIDX_RIGHT_INSET].left = x;
x -= 2;
- window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].left = x;
+ widgets[WIDX_RIGHT_OUTSET].left = x;
x--;
- window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].right = x;
+ widgets[WIDX_MIDDLE_OUTSET].right = x;
x -= 2;
- window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].right = x;
+ widgets[WIDX_MIDDLE_INSET].right = x;
x -= 3;
- window_game_bottom_toolbar_widgets[WIDX_NEWS_LOCATE].right = x;
+ widgets[WIDX_NEWS_LOCATE].right = x;
x -= 23;
- window_game_bottom_toolbar_widgets[WIDX_NEWS_LOCATE].left = x;
- window_game_bottom_toolbar_widgets[WIDX_DATE].left = window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].left + 2;
- window_game_bottom_toolbar_widgets[WIDX_DATE].right = window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].right
- - 2;
+ widgets[WIDX_NEWS_LOCATE].left = x;
+ widgets[WIDX_DATE].left = widgets[WIDX_RIGHT_OUTSET].left + 2;
+ widgets[WIDX_DATE].right = widgets[WIDX_RIGHT_OUTSET].right - 2;
- window_game_bottom_toolbar_widgets[WIDX_LEFT_INSET].type = WindowWidgetType::Empty;
- window_game_bottom_toolbar_widgets[WIDX_RIGHT_INSET].type = WindowWidgetType::Empty;
+ widgets[WIDX_LEFT_INSET].type = WindowWidgetType::Empty;
+ widgets[WIDX_RIGHT_INSET].type = WindowWidgetType::Empty;
if (News::IsQueueEmpty())
{
if (!(ThemeGetFlags() & UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR))
{
- window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::Empty;
- window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].type = WindowWidgetType::Empty;
- window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::Empty;
- window_game_bottom_toolbar_widgets[WIDX_NEWS_LOCATE].type = WindowWidgetType::Empty;
+ widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::Empty;
+ widgets[WIDX_MIDDLE_INSET].type = WindowWidgetType::Empty;
+ widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::Empty;
+ widgets[WIDX_NEWS_LOCATE].type = WindowWidgetType::Empty;
}
else
{
- window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::ImgBtn;
- window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].type = WindowWidgetType::FlatBtn;
- window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::Empty;
- window_game_bottom_toolbar_widgets[WIDX_NEWS_LOCATE].type = WindowWidgetType::Empty;
- window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].colour = 0;
- window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].colour = 0;
+ widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::ImgBtn;
+ widgets[WIDX_MIDDLE_INSET].type = WindowWidgetType::FlatBtn;
+ widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::Empty;
+ widgets[WIDX_NEWS_LOCATE].type = WindowWidgetType::Empty;
+ widgets[WIDX_MIDDLE_OUTSET].colour = 0;
+ widgets[WIDX_MIDDLE_INSET].colour = 0;
}
}
else
{
News::Item* newsItem = News::GetItem(0);
- window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::ImgBtn;
- window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].type = WindowWidgetType::FlatBtn;
- window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::FlatBtn;
- window_game_bottom_toolbar_widgets[WIDX_NEWS_LOCATE].type = WindowWidgetType::FlatBtn;
- window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].colour = 2;
- window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].colour = 2;
+ widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::ImgBtn;
+ widgets[WIDX_MIDDLE_INSET].type = WindowWidgetType::FlatBtn;
+ widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::FlatBtn;
+ widgets[WIDX_NEWS_LOCATE].type = WindowWidgetType::FlatBtn;
+ widgets[WIDX_MIDDLE_OUTSET].colour = 2;
+ widgets[WIDX_MIDDLE_INSET].colour = 2;
disabled_widgets &= ~(1uLL << WIDX_NEWS_SUBJECT);
disabled_widgets &= ~(1uLL << WIDX_NEWS_LOCATE);
@@ -598,7 +587,7 @@ namespace OpenRCT2::Ui::Windows
if (!(newsItem->TypeHasSubject()))
{
disabled_widgets |= (1uLL << WIDX_NEWS_SUBJECT);
- window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::Empty;
+ widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::Empty;
}
if (newsItem->HasButton())
@@ -611,9 +600,9 @@ namespace OpenRCT2::Ui::Windows
void OnDraw(DrawPixelInfo& dpi) override
{
- auto leftWidget = window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET];
- auto rightWidget = window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET];
- auto middleWidget = window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET];
+ auto leftWidget = widgets[WIDX_LEFT_OUTSET];
+ auto rightWidget = widgets[WIDX_RIGHT_OUTSET];
+ auto middleWidget = widgets[WIDX_MIDDLE_OUTSET];
// Draw panel grey backgrounds
auto leftTop = windowPos + ScreenCoordsXY{ leftWidget.left, leftWidget.top };
diff --git a/src/openrct2-ui/windows/Guest.cpp b/src/openrct2-ui/windows/Guest.cpp
index 6630332beb..fb8372231d 100644
--- a/src/openrct2-ui/windows/Guest.cpp
+++ b/src/openrct2-ui/windows/Guest.cpp
@@ -113,7 +113,7 @@ namespace OpenRCT2::Ui::Windows
MakeTab({ 189, 17 }, STR_DEBUG_TIP) /* Tab 7 */
// clang-format off
- static Widget _guestWindowWidgetsOverview[] = {
+ static constexpr Widget _guestWindowWidgetsOverview[] = {
MAIN_GUEST_WIDGETS,
MakeWidget({ 3, 45}, {164, 12}, WindowWidgetType::LabelCentred, WindowColour::Secondary ), // Label Thought marquee
MakeWidget({ 3, 57}, {164, 87}, WindowWidgetType::Viewport, WindowColour::Secondary ), // Viewport
@@ -122,11 +122,10 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({167, 69}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_RENAME), STR_NAME_GUEST_TIP ), // Rename Button
MakeWidget({167, 93}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_LOCATE), STR_LOCATE_SUBJECT_TIP ), // Locate Button
MakeWidget({167, 117}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_TRACK_PEEP), STR_TOGGLE_GUEST_TRACKING_TIP), // Track Button
- kWidgetsEnd,
};
// clang-format on
- static Widget _guestWindowWidgetsStats[] = {
+ static constexpr Widget _guestWindowWidgetsStats[] = {
MAIN_GUEST_WIDGETS,
MakeProgressBar({ 65, (kListRowHeight * 0) + 4 + 43 }, { 119, 10 }, COLOUR_BRIGHT_GREEN, 0, 19), // Happiness
MakeProgressBar({ 65, (kListRowHeight * 1) + 4 + 43 }, { 119, 10 }, COLOUR_BRIGHT_GREEN, 0, 19), // Energy
@@ -134,37 +133,31 @@ namespace OpenRCT2::Ui::Windows
MakeProgressBar({ 65, (kListRowHeight * 3) + 4 + 43 }, { 119, 10 }, COLOUR_BRIGHT_RED, 67, 100), // Thirst
MakeProgressBar({ 65, (kListRowHeight * 4) + 4 + 43 }, { 119, 10 }, COLOUR_BRIGHT_RED, 47, 100), // Nausea
MakeProgressBar({ 65, (kListRowHeight * 5) + 4 + 43 }, { 119, 10 }, COLOUR_BRIGHT_RED, 62, 100), // Toilet
- kWidgetsEnd,
};
- static Widget _guestWindowWidgetsRides[] = {
+ static constexpr Widget _guestWindowWidgetsRides[] = {
MAIN_GUEST_WIDGETS,
MakeWidget({ 3, 57 }, { 186, 87 }, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL),
- kWidgetsEnd,
};
- static Widget _guestWindowWidgetsFinance[] = {
+ static constexpr Widget _guestWindowWidgetsFinance[] = {
MAIN_GUEST_WIDGETS,
- kWidgetsEnd,
};
- static Widget _guestWindowWidgetsThoughts[] = {
+ static constexpr Widget _guestWindowWidgetsThoughts[] = {
MAIN_GUEST_WIDGETS,
- kWidgetsEnd,
};
- static Widget _guestWindowWidgetsInventory[] = {
+ static constexpr Widget _guestWindowWidgetsInventory[] = {
MAIN_GUEST_WIDGETS,
- kWidgetsEnd,
};
- static Widget _guestWindowWidgetsDebug[] = {
+ static constexpr Widget _guestWindowWidgetsDebug[] = {
MAIN_GUEST_WIDGETS,
- kWidgetsEnd,
};
// clang-format off
- static constexpr std::array _guestWindowPageWidgets = {
+ static constexpr std::span _guestWindowPageWidgets[] = {
_guestWindowWidgetsOverview,
_guestWindowWidgetsStats,
_guestWindowWidgetsRides,
@@ -173,7 +166,7 @@ namespace OpenRCT2::Ui::Windows
_guestWindowWidgetsInventory,
_guestWindowWidgetsDebug,
};
- static_assert(_guestWindowPageWidgets.size() == WINDOW_GUEST_PAGE_COUNT);
+ static_assert(std::size(_guestWindowPageWidgets) == WINDOW_GUEST_PAGE_COUNT);
// clang-format on
static constexpr std::array _guestWindowPageSizes = {
@@ -199,7 +192,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = _guestWindowWidgetsOverview;
+ SetWidgets(_guestWindowWidgetsOverview);
page = WINDOW_GUEST_OVERVIEW;
frame_no = 0;
_marqueePosition = 0;
@@ -448,12 +441,6 @@ namespace OpenRCT2::Ui::Windows
void OnPrepareDrawCommon()
{
- if (_guestWindowPageWidgets[page] != widgets)
- {
- widgets = _guestWindowPageWidgets[page];
- InitScrollWidgets();
- }
-
pressed_widgets |= 1uLL << (page + WIDX_TAB_1);
const auto peep = GetGuest();
@@ -521,7 +508,7 @@ namespace OpenRCT2::Ui::Windows
hold_down_widgets = 0;
pressed_widgets = 0;
- widgets = _guestWindowPageWidgets[page];
+ SetWidgets(_guestWindowPageWidgets[page]);
DisableWidgets();
Invalidate();
OnResize();
diff --git a/src/openrct2-ui/windows/GuestList.cpp b/src/openrct2-ui/windows/GuestList.cpp
index 3fc9fe28dd..353e5037c1 100644
--- a/src/openrct2-ui/windows/GuestList.cpp
+++ b/src/openrct2-ui/windows/GuestList.cpp
@@ -58,7 +58,7 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget window_guest_list_widgets[] = {
+ static constexpr Widget window_guest_list_widgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({ 0, 43}, {350, 287}, WindowWidgetType::Resize, WindowColour::Secondary ), // tab content panel
MakeWidget({ 5, 59}, { 80, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_ARG_4_PAGE_X ), // page dropdown
@@ -71,7 +71,6 @@ namespace OpenRCT2::Ui::Windows
MakeTab ({ 3, 17}, STR_INDIVIDUAL_GUESTS_TIP ), // tab 1
MakeTab ({ 34, 17}, STR_SUMMARISED_GUESTS_TIP ), // tab 2
MakeWidget({ 3, 72}, {344, 255}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_BOTH ), // guest list
- kWidgetsEnd,
};
// clang-format on
@@ -161,7 +160,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_guest_list_widgets;
+ SetWidgets(window_guest_list_widgets);
WindowInitScrollWidgets(*this);
_selectedTab = TabId::Summarised;
diff --git a/src/openrct2-ui/windows/InstallTrack.cpp b/src/openrct2-ui/windows/InstallTrack.cpp
index 982a3f8533..fd3aa0eda0 100644
--- a/src/openrct2-ui/windows/InstallTrack.cpp
+++ b/src/openrct2-ui/windows/InstallTrack.cpp
@@ -50,14 +50,13 @@ namespace OpenRCT2::Ui::Windows
constexpr int32_t ACTION_BUTTONS_LEFT = WW - 100;
// clang-format off
- static Widget window_install_track_widgets[] = {
+ static constexpr Widget window_install_track_widgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({ 4, 18}, {372, 219}, WindowWidgetType::FlatBtn, WindowColour::Primary ),
MakeWidget({PREVIEW_BUTTONS_LEFT, 422}, { 22, 24}, WindowWidgetType::FlatBtn, WindowColour::Primary, ImageId(SPR_ROTATE_ARROW), STR_ROTATE_90_TIP ),
MakeWidget({PREVIEW_BUTTONS_LEFT, 398}, { 22, 24}, WindowWidgetType::FlatBtn, WindowColour::Primary, ImageId(SPR_SCENERY), STR_TOGGLE_SCENERY_TIP),
MakeWidget({ ACTION_BUTTONS_LEFT, 241}, { 97, 15}, WindowWidgetType::Button, WindowColour::Primary, STR_INSTALL_NEW_TRACK_DESIGN_INSTALL ),
MakeWidget({ ACTION_BUTTONS_LEFT, 259}, { 97, 15}, WindowWidgetType::Button, WindowColour::Primary, STR_INSTALL_NEW_TRACK_DESIGN_CANCEL ),
- kWidgetsEnd,
};
// clang-format on
@@ -83,7 +82,7 @@ namespace OpenRCT2::Ui::Windows
void OnOpen() override
{
- widgets = window_install_track_widgets;
+ SetWidgets(window_install_track_widgets);
WindowInitScrollWidgets(*this);
WindowPushOthersRight(*this);
@@ -152,7 +151,7 @@ namespace OpenRCT2::Ui::Windows
DrawWidgets(dpi);
// Track preview
- Widget* widget = &window_install_track_widgets[WIDX_TRACK_PREVIEW];
+ Widget* widget = &widgets[WIDX_TRACK_PREVIEW];
auto screenPos = windowPos + ScreenCoordsXY{ widget->left + 1, widget->top + 1 };
int32_t colour = ColourMapA[colours[0].colour].darkest;
GfxFillRect(dpi, { screenPos, screenPos + ScreenCoordsXY{ 369, 216 } }, colour);
diff --git a/src/openrct2-ui/windows/Land.cpp b/src/openrct2-ui/windows/Land.cpp
index c45cb33206..077ba3569c 100644
--- a/src/openrct2-ui/windows/Land.cpp
+++ b/src/openrct2-ui/windows/Land.cpp
@@ -53,7 +53,7 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget window_land_widgets[] = {
+ static constexpr Widget window_land_widgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget ({19, 19}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_RIDE_CONSTRUCTION_SLOPE_UP), STR_ENABLE_MOUNTAIN_TOOL_TIP), // mountain mode
MakeWidget ({55, 19}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_PAINTBRUSH), STR_DISABLE_ELEVATION), // paint mode
@@ -62,7 +62,6 @@ namespace OpenRCT2::Ui::Windows
MakeRemapWidget({54, 63}, {16, 16}, WindowWidgetType::TrnBtn, WindowColour::Secondary, SPR_LAND_TOOL_INCREASE, STR_ADJUST_LARGER_LAND_TIP), // increment size
MakeWidget ({ 2, 106}, {47, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_CHANGE_BASE_LAND_TIP), // floor texture
MakeWidget ({49, 106}, {47, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_CHANGE_VERTICAL_LAND_TIP), // wall texture
- kWidgetsEnd,
};
// clang-format on
@@ -90,7 +89,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_land_widgets;
+ SetWidgets(window_land_widgets);
hold_down_widgets = (1uLL << WIDX_DECREMENT) | (1uLL << WIDX_INCREMENT);
WindowInitScrollWidgets(*this);
WindowPushOthersBelow(*this);
@@ -407,7 +406,7 @@ namespace OpenRCT2::Ui::Windows
return;
WidgetIndex widget_index = windowMgr->FindWidgetFromPoint(*window, screenPos);
- if (widget_index == -1)
+ if (widget_index == kWidgetIndexNull)
return;
const auto& widget = window->widgets[widget_index];
diff --git a/src/openrct2-ui/windows/LandRights.cpp b/src/openrct2-ui/windows/LandRights.cpp
index a7ef2463ba..157835ec2e 100644
--- a/src/openrct2-ui/windows/LandRights.cpp
+++ b/src/openrct2-ui/windows/LandRights.cpp
@@ -57,7 +57,7 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget window_land_rights_widgets[] = {
+ static constexpr Widget window_land_rights_widgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget ({ 27, 17}, { 44, 32}, WindowWidgetType::ImgBtn, WindowColour::Primary, ImageId(SPR_LAND_TOOL_SIZE_0) ), // preview box
MakeRemapWidget({ 28, 18}, { 16, 16}, WindowWidgetType::TrnBtn, WindowColour::Primary, SPR_LAND_TOOL_DECREASE, STR_ADJUST_SMALLER_LAND_RIGHTS_TIP ), // decrement size
@@ -69,7 +69,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({100, 54}, {170, 12}, WindowWidgetType::Empty, WindowColour::Primary, STR_LAND_OWNED, STR_SET_LAND_TO_BE_OWNED_TIP ),
MakeWidget ({100, 70}, {170, 12}, WindowWidgetType::Empty, WindowColour::Primary, STR_CONSTRUCTION_RIGHTS_SALE, STR_SET_CONSTRUCTION_RIGHTS_TO_BE_AVAILABLE_TIP),
MakeWidget ({100, 86}, {170, 12}, WindowWidgetType::Empty, WindowColour::Primary, STR_CONSTRUCTION_RIGHTS_OWNED, STR_SET_CONSTRUCTION_RIGHTS_TO_BE_OWNED_TIP ),
- kWidgetsEnd,
};
// clang-format on
@@ -126,7 +125,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_land_rights_widgets;
+ SetWidgets(window_land_rights_widgets);
hold_down_widgets = (1uLL << WIDX_INCREMENT) | (1uLL << WIDX_DECREMENT);
WindowInitScrollWidgets(*this);
WindowPushOthersBelow(*this);
@@ -287,23 +286,23 @@ namespace OpenRCT2::Ui::Windows
if (gLandRemainingOwnershipSales == 0)
{
SetWidgetDisabled(WIDX_BUY_LAND_RIGHTS, true);
- window_land_rights_widgets[WIDX_BUY_LAND_RIGHTS].tooltip = STR_NO_LAND_RIGHTS_FOR_SALE_TIP;
+ widgets[WIDX_BUY_LAND_RIGHTS].tooltip = STR_NO_LAND_RIGHTS_FOR_SALE_TIP;
}
else
{
SetWidgetDisabled(WIDX_BUY_LAND_RIGHTS, false);
- window_land_rights_widgets[WIDX_BUY_LAND_RIGHTS].tooltip = STR_BUY_LAND_RIGHTS_TIP;
+ widgets[WIDX_BUY_LAND_RIGHTS].tooltip = STR_BUY_LAND_RIGHTS_TIP;
}
if (gLandRemainingConstructionSales == 0)
{
SetWidgetDisabled(WIDX_BUY_CONSTRUCTION_RIGHTS, true);
- window_land_rights_widgets[WIDX_BUY_CONSTRUCTION_RIGHTS].tooltip = STR_NO_CONSTRUCTION_RIGHTS_FOR_SALE_TIP;
+ widgets[WIDX_BUY_CONSTRUCTION_RIGHTS].tooltip = STR_NO_CONSTRUCTION_RIGHTS_FOR_SALE_TIP;
}
else
{
SetWidgetDisabled(WIDX_BUY_CONSTRUCTION_RIGHTS, false);
- window_land_rights_widgets[WIDX_BUY_CONSTRUCTION_RIGHTS].tooltip = STR_BUY_CONSTRUCTION_RIGHTS_TIP;
+ widgets[WIDX_BUY_CONSTRUCTION_RIGHTS].tooltip = STR_BUY_CONSTRUCTION_RIGHTS_TIP;
}
// Position land size tool
@@ -359,7 +358,7 @@ namespace OpenRCT2::Ui::Windows
void OnPrepareDraw() override
{
SetWidgetPressed(WIDX_PREVIEW, true);
- window_land_rights_widgets[WIDX_PREVIEW].image = ImageId(LandTool::SizeToSpriteIndex(gLandToolSize));
+ widgets[WIDX_PREVIEW].image = ImageId(LandTool::SizeToSpriteIndex(gLandToolSize));
if (width != GetModeDimensions().x)
OnResize();
@@ -393,8 +392,8 @@ namespace OpenRCT2::Ui::Windows
void OnDraw(DrawPixelInfo& dpi) override
{
- auto screenCoords = ScreenCoordsXY{ windowPos.x + window_land_rights_widgets[WIDX_PREVIEW].midX(),
- windowPos.y + window_land_rights_widgets[WIDX_PREVIEW].midY() };
+ auto screenCoords = ScreenCoordsXY{ windowPos.x + widgets[WIDX_PREVIEW].midX(),
+ windowPos.y + widgets[WIDX_PREVIEW].midY() };
DrawWidgets(dpi);
// Draw number for tool sizes bigger than 7
@@ -415,8 +414,8 @@ namespace OpenRCT2::Ui::Windows
auto offset = widgets[WIDX_BUY_LAND_RIGHTS].type != WindowWidgetType::Empty ? 32 : 8;
- screenCoords = { window_land_rights_widgets[WIDX_PREVIEW].midX() + windowPos.x,
- window_land_rights_widgets[WIDX_PREVIEW].bottom + windowPos.y + offset };
+ screenCoords = { widgets[WIDX_PREVIEW].midX() + windowPos.x,
+ widgets[WIDX_PREVIEW].bottom + windowPos.y + offset };
DrawTextBasic(dpi, screenCoords, STR_COST_AMOUNT, ft, { TextAlignment::CENTRE });
}
}
diff --git a/src/openrct2-ui/windows/LoadSave.cpp b/src/openrct2-ui/windows/LoadSave.cpp
index f096cea754..c260c2e776 100644
--- a/src/openrct2-ui/windows/LoadSave.cpp
+++ b/src/openrct2-ui/windows/LoadSave.cpp
@@ -80,7 +80,7 @@ namespace OpenRCT2::Ui::Windows
static constexpr int16_t WH = kWindowSizeInit.height;
// clang-format off
- static Widget window_loadsave_widgets[] =
+ static constexpr Widget window_loadsave_widgets[] =
{
WINDOW_SHIM(STR_NONE, WW, WH),
MakeWidget({ 0, 15 }, { WW, WH - 15 }, WindowWidgetType::Resize, WindowColour::Secondary ), // WIDX_RESIZE
@@ -96,7 +96,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({ 64, WH - 50 }, { WW - 133, 14 }, WindowWidgetType::TextBox, WindowColour::Secondary ), // WIDX_FILENAME_TEXTBOX
MakeWidget({ WW - 65, WH - 50 }, { 60, 14 }, WindowWidgetType::Button, WindowColour::Secondary, STR_FILEBROWSER_SAVE_BUTTON ), // WIDX_SAVE
MakeWidget({ 4, WH - 24 }, { 197, 19 }, WindowWidgetType::Button, WindowColour::Primary, STR_FILEBROWSER_USE_SYSTEM_WINDOW ), // WIDX_BROWSE
- kWidgetsEnd,
};
// clang-format on
@@ -713,7 +712,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_loadsave_widgets;
+ SetWidgets(window_loadsave_widgets);
const auto uiContext = OpenRCT2::GetContext()->GetUiContext();
if (!uiContext->HasFilePicker())
@@ -1422,11 +1421,10 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget window_overwrite_prompt_widgets[] = {
+ static constexpr Widget window_overwrite_prompt_widgets[] = {
WINDOW_SHIM_WHITE(STR_FILEBROWSER_OVERWRITE_TITLE, OVERWRITE_WW, OVERWRITE_WH),
MakeWidget({ 10, OVERWRITE_WH - 20 }, { 84, 11 }, WindowWidgetType::Button, WindowColour::Primary, STR_FILEBROWSER_OVERWRITE_TITLE),
MakeWidget({ OVERWRITE_WW - 95, OVERWRITE_WH - 20 }, { 85, 11 }, WindowWidgetType::Button, WindowColour::Primary, STR_SAVE_PROMPT_CANCEL),
- kWidgetsEnd,
};
// clang-format on
@@ -1444,7 +1442,7 @@ namespace OpenRCT2::Ui::Windows
void OnOpen() override
{
- widgets = window_overwrite_prompt_widgets;
+ SetWidgets(window_overwrite_prompt_widgets);
}
void OnMouseUp(WidgetIndex widgetIndex) override
diff --git a/src/openrct2-ui/windows/Main.cpp b/src/openrct2-ui/windows/Main.cpp
index 1e12faaf49..7710a0fce7 100644
--- a/src/openrct2-ui/windows/Main.cpp
+++ b/src/openrct2-ui/windows/Main.cpp
@@ -19,9 +19,8 @@
namespace OpenRCT2::Ui::Windows
{
// clang-format off
- static Widget _mainWidgets[] = {
+ static constexpr Widget _mainWidgets[] = {
MakeWidget({0, 0}, {0, 0}, WindowWidgetType::Viewport, WindowColour::Primary),
- kWidgetsEnd,
};
// clang-format on
@@ -30,9 +29,9 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- _mainWidgets[0].right = width;
- _mainWidgets[0].bottom = height;
- widgets = _mainWidgets;
+ SetWidgets(_mainWidgets);
+ widgets[0].right = width;
+ widgets[0].bottom = height;
ViewportCreate(this, windowPos, width, height, Focus(CoordsXYZ(0x0FFF, 0x0FFF, 0)));
if (viewport != nullptr)
diff --git a/src/openrct2-ui/windows/Map.cpp b/src/openrct2-ui/windows/Map.cpp
index 4e7302d156..a67ce9e820 100644
--- a/src/openrct2-ui/windows/Map.cpp
+++ b/src/openrct2-ui/windows/Map.cpp
@@ -132,7 +132,7 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget window_map_widgets[] = {
+ static constexpr Widget window_map_widgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget ({ 0, 43}, {245, 215}, WindowWidgetType::Resize, WindowColour::Secondary ),
MakeRemapWidget ({ 3, 17}, { 31, 27}, WindowWidgetType::ColourBtn, WindowColour::Secondary, SPR_TAB, STR_SHOW_PEOPLE_ON_MAP_TIP ),
@@ -145,7 +145,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({ 4, 70}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_G2_PEEP_SPAWN), STR_SET_STARTING_POSITIONS_TIP ),
MakeWidget ({ 28, 94}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_PARK_ENTRANCE), STR_BUILD_PARK_ENTRANCE_TIP ),
MakeWidget ({110, 118}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_G2_MAP_GEN_BTN), STR_MAP_GENERATOR_TIP ),
- kWidgetsEnd,
};
// clang-format on
@@ -235,7 +234,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_map_widgets;
+ SetWidgets(window_map_widgets);
hold_down_widgets = (1uLL << WIDX_MAP_SIZE_SPINNER_Y_UP) | (1uLL << WIDX_MAP_SIZE_SPINNER_Y_DOWN)
| (1uLL << WIDX_MAP_SIZE_SPINNER_X_UP) | (1uLL << WIDX_MAP_SIZE_SPINNER_X_DOWN);
diff --git a/src/openrct2-ui/windows/MapGen.cpp b/src/openrct2-ui/windows/MapGen.cpp
index e8f41533e1..23e52cd643 100644
--- a/src/openrct2-ui/windows/MapGen.cpp
+++ b/src/openrct2-ui/windows/MapGen.cpp
@@ -124,7 +124,7 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({ 185, 200 }, { 109, 14 }, WindowWidgetType::Button, WindowColour::Secondary, STR_MAPGEN_ACTION_GENERATE)
// clang-format off
- static Widget BaseWidgets[] = {
+ static constexpr Widget BaseWidgets[] = {
SHARED_WIDGETS(STR_MAPGEN_CAPTION_GENERATOR),
MakeSpinnerWidgets ({165, 52}, { 50, 12}, WindowWidgetType::Spinner, WindowColour::Secondary, STR_COMMA16 ), // NB: 3 widgets
MakeWidget ({216, 52}, { 21, 12}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_G2_LINK_CHAIN), STR_MAINTAIN_SQUARE_MAP_TOOLTIP),
@@ -140,10 +140,9 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({ 10, 125}, {150, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_MAPGEN_NORMALIZE ), // WIDX_HEIGHTMAP_NORMALIZE
MakeWidget ({ 10, 141}, {150, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_MAPGEN_SMOOTH_HEIGHTMAP), // WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP
MakeSpinnerWidgets({179, 157}, {109, 12}, WindowWidgetType::Spinner, WindowColour::Secondary ), // WIDX_HEIGHTMAP_STRENGTH{,_UP,_DOWN}
- kWidgetsEnd,
};
- static Widget TerrainWidgets[] = {
+ static constexpr Widget TerrainWidgets[] = {
SHARED_WIDGETS(STR_MAPGEN_CAPTION_TERRAIN),
MakeSpinnerWidgets({179, 52}, {109, 12}, WindowWidgetType::Spinner, WindowColour::Secondary ), // WIDX_HEIGHTMAP_LOW{,_UP,_DOWN}
MakeSpinnerWidgets({179, 70}, {109, 12}, WindowWidgetType::Spinner, WindowColour::Secondary ), // WIDX_HEIGHTMAP_HIGH{,_UP,_DOWN}
@@ -151,26 +150,23 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({236, 88}, { 47, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_CHANGE_VERTICAL_LAND_TIP),
MakeWidget ({ 10, 106}, {150, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_MAPGEN_OPTION_RANDOM_TERRAIN ),
MakeWidget ({ 10, 122}, {150, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_MAPGEN_SMOOTH_TILE), // WIDX_HEIGHTMAP_SMOOTH_TILE_EDGES
- kWidgetsEnd,
};
- static Widget WaterWidgets[] = {
+ static constexpr Widget WaterWidgets[] = {
SHARED_WIDGETS(STR_MAPGEN_CAPTION_WATER),
MakeSpinnerWidgets({179, 52}, {109, 12}, WindowWidgetType::Spinner, WindowColour::Secondary ), // NB: 3 widgets
MakeWidget ({ 10, 70}, {195, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_BEACHES_WATER_BODIES),
- kWidgetsEnd,
};
- static Widget ForestsWidgets[] = {
+ static constexpr Widget ForestsWidgets[] = {
SHARED_WIDGETS(STR_MAPGEN_CAPTION_FORESTS),
MakeWidget ({ 10, 52}, {255, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_MAPGEN_OPTION_PLACE_TREES),
MakeSpinnerWidgets({179, 70}, {109, 12}, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_TREE_LAND_RATIO{,_UP,_DOWN}
MakeSpinnerWidgets({179, 88}, {109, 12}, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_TREE_ALTITUDE_MIN{,_UP,_DOWN}
MakeSpinnerWidgets({179, 106}, {109, 12}, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_TREE_ALTITUDE_MAX{,_UP,_DOWN}
- kWidgetsEnd,
};
- static Widget* PageWidgets[WINDOW_MAPGEN_PAGE_COUNT] = {
+ static std::span PageWidgets[WINDOW_MAPGEN_PAGE_COUNT] = {
BaseWidgets,
TerrainWidgets,
WaterWidgets,
@@ -282,7 +278,7 @@ namespace OpenRCT2::Ui::Windows
RemoveViewport();
hold_down_widgets = HoldDownWidgets[newPage];
- widgets = PageWidgets[newPage];
+ SetWidgets(PageWidgets[newPage]);
disabled_widgets = PageDisabledWidgets[newPage];
pressed_widgets = PressedWidgets[newPage];
@@ -515,12 +511,6 @@ namespace OpenRCT2::Ui::Windows
void BasePrepareDraw()
{
- if (widgets != PageWidgets[WINDOW_MAPGEN_PAGE_BASE])
- {
- widgets = PageWidgets[WINDOW_MAPGEN_PAGE_BASE];
- InitScrollWidgets();
- }
-
// Only allow linking the map size when X and Y are the same
SetWidgetPressed(WIDX_MAP_SIZE_LINK, _mapWidthAndHeightLinked);
SetWidgetDisabled(WIDX_MAP_SIZE_LINK, _settings.mapSize.x != _settings.mapSize.y);
@@ -578,26 +568,26 @@ namespace OpenRCT2::Ui::Windows
void ToggleSimplexWidgets(bool state)
{
// clang-format off
- BaseWidgets[WIDX_SIMPLEX_GROUP].type = state ? WindowWidgetType::Groupbox : WindowWidgetType::Empty;
- BaseWidgets[WIDX_SIMPLEX_BASE_FREQ].type = state ? WindowWidgetType::Spinner : WindowWidgetType::Empty;
- BaseWidgets[WIDX_SIMPLEX_BASE_FREQ_UP].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty;
- BaseWidgets[WIDX_SIMPLEX_BASE_FREQ_DOWN].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty;
- BaseWidgets[WIDX_SIMPLEX_OCTAVES].type = state ? WindowWidgetType::Spinner : WindowWidgetType::Empty;
- BaseWidgets[WIDX_SIMPLEX_OCTAVES_UP].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty;
- BaseWidgets[WIDX_SIMPLEX_OCTAVES_DOWN].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty;
+ widgets[WIDX_SIMPLEX_GROUP].type = state ? WindowWidgetType::Groupbox : WindowWidgetType::Empty;
+ widgets[WIDX_SIMPLEX_BASE_FREQ].type = state ? WindowWidgetType::Spinner : WindowWidgetType::Empty;
+ widgets[WIDX_SIMPLEX_BASE_FREQ_UP].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty;
+ widgets[WIDX_SIMPLEX_BASE_FREQ_DOWN].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty;
+ widgets[WIDX_SIMPLEX_OCTAVES].type = state ? WindowWidgetType::Spinner : WindowWidgetType::Empty;
+ widgets[WIDX_SIMPLEX_OCTAVES_UP].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty;
+ widgets[WIDX_SIMPLEX_OCTAVES_DOWN].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty;
// clang-format on
}
void ToggleHeightmapWidgets(bool state)
{
// clang-format off
- BaseWidgets[WIDX_HEIGHTMAP_GROUP].type = state ? WindowWidgetType::Groupbox : WindowWidgetType::Empty;
- BaseWidgets[WIDX_HEIGHTMAP_BROWSE].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty;
- BaseWidgets[WIDX_HEIGHTMAP_NORMALIZE].type = state ? WindowWidgetType::Checkbox : WindowWidgetType::Empty;
- BaseWidgets[WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP].type = state ? WindowWidgetType::Checkbox : WindowWidgetType::Empty;
- BaseWidgets[WIDX_HEIGHTMAP_STRENGTH].type = state ? WindowWidgetType::Spinner : WindowWidgetType::Empty;
- BaseWidgets[WIDX_HEIGHTMAP_STRENGTH_UP].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty;
- BaseWidgets[WIDX_HEIGHTMAP_STRENGTH_DOWN].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty;
+ widgets[WIDX_HEIGHTMAP_GROUP].type = state ? WindowWidgetType::Groupbox : WindowWidgetType::Empty;
+ widgets[WIDX_HEIGHTMAP_BROWSE].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty;
+ widgets[WIDX_HEIGHTMAP_NORMALIZE].type = state ? WindowWidgetType::Checkbox : WindowWidgetType::Empty;
+ widgets[WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP].type = state ? WindowWidgetType::Checkbox : WindowWidgetType::Empty;
+ widgets[WIDX_HEIGHTMAP_STRENGTH].type = state ? WindowWidgetType::Spinner : WindowWidgetType::Empty;
+ widgets[WIDX_HEIGHTMAP_STRENGTH_UP].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty;
+ widgets[WIDX_HEIGHTMAP_STRENGTH_DOWN].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty;
// clang-format on
}
@@ -744,12 +734,6 @@ namespace OpenRCT2::Ui::Windows
void ForestsPrepareDraw()
{
- if (widgets != PageWidgets[WINDOW_MAPGEN_PAGE_FORESTS])
- {
- widgets = PageWidgets[WINDOW_MAPGEN_PAGE_FORESTS];
- InitScrollWidgets();
- }
-
pressed_widgets = 0;
if (_settings.trees)
pressed_widgets |= 1uLL << WIDX_FORESTS_PLACE_TREES;
@@ -1221,12 +1205,6 @@ namespace OpenRCT2::Ui::Windows
void TerrainPrepareDraw()
{
- if (widgets != PageWidgets[WINDOW_MAPGEN_PAGE_TERRAIN])
- {
- widgets = PageWidgets[WINDOW_MAPGEN_PAGE_TERRAIN];
- InitScrollWidgets();
- }
-
SetCheckboxValue(WIDX_RANDOM_TERRAIN, _randomTerrain != 0);
SetCheckboxValue(WIDX_HEIGHTMAP_SMOOTH_TILE_EDGES, _settings.smoothTileEdges);
@@ -1348,12 +1326,6 @@ namespace OpenRCT2::Ui::Windows
void WaterPrepareDraw()
{
- if (widgets != PageWidgets[WINDOW_MAPGEN_PAGE_WATER])
- {
- widgets = PageWidgets[WINDOW_MAPGEN_PAGE_WATER];
- InitScrollWidgets();
- }
-
SetCheckboxValue(WIDX_ADD_BEACHES, _settings.beaches != 0);
SetPressedTab();
@@ -1383,11 +1355,9 @@ namespace OpenRCT2::Ui::Windows
void OnOpen() override
{
number = 0;
- frame_no = 0;
- page = WINDOW_MAPGEN_PAGE_BASE;
+ SetPage(WINDOW_MAPGEN_PAGE_BASE);
Invalidate();
- widgets = PageWidgets[WINDOW_MAPGEN_PAGE_BASE];
hold_down_widgets = HoldDownWidgets[WINDOW_MAPGEN_PAGE_BASE];
pressed_widgets = PressedWidgets[WINDOW_MAPGEN_PAGE_BASE];
disabled_widgets = PageDisabledWidgets[WINDOW_MAPGEN_PAGE_BASE];
diff --git a/src/openrct2-ui/windows/MapTooltip.cpp b/src/openrct2-ui/windows/MapTooltip.cpp
index 71ee35120f..3a77481343 100644
--- a/src/openrct2-ui/windows/MapTooltip.cpp
+++ b/src/openrct2-ui/windows/MapTooltip.cpp
@@ -22,9 +22,8 @@
namespace OpenRCT2::Ui::Windows
{
// clang-format off
- static Widget window_map_tooltip_widgets[] = {
+ static constexpr Widget window_map_tooltip_widgets[] = {
MakeWidget({0, 0}, {200, 30}, WindowWidgetType::ImgBtn, WindowColour::Primary),
- kWidgetsEnd,
};
// clang-format on
@@ -40,7 +39,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_map_tooltip_widgets;
+ SetWidgets(window_map_tooltip_widgets);
}
void OnUpdate() override
diff --git a/src/openrct2-ui/windows/MazeConstruction.cpp b/src/openrct2-ui/windows/MazeConstruction.cpp
index 16ec9830af..b64393bb22 100644
--- a/src/openrct2-ui/windows/MazeConstruction.cpp
+++ b/src/openrct2-ui/windows/MazeConstruction.cpp
@@ -61,7 +61,7 @@ namespace OpenRCT2::Ui::Windows
validate_global_widx(WC_MAZE_CONSTRUCTION, WIDX_MAZE_EXIT);
// clang-format off
- static Widget window_maze_construction_widgets[] = {
+ static constexpr Widget window_maze_construction_widgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({ 3, 17}, {160, 55}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_RIDE_CONSTRUCTION_MODE ),
MakeWidget({ 0, 0}, { 1, 1}, WindowWidgetType::Empty, WindowColour::Primary ),
@@ -94,7 +94,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({87, 178}, { 70, 12}, WindowWidgetType::Button, WindowColour::Secondary, STR_RIDE_CONSTRUCTION_EXIT, STR_RIDE_CONSTRUCTION_EXIT_TIP ),
MakeWidget({ 0, 0}, { 1, 1}, WindowWidgetType::Empty, WindowColour::Primary ),
MakeWidget({ 0, 0}, { 1, 1}, WindowWidgetType::Empty, WindowColour::Primary ),
- kWidgetsEnd,
};
// clang-format on
@@ -105,7 +104,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_maze_construction_widgets;
+ SetWidgets(window_maze_construction_widgets);
WindowInitScrollWidgets(*this);
rideId = _currentRideIndex;
ShowGridlines();
diff --git a/src/openrct2-ui/windows/Multiplayer.cpp b/src/openrct2-ui/windows/Multiplayer.cpp
index 07fd363ab3..a846142952 100644
--- a/src/openrct2-ui/windows/Multiplayer.cpp
+++ b/src/openrct2-ui/windows/Multiplayer.cpp
@@ -72,22 +72,20 @@ namespace OpenRCT2::Ui::Windows
MakeTab ({ 65, 17}, STR_GROUPS_TIP ), /* tab */ \
MakeTab ({ 96, 17}, STR_OPTIONS_TIP ) /* tab */
- static Widget window_multiplayer_information_widgets[] = {
+ static constexpr Widget window_multiplayer_information_widgets[] = {
MAIN_MULTIPLAYER_WIDGETS,
- kWidgetsEnd,
};
- static Widget window_multiplayer_players_widgets[] = {
+ static constexpr Widget window_multiplayer_players_widgets[] = {
MAIN_MULTIPLAYER_WIDGETS,
MakeWidget({ 3, 46}, {173, 15}, WindowWidgetType::TableHeader, WindowColour::Primary , STR_PLAYER ), // Player name
MakeWidget({176, 46}, { 83, 15}, WindowWidgetType::TableHeader, WindowColour::Primary , STR_GROUP ), // Player name
MakeWidget({259, 46}, {100, 15}, WindowWidgetType::TableHeader, WindowColour::Primary , STR_LAST_ACTION), // Player name
MakeWidget({359, 46}, { 42, 15}, WindowWidgetType::TableHeader, WindowColour::Primary , STR_PING ), // Player name
MakeWidget({ 3, 60}, {334, 177}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL), // list
- kWidgetsEnd,
};
- static Widget window_multiplayer_groups_widgets[] = {
+ static constexpr Widget window_multiplayer_groups_widgets[] = {
MAIN_MULTIPLAYER_WIDGETS,
MakeWidget({141, 46}, {175, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ), // default group
MakeWidget({305, 47}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH),
@@ -97,18 +95,16 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({ 72, 80}, {175, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ), // selected group
MakeWidget({236, 81}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH),
MakeWidget({ 3, 94}, {314, 207}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL ), // permissions list
- kWidgetsEnd,
};
- static Widget window_multiplayer_options_widgets[] = {
+ static constexpr Widget window_multiplayer_options_widgets[] = {
MAIN_MULTIPLAYER_WIDGETS,
MakeWidget({3, 50}, {295, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_LOG_CHAT, STR_LOG_CHAT_TIP ),
MakeWidget({3, 64}, {295, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_LOG_SERVER_ACTIONS, STR_LOG_SERVER_ACTIONS_TIP ),
MakeWidget({3, 78}, {295, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_ALLOW_KNOWN_KEYS_ONLY, STR_ALLOW_KNOWN_KEYS_ONLY_TIP),
- kWidgetsEnd,
};
- static Widget *window_multiplayer_page_widgets[] = {
+ static std::span window_multiplayer_page_widgets[] = {
window_multiplayer_information_widgets,
window_multiplayer_players_widgets,
window_multiplayer_groups_widgets,
@@ -214,7 +210,7 @@ namespace OpenRCT2::Ui::Windows
hold_down_widgets = 0;
pressed_widgets = 0;
- widgets = window_multiplayer_page_widgets[page];
+ SetWidgets(window_multiplayer_page_widgets[page]);
widgets[WIDX_TITLE].text = WindowMultiplayerPageTitles[page];
OnResize();
@@ -405,15 +401,15 @@ namespace OpenRCT2::Ui::Windows
}
case WINDOW_MULTIPLAYER_PAGE_PLAYERS:
{
- window_multiplayer_players_widgets[WIDX_LIST].right = width - 4;
- window_multiplayer_players_widgets[WIDX_LIST].bottom = height - 0x0F;
+ widgets[WIDX_LIST].right = width - 4;
+ widgets[WIDX_LIST].bottom = height - 0x0F;
WindowAlignTabs(this, WIDX_TAB1, WIDX_TAB4);
break;
}
case WINDOW_MULTIPLAYER_PAGE_GROUPS:
{
- window_multiplayer_groups_widgets[WIDX_PERMISSIONS_LIST].right = width - 4;
- window_multiplayer_groups_widgets[WIDX_PERMISSIONS_LIST].bottom = height - 0x0F;
+ widgets[WIDX_PERMISSIONS_LIST].right = width - 4;
+ widgets[WIDX_PERMISSIONS_LIST].bottom = height - 0x0F;
WindowAlignTabs(this, WIDX_TAB1, WIDX_TAB4);
// select other group if one is removed
@@ -530,11 +526,11 @@ namespace OpenRCT2::Ui::Windows
gDropdownItems[i].Format = STR_OPTIONS_DROPDOWN_ITEM;
gDropdownItems[i].Args = reinterpret_cast(NetworkGetGroupName(i));
}
- if (widget == &window_multiplayer_groups_widgets[WIDX_DEFAULT_GROUP_DROPDOWN])
+ if (widget == &widgets[WIDX_DEFAULT_GROUP_DROPDOWN])
{
Dropdown::SetChecked(NetworkGetGroupIndex(NetworkGetDefaultGroup()), true);
}
- else if (widget == &window_multiplayer_groups_widgets[WIDX_SELECTED_GROUP_DROPDOWN])
+ else if (widget == &widgets[WIDX_SELECTED_GROUP_DROPDOWN])
{
Dropdown::SetChecked(NetworkGetGroupIndex(_selectedGroup), true);
}
@@ -572,8 +568,7 @@ namespace OpenRCT2::Ui::Windows
}
screenSize = { 0, NetworkGetNumPlayers() * kScrollableRowHeight };
- int32_t i = screenSize.height - window_multiplayer_players_widgets[WIDX_LIST].bottom
- + window_multiplayer_players_widgets[WIDX_LIST].top + 21;
+ int32_t i = screenSize.height - widgets[WIDX_LIST].bottom + widgets[WIDX_LIST].top + 21;
if (i < 0)
i = 0;
if (i < scrolls[0].contentOffsetY)
@@ -593,8 +588,7 @@ namespace OpenRCT2::Ui::Windows
}
screenSize = { 0, NetworkGetNumActions() * kScrollableRowHeight };
- int32_t i = screenSize.height - window_multiplayer_groups_widgets[WIDX_LIST].bottom
- + window_multiplayer_groups_widgets[WIDX_LIST].top + 21;
+ int32_t i = screenSize.height - widgets[WIDX_LIST].bottom + widgets[WIDX_LIST].top + 21;
if (i < 0)
i = 0;
if (i < scrolls[0].contentOffsetY)
@@ -842,7 +836,7 @@ namespace OpenRCT2::Ui::Windows
{
thread_local std::string _buffer;
- Widget* widget = &window_multiplayer_groups_widgets[WIDX_DEFAULT_GROUP];
+ Widget* widget = &widgets[WIDX_DEFAULT_GROUP];
int32_t group = NetworkGetGroupIndex(NetworkGetDefaultGroup());
if (group != -1)
{
@@ -857,8 +851,7 @@ namespace OpenRCT2::Ui::Windows
}
auto screenPos = windowPos
- + ScreenCoordsXY{ window_multiplayer_groups_widgets[WIDX_CONTENT_PANEL].left + 4,
- window_multiplayer_groups_widgets[WIDX_CONTENT_PANEL].top + 4 };
+ + ScreenCoordsXY{ widgets[WIDX_CONTENT_PANEL].left + 4, widgets[WIDX_CONTENT_PANEL].top + 4 };
DrawTextBasic(dpi, screenPos, STR_DEFAULT_GROUP, {}, { colours[2] });
@@ -868,7 +861,7 @@ namespace OpenRCT2::Ui::Windows
dpi, { screenPos - ScreenCoordsXY{ 0, 6 }, screenPos + ScreenCoordsXY{ 310, -5 } }, colours[1],
INSET_RECT_FLAG_BORDER_INSET);
- widget = &window_multiplayer_groups_widgets[WIDX_SELECTED_GROUP];
+ widget = &widgets[WIDX_SELECTED_GROUP];
group = NetworkGetGroupIndex(_selectedGroup);
if (group != -1)
{
diff --git a/src/openrct2-ui/windows/NetworkStatus.cpp b/src/openrct2-ui/windows/NetworkStatus.cpp
index db730f4a0f..0b80ce3268 100644
--- a/src/openrct2-ui/windows/NetworkStatus.cpp
+++ b/src/openrct2-ui/windows/NetworkStatus.cpp
@@ -26,11 +26,10 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget window_network_status_widgets[] = {
+ static constexpr Widget window_network_status_widgets[] = {
MakeWidget({ 0, 0}, {400, 91}, WindowWidgetType::Frame, WindowColour::Primary ), // panel / background
MakeWidget({ 1, 1}, {397, 14}, WindowWidgetType::Caption, WindowColour::Primary, STR_NONE, STR_WINDOW_TITLE_TIP), // title bar
MakeWidget({388, 2}, { 11, 12}, WindowWidgetType::CloseBox, WindowColour::Primary, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP), // close x button
- kWidgetsEnd,
};
// clang-format on
@@ -39,7 +38,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_network_status_widgets;
+ SetWidgets(window_network_status_widgets);
WindowInitScrollWidgets(*this);
frame_no = 0;
diff --git a/src/openrct2-ui/windows/NewCampaign.cpp b/src/openrct2-ui/windows/NewCampaign.cpp
index e000ad9c2d..1fb2cdcc57 100644
--- a/src/openrct2-ui/windows/NewCampaign.cpp
+++ b/src/openrct2-ui/windows/NewCampaign.cpp
@@ -50,7 +50,7 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget window_new_campaign_widgets[] = {
+ static constexpr Widget window_new_campaign_widgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget ({ 14, 24}, {126, 12}, WindowWidgetType::Label, WindowColour::Primary, STR_EMPTY ), // ride label
MakeWidget ({100, 24}, {242, 12}, WindowWidgetType::DropdownMenu, WindowColour::Primary, STR_EMPTY ), // ride dropdown
@@ -58,7 +58,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({ 14, 41}, {126, 14}, WindowWidgetType::Label, WindowColour::Primary, STR_LENGTH_OF_TIME ), // weeks label
MakeSpinnerWidgets({120, 41}, {100, 14}, WindowWidgetType::Spinner, WindowColour::Primary, STR_EMPTY ), // weeks (3 widgets)
MakeWidget ({ 14, 89}, {322, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_MARKETING_START_THIS_MARKETING_CAMPAIGN), // start button
- kWidgetsEnd,
};
// clang-format on
@@ -175,7 +174,7 @@ namespace OpenRCT2::Ui::Windows
void OnOpen() override
{
- widgets = window_new_campaign_widgets;
+ SetWidgets(window_new_campaign_widgets);
hold_down_widgets = (1uLL << WIDX_WEEKS_INCREASE_BUTTON) | (1uLL << WIDX_WEEKS_DECREASE_BUTTON);
WindowInitScrollWidgets(*this);
}
diff --git a/src/openrct2-ui/windows/NewRide.cpp b/src/openrct2-ui/windows/NewRide.cpp
index 0837982e8e..e17681f485 100644
--- a/src/openrct2-ui/windows/NewRide.cpp
+++ b/src/openrct2-ui/windows/NewRide.cpp
@@ -209,7 +209,7 @@ namespace OpenRCT2::Ui::Windows
static constexpr ScreenSize GroupTrackTypeSize{ GroupByTrackTypeWidth, 14 };
// clang-format off
- static Widget window_new_ride_widgets[] = {
+ static constexpr Widget window_new_ride_widgets[] = {
WINDOW_SHIM(WindowTitle, WindowWidth, WindowHeight),
MakeWidget({ 0, 43}, {601, 339}, WindowWidgetType::Resize, WindowColour::Secondary ),
MakeTab ({ 3, 17}, STR_TRANSPORT_RIDES_TIP ),
@@ -227,7 +227,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({ 4, 46}, {211, 14}, WindowWidgetType::TextBox, WindowColour::Secondary ),
MakeWidget({218, 46}, { 70, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_OBJECT_SEARCH_CLEAR ),
MakeWidget(GroupByTrackTypeOrigin, GroupTrackTypeSize, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_GROUP_BY_TRACK_TYPE, STR_GROUP_BY_TRACK_TYPE_TIP ),
- kWidgetsEnd,
};
// clang-format on
@@ -300,7 +299,7 @@ namespace OpenRCT2::Ui::Windows
void OnOpen() override
{
- widgets = window_new_ride_widgets;
+ SetWidgets(window_new_ride_widgets);
PopulateRideList();
InitScrollWidgets();
_filter.clear();
diff --git a/src/openrct2-ui/windows/News.cpp b/src/openrct2-ui/windows/News.cpp
index dcfa354f2f..3881d3b223 100644
--- a/src/openrct2-ui/windows/News.cpp
+++ b/src/openrct2-ui/windows/News.cpp
@@ -39,11 +39,10 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget window_news_widgets[] = {
+ static constexpr Widget window_news_widgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({372, 18}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Primary, ImageId(SPR_TAB_GEARS_0)), // settings
MakeWidget({ 4, 44}, {392, 252}, WindowWidgetType::Scroll, WindowColour::Primary, SCROLL_VERTICAL), // scroll
- kWidgetsEnd,
};
// clang-format on
@@ -59,7 +58,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_news_widgets;
+ SetWidgets(window_news_widgets);
WindowInitScrollWidgets(*this);
_pressedNewsItemIndex = -1;
diff --git a/src/openrct2-ui/windows/NewsOptions.cpp b/src/openrct2-ui/windows/NewsOptions.cpp
index c3f952412e..d4f374c8fa 100644
--- a/src/openrct2-ui/windows/NewsOptions.cpp
+++ b/src/openrct2-ui/windows/NewsOptions.cpp
@@ -72,7 +72,7 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget WindowNewsOptionsWidgets[] = {
+ static constexpr Widget WindowNewsOptionsWidgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({ 0, 43}, {400, 257}, WindowWidgetType::Resize, WindowColour::Secondary), // Tab content panel
MakeTab ({ 3, 17} ), // Park tab
@@ -87,7 +87,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({ 0, 0}, {343, 14}, WindowWidgetType::Checkbox, WindowColour::Tertiary ),
MakeWidget({ 0, 0}, {343, 14}, WindowWidgetType::Checkbox, WindowColour::Tertiary ),
MakeWidget({ 0, 0}, {343, 14}, WindowWidgetType::Checkbox, WindowColour::Tertiary ),
- kWidgetsEnd,
};
// clang-format on
@@ -96,7 +95,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = WindowNewsOptionsWidgets;
+ SetWidgets(WindowNewsOptionsWidgets);
InitScrollWidgets();
colours[0] = COLOUR_GREY;
colours[1] = COLOUR_LIGHT_BLUE;
@@ -161,7 +160,7 @@ namespace OpenRCT2::Ui::Windows
const auto& baseCheckBox = widgets[WIDX_CHECKBOX_0];
int32_t y = baseCheckBox.top;
- int32_t checkboxWidgetIndex = WIDX_CHECKBOX_0;
+ uint16_t checkboxWidgetIndex = WIDX_CHECKBOX_0;
Widget* checkboxWidget = &widgets[checkboxWidgetIndex];
for (size_t i = 0; i < std::size(NewsItemOptionDefinitions); i++)
{
@@ -185,7 +184,7 @@ namespace OpenRCT2::Ui::Windows
}
// Remove unused checkboxes
- while (checkboxWidget->type != WindowWidgetType::Last)
+ while (checkboxWidgetIndex < widgets.size())
{
checkboxWidget->type = WindowWidgetType::Empty;
checkboxWidgetIndex++;
diff --git a/src/openrct2-ui/windows/ObjectLoadError.cpp b/src/openrct2-ui/windows/ObjectLoadError.cpp
index bfa6916dcb..e10784baa6 100644
--- a/src/openrct2-ui/windows/ObjectLoadError.cpp
+++ b/src/openrct2-ui/windows/ObjectLoadError.cpp
@@ -279,7 +279,7 @@ namespace OpenRCT2::Ui::Windows
constexpr int32_t TYPE_COL_LEFT = 5 * WW_LESS_PADDING / 8 + 1;
// clang-format off
- static Widget window_object_load_error_widgets[] = {
+ static constexpr Widget window_object_load_error_widgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({ NAME_COL_LEFT, 57}, {108, 14}, WindowWidgetType::TableHeader, WindowColour::Primary, STR_OBJECT_NAME ), // 'Object name' header
MakeWidget({SOURCE_COL_LEFT, 57}, {166, 14}, WindowWidgetType::TableHeader, WindowColour::Primary, STR_OBJECT_SOURCE ), // 'Object source' header
@@ -290,7 +290,6 @@ namespace OpenRCT2::Ui::Windows
#ifndef DISABLE_HTTP
MakeWidget({ 300, 377}, {146, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_DOWNLOAD_ALL, STR_DOWNLOAD_ALL_TIP ), // Download all button
#endif
- kWidgetsEnd,
};
// clang-format on
@@ -397,7 +396,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_object_load_error_widgets;
+ SetWidgets(window_object_load_error_widgets);
WindowInitScrollWidgets(*this);
colours[0] = COLOUR_LIGHT_BLUE;
diff --git a/src/openrct2-ui/windows/Options.cpp b/src/openrct2-ui/windows/Options.cpp
index 164390d9f6..fbd8b2a782 100644
--- a/src/openrct2-ui/windows/Options.cpp
+++ b/src/openrct2-ui/windows/Options.cpp
@@ -248,7 +248,7 @@ namespace OpenRCT2::Ui::Windows
MakeTab({ 158, 17 }, STR_OPTIONS_MISCELLANEOUS_TIP), \
MakeTab({ 189, 17 }, STR_OPTIONS_ADVANCED)
- static Widget window_options_display_widgets[] = {
+ static constexpr Widget window_options_display_widgets[] = {
MAIN_OPTIONS_WIDGETS,
MakeWidget ({ 5, 53}, {300, 170}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_HARDWARE_GROUP ), // Hardware group
MakeWidget ({ 10, 67}, {145, 12}, WindowWidgetType::Label, WindowColour::Secondary, STR_FULLSCREEN_MODE, STR_FULLSCREEN_MODE_TIP ), // Fullscreen
@@ -269,13 +269,12 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({ 11, 176}, {143, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_USE_VSYNC, STR_USE_VSYNC_TIP ), // Use vsync
MakeWidget ({ 11, 191}, {280, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_MINIMISE_FULLSCREEN_ON_FOCUS_LOSS, STR_MINIMISE_FULLSCREEN_ON_FOCUS_LOSS_TIP), // Minimise fullscreen focus loss
MakeWidget ({ 11, 206}, {280, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_DISABLE_SCREENSAVER, STR_DISABLE_SCREENSAVER_TIP ), // Disable screensaver
- kWidgetsEnd,
};
constexpr int32_t kFrameRenderingStart = 53;
constexpr int32_t kFrameEffectStart = 163;
- static Widget window_options_rendering_widgets[] = {
+ static constexpr Widget window_options_rendering_widgets[] = {
MAIN_OPTIONS_WIDGETS,
MakeWidget({ 5, kFrameRenderingStart + 0}, {300, 108}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_RENDERING_GROUP ), // Rendering group
MakeWidget({ 10, kFrameRenderingStart + 15}, {281, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_TILE_SMOOTHING, STR_TILE_SMOOTHING_TIP ), // Landscape smoothing
@@ -293,10 +292,9 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({40, kFrameEffectStart + 45}, {251, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_ENABLE_LIGHTING_VEHICLES, STR_ENABLE_LIGHTING_VEHICLES_TIP), // Enable light fx for vehicles
MakeWidget({10, kFrameEffectStart + 60}, {281, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_RENDER_WEATHER_EFFECTS, STR_RENDER_WEATHER_EFFECTS_TIP ), // Render weather effects
MakeWidget({25, kFrameEffectStart + 75}, {266, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_DISABLE_LIGHTNING_EFFECT, STR_DISABLE_LIGHTNING_EFFECT_TIP), // Disable lightning effect
- kWidgetsEnd,
};
- static Widget window_options_culture_widgets[] = {
+ static constexpr Widget window_options_culture_widgets[] = {
MAIN_OPTIONS_WIDGETS,
MakeWidget({ 10, 53}, {145, 12}, WindowWidgetType::Label, WindowColour::Secondary, STR_OPTIONS_LANGUAGE, STR_LANGUAGE_TIP ), // language
MakeWidget({155, 53}, {145, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_STRING ),
@@ -316,10 +314,9 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({ 10, 128}, {145, 12}, WindowWidgetType::Label, WindowColour::Secondary, STR_DATE_FORMAT, STR_DATE_FORMAT_TIP ), // Date format
MakeWidget({155, 128}, {145, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ),
MakeWidget({288, 129}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_DATE_FORMAT_TIP ),
- kWidgetsEnd,
};
- static Widget window_options_audio_widgets[] = {
+ static constexpr Widget window_options_audio_widgets[] = {
MAIN_OPTIONS_WIDGETS,
MakeWidget({ 10, 53}, {290, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ), // Audio device
MakeWidget({288, 54}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_AUDIO_DEVICE_TIP ),
@@ -333,14 +330,13 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({155, 68}, {145, 13}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_HORIZONTAL ), // Master volume
MakeWidget({155, 83}, {145, 13}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_HORIZONTAL ), // Sound effect volume
MakeWidget({155, 98}, {145, 13}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_HORIZONTAL ), // Music volume
- kWidgetsEnd,
};
constexpr int32_t kControlsGroupStart = 53;
constexpr int32_t kThemesGroupStart = 193;
constexpr int32_t kToolbarGroupStart = 245;
- static Widget window_options_controls_and_interface_widgets[] = {
+ static constexpr Widget window_options_controls_and_interface_widgets[] = {
MAIN_OPTIONS_WIDGETS,
MakeWidget({ 5, kControlsGroupStart + 0}, {300,137}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_CONTROLS_GROUP ), // Controls group
MakeWidget({ 10, kControlsGroupStart + 13}, {290, 14}, WindowWidgetType::Checkbox, WindowColour::Tertiary , STR_SCREEN_EDGE_SCROLLING, STR_SCREEN_EDGE_SCROLLING_TIP ), // Edge scrolling
@@ -368,7 +364,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({ 24, kToolbarGroupStart + 76}, {162, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary , STR_MUTE_BUTTON_ON_TOOLBAR, STR_MUTE_BUTTON_ON_TOOLBAR_TIP ), // Mute
MakeWidget({155, kToolbarGroupStart + 76}, {145, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary , STR_CHAT_BUTTON_ON_TOOLBAR, STR_CHAT_BUTTON_ON_TOOLBAR_TIP ), // Chat
MakeWidget({ 24, kToolbarGroupStart + 91}, {122, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary , STR_ZOOM_BUTTON_ON_TOOLBAR, STR_ZOOM_BUTTON_ON_TOOLBAR_TIP ), // Zoom
- kWidgetsEnd,
};
constexpr int32_t kTitleSequenceStart = 53;
@@ -376,7 +371,7 @@ namespace OpenRCT2::Ui::Windows
constexpr int32_t kScenarioOptionsGroupStart = kScenarioGroupStart + 55;
constexpr int32_t kTweaksStart = kScenarioOptionsGroupStart + 39;
- static Widget window_options_misc_widgets[] = {
+ static constexpr Widget window_options_misc_widgets[] = {
MAIN_OPTIONS_WIDGETS,
MakeWidget( { 5, kTitleSequenceStart + 0}, {300, 31}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_OPTIONS_TITLE_SEQUENCE ),
MakeDropdownWidgets({ 10, kTitleSequenceStart + 15}, {290, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_STRINGID, STR_TITLE_SEQUENCE_TIP), // Title sequence dropdown
@@ -398,10 +393,9 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({ 10, kTweaksStart + 77}, {165, 12}, WindowWidgetType::Label, WindowColour::Secondary, STR_DEFAULT_INSPECTION_INTERVAL, STR_DEFAULT_INSPECTION_INTERVAL_TIP),
MakeWidget({175, kTweaksStart + 76}, {125, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ), // Default inspection time dropdown
MakeWidget({288, kTweaksStart + 77}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_DEFAULT_INSPECTION_INTERVAL_TIP ), // Default inspection time dropdown button
- kWidgetsEnd,
};
- static Widget window_options_advanced_widgets[] = {
+ static constexpr Widget window_options_advanced_widgets[] = {
MAIN_OPTIONS_WIDGETS,
MakeWidget ({ 10, 54}, {290, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary, STR_ENABLE_DEBUGGING_TOOLS, STR_ENABLE_DEBUGGING_TOOLS_TIP ), // Enable debugging tools
MakeWidget ({ 10, 69}, {290, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary, STR_SAVE_PLUGIN_DATA, STR_SAVE_PLUGIN_DATA_TIP ), // Export plug-in objects with saved games
@@ -420,10 +414,9 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({150, 192}, {150, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_EXPORT_EMSCRIPTEN, STR_NONE ), // Emscripten data export
MakeWidget ({150, 208}, {150, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_IMPORT_EMSCRIPTEN, STR_NONE ), // Emscripten data import
#endif
- kWidgetsEnd,
};
- static Widget *window_options_page_widgets[] = {
+ static constexpr std::span window_options_page_widgets[] = {
window_options_display_widgets,
window_options_rendering_widgets,
window_options_culture_widgets,
@@ -441,10 +434,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_options_display_widgets;
- page = WINDOW_OPTIONS_PAGE_DISPLAY;
- frame_no = 0;
- InitScrollWidgets();
+ SetPage(WINDOW_OPTIONS_PAGE_DISPLAY);
}
void OnMouseUp(WidgetIndex widgetIndex) override
@@ -663,11 +653,6 @@ namespace OpenRCT2::Ui::Windows
void CommonPrepareDrawBefore()
{
- if (window_options_page_widgets[page] != widgets)
- {
- widgets = window_options_page_widgets[page];
- InitScrollWidgets();
- }
SetPressedTab();
disabled_widgets = 0;
@@ -684,9 +669,10 @@ namespace OpenRCT2::Ui::Windows
{
// Automatically adjust window height to fit widgets
int32_t y = 0;
- for (auto widget = &widgets[WIDX_PAGE_START]; widget->type != WindowWidgetType::Last; widget++)
+ for (WidgetIndex widgetIdx = WIDX_PAGE_START; widgetIdx < widgets.size(); widgetIdx++)
{
- y = std::max(y, widget->bottom);
+ const auto& widget = widgets[widgetIdx];
+ y = std::max(y, widget.bottom);
}
height = y + 6;
ResizeFrameWithPage();
@@ -2107,7 +2093,7 @@ namespace OpenRCT2::Ui::Windows
page = p;
frame_no = 0;
pressed_widgets = 0;
- widgets = window_options_page_widgets[page];
+ SetWidgets(window_options_page_widgets[page]);
Invalidate();
OnResize();
diff --git a/src/openrct2-ui/windows/Park.cpp b/src/openrct2-ui/windows/Park.cpp
index 123efe5141..47b0589674 100644
--- a/src/openrct2-ui/windows/Park.cpp
+++ b/src/openrct2-ui/windows/Park.cpp
@@ -100,7 +100,7 @@ namespace OpenRCT2::Ui::Windows
MakeTab({ 189, 17 }, STR_PARK_AWARDS_TAB_TIP) /* tab 7 */
// clang-format off
- static Widget _entranceWidgets[] = {
+ static constexpr Widget _entranceWidgets[] = {
MAIN_PARK_WIDGETS(230),
MakeWidget({ 3, 46}, {202, 115}, WindowWidgetType::Viewport, WindowColour::Secondary ), // viewport
MakeWidget({ 3, 161}, {202, 11}, WindowWidgetType::LabelCentred, WindowColour::Secondary ), // status
@@ -110,43 +110,36 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({205, 121}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_RENAME), STR_NAME_PARK_TIP ), // rename
MakeWidget({210, 51}, { 14, 15}, WindowWidgetType::ImgBtn, WindowColour::Secondary, ImageId(SPR_G2_RCT1_CLOSE_BUTTON_0), STR_CLOSE_PARK_TIP ),
MakeWidget({210, 66}, { 14, 14}, WindowWidgetType::ImgBtn, WindowColour::Secondary, ImageId(SPR_G2_RCT1_OPEN_BUTTON_0), STR_OPEN_PARK_TIP ),
- kWidgetsEnd,
};
- static Widget _ratingWidgets[] = {
+ static constexpr Widget _ratingWidgets[] = {
MAIN_PARK_WIDGETS(255),
- kWidgetsEnd,
};
- static Widget _guestsWidgets[] = {
+ static constexpr Widget _guestsWidgets[] = {
MAIN_PARK_WIDGETS(255),
- kWidgetsEnd,
};
- static Widget _priceWidgets[] = {
+ static constexpr Widget _priceWidgets[] = {
MAIN_PARK_WIDGETS(230),
MakeWidget ({ 21, 50}, {126, 14}, WindowWidgetType::Label, WindowColour::Secondary, STR_ADMISSION_PRICE),
MakeSpinnerWidgets({147, 50}, { 76, 14}, WindowWidgetType::Spinner, WindowColour::Secondary ), // Price (3 widgets)
- kWidgetsEnd,
};
- static Widget _statsWidgets[] = {
+ static constexpr Widget _statsWidgets[] = {
MAIN_PARK_WIDGETS(230),
- kWidgetsEnd,
};
- static Widget _objectiveWidgets[] = {
+ static constexpr Widget _objectiveWidgets[] = {
MAIN_PARK_WIDGETS(230),
MakeWidget({7, 207}, {216, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_ENTER_NAME_INTO_SCENARIO_CHART), // enter name
- kWidgetsEnd,
};
- static Widget _awardsWidgets[] = {
+ static constexpr Widget _awardsWidgets[] = {
MAIN_PARK_WIDGETS(230),
- kWidgetsEnd,
};
- static std::array _pagedWidgets = {
+ static std::span _pagedWidgets[] = {
_entranceWidgets,
_ratingWidgets,
_guestsWidgets,
@@ -523,7 +516,7 @@ namespace OpenRCT2::Ui::Windows
void OnPrepareDrawEntrance()
{
const auto& gameState = GetGameState();
- widgets = _pagedWidgets[page];
+ SetWidgets(_pagedWidgets[page]);
InitScrollWidgets();
SetPressedTab();
@@ -701,13 +694,6 @@ namespace OpenRCT2::Ui::Windows
void OnPrepareDrawRating()
{
- auto* ratingWidgets = _pagedWidgets[page];
- if (ratingWidgets != widgets)
- {
- widgets = ratingWidgets;
- InitScrollWidgets();
- }
-
SetPressedTab();
PrepareWindowTitleText();
@@ -777,13 +763,6 @@ namespace OpenRCT2::Ui::Windows
void OnPrepareDrawGuests()
{
- auto* guestsWidgets = _pagedWidgets[page];
- if (widgets != guestsWidgets)
- {
- widgets = guestsWidgets;
- InitScrollWidgets();
- }
-
SetPressedTab();
PrepareWindowTitleText();
@@ -887,13 +866,6 @@ namespace OpenRCT2::Ui::Windows
void OnPrepareDrawPrice()
{
- auto* priceWidgets = _pagedWidgets[page];
- if (widgets != priceWidgets)
- {
- widgets = priceWidgets;
- InitScrollWidgets();
- }
-
SetPressedTab();
PrepareWindowTitleText();
@@ -979,13 +951,6 @@ namespace OpenRCT2::Ui::Windows
void OnPrepareDrawStats()
{
- auto* statsWidgets = _pagedWidgets[page];
- if (widgets != statsWidgets)
- {
- widgets = statsWidgets;
- InitScrollWidgets();
- }
-
SetPressedTab();
PrepareWindowTitleText();
@@ -1179,13 +1144,6 @@ namespace OpenRCT2::Ui::Windows
void OnPrepareDrawAwards()
{
- auto* awardsWidgets = _pagedWidgets[page];
- if (widgets != awardsWidgets)
- {
- widgets = awardsWidgets;
- InitScrollWidgets();
- }
-
SetPressedTab();
PrepareWindowTitleText();
@@ -1233,9 +1191,10 @@ namespace OpenRCT2::Ui::Windows
RemoveViewport();
hold_down_widgets = _pagedHoldDownWidgets[newPage];
- widgets = _pagedWidgets[newPage];
+ SetWidgets(_pagedWidgets[newPage]);
SetDisabledTabs();
Invalidate();
+ InitScrollWidgets();
OnResize();
OnPrepareDraw();
diff --git a/src/openrct2-ui/windows/PatrolArea.cpp b/src/openrct2-ui/windows/PatrolArea.cpp
index ad9eef35ab..0c0129f24e 100644
--- a/src/openrct2-ui/windows/PatrolArea.cpp
+++ b/src/openrct2-ui/windows/PatrolArea.cpp
@@ -45,12 +45,11 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget PatrolAreaWidgets[] = {
+ static constexpr Widget PatrolAreaWidgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget ({27, 17}, {44, 32}, WindowWidgetType::ImgBtn, WindowColour::Primary , ImageId(SPR_LAND_TOOL_SIZE_0) ), // preview box
MakeRemapWidget({28, 18}, {16, 16}, WindowWidgetType::TrnBtn, WindowColour::Tertiary, SPR_LAND_TOOL_DECREASE, STR_ADJUST_SMALLER_PATROL_AREA_TIP), // decrement size
MakeRemapWidget({54, 32}, {16, 16}, WindowWidgetType::TrnBtn, WindowColour::Tertiary, SPR_LAND_TOOL_INCREASE, STR_ADJUST_LARGER_PATROL_AREA_TIP ), // increment size
- kWidgetsEnd,
};
// clang-format on
@@ -59,7 +58,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = PatrolAreaWidgets;
+ SetWidgets(PatrolAreaWidgets);
hold_down_widgets = (1uLL << WIDX_INCREMENT) | (1uLL << WIDX_DECREMENT);
WindowInitScrollWidgets(*this);
WindowPushOthersBelow(*this);
@@ -133,7 +132,7 @@ namespace OpenRCT2::Ui::Windows
void OnPrepareDraw() override
{
SetWidgetPressed(WIDX_PREVIEW, true);
- PatrolAreaWidgets[WIDX_PREVIEW].image = ImageId(LandTool::SizeToSpriteIndex(gLandToolSize));
+ widgets[WIDX_PREVIEW].image = ImageId(LandTool::SizeToSpriteIndex(gLandToolSize));
}
void OnDraw(DrawPixelInfo& dpi) override
@@ -143,8 +142,8 @@ namespace OpenRCT2::Ui::Windows
// Draw number for tool sizes bigger than 7
if (gLandToolSize > kLandToolMaximumSizeWithSprite)
{
- auto screenCoords = ScreenCoordsXY{ windowPos.x + PatrolAreaWidgets[WIDX_PREVIEW].midX(),
- windowPos.y + PatrolAreaWidgets[WIDX_PREVIEW].midY() };
+ auto screenCoords = ScreenCoordsXY{ windowPos.x + widgets[WIDX_PREVIEW].midX(),
+ windowPos.y + widgets[WIDX_PREVIEW].midY() };
auto ft = Formatter();
ft.Add(gLandToolSize);
DrawTextBasic(
diff --git a/src/openrct2-ui/windows/Player.cpp b/src/openrct2-ui/windows/Player.cpp
index 6583dda356..a191327c4a 100644
--- a/src/openrct2-ui/windows/Player.cpp
+++ b/src/openrct2-ui/windows/Player.cpp
@@ -57,22 +57,20 @@ namespace OpenRCT2::Ui::Windows
MakeTab({ 3, 17 }), \
MakeTab({ 34, 17 })
- static Widget window_player_overview_widgets[] = {
+ static constexpr Widget window_player_overview_widgets[] = {
WINDOW_PLAYER_COMMON_WIDGETS,
MakeWidget({ 3, 46}, {175, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ), // Permission group
MakeWidget({167, 47}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH ),
MakeWidget({179, 45}, { 12, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_LOCATE), STR_LOCATE_PLAYER_TIP), // Locate button
MakeWidget({179, 69}, { 12, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_DEMOLISH), STR_KICK_PLAYER_TIP ), // Kick button
MakeWidget({ 3, 60}, {175, 61}, WindowWidgetType::Viewport, WindowColour::Secondary ), // Viewport
- kWidgetsEnd,
};
- static Widget window_player_statistics_widgets[] = {
+ static constexpr Widget window_player_statistics_widgets[] = {
WINDOW_PLAYER_COMMON_WIDGETS,
- kWidgetsEnd,
};
- static Widget *window_player_page_widgets[] = {
+ static constexpr std::span window_player_page_widgets[] = {
window_player_overview_widgets,
window_player_statistics_widgets,
};
@@ -104,12 +102,9 @@ namespace OpenRCT2::Ui::Windows
min_height = 134;
max_width = 500;
max_height = 450;
-
- Invalidate();
-
- widgets = window_player_page_widgets[WINDOW_PLAYER_PAGE_OVERVIEW];
hold_down_widgets = 0;
pressed_widgets = 0;
+ SetPage(WINDOW_PLAYER_PAGE_OVERVIEW);
}
void OnResize() override
@@ -221,7 +216,7 @@ namespace OpenRCT2::Ui::Windows
hold_down_widgets = 0;
pressed_widgets = 0;
- widgets = window_player_page_widgets[newPage];
+ SetWidgets(window_player_page_widgets[newPage]);
Invalidate();
OnResize();
OnPrepareDraw();
@@ -376,12 +371,6 @@ namespace OpenRCT2::Ui::Windows
return;
}
- if (window_player_page_widgets[page] != widgets)
- {
- widgets = window_player_page_widgets[page];
- InitScrollWidgets();
- }
-
pressed_widgets &= ~(WIDX_TAB_1);
pressed_widgets &= ~(WIDX_TAB_2);
pressed_widgets |= 1uLL << (page + WIDX_TAB_1);
@@ -406,7 +395,7 @@ namespace OpenRCT2::Ui::Windows
if (viewport != nullptr)
{
- Widget* viewportWidget = &window_player_overview_widgets[WIDX_VIEWPORT];
+ Widget* viewportWidget = &widgets[WIDX_VIEWPORT];
viewport->pos = windowPos + ScreenCoordsXY{ viewportWidget->left, viewportWidget->top };
viewport->width = viewportWidget->width();
@@ -435,7 +424,7 @@ namespace OpenRCT2::Ui::Windows
int32_t groupindex = NetworkGetGroupIndex(NetworkGetPlayerGroup(player));
if (groupindex != -1)
{
- Widget* widget = &window_player_overview_widgets[WIDX_GROUP];
+ Widget* widget = &widgets[WIDX_GROUP];
thread_local std::string _buffer;
_buffer.assign("{WINDOW_COLOUR_2}");
@@ -594,12 +583,6 @@ namespace OpenRCT2::Ui::Windows
void OnPrepareDrawStatistics()
{
- if (window_player_page_widgets[page] != widgets)
- {
- widgets = window_player_page_widgets[page];
- InitScrollWidgets();
- }
-
pressed_widgets &= ~(WIDX_TAB_1);
pressed_widgets &= ~(WIDX_TAB_2);
pressed_widgets |= 1uLL << (page + WIDX_TAB_1);
@@ -623,8 +606,7 @@ namespace OpenRCT2::Ui::Windows
}
auto screenCoords = windowPos
- + ScreenCoordsXY{ window_player_overview_widgets[WIDX_PAGE_BACKGROUND].left + 4,
- window_player_overview_widgets[WIDX_PAGE_BACKGROUND].top + 4 };
+ + ScreenCoordsXY{ widgets[WIDX_PAGE_BACKGROUND].left + 4, widgets[WIDX_PAGE_BACKGROUND].top + 4 };
auto ft = Formatter();
ft.Add(NetworkGetPlayerCommandsRan(player));
diff --git a/src/openrct2-ui/windows/ProgressWindow.cpp b/src/openrct2-ui/windows/ProgressWindow.cpp
index e9e87dd6f9..dec1db3bec 100644
--- a/src/openrct2-ui/windows/ProgressWindow.cpp
+++ b/src/openrct2-ui/windows/ProgressWindow.cpp
@@ -34,11 +34,10 @@ namespace OpenRCT2::Ui::Windows
static constexpr int32_t kWindowHeight = 90;
// clang-format off
- static Widget kProgressWindowWidgets[] = {
+ static constexpr Widget kProgressWindowWidgets[] = {
MakeWidget({ 0, 0}, { kWindowWidth, kWindowHeight}, WindowWidgetType::Frame, WindowColour::Primary ), // panel / background
MakeWidget({ 1, 1}, {kWindowWidth - 3, 14}, WindowWidgetType::Caption, WindowColour::Primary, STR_STRINGID, STR_WINDOW_TITLE_TIP), // title bar
MakeWidget({kWindowWidth - 12, 2}, { 11, 12}, WindowWidgetType::CloseBox, WindowColour::Primary, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP), // close x button
- kWidgetsEnd,
};
struct LoaderVehicleStyle
@@ -85,7 +84,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = kProgressWindowWidgets;
+ SetWidgets(kProgressWindowWidgets);
WindowInitScrollWidgets(*this);
frame_no = 0;
diff --git a/src/openrct2-ui/windows/RefurbishRidePrompt.cpp b/src/openrct2-ui/windows/RefurbishRidePrompt.cpp
index c0a8284928..e157fb33b8 100644
--- a/src/openrct2-ui/windows/RefurbishRidePrompt.cpp
+++ b/src/openrct2-ui/windows/RefurbishRidePrompt.cpp
@@ -34,12 +34,11 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget window_ride_refurbish_widgets[] =
+ static constexpr Widget window_ride_refurbish_widgets[] =
{
WINDOW_SHIM_WHITE(STR_REFURBISH_RIDE, WW, WH),
MakeWidget({ 10, WH - 22 }, { 85, 14 }, WindowWidgetType::Button, WindowColour::Primary, STR_REFURBISH),
MakeWidget({ WW - 95, WH - 22 }, { 85, 14 }, WindowWidgetType::Button, WindowColour::Primary, STR_SAVE_PROMPT_CANCEL),
- kWidgetsEnd,
};
// clang-format on
@@ -56,7 +55,7 @@ namespace OpenRCT2::Ui::Windows
void OnOpen() override
{
- widgets = window_ride_refurbish_widgets;
+ SetWidgets(window_ride_refurbish_widgets);
WindowInitScrollWidgets(*this);
}
diff --git a/src/openrct2-ui/windows/Research.cpp b/src/openrct2-ui/windows/Research.cpp
index f1aff77a4f..7b627ef14c 100644
--- a/src/openrct2-ui/windows/Research.cpp
+++ b/src/openrct2-ui/windows/Research.cpp
@@ -67,7 +67,7 @@ namespace OpenRCT2::Ui::Windows
#pragma region Widgets
// clang-format off
- static Widget window_research_development_widgets[] = {
+ static constexpr Widget window_research_development_widgets[] = {
WINDOW_SHIM(STR_RESEARCH_AND_DEVELOPMENT, WW_DEVELOPMENT, WH_DEVELOPMENT),
MakeWidget({ 0, 43}, { WW_DEVELOPMENT, 153}, WindowWidgetType::Resize, WindowColour::Secondary ),
MakeTab ({ 3, 17}, STR_RESEARCH_AND_DEVELOPMENT_TIP),
@@ -75,10 +75,9 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({ 3, 47}, {WW_DEVELOPMENT - 10, 70}, WindowWidgetType::Groupbox, WindowColour::Tertiary , STR_CURRENTLY_IN_DEVELOPMENT ),
MakeWidget({ 3, 124}, {WW_DEVELOPMENT - 10, 65}, WindowWidgetType::Groupbox, WindowColour::Tertiary , STR_LAST_DEVELOPMENT ),
MakeWidget({265, 161}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Tertiary , 0xFFFFFFFF, STR_RESEARCH_SHOW_DETAILS_TIP ),
- kWidgetsEnd,
};
- static Widget window_research_funding_widgets[] = {
+ static constexpr Widget window_research_funding_widgets[] = {
WINDOW_SHIM(STR_RESEARCH_FUNDING, WW_FUNDING, WH_FUNDING),
MakeWidget({ 0, 43}, { WW_FUNDING, 164}, WindowWidgetType::Resize, WindowColour::Secondary ),
MakeTab ({ 3, 17}, STR_RESEARCH_AND_DEVELOPMENT_TIP ),
@@ -94,10 +93,9 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({ 8, 160}, {WW_FUNDING - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary , STR_RESEARCH_NEW_WATER_RIDES, STR_RESEARCH_NEW_WATER_RIDES_TIP ),
MakeWidget({ 8, 173}, {WW_FUNDING - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary , STR_RESEARCH_NEW_SHOPS_AND_STALLS, STR_RESEARCH_NEW_SHOPS_AND_STALLS_TIP ),
MakeWidget({ 8, 186}, {WW_FUNDING - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary , STR_RESEARCH_NEW_SCENERY_AND_THEMING, STR_RESEARCH_NEW_SCENERY_AND_THEMING_TIP ),
- kWidgetsEnd,
};
- static Widget *window_research_page_widgets[] = {
+ static constexpr std::span window_research_page_widgets[] = {
window_research_development_widgets,
window_research_funding_widgets,
};
@@ -122,7 +120,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = window_research_page_widgets[WINDOW_RESEARCH_PAGE_DEVELOPMENT];
+ SetPage(WINDOW_RESEARCH_PAGE_DEVELOPMENT);
width = WW_DEVELOPMENT;
height = WH_DEVELOPMENT;
ResearchUpdateUncompletedTypes();
@@ -135,7 +133,7 @@ namespace OpenRCT2::Ui::Windows
RemoveViewport();
hold_down_widgets = 0;
- widgets = window_research_page_widgets[newPageIndex];
+ SetWidgets(window_research_page_widgets[newPageIndex]);
disabled_widgets = 0;
pressed_widgets = 0;
@@ -230,14 +228,6 @@ namespace OpenRCT2::Ui::Windows
void OnPrepareDraw() override
{
- auto* targetWidgets = window_research_page_widgets[page];
-
- if (widgets != targetWidgets)
- {
- widgets = targetWidgets;
- InitScrollWidgets();
- }
-
for (auto i = 0; i < WINDOW_RESEARCH_PAGE_COUNT; i++)
{
SetWidgetPressed(WIDX_TAB_1 + i, false);
diff --git a/src/openrct2-ui/windows/Ride.cpp b/src/openrct2-ui/windows/Ride.cpp
index fdb04dc8c4..bffe17ffba 100644
--- a/src/openrct2-ui/windows/Ride.cpp
+++ b/src/openrct2-ui/windows/Ride.cpp
@@ -256,7 +256,7 @@ namespace OpenRCT2::Ui::Windows
MakeTab({ 282, 17 }, STR_CUSTOMER_INFORMATION_TIP)
// 0x009ADC34
- static Widget _mainWidgets[] = {
+ static constexpr Widget _mainWidgets[] = {
MAIN_RIDE_WIDGETS,
MakeWidget({ 3, 60}, {288, 107}, WindowWidgetType::Viewport, WindowColour::Secondary ),
MakeWidget({ 35, 46}, {222, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, kWidgetContentEmpty, STR_VIEW_SELECTION ),
@@ -273,11 +273,10 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({296, 76}, { 14, 14}, WindowWidgetType::ImgBtn, WindowColour::Secondary, ImageId(SPR_G2_RCT1_OPEN_BUTTON_0), STR_OPEN_RIDE_TIP ),
MakeWidget({ 3, 180}, {305, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_ARG_6_STRINGID ),
MakeWidget({297, 180}, { 11, 12}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH ),
- kWidgetsEnd,
};
// 0x009ADDA8
- static Widget _vehicleWidgets[] = {
+ static constexpr Widget _vehicleWidgets[] = {
MAIN_RIDE_WIDGETS,
MakeWidget ({ 7, 50}, {302, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ),
MakeWidget ({297, 51}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH ),
@@ -285,11 +284,10 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({ 7, 154}, {302, 43}, WindowWidgetType::Scroll, WindowColour::Secondary, STR_EMPTY ),
MakeSpinnerWidgets({ 7, 203}, {145, 12}, WindowWidgetType::Spinner, WindowColour::Secondary, STR_RIDE_VEHICLE_COUNT, STR_MAX_VEHICLES_TIP ),
MakeSpinnerWidgets({164, 203}, {145, 12}, WindowWidgetType::Spinner, WindowColour::Secondary, STR_1_CAR_PER_TRAIN, STR_MAX_CARS_PER_TRAIN_TIP),
- kWidgetsEnd,
};
// 0x009ADEFC
- static Widget _operatingWidgets[] = {
+ static constexpr Widget _operatingWidgets[] = {
MAIN_RIDE_WIDGETS,
MakeSpinnerWidgets({157, 61}, {152, 12}, WindowWidgetType::Spinner, WindowColour::Secondary, STR_ARG_18_STRINGID ), // NB: 3 widgets
MakeSpinnerWidgets({157, 75}, {152, 12}, WindowWidgetType::Spinner, WindowColour::Secondary, STR_LIFT_HILL_CHAIN_SPEED_VALUE ), // NB: 3 widgets
@@ -308,11 +306,10 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({297, 110}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH ),
MakeWidget ({ 21, 89}, {129, 12}, WindowWidgetType::Label, WindowColour::Secondary, STR_NUMBER_OF_CIRCUITS, STR_NUMBER_OF_CIRCUITS_TIP ),
MakeSpinnerWidgets({157, 89}, {152, 12}, WindowWidgetType::Spinner, WindowColour::Secondary, STR_NUMBER_OF_CIRCUITS_VALUE ), // NB: 3 widgets
- kWidgetsEnd,
};
// 0x009AE190
- static Widget _maintenanceWidgets[] = {
+ static constexpr Widget _maintenanceWidgets[] = {
MAIN_RIDE_WIDGETS,
MakeWidget({107, 71}, {202, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_EMPTY, STR_SELECT_HOW_OFTEN_A_MECHANIC_SHOULD_CHECK_THIS_RIDE),
MakeWidget({297, 72}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_SELECT_HOW_OFTEN_A_MECHANIC_SHOULD_CHECK_THIS_RIDE),
@@ -321,11 +318,10 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({241, 108}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_NO_ENTRY), STR_DEBUG_FORCE_BREAKDOWN_TIP ),
MakeProgressBar({107, 47}, { 147, 10}, COLOUR_BRIGHT_GREEN),
MakeProgressBar({107, 58}, { 147, 10}, COLOUR_BRIGHT_RED),
- kWidgetsEnd,
};
// 0x009AE2A4
- static Widget _colourWidgets[] = {
+ static constexpr Widget _colourWidgets[] = {
MAIN_RIDE_WIDGETS,
MakeWidget({ 3, 47}, { 68, 47}, WindowWidgetType::Spinner, WindowColour::Secondary ),
MakeWidget({ 74, 49}, {239, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_ARG_14_STRINGID ),
@@ -349,44 +345,40 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({119, 190}, { 12, 12}, WindowWidgetType::ColourBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_SELECT_ADDITIONAL_COLOUR_2_TIP ),
MakeWidget({100, 74}, {239, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_RANDOM_COLOUR ),
MakeWidget({139, 190}, {110, 12}, WindowWidgetType::Button, WindowColour::Secondary, STR_RANDOMISE_VEHICLE_COLOURS, STR_RANDOMISE_VEHICLE_COLOURS_TIP ),
- kWidgetsEnd,
};
// 0x009AE4C8
- static Widget _musicWidgets[] = {
+ static constexpr Widget _musicWidgets[] = {
MAIN_RIDE_WIDGETS,
MakeWidget({ 7, 47}, {302, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_PLAY_MUSIC, STR_SELECT_MUSIC_TIP ),
MakeWidget({ 7, 62}, {302, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_EMPTY ),
MakeWidget({297, 63}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_SELECT_MUSIC_STYLE_TIP),
MakeWidget({154, 90}, {114, 114}, WindowWidgetType::FlatBtn, WindowColour::Secondary ),
MakeWidget({ 7, 90}, {500, 450}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_BOTH ),
- kWidgetsEnd,
};
// 0x009AE5DC
- static Widget _measurementWidgets[] = {
+ static constexpr Widget _measurementWidgets[] = {
MAIN_RIDE_WIDGETS,
MakeWidget({288, 194}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_FLOPPY), STR_SAVE_TRACK_DESIGN),
MakeWidget({ 4, 127}, {154, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_SELECT_NEARBY_SCENERY ),
MakeWidget({158, 127}, {154, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_RESET_SELECTION ),
MakeWidget({ 4, 177}, {154, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_DESIGN_SAVE ),
MakeWidget({158, 177}, {154, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_DESIGN_CANCEL ),
- kWidgetsEnd,
};
// 0x009AE710
- static Widget _graphsWidgets[] = {
+ static constexpr Widget _graphsWidgets[] = {
MAIN_RIDE_WIDGETS,
MakeWidget({ 3, 46}, {306, 112}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_HORIZONTAL, STR_LOGGING_DATA_FROM_TIP ),
MakeWidget({ 3, 163}, { 73, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_RIDE_STATS_VELOCITY, STR_SHOW_GRAPH_OF_VELOCITY_AGAINST_TIME_TIP ),
MakeWidget({ 76, 163}, { 73, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_RIDE_STATS_ALTITUDE, STR_SHOW_GRAPH_OF_ALTITUDE_AGAINST_TIME_TIP ),
MakeWidget({149, 163}, { 73, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_RIDE_STATS_VERT_G, STR_SHOW_GRAPH_OF_VERTICAL_ACCELERATION_AGAINST_TIME_TIP),
MakeWidget({222, 163}, { 73, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_RIDE_STATS_LAT_G, STR_SHOW_GRAPH_OF_LATERAL_ACCELERATION_AGAINST_TIME_TIP ),
- kWidgetsEnd,
};
// 0x009AE844
- static Widget _incomeWidgets[] = {
+ static constexpr Widget _incomeWidgets[] = {
MAIN_RIDE_WIDGETS,
MakeWidget ({ 19, 50}, {126, 14}, WindowWidgetType::Label, WindowColour::Secondary ),
MakeSpinnerWidgets({147, 50}, {162, 14}, WindowWidgetType::Spinner, WindowColour::Secondary, STR_ARG_6_CURRENCY2DP ), // NB: 3 widgets
@@ -394,19 +386,17 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({ 19, 94}, {126, 14}, WindowWidgetType::Label, WindowColour::Secondary ),
MakeSpinnerWidgets({147, 94}, {162, 14}, WindowWidgetType::Spinner, WindowColour::Secondary, STR_RIDE_SECONDARY_PRICE_VALUE ), // NB: 3 widgets
MakeWidget ({ 5, 106}, {306, 13}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_SAME_PRICE_THROUGHOUT_PARK, STR_SAME_PRICE_THROUGHOUT_PARK_TIP),
- kWidgetsEnd,
};
// 0x009AE9C8
- static Widget _customerWidgets[] = {
+ static constexpr Widget _customerWidgets[] = {
MAIN_RIDE_WIDGETS,
MakeWidget({289, 54}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_SHOW_GUESTS_THOUGHTS_ABOUT_THIS_RIDE_ATTRACTION), STR_SHOW_GUESTS_THOUGHTS_ABOUT_THIS_RIDE_ATTRACTION_TIP),
MakeWidget({289, 78}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_SHOW_GUESTS_ON_THIS_RIDE_ATTRACTION), STR_SHOW_GUESTS_ON_THIS_RIDE_ATTRACTION_TIP ),
MakeWidget({289, 102}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_SHOW_GUESTS_QUEUING_FOR_THIS_RIDE_ATTRACTION), STR_SHOW_GUESTS_QUEUING_FOR_THIS_RIDE_ATTRACTION_TIP ),
- kWidgetsEnd,
};
- static const std::array PageWidgets = {
+ static constexpr std::span PageWidgets[] = {
_mainWidgets,
_vehicleWidgets,
_operatingWidgets,
@@ -756,11 +746,10 @@ namespace OpenRCT2::Ui::Windows
void OnOpen() override
{
- widgets = PageWidgets[WINDOW_RIDE_PAGE_MAIN];
+ SetWidgets(PageWidgets[WINDOW_RIDE_PAGE_MAIN]);
hold_down_widgets = PageHoldDownWidgets[WINDOW_RIDE_PAGE_MAIN];
- page = WINDOW_RIDE_PAGE_MAIN;
- frame_no = 0;
+ SetPage(WINDOW_RIDE_PAGE_MAIN);
list_information_type = 0;
picked_peep_frame = 0;
DisableTabs();
@@ -1177,7 +1166,7 @@ namespace OpenRCT2::Ui::Windows
hold_down_widgets = PageHoldDownWidgets[page];
pressed_widgets = 0;
- widgets = PageWidgets[page];
+ SetWidgets(PageWidgets[page]);
DisableTabs();
Invalidate();
@@ -1560,7 +1549,7 @@ namespace OpenRCT2::Ui::Windows
{
_viewIndex = 0;
}
- if (number < _rideOverallViewsCache.size())
+ if (static_cast(number) < _rideOverallViewsCache.size())
{
const auto& view = _rideOverallViewsCache[number];
newFocus = Focus(view.loc, view.zoom);
@@ -2329,13 +2318,6 @@ namespace OpenRCT2::Ui::Windows
{
int32_t i, widgetHeight;
- auto* newWidgets = PageWidgets[page];
- if (widgets != newWidgets)
- {
- widgets = newWidgets;
- InitScrollWidgets();
- }
-
SetPressedTab();
auto ride = GetRide(rideId);
@@ -2793,13 +2775,6 @@ namespace OpenRCT2::Ui::Windows
StringId stringId;
int32_t carsPerTrain;
- auto* newWidgets = PageWidgets[page];
- if (widgets != newWidgets)
- {
- widgets = newWidgets;
- InitScrollWidgets();
- }
-
SetPressedTab();
auto ride = GetRide(rideId);
@@ -3487,13 +3462,6 @@ namespace OpenRCT2::Ui::Windows
{
StringId format, caption, tooltip;
- auto* newWidgets = PageWidgets[page];
- if (widgets != newWidgets)
- {
- widgets = newWidgets;
- InitScrollWidgets();
- }
-
SetPressedTab();
auto ride = GetRide(rideId);
@@ -4021,13 +3989,6 @@ namespace OpenRCT2::Ui::Windows
void MaintenanceOnPrepareDraw()
{
- auto newWidgets = PageWidgets[page];
- if (widgets != newWidgets)
- {
- widgets = newWidgets;
- InitScrollWidgets();
- }
-
SetPressedTab();
auto ride = GetRide(rideId);
@@ -4604,13 +4565,6 @@ namespace OpenRCT2::Ui::Windows
TrackColour trackColour;
VehicleColour vehicleColour;
- auto newWidgets = PageWidgets[page];
- if (widgets != newWidgets)
- {
- widgets = newWidgets;
- InitScrollWidgets();
- }
-
SetPressedTab();
auto ride = GetRide(rideId);
@@ -5217,13 +5171,6 @@ namespace OpenRCT2::Ui::Windows
void MusicOnPrepareDraw()
{
- auto newWidgets = PageWidgets[page];
- if (widgets != newWidgets)
- {
- widgets = newWidgets;
- InitScrollWidgets();
- }
-
SetPressedTab();
auto ride = GetRide(rideId);
@@ -5613,13 +5560,6 @@ namespace OpenRCT2::Ui::Windows
void MeasurementsOnPrepareDraw()
{
- auto newWidgets = PageWidgets[page];
- if (widgets != newWidgets)
- {
- widgets = newWidgets;
- InitScrollWidgets();
- }
-
SetPressedTab();
auto ride = GetRide(rideId);
@@ -6058,13 +5998,6 @@ namespace OpenRCT2::Ui::Windows
void GraphsOnPrepareDraw()
{
- auto newWidgets = PageWidgets[page];
- if (widgets != newWidgets)
- {
- widgets = newWidgets;
- InitScrollWidgets();
- }
-
SetPressedTab();
auto ride = GetRide(rideId);
@@ -6573,13 +6506,6 @@ namespace OpenRCT2::Ui::Windows
void IncomeOnPrepareDraw()
{
- auto newWidgets = PageWidgets[page];
- if (widgets != newWidgets)
- {
- widgets = newWidgets;
- InitScrollWidgets();
- }
-
SetPressedTab();
auto ride = GetRide(rideId);
@@ -6856,13 +6782,6 @@ namespace OpenRCT2::Ui::Windows
void CustomerOnPrepareDraw()
{
- auto newWidgets = PageWidgets[page];
- if (widgets != newWidgets)
- {
- widgets = newWidgets;
- InitScrollWidgets();
- }
-
SetPressedTab();
auto ride = GetRide(rideId);
diff --git a/src/openrct2-ui/windows/RideConstruction.cpp b/src/openrct2-ui/windows/RideConstruction.cpp
index 4e77ccb561..a073404c10 100644
--- a/src/openrct2-ui/windows/RideConstruction.cpp
+++ b/src/openrct2-ui/windows/RideConstruction.cpp
@@ -142,7 +142,7 @@ namespace OpenRCT2::Ui::Windows
validate_global_widx(WC_RIDE_CONSTRUCTION, WIDX_ROTATE);
// clang-format off
- static Widget _rideConstructionWidgets[] = {
+ static constexpr Widget _rideConstructionWidgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget ({ 3, 17}, { GW, 57}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_RIDE_CONSTRUCTION_DIRECTION ),
MakeWidget ({ 3, 76}, { GW, 41}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_RIDE_CONSTRUCTION_SLOPE ),
@@ -179,7 +179,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({118, 120}, { 89, 41}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_RIDE_CONSTRUCTION_SEAT_ROT ),
MakeSpinnerWidgets({123, 138}, { 58, 12}, WindowWidgetType::Spinner, WindowColour::Secondary, 0, STR_RIDE_CONSTRUCTION_SELECT_SEAT_ROTATION_ANGLE_TIP),
MakeWidget ({161, 338}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_G2_SIMULATE), STR_SIMULATE_RIDE_TIP ),
- kWidgetsEnd,
};
// clang-format on
@@ -239,7 +238,7 @@ namespace OpenRCT2::Ui::Windows
return;
}
- widgets = _rideConstructionWidgets;
+ SetWidgets(_rideConstructionWidgets);
number = _currentRideIndex.ToUnderlying();
InitScrollWidgets();
@@ -527,7 +526,7 @@ namespace OpenRCT2::Ui::Windows
{
case TrackPitch::None:
if (_currentlySelectedTrack != TrackCurve::None
- || (IsTrackEnabled(TrackGroup::slopeSteepLong)
+ || (IsTrackEnabled(TrackGroup::slopeSteepLong) && !IsTrackEnabled(TrackGroup::diagSlopeSteepLong)
&& TrackPieceDirectionIsDiagonal(_currentTrackPieceDirection)))
{
disabledWidgets |= (1uLL << WIDX_SLOPE_DOWN_STEEP) | (1uLL << WIDX_SLOPE_UP_STEEP);
@@ -541,7 +540,9 @@ namespace OpenRCT2::Ui::Windows
if (!IsTrackEnabled(TrackGroup::flatToSteepSlope)
&& !(
IsTrackEnabled(TrackGroup::slopeSteepLong)
- && !TrackPieceDirectionIsDiagonal(_currentTrackPieceDirection)))
+ && !(
+ TrackPieceDirectionIsDiagonal(_currentTrackPieceDirection)
+ && !IsTrackEnabled(TrackGroup::diagSlopeSteepLong))))
{
disabledWidgets |= (1uLL << WIDX_LEVEL);
}
@@ -554,7 +555,9 @@ namespace OpenRCT2::Ui::Windows
if (!IsTrackEnabled(TrackGroup::flatToSteepSlope)
&& !(
IsTrackEnabled(TrackGroup::slopeSteepLong)
- && !TrackPieceDirectionIsDiagonal(_currentTrackPieceDirection)))
+ && !(
+ TrackPieceDirectionIsDiagonal(_currentTrackPieceDirection)
+ && !IsTrackEnabled(TrackGroup::diagSlopeSteepLong))))
{
disabledWidgets |= (1uLL << WIDX_LEVEL);
}
@@ -566,7 +569,8 @@ namespace OpenRCT2::Ui::Windows
}
if (_previousTrackPitchEnd == TrackPitch::None)
{
- if (!IsTrackEnabled(TrackGroup::flatToSteepSlope) && !IsTrackEnabled(TrackGroup::slopeSteepLong))
+ if (!IsTrackEnabled(TrackGroup::flatToSteepSlope) && !IsTrackEnabled(TrackGroup::slopeSteepLong)
+ && !IsTrackEnabled(TrackGroup::diagSlopeSteepLong))
{
disabledWidgets |= (1uLL << WIDX_SLOPE_DOWN_STEEP) | (1uLL << WIDX_SLOPE_UP_STEEP);
}
@@ -1574,7 +1578,7 @@ namespace OpenRCT2::Ui::Windows
currentRide->FormatNameTo(ft);
}
- static void OnDrawUpdateCoveredPieces(const TrackDrawerDescriptor& trackDrawerDescriptor, Widget* widgets)
+ static void OnDrawUpdateCoveredPieces(const TrackDrawerDescriptor& trackDrawerDescriptor, std::span widgets)
{
widgets[WIDX_U_TRACK].type = WindowWidgetType::Empty;
widgets[WIDX_O_TRACK].type = WindowWidgetType::Empty;
@@ -4929,11 +4933,30 @@ namespace OpenRCT2::Ui::Windows
trackType = TrackElemType::Down60ToFlatLongBase;
break;
+ default:
+ break;
+ }
+ }
+
+ if (IsTrackEnabled(TrackGroup::diagSlopeSteepLong))
+ {
+ switch (trackType)
+ {
case TrackElemType::DiagFlatToUp60:
+ trackType = TrackElemType::DiagFlatToUp60LongBase;
+ break;
+
case TrackElemType::DiagUp60ToFlat:
+ trackType = TrackElemType::DiagUp60ToFlatLongBase;
+ break;
+
case TrackElemType::DiagFlatToDown60:
+ trackType = TrackElemType::DiagFlatToDown60LongBase;
+ break;
+
case TrackElemType::DiagDown60ToFlat:
- return true;
+ trackType = TrackElemType::DiagDown60ToFlatLongBase;
+ break;
default:
break;
diff --git a/src/openrct2-ui/windows/RideList.cpp b/src/openrct2-ui/windows/RideList.cpp
index cc185d1615..5d2c49ac9c 100644
--- a/src/openrct2-ui/windows/RideList.cpp
+++ b/src/openrct2-ui/windows/RideList.cpp
@@ -63,7 +63,7 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget _rideListWidgets[] = {
+ static constexpr Widget _rideListWidgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({ 0, 43}, {340, 197}, WindowWidgetType::Resize, WindowColour::Secondary ), // tab page background
MakeWidget({315, 60}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_TOGGLE_OPEN_CLOSE), STR_OPEN_OR_CLOSE_ALL_RIDES ), // open / close all toggle
@@ -77,7 +77,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({320, 62}, { 14, 14}, WindowWidgetType::ImgBtn, WindowColour::Secondary, ImageId(SPR_G2_RCT1_CLOSE_BUTTON_0) ),
MakeWidget({320, 76}, { 14, 14}, WindowWidgetType::ImgBtn, WindowColour::Secondary, ImageId(SPR_G2_RCT1_OPEN_BUTTON_0) ),
MakeWidget({315, 90}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_DEMOLISH), STR_QUICK_DEMOLISH_RIDE ),
- kWidgetsEnd,
};
// clang-format on
@@ -174,7 +173,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = _rideListWidgets;
+ SetWidgets(_rideListWidgets);
WindowInitScrollWidgets(*this);
page = PAGE_RIDES;
selected_list_item = -1;
diff --git a/src/openrct2-ui/windows/SavePrompt.cpp b/src/openrct2-ui/windows/SavePrompt.cpp
index d1e14b00ae..e454126c35 100644
--- a/src/openrct2-ui/windows/SavePrompt.cpp
+++ b/src/openrct2-ui/windows/SavePrompt.cpp
@@ -40,13 +40,12 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget _savePromptWidgets[] = {
+ static constexpr Widget _savePromptWidgets[] = {
WINDOW_SHIM_WHITE(STR_NONE, WW_SAVE, WH_SAVE),
MakeWidget({ 2, 19}, {256, 12}, WindowWidgetType::LabelCentred, WindowColour::Primary, STR_EMPTY ), // question/label
MakeWidget({ 8, 35}, { 78, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_SAVE_PROMPT_SAVE ), // save
MakeWidget({ 91, 35}, { 78, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_SAVE_PROMPT_DONT_SAVE), // don't save
MakeWidget({174, 35}, { 78, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_SAVE_PROMPT_CANCEL ), // cancel
- kWidgetsEnd,
};
// clang-format on
@@ -60,11 +59,10 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget _quitPromptWidgets[] = {
+ static constexpr Widget _quitPromptWidgets[] = {
WINDOW_SHIM_WHITE(STR_QUIT_GAME_PROMPT_TITLE, WW_QUIT, WH_QUIT),
MakeWidget({ 8, 19}, {78, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_OK ), // ok
MakeWidget({91, 19}, {78, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_CANCEL), // cancel
- kWidgetsEnd,
};
// clang-format on
@@ -98,7 +96,10 @@ namespace OpenRCT2::Ui::Windows
{
bool canSave = !(gScreenFlags & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER));
- widgets = canSave ? _savePromptWidgets : _quitPromptWidgets;
+ if (canSave)
+ SetWidgets(_savePromptWidgets);
+ else
+ SetWidgets(_quitPromptWidgets);
InitScrollWidgets();
diff --git a/src/openrct2-ui/windows/ScenarioSelect.cpp b/src/openrct2-ui/windows/ScenarioSelect.cpp
index 1fb8d17359..65003c5362 100644
--- a/src/openrct2-ui/windows/ScenarioSelect.cpp
+++ b/src/openrct2-ui/windows/ScenarioSelect.cpp
@@ -92,7 +92,7 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget _scenarioSelectWidgets[] = {
+ static constexpr Widget _scenarioSelectWidgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({ TabWidth + 1, WidgetsStart }, { WW, 284 }, WindowWidgetType::Resize, WindowColour::Secondary), // tab content panel
MakeRemapWidget({ 3, TabsStart + (TabHeight * 0) }, { TabWidth, TabHeight}, WindowWidgetType::Tab, WindowColour::Secondary, SPR_G2_SIDEWAYS_TAB), // tab 01
@@ -106,7 +106,6 @@ namespace OpenRCT2::Ui::Windows
MakeRemapWidget({ 3, TabsStart + (TabHeight * 8) }, { TabWidth, TabHeight}, WindowWidgetType::Tab, WindowColour::Secondary, SPR_G2_SIDEWAYS_TAB), // tab 09
MakeRemapWidget({ 3, TabsStart + (TabHeight * 8) }, { TabWidth, TabHeight}, WindowWidgetType::Tab, WindowColour::Secondary, SPR_G2_SIDEWAYS_TAB), // tab 10
MakeWidget({ TabWidth + 3, WidgetsStart + 1 }, { WW - SidebarWidth, 362 }, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL), // level list
- kWidgetsEnd,
};
// clang-format on
@@ -126,7 +125,7 @@ namespace OpenRCT2::Ui::Windows
void OnOpen() override
{
- widgets = _scenarioSelectWidgets;
+ SetWidgets(_scenarioSelectWidgets);
// Load scenario list
ScenarioRepositoryScan();
diff --git a/src/openrct2-ui/windows/Scenery.cpp b/src/openrct2-ui/windows/Scenery.cpp
index ab34c1244a..73730c0195 100644
--- a/src/openrct2-ui/windows/Scenery.cpp
+++ b/src/openrct2-ui/windows/Scenery.cpp
@@ -108,7 +108,7 @@ namespace OpenRCT2::Ui::Windows
validate_global_widx(WC_SCENERY, WIDX_SCENERY_EYEDROPPER_BUTTON);
// clang-format off
- static Widget WindowSceneryBaseWidgets[] = {
+ static constexpr Widget WindowSceneryBaseWidgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WINDOW_SCENERY_MIN_WIDTH, WINDOW_SCENERY_MIN_HEIGHT),
MakeWidget ({ 0, 43}, {634, 99}, WindowWidgetType::Resize, WindowColour::Secondary ), // 8 0x009DE2C8
MakeWidget ({ 2, 62}, {607, 80}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL ), // 1000000 0x009DE418
@@ -122,7 +122,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({ 4, 46}, {211, 14}, WindowWidgetType::TextBox, WindowColour::Secondary ),
MakeWidget ({218, 46}, { 70, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_OBJECT_SEARCH_CLEAR ),
MakeWidget ({539, 46}, { 70, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_RESTRICT_SCENERY, STR_RESTRICT_SCENERY_TIP ),
- kWidgetsEnd,
};
// clang-format on
@@ -205,7 +204,6 @@ namespace OpenRCT2::Ui::Windows
};
std::vector _tabEntries;
- std::vector _widgets;
int32_t _requiredWidth;
int32_t _actualMinHeight;
ScenerySelection _selectedScenery;
@@ -1362,15 +1360,7 @@ namespace OpenRCT2::Ui::Windows
void PrepareWidgets()
{
// Add the base widgets
- _widgets.clear();
- for (const auto& widget : WindowSceneryBaseWidgets)
- {
- _widgets.push_back(widget);
- }
-
- // Remove WWT_LAST
- auto lastWidget = _widgets.back();
- _widgets.pop_back();
+ SetWidgets(WindowSceneryBaseWidgets);
// Add tabs
_actualMinHeight = WINDOW_SCENERY_MIN_HEIGHT;
@@ -1407,7 +1397,7 @@ namespace OpenRCT2::Ui::Windows
}
}
- _widgets.push_back(widget);
+ widgets.push_back(widget);
tabsInThisRow++;
if (tabsInThisRow >= maxTabsInThisRow)
@@ -1420,35 +1410,31 @@ namespace OpenRCT2::Ui::Windows
}
}
- _widgets.push_back(lastWidget);
-
// Shift base widgets based on number of tab rows
int32_t shiftAmount = (GetTabRowCount() - 1) * TabHeight;
if (shiftAmount > 0)
{
- _widgets[WIDX_SCENERY_LIST].top += shiftAmount;
- _widgets[WIDX_SCENERY_LIST].bottom += shiftAmount;
- _widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].top += shiftAmount;
- _widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].bottom += shiftAmount;
- _widgets[WIDX_SCENERY_REPAINT_SCENERY_BUTTON].top += shiftAmount;
- _widgets[WIDX_SCENERY_REPAINT_SCENERY_BUTTON].bottom += shiftAmount;
- _widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].top += shiftAmount;
- _widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].bottom += shiftAmount;
- _widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].top += shiftAmount;
- _widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].bottom += shiftAmount;
- _widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].top += shiftAmount;
- _widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].bottom += shiftAmount;
- _widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].top += shiftAmount;
- _widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].bottom += shiftAmount;
- _widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].top += shiftAmount;
- _widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].bottom += shiftAmount;
- _widgets[WIDX_FILTER_TEXT_BOX].top += shiftAmount;
- _widgets[WIDX_FILTER_TEXT_BOX].bottom += shiftAmount;
- _widgets[WIDX_FILTER_CLEAR_BUTTON].top += shiftAmount;
- _widgets[WIDX_FILTER_CLEAR_BUTTON].bottom += shiftAmount;
+ widgets[WIDX_SCENERY_LIST].top += shiftAmount;
+ widgets[WIDX_SCENERY_LIST].bottom += shiftAmount;
+ widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].top += shiftAmount;
+ widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].bottom += shiftAmount;
+ widgets[WIDX_SCENERY_REPAINT_SCENERY_BUTTON].top += shiftAmount;
+ widgets[WIDX_SCENERY_REPAINT_SCENERY_BUTTON].bottom += shiftAmount;
+ widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].top += shiftAmount;
+ widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].bottom += shiftAmount;
+ widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].top += shiftAmount;
+ widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].bottom += shiftAmount;
+ widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].top += shiftAmount;
+ widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].bottom += shiftAmount;
+ widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].top += shiftAmount;
+ widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].bottom += shiftAmount;
+ widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].top += shiftAmount;
+ widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].bottom += shiftAmount;
+ widgets[WIDX_FILTER_TEXT_BOX].top += shiftAmount;
+ widgets[WIDX_FILTER_TEXT_BOX].bottom += shiftAmount;
+ widgets[WIDX_FILTER_CLEAR_BUTTON].top += shiftAmount;
+ widgets[WIDX_FILTER_CLEAR_BUTTON].bottom += shiftAmount;
}
-
- widgets = _widgets.data();
}
ScenerySelection GetSceneryIdByCursorPos(const ScreenCoordsXY& screenCoords) const
diff --git a/src/openrct2-ui/windows/SceneryScatter.cpp b/src/openrct2-ui/windows/SceneryScatter.cpp
index 8f4ce306ca..57a10df675 100644
--- a/src/openrct2-ui/windows/SceneryScatter.cpp
+++ b/src/openrct2-ui/windows/SceneryScatter.cpp
@@ -40,7 +40,7 @@ namespace OpenRCT2::Ui::Windows
ScatterToolDensity gWindowSceneryScatterDensity;
// clang-format off
- static Widget _sceneryScatterWidgets[] = {
+ static constexpr Widget _sceneryScatterWidgets[] = {
MakeWidget ({ 0, 0}, {86, 100}, WindowWidgetType::Frame, WindowColour::Secondary ), // panel / background
MakeWidget ({ 1, 1}, {84, 14}, WindowWidgetType::Caption, WindowColour::Primary , STR_SCENERY_SCATTER, STR_WINDOW_TITLE_TIP ), // title bar
MakeWidget ({73, 2}, {11, 12}, WindowWidgetType::CloseBox, WindowColour::Primary , STR_CLOSE_X, STR_CLOSE_WINDOW_TIP ), // close x button
@@ -53,7 +53,6 @@ namespace OpenRCT2::Ui::Windows
MakeRemapWidget({ 7, 68}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_G2_SCENERY_SCATTER_LOW, STR_SCATTER_TOOL_DENSITY_LOW ), // low amount
MakeRemapWidget({31, 68}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_G2_SCENERY_SCATTER_MEDIUM, STR_SCATTER_TOOL_DENSITY_MEDIUM), // medium amount
MakeRemapWidget({55, 68}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_G2_SCENERY_SCATTER_HIGH, STR_SCATTER_TOOL_DENSITY_HIGH ), // high amount
- kWidgetsEnd,
};
// clang-format on
@@ -62,7 +61,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = _sceneryScatterWidgets;
+ SetWidgets(_sceneryScatterWidgets);
hold_down_widgets = (1uLL << WIDX_INCREMENT) | (1uLL << WIDX_DECREMENT);
WindowInitScrollWidgets(*this);
WindowPushOthersBelow(*this);
diff --git a/src/openrct2-ui/windows/ServerList.cpp b/src/openrct2-ui/windows/ServerList.cpp
index 8b5ca04d61..0a2789fb23 100644
--- a/src/openrct2-ui/windows/ServerList.cpp
+++ b/src/openrct2-ui/windows/ServerList.cpp
@@ -62,7 +62,7 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget _serverListWidgets[] = {
+ static constexpr Widget _serverListWidgets[] = {
MakeWidget({ 0, 0}, {341, 91}, WindowWidgetType::Frame, WindowColour::Primary ), // panel / background
MakeWidget({ 1, 1}, {338, 14}, WindowWidgetType::Caption, WindowColour::Primary, STR_SERVER_LIST, STR_WINDOW_TITLE_TIP), // title bar
MakeWidget({327, 2}, { 11, 12}, WindowWidgetType::CloseBox, WindowColour::Primary, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP), // close x button
@@ -71,7 +71,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({ 6, 53}, {101, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_FETCH_SERVERS ), // fetch servers button
MakeWidget({112, 53}, {101, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_ADD_SERVER ), // add server button
MakeWidget({218, 53}, {101, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_START_SERVER ), // start server button
- kWidgetsEnd,
};
// clang-format on
@@ -95,8 +94,8 @@ namespace OpenRCT2::Ui::Windows
void OnOpen() override
{
_playerName = Config::Get().network.PlayerName;
- widgets = _serverListWidgets;
- _serverListWidgets[WIDX_PLAYER_NAME_INPUT].string = const_cast(_playerName.c_str());
+ SetWidgets(_serverListWidgets);
+ widgets[WIDX_PLAYER_NAME_INPUT].string = const_cast(_playerName.c_str());
InitScrollWidgets();
no_list_items = 0;
selected_list_item = -1;
diff --git a/src/openrct2-ui/windows/ServerStart.cpp b/src/openrct2-ui/windows/ServerStart.cpp
index 1f538b7c3f..0c966df47c 100644
--- a/src/openrct2-ui/windows/ServerStart.cpp
+++ b/src/openrct2-ui/windows/ServerStart.cpp
@@ -45,7 +45,7 @@ namespace OpenRCT2::Ui::Windows
static constexpr int32_t WH = 154;
// clang-format off
- static Widget _windowServerStartWidgets[] = {
+ static constexpr Widget _windowServerStartWidgets[] = {
MakeWidget({ 0, 0 }, { WW, WH }, WindowWidgetType::Frame, WindowColour::Primary), // panel / background
MakeWidget({ 1, 1 }, { 298, 14 }, WindowWidgetType::Caption, WindowColour::Primary, STR_START_SERVER,STR_WINDOW_TITLE_TIP), // title bar
MakeWidget({ WW - 13, 2 }, { 11, 12 }, WindowWidgetType::CloseBox, WindowColour::Primary, STR_CLOSE_X,STR_CLOSE_WINDOW_TIP), // close x button
@@ -58,7 +58,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({ 6, 117 }, { 287, 14 }, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_ADVERTISE,STR_ADVERTISE_SERVER_TIP), // advertise checkbox
MakeWidget({ 6, WH - 6 - 13 }, { 101, 14 }, WindowWidgetType::Button, WindowColour::Secondary,STR_NEW_GAME), // start server button
MakeWidget({ 112, WH - 6 - 13 }, { 101, 14 }, WindowWidgetType::Button, WindowColour::Secondary, STR_LOAD_GAME), // None
- kWidgetsEnd,
};
// clang-format on
@@ -67,7 +66,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = _windowServerStartWidgets;
+ SetWidgets(_windowServerStartWidgets);
widgets[WIDX_PORT_INPUT].string = _port;
widgets[WIDX_NAME_INPUT].string = _name;
widgets[WIDX_DESCRIPTION_INPUT].string = _description;
diff --git a/src/openrct2-ui/windows/ShortcutKeys.cpp b/src/openrct2-ui/windows/ShortcutKeys.cpp
index 2cb9d2a6ee..9b079d8c5c 100644
--- a/src/openrct2-ui/windows/ShortcutKeys.cpp
+++ b/src/openrct2-ui/windows/ShortcutKeys.cpp
@@ -43,12 +43,11 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget _shortcutWidgets[] = {
+ static constexpr Widget _shortcutWidgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({0, 43}, {350, 287}, WindowWidgetType::Resize, WindowColour::Secondary),
MakeWidget({4, 47}, {412, 215}, WindowWidgetType::Scroll, WindowColour::Primary, SCROLL_VERTICAL, STR_SHORTCUT_LIST_TIP ),
MakeWidget({4, WH-15}, {150, 12}, WindowWidgetType::Button, WindowColour::Primary, STR_SHORTCUT_ACTION_RESET, STR_SHORTCUT_ACTION_RESET_TIP),
- kWidgetsEnd,
};
// clang-format on
@@ -62,10 +61,9 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget window_shortcut_change_widgets[] = {
+ static constexpr Widget window_shortcut_change_widgets[] = {
WINDOW_SHIM(CHANGE_WINDOW_TITLE, CHANGE_WW, CHANGE_WH),
MakeWidget({ 75, 56 }, { 100, 14 }, WindowWidgetType::Button, WindowColour::Primary, STR_SHORTCUT_REMOVE, STR_SHORTCUT_REMOVE_TIP),
- kWidgetsEnd,
};
// clang-format on
@@ -100,7 +98,7 @@ namespace OpenRCT2::Ui::Windows
void OnOpen() override
{
- widgets = window_shortcut_change_widgets;
+ SetWidgets(window_shortcut_change_widgets);
WindowInitScrollWidgets(*this);
}
@@ -450,20 +448,17 @@ namespace OpenRCT2::Ui::Windows
void InitialiseWidgets()
{
- _widgets.clear();
- _widgets.insert(_widgets.begin(), std::begin(_shortcutWidgets), std::end(_shortcutWidgets) - 1);
+ widgets.clear();
+ widgets.insert(widgets.begin(), std::begin(_shortcutWidgets), std::end(_shortcutWidgets) - 1);
int32_t x = 3;
for (size_t i = 0; i < _tabs.size(); i++)
{
auto tab = MakeTab({ x, 17 }, STR_NONE);
- _widgets.push_back(tab);
+ widgets.push_back(tab);
x += 31;
}
- _widgets.push_back(kWidgetsEnd);
- widgets = _widgets.data();
-
WindowInitScrollWidgets(*this);
}
@@ -581,7 +576,7 @@ namespace OpenRCT2::Ui::Windows
WIDX_RESET_PROMPT_CANCEL
};
- static Widget WindowResetShortcutKeysPromptWidgets[] = {
+ static constexpr Widget WindowResetShortcutKeysPromptWidgets[] = {
WINDOW_SHIM_WHITE(STR_SHORTCUT_ACTION_RESET, RESET_PROMPT_WW, RESET_PROMPT_WH),
MakeWidget(
{ 2, 30 }, { RESET_PROMPT_WW - 4, 12 }, WindowWidgetType::LabelCentred, WindowColour::Primary,
@@ -590,14 +585,13 @@ namespace OpenRCT2::Ui::Windows
MakeWidget(
{ RESET_PROMPT_WW - 95, RESET_PROMPT_WH - 22 }, { 85, 14 }, WindowWidgetType::Button, WindowColour::Primary,
STR_SAVE_PROMPT_CANCEL),
- kWidgetsEnd,
};
class ResetShortcutKeysPrompt final : public Window
{
void OnOpen() override
{
- widgets = WindowResetShortcutKeysPromptWidgets;
+ SetWidgets(WindowResetShortcutKeysPromptWidgets);
}
void OnMouseUp(WidgetIndex widgetIndex) override
diff --git a/src/openrct2-ui/windows/Sign.cpp b/src/openrct2-ui/windows/Sign.cpp
index 6c51039545..3f3bf92f19 100644
--- a/src/openrct2-ui/windows/Sign.cpp
+++ b/src/openrct2-ui/windows/Sign.cpp
@@ -48,14 +48,13 @@ namespace OpenRCT2::Ui::Windows
// clang-format off
// 0x9AEE00
- static Widget _signWidgets[] = {
+ static constexpr Widget _signWidgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({ 3, 17}, {85, 60}, WindowWidgetType::Viewport, WindowColour::Secondary ), // Viewport
MakeWidget({WW - 25, 19}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_RENAME), STR_CHANGE_SIGN_TEXT_TIP ), // change sign button
MakeWidget({WW - 25, 67}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_DEMOLISH), STR_DEMOLISH_SIGN_TIP ), // demolish button
MakeWidget({ 5, WH - 16}, {12, 12}, WindowWidgetType::ColourBtn, WindowColour::Secondary, kWidgetContentEmpty, STR_SELECT_MAIN_SIGN_COLOUR_TIP), // Main colour
MakeWidget({ 17, WH - 16}, {12, 12}, WindowWidgetType::ColourBtn, WindowColour::Secondary, kWidgetContentEmpty, STR_SELECT_TEXT_COLOUR_TIP ), // Text colour
- kWidgetsEnd,
};
// clang-format on
@@ -86,7 +85,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = _signWidgets;
+ SetWidgets(_signWidgets);
WindowInitScrollWidgets(*this);
}
diff --git a/src/openrct2-ui/windows/Staff.cpp b/src/openrct2-ui/windows/Staff.cpp
index 7a82fd97a8..eed00969f7 100644
--- a/src/openrct2-ui/windows/Staff.cpp
+++ b/src/openrct2-ui/windows/Staff.cpp
@@ -93,7 +93,7 @@ namespace OpenRCT2::Ui::Windows
MakeTab({ 65, 17 }, STR_STAFF_STATS_TIP) /* Tab 3 */
// clang-format off
- static Widget _staffOverviewWidgets[] = {
+ static constexpr Widget _staffOverviewWidgets[] = {
MAIN_STAFF_WIDGETS,
MakeWidget ({ 3, 47}, {162, 120}, WindowWidgetType::Viewport, WindowColour::Secondary ), // Viewport
MakeWidget ({ 3, WH - 13}, {162, 11}, WindowWidgetType::LabelCentred, WindowColour::Secondary ), // Label at bottom of viewport
@@ -102,11 +102,10 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({WW - 25, 93}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_RENAME), STR_NAME_STAFF_TIP ), // Rename Button
MakeWidget ({WW - 25, 117}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_LOCATE), STR_LOCATE_SUBJECT_TIP), // Locate Button
MakeWidget ({WW - 25, 141}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_DEMOLISH), STR_FIRE_STAFF_TIP ), // Fire Button
- kWidgetsEnd,
};
//0x9AF910
- static Widget _staffOptionsWidgets[] = {
+ static constexpr Widget _staffOptionsWidgets[] = {
MAIN_STAFF_WIDGETS,
MakeWidget ({ 5, 50}, {180, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary ), // Checkbox 1
MakeWidget ({ 5, 67}, {180, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary ), // Checkbox 2
@@ -114,17 +113,15 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({ 5, 101}, {180, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary ), // Checkbox 4
MakeWidget ({ 5, 50}, {180, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ), // Costume Dropdown
MakeWidget ({WW - 17, 51}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_SELECT_COSTUME_TIP), // Costume Dropdown Button
- kWidgetsEnd,
};
// clang-format on
// 0x9AF9F4
- static Widget _staffStatsWidgets[] = {
+ static constexpr Widget _staffStatsWidgets[] = {
MAIN_STAFF_WIDGETS,
- kWidgetsEnd,
};
- static Widget* window_staff_page_widgets[] = {
+ static constexpr std::span window_staff_page_widgets[] = {
_staffOverviewWidgets,
_staffOptionsWidgets,
_staffStatsWidgets,
@@ -341,11 +338,6 @@ namespace OpenRCT2::Ui::Windows
{
ColourSchemeUpdateByClass(this, static_cast(WindowClass::Staff));
- if (window_staff_page_widgets[page] != widgets)
- {
- widgets = window_staff_page_widgets[page];
- InitScrollWidgets();
- }
SetPressedTab();
DisableWidgets();
@@ -1086,7 +1078,7 @@ namespace OpenRCT2::Ui::Windows
return;
}
- for (WidgetIndex widgetIndex = WIDX_TAB_1; widgets[widgetIndex].type != kWidgetsEnd.type; widgetIndex++)
+ for (WidgetIndex widgetIndex = WIDX_TAB_1; widgetIndex < widgets.size(); widgetIndex++)
{
SetWidgetDisabled(widgetIndex, false);
}
@@ -1132,7 +1124,7 @@ namespace OpenRCT2::Ui::Windows
frame_no = 0;
pressed_widgets = 0;
hold_down_widgets = 0;
- widgets = window_staff_page_widgets[page];
+ SetWidgets(window_staff_page_widgets[page]);
RemoveViewport();
diff --git a/src/openrct2-ui/windows/StaffFirePrompt.cpp b/src/openrct2-ui/windows/StaffFirePrompt.cpp
index d903ca9111..3b24b3b7a2 100644
--- a/src/openrct2-ui/windows/StaffFirePrompt.cpp
+++ b/src/openrct2-ui/windows/StaffFirePrompt.cpp
@@ -34,11 +34,10 @@ namespace OpenRCT2::Ui::Windows
// clang-format off
// 0x9AFB4C
- static Widget _staffFireWidgets[] = {
+ static constexpr Widget _staffFireWidgets[] = {
WINDOW_SHIM_WHITE(WINDOW_TITLE, WW, WH),
MakeWidget({ 10, WH - 20}, {85, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_YES ),
MakeWidget({WW - 95, WH - 20}, {85, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_SAVE_PROMPT_CANCEL),
- kWidgetsEnd,
};
// clang-format on
@@ -52,7 +51,7 @@ namespace OpenRCT2::Ui::Windows
void OnOpen() override
{
- widgets = _staffFireWidgets;
+ SetWidgets(_staffFireWidgets);
WindowInitScrollWidgets(*this);
}
diff --git a/src/openrct2-ui/windows/StaffList.cpp b/src/openrct2-ui/windows/StaffList.cpp
index e1f8cd013d..24928e529b 100644
--- a/src/openrct2-ui/windows/StaffList.cpp
+++ b/src/openrct2-ui/windows/StaffList.cpp
@@ -80,7 +80,7 @@ namespace OpenRCT2::Ui::Windows
constexpr int32_t MAX_WH = 450;
// clang-format off
- static Widget _staffListWidgets[] = {
+ static constexpr Widget _staffListWidgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({ 0, 43}, { WW, WH - 43}, WindowWidgetType::Resize, WindowColour::Secondary ), // tab content panel
MakeTab ({ 3, 17}, STR_STAFF_HANDYMEN_TAB_TIP ), // handymen tab
@@ -93,7 +93,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({243, 46}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_DEMOLISH), STR_QUICK_FIRE_STAFF ), // quick fire staff
MakeWidget({267, 46}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_PATROL_BTN), STR_SHOW_PATROL_AREA_TIP ), // show staff patrol area tool
MakeWidget({291, 46}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_MAP), STR_SHOW_STAFF_ON_MAP_TIP), // show staff on map button
- kWidgetsEnd,
};
// clang-format on
@@ -122,7 +121,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = _staffListWidgets;
+ SetWidgets(_staffListWidgets);
WindowInitScrollWidgets(*this);
widgets[WIDX_STAFF_LIST_UNIFORM_COLOUR_PICKER].type = WindowWidgetType::Empty;
diff --git a/src/openrct2-ui/windows/TextInput.cpp b/src/openrct2-ui/windows/TextInput.cpp
index ec9521f3bb..79db7aef42 100644
--- a/src/openrct2-ui/windows/TextInput.cpp
+++ b/src/openrct2-ui/windows/TextInput.cpp
@@ -35,11 +35,10 @@ namespace OpenRCT2::Ui::Windows
WIDX_OKAY
};
- static Widget _textInputWidgets[] = {
+ static constexpr Widget _textInputWidgets[] = {
WINDOW_SHIM(STR_NONE, WW, WH),
MakeWidget({ 170, 68 }, { 71, 14 }, WindowWidgetType::Button, WindowColour::Secondary, STR_CANCEL),
MakeWidget({ 10, 68 }, { 71, 14 }, WindowWidgetType::Button, WindowColour::Secondary, STR_OK),
- kWidgetsEnd,
};
class TextInputWindow final : public Window
@@ -64,7 +63,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = _textInputWidgets;
+ SetWidgets(_textInputWidgets);
WindowInitScrollWidgets(*this);
SetParentWindow(nullptr, 0);
}
diff --git a/src/openrct2-ui/windows/Themes.cpp b/src/openrct2-ui/windows/Themes.cpp
index 7274d95db6..05a5c1e849 100644
--- a/src/openrct2-ui/windows/Themes.cpp
+++ b/src/openrct2-ui/windows/Themes.cpp
@@ -78,7 +78,7 @@ namespace OpenRCT2::Ui::Windows
const uint16_t kWindowHeaderWidth = 152;
// clang-format off
- static Widget _themesWidgets[] = {
+ static constexpr Widget _themesWidgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({ 0, 43}, {320, 64}, WindowWidgetType::Resize, WindowColour::Secondary ), // tab content panel
MakeTab ({ 3, 17}, STR_THEMES_TAB_SETTINGS_TIP ), // settings tab
@@ -104,7 +104,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({ 10, 69}, {290, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_THEMES_OPTION_RCT1_PARK_CONTROLS ), // rct1 park lights
MakeWidget({ 10, 84}, {290, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_THEMES_OPTION_RCT1_SCENARIO_SELECTION_FONT ), // rct1 scenario font
MakeWidget({ 10, 99}, {290, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_THEMES_OPTION_RCT1_BOTTOM_TOOLBAR ), // rct1 bottom toolbar
- kWidgetsEnd,
};
// clang-format on
@@ -265,7 +264,7 @@ namespace OpenRCT2::Ui::Windows
void OnOpen() override
{
- widgets = _themesWidgets;
+ SetWidgets(_themesWidgets);
WindowThemesInitVars();
diff --git a/src/openrct2-ui/windows/TileInspector.cpp b/src/openrct2-ui/windows/TileInspector.cpp
index cb705a3800..04b5faaae8 100644
--- a/src/openrct2-ui/windows/TileInspector.cpp
+++ b/src/openrct2-ui/windows/TileInspector.cpp
@@ -199,6 +199,22 @@ namespace OpenRCT2::Ui::Windows
static_assert(WC_TILE_INSPECTOR__WIDX_SPINNER_X_DECREASE == WIDX_SPINNER_X_DECREASE);
static_assert(WC_TILE_INSPECTOR__WIDX_SPINNER_Y_INCREASE == WIDX_SPINNER_Y_INCREASE);
static_assert(WC_TILE_INSPECTOR__WIDX_SPINNER_Y_DECREASE == WIDX_SPINNER_Y_DECREASE);
+ static_assert(WC_TILE_INSPECTOR__WIDX_SURFACE_SPINNER_HEIGHT_INCREASE == WIDX_SURFACE_SPINNER_HEIGHT_INCREASE);
+ static_assert(WC_TILE_INSPECTOR__WIDX_SURFACE_SPINNER_HEIGHT_DECREASE == WIDX_SURFACE_SPINNER_HEIGHT_DECREASE);
+ static_assert(WC_TILE_INSPECTOR__WIDX_PATH_SPINNER_HEIGHT_INCREASE == WIDX_PATH_SPINNER_HEIGHT_INCREASE);
+ static_assert(WC_TILE_INSPECTOR__WIDX_PATH_SPINNER_HEIGHT_DECREASE == WIDX_PATH_SPINNER_HEIGHT_DECREASE);
+ static_assert(WC_TILE_INSPECTOR__WIDX_TRACK_SPINNER_HEIGHT_INCREASE == WIDX_TRACK_SPINNER_HEIGHT_INCREASE);
+ static_assert(WC_TILE_INSPECTOR__WIDX_TRACK_SPINNER_HEIGHT_DECREASE == WIDX_TRACK_SPINNER_HEIGHT_DECREASE);
+ static_assert(WC_TILE_INSPECTOR__WIDX_SCENERY_SPINNER_HEIGHT_INCREASE == WIDX_SCENERY_SPINNER_HEIGHT_INCREASE);
+ static_assert(WC_TILE_INSPECTOR__WIDX_SCENERY_SPINNER_HEIGHT_DECREASE == WIDX_SCENERY_SPINNER_HEIGHT_DECREASE);
+ static_assert(WC_TILE_INSPECTOR__WIDX_ENTRANCE_SPINNER_HEIGHT_INCREASE == WIDX_ENTRANCE_SPINNER_HEIGHT_INCREASE);
+ static_assert(WC_TILE_INSPECTOR__WIDX_ENTRANCE_SPINNER_HEIGHT_DECREASE == WIDX_ENTRANCE_SPINNER_HEIGHT_DECREASE);
+ static_assert(WC_TILE_INSPECTOR__WIDX_WALL_SPINNER_HEIGHT_INCREASE == WIDX_WALL_SPINNER_HEIGHT_INCREASE);
+ static_assert(WC_TILE_INSPECTOR__WIDX_WALL_SPINNER_HEIGHT_DECREASE == WIDX_WALL_SPINNER_HEIGHT_DECREASE);
+ static_assert(WC_TILE_INSPECTOR__WIDX_LARGE_SCENERY_SPINNER_HEIGHT_INCREASE == WIDX_LARGE_SCENERY_SPINNER_HEIGHT_INCREASE);
+ static_assert(WC_TILE_INSPECTOR__WIDX_LARGE_SCENERY_SPINNER_HEIGHT_DECREASE == WIDX_LARGE_SCENERY_SPINNER_HEIGHT_DECREASE);
+ static_assert(WC_TILE_INSPECTOR__WIDX_BANNER_SPINNER_HEIGHT_INCREASE == WIDX_BANNER_SPINNER_HEIGHT_INCREASE);
+ static_assert(WC_TILE_INSPECTOR__WIDX_BANNER_SPINNER_HEIGHT_DECREASE == WIDX_BANNER_SPINNER_HEIGHT_DECREASE);
#pragma region MEASUREMENTS
@@ -289,16 +305,15 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({6, 0}, {WW - 12, 0}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_NONE, STR_NONE ), /* Details group box */ \
MakeWidget({6, 0}, {WW - 12, 0}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_TILE_INSPECTOR_GROUPBOX_PROPERTIES, STR_NONE ) /* Properties group box */
- static Widget DefaultWidgets[] = {
+ static constexpr Widget DefaultWidgets[] = {
MAIN_TILE_INSPECTOR_WIDGETS,
- kWidgetsEnd,
};
constexpr int32_t NumSurfaceProperties = 4;
constexpr int32_t NumSurfaceDetails = 4;
constexpr int32_t SurfacePropertiesHeight = 16 + NumSurfaceProperties * 21;
constexpr int32_t SurfaceDetailsHeight = 20 + NumSurfaceDetails * 11;
- static Widget SurfaceWidgets[] = {
+ static constexpr Widget SurfaceWidgets[] = {
MAIN_TILE_INSPECTOR_WIDGETS,
MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_SURFACE_SPINNER_HEIGHT{,_INCREASE,_DECREASE}
MakeWidget(PropertyRowCol({ 12, 0 }, 1, 0), PropertyButtonSize, WindowWidgetType::Button, WindowColour::Secondary, STR_TILE_INSPECTOR_SURFACE_REMOVE_FENCES), // WIDX_SURFACE_BUTTON_REMOVE_FENCES
@@ -308,14 +323,13 @@ namespace OpenRCT2::Ui::Windows
MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 3, 1), 1, 2), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_SURFACE_CHECK_CORNER_S
MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 3, 1), 0, 1), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_SURFACE_CHECK_CORNER_W
MakeWidget(PropertyRowCol({ 12, 0 }, 4, 0), PropertyFullWidth, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_TILE_INSPECTOR_SURFACE_DIAGONAL), // WIDX_SURFACE_CHECK_DIAGONAL
- kWidgetsEnd,
};
constexpr int32_t NumPathProperties = 6;
constexpr int32_t NumPathDetails = 3;
constexpr int32_t PathPropertiesHeight = 16 + NumPathProperties * 21;
constexpr int32_t PathDetailsHeight = 20 + NumPathDetails * 11;
- static Widget PathWidgets[] = {
+ static constexpr Widget PathWidgets[] = {
MAIN_TILE_INSPECTOR_WIDGETS,
MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_PATH_SPINNER_HEIGHT{,_INCREASE,_DECREASE}
MakeWidget(PropertyRowCol({ 12, 0 }, 1, 0), PropertyFullWidth, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_TILE_INSPECTOR_PATH_BROKEN), // WIDX_PATH_CHECK_BROKEN
@@ -329,28 +343,26 @@ namespace OpenRCT2::Ui::Windows
MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 4, 1), 0, 2), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_PATH_CHECK_EDGE_W
MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 4, 1), 1, 1), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_PATH_CHECK_EDGE_NW
MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 4, 1), 2, 0), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_PATH_CHECK_EDGE_N
- kWidgetsEnd,
};
constexpr int32_t NumTrackProperties = 5;
constexpr int32_t NumTrackDetails = 7;
constexpr int32_t TrackPropertiesHeight = 16 + NumTrackProperties * 21;
constexpr int32_t TrackDetailsHeight = 20 + NumTrackDetails * 11;
- static Widget TrackWidgets[] = {
+ static constexpr Widget TrackWidgets[] = {
MAIN_TILE_INSPECTOR_WIDGETS,
MakeWidget(PropertyRowCol({ 12, 0}, 0, 0), PropertyFullWidth, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_TILE_INSPECTOR_TRACK_ENTIRE_TRACK_PIECE), // WIDX_TRACK_CHECK_APPLY_TO_ALL
MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 1, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_TRACK_SPINNER_HEIGHT{,_INCREASE,_DECREASE}
MakeWidget(PropertyRowCol({ 12, 0}, 2, 0), PropertyFullWidth, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_TILE_INSPECTOR_TRACK_CHAIN_LIFT), // WIDX_TRACK_CHECK_CHAIN_LIFT
MakeWidget(PropertyRowCol({ 12, 0}, 3, 0), PropertyFullWidth, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_TILE_INSPECTOR_TRACK_BRAKE_CLOSED), // WIDX_TRACK_CHECK_BRAKE_CLOSED
MakeWidget(PropertyRowCol({ 12, 0}, 4, 0), PropertyFullWidth, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_TILE_INSPECTOR_TRACK_IS_INDESTRUCTIBLE), // WIDX_TRACK_CHECK_IS_INDESTRUCTIBLE
- kWidgetsEnd,
};
constexpr int32_t NumSceneryProperties = 4; // The checkbox groups both count for 2 rows
constexpr int32_t NumSceneryDetails = 3;
constexpr int32_t SceneryPropertiesHeight = 16 + NumSceneryProperties * 21;
constexpr int32_t SceneryDetailsHeight = 20 + NumSceneryDetails * 11;
- static Widget SceneryWidgets[] = {
+ static constexpr Widget SceneryWidgets[] = {
MAIN_TILE_INSPECTOR_WIDGETS,
MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_SCENERY_SPINNER_HEIGHT{,_INCREASE,_DECREASE}
MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 1, 1), 1, 0), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_SCENERY_CHECK_QUARTER_N
@@ -361,60 +373,54 @@ namespace OpenRCT2::Ui::Windows
MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 2, 1), 2, 1), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_SCENERY_CHECK_COLLISION_E
MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 2, 1), 1, 2), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_SCENERY_CHECK_COLLISION_S
MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 2, 1), 0, 1), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_SCENERY_CHECK_COLLISION_W
- kWidgetsEnd,
};
constexpr int32_t NumEntranceProperties = 2;
constexpr int32_t NumEntranceDetails = 4;
constexpr int32_t EntrancePropertiesHeight = 16 + NumEntranceProperties * 21;
constexpr int32_t EntranceDetailsHeight = 20 + NumEntranceDetails * 11;
- static Widget EntranceWidgets[] = {
+ static constexpr Widget EntranceWidgets[] = {
MAIN_TILE_INSPECTOR_WIDGETS,
MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_ENTRANCE_SPINNER_HEIGHT{,_INCREASE,_DECREASE}
MakeWidget(PropertyRowCol({ 12, 0 }, 1, 0), PropertyButtonSize, WindowWidgetType::Button, WindowColour::Secondary, STR_TILE_INSPECTOR_ENTRANCE_MAKE_USABLE, STR_TILE_INSPECTOR_ENTRANCE_MAKE_USABLE_TIP), // WIDX_ENTRANCE_BUTTON_MAKE_USABLE
- kWidgetsEnd,
};
constexpr int32_t NumWallProperties = 4;
constexpr int32_t NumWallDetails = 2;
constexpr int32_t WallPropertiesHeight = 16 + NumWallProperties * 21;
constexpr int32_t WallDetailsHeight = 20 + NumWallDetails * 11;
- static Widget WallWidgets[] = {
+ static constexpr Widget WallWidgets[] = {
MAIN_TILE_INSPECTOR_WIDGETS,
MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_WALL_SPINNER_HEIGHT{,_INCREASE,_DECREASE}
MakeWidget(PropertyRowCol({ 12, 0 }, 1, 1), PropertyButtonSize, WindowWidgetType::DropdownMenu, WindowColour::Secondary), // WIDX_WALL_DROPDOWN_SLOPE
MakeWidget(PropertyRowCol({ 12 + PropertyButtonSize.width - 12, 0 }, 1, 1), { 11, 12}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH), // WIDX_WALL_DROPDOWN_SLOPE_BUTTON
MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 2, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_WALL_SPINNER_ANIMATION_FRAME{,_INCREASE,_DECREASE}
MakeWidget(PropertyRowCol({ 12, 0 }, 3, 0), PropertyFullWidth, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_TILE_INSPECTOR_WALL_ANIMATION_IS_BACKWARDS), // WIDX_WALL_ANIMATION_IS_BACKWARDS
- kWidgetsEnd,
};
constexpr int32_t NumLargeSceneryProperties = 1;
constexpr int32_t NumLargeSceneryDetails = 3;
constexpr int32_t LargeSceneryPropertiesHeight = 16 + NumLargeSceneryProperties * 21;
constexpr int32_t LargeSceneryDetailsHeight = 20 + NumLargeSceneryDetails * 11;
- static Widget LargeSceneryWidgets[] = {
+ static constexpr Widget LargeSceneryWidgets[] = {
MAIN_TILE_INSPECTOR_WIDGETS,
MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_LARGE_SCENERY_SPINNER_HEIGHT{,_INCREASE,_DECREASE}
- kWidgetsEnd,
};
constexpr int32_t NumBannerProperties = 3;
constexpr int32_t NumBannerDetails = 1;
constexpr int32_t BannerPropertiesHeight = 16 + NumBannerProperties * 21;
constexpr int32_t BannerDetailsHeight = 20 + NumBannerDetails * 11;
- static Widget BannerWidgets[] = {
+ static constexpr Widget BannerWidgets[] = {
MAIN_TILE_INSPECTOR_WIDGETS,
MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_BANNER_SPINNER_HEIGHT{,_INCREASE,_DECREASE}
MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 1, 1), 3, 1), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_BANNER_CHECK_BLOCK_NE
MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 1, 1), 3, 3), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_BANNER_CHECK_BLOCK_SE
MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 1, 1), 1, 3), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_BANNER_CHECK_BLOCK_SW
MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 1, 1), 1, 1), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_BANNER_CHECK_BLOCK_NW
-
- kWidgetsEnd,
};
- static Widget *PageWidgets[] = {
+ static constexpr std::span PageWidgets[] = {
DefaultWidgets,
SurfaceWidgets,
PathWidgets,
@@ -1778,7 +1784,7 @@ static uint64_t PageDisabledWidgets[] = {
}
tileInspectorPage = p;
auto pageIndex = EnumValue(p);
- widgets = PageWidgets[pageIndex];
+ SetWidgets(PageWidgets[pageIndex]);
hold_down_widgets = PageHoldDownWidgets[pageIndex];
disabled_widgets = PageDisabledWidgets[pageIndex];
pressed_widgets = 0;
diff --git a/src/openrct2-ui/windows/TitleExit.cpp b/src/openrct2-ui/windows/TitleExit.cpp
index 0fd2a4efd7..ef4b3d5837 100644
--- a/src/openrct2-ui/windows/TitleExit.cpp
+++ b/src/openrct2-ui/windows/TitleExit.cpp
@@ -19,16 +19,15 @@ namespace OpenRCT2::Ui::Windows
WIDX_EXIT,
};
- static Widget _titleExitWidgets[] = {
+ static constexpr Widget _titleExitWidgets[] = {
MakeWidget({ 0, 0 }, { 40, 64 }, WindowWidgetType::ImgBtn, WindowColour::Tertiary, ImageId(SPR_MENU_EXIT), STR_EXIT),
- kWidgetsEnd,
};
class TitleExitWindow final : public Window
{
void OnOpen() override
{
- widgets = _titleExitWidgets;
+ SetWidgets(_titleExitWidgets);
InitScrollWidgets();
}
diff --git a/src/openrct2-ui/windows/TitleLogo.cpp b/src/openrct2-ui/windows/TitleLogo.cpp
index fa5b23b83c..81ab20ddf2 100644
--- a/src/openrct2-ui/windows/TitleLogo.cpp
+++ b/src/openrct2-ui/windows/TitleLogo.cpp
@@ -23,9 +23,8 @@ namespace OpenRCT2::Ui::Windows
WIDX_LOGO
};
- static Widget _titleLogoWidgets[] = {
+ static constexpr Widget _titleLogoWidgets[] = {
MakeWidget({ 0, 0 }, { WW + 1, WH + 1 }, WindowWidgetType::ImgBtn, WindowColour::Primary),
- kWidgetsEnd,
};
class TitleLogoWindow final : public Window
@@ -37,7 +36,7 @@ namespace OpenRCT2::Ui::Windows
*/
void OnOpen() override
{
- widgets = _titleLogoWidgets;
+ SetWidgets(_titleLogoWidgets);
WindowInitScrollWidgets(*this);
colours[0] = ColourWithFlags{ COLOUR_GREY }.withFlag(ColourFlag::translucent, true);
colours[1] = ColourWithFlags{ COLOUR_GREY }.withFlag(ColourFlag::translucent, true);
diff --git a/src/openrct2-ui/windows/TitleMenu.cpp b/src/openrct2-ui/windows/TitleMenu.cpp
index 26605532f6..ce3731dc7f 100644
--- a/src/openrct2-ui/windows/TitleMenu.cpp
+++ b/src/openrct2-ui/windows/TitleMenu.cpp
@@ -47,13 +47,12 @@ namespace OpenRCT2::Ui::Windows
static constexpr ScreenSize UpdateButtonDims = { MenuButtonDims.width * 4, 28 };
// clang-format off
- static Widget _titleMenuWidgets[] = {
+ static constexpr Widget _titleMenuWidgets[] = {
MakeWidget({0, UpdateButtonDims.height}, MenuButtonDims, WindowWidgetType::ImgBtn, WindowColour::Tertiary, ImageId(SPR_MENU_NEW_GAME), STR_START_NEW_GAME_TIP),
MakeWidget({0, UpdateButtonDims.height}, MenuButtonDims, WindowWidgetType::ImgBtn, WindowColour::Tertiary, ImageId(SPR_MENU_LOAD_GAME), STR_CONTINUE_SAVED_GAME_TIP),
MakeWidget({0, UpdateButtonDims.height}, MenuButtonDims, WindowWidgetType::ImgBtn, WindowColour::Tertiary, ImageId(SPR_G2_MENU_MULTIPLAYER), STR_SHOW_MULTIPLAYER_TIP),
MakeWidget({0, UpdateButtonDims.height}, MenuButtonDims, WindowWidgetType::ImgBtn, WindowColour::Tertiary, ImageId(SPR_MENU_TOOLBOX), STR_GAME_TOOLS_TIP),
MakeWidget({0, 0}, UpdateButtonDims, WindowWidgetType::Empty, WindowColour::Secondary, STR_UPDATE_AVAILABLE),
- kWidgetsEnd,
};
// clang-format on
@@ -93,14 +92,14 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = _titleMenuWidgets;
+ SetWidgets(_titleMenuWidgets);
#ifdef DISABLE_NETWORK
widgets[WIDX_MULTIPLAYER].type = WindowWidgetType::Empty;
#endif
int32_t x = 0;
- for (Widget* widget = widgets; widget != &widgets[WIDX_NEW_VERSION]; widget++)
+ for (Widget* widget = widgets.data(); widget != &widgets[WIDX_NEW_VERSION]; widget++)
{
if (widget->type != WindowWidgetType::Empty)
{
diff --git a/src/openrct2-ui/windows/TitleOptions.cpp b/src/openrct2-ui/windows/TitleOptions.cpp
index 2ab8dcc91d..4657f236e5 100644
--- a/src/openrct2-ui/windows/TitleOptions.cpp
+++ b/src/openrct2-ui/windows/TitleOptions.cpp
@@ -18,9 +18,8 @@ namespace OpenRCT2::Ui::Windows
WIDX_OPTIONS,
};
- static Widget _windowTitleOptionsWidgets[] = {
+ static constexpr Widget _windowTitleOptionsWidgets[] = {
MakeWidget({ 0, 0 }, { 80, 15 }, WindowWidgetType::Button, WindowColour::Tertiary, STR_OPTIONS, STR_OPTIONS_TIP),
- kWidgetsEnd,
};
class TitleOptionsWindow final : public Window
@@ -28,7 +27,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = _windowTitleOptionsWidgets;
+ SetWidgets(_windowTitleOptionsWidgets);
WindowInitScrollWidgets(*this);
}
diff --git a/src/openrct2-ui/windows/TitleVersion.cpp b/src/openrct2-ui/windows/TitleVersion.cpp
index 4f1e59e7b0..791a9049fb 100644
--- a/src/openrct2-ui/windows/TitleVersion.cpp
+++ b/src/openrct2-ui/windows/TitleVersion.cpp
@@ -21,17 +21,8 @@ namespace OpenRCT2::Ui::Windows
static constexpr uint8_t kTextOffset = 8;
- static Widget _widgets[] = {
- kWidgetsEnd,
- };
-
class TitleVersionWindow final : public Window
{
- void OnOpen() override
- {
- widgets = _widgets;
- }
-
void OnDraw(DrawPixelInfo& dpi) override
{
// Write name and version information
diff --git a/src/openrct2-ui/windows/Tooltip.cpp b/src/openrct2-ui/windows/Tooltip.cpp
index 89b9e0b527..16454fbc4b 100644
--- a/src/openrct2-ui/windows/Tooltip.cpp
+++ b/src/openrct2-ui/windows/Tooltip.cpp
@@ -24,9 +24,8 @@ namespace OpenRCT2::Ui::Windows
WIDX_BACKGROUND
};
- static Widget _tooltipWidgets[] = {
+ static constexpr Widget _tooltipWidgets[] = {
MakeWidget({ 0, 0 }, { 200, 32 }, WindowWidgetType::ImgBtn, WindowColour::Primary),
- kWidgetsEnd,
};
class TooltipWindow final : public Window
@@ -44,7 +43,7 @@ namespace OpenRCT2::Ui::Windows
width = textWidth + 5;
height = textHeight + 4;
- widgets = _tooltipWidgets;
+ SetWidgets(_tooltipWidgets);
widgets[WIDX_BACKGROUND].right = width;
widgets[WIDX_BACKGROUND].bottom = height;
@@ -165,7 +164,7 @@ namespace OpenRCT2::Ui::Windows
void WindowTooltipOpen(WindowBase* widgetWindow, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
{
- if (widgetWindow == nullptr || widgetIndex == -1)
+ if (widgetWindow == nullptr || widgetIndex == kWidgetIndexNull)
return;
auto widget = &widgetWindow->widgets[widgetIndex];
diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp
index 5c9ae87777..098851dd15 100644
--- a/src/openrct2-ui/windows/TopToolbar.cpp
+++ b/src/openrct2-ui/windows/TopToolbar.cpp
@@ -236,7 +236,7 @@ namespace OpenRCT2::Ui::Windows
#pragma endregion
- static Widget _topToolbarWidgets[] = {
+ static constexpr Widget _topToolbarWidgets[] = {
MakeRemapWidget({ 0, 0}, {30, kTopToolbarHeight + 1}, WindowWidgetType::TrnBtn, WindowColour::Primary , SPR_TOOLBAR_PAUSE, STR_PAUSE_GAME_TIP ), // Pause
MakeRemapWidget({ 60, 0}, {30, kTopToolbarHeight + 1}, WindowWidgetType::TrnBtn, WindowColour::Primary , SPR_TOOLBAR_FILE, STR_DISC_AND_GAME_OPTIONS_TIP ), // File menu
MakeRemapWidget({250, 0}, {30, kTopToolbarHeight + 1}, WindowWidgetType::TrnBtn, WindowColour::Primary , SPR_G2_TOOLBAR_MUTE, STR_TOOLBAR_MUTE_TIP ), // Mute
@@ -264,7 +264,6 @@ namespace OpenRCT2::Ui::Windows
MakeRemapWidget({ 30, 0}, {30, kTopToolbarHeight + 1}, WindowWidgetType::TrnBtn, WindowColour::Primary , SPR_G2_TOOLBAR_MULTIPLAYER, STR_SHOW_MULTIPLAYER_STATUS_TIP ), // Network
MakeRemapWidget({ 30, 0}, {30, kTopToolbarHeight + 1}, WindowWidgetType::TrnBtn, WindowColour::Primary , SPR_TAB_TOOLBAR, STR_TOOLBAR_CHAT_TIP ), // Chat
MakeWidget ({ 0, 0}, {10, 1}, WindowWidgetType::Empty, WindowColour::Primary ), // Artificial widget separator
- kWidgetsEnd,
};
// clang-format on
@@ -1003,7 +1002,7 @@ namespace OpenRCT2::Ui::Windows
WindowClass::TopToolbar, ScreenCoordsXY(0, 0), ContextGetWidth(), kTopToolbarHeight + 1,
WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_NO_BACKGROUND);
- window->widgets = _topToolbarWidgets;
+ window->SetWidgets(_topToolbarWidgets);
WindowInitScrollWidgets(*window);
diff --git a/src/openrct2-ui/windows/TrackDesignManage.cpp b/src/openrct2-ui/windows/TrackDesignManage.cpp
index 1ace39ea5b..c82fbb3c58 100644
--- a/src/openrct2-ui/windows/TrackDesignManage.cpp
+++ b/src/openrct2-ui/windows/TrackDesignManage.cpp
@@ -40,18 +40,16 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget _trackManageWidgets[] = {
+ static constexpr Widget _trackManageWidgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({ 10, 24}, {110, 12}, WindowWidgetType::Button, WindowColour::Primary, STR_TRACK_MANAGE_RENAME),
MakeWidget({130, 24}, {110, 12}, WindowWidgetType::Button, WindowColour::Primary, STR_TRACK_MANAGE_DELETE),
- kWidgetsEnd,
};
- static Widget _trackDeletePromptWidgets[] = {
+ static constexpr Widget _trackDeletePromptWidgets[] = {
WINDOW_SHIM(STR_DELETE_FILE, WW_DELETE_PROMPT, WH_DELETE_PROMPT),
MakeWidget({ 10, 54}, {110, 12}, WindowWidgetType::Button, WindowColour::Primary, STR_TRACK_MANAGE_DELETE),
MakeWidget({130, 54}, {110, 12}, WindowWidgetType::Button, WindowColour::Primary, STR_CANCEL ),
- kWidgetsEnd,
};
// clang-format on
@@ -120,7 +118,7 @@ namespace OpenRCT2::Ui::Windows
void TrackDesignManageWindow::OnOpen()
{
- widgets = _trackManageWidgets;
+ SetWidgets(_trackManageWidgets);
WindowInitScrollWidgets(*this);
WindowTrackDesignListSetBeingUpdated(true);
@@ -205,7 +203,7 @@ namespace OpenRCT2::Ui::Windows
void TrackDeletePromptWindow::OnOpen()
{
- widgets = _trackDeletePromptWidgets;
+ SetWidgets(_trackDeletePromptWidgets);
WindowInitScrollWidgets(*this);
}
diff --git a/src/openrct2-ui/windows/TrackDesignPlace.cpp b/src/openrct2-ui/windows/TrackDesignPlace.cpp
index 7a6e4cde7f..d35e59895e 100644
--- a/src/openrct2-ui/windows/TrackDesignPlace.cpp
+++ b/src/openrct2-ui/windows/TrackDesignPlace.cpp
@@ -68,13 +68,12 @@ namespace OpenRCT2::Ui::Windows
validate_global_widx(WC_TRACK_DESIGN_PLACE, WIDX_ROTATE);
// clang-format off
- static Widget _trackPlaceWidgets[] = {
+ static constexpr Widget _trackPlaceWidgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({173, 83}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Primary, ImageId(SPR_ROTATE_ARROW), STR_ROTATE_90_TIP ),
MakeWidget({173, 59}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Primary, ImageId(SPR_MIRROR_ARROW), STR_MIRROR_IMAGE_TIP ),
MakeWidget({ 4, 109}, {192, 12}, WindowWidgetType::Button, WindowColour::Primary, STR_SELECT_A_DIFFERENT_DESIGN, STR_GO_BACK_TO_DESIGN_SELECTION_WINDOW_TIP),
MakeWidget({ 0, 0}, { 1, 1}, WindowWidgetType::Empty, WindowColour::Primary),
- kWidgetsEnd,
};
// clang-format on
@@ -103,7 +102,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = _trackPlaceWidgets;
+ SetWidgets(_trackPlaceWidgets);
WindowInitScrollWidgets(*this);
ToolSet(*this, WIDX_PRICE, Tool::Crosshair);
InputSetFlag(INPUT_FLAG_6, true);
diff --git a/src/openrct2-ui/windows/TrackList.cpp b/src/openrct2-ui/windows/TrackList.cpp
index 84d6a055c9..bbb102b292 100644
--- a/src/openrct2-ui/windows/TrackList.cpp
+++ b/src/openrct2-ui/windows/TrackList.cpp
@@ -55,7 +55,7 @@ namespace OpenRCT2::Ui::Windows
validate_global_widx(WC_TRACK_DESIGN_LIST, WIDX_ROTATE);
// clang-format off
- static Widget _trackListWidgets[] = {
+ static constexpr Widget _trackListWidgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({ 4, 18}, {218, 13}, WindowWidgetType::TableHeader, WindowColour::Primary, STR_SELECT_OTHER_RIDE ),
MakeWidget({ 4, 32}, {124, 13}, WindowWidgetType::TextBox, WindowColour::Secondary ),
@@ -64,7 +64,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({224, 18}, {372, 219}, WindowWidgetType::FlatBtn, WindowColour::Primary ),
MakeWidget({572, 405}, { ROTATE_AND_SCENERY_BUTTON_SIZE, ROTATE_AND_SCENERY_BUTTON_SIZE}, WindowWidgetType::FlatBtn, WindowColour::Primary, ImageId(SPR_ROTATE_ARROW), STR_ROTATE_90_TIP ),
MakeWidget({572, 381}, { ROTATE_AND_SCENERY_BUTTON_SIZE, ROTATE_AND_SCENERY_BUTTON_SIZE}, WindowWidgetType::FlatBtn, WindowColour::Primary, ImageId(SPR_SCENERY), STR_TOGGLE_SCENERY_TIP ),
- kWidgetsEnd,
};
// clang-format on
@@ -218,8 +217,8 @@ namespace OpenRCT2::Ui::Windows
void OnOpen() override
{
String::set(_filterString, sizeof(_filterString), "");
- _trackListWidgets[WIDX_FILTER_STRING].string = _filterString;
- widgets = _trackListWidgets;
+ SetWidgets(_trackListWidgets);
+ widgets[WIDX_FILTER_STRING].string = _filterString;
LoadDesignsList(_window_track_list_item);
diff --git a/src/openrct2-ui/windows/Transparency.cpp b/src/openrct2-ui/windows/Transparency.cpp
index 5d658ee9be..77381784cb 100644
--- a/src/openrct2-ui/windows/Transparency.cpp
+++ b/src/openrct2-ui/windows/Transparency.cpp
@@ -63,7 +63,7 @@ namespace OpenRCT2::Ui::Windows
#pragma endregion
// clang-format off
- static Widget _transparancyWidgets[] =
+ static constexpr Widget _transparancyWidgets[] =
{
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({ 2, 17}, HIDE_SIZE, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_G2_BUTTON_HIDE_VEGETATION), STR_SEE_THROUGH_VEGETATION),
@@ -81,8 +81,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({ 77, 42}, INVISIBLE_SIZE, WindowWidgetType::FlatBtn, WindowColour::Tertiary, STR_NONE, STR_INVISIBLE_RIDES),
MakeWidget({102, 42}, INVISIBLE_SIZE, WindowWidgetType::FlatBtn, WindowColour::Tertiary, STR_NONE, STR_INVISIBLE_VEHICLES),
MakeWidget({127, 42}, INVISIBLE_SIZE, WindowWidgetType::FlatBtn, WindowColour::Tertiary, STR_NONE, STR_INVISIBLE_SUPPORTS),
-
- { kWidgetsEnd },
};
// clang-format on
@@ -92,7 +90,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = _transparancyWidgets;
+ SetWidgets(_transparancyWidgets);
WindowPushOthersBelow(*this);
auto* w = WindowGetMain();
diff --git a/src/openrct2-ui/windows/ViewClipping.cpp b/src/openrct2-ui/windows/ViewClipping.cpp
index 4fc6b75675..15e30a91d1 100644
--- a/src/openrct2-ui/windows/ViewClipping.cpp
+++ b/src/openrct2-ui/windows/ViewClipping.cpp
@@ -51,7 +51,7 @@ namespace OpenRCT2::Ui::Windows
static constexpr int32_t WH = 155;
// clang-format off
- static Widget _viewClippingWidgets[] = {
+ static constexpr Widget _viewClippingWidgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget ({ 11, 19}, { 159, 11}, WindowWidgetType::Checkbox, WindowColour::Primary, STR_VIEW_CLIPPING_HEIGHT_ENABLE, STR_VIEW_CLIPPING_HEIGHT_ENABLE_TIP ), // clip enable/disable check box
MakeWidget ({ 5, 36}, {WW - 10, 48}, WindowWidgetType::Groupbox, WindowColour::Primary, STR_VIEW_CLIPPING_VERTICAL_CLIPPING ),
@@ -60,8 +60,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget ({ 5, 90}, {WW - 10, 60}, WindowWidgetType::Groupbox, WindowColour::Primary, STR_VIEW_CLIPPING_HORIZONTAL_CLIPPING ),
MakeWidget ({ 11, 105}, { 158, 17}, WindowWidgetType::Button, WindowColour::Primary, STR_VIEW_CLIPPING_SELECT_AREA ), // selector
MakeWidget ({ 11, 126}, { 158, 18}, WindowWidgetType::Button, WindowColour::Primary, STR_VIEW_CLIPPING_CLEAR_SELECTION ), // clear
-
- kWidgetsEnd,
};
// clang-format on
@@ -346,7 +344,7 @@ namespace OpenRCT2::Ui::Windows
void OnOpen() override
{
- this->widgets = _viewClippingWidgets;
+ SetWidgets(_viewClippingWidgets);
this->hold_down_widgets = (1uLL << WIDX_CLIP_HEIGHT_INCREASE) | (1uL << WIDX_CLIP_HEIGHT_DECREASE);
WindowInitScrollWidgets(*this);
diff --git a/src/openrct2-ui/windows/Viewport.cpp b/src/openrct2-ui/windows/Viewport.cpp
index e99e01cf95..13476843d1 100644
--- a/src/openrct2-ui/windows/Viewport.cpp
+++ b/src/openrct2-ui/windows/Viewport.cpp
@@ -43,7 +43,7 @@ namespace OpenRCT2::Ui::Windows
#pragma endregion
// clang-format off
- static Widget _viewportWidgets[] =
+ static constexpr Widget _viewportWidgets[] =
{
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget({ 0, 14}, { WW - 1, WH - 1}, WindowWidgetType::Resize, WindowColour::Secondary ), // resize
@@ -52,7 +52,6 @@ namespace OpenRCT2::Ui::Windows
MakeWidget({WW - 25, 41}, VIEWPORT_BUTTON, WindowWidgetType::FlatBtn, WindowColour::Primary , ImageId(SPR_G2_ZOOM_OUT), STR_ZOOM_OUT_TIP ), // zoom out
MakeWidget({WW - 25, 65}, VIEWPORT_BUTTON, WindowWidgetType::FlatBtn, WindowColour::Primary , ImageId(SPR_LOCATE), STR_LOCATE_SUBJECT_TIP), // locate
MakeWidget({WW - 25, 89}, VIEWPORT_BUTTON, WindowWidgetType::FlatBtn, WindowColour::Primary , ImageId(SPR_ROTATE_ARROW),STR_LOCATE_SUBJECT_TIP), // rotate
- kWidgetsEnd,
};
// clang-format on
@@ -76,7 +75,7 @@ namespace OpenRCT2::Ui::Windows
{
GetFreeViewportNumber();
- widgets = _viewportWidgets;
+ SetWidgets(_viewportWidgets);
// Create viewport
ViewportCreate(this, windowPos, width, height, Focus(TileCoordsXYZ(128, 128, 0).ToCoordsXYZ()));
diff --git a/src/openrct2-ui/windows/Water.cpp b/src/openrct2-ui/windows/Water.cpp
index fecda78373..8427e3ef88 100644
--- a/src/openrct2-ui/windows/Water.cpp
+++ b/src/openrct2-ui/windows/Water.cpp
@@ -41,12 +41,11 @@ namespace OpenRCT2::Ui::Windows
};
// clang-format off
- static Widget _waterWidgets[] = {
+ static constexpr Widget _waterWidgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget ({16, 17}, {44, 32}, WindowWidgetType::ImgBtn, WindowColour::Primary , ImageId(SPR_LAND_TOOL_SIZE_0), STR_NONE), // preview box
MakeRemapWidget({17, 18}, {16, 16}, WindowWidgetType::TrnBtn, WindowColour::Tertiary, SPR_LAND_TOOL_DECREASE, STR_ADJUST_SMALLER_WATER_TIP), // decrement size
MakeRemapWidget({43, 32}, {16, 16}, WindowWidgetType::TrnBtn, WindowColour::Tertiary, SPR_LAND_TOOL_INCREASE, STR_ADJUST_LARGER_WATER_TIP), // increment size
- kWidgetsEnd,
};
// clang-format on
@@ -59,7 +58,7 @@ namespace OpenRCT2::Ui::Windows
public:
void OnOpen() override
{
- widgets = _waterWidgets;
+ SetWidgets(_waterWidgets);
hold_down_widgets = (1uLL << WIDX_INCREMENT) | (1uLL << WIDX_DECREMENT);
WindowInitScrollWidgets(*this);
WindowPushOthersBelow(*this);
diff --git a/src/openrct2-ui/windows/Window.h b/src/openrct2-ui/windows/Window.h
index ddc0faaf7d..a953b8954c 100644
--- a/src/openrct2-ui/windows/Window.h
+++ b/src/openrct2-ui/windows/Window.h
@@ -11,6 +11,7 @@
#include
#include
+#include
#include
struct ObjectEntryDescriptor;
diff --git a/src/openrct2/Context.h b/src/openrct2/Context.h
index 290dce7602..1a8649e6d8 100644
--- a/src/openrct2/Context.h
+++ b/src/openrct2/Context.h
@@ -25,12 +25,13 @@ enum class CursorID : uint8_t;
namespace OpenRCT2
{
struct IStream;
-}
+ class Intent;
+ struct WindowBase;
+} // namespace OpenRCT2
+
struct ITrackDesignRepository;
struct IGameStateSnapshots;
-class Intent;
-struct WindowBase;
struct NewVersionInfo;
struct TTFFontDescriptor;
@@ -221,12 +222,12 @@ int32_t ContextGetWidth();
int32_t ContextGetHeight();
bool ContextHasFocus();
void ContextSetCursorTrap(bool value);
-WindowBase* ContextOpenWindow(WindowClass wc);
-WindowBase* ContextOpenDetailWindow(uint8_t type, int32_t id);
-WindowBase* ContextOpenWindowView(uint8_t view);
-WindowBase* ContextShowError(StringId title, StringId message, const class Formatter& args, bool autoClose = false);
-WindowBase* ContextOpenIntent(Intent* intent);
-void ContextBroadcastIntent(Intent* intent);
+OpenRCT2::WindowBase* ContextOpenWindow(WindowClass wc);
+OpenRCT2::WindowBase* ContextOpenDetailWindow(uint8_t type, int32_t id);
+OpenRCT2::WindowBase* ContextOpenWindowView(uint8_t view);
+OpenRCT2::WindowBase* ContextShowError(StringId title, StringId message, const class Formatter& args, bool autoClose = false);
+OpenRCT2::WindowBase* ContextOpenIntent(OpenRCT2::Intent* intent);
+void ContextBroadcastIntent(OpenRCT2::Intent* intent);
void ContextForceCloseWindowByClass(WindowClass wc);
void ContextHandleInput();
void ContextInputHandleKeyboard(bool isTitle);
diff --git a/src/openrct2/Game.h b/src/openrct2/Game.h
index 9b4908e1b1..e83ddfbd53 100644
--- a/src/openrct2/Game.h
+++ b/src/openrct2/Game.h
@@ -13,7 +13,11 @@
#include
-class Intent;
+namespace OpenRCT2
+{
+ class Intent;
+}
+
struct ParkLoadResult;
enum class GameCommand : int32_t
@@ -165,7 +169,7 @@ void PauseToggle();
bool GameIsPaused();
bool GameIsNotPaused();
void SaveGame();
-std::unique_ptr CreateSaveGameAsIntent();
+std::unique_ptr CreateSaveGameAsIntent();
void SaveGameAs();
void SaveGameCmd(u8string_view name = {});
void SaveGameWithName(u8string_view name);
diff --git a/src/openrct2/Input.cpp b/src/openrct2/Input.cpp
index c25e902ed1..2f85b6a3a2 100644
--- a/src/openrct2/Input.cpp
+++ b/src/openrct2/Input.cpp
@@ -12,65 +12,68 @@
#include "Context.h"
#include "Game.h"
-InputState _inputState;
-uint8_t _inputFlags;
-
-WidgetRef gHoverWidget;
-WidgetRef gPressedWidget;
-
-uint32_t _tooltipNotShownTimeout;
-
-/**
- *
- * rct2: 0x006E3B43
- */
-void TitleHandleKeyboardInput()
+namespace OpenRCT2
{
- ContextInputHandleKeyboard(true);
-}
+ InputState _inputState;
+ uint8_t _inputFlags;
-/**
- *
- * rct2: 0x006E3B43
- */
-void GameHandleKeyboardInput()
-{
- ContextInputHandleKeyboard(false);
-}
+ WidgetRef gHoverWidget;
+ WidgetRef gPressedWidget;
-void InputSetFlag(INPUT_FLAGS flag, bool on)
-{
- if (on)
+ uint32_t _tooltipNotShownTimeout;
+
+ /**
+ *
+ * rct2: 0x006E3B43
+ */
+ void TitleHandleKeyboardInput()
{
- _inputFlags |= flag;
+ ContextInputHandleKeyboard(true);
}
- else
+
+ /**
+ *
+ * rct2: 0x006E3B43
+ */
+ void GameHandleKeyboardInput()
{
- _inputFlags &= ~flag;
+ ContextInputHandleKeyboard(false);
}
-}
-bool InputTestFlag(INPUT_FLAGS flag)
-{
- return _inputFlags & flag;
-}
+ void InputSetFlag(INPUT_FLAGS flag, bool on)
+ {
+ if (on)
+ {
+ _inputFlags |= flag;
+ }
+ else
+ {
+ _inputFlags &= ~flag;
+ }
+ }
-void InputResetFlags()
-{
- _inputFlags = 0;
-}
+ bool InputTestFlag(INPUT_FLAGS flag)
+ {
+ return _inputFlags & flag;
+ }
-void InputSetState(InputState state)
-{
- _inputState = state;
-}
+ void InputResetFlags()
+ {
+ _inputFlags = 0;
+ }
-InputState InputGetState()
-{
- return _inputState;
-}
+ void InputSetState(InputState state)
+ {
+ _inputState = state;
+ }
-void ResetTooltipNotShown()
-{
- _tooltipNotShownTimeout = gCurrentRealTimeTicks + 50;
-}
+ InputState InputGetState()
+ {
+ return _inputState;
+ }
+
+ void ResetTooltipNotShown()
+ {
+ _tooltipNotShownTimeout = gCurrentRealTimeTicks + 50;
+ }
+} // namespace OpenRCT2
diff --git a/src/openrct2/Input.h b/src/openrct2/Input.h
index bf38db927c..8189e18926 100644
--- a/src/openrct2/Input.h
+++ b/src/openrct2/Input.h
@@ -11,65 +11,68 @@
#include "interface/Window.h"
-enum INPUT_FLAGS
+namespace OpenRCT2
{
- INPUT_FLAG_WIDGET_PRESSED = (1 << 0),
+ enum INPUT_FLAGS
+ {
+ INPUT_FLAG_WIDGET_PRESSED = (1 << 0),
- // The dropdown can stay open if the mouse is released, set on flag Dropdown::Flag::StayOpen
- INPUT_FLAG_DROPDOWN_STAY_OPEN = (1 << 1),
+ // The dropdown can stay open if the mouse is released, set on flag Dropdown::Flag::StayOpen
+ INPUT_FLAG_DROPDOWN_STAY_OPEN = (1 << 1),
- // The mouse has been released and the dropdown is still open
- // INPUT_FLAG_DROPDOWN_STAY_OPEN is already set if this happens
- INPUT_FLAG_DROPDOWN_MOUSE_UP = (1 << 2),
+ // The mouse has been released and the dropdown is still open
+ // INPUT_FLAG_DROPDOWN_STAY_OPEN is already set if this happens
+ INPUT_FLAG_DROPDOWN_MOUSE_UP = (1 << 2),
- INPUT_FLAG_TOOL_ACTIVE = (1 << 3),
+ INPUT_FLAG_TOOL_ACTIVE = (1 << 3),
- // Left click on a viewport
- INPUT_FLAG_4 = (1 << 4),
+ // Left click on a viewport
+ INPUT_FLAG_4 = (1 << 4),
- INPUT_FLAG_5 = (1 << 5),
+ INPUT_FLAG_5 = (1 << 5),
- // Some of the map tools (clear, footpath, scenery)
- // never read as far as I know.
- INPUT_FLAG_6 = (1 << 6),
+ // Some of the map tools (clear, footpath, scenery)
+ // never read as far as I know.
+ INPUT_FLAG_6 = (1 << 6),
- INPUT_FLAG_VIEWPORT_SCROLLING = (1 << 7)
-};
+ INPUT_FLAG_VIEWPORT_SCROLLING = (1 << 7)
+ };
-enum class InputState
-{
- Reset,
- Normal,
- WidgetPressed,
- PositioningWindow,
- ViewportRight,
- DropdownActive,
- ViewportLeft,
- ScrollLeft,
- Resizing,
- ScrollRight
-};
+ enum class InputState
+ {
+ Reset,
+ Normal,
+ WidgetPressed,
+ PositioningWindow,
+ ViewportRight,
+ DropdownActive,
+ ViewportLeft,
+ ScrollLeft,
+ Resizing,
+ ScrollRight
+ };
-extern WidgetRef gHoverWidget;
-extern WidgetRef gPressedWidget;
+ extern WidgetRef gHoverWidget;
+ extern WidgetRef gPressedWidget;
-extern uint32_t gTooltipCloseTimeout;
-extern WidgetRef gTooltipWidget;
-extern ScreenCoordsXY gTooltipCursor;
+ extern uint32_t gTooltipCloseTimeout;
+ extern WidgetRef gTooltipWidget;
+ extern ScreenCoordsXY gTooltipCursor;
-// TODO: Move to openrct2-ui and make static again
-extern InputState _inputState;
-extern uint8_t _inputFlags;
-extern uint32_t _tooltipNotShownTimeout;
+ // TODO: Move to openrct2-ui and make static again
+ extern InputState _inputState;
+ extern uint8_t _inputFlags;
+ extern uint32_t _tooltipNotShownTimeout;
-void TitleHandleKeyboardInput();
-void GameHandleKeyboardInput();
+ void TitleHandleKeyboardInput();
+ void GameHandleKeyboardInput();
-void InputSetFlag(INPUT_FLAGS flag, bool on);
-bool InputTestFlag(INPUT_FLAGS flag);
-void InputResetFlags();
+ void InputSetFlag(INPUT_FLAGS flag, bool on);
+ bool InputTestFlag(INPUT_FLAGS flag);
+ void InputResetFlags();
-void InputSetState(InputState state);
-InputState InputGetState();
+ void InputSetState(InputState state);
+ InputState InputGetState();
-void ResetTooltipNotShown();
+ void ResetTooltipNotShown();
+} // namespace OpenRCT2
diff --git a/src/openrct2/actions/RideCreateAction.cpp b/src/openrct2/actions/RideCreateAction.cpp
index be4d39e8c6..235106cf61 100644
--- a/src/openrct2/actions/RideCreateAction.cpp
+++ b/src/openrct2/actions/RideCreateAction.cpp
@@ -28,6 +28,8 @@
#include "../scenario/Scenario.h"
#include "../world/Park.h"
+#include
+
using namespace OpenRCT2;
RideCreateAction::RideCreateAction(
@@ -147,18 +149,12 @@ GameActions::Result RideCreateAction::Execute() const
ride->overall_view.SetNull();
ride->SetNameToDefault();
- for (auto& station : ride->GetStations())
- {
- station.Start.SetNull();
- station.Entrance.SetNull();
- station.Exit.SetNull();
- station.TrainAtStation = RideStation::kNoTrain;
- station.QueueTime = 0;
- station.SegmentLength = 0;
- station.QueueLength = 0;
- station.Length = 0;
- station.Height = 0;
- }
+ // Default initialize all stations.
+ RideStation station{};
+ station.Start.SetNull();
+ station.Entrance.SetNull();
+ station.Exit.SetNull();
+ std::ranges::fill(ride->GetStations(), station);
ride->status = RideStatus::Closed;
ride->NumTrains = 1;
diff --git a/src/openrct2/actions/TrackRemoveAction.cpp b/src/openrct2/actions/TrackRemoveAction.cpp
index 694b837491..5191487256 100644
--- a/src/openrct2/actions/TrackRemoveAction.cpp
+++ b/src/openrct2/actions/TrackRemoveAction.cpp
@@ -234,7 +234,7 @@ GameActions::Result TrackRemoveAction::Query() const
GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, STR_ERR_SURFACE_ELEMENT_NOT_FOUND);
}
- int8_t _support_height = tileElement->BaseHeight - surfaceElement->BaseHeight;
+ int16_t _support_height = tileElement->BaseHeight - surfaceElement->BaseHeight;
if (_support_height < 0)
{
_support_height = 10;
@@ -410,7 +410,7 @@ GameActions::Result TrackRemoveAction::Execute() const
GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, STR_ERR_SURFACE_ELEMENT_NOT_FOUND);
}
- int8_t _support_height = tileElement->BaseHeight - surfaceElement->BaseHeight;
+ int16_t _support_height = tileElement->BaseHeight - surfaceElement->BaseHeight;
if (_support_height < 0)
{
_support_height = 10;
diff --git a/src/openrct2/core/OrcaStream.hpp b/src/openrct2/core/OrcaStream.hpp
index a4030e4c40..d59cdb53cc 100644
--- a/src/openrct2/core/OrcaStream.hpp
+++ b/src/openrct2/core/OrcaStream.hpp
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -468,15 +469,8 @@ namespace OpenRCT2
}
}
- template
- void ReadWriteArray(TArr (&arr)[TArrSize], TFunc f)
- {
- auto& arr2 = *(reinterpret_cast*>(arr));
- ReadWriteArray(arr2, f);
- }
-
- template
- void ReadWriteArray(std::array& arr, TFunc f)
+ template
+ void ReadWriteArray(std::span arr, TFunc f)
{
if (_mode == Mode::READING)
{
@@ -487,7 +481,7 @@ namespace OpenRCT2
}
for (size_t i = 0; i < count; i++)
{
- if (i < TArrSize)
+ if (i < arr.size())
{
f(arr[i]);
}
@@ -509,6 +503,18 @@ namespace OpenRCT2
}
}
+ template
+ void ReadWriteArray(TArr (&arr)[TArrSize], TFunc f)
+ {
+ ReadWriteArray(std::span{ arr, TArrSize }, f);
+ }
+
+ template
+ void ReadWriteArray(std::array& arr, TFunc f)
+ {
+ ReadWriteArray(std::span{ arr.begin(), arr.end() }, f);
+ }
+
template
void Ignore()
{
diff --git a/src/openrct2/entity/EntityRegistry.cpp b/src/openrct2/entity/EntityRegistry.cpp
index de7e54a43d..f4592de1d0 100644
--- a/src/openrct2/entity/EntityRegistry.cpp
+++ b/src/openrct2/entity/EntityRegistry.cpp
@@ -531,6 +531,8 @@ static void FreeEntity(EntityBase& entity)
else if (guest != nullptr)
{
guest->SetName({});
+ guest->GuestNextInQueue = EntityId::GetNull();
+
OpenRCT2::RideUse::GetHistory().RemoveHandle(guest->Id);
OpenRCT2::RideUse::GetTypeHistory().RemoveHandle(guest->Id);
}
diff --git a/src/openrct2/entity/Guest.cpp b/src/openrct2/entity/Guest.cpp
index 9b14e4b5cc..bec70cc448 100644
--- a/src/openrct2/entity/Guest.cpp
+++ b/src/openrct2/entity/Guest.cpp
@@ -7280,6 +7280,7 @@ Guest* Guest::Generate(const CoordsXYZ& coords)
peep->ResetPathfindGoal();
peep->RemoveAllItems();
peep->GuestHeadingToRideId = RideId::GetNull();
+ peep->GuestNextInQueue = EntityId::GetNull();
peep->LitterCount = 0;
peep->DisgustingCount = 0;
peep->VandalismSeen = 0;
diff --git a/src/openrct2/interface/InteractiveConsole.cpp b/src/openrct2/interface/InteractiveConsole.cpp
index 148cb79e98..b732633506 100644
--- a/src/openrct2/interface/InteractiveConsole.cpp
+++ b/src/openrct2/interface/InteractiveConsole.cpp
@@ -691,8 +691,8 @@ static void ConsoleCommandGet(InteractiveConsole& console, const arguments_t& ar
if (w != nullptr)
{
Viewport* viewport = WindowGetViewport(w);
- auto info = GetMapCoordinatesFromPos(
- { viewport->ViewWidth() / 2, viewport->ViewHeight() / 2 }, EnumsToFlags(ViewportInteractionItem::Terrain));
+ auto info = GetMapCoordinatesFromPosWindow(
+ w, { viewport->width / 2, viewport->height / 2 }, EnumsToFlags(ViewportInteractionItem::Terrain));
auto tileMapCoord = TileCoordsXY(info.Loc);
console.WriteFormatLine("location %d %d", tileMapCoord.x, tileMapCoord.y);
diff --git a/src/openrct2/interface/Viewport.cpp b/src/openrct2/interface/Viewport.cpp
index a250b66b40..83acf71165 100644
--- a/src/openrct2/interface/Viewport.cpp
+++ b/src/openrct2/interface/Viewport.cpp
@@ -50,1974 +50,1980 @@
#include
#include
-using namespace OpenRCT2;
-using namespace OpenRCT2::Numerics;
-
-enum : uint8_t
+namespace OpenRCT2
{
- IMAGE_TYPE_DEFAULT = 0,
- IMAGE_TYPE_REMAP = (1 << 1),
- IMAGE_TYPE_TRANSPARENT = (1 << 2),
-};
+ using namespace OpenRCT2::Numerics;
-uint8_t gShowGridLinesRefCount;
-uint8_t gShowLandRightsRefCount;
-uint8_t gShowConstructionRightsRefCount;
-
-static std::list _viewports;
-Viewport* g_music_tracking_viewport;
-
-static std::unique_ptr _paintJobs;
-static std::vector _paintColumns;
-
-InteractionInfo::InteractionInfo(const PaintStruct* ps)
- : Loc(ps->MapPos)
- , Element(ps->Element)
- , Entity(ps->Entity)
- , interactionType(ps->InteractionItem)
-{
-}
-
-static void ViewportPaintWeatherGloom(DrawPixelInfo& dpi);
-static void ViewportPaint(const Viewport* viewport, DrawPixelInfo& dpi);
-static void ViewportUpdateFollowSprite(WindowBase* window);
-static void ViewportUpdateSmartFollowEntity(WindowBase* window);
-static void ViewportUpdateSmartFollowStaff(WindowBase* window, const Staff& peep);
-static void ViewportUpdateSmartFollowVehicle(WindowBase* window);
-static void ViewportInvalidate(const Viewport* viewport, const ScreenRect& screenRect);
-
-/**
- * This is not a viewport function. It is used to setup many variables for
- * multiple things.
- * rct2: 0x006E6EAC
- */
-void ViewportInitAll()
-{
- if (!gOpenRCT2NoGraphics)
+ enum : uint8_t
+ {
+ IMAGE_TYPE_DEFAULT = 0,
+ IMAGE_TYPE_REMAP = (1 << 1),
+ IMAGE_TYPE_TRANSPARENT = (1 << 2),
+ };
+
+ uint8_t gShowGridLinesRefCount;
+ uint8_t gShowLandRightsRefCount;
+ uint8_t gShowConstructionRightsRefCount;
+
+ static std::list _viewports;
+ Viewport* g_music_tracking_viewport;
+
+ static std::unique_ptr _paintJobs;
+ static std::vector _paintColumns;
+
+ InteractionInfo::InteractionInfo(const PaintStruct* ps)
+ : Loc(ps->MapPos)
+ , Element(ps->Element)
+ , Entity(ps->Entity)
+ , interactionType(ps->InteractionItem)
{
- ColoursInitMaps();
}
- WindowInitAll();
+ static void ViewportPaintWeatherGloom(DrawPixelInfo& dpi);
+ static void ViewportPaint(const Viewport* viewport, DrawPixelInfo& dpi);
+ static void ViewportUpdateFollowSprite(WindowBase* window);
+ static void ViewportUpdateSmartFollowEntity(WindowBase* window);
+ static void ViewportUpdateSmartFollowStaff(WindowBase* window, const Staff& peep);
+ static void ViewportUpdateSmartFollowVehicle(WindowBase* window);
+ static void ViewportInvalidate(const Viewport* viewport, const ScreenRect& screenRect);
- // ?
- InputResetFlags();
- InputSetState(InputState::Reset);
- gPressedWidget.window_classification = WindowClass::Null;
- gPickupPeepImage = ImageId();
- ResetTooltipNotShown();
- gMapSelectFlags = 0;
- ClearPatrolAreaToRender();
- TextinputCancel();
-}
-
-/**
- * Converts between 3d point of a sprite to 2d coordinates for centring on that
- * sprite
- * rct2: 0x006EB0C1
- * x : ax
- * y : bx
- * z : cx
- * out_x : ax
- * out_y : bx
- */
-std::optional centre_2d_coordinates(const CoordsXYZ& loc, Viewport* viewport)
-{
- // If the start location was invalid
- // propagate the invalid location to the output.
- // This fixes a bug that caused the game to enter an infinite loop.
- if (loc.IsNull())
+ /**
+ * This is not a viewport function. It is used to setup many variables for
+ * multiple things.
+ * rct2: 0x006E6EAC
+ */
+ void ViewportInitAll()
{
- return std::nullopt;
+ if (!gOpenRCT2NoGraphics)
+ {
+ ColoursInitMaps();
+ }
+
+ WindowInitAll();
+
+ // ?
+ InputResetFlags();
+ InputSetState(InputState::Reset);
+ gPressedWidget.window_classification = WindowClass::Null;
+ gPickupPeepImage = ImageId();
+ ResetTooltipNotShown();
+ gMapSelectFlags = 0;
+ ClearPatrolAreaToRender();
+ TextinputCancel();
}
- auto screenCoord = Translate3DTo2DWithZ(viewport->rotation, loc);
- screenCoord.x -= viewport->ViewWidth() / 2;
- screenCoord.y -= viewport->ViewHeight() / 2;
- return { screenCoord };
-}
+ /**
+ * Converts between 3d point of a sprite to 2d coordinates for centring on that
+ * sprite
+ * rct2: 0x006EB0C1
+ * x : ax
+ * y : bx
+ * z : cx
+ * out_x : ax
+ * out_y : bx
+ */
+ std::optional centre_2d_coordinates(const CoordsXYZ& loc, Viewport* viewport)
+ {
+ // If the start location was invalid
+ // propagate the invalid location to the output.
+ // This fixes a bug that caused the game to enter an infinite loop.
+ if (loc.IsNull())
+ {
+ return std::nullopt;
+ }
-CoordsXYZ Focus::GetPos() const
-{
- return std::visit(
- [](auto&& arg) {
- using T = std::decay_t;
- if constexpr (std::is_same_v)
- return arg;
- else if constexpr (std::is_same_v)
- {
- auto* centreEntity = GetEntity(arg);
- if (centreEntity != nullptr)
+ auto screenCoord = Translate3DTo2DWithZ(viewport->rotation, loc);
+ screenCoord.x -= viewport->ViewWidth() / 2;
+ screenCoord.y -= viewport->ViewHeight() / 2;
+ return { screenCoord };
+ }
+
+ CoordsXYZ Focus::GetPos() const
+ {
+ return std::visit(
+ [](auto&& arg) {
+ using T = std::decay_t;
+ if constexpr (std::is_same_v)
+ return arg;
+ else if constexpr (std::is_same_v)
{
- return CoordsXYZ{ centreEntity->x, centreEntity->y, centreEntity->z };
+ auto* centreEntity = GetEntity(arg);
+ if (centreEntity != nullptr)
+ {
+ return CoordsXYZ{ centreEntity->x, centreEntity->y, centreEntity->z };
+ }
+ else
+ {
+ LOG_ERROR("Invalid entity for focus.");
+ return CoordsXYZ{};
+ }
}
- else
- {
- LOG_ERROR("Invalid entity for focus.");
- return CoordsXYZ{};
- }
- }
- },
- data);
-}
-
-/**
- * Viewport will look at sprite or at coordinates as specified in flags 0b_1X
- * for sprite 0b_0X for coordinates
- *
- * rct2: 0x006EB009
- * x: ax
- * y: eax (top 16)
- * width: bx
- * height: ebx (top 16)
- * zoom: cl (8 bits)
- * centre_x: edx lower 16 bits
- * centre_y: edx upper 16 bits
- * centre_z: ecx upper 16 bits
- * sprite: edx lower 16 bits
- * flags: edx top most 2 bits 0b_X1 for zoom clear see below for 2nd bit.
- * w: esi
- */
-void ViewportCreate(WindowBase* w, const ScreenCoordsXY& screenCoords, int32_t width, int32_t height, const Focus& focus)
-{
- Viewport* viewport = nullptr;
- if (_viewports.size() >= kMaxViewportCount)
- {
- LOG_ERROR("No more viewport slots left to allocate.");
- return;
+ },
+ data);
}
- auto itViewport = _viewports.insert(_viewports.end(), Viewport{});
-
- viewport = &*itViewport;
- viewport->pos = screenCoords;
- viewport->width = width;
- viewport->height = height;
-
- const auto zoom = focus.zoom;
- viewport->zoom = zoom;
- viewport->flags = 0;
- viewport->rotation = GetCurrentRotation();
-
- if (Config::Get().general.AlwaysShowGridlines)
- viewport->flags |= VIEWPORT_FLAG_GRIDLINES;
- w->viewport = viewport;
-
- CoordsXYZ centrePos = focus.GetPos();
- w->viewport_target_sprite = std::visit(
- [](auto&& arg) {
- using T = std::decay_t;
- if constexpr (std::is_same_v)
- return EntityId::GetNull();
- else if constexpr (std::is_same_v)
- return arg;
- },
- focus.data);
-
- auto centreLoc = centre_2d_coordinates(centrePos, viewport);
- if (!centreLoc.has_value())
+ /**
+ * Viewport will look at sprite or at coordinates as specified in flags 0b_1X
+ * for sprite 0b_0X for coordinates
+ *
+ * rct2: 0x006EB009
+ * x: ax
+ * y: eax (top 16)
+ * width: bx
+ * height: ebx (top 16)
+ * zoom: cl (8 bits)
+ * centre_x: edx lower 16 bits
+ * centre_y: edx upper 16 bits
+ * centre_z: ecx upper 16 bits
+ * sprite: edx lower 16 bits
+ * flags: edx top most 2 bits 0b_X1 for zoom clear see below for 2nd bit.
+ * w: esi
+ */
+ void ViewportCreate(WindowBase* w, const ScreenCoordsXY& screenCoords, int32_t width, int32_t height, const Focus& focus)
{
- LOG_ERROR("Invalid location for viewport.");
- return;
- }
- w->savedViewPos = *centreLoc;
- viewport->viewPos = *centreLoc;
-}
-
-void ViewportRemove(Viewport* viewport)
-{
- auto it = std::find_if(_viewports.begin(), _viewports.end(), [viewport](const auto& vp) { return &vp == viewport; });
- if (it == _viewports.end())
- {
- LOG_ERROR("Unable to remove viewport: %p", viewport);
- return;
- }
- _viewports.erase(it);
-}
-
-static Viewport* ViewportGetMain()
-{
- auto mainWindow = WindowGetMain();
- if (mainWindow == nullptr)
- {
- return nullptr;
- }
- return mainWindow->viewport;
-}
-
-void ViewportsInvalidate(int32_t x, int32_t y, int32_t z0, int32_t z1, ZoomLevel maxZoom)
-{
- for (auto& vp : _viewports)
- {
- if (maxZoom == ZoomLevel{ -1 } || vp.zoom <= ZoomLevel{ maxZoom })
+ Viewport* viewport = nullptr;
+ if (_viewports.size() >= kMaxViewportCount)
{
- int32_t x1, y1, x2, y2;
-
- x += 16;
- y += 16;
- auto screenCoord = Translate3DTo2DWithZ(vp.rotation, CoordsXYZ{ x, y, 0 });
-
- x1 = screenCoord.x - 32;
- y1 = screenCoord.y - 32 - z1;
- x2 = screenCoord.x + 32;
- y2 = screenCoord.y + 32 - z0;
-
- ViewportInvalidate(&vp, ScreenRect{ { x1, y1 }, { x2, y2 } });
- }
- }
-}
-
-void ViewportsInvalidate(const CoordsXYZ& pos, int32_t width, int32_t minHeight, int32_t maxHeight, ZoomLevel maxZoom)
-{
- for (auto& vp : _viewports)
- {
- if (maxZoom == ZoomLevel{ -1 } || vp.zoom <= ZoomLevel{ maxZoom })
- {
- auto screenCoords = Translate3DTo2DWithZ(vp.rotation, pos);
- auto screenPos = ScreenRect(
- screenCoords - ScreenCoordsXY{ width, minHeight }, screenCoords + ScreenCoordsXY{ width, maxHeight });
-
- ViewportInvalidate(&vp, screenPos);
- }
- }
-}
-
-void ViewportsInvalidate(const ScreenRect& screenRect, ZoomLevel maxZoom)
-{
- for (auto& vp : _viewports)
- {
- if (maxZoom == ZoomLevel{ -1 } || vp.zoom <= ZoomLevel{ maxZoom })
- {
- ViewportInvalidate(&vp, screenRect);
- }
- }
-}
-
-/**
- *
- * rct2: 0x00689174
- * edx is assumed to be (and always is) the current rotation, so it is not
- * needed as parameter.
- */
-CoordsXYZ ViewportAdjustForMapHeight(const ScreenCoordsXY& startCoords, uint8_t rotation)
-{
- int32_t height = 0;
-
- CoordsXY pos{};
- for (int32_t i = 0; i < 6; i++)
- {
- pos = ViewportPosToMapPos(startCoords, height, rotation);
- height = TileElementHeight(pos);
-
- // HACK: This is to prevent the x and y values being set to values outside
- // of the map. This can happen when the height is larger than the map size.
- auto mapSizeMinus2 = GetMapSizeMinus2();
- if (pos.x > mapSizeMinus2.x && pos.y > mapSizeMinus2.y)
- {
- static constexpr CoordsXY corr[] = {
- { -1, -1 },
- { 1, -1 },
- { 1, 1 },
- { -1, 1 },
- };
- pos.x += corr[rotation].x * height;
- pos.y += corr[rotation].y * height;
- }
- }
-
- return { pos, height };
-}
-
-/*
- * rct2: 0x006E7FF3
- */
-static void ViewportRedrawAfterShift(
- DrawPixelInfo& dpi, WindowBase* window, const WindowBase* originalWindow, const ScreenCoordsXY shift,
- const ScreenRect& drawRect)
-{
- // sub-divide by intersecting windows
- if (window != nullptr)
- {
- // skip current window and non-intersecting windows
- if (window == originalWindow || drawRect.GetRight() <= window->windowPos.x
- || drawRect.GetLeft() >= window->windowPos.x + window->width || drawRect.GetBottom() <= window->windowPos.y
- || drawRect.GetTop() >= window->windowPos.y + window->height)
- {
- auto itWindowPos = WindowGetIterator(window);
- auto itNextWindow = itWindowPos != g_window_list.end() ? std::next(itWindowPos) : g_window_list.end();
- ViewportRedrawAfterShift(
- dpi, itNextWindow == g_window_list.end() ? nullptr : itNextWindow->get(), originalWindow, shift, drawRect);
+ LOG_ERROR("No more viewport slots left to allocate.");
return;
}
- if (drawRect.GetLeft() < window->windowPos.x)
- {
- ScreenRect leftRect = { drawRect.Point1, { window->windowPos.x, drawRect.GetBottom() } };
- ViewportRedrawAfterShift(dpi, window, originalWindow, shift, leftRect);
+ auto itViewport = _viewports.insert(_viewports.end(), Viewport{});
- ScreenRect rightRect = { { window->windowPos.x, drawRect.GetTop() }, drawRect.Point2 };
- ViewportRedrawAfterShift(dpi, window, originalWindow, shift, rightRect);
+ viewport = &*itViewport;
+ viewport->pos = screenCoords;
+ viewport->width = width;
+ viewport->height = height;
+
+ const auto zoom = focus.zoom;
+ viewport->zoom = zoom;
+ viewport->flags = 0;
+ viewport->rotation = GetCurrentRotation();
+
+ if (Config::Get().general.AlwaysShowGridlines)
+ viewport->flags |= VIEWPORT_FLAG_GRIDLINES;
+ w->viewport = viewport;
+
+ CoordsXYZ centrePos = focus.GetPos();
+ w->viewport_target_sprite = std::visit(
+ [](auto&& arg) {
+ using T = std::decay_t;
+ if constexpr (std::is_same_v)
+ return EntityId::GetNull();
+ else if constexpr (std::is_same_v)
+ return arg;
+ },
+ focus.data);
+
+ auto centreLoc = centre_2d_coordinates(centrePos, viewport);
+ if (!centreLoc.has_value())
+ {
+ LOG_ERROR("Invalid location for viewport.");
+ return;
}
- else if (drawRect.GetRight() > window->windowPos.x + window->width)
- {
- ScreenRect leftRect = { drawRect.Point1, { window->windowPos.x + window->width, drawRect.GetBottom() } };
- ViewportRedrawAfterShift(dpi, window, originalWindow, shift, leftRect);
+ w->savedViewPos = *centreLoc;
+ viewport->viewPos = *centreLoc;
+ }
- ScreenRect rightRect = { { window->windowPos.x + window->width, drawRect.GetTop() }, drawRect.Point2 };
- ViewportRedrawAfterShift(dpi, window, originalWindow, shift, rightRect);
+ void ViewportRemove(Viewport* viewport)
+ {
+ auto it = std::find_if(_viewports.begin(), _viewports.end(), [viewport](const auto& vp) { return &vp == viewport; });
+ if (it == _viewports.end())
+ {
+ LOG_ERROR("Unable to remove viewport: %p", viewport);
+ return;
}
- else if (drawRect.GetTop() < window->windowPos.y)
- {
- ScreenRect topRect = { drawRect.Point1, { drawRect.GetRight(), window->windowPos.y } };
- ViewportRedrawAfterShift(dpi, window, originalWindow, shift, topRect);
+ _viewports.erase(it);
+ }
- ScreenRect bottomRect = { { drawRect.GetLeft(), window->windowPos.y }, drawRect.Point2 };
- ViewportRedrawAfterShift(dpi, window, originalWindow, shift, bottomRect);
+ static Viewport* ViewportGetMain()
+ {
+ auto mainWindow = WindowGetMain();
+ if (mainWindow == nullptr)
+ {
+ return nullptr;
}
- else if (drawRect.GetBottom() > window->windowPos.y + window->height)
- {
- ScreenRect topRect = { drawRect.Point1, { drawRect.GetRight(), window->windowPos.y + window->height } };
- ViewportRedrawAfterShift(dpi, window, originalWindow, shift, topRect);
+ return mainWindow->viewport;
+ }
- ScreenRect bottomRect = { { drawRect.GetLeft(), window->windowPos.y + window->height }, drawRect.Point2 };
- ViewportRedrawAfterShift(dpi, window, originalWindow, shift, bottomRect);
+ void ViewportsInvalidate(int32_t x, int32_t y, int32_t z0, int32_t z1, ZoomLevel maxZoom)
+ {
+ for (auto& vp : _viewports)
+ {
+ if (maxZoom == ZoomLevel{ -1 } || vp.zoom <= ZoomLevel{ maxZoom })
+ {
+ int32_t x1, y1, x2, y2;
+
+ x += 16;
+ y += 16;
+ auto screenCoord = Translate3DTo2DWithZ(vp.rotation, CoordsXYZ{ x, y, 0 });
+
+ x1 = screenCoord.x - 32;
+ y1 = screenCoord.y - 32 - z1;
+ x2 = screenCoord.x + 32;
+ y2 = screenCoord.y + 32 - z0;
+
+ ViewportInvalidate(&vp, ScreenRect{ { x1, y1 }, { x2, y2 } });
+ }
}
}
- else
+
+ void ViewportsInvalidate(const CoordsXYZ& pos, int32_t width, int32_t minHeight, int32_t maxHeight, ZoomLevel maxZoom)
{
- auto left = drawRect.GetLeft();
- auto right = drawRect.GetRight();
- auto top = drawRect.GetTop();
- auto bottom = drawRect.GetBottom();
-
- // if moved more than the draw rectangle size
- if (abs(shift.x) < drawRect.GetWidth() && abs(shift.y) < drawRect.GetHeight())
+ for (auto& vp : _viewports)
{
- // update whole block ?
- DrawingEngineCopyRect(
- drawRect.GetLeft(), drawRect.GetTop(), drawRect.GetWidth(), drawRect.GetHeight(), shift.x, shift.y);
+ if (maxZoom == ZoomLevel{ -1 } || vp.zoom <= ZoomLevel{ maxZoom })
+ {
+ auto screenCoords = Translate3DTo2DWithZ(vp.rotation, pos);
+ auto screenPos = ScreenRect(
+ screenCoords - ScreenCoordsXY{ width, minHeight }, screenCoords + ScreenCoordsXY{ width, maxHeight });
- if (shift.x > 0)
- {
- // draw left
- auto _right = left + shift.x;
- WindowDrawAll(dpi, left, top, _right, bottom);
- left += shift.x;
+ ViewportInvalidate(&vp, screenPos);
}
- else if (shift.x < 0)
+ }
+ }
+
+ void ViewportsInvalidate(const ScreenRect& screenRect, ZoomLevel maxZoom)
+ {
+ for (auto& vp : _viewports)
+ {
+ if (maxZoom == ZoomLevel{ -1 } || vp.zoom <= ZoomLevel{ maxZoom })
{
- // draw right
- auto _left = right + shift.x;
- WindowDrawAll(dpi, _left, top, right, bottom);
- right += shift.x;
+ ViewportInvalidate(&vp, screenRect);
+ }
+ }
+ }
+
+ /**
+ *
+ * rct2: 0x00689174
+ * edx is assumed to be (and always is) the current rotation, so it is not
+ * needed as parameter.
+ */
+ CoordsXYZ ViewportAdjustForMapHeight(const ScreenCoordsXY& startCoords, uint8_t rotation)
+ {
+ int32_t height = 0;
+
+ CoordsXY pos{};
+ for (int32_t i = 0; i < 6; i++)
+ {
+ pos = ViewportPosToMapPos(startCoords, height, rotation);
+ height = TileElementHeight(pos);
+
+ // HACK: This is to prevent the x and y values being set to values outside
+ // of the map. This can happen when the height is larger than the map size.
+ auto mapSizeMinus2 = GetMapSizeMinus2();
+ if (pos.x > mapSizeMinus2.x && pos.y > mapSizeMinus2.y)
+ {
+ static constexpr CoordsXY corr[] = {
+ { -1, -1 },
+ { 1, -1 },
+ { 1, 1 },
+ { -1, 1 },
+ };
+ pos.x += corr[rotation].x * height;
+ pos.y += corr[rotation].y * height;
+ }
+ }
+
+ return { pos, height };
+ }
+
+ /*
+ * rct2: 0x006E7FF3
+ */
+ static void ViewportRedrawAfterShift(
+ DrawPixelInfo& dpi, WindowBase* window, const WindowBase* originalWindow, const ScreenCoordsXY shift,
+ const ScreenRect& drawRect)
+ {
+ // sub-divide by intersecting windows
+ if (window != nullptr)
+ {
+ // skip current window and non-intersecting windows
+ if (window == originalWindow || drawRect.GetRight() <= window->windowPos.x
+ || drawRect.GetLeft() >= window->windowPos.x + window->width || drawRect.GetBottom() <= window->windowPos.y
+ || drawRect.GetTop() >= window->windowPos.y + window->height)
+ {
+ auto itWindowPos = WindowGetIterator(window);
+ auto itNextWindow = itWindowPos != g_window_list.end() ? std::next(itWindowPos) : g_window_list.end();
+ ViewportRedrawAfterShift(
+ dpi, itNextWindow == g_window_list.end() ? nullptr : itNextWindow->get(), originalWindow, shift, drawRect);
+ return;
}
- if (shift.y > 0)
+ if (drawRect.GetLeft() < window->windowPos.x)
{
- // draw top
- bottom = top + shift.y;
- WindowDrawAll(dpi, left, top, right, bottom);
+ ScreenRect leftRect = { drawRect.Point1, { window->windowPos.x, drawRect.GetBottom() } };
+ ViewportRedrawAfterShift(dpi, window, originalWindow, shift, leftRect);
+
+ ScreenRect rightRect = { { window->windowPos.x, drawRect.GetTop() }, drawRect.Point2 };
+ ViewportRedrawAfterShift(dpi, window, originalWindow, shift, rightRect);
}
- else if (shift.y < 0)
+ else if (drawRect.GetRight() > window->windowPos.x + window->width)
{
- // draw bottom
- top = bottom + shift.y;
- WindowDrawAll(dpi, left, top, right, bottom);
+ ScreenRect leftRect = { drawRect.Point1, { window->windowPos.x + window->width, drawRect.GetBottom() } };
+ ViewportRedrawAfterShift(dpi, window, originalWindow, shift, leftRect);
+
+ ScreenRect rightRect = { { window->windowPos.x + window->width, drawRect.GetTop() }, drawRect.Point2 };
+ ViewportRedrawAfterShift(dpi, window, originalWindow, shift, rightRect);
+ }
+ else if (drawRect.GetTop() < window->windowPos.y)
+ {
+ ScreenRect topRect = { drawRect.Point1, { drawRect.GetRight(), window->windowPos.y } };
+ ViewportRedrawAfterShift(dpi, window, originalWindow, shift, topRect);
+
+ ScreenRect bottomRect = { { drawRect.GetLeft(), window->windowPos.y }, drawRect.Point2 };
+ ViewportRedrawAfterShift(dpi, window, originalWindow, shift, bottomRect);
+ }
+ else if (drawRect.GetBottom() > window->windowPos.y + window->height)
+ {
+ ScreenRect topRect = { drawRect.Point1, { drawRect.GetRight(), window->windowPos.y + window->height } };
+ ViewportRedrawAfterShift(dpi, window, originalWindow, shift, topRect);
+
+ ScreenRect bottomRect = { { drawRect.GetLeft(), window->windowPos.y + window->height }, drawRect.Point2 };
+ ViewportRedrawAfterShift(dpi, window, originalWindow, shift, bottomRect);
}
}
else
{
- // redraw whole draw rectangle
- WindowDrawAll(dpi, left, top, right, bottom);
+ auto left = drawRect.GetLeft();
+ auto right = drawRect.GetRight();
+ auto top = drawRect.GetTop();
+ auto bottom = drawRect.GetBottom();
+
+ // if moved more than the draw rectangle size
+ if (abs(shift.x) < drawRect.GetWidth() && abs(shift.y) < drawRect.GetHeight())
+ {
+ // update whole block ?
+ DrawingEngineCopyRect(
+ drawRect.GetLeft(), drawRect.GetTop(), drawRect.GetWidth(), drawRect.GetHeight(), shift.x, shift.y);
+
+ if (shift.x > 0)
+ {
+ // draw left
+ auto _right = left + shift.x;
+ WindowDrawAll(dpi, left, top, _right, bottom);
+ left += shift.x;
+ }
+ else if (shift.x < 0)
+ {
+ // draw right
+ auto _left = right + shift.x;
+ WindowDrawAll(dpi, _left, top, right, bottom);
+ right += shift.x;
+ }
+
+ if (shift.y > 0)
+ {
+ // draw top
+ bottom = top + shift.y;
+ WindowDrawAll(dpi, left, top, right, bottom);
+ }
+ else if (shift.y < 0)
+ {
+ // draw bottom
+ top = bottom + shift.y;
+ WindowDrawAll(dpi, left, top, right, bottom);
+ }
+ }
+ else
+ {
+ // redraw whole draw rectangle
+ WindowDrawAll(dpi, left, top, right, bottom);
+ }
}
}
-}
-static void ViewportShiftPixels(DrawPixelInfo& dpi, WindowBase* window, Viewport* viewport, int32_t x_diff, int32_t y_diff)
-{
- // This loop redraws all parts covered by transparent windows.
- auto it = WindowGetIterator(window);
- for (; it != g_window_list.end(); it++)
+ static void ViewportShiftPixels(DrawPixelInfo& dpi, WindowBase* window, Viewport* viewport, int32_t x_diff, int32_t y_diff)
{
- auto w = it->get();
- if (!(w->flags & WF_TRANSPARENT))
- continue;
- if (w->viewport == viewport)
- continue;
+ // This loop redraws all parts covered by transparent windows.
+ auto it = WindowGetIterator(window);
+ for (; it != g_window_list.end(); it++)
+ {
+ auto w = it->get();
+ if (!(w->flags & WF_TRANSPARENT))
+ continue;
+ if (w->viewport == viewport)
+ continue;
- if (viewport->pos.x + viewport->width <= w->windowPos.x)
- continue;
- if (w->windowPos.x + w->width <= viewport->pos.x)
- continue;
+ if (viewport->pos.x + viewport->width <= w->windowPos.x)
+ continue;
+ if (w->windowPos.x + w->width <= viewport->pos.x)
+ continue;
- if (viewport->pos.y + viewport->height <= w->windowPos.y)
- continue;
- if (w->windowPos.y + w->height <= viewport->pos.y)
- continue;
+ if (viewport->pos.y + viewport->height <= w->windowPos.y)
+ continue;
+ if (w->windowPos.y + w->height <= viewport->pos.y)
+ continue;
- auto left = w->windowPos.x;
- auto right = w->windowPos.x + w->width;
- auto top = w->windowPos.y;
- auto bottom = w->windowPos.y + w->height;
+ auto left = w->windowPos.x;
+ auto right = w->windowPos.x + w->width;
+ auto top = w->windowPos.y;
+ auto bottom = w->windowPos.y + w->height;
- if (left < viewport->pos.x)
- left = viewport->pos.x;
- if (right > viewport->pos.x + viewport->width)
- right = viewport->pos.x + viewport->width;
+ if (left < viewport->pos.x)
+ left = viewport->pos.x;
+ if (right > viewport->pos.x + viewport->width)
+ right = viewport->pos.x + viewport->width;
- if (top < viewport->pos.y)
- top = viewport->pos.y;
- if (bottom > viewport->pos.y + viewport->height)
- bottom = viewport->pos.y + viewport->height;
+ if (top < viewport->pos.y)
+ top = viewport->pos.y;
+ if (bottom > viewport->pos.y + viewport->height)
+ bottom = viewport->pos.y + viewport->height;
- if (left >= right)
- continue;
- if (top >= bottom)
- continue;
+ if (left >= right)
+ continue;
+ if (top >= bottom)
+ continue;
- WindowDrawAll(dpi, left, top, right, bottom);
+ WindowDrawAll(dpi, left, top, right, bottom);
+ }
+
+ ViewportRedrawAfterShift(
+ dpi, window, window, { x_diff, y_diff },
+ { viewport->pos, { viewport->pos.x + viewport->width, viewport->pos.y + viewport->height } });
}
- ViewportRedrawAfterShift(
- dpi, window, window, { x_diff, y_diff },
- { viewport->pos, { viewport->pos.x + viewport->width, viewport->pos.y + viewport->height } });
-}
-
-static void ViewportMove(const ScreenCoordsXY& coords, WindowBase* w, Viewport* viewport)
-{
- auto zoom = viewport->zoom;
-
- // Note: do not do the subtraction and then divide!
- // Note: Due to arithmetic shift != /zoom a shift will have to be used
- // hopefully when 0x006E7FF3 is finished this can be converted to /zoom.
- auto x_diff = viewport->zoom.ApplyInversedTo(viewport->viewPos.x) - viewport->zoom.ApplyInversedTo(coords.x);
- auto y_diff = viewport->zoom.ApplyInversedTo(viewport->viewPos.y) - viewport->zoom.ApplyInversedTo(coords.y);
-
- viewport->viewPos = coords;
-
- // If no change in viewing area
- if ((!x_diff) && (!y_diff))
- return;
-
- if (w->flags & WF_7)
+ static void ViewportMove(const ScreenCoordsXY& coords, WindowBase* w, Viewport* viewport)
{
- int32_t left = std::max(viewport->pos.x, 0);
- int32_t top = std::max(viewport->pos.y, 0);
- int32_t right = std::min(viewport->pos.x + viewport->width, ContextGetWidth());
- int32_t bottom = std::min(viewport->pos.y + viewport->height, ContextGetHeight());
+ auto zoom = viewport->zoom;
- if (left >= right)
+ // Note: do not do the subtraction and then divide!
+ // Note: Due to arithmetic shift != /zoom a shift will have to be used
+ // hopefully when 0x006E7FF3 is finished this can be converted to /zoom.
+ auto x_diff = viewport->zoom.ApplyInversedTo(viewport->viewPos.x) - viewport->zoom.ApplyInversedTo(coords.x);
+ auto y_diff = viewport->zoom.ApplyInversedTo(viewport->viewPos.y) - viewport->zoom.ApplyInversedTo(coords.y);
+
+ viewport->viewPos = coords;
+
+ // If no change in viewing area
+ if ((!x_diff) && (!y_diff))
return;
- if (top >= bottom)
+
+ if (w->flags & WF_7)
+ {
+ int32_t left = std::max(viewport->pos.x, 0);
+ int32_t top = std::max(viewport->pos.y, 0);
+ int32_t right = std::min(viewport->pos.x + viewport->width, ContextGetWidth());
+ int32_t bottom = std::min(viewport->pos.y + viewport->height, ContextGetHeight());
+
+ if (left >= right)
+ return;
+ if (top >= bottom)
+ return;
+
+ if (DrawingEngineHasDirtyOptimisations())
+ {
+ DrawPixelInfo& dpi = DrawingEngineGetDpi();
+ WindowDrawAll(dpi, left, top, right, bottom);
+ return;
+ }
+ }
+
+ Viewport view_copy = *viewport;
+
+ if (viewport->pos.x < 0)
+ {
+ viewport->width += viewport->pos.x;
+ viewport->viewPos.x -= zoom.ApplyTo(viewport->pos.x);
+ viewport->pos.x = 0;
+ }
+
+ int32_t eax = viewport->pos.x + viewport->width - ContextGetWidth();
+ if (eax > 0)
+ {
+ viewport->width -= eax;
+ }
+
+ if (viewport->width <= 0)
+ {
+ *viewport = view_copy;
return;
+ }
+
+ if (viewport->pos.y < 0)
+ {
+ viewport->height += viewport->pos.y;
+ viewport->viewPos.y -= zoom.ApplyTo(viewport->pos.y);
+ viewport->pos.y = 0;
+ }
+
+ eax = viewport->pos.y + viewport->height - ContextGetHeight();
+ if (eax > 0)
+ {
+ viewport->height -= eax;
+ }
+
+ if (viewport->height <= 0)
+ {
+ *viewport = view_copy;
+ return;
+ }
if (DrawingEngineHasDirtyOptimisations())
{
DrawPixelInfo& dpi = DrawingEngineGetDpi();
- WindowDrawAll(dpi, left, top, right, bottom);
+ ViewportShiftPixels(dpi, w, viewport, x_diff, y_diff);
+ }
+
+ *viewport = view_copy;
+ }
+
+ // rct2: 0x006E7A15
+ static void ViewportSetUndergroundFlag(int32_t underground, WindowBase* window, Viewport* viewport)
+ {
+ if (window->classification != WindowClass::MainWindow
+ || (window->classification == WindowClass::MainWindow && !window->viewport_smart_follow_sprite.IsNull()))
+ {
+ if (!underground)
+ {
+ int32_t bit = viewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE;
+ viewport->flags &= ~VIEWPORT_FLAG_UNDERGROUND_INSIDE;
+ if (!bit)
+ return;
+ }
+ else
+ {
+ int32_t bit = viewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE;
+ viewport->flags |= VIEWPORT_FLAG_UNDERGROUND_INSIDE;
+ if (bit)
+ return;
+ }
+ window->Invalidate();
+ }
+ }
+
+ /**
+ *
+ * rct2: 0x006E7A3A
+ */
+ void ViewportUpdatePosition(WindowBase* window)
+ {
+ window->OnResize();
+
+ Viewport* viewport = window->viewport;
+ if (viewport == nullptr)
return;
- }
- }
- Viewport view_copy = *viewport;
-
- if (viewport->pos.x < 0)
- {
- viewport->width += viewport->pos.x;
- viewport->viewPos.x -= zoom.ApplyTo(viewport->pos.x);
- viewport->pos.x = 0;
- }
-
- int32_t eax = viewport->pos.x + viewport->width - ContextGetWidth();
- if (eax > 0)
- {
- viewport->width -= eax;
- }
-
- if (viewport->width <= 0)
- {
- *viewport = view_copy;
- return;
- }
-
- if (viewport->pos.y < 0)
- {
- viewport->height += viewport->pos.y;
- viewport->viewPos.y -= zoom.ApplyTo(viewport->pos.y);
- viewport->pos.y = 0;
- }
-
- eax = viewport->pos.y + viewport->height - ContextGetHeight();
- if (eax > 0)
- {
- viewport->height -= eax;
- }
-
- if (viewport->height <= 0)
- {
- *viewport = view_copy;
- return;
- }
-
- if (DrawingEngineHasDirtyOptimisations())
- {
- DrawPixelInfo& dpi = DrawingEngineGetDpi();
- ViewportShiftPixels(dpi, w, viewport, x_diff, y_diff);
- }
-
- *viewport = view_copy;
-}
-
-// rct2: 0x006E7A15
-static void ViewportSetUndergroundFlag(int32_t underground, WindowBase* window, Viewport* viewport)
-{
- if (window->classification != WindowClass::MainWindow
- || (window->classification == WindowClass::MainWindow && !window->viewport_smart_follow_sprite.IsNull()))
- {
- if (!underground)
+ if (!window->viewport_smart_follow_sprite.IsNull())
{
- int32_t bit = viewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE;
- viewport->flags &= ~VIEWPORT_FLAG_UNDERGROUND_INSIDE;
- if (!bit)
- return;
+ ViewportUpdateSmartFollowEntity(window);
}
- else
- {
- int32_t bit = viewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE;
- viewport->flags |= VIEWPORT_FLAG_UNDERGROUND_INSIDE;
- if (bit)
- return;
- }
- window->Invalidate();
- }
-}
-
-/**
- *
- * rct2: 0x006E7A3A
- */
-void ViewportUpdatePosition(WindowBase* window)
-{
- window->OnResize();
-
- Viewport* viewport = window->viewport;
- if (viewport == nullptr)
- return;
-
- if (!window->viewport_smart_follow_sprite.IsNull())
- {
- ViewportUpdateSmartFollowEntity(window);
- }
-
- if (!window->viewport_target_sprite.IsNull())
- {
- ViewportUpdateFollowSprite(window);
- return;
- }
-
- ViewportSetUndergroundFlag(0, window, viewport);
-
- auto viewportMidPoint = ScreenCoordsXY{ window->savedViewPos.x + viewport->ViewWidth() / 2,
- window->savedViewPos.y + viewport->ViewHeight() / 2 };
-
- auto mapCoord = ViewportPosToMapPos(viewportMidPoint, 0, viewport->rotation);
-
- // Clamp to the map minimum value
- int32_t at_map_edge = 0;
- if (mapCoord.x < kMapMinimumXY)
- {
- mapCoord.x = kMapMinimumXY;
- at_map_edge = 1;
- }
- if (mapCoord.y < kMapMinimumXY)
- {
- mapCoord.y = kMapMinimumXY;
- at_map_edge = 1;
- }
-
- // Clamp to the map maximum value (scenario specific)
- auto mapSizeMinus2 = GetMapSizeMinus2();
- if (mapCoord.x > mapSizeMinus2.x)
- {
- mapCoord.x = mapSizeMinus2.x;
- at_map_edge = 1;
- }
- if (mapCoord.y > mapSizeMinus2.y)
- {
- mapCoord.y = mapSizeMinus2.y;
- at_map_edge = 1;
- }
-
- if (at_map_edge)
- {
- auto centreLoc = centre_2d_coordinates({ mapCoord, 0 }, viewport);
- if (centreLoc.has_value())
- {
- window->savedViewPos = centreLoc.value();
- }
- }
-
- auto windowCoords = window->savedViewPos;
- if (window->flags & WF_SCROLLING_TO_LOCATION)
- {
- // Moves the viewport if focusing in on an item
- uint8_t flags = 0;
- windowCoords.x -= viewport->viewPos.x;
- if (windowCoords.x < 0)
- {
- windowCoords.x = -windowCoords.x;
- flags |= 1;
- }
- windowCoords.y -= viewport->viewPos.y;
- if (windowCoords.y < 0)
- {
- windowCoords.y = -windowCoords.y;
- flags |= 2;
- }
- windowCoords.x = (windowCoords.x + 7) / 8;
- windowCoords.y = (windowCoords.y + 7) / 8;
-
- // If we are at the final zoom position
- if (!windowCoords.x && !windowCoords.y)
- {
- window->flags &= ~WF_SCROLLING_TO_LOCATION;
- }
- if (flags & 1)
- {
- windowCoords.x = -windowCoords.x;
- }
- if (flags & 2)
- {
- windowCoords.y = -windowCoords.y;
- }
- windowCoords.x += viewport->viewPos.x;
- windowCoords.y += viewport->viewPos.y;
- }
-
- ViewportMove(windowCoords, window, viewport);
-}
-
-void ViewportUpdateFollowSprite(WindowBase* window)
-{
- if (!window->viewport_target_sprite.IsNull() && window->viewport != nullptr)
- {
- auto* sprite = GetEntity(window->viewport_target_sprite);
- if (sprite == nullptr)
+
+ if (!window->viewport_target_sprite.IsNull())
{
+ ViewportUpdateFollowSprite(window);
return;
}
- if (!(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO))
+ ViewportSetUndergroundFlag(0, window, viewport);
+
+ auto viewportMidPoint = ScreenCoordsXY{ window->savedViewPos.x + viewport->ViewWidth() / 2,
+ window->savedViewPos.y + viewport->ViewHeight() / 2 };
+
+ auto mapCoord = ViewportPosToMapPos(viewportMidPoint, 0, viewport->rotation);
+
+ // Clamp to the map minimum value
+ int32_t at_map_edge = 0;
+ if (mapCoord.x < kMapMinimumXY)
{
- int32_t height = (TileElementHeight({ sprite->x, sprite->y }))-16;
- int32_t underground = sprite->z < height;
- ViewportSetUndergroundFlag(underground, window, window->viewport);
+ mapCoord.x = kMapMinimumXY;
+ at_map_edge = 1;
+ }
+ if (mapCoord.y < kMapMinimumXY)
+ {
+ mapCoord.y = kMapMinimumXY;
+ at_map_edge = 1;
}
- auto centreLoc = centre_2d_coordinates(sprite->GetLocation(), window->viewport);
- if (centreLoc.has_value())
+ // Clamp to the map maximum value (scenario specific)
+ auto mapSizeMinus2 = GetMapSizeMinus2();
+ if (mapCoord.x > mapSizeMinus2.x)
{
- window->savedViewPos = *centreLoc;
- ViewportMove(*centreLoc, window, window->viewport);
+ mapCoord.x = mapSizeMinus2.x;
+ at_map_edge = 1;
}
- }
-}
-
-void ViewportUpdateSmartFollowEntity(WindowBase* window)
-{
- auto entity = TryGetEntity(window->viewport_smart_follow_sprite);
- if (entity == nullptr || entity->Type == EntityType::Null)
- {
- window->viewport_smart_follow_sprite = EntityId::GetNull();
- window->viewport_target_sprite = EntityId::GetNull();
- return;
- }
-
- switch (entity->Type)
- {
- case EntityType::Vehicle:
- ViewportUpdateSmartFollowVehicle(window);
- break;
-
- case EntityType::Guest:
+ if (mapCoord.y > mapSizeMinus2.y)
{
- auto* guest = entity->As();
- if (guest == nullptr)
+ mapCoord.y = mapSizeMinus2.y;
+ at_map_edge = 1;
+ }
+
+ if (at_map_edge)
+ {
+ auto centreLoc = centre_2d_coordinates({ mapCoord, 0 }, viewport);
+ if (centreLoc.has_value())
+ {
+ window->savedViewPos = centreLoc.value();
+ }
+ }
+
+ auto windowCoords = window->savedViewPos;
+ if (window->flags & WF_SCROLLING_TO_LOCATION)
+ {
+ // Moves the viewport if focusing in on an item
+ uint8_t flags = 0;
+ windowCoords.x -= viewport->viewPos.x;
+ if (windowCoords.x < 0)
+ {
+ windowCoords.x = -windowCoords.x;
+ flags |= 1;
+ }
+ windowCoords.y -= viewport->viewPos.y;
+ if (windowCoords.y < 0)
+ {
+ windowCoords.y = -windowCoords.y;
+ flags |= 2;
+ }
+ windowCoords.x = (windowCoords.x + 7) / 8;
+ windowCoords.y = (windowCoords.y + 7) / 8;
+
+ // If we are at the final zoom position
+ if (!windowCoords.x && !windowCoords.y)
+ {
+ window->flags &= ~WF_SCROLLING_TO_LOCATION;
+ }
+ if (flags & 1)
+ {
+ windowCoords.x = -windowCoords.x;
+ }
+ if (flags & 2)
+ {
+ windowCoords.y = -windowCoords.y;
+ }
+ windowCoords.x += viewport->viewPos.x;
+ windowCoords.y += viewport->viewPos.y;
+ }
+
+ ViewportMove(windowCoords, window, viewport);
+ }
+
+ void ViewportUpdateFollowSprite(WindowBase* window)
+ {
+ if (!window->viewport_target_sprite.IsNull() && window->viewport != nullptr)
+ {
+ auto* sprite = GetEntity(window->viewport_target_sprite);
+ if (sprite == nullptr)
{
return;
}
- ViewportUpdateSmartFollowGuest(window, *guest);
- break;
- }
- case EntityType::Staff:
- {
- auto* staff = entity->As();
- if (staff == nullptr)
+
+ if (!(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO))
{
- return;
+ int32_t height = (TileElementHeight({ sprite->x, sprite->y }))-16;
+ int32_t underground = sprite->z < height;
+ ViewportSetUndergroundFlag(underground, window, window->viewport);
}
- ViewportUpdateSmartFollowStaff(window, *staff);
- break;
- }
- default: // All other types don't need any "smart" following; steam particle, duck, money effect, etc.
- window->focus = Focus(window->viewport_smart_follow_sprite);
- window->viewport_target_sprite = window->viewport_smart_follow_sprite;
- break;
- }
-}
-void ViewportUpdateSmartFollowGuest(WindowBase* window, const Guest& peep)
-{
- Focus focus = Focus(peep.Id);
- window->viewport_target_sprite = peep.Id;
-
- if (peep.State == PeepState::Picked)
- {
- window->viewport_smart_follow_sprite = EntityId::GetNull();
- window->viewport_target_sprite = EntityId::GetNull();
- window->focus = std::nullopt; // No focus
- return;
- }
-
- bool overallFocus = true;
- if (peep.State == PeepState::OnRide || peep.State == PeepState::EnteringRide
- || (peep.State == PeepState::LeavingRide && peep.x == kLocationNull))
- {
- auto ride = GetRide(peep.CurrentRide);
- if (ride != nullptr && (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK))
- {
- auto train = GetEntity(ride->vehicles[peep.CurrentTrain]);
- if (train != nullptr)
+ auto centreLoc = centre_2d_coordinates(sprite->GetLocation(), window->viewport);
+ if (centreLoc.has_value())
{
- const auto car = train->GetCar(peep.CurrentCar);
- if (car != nullptr)
+ window->savedViewPos = *centreLoc;
+ ViewportMove(*centreLoc, window, window->viewport);
+ }
+ }
+ }
+
+ void ViewportUpdateSmartFollowEntity(WindowBase* window)
+ {
+ auto entity = TryGetEntity(window->viewport_smart_follow_sprite);
+ if (entity == nullptr || entity->Type == EntityType::Null)
+ {
+ window->viewport_smart_follow_sprite = EntityId::GetNull();
+ window->viewport_target_sprite = EntityId::GetNull();
+ return;
+ }
+
+ switch (entity->Type)
+ {
+ case EntityType::Vehicle:
+ ViewportUpdateSmartFollowVehicle(window);
+ break;
+
+ case EntityType::Guest:
+ {
+ auto* guest = entity->As();
+ if (guest == nullptr)
{
- focus = Focus(car->Id);
- overallFocus = false;
- window->viewport_target_sprite = car->Id;
+ return;
+ }
+ ViewportUpdateSmartFollowGuest(window, *guest);
+ break;
+ }
+ case EntityType::Staff:
+ {
+ auto* staff = entity->As();
+ if (staff == nullptr)
+ {
+ return;
+ }
+ ViewportUpdateSmartFollowStaff(window, *staff);
+ break;
+ }
+ default: // All other types don't need any "smart" following; steam particle, duck, money effect, etc.
+ window->focus = Focus(window->viewport_smart_follow_sprite);
+ window->viewport_target_sprite = window->viewport_smart_follow_sprite;
+ break;
+ }
+ }
+
+ void ViewportUpdateSmartFollowGuest(WindowBase* window, const Guest& peep)
+ {
+ Focus focus = Focus(peep.Id);
+ window->viewport_target_sprite = peep.Id;
+
+ if (peep.State == PeepState::Picked)
+ {
+ window->viewport_smart_follow_sprite = EntityId::GetNull();
+ window->viewport_target_sprite = EntityId::GetNull();
+ window->focus = std::nullopt; // No focus
+ return;
+ }
+
+ bool overallFocus = true;
+ if (peep.State == PeepState::OnRide || peep.State == PeepState::EnteringRide
+ || (peep.State == PeepState::LeavingRide && peep.x == kLocationNull))
+ {
+ auto ride = GetRide(peep.CurrentRide);
+ if (ride != nullptr && (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK))
+ {
+ auto train = GetEntity(ride->vehicles[peep.CurrentTrain]);
+ if (train != nullptr)
+ {
+ const auto car = train->GetCar(peep.CurrentCar);
+ if (car != nullptr)
+ {
+ focus = Focus(car->Id);
+ overallFocus = false;
+ window->viewport_target_sprite = car->Id;
+ }
}
}
}
- }
- if (peep.x == kLocationNull && overallFocus)
- {
- auto ride = GetRide(peep.CurrentRide);
- if (ride != nullptr)
+ if (peep.x == kLocationNull && overallFocus)
{
- auto xy = ride->overall_view.ToTileCentre();
- CoordsXYZ coordFocus;
- coordFocus.x = xy.x;
- coordFocus.y = xy.y;
- coordFocus.z = TileElementHeight(xy) + (4 * kCoordsZStep);
- focus = Focus(coordFocus);
- window->viewport_target_sprite = EntityId::GetNull();
+ auto ride = GetRide(peep.CurrentRide);
+ if (ride != nullptr)
+ {
+ auto xy = ride->overall_view.ToTileCentre();
+ CoordsXYZ coordFocus;
+ coordFocus.x = xy.x;
+ coordFocus.y = xy.y;
+ coordFocus.z = TileElementHeight(xy) + (4 * kCoordsZStep);
+ focus = Focus(coordFocus);
+ window->viewport_target_sprite = EntityId::GetNull();
+ }
}
+
+ window->focus = focus;
}
- window->focus = focus;
-}
-
-void ViewportUpdateSmartFollowStaff(WindowBase* window, const Staff& peep)
-{
- if (peep.State == PeepState::Picked)
+ void ViewportUpdateSmartFollowStaff(WindowBase* window, const Staff& peep)
{
- window->viewport_smart_follow_sprite = EntityId::GetNull();
- window->viewport_target_sprite = EntityId::GetNull();
- window->focus = std::nullopt;
- return;
+ if (peep.State == PeepState::Picked)
+ {
+ window->viewport_smart_follow_sprite = EntityId::GetNull();
+ window->viewport_target_sprite = EntityId::GetNull();
+ window->focus = std::nullopt;
+ return;
+ }
+
+ window->focus = Focus(window->viewport_smart_follow_sprite);
+ window->viewport_target_sprite = window->viewport_smart_follow_sprite;
}
- window->focus = Focus(window->viewport_smart_follow_sprite);
- window->viewport_target_sprite = window->viewport_smart_follow_sprite;
-}
-
-void ViewportUpdateSmartFollowVehicle(WindowBase* window)
-{
- window->focus = Focus(window->viewport_smart_follow_sprite);
- window->viewport_target_sprite = window->viewport_smart_follow_sprite;
-}
-
-static void ViewportRotateSingleInternal(WindowBase& w, int32_t direction)
-{
- auto* viewport = w.viewport;
- if (viewport == nullptr)
- return;
-
- auto windowPos = ScreenCoordsXY{ (viewport->width >> 1), (viewport->height >> 1) } + viewport->pos;
-
- // has something to do with checking if middle of the viewport is obstructed
- Viewport* other;
- auto mapXYCoords = ScreenGetMapXY(windowPos, &other);
- CoordsXYZ coords{};
-
- // other != viewport probably triggers on viewports in ride or guest window?
- // mapXYCoords is nullopt if middle of viewport is obstructed by another window?
- if (!mapXYCoords.has_value() || other != viewport)
+ void ViewportUpdateSmartFollowVehicle(WindowBase* window)
{
- auto viewPos = ScreenCoordsXY{ (viewport->ViewWidth() >> 1), (viewport->ViewHeight() >> 1) } + viewport->viewPos;
-
- coords = ViewportAdjustForMapHeight(viewPos, viewport->rotation);
+ window->focus = Focus(window->viewport_smart_follow_sprite);
+ window->viewport_target_sprite = window->viewport_smart_follow_sprite;
}
- else
+
+ static void ViewportRotateSingleInternal(WindowBase& w, int32_t direction)
{
- coords.x = mapXYCoords->x;
- coords.y = mapXYCoords->y;
- coords.z = TileElementHeight(coords);
- }
-
- viewport->rotation = (viewport->rotation + direction) & 3;
-
- auto centreLoc = centre_2d_coordinates(coords, viewport);
-
- if (centreLoc.has_value())
- {
- w.savedViewPos = centreLoc.value();
- viewport->viewPos = *centreLoc;
- }
-
- w.Invalidate();
- w.OnViewportRotate();
-}
-
-void ViewportRotateSingle(WindowBase* window, int32_t direction)
-{
- ViewportRotateSingleInternal(*window, direction);
-}
-
-void ViewportRotateAll(int32_t direction)
-{
- WindowVisitEach([direction](WindowBase* w) {
- auto* viewport = w->viewport;
+ auto* viewport = w.viewport;
if (viewport == nullptr)
return;
- if (viewport->flags & VIEWPORT_FLAG_INDEPEDENT_ROTATION)
+
+ auto windowPos = ScreenCoordsXY{ (viewport->width >> 1), (viewport->height >> 1) } + viewport->pos;
+
+ // has something to do with checking if middle of the viewport is obstructed
+ Viewport* other;
+ auto mapXYCoords = ScreenGetMapXY(windowPos, &other);
+ CoordsXYZ coords{};
+
+ // other != viewport probably triggers on viewports in ride or guest window?
+ // mapXYCoords is nullopt if middle of viewport is obstructed by another window?
+ if (!mapXYCoords.has_value() || other != viewport)
+ {
+ auto viewPos = ScreenCoordsXY{ (viewport->ViewWidth() >> 1), (viewport->ViewHeight() >> 1) } + viewport->viewPos;
+
+ coords = ViewportAdjustForMapHeight(viewPos, viewport->rotation);
+ }
+ else
+ {
+ coords.x = mapXYCoords->x;
+ coords.y = mapXYCoords->y;
+ coords.z = TileElementHeight(coords);
+ }
+
+ viewport->rotation = (viewport->rotation + direction) & 3;
+
+ auto centreLoc = centre_2d_coordinates(coords, viewport);
+
+ if (centreLoc.has_value())
+ {
+ w.savedViewPos = centreLoc.value();
+ viewport->viewPos = *centreLoc;
+ }
+
+ w.Invalidate();
+ w.OnViewportRotate();
+ }
+
+ void ViewportRotateSingle(WindowBase* window, int32_t direction)
+ {
+ ViewportRotateSingleInternal(*window, direction);
+ }
+
+ void ViewportRotateAll(int32_t direction)
+ {
+ WindowVisitEach([direction](WindowBase* w) {
+ auto* viewport = w->viewport;
+ if (viewport == nullptr)
+ return;
+ if (viewport->flags & VIEWPORT_FLAG_INDEPEDENT_ROTATION)
+ return;
+ ViewportRotateSingleInternal(*w, direction);
+ });
+ }
+
+ /**
+ *
+ * rct2: 0x00685C02
+ * ax: left
+ * bx: top
+ * dx: right
+ * esi: viewport
+ * edi: dpi
+ * ebp: bottom
+ */
+ void ViewportRender(DrawPixelInfo& dpi, const Viewport* viewport)
+ {
+ if (viewport->flags & VIEWPORT_FLAG_RENDERING_INHIBITED)
return;
- ViewportRotateSingleInternal(*w, direction);
- });
-}
-/**
- *
- * rct2: 0x00685C02
- * ax: left
- * bx: top
- * dx: right
- * esi: viewport
- * edi: dpi
- * ebp: bottom
- */
-void ViewportRender(DrawPixelInfo& dpi, const Viewport* viewport)
-{
- if (viewport->flags & VIEWPORT_FLAG_RENDERING_INHIBITED)
- return;
+ if (dpi.x + dpi.width <= viewport->pos.x)
+ return;
+ if (dpi.y + dpi.height <= viewport->pos.y)
+ return;
+ if (dpi.x >= viewport->pos.x + viewport->width)
+ return;
+ if (dpi.y >= viewport->pos.y + viewport->height)
+ return;
- if (dpi.x + dpi.width <= viewport->pos.x)
- return;
- if (dpi.y + dpi.height <= viewport->pos.y)
- return;
- if (dpi.x >= viewport->pos.x + viewport->width)
- return;
- if (dpi.y >= viewport->pos.y + viewport->height)
- return;
+ ViewportPaint(viewport, dpi);
+ }
- ViewportPaint(viewport, dpi);
-}
-
-static void ViewportFillColumn(PaintSession& session)
-{
- PROFILED_FUNCTION();
-
- PaintSessionGenerate(session);
- PaintSessionArrange(session);
-}
-
-static void ViewportPaintColumn(PaintSession& session)
-{
- PROFILED_FUNCTION();
-
- if (session.ViewFlags
- & (VIEWPORT_FLAG_HIDE_VERTICAL | VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_UNDERGROUND_INSIDE
- | VIEWPORT_FLAG_CLIP_VIEW)
- && (~session.ViewFlags & VIEWPORT_FLAG_TRANSPARENT_BACKGROUND))
+ static void ViewportFillColumn(PaintSession& session)
{
- uint8_t colour = COLOUR_AQUAMARINE;
- if (session.ViewFlags & VIEWPORT_FLAG_HIDE_ENTITIES)
+ PROFILED_FUNCTION();
+
+ PaintSessionGenerate(session);
+ PaintSessionArrange(session);
+ }
+
+ static void ViewportPaintColumn(PaintSession& session)
+ {
+ PROFILED_FUNCTION();
+
+ if (session.ViewFlags
+ & (VIEWPORT_FLAG_HIDE_VERTICAL | VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_UNDERGROUND_INSIDE
+ | VIEWPORT_FLAG_CLIP_VIEW)
+ && (~session.ViewFlags & VIEWPORT_FLAG_TRANSPARENT_BACKGROUND))
{
- colour = COLOUR_BLACK;
- }
- GfxClear(session.DPI, colour);
- }
-
- PaintDrawStructs(session);
-
- if (Config::Get().general.RenderWeatherGloom && !gTrackDesignSaveMode && !(session.ViewFlags & VIEWPORT_FLAG_HIDE_ENTITIES)
- && !(session.ViewFlags & VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES))
- {
- ViewportPaintWeatherGloom(session.DPI);
- }
-
- if (session.PSStringHead != nullptr)
- {
- PaintDrawMoneyStructs(session.DPI, session.PSStringHead);
- }
-}
-
-/**
- *
- * rct2: 0x00685CBF
- * eax: left
- * ebx: top
- * edx: right
- * esi: viewport
- * edi: dpi
- * ebp: bottom
- */
-static void ViewportPaint(const Viewport* viewport, DrawPixelInfo& dpi)
-{
- PROFILED_FUNCTION();
-
- const int32_t offsetX = dpi.x - viewport->pos.x;
- const int32_t offsetY = dpi.y - viewport->pos.y;
- const int32_t worldX = viewport->zoom.ApplyInversedTo(viewport->viewPos.x) + std::max(0, offsetX);
- const int32_t worldY = viewport->zoom.ApplyInversedTo(viewport->viewPos.y) + std::max(0, offsetY);
- const int32_t width = std::min(viewport->pos.x + viewport->width, dpi.x + dpi.width) - std::max(viewport->pos.x, dpi.x);
- const int32_t height = std::min(viewport->pos.y + viewport->height, dpi.y + dpi.height) - std::max(viewport->pos.y, dpi.y);
-
- DrawPixelInfo worldDpi;
- worldDpi.DrawingEngine = dpi.DrawingEngine;
- worldDpi.bits = dpi.bits + std::max(0, -offsetX) + std::max(0, -offsetY) * dpi.LineStride();
- worldDpi.x = worldX;
- worldDpi.y = worldY;
- worldDpi.width = width;
- worldDpi.height = height;
- worldDpi.pitch = dpi.LineStride() - worldDpi.width;
- worldDpi.zoom_level = viewport->zoom;
-
- _paintColumns.clear();
-
- bool useMultithreading = Config::Get().general.MultiThreading;
- if (useMultithreading && _paintJobs == nullptr)
- {
- _paintJobs = std::make_unique();
- }
- else if (useMultithreading == false && _paintJobs != nullptr)
- {
- _paintJobs.reset();
- }
-
- bool useParallelDrawing = false;
- if (useMultithreading && (dpi.DrawingEngine->GetFlags() & DEF_PARALLEL_DRAWING))
- {
- useParallelDrawing = true;
- }
-
- const int32_t columnWidth = worldDpi.zoom_level.ApplyInversedTo(kCoordsXYStep);
- const int32_t rightBorder = worldDpi.x + worldDpi.width;
- const int32_t alignedX = floor2(worldDpi.x, columnWidth);
-
- // Generate and sort columns.
- for (int32_t x = alignedX; x < rightBorder; x += columnWidth)
- {
- PaintSession* session = PaintSessionAlloc(worldDpi, viewport->flags, viewport->rotation);
- _paintColumns.push_back(session);
-
- DrawPixelInfo& columnDpi = session->DPI;
- if (x >= columnDpi.x)
- {
- const int32_t leftPitch = x - columnDpi.x;
- columnDpi.width = columnDpi.width - leftPitch;
- columnDpi.bits += leftPitch;
- columnDpi.pitch += leftPitch;
- columnDpi.x = x;
+ uint8_t colour = COLOUR_AQUAMARINE;
+ if (session.ViewFlags & VIEWPORT_FLAG_HIDE_ENTITIES)
+ {
+ colour = COLOUR_BLACK;
+ }
+ GfxClear(session.DPI, colour);
}
- int32_t paintRight = columnDpi.x + columnDpi.width;
- if (paintRight >= x + columnWidth)
+ PaintDrawStructs(session);
+
+ if (Config::Get().general.RenderWeatherGloom && !gTrackDesignSaveMode
+ && !(session.ViewFlags & VIEWPORT_FLAG_HIDE_ENTITIES) && !(session.ViewFlags & VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES))
{
- const int32_t rightPitch = paintRight - x - columnWidth;
- paintRight -= rightPitch;
- columnDpi.pitch += rightPitch;
+ ViewportPaintWeatherGloom(session.DPI);
+ }
+
+ if (session.PSStringHead != nullptr)
+ {
+ PaintDrawMoneyStructs(session.DPI, session.PSStringHead);
+ }
+ }
+
+ /**
+ *
+ * rct2: 0x00685CBF
+ * eax: left
+ * ebx: top
+ * edx: right
+ * esi: viewport
+ * edi: dpi
+ * ebp: bottom
+ */
+ static void ViewportPaint(const Viewport* viewport, DrawPixelInfo& dpi)
+ {
+ PROFILED_FUNCTION();
+
+ const int32_t offsetX = dpi.x - viewport->pos.x;
+ const int32_t offsetY = dpi.y - viewport->pos.y;
+ const int32_t worldX = viewport->zoom.ApplyInversedTo(viewport->viewPos.x) + std::max(0, offsetX);
+ const int32_t worldY = viewport->zoom.ApplyInversedTo(viewport->viewPos.y) + std::max(0, offsetY);
+ const int32_t width = std::min(viewport->pos.x + viewport->width, dpi.x + dpi.width) - std::max(viewport->pos.x, dpi.x);
+ const int32_t height = std::min(viewport->pos.y + viewport->height, dpi.y + dpi.height)
+ - std::max(viewport->pos.y, dpi.y);
+
+ DrawPixelInfo worldDpi;
+ worldDpi.DrawingEngine = dpi.DrawingEngine;
+ worldDpi.bits = dpi.bits + std::max(0, -offsetX) + std::max(0, -offsetY) * dpi.LineStride();
+ worldDpi.x = worldX;
+ worldDpi.y = worldY;
+ worldDpi.width = width;
+ worldDpi.height = height;
+ worldDpi.pitch = dpi.LineStride() - worldDpi.width;
+ worldDpi.zoom_level = viewport->zoom;
+
+ _paintColumns.clear();
+
+ bool useMultithreading = Config::Get().general.MultiThreading;
+ if (useMultithreading && _paintJobs == nullptr)
+ {
+ _paintJobs = std::make_unique();
+ }
+ else if (useMultithreading == false && _paintJobs != nullptr)
+ {
+ _paintJobs.reset();
+ }
+
+ bool useParallelDrawing = false;
+ if (useMultithreading && (dpi.DrawingEngine->GetFlags() & DEF_PARALLEL_DRAWING))
+ {
+ useParallelDrawing = true;
+ }
+
+ const int32_t columnWidth = worldDpi.zoom_level.ApplyInversedTo(kCoordsXYStep);
+ const int32_t rightBorder = worldDpi.x + worldDpi.width;
+ const int32_t alignedX = floor2(worldDpi.x, columnWidth);
+
+ // Generate and sort columns.
+ for (int32_t x = alignedX; x < rightBorder; x += columnWidth)
+ {
+ PaintSession* session = PaintSessionAlloc(worldDpi, viewport->flags, viewport->rotation);
+ _paintColumns.push_back(session);
+
+ DrawPixelInfo& columnDpi = session->DPI;
+ if (x >= columnDpi.x)
+ {
+ const int32_t leftPitch = x - columnDpi.x;
+ columnDpi.width = columnDpi.width - leftPitch;
+ columnDpi.bits += leftPitch;
+ columnDpi.pitch += leftPitch;
+ columnDpi.x = x;
+ }
+
+ int32_t paintRight = columnDpi.x + columnDpi.width;
+ if (paintRight >= x + columnWidth)
+ {
+ const int32_t rightPitch = paintRight - x - columnWidth;
+ paintRight -= rightPitch;
+ columnDpi.pitch += rightPitch;
+ }
+ columnDpi.width = paintRight - columnDpi.x;
+
+ if (useMultithreading)
+ {
+ _paintJobs->AddTask([session]() -> void { ViewportFillColumn(*session); });
+ }
+ else
+ {
+ ViewportFillColumn(*session);
+ }
}
- columnDpi.width = paintRight - columnDpi.x;
if (useMultithreading)
{
- _paintJobs->AddTask([session]() -> void { ViewportFillColumn(*session); });
+ _paintJobs->Join();
}
- else
+
+ // Paint columns.
+ for (auto* session : _paintColumns)
{
- ViewportFillColumn(*session);
+ if (useParallelDrawing)
+ {
+ _paintJobs->AddTask([session]() -> void { ViewportPaintColumn(*session); });
+ }
+ else
+ {
+ ViewportPaintColumn(*session);
+ }
}
- }
-
- if (useMultithreading)
- {
- _paintJobs->Join();
- }
-
- // Paint columns.
- for (auto* session : _paintColumns)
- {
if (useParallelDrawing)
{
- _paintJobs->AddTask([session]() -> void { ViewportPaintColumn(*session); });
+ _paintJobs->Join();
+ }
+
+ // Release resources.
+ for (auto* session : _paintColumns)
+ {
+ PaintSessionFree(session);
+ }
+ }
+
+ static void ViewportPaintWeatherGloom(DrawPixelInfo& dpi)
+ {
+ auto paletteId = ClimateGetWeatherGloomPaletteId(GetGameState().ClimateCurrent);
+ if (paletteId != FilterPaletteID::PaletteNull)
+ {
+ auto x = dpi.x;
+ auto y = dpi.y;
+ auto w = dpi.width;
+ auto h = dpi.height;
+ GfxFilterRect(dpi, ScreenRect(x, y, x + w, y + h), paletteId);
+ }
+ }
+
+ /**
+ *
+ * rct2: 0x0068958D
+ */
+ std::optional ScreenPosToMapPos(const ScreenCoordsXY& screenCoords, int32_t* direction)
+ {
+ auto mapCoords = ScreenGetMapXY(screenCoords, nullptr);
+ if (!mapCoords.has_value())
+ return std::nullopt;
+
+ int32_t my_direction;
+ int32_t dist_from_centre_x = abs(mapCoords->x % 32);
+ int32_t dist_from_centre_y = abs(mapCoords->y % 32);
+ if (dist_from_centre_x > 8 && dist_from_centre_x < 24 && dist_from_centre_y > 8 && dist_from_centre_y < 24)
+ {
+ my_direction = 4;
}
else
{
- ViewportPaintColumn(*session);
- }
- }
- if (useParallelDrawing)
- {
- _paintJobs->Join();
- }
-
- // Release resources.
- for (auto* session : _paintColumns)
- {
- PaintSessionFree(session);
- }
-}
-
-static void ViewportPaintWeatherGloom(DrawPixelInfo& dpi)
-{
- auto paletteId = ClimateGetWeatherGloomPaletteId(GetGameState().ClimateCurrent);
- if (paletteId != FilterPaletteID::PaletteNull)
- {
- auto x = dpi.x;
- auto y = dpi.y;
- auto w = dpi.width;
- auto h = dpi.height;
- GfxFilterRect(dpi, ScreenRect(x, y, x + w, y + h), paletteId);
- }
-}
-
-/**
- *
- * rct2: 0x0068958D
- */
-std::optional ScreenPosToMapPos(const ScreenCoordsXY& screenCoords, int32_t* direction)
-{
- auto mapCoords = ScreenGetMapXY(screenCoords, nullptr);
- if (!mapCoords.has_value())
- return std::nullopt;
-
- int32_t my_direction;
- int32_t dist_from_centre_x = abs(mapCoords->x % 32);
- int32_t dist_from_centre_y = abs(mapCoords->y % 32);
- if (dist_from_centre_x > 8 && dist_from_centre_x < 24 && dist_from_centre_y > 8 && dist_from_centre_y < 24)
- {
- my_direction = 4;
- }
- else
- {
- auto mod_x = mapCoords->x & 0x1F;
- auto mod_y = mapCoords->y & 0x1F;
- if (mod_x <= 16)
- {
- if (mod_y < 16)
+ auto mod_x = mapCoords->x & 0x1F;
+ auto mod_y = mapCoords->y & 0x1F;
+ if (mod_x <= 16)
{
- my_direction = 2;
- }
- else
- {
- my_direction = 3;
- }
- }
- else
- {
- if (mod_y < 16)
- {
- my_direction = 1;
- }
- else
- {
- my_direction = 0;
- }
- }
- }
-
- if (direction != nullptr)
- *direction = my_direction;
- return { mapCoords->ToTileStart() };
-}
-
-[[nodiscard]] ScreenCoordsXY Viewport::ScreenToViewportCoord(const ScreenCoordsXY& screenCoords) const
-{
- ScreenCoordsXY ret;
- ret.x = (zoom.ApplyTo(screenCoords.x - pos.x)) + viewPos.x;
- ret.y = (zoom.ApplyTo(screenCoords.y - pos.y)) + viewPos.y;
- return ret;
-}
-
-void Viewport::Invalidate() const
-{
- ViewportInvalidate(this, { viewPos, viewPos + ScreenCoordsXY{ ViewWidth(), ViewHeight() } });
-}
-
-CoordsXY ViewportPosToMapPos(const ScreenCoordsXY& coords, int32_t z, uint8_t rotation)
-{
- // Reverse of Translate3DTo2DWithZ
- CoordsXY ret = { coords.y - coords.x / 2 + z, coords.y + coords.x / 2 + z };
- auto inverseRotation = DirectionFlipXAxis(rotation);
- return ret.Rotate(inverseRotation);
-}
-
-/**
- *
- * rct2: 0x00664689
- */
-void ShowGridlines()
-{
- if (gShowGridLinesRefCount == 0)
- {
- WindowBase* mainWindow = WindowGetMain();
- if (mainWindow != nullptr)
- {
- if (!(mainWindow->viewport->flags & VIEWPORT_FLAG_GRIDLINES))
- {
- mainWindow->viewport->flags |= VIEWPORT_FLAG_GRIDLINES;
- mainWindow->Invalidate();
- }
- }
- }
- gShowGridLinesRefCount++;
-}
-
-/**
- *
- * rct2: 0x006646B4
- */
-void HideGridlines()
-{
- if (gShowGridLinesRefCount > 0)
- gShowGridLinesRefCount--;
-
- if (gShowGridLinesRefCount == 0)
- {
- WindowBase* mainWindow = WindowGetMain();
- if (mainWindow != nullptr)
- {
- if (!Config::Get().general.AlwaysShowGridlines)
- {
- mainWindow->viewport->flags &= ~VIEWPORT_FLAG_GRIDLINES;
- mainWindow->Invalidate();
- }
- }
- }
-}
-
-/**
- *
- * rct2: 0x00664E8E
- */
-void ShowLandRights()
-{
- if (gShowLandRightsRefCount == 0)
- {
- WindowBase* mainWindow = WindowGetMain();
- if (mainWindow != nullptr)
- {
- if (!(mainWindow->viewport->flags & VIEWPORT_FLAG_LAND_OWNERSHIP))
- {
- mainWindow->viewport->flags |= VIEWPORT_FLAG_LAND_OWNERSHIP;
- mainWindow->Invalidate();
- }
- }
- }
- gShowLandRightsRefCount++;
-}
-
-/**
- *
- * rct2: 0x00664EB9
- */
-void HideLandRights()
-{
- if (gShowLandRightsRefCount > 0)
- gShowLandRightsRefCount--;
-
- if (gShowLandRightsRefCount == 0)
- {
- WindowBase* mainWindow = WindowGetMain();
- if (mainWindow != nullptr)
- {
- if (mainWindow->viewport->flags & VIEWPORT_FLAG_LAND_OWNERSHIP)
- {
- mainWindow->viewport->flags &= ~VIEWPORT_FLAG_LAND_OWNERSHIP;
- mainWindow->Invalidate();
- }
- }
- }
-}
-
-/**
- *
- * rct2: 0x00664EDD
- */
-void ShowConstructionRights()
-{
- if (gShowConstructionRightsRefCount == 0)
- {
- WindowBase* mainWindow = WindowGetMain();
- if (mainWindow != nullptr)
- {
- if (!(mainWindow->viewport->flags & VIEWPORT_FLAG_CONSTRUCTION_RIGHTS))
- {
- mainWindow->viewport->flags |= VIEWPORT_FLAG_CONSTRUCTION_RIGHTS;
- mainWindow->Invalidate();
- }
- }
- }
- gShowConstructionRightsRefCount++;
-}
-
-/**
- *
- * rct2: 0x00664F08
- */
-void HideConstructionRights()
-{
- if (gShowConstructionRightsRefCount > 0)
- gShowConstructionRightsRefCount--;
-
- if (gShowConstructionRightsRefCount == 0)
- {
- WindowBase* mainWindow = WindowGetMain();
- if (mainWindow != nullptr)
- {
- if (mainWindow->viewport->flags & VIEWPORT_FLAG_CONSTRUCTION_RIGHTS)
- {
- mainWindow->viewport->flags &= ~VIEWPORT_FLAG_CONSTRUCTION_RIGHTS;
- mainWindow->Invalidate();
- }
- }
- }
-}
-
-/**
- *
- * rct2: 0x006CB70A
- */
-void ViewportSetVisibility(ViewportVisibility mode)
-{
- WindowBase* window = WindowGetMain();
-
- if (window != nullptr)
- {
- Viewport* vp = window->viewport;
- uint32_t invalidate = 0;
-
- switch (mode)
- {
- case ViewportVisibility::Default:
- { // Set all these flags to 0, and invalidate if any were active
- uint32_t mask = VIEWPORT_FLAG_UNDERGROUND_INSIDE | VIEWPORT_FLAG_HIDE_RIDES | VIEWPORT_FLAG_HIDE_SCENERY
- | VIEWPORT_FLAG_HIDE_PATHS | VIEWPORT_FLAG_LAND_HEIGHTS | VIEWPORT_FLAG_TRACK_HEIGHTS
- | VIEWPORT_FLAG_PATH_HEIGHTS | VIEWPORT_FLAG_HIDE_GUESTS | VIEWPORT_FLAG_HIDE_STAFF
- | VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_HIDE_VERTICAL | VIEWPORT_FLAG_HIDE_VEHICLES
- | VIEWPORT_FLAG_HIDE_SUPPORTS | VIEWPORT_FLAG_HIDE_VEGETATION;
-
- invalidate += vp->flags & mask;
- vp->flags &= ~mask;
- break;
- }
- case ViewportVisibility::UndergroundViewOn: // 6CB79D
- case ViewportVisibility::UndergroundViewGhostOn: // 6CB7C4
- // Set underground on, invalidate if it was off
- invalidate += !(vp->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE);
- vp->flags |= VIEWPORT_FLAG_UNDERGROUND_INSIDE;
- break;
- case ViewportVisibility::TrackHeights: // 6CB7EB
- // Set track heights on, invalidate if off
- invalidate += !(vp->flags & VIEWPORT_FLAG_TRACK_HEIGHTS);
- vp->flags |= VIEWPORT_FLAG_TRACK_HEIGHTS;
- break;
- case ViewportVisibility::UndergroundViewOff: // 6CB7B1
- case ViewportVisibility::UndergroundViewGhostOff: // 6CB7D8
- // Set underground off, invalidate if it was on
- invalidate += vp->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE;
- vp->flags &= ~(static_cast(VIEWPORT_FLAG_UNDERGROUND_INSIDE));
- break;
- }
- if (invalidate != 0)
- window->Invalidate();
- }
-}
-
-static bool IsCursorIdVegetation(CursorID cursor)
-{
- switch (cursor)
- {
- case CursorID::TreeDown:
- case CursorID::FlowerDown:
- return true;
- default:
- return false;
- }
-}
-
-static bool IsTileElementVegetation(const TileElement* tileElement)
-{
- switch (tileElement->GetType())
- {
- case TileElementType::SmallScenery:
- {
- auto sceneryItem = tileElement->AsSmallScenery();
- auto sceneryEntry = sceneryItem->GetEntry();
- if (sceneryEntry != nullptr
- && (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_IS_TREE) || IsCursorIdVegetation(sceneryEntry->tool_id)))
- {
- return true;
- }
- break;
- }
- case TileElementType::LargeScenery:
- {
- auto sceneryItem = tileElement->AsLargeScenery();
- auto sceneryEntry = sceneryItem->GetEntry();
- if (sceneryEntry != nullptr && IsCursorIdVegetation(sceneryEntry->tool_id))
- {
- return true;
- }
- break;
- }
- case TileElementType::Wall:
- {
- auto sceneryItem = tileElement->AsWall();
- auto sceneryEntry = sceneryItem->GetEntry();
- if (sceneryEntry != nullptr && IsCursorIdVegetation(sceneryEntry->tool_id))
- {
- return true;
- }
- break;
- }
- default:
- break;
- }
- return false;
-}
-
-VisibilityKind GetPaintStructVisibility(const PaintStruct* ps, uint32_t viewFlags)
-{
- switch (ps->InteractionItem)
- {
- case ViewportInteractionItem::Entity:
- if (ps->Entity != nullptr)
- {
- switch (ps->Entity->Type)
+ if (mod_y < 16)
{
- case EntityType::Vehicle:
- {
- if (viewFlags & VIEWPORT_FLAG_HIDE_VEHICLES)
- {
- return (viewFlags & VIEWPORT_FLAG_INVISIBLE_VEHICLES) ? VisibilityKind::Hidden
- : VisibilityKind::Partial;
- }
- // Rides without track can technically have a 'vehicle':
- // these should be hidden if 'hide rides' is enabled
- if (viewFlags & VIEWPORT_FLAG_HIDE_RIDES)
- {
- auto vehicle = ps->Entity->As();
- if (vehicle == nullptr)
- break;
-
- auto ride = vehicle->GetRide();
- if (ride != nullptr && !ride->GetRideTypeDescriptor().HasFlag(RtdFlag::hasTrack))
- {
- return (viewFlags & VIEWPORT_FLAG_INVISIBLE_RIDES) ? VisibilityKind::Hidden
- : VisibilityKind::Partial;
- }
- }
- break;
- }
- case EntityType::Guest:
- if (viewFlags & VIEWPORT_FLAG_HIDE_GUESTS)
- {
- return VisibilityKind::Hidden;
- }
- break;
- case EntityType::Staff:
- if (viewFlags & VIEWPORT_FLAG_HIDE_STAFF)
- {
- return VisibilityKind::Hidden;
- }
- break;
- default:
- break;
- }
- }
- break;
- case ViewportInteractionItem::Ride:
- if (viewFlags & VIEWPORT_FLAG_HIDE_RIDES)
- {
- return (viewFlags & VIEWPORT_FLAG_INVISIBLE_RIDES) ? VisibilityKind::Hidden : VisibilityKind::Partial;
- }
- break;
- case ViewportInteractionItem::Footpath:
- case ViewportInteractionItem::PathAddition:
- case ViewportInteractionItem::Banner:
- if (viewFlags & VIEWPORT_FLAG_HIDE_PATHS)
- {
- return (viewFlags & VIEWPORT_FLAG_INVISIBLE_PATHS) ? VisibilityKind::Hidden : VisibilityKind::Partial;
- }
- break;
- case ViewportInteractionItem::Scenery:
- case ViewportInteractionItem::LargeScenery:
- case ViewportInteractionItem::Wall:
- if (ps->Element != nullptr)
- {
- if (IsTileElementVegetation(ps->Element))
- {
- if (viewFlags & VIEWPORT_FLAG_HIDE_VEGETATION)
- {
- return (viewFlags & VIEWPORT_FLAG_INVISIBLE_VEGETATION) ? VisibilityKind::Hidden
- : VisibilityKind::Partial;
- }
+ my_direction = 2;
}
else
{
- if (viewFlags & VIEWPORT_FLAG_HIDE_SCENERY)
- {
- return (viewFlags & VIEWPORT_FLAG_INVISIBLE_SCENERY) ? VisibilityKind::Hidden : VisibilityKind::Partial;
- }
+ my_direction = 3;
}
}
- if (ps->InteractionItem == ViewportInteractionItem::Wall && (viewFlags & VIEWPORT_FLAG_UNDERGROUND_INSIDE))
+ else
{
- return VisibilityKind::Partial;
+ if (mod_y < 16)
+ {
+ my_direction = 1;
+ }
+ else
+ {
+ my_direction = 0;
+ }
}
- break;
- default:
- break;
- }
- return VisibilityKind::Visible;
-}
+ }
-/**
- * Checks if a PaintStruct sprite type is in the filter mask.
- */
-static bool PSInteractionTypeIsInFilter(PaintStruct* ps, uint16_t filter)
-{
- if (ps->InteractionItem != ViewportInteractionItem::None && ps->InteractionItem != ViewportInteractionItem::Label
- && ps->InteractionItem <= ViewportInteractionItem::Banner)
+ if (direction != nullptr)
+ *direction = my_direction;
+ return { mapCoords->ToTileStart() };
+ }
+
+ [[nodiscard]] ScreenCoordsXY Viewport::ScreenToViewportCoord(const ScreenCoordsXY& screenCoords) const
{
- auto mask = EnumToFlag(ps->InteractionItem);
- if (filter & mask)
+ ScreenCoordsXY ret;
+ ret.x = (zoom.ApplyTo(screenCoords.x - pos.x)) + viewPos.x;
+ ret.y = (zoom.ApplyTo(screenCoords.y - pos.y)) + viewPos.y;
+ return ret;
+ }
+
+ void Viewport::Invalidate() const
+ {
+ ViewportInvalidate(this, { viewPos, viewPos + ScreenCoordsXY{ ViewWidth(), ViewHeight() } });
+ }
+
+ CoordsXY ViewportPosToMapPos(const ScreenCoordsXY& coords, int32_t z, uint8_t rotation)
+ {
+ // Reverse of Translate3DTo2DWithZ
+ CoordsXY ret = { coords.y - coords.x / 2 + z, coords.y + coords.x / 2 + z };
+ auto inverseRotation = DirectionFlipXAxis(rotation);
+ return ret.Rotate(inverseRotation);
+ }
+
+ /**
+ *
+ * rct2: 0x00664689
+ */
+ void ShowGridlines()
+ {
+ if (gShowGridLinesRefCount == 0)
{
- return true;
+ WindowBase* mainWindow = WindowGetMain();
+ if (mainWindow != nullptr)
+ {
+ if (!(mainWindow->viewport->flags & VIEWPORT_FLAG_GRIDLINES))
+ {
+ mainWindow->viewport->flags |= VIEWPORT_FLAG_GRIDLINES;
+ mainWindow->Invalidate();
+ }
+ }
+ }
+ gShowGridLinesRefCount++;
+ }
+
+ /**
+ *
+ * rct2: 0x006646B4
+ */
+ void HideGridlines()
+ {
+ if (gShowGridLinesRefCount > 0)
+ gShowGridLinesRefCount--;
+
+ if (gShowGridLinesRefCount == 0)
+ {
+ WindowBase* mainWindow = WindowGetMain();
+ if (mainWindow != nullptr)
+ {
+ if (!Config::Get().general.AlwaysShowGridlines)
+ {
+ mainWindow->viewport->flags &= ~VIEWPORT_FLAG_GRIDLINES;
+ mainWindow->Invalidate();
+ }
+ }
}
}
- return false;
-}
-/**
- * rct2: 0x00679236, 0x00679662, 0x00679B0D, 0x00679FF1
- */
-static bool IsPixelPresentBMP(
- const uint32_t imageType, const G1Element* g1, const int32_t x, const int32_t y, const PaletteMap& paletteMap)
-{
- uint8_t* index = g1->offset + (y * g1->width) + x;
-
- // Needs investigation as it has no consideration for pure BMP maps.
- if (!(g1->flags & G1_FLAG_HAS_TRANSPARENCY))
+ /**
+ *
+ * rct2: 0x00664E8E
+ */
+ void ShowLandRights()
{
+ if (gShowLandRightsRefCount == 0)
+ {
+ WindowBase* mainWindow = WindowGetMain();
+ if (mainWindow != nullptr)
+ {
+ if (!(mainWindow->viewport->flags & VIEWPORT_FLAG_LAND_OWNERSHIP))
+ {
+ mainWindow->viewport->flags |= VIEWPORT_FLAG_LAND_OWNERSHIP;
+ mainWindow->Invalidate();
+ }
+ }
+ }
+ gShowLandRightsRefCount++;
+ }
+
+ /**
+ *
+ * rct2: 0x00664EB9
+ */
+ void HideLandRights()
+ {
+ if (gShowLandRightsRefCount > 0)
+ gShowLandRightsRefCount--;
+
+ if (gShowLandRightsRefCount == 0)
+ {
+ WindowBase* mainWindow = WindowGetMain();
+ if (mainWindow != nullptr)
+ {
+ if (mainWindow->viewport->flags & VIEWPORT_FLAG_LAND_OWNERSHIP)
+ {
+ mainWindow->viewport->flags &= ~VIEWPORT_FLAG_LAND_OWNERSHIP;
+ mainWindow->Invalidate();
+ }
+ }
+ }
+ }
+
+ /**
+ *
+ * rct2: 0x00664EDD
+ */
+ void ShowConstructionRights()
+ {
+ if (gShowConstructionRightsRefCount == 0)
+ {
+ WindowBase* mainWindow = WindowGetMain();
+ if (mainWindow != nullptr)
+ {
+ if (!(mainWindow->viewport->flags & VIEWPORT_FLAG_CONSTRUCTION_RIGHTS))
+ {
+ mainWindow->viewport->flags |= VIEWPORT_FLAG_CONSTRUCTION_RIGHTS;
+ mainWindow->Invalidate();
+ }
+ }
+ }
+ gShowConstructionRightsRefCount++;
+ }
+
+ /**
+ *
+ * rct2: 0x00664F08
+ */
+ void HideConstructionRights()
+ {
+ if (gShowConstructionRightsRefCount > 0)
+ gShowConstructionRightsRefCount--;
+
+ if (gShowConstructionRightsRefCount == 0)
+ {
+ WindowBase* mainWindow = WindowGetMain();
+ if (mainWindow != nullptr)
+ {
+ if (mainWindow->viewport->flags & VIEWPORT_FLAG_CONSTRUCTION_RIGHTS)
+ {
+ mainWindow->viewport->flags &= ~VIEWPORT_FLAG_CONSTRUCTION_RIGHTS;
+ mainWindow->Invalidate();
+ }
+ }
+ }
+ }
+
+ /**
+ *
+ * rct2: 0x006CB70A
+ */
+ void ViewportSetVisibility(ViewportVisibility mode)
+ {
+ WindowBase* window = WindowGetMain();
+
+ if (window != nullptr)
+ {
+ Viewport* vp = window->viewport;
+ uint32_t invalidate = 0;
+
+ switch (mode)
+ {
+ case ViewportVisibility::Default:
+ { // Set all these flags to 0, and invalidate if any were active
+ uint32_t mask = VIEWPORT_FLAG_UNDERGROUND_INSIDE | VIEWPORT_FLAG_HIDE_RIDES | VIEWPORT_FLAG_HIDE_SCENERY
+ | VIEWPORT_FLAG_HIDE_PATHS | VIEWPORT_FLAG_LAND_HEIGHTS | VIEWPORT_FLAG_TRACK_HEIGHTS
+ | VIEWPORT_FLAG_PATH_HEIGHTS | VIEWPORT_FLAG_HIDE_GUESTS | VIEWPORT_FLAG_HIDE_STAFF
+ | VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_HIDE_VERTICAL | VIEWPORT_FLAG_HIDE_VEHICLES
+ | VIEWPORT_FLAG_HIDE_SUPPORTS | VIEWPORT_FLAG_HIDE_VEGETATION;
+
+ invalidate += vp->flags & mask;
+ vp->flags &= ~mask;
+ break;
+ }
+ case ViewportVisibility::UndergroundViewOn: // 6CB79D
+ case ViewportVisibility::UndergroundViewGhostOn: // 6CB7C4
+ // Set underground on, invalidate if it was off
+ invalidate += !(vp->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE);
+ vp->flags |= VIEWPORT_FLAG_UNDERGROUND_INSIDE;
+ break;
+ case ViewportVisibility::TrackHeights: // 6CB7EB
+ // Set track heights on, invalidate if off
+ invalidate += !(vp->flags & VIEWPORT_FLAG_TRACK_HEIGHTS);
+ vp->flags |= VIEWPORT_FLAG_TRACK_HEIGHTS;
+ break;
+ case ViewportVisibility::UndergroundViewOff: // 6CB7B1
+ case ViewportVisibility::UndergroundViewGhostOff: // 6CB7D8
+ // Set underground off, invalidate if it was on
+ invalidate += vp->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE;
+ vp->flags &= ~(static_cast(VIEWPORT_FLAG_UNDERGROUND_INSIDE));
+ break;
+ }
+ if (invalidate != 0)
+ window->Invalidate();
+ }
+ }
+
+ static bool IsCursorIdVegetation(CursorID cursor)
+ {
+ switch (cursor)
+ {
+ case CursorID::TreeDown:
+ case CursorID::FlowerDown:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ static bool IsTileElementVegetation(const TileElement* tileElement)
+ {
+ switch (tileElement->GetType())
+ {
+ case TileElementType::SmallScenery:
+ {
+ auto sceneryItem = tileElement->AsSmallScenery();
+ auto sceneryEntry = sceneryItem->GetEntry();
+ if (sceneryEntry != nullptr
+ && (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_IS_TREE) || IsCursorIdVegetation(sceneryEntry->tool_id)))
+ {
+ return true;
+ }
+ break;
+ }
+ case TileElementType::LargeScenery:
+ {
+ auto sceneryItem = tileElement->AsLargeScenery();
+ auto sceneryEntry = sceneryItem->GetEntry();
+ if (sceneryEntry != nullptr && IsCursorIdVegetation(sceneryEntry->tool_id))
+ {
+ return true;
+ }
+ break;
+ }
+ case TileElementType::Wall:
+ {
+ auto sceneryItem = tileElement->AsWall();
+ auto sceneryEntry = sceneryItem->GetEntry();
+ if (sceneryEntry != nullptr && IsCursorIdVegetation(sceneryEntry->tool_id))
+ {
+ return true;
+ }
+ break;
+ }
+ default:
+ break;
+ }
return false;
}
- if (imageType & IMAGE_TYPE_REMAP)
+ VisibilityKind GetPaintStructVisibility(const PaintStruct* ps, uint32_t viewFlags)
{
- return paletteMap[*index] != 0;
+ switch (ps->InteractionItem)
+ {
+ case ViewportInteractionItem::Entity:
+ if (ps->Entity != nullptr)
+ {
+ switch (ps->Entity->Type)
+ {
+ case EntityType::Vehicle:
+ {
+ if (viewFlags & VIEWPORT_FLAG_HIDE_VEHICLES)
+ {
+ return (viewFlags & VIEWPORT_FLAG_INVISIBLE_VEHICLES) ? VisibilityKind::Hidden
+ : VisibilityKind::Partial;
+ }
+ // Rides without track can technically have a 'vehicle':
+ // these should be hidden if 'hide rides' is enabled
+ if (viewFlags & VIEWPORT_FLAG_HIDE_RIDES)
+ {
+ auto vehicle = ps->Entity->As();
+ if (vehicle == nullptr)
+ break;
+
+ auto ride = vehicle->GetRide();
+ if (ride != nullptr && !ride->GetRideTypeDescriptor().HasFlag(RtdFlag::hasTrack))
+ {
+ return (viewFlags & VIEWPORT_FLAG_INVISIBLE_RIDES) ? VisibilityKind::Hidden
+ : VisibilityKind::Partial;
+ }
+ }
+ break;
+ }
+ case EntityType::Guest:
+ if (viewFlags & VIEWPORT_FLAG_HIDE_GUESTS)
+ {
+ return VisibilityKind::Hidden;
+ }
+ break;
+ case EntityType::Staff:
+ if (viewFlags & VIEWPORT_FLAG_HIDE_STAFF)
+ {
+ return VisibilityKind::Hidden;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case ViewportInteractionItem::Ride:
+ if (viewFlags & VIEWPORT_FLAG_HIDE_RIDES)
+ {
+ return (viewFlags & VIEWPORT_FLAG_INVISIBLE_RIDES) ? VisibilityKind::Hidden : VisibilityKind::Partial;
+ }
+ break;
+ case ViewportInteractionItem::Footpath:
+ case ViewportInteractionItem::PathAddition:
+ case ViewportInteractionItem::Banner:
+ if (viewFlags & VIEWPORT_FLAG_HIDE_PATHS)
+ {
+ return (viewFlags & VIEWPORT_FLAG_INVISIBLE_PATHS) ? VisibilityKind::Hidden : VisibilityKind::Partial;
+ }
+ break;
+ case ViewportInteractionItem::Scenery:
+ case ViewportInteractionItem::LargeScenery:
+ case ViewportInteractionItem::Wall:
+ if (ps->Element != nullptr)
+ {
+ if (IsTileElementVegetation(ps->Element))
+ {
+ if (viewFlags & VIEWPORT_FLAG_HIDE_VEGETATION)
+ {
+ return (viewFlags & VIEWPORT_FLAG_INVISIBLE_VEGETATION) ? VisibilityKind::Hidden
+ : VisibilityKind::Partial;
+ }
+ }
+ else
+ {
+ if (viewFlags & VIEWPORT_FLAG_HIDE_SCENERY)
+ {
+ return (viewFlags & VIEWPORT_FLAG_INVISIBLE_SCENERY) ? VisibilityKind::Hidden
+ : VisibilityKind::Partial;
+ }
+ }
+ }
+ if (ps->InteractionItem == ViewportInteractionItem::Wall && (viewFlags & VIEWPORT_FLAG_UNDERGROUND_INSIDE))
+ {
+ return VisibilityKind::Partial;
+ }
+ break;
+ default:
+ break;
+ }
+ return VisibilityKind::Visible;
}
- if (imageType & IMAGE_TYPE_TRANSPARENT)
+ /**
+ * Checks if a PaintStruct sprite type is in the filter mask.
+ */
+ static bool PSInteractionTypeIsInFilter(PaintStruct* ps, uint16_t filter)
{
+ if (ps->InteractionItem != ViewportInteractionItem::None && ps->InteractionItem != ViewportInteractionItem::Label
+ && ps->InteractionItem <= ViewportInteractionItem::Banner)
+ {
+ auto mask = EnumToFlag(ps->InteractionItem);
+ if (filter & mask)
+ {
+ return true;
+ }
+ }
return false;
}
- return (*index != 0);
-}
-
-/**
- * rct2: 0x0067933B, 0x00679788, 0x00679C4A, 0x0067A117
- */
-static bool IsPixelPresentRLE(const uint8_t* imgData, const int32_t x, const int32_t y)
-{
- uint16_t lineOffset;
- std::memcpy(&lineOffset, &imgData[y * sizeof(uint16_t)], sizeof(uint16_t));
- const uint8_t* data8 = imgData + lineOffset;
-
- bool lastDataLine = false;
- while (!lastDataLine)
+ /**
+ * rct2: 0x00679236, 0x00679662, 0x00679B0D, 0x00679FF1
+ */
+ static bool IsPixelPresentBMP(
+ const uint32_t imageType, const G1Element* g1, const int32_t x, const int32_t y, const PaletteMap& paletteMap)
{
- int32_t numPixels = *data8++;
- uint8_t pixelRunStart = *data8++;
- lastDataLine = numPixels & 0x80;
- numPixels &= 0x7F;
- data8 += numPixels;
+ uint8_t* index = g1->offset + (y * g1->width) + x;
- if (pixelRunStart <= x && x < pixelRunStart + numPixels)
- return true;
- }
- return false;
-}
-
-/**
- * rct2: 0x00679074
- */
-static bool IsSpriteInteractedWithPaletteSet(
- DrawPixelInfo& dpi, ImageId imageId, const ScreenCoordsXY& coords, const PaletteMap& paletteMap, const uint8_t imageType)
-{
- PROFILED_FUNCTION();
-
- const G1Element* g1 = GfxGetG1Element(imageId);
- if (g1 == nullptr)
- {
- return false;
- }
-
- ZoomLevel zoomLevel = dpi.zoom_level;
- ScreenCoordsXY interactionPoint{ dpi.WorldX(), dpi.WorldY() };
- ScreenCoordsXY origin = coords;
-
- if (dpi.zoom_level > ZoomLevel{ 0 })
- {
- if (g1->flags & G1_FLAG_NO_ZOOM_DRAW)
+ // Needs investigation as it has no consideration for pure BMP maps.
+ if (!(g1->flags & G1_FLAG_HAS_TRANSPARENCY))
{
return false;
}
- while (g1->flags & G1_FLAG_HAS_ZOOM_SPRITE && zoomLevel > ZoomLevel{ 0 })
+ if (imageType & IMAGE_TYPE_REMAP)
{
- imageId = imageId.WithIndex(imageId.GetIndex() - g1->zoomed_offset);
- g1 = GfxGetG1Element(imageId);
- if (g1 == nullptr || g1->flags & G1_FLAG_NO_ZOOM_DRAW)
- {
- return false;
- }
- zoomLevel = zoomLevel - 1;
- interactionPoint.x >>= 1;
- interactionPoint.y >>= 1;
- origin.x >>= 1;
- origin.y >>= 1;
+ return paletteMap[*index] != 0;
}
+
+ if (imageType & IMAGE_TYPE_TRANSPARENT)
+ {
+ return false;
+ }
+
+ return (*index != 0);
}
- origin.x += g1->x_offset;
- origin.y += g1->y_offset;
- interactionPoint -= origin;
-
- if (interactionPoint.x < 0 || interactionPoint.y < 0 || interactionPoint.x >= g1->width || interactionPoint.y >= g1->height)
+ /**
+ * rct2: 0x0067933B, 0x00679788, 0x00679C4A, 0x0067A117
+ */
+ static bool IsPixelPresentRLE(const uint8_t* imgData, const int32_t x, const int32_t y)
{
+ uint16_t lineOffset;
+ std::memcpy(&lineOffset, &imgData[y * sizeof(uint16_t)], sizeof(uint16_t));
+ const uint8_t* data8 = imgData + lineOffset;
+
+ bool lastDataLine = false;
+ while (!lastDataLine)
+ {
+ int32_t numPixels = *data8++;
+ uint8_t pixelRunStart = *data8++;
+ lastDataLine = numPixels & 0x80;
+ numPixels &= 0x7F;
+ data8 += numPixels;
+
+ if (pixelRunStart <= x && x < pixelRunStart + numPixels)
+ return true;
+ }
return false;
}
- if (g1->flags & G1_FLAG_RLE_COMPRESSION)
+ /**
+ * rct2: 0x00679074
+ */
+ static bool IsSpriteInteractedWithPaletteSet(
+ DrawPixelInfo& dpi, ImageId imageId, const ScreenCoordsXY& coords, const PaletteMap& paletteMap,
+ const uint8_t imageType)
{
- return IsPixelPresentRLE(g1->offset, interactionPoint.x, interactionPoint.y);
- }
+ PROFILED_FUNCTION();
- if (!(g1->flags & G1_FLAG_1))
- {
- return IsPixelPresentBMP(imageType, g1, interactionPoint.x, interactionPoint.y, paletteMap);
- }
-
- Guard::Assert(false, "Invalid image type encountered.");
- return false;
-}
-
-/**
- *
- * rct2: 0x00679023
- */
-
-static bool IsSpriteInteractedWith(DrawPixelInfo& dpi, ImageId imageId, const ScreenCoordsXY& coords)
-{
- PROFILED_FUNCTION();
-
- auto paletteMap = PaletteMap::GetDefault();
- uint8_t imageType;
- if (imageId.HasPrimary() || imageId.IsRemap())
- {
- imageType = IMAGE_TYPE_REMAP;
- uint8_t paletteIndex;
- if (imageId.HasSecondary())
+ const G1Element* g1 = GfxGetG1Element(imageId);
+ if (g1 == nullptr)
{
- paletteIndex = imageId.GetPrimary();
+ return false;
+ }
+
+ ZoomLevel zoomLevel = dpi.zoom_level;
+ ScreenCoordsXY interactionPoint{ dpi.WorldX(), dpi.WorldY() };
+ ScreenCoordsXY origin = coords;
+
+ if (dpi.zoom_level > ZoomLevel{ 0 })
+ {
+ if (g1->flags & G1_FLAG_NO_ZOOM_DRAW)
+ {
+ return false;
+ }
+
+ while (g1->flags & G1_FLAG_HAS_ZOOM_SPRITE && zoomLevel > ZoomLevel{ 0 })
+ {
+ imageId = imageId.WithIndex(imageId.GetIndex() - g1->zoomed_offset);
+ g1 = GfxGetG1Element(imageId);
+ if (g1 == nullptr || g1->flags & G1_FLAG_NO_ZOOM_DRAW)
+ {
+ return false;
+ }
+ zoomLevel = zoomLevel - 1;
+ interactionPoint.x >>= 1;
+ interactionPoint.y >>= 1;
+ origin.x >>= 1;
+ origin.y >>= 1;
+ }
+ }
+
+ origin.x += g1->x_offset;
+ origin.y += g1->y_offset;
+ interactionPoint -= origin;
+
+ if (interactionPoint.x < 0 || interactionPoint.y < 0 || interactionPoint.x >= g1->width
+ || interactionPoint.y >= g1->height)
+ {
+ return false;
+ }
+
+ if (g1->flags & G1_FLAG_RLE_COMPRESSION)
+ {
+ return IsPixelPresentRLE(g1->offset, interactionPoint.x, interactionPoint.y);
+ }
+
+ if (!(g1->flags & G1_FLAG_1))
+ {
+ return IsPixelPresentBMP(imageType, g1, interactionPoint.x, interactionPoint.y, paletteMap);
+ }
+
+ Guard::Assert(false, "Invalid image type encountered.");
+ return false;
+ }
+
+ /**
+ *
+ * rct2: 0x00679023
+ */
+
+ static bool IsSpriteInteractedWith(DrawPixelInfo& dpi, ImageId imageId, const ScreenCoordsXY& coords)
+ {
+ PROFILED_FUNCTION();
+
+ auto paletteMap = PaletteMap::GetDefault();
+ uint8_t imageType;
+ if (imageId.HasPrimary() || imageId.IsRemap())
+ {
+ imageType = IMAGE_TYPE_REMAP;
+ uint8_t paletteIndex;
+ if (imageId.HasSecondary())
+ {
+ paletteIndex = imageId.GetPrimary();
+ }
+ else
+ {
+ paletteIndex = imageId.GetRemap();
+ }
+ if (auto pm = GetPaletteMapForColour(paletteIndex); pm.has_value())
+ {
+ paletteMap = pm.value();
+ }
}
else
{
- paletteIndex = imageId.GetRemap();
- }
- if (auto pm = GetPaletteMapForColour(paletteIndex); pm.has_value())
- {
- paletteMap = pm.value();
+ imageType = IMAGE_TYPE_DEFAULT;
}
+ return IsSpriteInteractedWithPaletteSet(dpi, imageId, coords, paletteMap, imageType);
}
- else
+
+ /**
+ *
+ * rct2: 0x0068862C
+ */
+ InteractionInfo SetInteractionInfoFromPaintSession(PaintSession* session, uint32_t viewFlags, uint16_t filter)
{
- imageType = IMAGE_TYPE_DEFAULT;
- }
- return IsSpriteInteractedWithPaletteSet(dpi, imageId, coords, paletteMap, imageType);
-}
+ PROFILED_FUNCTION();
-/**
- *
- * rct2: 0x0068862C
- */
-InteractionInfo SetInteractionInfoFromPaintSession(PaintSession* session, uint32_t viewFlags, uint16_t filter)
-{
- PROFILED_FUNCTION();
+ InteractionInfo info{};
- InteractionInfo info{};
-
- PaintStruct* ps = session->PaintHead;
- while (ps != nullptr)
- {
- PaintStruct* old_ps = ps;
- PaintStruct* next_ps = ps;
- while (next_ps != nullptr)
+ PaintStruct* ps = session->PaintHead;
+ while (ps != nullptr)
{
- ps = next_ps;
- if (IsSpriteInteractedWith(session->DPI, ps->image_id, ps->ScreenPos))
+ PaintStruct* old_ps = ps;
+ PaintStruct* next_ps = ps;
+ while (next_ps != nullptr)
{
- if (PSInteractionTypeIsInFilter(ps, filter)
- && GetPaintStructVisibility(ps, viewFlags) == VisibilityKind::Visible)
+ ps = next_ps;
+ if (IsSpriteInteractedWith(session->DPI, ps->image_id, ps->ScreenPos))
{
- info = { ps };
+ if (PSInteractionTypeIsInFilter(ps, filter)
+ && GetPaintStructVisibility(ps, viewFlags) == VisibilityKind::Visible)
+ {
+ info = { ps };
+ }
}
+ next_ps = ps->Children;
}
- next_ps = ps->Children;
- }
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnull-dereference"
- for (AttachedPaintStruct* attached_ps = ps->Attached; attached_ps != nullptr; attached_ps = attached_ps->NextEntry)
- {
- if (IsSpriteInteractedWith(session->DPI, attached_ps->image_id, ps->ScreenPos + attached_ps->RelativePos))
+ for (AttachedPaintStruct* attached_ps = ps->Attached; attached_ps != nullptr; attached_ps = attached_ps->NextEntry)
{
- if (PSInteractionTypeIsInFilter(ps, filter)
- && GetPaintStructVisibility(ps, viewFlags) == VisibilityKind::Visible)
+ if (IsSpriteInteractedWith(session->DPI, attached_ps->image_id, ps->ScreenPos + attached_ps->RelativePos))
{
- info = { ps };
+ if (PSInteractionTypeIsInFilter(ps, filter)
+ && GetPaintStructVisibility(ps, viewFlags) == VisibilityKind::Visible)
+ {
+ info = { ps };
+ }
}
}
- }
#pragma GCC diagnostic pop
- ps = old_ps->NextQuadrantEntry;
- }
- return info;
-}
-
-/**
- *
- * rct2: 0x00685ADC
- * screenX: eax
- * screenY: ebx
- * flags: edx
- * x: ax
- * y: cx
- * interactionType: bl
- * tileElement: edx
- * viewport: edi
- */
-InteractionInfo GetMapCoordinatesFromPos(const ScreenCoordsXY& screenCoords, int32_t flags)
-{
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- WindowBase* window = windowMgr->FindFromPoint(screenCoords);
- return GetMapCoordinatesFromPosWindow(window, screenCoords, flags);
-}
-
-InteractionInfo GetMapCoordinatesFromPosWindow(WindowBase* window, const ScreenCoordsXY& screenCoords, int32_t flags)
-{
- InteractionInfo info{};
- if (window == nullptr || window->viewport == nullptr)
- {
+ ps = old_ps->NextQuadrantEntry;
+ }
return info;
}
- Viewport* viewport = window->viewport;
- auto viewLoc = screenCoords;
- viewLoc -= viewport->pos;
- if (viewLoc.x >= 0 && viewLoc.x < static_cast(viewport->width) && viewLoc.y >= 0
- && viewLoc.y < static_cast(viewport->height))
+ /**
+ *
+ * rct2: 0x00685ADC
+ * screenX: eax
+ * screenY: ebx
+ * flags: edx
+ * x: ax
+ * y: cx
+ * interactionType: bl
+ * tileElement: edx
+ * viewport: edi
+ */
+ InteractionInfo GetMapCoordinatesFromPos(const ScreenCoordsXY& screenCoords, int32_t flags)
{
- viewLoc.x = viewport->zoom.ApplyTo(viewLoc.x);
- viewLoc.y = viewport->zoom.ApplyTo(viewLoc.y);
- viewLoc += viewport->viewPos;
- if (viewport->zoom > ZoomLevel{ 0 })
- {
- viewLoc.x &= viewport->zoom.ApplyTo(0xFFFFFFFF) & 0xFFFFFFFF;
- viewLoc.y &= viewport->zoom.ApplyTo(0xFFFFFFFF) & 0xFFFFFFFF;
- }
- DrawPixelInfo dpi;
- dpi.zoom_level = viewport->zoom;
- dpi.x = viewport->zoom.ApplyInversedTo(viewLoc.x);
- dpi.y = viewport->zoom.ApplyInversedTo(viewLoc.y);
- dpi.height = 1;
- dpi.width = 1;
-
- PaintSession* session = PaintSessionAlloc(dpi, viewport->flags, viewport->rotation);
- PaintSessionGenerate(*session);
- PaintSessionArrange(*session);
- info = SetInteractionInfoFromPaintSession(session, viewport->flags, flags & 0xFFFF);
- PaintSessionFree(session);
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ WindowBase* window = windowMgr->FindFromPoint(screenCoords);
+ return GetMapCoordinatesFromPosWindow(window, screenCoords, flags);
}
- return info;
-}
-/**
- * screenRect represents 2D map coordinates at zoom 0.
- */
-void ViewportInvalidate(const Viewport* viewport, const ScreenRect& screenRect)
-{
- PROFILED_FUNCTION();
-
- // if unknown viewport visibility, use the containing window to discover the status
- if (viewport->visibility == VisibilityCache::Unknown)
+ InteractionInfo GetMapCoordinatesFromPosWindow(WindowBase* window, const ScreenCoordsXY& screenCoords, int32_t flags)
{
- auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
- auto owner = windowManager->GetOwner(viewport);
- if (owner != nullptr && owner->classification != WindowClass::MainWindow)
+ InteractionInfo info{};
+ if (window == nullptr || window->viewport == nullptr)
{
- // note, window_is_visible will update viewport->visibility, so this should have a low hit count
- if (!WindowIsVisible(*owner))
+ return info;
+ }
+
+ Viewport* viewport = window->viewport;
+ auto viewLoc = screenCoords;
+ viewLoc -= viewport->pos;
+ if (viewLoc.x >= 0 && viewLoc.x < static_cast(viewport->width) && viewLoc.y >= 0
+ && viewLoc.y < static_cast(viewport->height))
+ {
+ viewLoc.x = viewport->zoom.ApplyTo(viewLoc.x);
+ viewLoc.y = viewport->zoom.ApplyTo(viewLoc.y);
+ viewLoc += viewport->viewPos;
+ if (viewport->zoom > ZoomLevel{ 0 })
{
- return;
+ viewLoc.x &= viewport->zoom.ApplyTo(0xFFFFFFFF) & 0xFFFFFFFF;
+ viewLoc.y &= viewport->zoom.ApplyTo(0xFFFFFFFF) & 0xFFFFFFFF;
+ }
+ DrawPixelInfo dpi;
+ dpi.zoom_level = viewport->zoom;
+ dpi.x = viewport->zoom.ApplyInversedTo(viewLoc.x);
+ dpi.y = viewport->zoom.ApplyInversedTo(viewLoc.y);
+ dpi.height = 1;
+ dpi.width = 1;
+
+ PaintSession* session = PaintSessionAlloc(dpi, viewport->flags, viewport->rotation);
+ PaintSessionGenerate(*session);
+ PaintSessionArrange(*session);
+ info = SetInteractionInfoFromPaintSession(session, viewport->flags, flags & 0xFFFF);
+ PaintSessionFree(session);
+ }
+ return info;
+ }
+
+ /**
+ * screenRect represents 2D map coordinates at zoom 0.
+ */
+ void ViewportInvalidate(const Viewport* viewport, const ScreenRect& screenRect)
+ {
+ PROFILED_FUNCTION();
+
+ // if unknown viewport visibility, use the containing window to discover the status
+ if (viewport->visibility == VisibilityCache::Unknown)
+ {
+ auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
+ auto owner = windowManager->GetOwner(viewport);
+ if (owner != nullptr && owner->classification != WindowClass::MainWindow)
+ {
+ // note, window_is_visible will update viewport->visibility, so this should have a low hit count
+ if (!WindowIsVisible(*owner))
+ {
+ return;
+ }
}
}
+
+ if (viewport->visibility == VisibilityCache::Covered)
+ return;
+
+ auto zoom = viewport->zoom;
+ auto viewPos = viewport->viewPos;
+ auto viewportScreenPos = viewport->pos;
+
+ ScreenRect invalidRect = { { zoom.ApplyInversedTo(screenRect.GetLeft() - viewPos.x),
+ zoom.ApplyInversedTo(screenRect.GetTop() - viewPos.y) },
+ { zoom.ApplyInversedTo(screenRect.GetRight() - viewPos.x),
+ zoom.ApplyInversedTo(screenRect.GetBottom() - viewPos.y) } };
+
+ if (invalidRect.GetTop() >= viewport->height || invalidRect.GetBottom() <= 0 || invalidRect.GetLeft() >= viewport->width
+ || invalidRect.GetRight() <= 0)
+ {
+ return;
+ }
+ invalidRect.Point1 += viewportScreenPos;
+ invalidRect.Point2 += viewportScreenPos;
+ GfxSetDirtyBlocks(invalidRect);
}
- if (viewport->visibility == VisibilityCache::Covered)
- return;
-
- auto zoom = viewport->zoom;
- auto viewPos = viewport->viewPos;
- auto viewportScreenPos = viewport->pos;
-
- ScreenRect invalidRect = {
- { zoom.ApplyInversedTo(screenRect.GetLeft() - viewPos.x), zoom.ApplyInversedTo(screenRect.GetTop() - viewPos.y) },
- { zoom.ApplyInversedTo(screenRect.GetRight() - viewPos.x), zoom.ApplyInversedTo(screenRect.GetBottom() - viewPos.y) }
- };
-
- if (invalidRect.GetTop() >= viewport->height || invalidRect.GetBottom() <= 0 || invalidRect.GetLeft() >= viewport->width
- || invalidRect.GetRight() <= 0)
+ static Viewport* ViewportFindFromPoint(const ScreenCoordsXY& screenCoords)
{
- return;
- }
- invalidRect.Point1 += viewportScreenPos;
- invalidRect.Point2 += viewportScreenPos;
- GfxSetDirtyBlocks(invalidRect);
-}
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ WindowBase* w = windowMgr->FindFromPoint(screenCoords);
+ if (w == nullptr)
+ return nullptr;
-static Viewport* ViewportFindFromPoint(const ScreenCoordsXY& screenCoords)
-{
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- WindowBase* w = windowMgr->FindFromPoint(screenCoords);
- if (w == nullptr)
- return nullptr;
-
- Viewport* viewport = w->viewport;
- if (viewport == nullptr)
- return nullptr;
-
- if (viewport->ContainsScreen(screenCoords))
- return viewport;
-
- return nullptr;
-}
-
-/**
- *
- * rct2: 0x00688972
- * In:
- * screen_x: eax
- * screen_y: ebx
- * Out:
- * x: ax
- * y: bx
- * tile_element: edx ?
- * viewport: edi
- */
-std::optional ScreenGetMapXY(const ScreenCoordsXY& screenCoords, Viewport** viewport)
-{
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
-
- // This will get the tile location but we will need the more accuracy
- WindowBase* window = windowMgr->FindFromPoint(screenCoords);
- if (window == nullptr || window->viewport == nullptr)
- {
- return std::nullopt;
- }
- auto myViewport = window->viewport;
- auto info = GetMapCoordinatesFromPosWindow(window, screenCoords, EnumsToFlags(ViewportInteractionItem::Terrain));
- if (info.interactionType == ViewportInteractionItem::None)
- {
- return std::nullopt;
- }
-
- auto start_vp_pos = myViewport->ScreenToViewportCoord(screenCoords);
- CoordsXY cursorMapPos = info.Loc.ToTileCentre();
-
- // Iterates the cursor location to work out exactly where on the tile it is
- for (int32_t i = 0; i < 5; i++)
- {
- int32_t z = TileElementHeight(cursorMapPos);
- cursorMapPos = ViewportPosToMapPos(start_vp_pos, z, myViewport->rotation);
- cursorMapPos.x = std::clamp(cursorMapPos.x, info.Loc.x, info.Loc.x + 31);
- cursorMapPos.y = std::clamp(cursorMapPos.y, info.Loc.y, info.Loc.y + 31);
- }
-
- if (viewport != nullptr)
- *viewport = myViewport;
-
- return cursorMapPos;
-}
-
-/**
- *
- * rct2: 0x006894D4
- */
-std::optional ScreenGetMapXYWithZ(const ScreenCoordsXY& screenCoords, int32_t z)
-{
- Viewport* viewport = ViewportFindFromPoint(screenCoords);
- if (viewport == nullptr)
- {
- return std::nullopt;
- }
-
- auto vpCoords = viewport->ScreenToViewportCoord(screenCoords);
- auto mapPosition = ViewportPosToMapPos(vpCoords, z, viewport->rotation);
- if (!MapIsLocationValid(mapPosition))
- {
- return std::nullopt;
- }
-
- return mapPosition;
-}
-
-/**
- *
- * rct2: 0x00689604
- */
-std::optional ScreenGetMapXYQuadrant(const ScreenCoordsXY& screenCoords, uint8_t* quadrant)
-{
- auto mapCoords = ScreenGetMapXY(screenCoords, nullptr);
- if (!mapCoords.has_value())
- return std::nullopt;
-
- *quadrant = MapGetTileQuadrant(*mapCoords);
- return mapCoords->ToTileStart();
-}
-
-/**
- *
- * rct2: 0x0068964B
- */
-std::optional ScreenGetMapXYQuadrantWithZ(const ScreenCoordsXY& screenCoords, int32_t z, uint8_t* quadrant)
-{
- auto mapCoords = ScreenGetMapXYWithZ(screenCoords, z);
- if (!mapCoords.has_value())
- return std::nullopt;
-
- *quadrant = MapGetTileQuadrant(*mapCoords);
- return mapCoords->ToTileStart();
-}
-
-/**
- *
- * rct2: 0x00689692
- */
-std::optional ScreenGetMapXYSide(const ScreenCoordsXY& screenCoords, uint8_t* side)
-{
- auto mapCoords = ScreenGetMapXY(screenCoords, nullptr);
- if (!mapCoords.has_value())
- return std::nullopt;
-
- *side = MapGetTileSide(*mapCoords);
- return mapCoords->ToTileStart();
-}
-
-/**
- *
- * rct2: 0x006896DC
- */
-std::optional ScreenGetMapXYSideWithZ(const ScreenCoordsXY& screenCoords, int32_t z, uint8_t* side)
-{
- auto mapCoords = ScreenGetMapXYWithZ(screenCoords, z);
- if (!mapCoords.has_value())
- return std::nullopt;
-
- *side = MapGetTileSide(*mapCoords);
- return mapCoords->ToTileStart();
-}
-
-ScreenCoordsXY Translate3DTo2DWithZ(int32_t rotation, const CoordsXYZ& pos)
-{
- auto rotated = pos.Rotate(rotation);
- // Use right shift to avoid issues like #9301
- return ScreenCoordsXY{ rotated.y - rotated.x, ((rotated.x + rotated.y) >> 1) - pos.z };
-}
-
-/**
- * Get current viewport rotation.
- *
- * If an invalid rotation is detected and DEBUG_LEVEL_1 is enabled, an error
- * will be reported.
- *
- * @returns rotation in range 0-3 (inclusive)
- */
-uint8_t GetCurrentRotation()
-{
- auto* viewport = ViewportGetMain();
- if (viewport == nullptr)
- {
- LOG_VERBOSE("No viewport found! Will return 0.");
- return 0;
- }
- uint8_t rotation = viewport->rotation;
- uint8_t rotation_masked = rotation & 3;
-#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
- if (rotation != rotation_masked)
- {
- LOG_ERROR(
- "Found wrong rotation %d! Will return %d instead.", static_cast(rotation),
- static_cast(rotation_masked));
- }
-#endif // DEBUG_LEVEL_1
- return rotation_masked;
-}
-
-int32_t GetHeightMarkerOffset()
-{
- // Height labels in units
- if (Config::Get().general.ShowHeightAsUnits)
- return 0;
-
- // Height labels in feet
- if (Config::Get().general.MeasurementFormat == MeasurementFormat::Imperial)
- return 1 * 256;
-
- // Height labels in metres
- return 2 * 256;
-}
-
-void ViewportSetSavedView()
-{
- WindowBase* w = WindowGetMain();
- if (w != nullptr)
- {
Viewport* viewport = w->viewport;
- auto& gameState = GetGameState();
+ if (viewport == nullptr)
+ return nullptr;
- gameState.SavedView = ScreenCoordsXY{ viewport->ViewWidth() / 2, viewport->ViewHeight() / 2 } + viewport->viewPos;
+ if (viewport->ContainsScreen(screenCoords))
+ return viewport;
- gameState.SavedViewZoom = viewport->zoom;
- gameState.SavedViewRotation = viewport->rotation;
+ return nullptr;
}
-}
+
+ /**
+ *
+ * rct2: 0x00688972
+ * In:
+ * screen_x: eax
+ * screen_y: ebx
+ * Out:
+ * x: ax
+ * y: bx
+ * tile_element: edx ?
+ * viewport: edi
+ */
+ std::optional ScreenGetMapXY(const ScreenCoordsXY& screenCoords, Viewport** viewport)
+ {
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+
+ // This will get the tile location but we will need the more accuracy
+ WindowBase* window = windowMgr->FindFromPoint(screenCoords);
+ if (window == nullptr || window->viewport == nullptr)
+ {
+ return std::nullopt;
+ }
+ auto myViewport = window->viewport;
+ auto info = GetMapCoordinatesFromPosWindow(window, screenCoords, EnumsToFlags(ViewportInteractionItem::Terrain));
+ if (info.interactionType == ViewportInteractionItem::None)
+ {
+ return std::nullopt;
+ }
+
+ auto start_vp_pos = myViewport->ScreenToViewportCoord(screenCoords);
+ CoordsXY cursorMapPos = info.Loc.ToTileCentre();
+
+ // Iterates the cursor location to work out exactly where on the tile it is
+ for (int32_t i = 0; i < 5; i++)
+ {
+ int32_t z = TileElementHeight(cursorMapPos);
+ cursorMapPos = ViewportPosToMapPos(start_vp_pos, z, myViewport->rotation);
+ cursorMapPos.x = std::clamp(cursorMapPos.x, info.Loc.x, info.Loc.x + 31);
+ cursorMapPos.y = std::clamp(cursorMapPos.y, info.Loc.y, info.Loc.y + 31);
+ }
+
+ if (viewport != nullptr)
+ *viewport = myViewport;
+
+ return cursorMapPos;
+ }
+
+ /**
+ *
+ * rct2: 0x006894D4
+ */
+ std::optional ScreenGetMapXYWithZ(const ScreenCoordsXY& screenCoords, int32_t z)
+ {
+ Viewport* viewport = ViewportFindFromPoint(screenCoords);
+ if (viewport == nullptr)
+ {
+ return std::nullopt;
+ }
+
+ auto vpCoords = viewport->ScreenToViewportCoord(screenCoords);
+ auto mapPosition = ViewportPosToMapPos(vpCoords, z, viewport->rotation);
+ if (!MapIsLocationValid(mapPosition))
+ {
+ return std::nullopt;
+ }
+
+ return mapPosition;
+ }
+
+ /**
+ *
+ * rct2: 0x00689604
+ */
+ std::optional ScreenGetMapXYQuadrant(const ScreenCoordsXY& screenCoords, uint8_t* quadrant)
+ {
+ auto mapCoords = ScreenGetMapXY(screenCoords, nullptr);
+ if (!mapCoords.has_value())
+ return std::nullopt;
+
+ *quadrant = MapGetTileQuadrant(*mapCoords);
+ return mapCoords->ToTileStart();
+ }
+
+ /**
+ *
+ * rct2: 0x0068964B
+ */
+ std::optional ScreenGetMapXYQuadrantWithZ(const ScreenCoordsXY& screenCoords, int32_t z, uint8_t* quadrant)
+ {
+ auto mapCoords = ScreenGetMapXYWithZ(screenCoords, z);
+ if (!mapCoords.has_value())
+ return std::nullopt;
+
+ *quadrant = MapGetTileQuadrant(*mapCoords);
+ return mapCoords->ToTileStart();
+ }
+
+ /**
+ *
+ * rct2: 0x00689692
+ */
+ std::optional ScreenGetMapXYSide(const ScreenCoordsXY& screenCoords, uint8_t* side)
+ {
+ auto mapCoords = ScreenGetMapXY(screenCoords, nullptr);
+ if (!mapCoords.has_value())
+ return std::nullopt;
+
+ *side = MapGetTileSide(*mapCoords);
+ return mapCoords->ToTileStart();
+ }
+
+ /**
+ *
+ * rct2: 0x006896DC
+ */
+ std::optional ScreenGetMapXYSideWithZ(const ScreenCoordsXY& screenCoords, int32_t z, uint8_t* side)
+ {
+ auto mapCoords = ScreenGetMapXYWithZ(screenCoords, z);
+ if (!mapCoords.has_value())
+ return std::nullopt;
+
+ *side = MapGetTileSide(*mapCoords);
+ return mapCoords->ToTileStart();
+ }
+
+ ScreenCoordsXY Translate3DTo2DWithZ(int32_t rotation, const CoordsXYZ& pos)
+ {
+ auto rotated = pos.Rotate(rotation);
+ // Use right shift to avoid issues like #9301
+ return ScreenCoordsXY{ rotated.y - rotated.x, ((rotated.x + rotated.y) >> 1) - pos.z };
+ }
+
+ /**
+ * Get current viewport rotation.
+ *
+ * If an invalid rotation is detected and DEBUG_LEVEL_1 is enabled, an error
+ * will be reported.
+ *
+ * @returns rotation in range 0-3 (inclusive)
+ */
+ uint8_t GetCurrentRotation()
+ {
+ auto* viewport = ViewportGetMain();
+ if (viewport == nullptr)
+ {
+ LOG_VERBOSE("No viewport found! Will return 0.");
+ return 0;
+ }
+ uint8_t rotation = viewport->rotation;
+ uint8_t rotation_masked = rotation & 3;
+#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
+ if (rotation != rotation_masked)
+ {
+ LOG_ERROR(
+ "Found wrong rotation %d! Will return %d instead.", static_cast(rotation),
+ static_cast(rotation_masked));
+ }
+#endif // DEBUG_LEVEL_1
+ return rotation_masked;
+ }
+
+ int32_t GetHeightMarkerOffset()
+ {
+ // Height labels in units
+ if (Config::Get().general.ShowHeightAsUnits)
+ return 0;
+
+ // Height labels in feet
+ if (Config::Get().general.MeasurementFormat == MeasurementFormat::Imperial)
+ return 1 * 256;
+
+ // Height labels in metres
+ return 2 * 256;
+ }
+
+ void ViewportSetSavedView()
+ {
+ WindowBase* w = WindowGetMain();
+ if (w != nullptr)
+ {
+ Viewport* viewport = w->viewport;
+ auto& gameState = GetGameState();
+
+ gameState.SavedView = ScreenCoordsXY{ viewport->ViewWidth() / 2, viewport->ViewHeight() / 2 } + viewport->viewPos;
+
+ gameState.SavedViewZoom = viewport->zoom;
+ gameState.SavedViewRotation = viewport->rotation;
+ }
+ }
+} // namespace OpenRCT2
ZoomLevel ZoomLevel::min()
{
diff --git a/src/openrct2/interface/Viewport.h b/src/openrct2/interface/Viewport.h
index 0d9c50c452..3b43670f68 100644
--- a/src/openrct2/interface/Viewport.h
+++ b/src/openrct2/interface/Viewport.h
@@ -20,54 +20,58 @@ struct PaintSession;
struct PaintStruct;
struct DrawPixelInfo;
struct TileElement;
-struct WindowBase;
struct EntityBase;
struct Guest;
struct Staff;
struct PaintEntry;
-// Flags must currenly retain their values to avoid breaking plugins.
-// Values can be changed when plugins move to using named constants.
-enum : uint32_t
+namespace OpenRCT2
{
- VIEWPORT_FLAG_NONE = 0u,
+ struct WindowBase;
- VIEWPORT_FLAG_GRIDLINES = (1u << 7),
- VIEWPORT_FLAG_UNDERGROUND_INSIDE = (1u << 0),
- VIEWPORT_FLAG_HIDE_BASE = (1u << 12),
- VIEWPORT_FLAG_HIDE_VERTICAL = (1u << 13),
+ // Flags must currenly retain their values to avoid breaking plugins.
+ // Values can be changed when plugins move to using named constants.
+ enum : uint32_t
+ {
+ VIEWPORT_FLAG_NONE = 0u,
- VIEWPORT_FLAG_SOUND_ON = (1u << 10),
- VIEWPORT_FLAG_LAND_OWNERSHIP = (1u << 8),
- VIEWPORT_FLAG_CONSTRUCTION_RIGHTS = (1u << 9),
- VIEWPORT_FLAG_HIDE_ENTITIES = (1u << 14),
- VIEWPORT_FLAG_CLIP_VIEW = (1u << 17),
- VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES = (1u << 18),
- VIEWPORT_FLAG_TRANSPARENT_BACKGROUND = (1u << 19),
+ VIEWPORT_FLAG_GRIDLINES = (1u << 7),
+ VIEWPORT_FLAG_UNDERGROUND_INSIDE = (1u << 0),
+ VIEWPORT_FLAG_HIDE_BASE = (1u << 12),
+ VIEWPORT_FLAG_HIDE_VERTICAL = (1u << 13),
- VIEWPORT_FLAG_LAND_HEIGHTS = (1u << 4),
- VIEWPORT_FLAG_TRACK_HEIGHTS = (1u << 5),
- VIEWPORT_FLAG_PATH_HEIGHTS = (1u << 6),
+ VIEWPORT_FLAG_SOUND_ON = (1u << 10),
+ VIEWPORT_FLAG_LAND_OWNERSHIP = (1u << 8),
+ VIEWPORT_FLAG_CONSTRUCTION_RIGHTS = (1u << 9),
+ VIEWPORT_FLAG_HIDE_ENTITIES = (1u << 14),
+ VIEWPORT_FLAG_CLIP_VIEW = (1u << 17),
+ VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES = (1u << 18),
+ VIEWPORT_FLAG_TRANSPARENT_BACKGROUND = (1u << 19),
- VIEWPORT_FLAG_HIDE_RIDES = (1u << 1),
- VIEWPORT_FLAG_HIDE_VEHICLES = (1u << 20),
- VIEWPORT_FLAG_HIDE_VEGETATION = (1u << 21),
- VIEWPORT_FLAG_HIDE_SCENERY = (1u << 2),
- VIEWPORT_FLAG_HIDE_PATHS = (1u << 16),
- VIEWPORT_FLAG_HIDE_SUPPORTS = (1u << 3),
- VIEWPORT_FLAG_HIDE_GUESTS = (1u << 11),
- VIEWPORT_FLAG_HIDE_STAFF = (1u << 23),
+ VIEWPORT_FLAG_LAND_HEIGHTS = (1u << 4),
+ VIEWPORT_FLAG_TRACK_HEIGHTS = (1u << 5),
+ VIEWPORT_FLAG_PATH_HEIGHTS = (1u << 6),
- VIEWPORT_FLAG_INVISIBLE_RIDES = (1u << 24),
- VIEWPORT_FLAG_INVISIBLE_VEHICLES = (1u << 25),
- VIEWPORT_FLAG_INVISIBLE_VEGETATION = (1u << 26),
- VIEWPORT_FLAG_INVISIBLE_SCENERY = (1u << 27),
- VIEWPORT_FLAG_INVISIBLE_PATHS = (1u << 28),
- VIEWPORT_FLAG_INVISIBLE_SUPPORTS = (1u << 29),
+ VIEWPORT_FLAG_HIDE_RIDES = (1u << 1),
+ VIEWPORT_FLAG_HIDE_VEHICLES = (1u << 20),
+ VIEWPORT_FLAG_HIDE_VEGETATION = (1u << 21),
+ VIEWPORT_FLAG_HIDE_SCENERY = (1u << 2),
+ VIEWPORT_FLAG_HIDE_PATHS = (1u << 16),
+ VIEWPORT_FLAG_HIDE_SUPPORTS = (1u << 3),
+ VIEWPORT_FLAG_HIDE_GUESTS = (1u << 11),
+ VIEWPORT_FLAG_HIDE_STAFF = (1u << 23),
- VIEWPORT_FLAG_INDEPEDENT_ROTATION = (1u << 30),
- VIEWPORT_FLAG_RENDERING_INHIBITED = (1u << 31),
-};
+ VIEWPORT_FLAG_INVISIBLE_RIDES = (1u << 24),
+ VIEWPORT_FLAG_INVISIBLE_VEHICLES = (1u << 25),
+ VIEWPORT_FLAG_INVISIBLE_VEGETATION = (1u << 26),
+ VIEWPORT_FLAG_INVISIBLE_SCENERY = (1u << 27),
+ VIEWPORT_FLAG_INVISIBLE_PATHS = (1u << 28),
+ VIEWPORT_FLAG_INVISIBLE_SUPPORTS = (1u << 29),
+
+ VIEWPORT_FLAG_INDEPEDENT_ROTATION = (1u << 30),
+ VIEWPORT_FLAG_RENDERING_INHIBITED = (1u << 31),
+ };
+} // namespace OpenRCT2
enum class VisibilityKind
{
@@ -103,75 +107,78 @@ enum class ViewportVisibility : uint8_t
UndergroundViewGhostOff = 5,
};
-constexpr uint16_t ViewportInteractionItemAll = std::numeric_limits::max();
-
-struct InteractionInfo
+namespace OpenRCT2
{
- InteractionInfo() = default;
- InteractionInfo(const PaintStruct* ps);
- CoordsXY Loc;
- TileElement* Element{};
- EntityBase* Entity{};
- ViewportInteractionItem interactionType = ViewportInteractionItem::None;
-};
+ constexpr uint16_t ViewportInteractionItemAll = std::numeric_limits::max();
-constexpr int32_t kMaxViewportCount = kWindowLimitMax;
+ struct InteractionInfo
+ {
+ InteractionInfo() = default;
+ InteractionInfo(const PaintStruct* ps);
+ CoordsXY Loc;
+ TileElement* Element{};
+ EntityBase* Entity{};
+ ViewportInteractionItem interactionType = ViewportInteractionItem::None;
+ };
-/**
- * A reference counter for whether something is forcing the grid lines to show. When the counter
- * is decremented to 0, the grid lines are hidden.
- */
-extern uint8_t gShowGridLinesRefCount;
-extern uint8_t gShowLandRightsRefCount;
-extern uint8_t gShowConstructionRightsRefCount;
+ constexpr int32_t kMaxViewportCount = kWindowLimitMax;
-// rct2: 0x014234BC
-extern Viewport* g_music_tracking_viewport;
+ /**
+ * A reference counter for whether something is forcing the grid lines to show. When the counter
+ * is decremented to 0, the grid lines are hidden.
+ */
+ extern uint8_t gShowGridLinesRefCount;
+ extern uint8_t gShowLandRightsRefCount;
+ extern uint8_t gShowConstructionRightsRefCount;
-void ViewportInitAll();
-std::optional centre_2d_coordinates(const CoordsXYZ& loc, Viewport* viewport);
-void ViewportCreate(WindowBase* w, const ScreenCoordsXY& screenCoords, int32_t width, int32_t height, const Focus& focus);
-void ViewportRemove(Viewport* viewport);
+ // rct2: 0x014234BC
+ extern Viewport* g_music_tracking_viewport;
-void ViewportsInvalidate(int32_t x, int32_t y, int32_t z0, int32_t z1, ZoomLevel maxZoom);
-void ViewportsInvalidate(const CoordsXYZ& pos, int32_t width, int32_t minHeight, int32_t maxHeight, ZoomLevel maxZoom);
-void ViewportsInvalidate(const ScreenRect& screenRect, ZoomLevel maxZoom = ZoomLevel{ -1 });
-void ViewportUpdatePosition(WindowBase* window);
-void ViewportUpdateSmartFollowGuest(WindowBase* window, const Guest& peep);
-void ViewportRotateSingle(WindowBase* window, int32_t direction);
-void ViewportRotateAll(int32_t direction);
-void ViewportRender(DrawPixelInfo& dpi, const Viewport* viewport);
+ void ViewportInitAll();
+ std::optional centre_2d_coordinates(const CoordsXYZ& loc, Viewport* viewport);
+ void ViewportCreate(WindowBase* w, const ScreenCoordsXY& screenCoords, int32_t width, int32_t height, const Focus& focus);
+ void ViewportRemove(Viewport* viewport);
-CoordsXYZ ViewportAdjustForMapHeight(const ScreenCoordsXY& startCoords, uint8_t rotation);
+ void ViewportsInvalidate(int32_t x, int32_t y, int32_t z0, int32_t z1, ZoomLevel maxZoom);
+ void ViewportsInvalidate(const CoordsXYZ& pos, int32_t width, int32_t minHeight, int32_t maxHeight, ZoomLevel maxZoom);
+ void ViewportsInvalidate(const ScreenRect& screenRect, ZoomLevel maxZoom = ZoomLevel{ -1 });
+ void ViewportUpdatePosition(WindowBase* window);
+ void ViewportUpdateSmartFollowGuest(WindowBase* window, const Guest& peep);
+ void ViewportRotateSingle(WindowBase* window, int32_t direction);
+ void ViewportRotateAll(int32_t direction);
+ void ViewportRender(DrawPixelInfo& dpi, const Viewport* viewport);
-CoordsXY ViewportPosToMapPos(const ScreenCoordsXY& coords, int32_t z, uint8_t rotation);
-std::optional ScreenPosToMapPos(const ScreenCoordsXY& screenCoords, int32_t* direction);
+ CoordsXYZ ViewportAdjustForMapHeight(const ScreenCoordsXY& startCoords, uint8_t rotation);
-void ShowGridlines();
-void HideGridlines();
-void ShowLandRights();
-void HideLandRights();
-void ShowConstructionRights();
-void HideConstructionRights();
-void ViewportSetVisibility(ViewportVisibility mode);
+ CoordsXY ViewportPosToMapPos(const ScreenCoordsXY& coords, int32_t z, uint8_t rotation);
+ std::optional ScreenPosToMapPos(const ScreenCoordsXY& screenCoords, int32_t* direction);
-InteractionInfo GetMapCoordinatesFromPos(const ScreenCoordsXY& screenCoords, int32_t flags);
-InteractionInfo GetMapCoordinatesFromPosWindow(WindowBase* window, const ScreenCoordsXY& screenCoords, int32_t flags);
+ void ShowGridlines();
+ void HideGridlines();
+ void ShowLandRights();
+ void HideLandRights();
+ void ShowConstructionRights();
+ void HideConstructionRights();
+ void ViewportSetVisibility(ViewportVisibility mode);
-InteractionInfo SetInteractionInfoFromPaintSession(PaintSession* session, uint32_t viewFlags, uint16_t filter);
+ InteractionInfo GetMapCoordinatesFromPos(const ScreenCoordsXY& screenCoords, int32_t flags);
+ InteractionInfo GetMapCoordinatesFromPosWindow(WindowBase* window, const ScreenCoordsXY& screenCoords, int32_t flags);
-std::optional ScreenGetMapXY(const ScreenCoordsXY& screenCoords, Viewport** viewport);
-std::optional ScreenGetMapXYWithZ(const ScreenCoordsXY& screenCoords, int32_t z);
-std::optional ScreenGetMapXYQuadrant(const ScreenCoordsXY& screenCoords, uint8_t* quadrant);
-std::optional ScreenGetMapXYQuadrantWithZ(const ScreenCoordsXY& screenCoords, int32_t z, uint8_t* quadrant);
-std::optional ScreenGetMapXYSide(const ScreenCoordsXY& screenCoords, uint8_t* side);
-std::optional ScreenGetMapXYSideWithZ(const ScreenCoordsXY& screenCoords, int32_t z, uint8_t* side);
+ InteractionInfo SetInteractionInfoFromPaintSession(PaintSession* session, uint32_t viewFlags, uint16_t filter);
-ScreenCoordsXY Translate3DTo2DWithZ(int32_t rotation, const CoordsXYZ& pos);
+ std::optional ScreenGetMapXY(const ScreenCoordsXY& screenCoords, Viewport** viewport);
+ std::optional ScreenGetMapXYWithZ(const ScreenCoordsXY& screenCoords, int32_t z);
+ std::optional ScreenGetMapXYQuadrant(const ScreenCoordsXY& screenCoords, uint8_t* quadrant);
+ std::optional ScreenGetMapXYQuadrantWithZ(const ScreenCoordsXY& screenCoords, int32_t z, uint8_t* quadrant);
+ std::optional ScreenGetMapXYSide(const ScreenCoordsXY& screenCoords, uint8_t* side);
+ std::optional ScreenGetMapXYSideWithZ(const ScreenCoordsXY& screenCoords, int32_t z, uint8_t* side);
-uint8_t GetCurrentRotation();
-int32_t GetHeightMarkerOffset();
+ ScreenCoordsXY Translate3DTo2DWithZ(int32_t rotation, const CoordsXYZ& pos);
-void ViewportSetSavedView();
+ uint8_t GetCurrentRotation();
+ int32_t GetHeightMarkerOffset();
-VisibilityKind GetPaintStructVisibility(const PaintStruct* ps, uint32_t viewFlags);
+ void ViewportSetSavedView();
+
+ VisibilityKind GetPaintStructVisibility(const PaintStruct* ps, uint32_t viewFlags);
+} // namespace OpenRCT2
diff --git a/src/openrct2/interface/Widget.h b/src/openrct2/interface/Widget.h
index d4d5b2b106..e89826f95a 100644
--- a/src/openrct2/interface/Widget.h
+++ b/src/openrct2/interface/Widget.h
@@ -9,56 +9,156 @@
#pragma once
+#include "../core/StringTypes.h"
+#include "../drawing/ImageId.hpp"
+#include "../localisation/StringIdType.h"
+#include "../world/Location.hpp"
+
#include
-struct WindowBase;
-
-using WidgetIndex = int16_t;
-
-enum class WindowWidgetType : uint8_t
+namespace OpenRCT2
{
- Empty = 0,
- Frame = 1,
- Resize = 2,
- ImgBtn = 3,
- ColourBtn = 6,
- TrnBtn = 7,
- Tab = 8,
- FlatBtn = 9,
- Button = 10,
- LabelCentred = 12, // Centred text
- TableHeader = 13, // Left-aligned textual button
- Label = 14, // Left-aligned text
- Spinner = 15,
- DropdownMenu = 16,
- Viewport = 17,
- Groupbox = 19,
- Caption = 20,
- CloseBox = 21,
- Scroll = 22,
- Checkbox = 23,
- Placeholder = 25,
- ProgressBar = 29,
- Custom = 28,
- TextBox = 27,
- Last = 26,
-};
+ using WidgetIndex = uint16_t;
+ constexpr WidgetIndex kWidgetIndexNull = 0xFFFF;
-constexpr uint8_t kCloseButtonWidth = 10;
+ enum class WindowWidgetType : uint8_t
+ {
+ Empty = 0,
+ Frame = 1,
+ Resize = 2,
+ ImgBtn = 3,
+ ColourBtn = 6,
+ TrnBtn = 7,
+ Tab = 8,
+ FlatBtn = 9,
+ Button = 10,
+ LabelCentred = 12, // Centred text
+ TableHeader = 13, // Left-aligned textual button
+ Label = 14, // Left-aligned text
+ Spinner = 15,
+ DropdownMenu = 16,
+ Viewport = 17,
+ Groupbox = 19,
+ Caption = 20,
+ CloseBox = 21,
+ Scroll = 22,
+ Checkbox = 23,
+ Placeholder = 25,
+ ProgressBar = 29,
+ Custom = 28,
+ TextBox = 27,
+ };
-constexpr int32_t kScrollableRowHeight = 12;
-constexpr uint8_t kListRowHeight = 12;
-constexpr uint8_t kTableCellHeight = 12;
-constexpr uint8_t kButtonFaceHeight = 12;
-constexpr uint8_t kSpinnerHeight = 12;
-constexpr uint8_t kDropdownHeight = 12;
+ using WidgetFlags = uint32_t;
+ namespace WIDGET_FLAGS
+ {
+ const WidgetFlags TEXT_IS_STRING = 1 << 0;
+ const WidgetFlags IS_PRESSED = 1 << 2;
+ const WidgetFlags IS_DISABLED = 1 << 3;
+ const WidgetFlags TOOLTIP_IS_STRING = 1 << 4;
+ const WidgetFlags IS_HIDDEN = 1 << 5;
+ const WidgetFlags IS_HOLDABLE = 1 << 6;
+ } // namespace WIDGET_FLAGS
-constexpr uint16_t kTextInputSize = 1024;
-constexpr uint16_t kTopToolbarHeight = 27;
+ enum
+ {
+ SCROLL_HORIZONTAL = (1 << 0),
+ SCROLL_VERTICAL = (1 << 1),
+ SCROLL_BOTH = SCROLL_HORIZONTAL | SCROLL_VERTICAL
+ };
-enum
-{
- SCROLL_HORIZONTAL = (1 << 0),
- SCROLL_VERTICAL = (1 << 1),
- SCROLL_BOTH = SCROLL_HORIZONTAL | SCROLL_VERTICAL
-};
+ struct Widget
+ {
+ WindowWidgetType type{};
+ uint8_t colour{};
+ int16_t left{};
+ int16_t right{};
+ int16_t top{};
+ int16_t bottom{};
+ union
+ {
+ uint32_t content;
+ ImageId image{};
+ StringId text;
+ utf8* string;
+ };
+ StringId tooltip{ STR_NONE };
+
+ // New properties
+ WidgetFlags flags{};
+ utf8* sztooltip{};
+
+ int16_t width() const
+ {
+ return right - left;
+ }
+
+ int16_t height() const
+ {
+ return bottom - top;
+ }
+
+ int16_t midX() const
+ {
+ return (left + right) / 2;
+ }
+
+ int16_t midY() const
+ {
+ return (top + bottom) / 2;
+ }
+
+ int16_t textTop() const
+ {
+ if (height() >= 10)
+ return std::max(top, top + (height() / 2) - 5);
+
+ return top - 1;
+ }
+
+ void moveRight(int32_t amount)
+ {
+ left += amount;
+ right += amount;
+ }
+
+ void moveDown(int32_t amount)
+ {
+ top += amount;
+ bottom += amount;
+ }
+
+ void moveTo(ScreenCoordsXY coords)
+ {
+ moveRight(coords.x - left);
+ moveDown(coords.y - top);
+ }
+
+ void moveToX(int16_t x)
+ {
+ moveRight(x - left);
+ }
+
+ void moveToY(int16_t y)
+ {
+ moveDown(y - top);
+ }
+
+ bool IsVisible() const
+ {
+ return !(flags & OpenRCT2::WIDGET_FLAGS::IS_HIDDEN);
+ }
+ };
+
+ constexpr uint8_t kCloseButtonWidth = 10;
+
+ constexpr int32_t kScrollableRowHeight = 12;
+ constexpr uint8_t kListRowHeight = 12;
+ constexpr uint8_t kTableCellHeight = 12;
+ constexpr uint8_t kButtonFaceHeight = 12;
+ constexpr uint8_t kSpinnerHeight = 12;
+ constexpr uint8_t kDropdownHeight = 12;
+
+ constexpr uint16_t kTextInputSize = 1024;
+ constexpr uint16_t kTopToolbarHeight = 27;
+} // namespace OpenRCT2
diff --git a/src/openrct2/interface/Window.cpp b/src/openrct2/interface/Window.cpp
index ffc5fc09a2..82e1285862 100644
--- a/src/openrct2/interface/Window.cpp
+++ b/src/openrct2/interface/Window.cpp
@@ -39,22 +39,23 @@
#include
#include
-using namespace OpenRCT2;
+namespace OpenRCT2
+{
-std::list> g_window_list;
-WindowBase* gWindowAudioExclusive;
+ std::list> g_window_list;
+ WindowBase* gWindowAudioExclusive;
-WindowCloseModifier gLastCloseModifier = { { WindowClass::Null, 0 }, CloseWindowModifier::None };
+ WindowCloseModifier gLastCloseModifier = { { WindowClass::Null, 0 }, CloseWindowModifier::None };
-uint32_t gWindowUpdateTicks;
-colour_t gCurrentWindowColours[3];
+ uint32_t gWindowUpdateTicks;
+ colour_t gCurrentWindowColours[3];
-Tool gCurrentToolId;
-WidgetRef gCurrentToolWidget;
+ Tool gCurrentToolId;
+ WidgetRef gCurrentToolWidget;
-// converted from uint16_t values at 0x009A41EC - 0x009A4230
-// these are percentage coordinates of the viewport to centre to, if a window is obscuring a location, the next is tried
-// clang-format off
+ // converted from uint16_t values at 0x009A41EC - 0x009A4230
+ // these are percentage coordinates of the viewport to centre to, if a window is obscuring a location, the next is tried
+ // clang-format off
static constexpr float window_scroll_locations[][2] = {
{ 0.5f, 0.5f },
{ 0.75f, 0.5f },
@@ -74,1261 +75,1267 @@ static constexpr float window_scroll_locations[][2] = {
{ 0.125f, 0.875f },
{ 0.125f, 0.125f },
};
-// clang-format on
+ // clang-format on
-namespace OpenRCT2::WindowCloseFlags
-{
- static constexpr uint32_t None = 0;
- static constexpr uint32_t CloseSingle = (1 << 0);
-} // namespace OpenRCT2::WindowCloseFlags
-
-static void WindowDrawCore(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom);
-static void WindowDrawSingle(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom);
-
-std::list>::iterator WindowGetIterator(const WindowBase* w)
-{
- return std::find_if(g_window_list.begin(), g_window_list.end(), [w](const std::shared_ptr& w2) -> bool {
- return w == w2.get();
- });
-}
-
-void WindowVisitEach(std::function func)
-{
- for (auto& w : g_window_list)
+ namespace WindowCloseFlags
{
- if (w->flags & WF_DEAD)
- continue;
- func(w.get());
- }
-}
+ static constexpr uint32_t None = 0;
+ static constexpr uint32_t CloseSingle = (1 << 0);
+ } // namespace WindowCloseFlags
-void WindowSetFlagForAllViewports(uint32_t viewportFlag, bool enabled)
-{
- WindowVisitEach([&](WindowBase* w) {
- if (w->viewport != nullptr)
- {
- if (enabled)
- w->viewport->flags |= viewportFlag;
- else
- w->viewport->flags &= ~viewportFlag;
- }
- });
-}
+ static void WindowDrawCore(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom);
+ static void WindowDrawSingle(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom);
-/**
- *
- * rct2: 0x006ED7B0
- */
-void WindowDispatchUpdateAll()
-{
- // gTooltipNotShownTicks++;
- WindowVisitEach([&](WindowBase* w) { w->OnUpdate(); });
-}
-
-void WindowUpdateAllViewports()
-{
- WindowVisitEach([&](WindowBase* w) {
- if (w->viewport != nullptr && WindowIsVisible(*w))
- {
- ViewportUpdatePosition(w);
- }
- });
-}
-
-/**
- *
- * rct2: 0x006E77A1
- */
-void WindowUpdateAll()
-{
- // Remove all windows in g_window_list that have the WF_DEAD flag
- g_window_list.remove_if([](auto&& w) -> bool { return w->flags & WF_DEAD; });
-
- // Periodic update happens every second so 40 ticks.
- if (gCurrentRealTimeTicks >= gWindowUpdateTicks)
+ std::list>::iterator WindowGetIterator(const WindowBase* w)
{
- gWindowUpdateTicks = gCurrentRealTimeTicks + kGameUpdateFPS;
-
- WindowVisitEach([](WindowBase* w) { w->OnPeriodicUpdate(); });
+ return std::find_if(g_window_list.begin(), g_window_list.end(), [w](const std::shared_ptr& w2) -> bool {
+ return w == w2.get();
+ });
}
- // Border flash invalidation
- WindowVisitEach([](WindowBase* w) {
- if (w->flags & WF_WHITE_BORDER_MASK)
- {
- w->flags -= WF_WHITE_BORDER_ONE;
- if (!(w->flags & WF_WHITE_BORDER_MASK))
- {
- w->Invalidate();
- }
- }
- });
-
- auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
- windowManager->UpdateMouseWheel();
-}
-
-void WindowNotifyLanguageChange()
-{
- WindowVisitEach([&](WindowBase* w) { w->OnLanguageChange(); });
-}
-
-static void WindowCloseSurplus(int32_t cap, WindowClass avoid_classification)
-{
- // find the amount of windows that are currently open
- auto count = static_cast(g_window_list.size());
- // difference between amount open and cap = amount to close
- auto diff = count - kWindowLimitReserved - cap;
- for (auto i = 0; i < diff; i++)
+ void WindowVisitEach(std::function func)
{
- // iterates through the list until it finds the newest window, or a window that can be closed
- WindowBase* foundW{};
for (auto& w : g_window_list)
{
if (w->flags & WF_DEAD)
continue;
- if (!(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT | WF_NO_AUTO_CLOSE)))
+ func(w.get());
+ }
+ }
+
+ void WindowSetFlagForAllViewports(uint32_t viewportFlag, bool enabled)
+ {
+ WindowVisitEach([&](WindowBase* w) {
+ if (w->viewport != nullptr)
{
- foundW = w.get();
- break;
+ if (enabled)
+ w->viewport->flags |= viewportFlag;
+ else
+ w->viewport->flags &= ~viewportFlag;
}
- }
- // skip window if window matches specified WindowClass (as user may be modifying via options)
- if (avoid_classification != WindowClass::Null && foundW != nullptr && foundW->classification == avoid_classification)
- {
- continue;
- }
- WindowClose(*foundW);
+ });
}
-}
-/*
- * Changes the maximum amount of windows allowed
- */
-void WindowSetWindowLimit(int32_t value)
-{
- int32_t prev = Config::Get().general.WindowLimit;
- int32_t val = std::clamp(value, kWindowLimitMin, kWindowLimitMax);
- Config::Get().general.WindowLimit = val;
- Config::Save();
- // Checks if value decreases and then closes surplus
- // windows if one sets a limit lower than the number of windows open
- if (val < prev)
+ /**
+ *
+ * rct2: 0x006ED7B0
+ */
+ void WindowDispatchUpdateAll()
{
- WindowCloseSurplus(val, WindowClass::Options);
+ // gTooltipNotShownTicks++;
+ WindowVisitEach([&](WindowBase* w) { w->OnUpdate(); });
}
-}
-/**
- * Closes the specified window.
- * rct2: 0x006ECD4C
- *
- * @param window The window to close (esi).
- */
-void WindowClose(WindowBase& w)
-{
- w.OnClose();
-
- // Remove viewport
- w.RemoveViewport();
-
- // Invalidate the window (area)
- w.Invalidate();
-
- w.flags |= WF_DEAD;
-}
-
-template
-static void WindowCloseByCondition(TPred pred, uint32_t flags = WindowCloseFlags::None)
-{
- for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); ++it)
+ void WindowUpdateAllViewports()
{
- auto& wnd = *(*it);
- if (wnd.flags & WF_DEAD)
- continue;
-
- if (pred(&wnd))
- {
- WindowClose(wnd);
- if (flags & WindowCloseFlags::CloseSingle)
+ WindowVisitEach([&](WindowBase* w) {
+ if (w->viewport != nullptr && WindowIsVisible(*w))
{
- return;
+ ViewportUpdatePosition(w);
}
- }
- }
-}
-
-/**
- * Closes all windows with the specified window class.
- * rct2: 0x006ECCF4
- * @param cls (cl) with bit 15 set
- */
-void WindowCloseByClass(WindowClass cls)
-{
- WindowCloseByCondition([&](WindowBase* w) -> bool { return w->classification == cls; });
-}
-
-/**
- * Closes all windows with specified window class and number.
- * rct2: 0x006ECCF4
- * @param cls (cl) without bit 15 set
- * @param number (dx)
- */
-void WindowCloseByNumber(WindowClass cls, rct_windownumber number)
-{
- WindowCloseByCondition([cls, number](WindowBase* w) -> bool { return w->classification == cls && w->number == number; });
-}
-
-// TODO: Refactor this to use variant once the new window class is done.
-void WindowCloseByNumber(WindowClass cls, EntityId number)
-{
- WindowCloseByNumber(cls, static_cast(number.ToUnderlying()));
-}
-
-/**
- * Closes the top-most window
- *
- * rct2: 0x006E403C
- */
-void WindowCloseTop()
-{
- WindowCloseByClass(WindowClass::Dropdown);
-
- if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR)
- {
- if (GetGameState().EditorStep != EditorStep::LandscapeEditor)
- return;
+ });
}
- auto pred = [](WindowBase* w) -> bool { return !(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)); };
- WindowCloseByCondition(pred, WindowCloseFlags::CloseSingle);
-}
-
-/**
- * Closes all open windows
- *
- * rct2: 0x006EE927
- */
-void WindowCloseAll()
-{
- WindowCloseByClass(WindowClass::Dropdown);
- WindowCloseByCondition([](WindowBase* w) -> bool { return !(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)); });
-}
-
-void WindowCloseAllExceptClass(WindowClass cls)
-{
- WindowCloseByClass(WindowClass::Dropdown);
- WindowCloseByCondition([cls](WindowBase* w) -> bool {
- return w->classification != cls && !(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT));
- });
-}
-
-/**
- * Closes all windows, save for those having any of the passed flags.
- */
-void WindowCloseAllExceptFlags(uint16_t flags)
-{
- WindowCloseByCondition([flags](WindowBase* w) -> bool { return !(w->flags & flags); });
-}
-
-/**
- * Closes all windows except the specified window number and class.
- * @param number (dx)
- * @param cls (cl) without bit 15 set
- */
-void WindowCloseAllExceptNumberAndClass(rct_windownumber number, WindowClass cls)
-{
- WindowCloseByClass(WindowClass::Dropdown);
- WindowCloseByCondition([cls, number](WindowBase* w) -> bool {
- return (!(w->number == number && w->classification == cls) && !(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)));
- });
-}
-
-/**
- * Invalidates the specified window.
- * rct2: 0x006EB13A
- *
- * @param window The window to invalidate (esi).
- */
-template
-static void WindowInvalidateByCondition(TPred pred)
-{
- WindowVisitEach([pred](WindowBase* w) {
- if (pred(w))
- {
- w->Invalidate();
- }
- });
-}
-
-/**
- * Invalidates all windows with the specified window class.
- * rct2: 0x006EC3AC
- * @param cls (al) with bit 14 set
- */
-void WindowInvalidateByClass(WindowClass cls)
-{
- WindowInvalidateByCondition([cls](WindowBase* w) -> bool { return w->classification == cls; });
-}
-
-/**
- * Invalidates all windows with the specified window class and number.
- * rct2: 0x006EC3AC
- */
-void WindowInvalidateByNumber(WindowClass cls, rct_windownumber number)
-{
- WindowInvalidateByCondition(
- [cls, number](WindowBase* w) -> bool { return w->classification == cls && w->number == number; });
-}
-
-// TODO: Use variant for this once the window framework is done.
-void WindowInvalidateByNumber(WindowClass cls, EntityId id)
-{
- WindowInvalidateByNumber(cls, static_cast(id.ToUnderlying()));
-}
-
-/**
- * Invalidates all windows.
- */
-void WindowInvalidateAll()
-{
- WindowVisitEach([](WindowBase* w) { w->Invalidate(); });
-}
-
-/**
- * Invalidates the specified widget of a window.
- * rct2: 0x006EC402
- */
-void WidgetInvalidate(WindowBase& w, WidgetIndex widgetIndex)
-{
-#ifdef DEBUG
- for (int32_t i = 0; i <= widgetIndex; i++)
+ /**
+ *
+ * rct2: 0x006E77A1
+ */
+ void WindowUpdateAll()
{
- assert(w.widgets[i].type != WindowWidgetType::Last);
- }
-#endif
+ // Remove all windows in g_window_list that have the WF_DEAD flag
+ g_window_list.remove_if([](auto&& w) -> bool { return w->flags & WF_DEAD; });
- const auto& widget = w.widgets[widgetIndex];
- if (widget.left == -2)
- return;
-
- GfxSetDirtyBlocks({ { w.windowPos + ScreenCoordsXY{ widget.left, widget.top } },
- { w.windowPos + ScreenCoordsXY{ widget.right + 1, widget.bottom + 1 } } });
-}
-
-template
-static void widget_invalidate_by_condition(TPred pred)
-{
- WindowVisitEach([pred](WindowBase* w) {
- if (pred(w))
+ // Periodic update happens every second so 40 ticks.
+ if (gCurrentRealTimeTicks >= gWindowUpdateTicks)
{
- w->Invalidate();
+ gWindowUpdateTicks = gCurrentRealTimeTicks + kGameUpdateFPS;
+
+ WindowVisitEach([](WindowBase* w) { w->OnPeriodicUpdate(); });
}
- });
-}
-/**
- * Invalidates the specified widget of all windows that match the specified window class.
- */
-void WidgetInvalidateByClass(WindowClass cls, WidgetIndex widgetIndex)
-{
- WindowVisitEach([cls, widgetIndex](WindowBase* w) {
- if (w->classification == cls)
- {
- WidgetInvalidate(*w, widgetIndex);
- }
- });
-}
-
-/**
- * Invalidates the specified widget of all windows that match the specified window class and number.
- * rct2: 0x006EC3AC
- */
-void WidgetInvalidateByNumber(WindowClass cls, rct_windownumber number, WidgetIndex widgetIndex)
-{
- WindowVisitEach([cls, number, widgetIndex](WindowBase* w) {
- if (w->classification == cls && w->number == number)
- {
- WidgetInvalidate(*w, widgetIndex);
- }
- });
-}
-
-int32_t WindowGetScrollDataIndex(const WindowBase& w, WidgetIndex widget_index)
-{
- int32_t i, result;
-
- result = 0;
- for (i = 0; i < widget_index; i++)
- {
- const auto& widget = w.widgets[i];
- if (widget.type == WindowWidgetType::Scroll)
- result++;
- }
- return result;
-}
-
-/**
- *
- * rct2: 0x006ECDA4
- */
-WindowBase* WindowBringToFront(WindowBase& w)
-{
- if (!(w.flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)))
- {
- auto itSourcePos = WindowGetIterator(&w);
- if (itSourcePos != g_window_list.end())
- {
- // Insert in front of the first non-stick-to-front window
- auto itDestPos = g_window_list.begin();
- for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++)
+ // Border flash invalidation
+ WindowVisitEach([](WindowBase* w) {
+ if (w->flags & WF_WHITE_BORDER_MASK)
{
- auto& w2 = *it;
- if (!(w2->flags & WF_STICK_TO_FRONT))
+ w->flags -= WF_WHITE_BORDER_ONE;
+ if (!(w->flags & WF_WHITE_BORDER_MASK))
{
- itDestPos = it.base();
+ w->Invalidate();
+ }
+ }
+ });
+
+ auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
+ windowManager->UpdateMouseWheel();
+ }
+
+ void WindowNotifyLanguageChange()
+ {
+ WindowVisitEach([&](WindowBase* w) { w->OnLanguageChange(); });
+ }
+
+ static void WindowCloseSurplus(int32_t cap, WindowClass avoid_classification)
+ {
+ // find the amount of windows that are currently open
+ auto count = static_cast(g_window_list.size());
+ // difference between amount open and cap = amount to close
+ auto diff = count - kWindowLimitReserved - cap;
+ for (auto i = 0; i < diff; i++)
+ {
+ // iterates through the list until it finds the newest window, or a window that can be closed
+ WindowBase* foundW{};
+ for (auto& w : g_window_list)
+ {
+ if (w->flags & WF_DEAD)
+ continue;
+ if (!(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT | WF_NO_AUTO_CLOSE)))
+ {
+ foundW = w.get();
break;
}
}
-
- g_window_list.splice(itDestPos, g_window_list, itSourcePos);
- w.Invalidate();
-
- if (w.windowPos.x + w.width < 20)
+ // skip window if window matches specified WindowClass (as user may be modifying via options)
+ if (avoid_classification != WindowClass::Null && foundW != nullptr
+ && foundW->classification == avoid_classification)
{
- int32_t i = 20 - w.windowPos.x;
- w.windowPos.x += i;
- if (w.viewport != nullptr)
- w.viewport->pos.x += i;
- w.Invalidate();
+ continue;
}
+ WindowClose(*foundW);
}
}
- return &w;
-}
-WindowBase* WindowBringToFrontByClassWithFlags(WindowClass cls, uint16_t flags)
-{
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- WindowBase* w = windowMgr->FindByClass(cls);
- if (w != nullptr)
+ /*
+ * Changes the maximum amount of windows allowed
+ */
+ void WindowSetWindowLimit(int32_t value)
{
- w->flags |= flags;
- w->Invalidate();
- w = WindowBringToFront(*w);
- }
-
- return w;
-}
-
-WindowBase* WindowBringToFrontByClass(WindowClass cls)
-{
- return WindowBringToFrontByClassWithFlags(cls, WF_WHITE_BORDER_MASK);
-}
-
-/**
- *
- * rct2: 0x006ED78A
- * cls (cl)
- * number (dx)
- */
-WindowBase* WindowBringToFrontByNumber(WindowClass cls, rct_windownumber number)
-{
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- WindowBase* w = windowMgr->FindByNumber(cls, number);
- if (w != nullptr)
- {
- w->flags |= WF_WHITE_BORDER_MASK;
- w->Invalidate();
- w = WindowBringToFront(*w);
- }
-
- return w;
-}
-
-/**
- *
- * rct2: 0x006EE65A
- */
-void WindowPushOthersRight(WindowBase& window)
-{
- WindowVisitEach([&window](WindowBase* w) {
- if (w == &window)
- return;
- if (w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT))
- return;
- if (w->windowPos.x >= window.windowPos.x + window.width)
- return;
- if (w->windowPos.x + w->width <= window.windowPos.x)
- return;
- if (w->windowPos.y >= window.windowPos.y + window.height)
- return;
- if (w->windowPos.y + w->height <= window.windowPos.y)
- return;
-
- w->Invalidate();
- if (window.windowPos.x + window.width + 13 >= ContextGetWidth())
- return;
- auto push_amount = window.windowPos.x + window.width - w->windowPos.x + 3;
- w->windowPos.x += push_amount;
- w->Invalidate();
- if (w->viewport != nullptr)
- w->viewport->pos.x += push_amount;
- });
-}
-
-/**
- *
- * rct2: 0x006EE6EA
- */
-void WindowPushOthersBelow(WindowBase& w1)
-{
- // Enumerate through all other windows
- WindowVisitEach([&w1](WindowBase* w2) {
- if (&w1 == w2)
- return;
- // ?
- if (w2->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT))
- return;
- // Check if w2 intersects with w1
- if (w2->windowPos.x > (w1.windowPos.x + w1.width) || w2->windowPos.x + w2->width < w1.windowPos.x)
- return;
- if (w2->windowPos.y > (w1.windowPos.y + w1.height) || w2->windowPos.y + w2->height < w1.windowPos.y)
- return;
-
- // Check if there is room to push it down
- if (w1.windowPos.y + w1.height + 80 >= ContextGetHeight())
- return;
-
- // Invalidate the window's current area
- w2->Invalidate();
-
- int32_t push_amount = w1.windowPos.y + w1.height - w2->windowPos.y + 3;
- w2->windowPos.y += push_amount;
-
- // Invalidate the window's new area
- w2->Invalidate();
-
- // Update viewport position if necessary
- if (w2->viewport != nullptr)
- w2->viewport->pos.y += push_amount;
- });
-}
-
-/**
- *
- * rct2: 0x006EE2E4
- */
-WindowBase* WindowGetMain()
-{
- for (auto& w : g_window_list)
- {
- if (w->flags & WF_DEAD)
- continue;
- if (w->classification == WindowClass::MainWindow)
+ int32_t prev = Config::Get().general.WindowLimit;
+ int32_t val = std::clamp(value, kWindowLimitMin, kWindowLimitMax);
+ Config::Get().general.WindowLimit = val;
+ Config::Save();
+ // Checks if value decreases and then closes surplus
+ // windows if one sets a limit lower than the number of windows open
+ if (val < prev)
{
- return w.get();
+ WindowCloseSurplus(val, WindowClass::Options);
}
}
- return nullptr;
-}
-/**
- *
- * rct2: 0x006E7C9C
- * @param w (esi)
- * @param x (eax)
- * @param y (ecx)
- * @param z (edx)
- */
-void WindowScrollToLocation(WindowBase& w, const CoordsXYZ& coords)
-{
- WindowUnfollowSprite(w);
- if (w.viewport != nullptr)
+ /**
+ * Closes the specified window.
+ * rct2: 0x006ECD4C
+ *
+ * @param window The window to close (esi).
+ */
+ void WindowClose(WindowBase& w)
{
- int16_t height = TileElementHeight(coords);
- if (coords.z < height - 16)
+ w.OnClose();
+
+ // Remove viewport
+ w.RemoveViewport();
+
+ // Invalidate the window (area)
+ w.Invalidate();
+
+ w.flags |= WF_DEAD;
+ }
+
+ template
+ static void WindowCloseByCondition(TPred pred, uint32_t flags = WindowCloseFlags::None)
+ {
+ for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); ++it)
{
- if (!(w.viewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE))
+ auto& wnd = *(*it);
+ if (wnd.flags & WF_DEAD)
+ continue;
+
+ if (pred(&wnd))
{
- w.viewport->flags |= VIEWPORT_FLAG_UNDERGROUND_INSIDE;
- w.Invalidate();
- }
- }
- else
- {
- if (w.viewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE)
- {
- w.viewport->flags &= ~VIEWPORT_FLAG_UNDERGROUND_INSIDE;
- w.Invalidate();
- }
- }
-
- auto screenCoords = Translate3DTo2DWithZ(w.viewport->rotation, coords);
-
- int32_t i = 0;
- if (!(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO))
- {
- bool found = false;
- while (!found)
- {
- auto x2 = w.viewport->pos.x + static_cast(w.viewport->width * window_scroll_locations[i][0]);
- auto y2 = w.viewport->pos.y + static_cast(w.viewport->height * window_scroll_locations[i][1]);
-
- auto it = WindowGetIterator(&w);
- for (; it != g_window_list.end(); it++)
+ WindowClose(wnd);
+ if (flags & WindowCloseFlags::CloseSingle)
{
- auto w2 = (*it).get();
- auto x1 = w2->windowPos.x - 10;
- auto y1 = w2->windowPos.y - 10;
- if (x2 >= x1 && x2 <= w2->width + x1 + 20)
+ return;
+ }
+ }
+ }
+ }
+
+ /**
+ * Closes all windows with the specified window class.
+ * rct2: 0x006ECCF4
+ * @param cls (cl) with bit 15 set
+ */
+ void WindowCloseByClass(WindowClass cls)
+ {
+ WindowCloseByCondition([&](WindowBase* w) -> bool { return w->classification == cls; });
+ }
+
+ /**
+ * Closes all windows with specified window class and number.
+ * rct2: 0x006ECCF4
+ * @param cls (cl) without bit 15 set
+ * @param number (dx)
+ */
+ void WindowCloseByNumber(WindowClass cls, rct_windownumber number)
+ {
+ WindowCloseByCondition(
+ [cls, number](WindowBase* w) -> bool { return w->classification == cls && w->number == number; });
+ }
+
+ // TODO: Refactor this to use variant once the new window class is done.
+ void WindowCloseByNumber(WindowClass cls, EntityId number)
+ {
+ WindowCloseByNumber(cls, static_cast(number.ToUnderlying()));
+ }
+
+ /**
+ * Closes the top-most window
+ *
+ * rct2: 0x006E403C
+ */
+ void WindowCloseTop()
+ {
+ WindowCloseByClass(WindowClass::Dropdown);
+
+ if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR)
+ {
+ if (GetGameState().EditorStep != EditorStep::LandscapeEditor)
+ return;
+ }
+
+ auto pred = [](WindowBase* w) -> bool { return !(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)); };
+ WindowCloseByCondition(pred, WindowCloseFlags::CloseSingle);
+ }
+
+ /**
+ * Closes all open windows
+ *
+ * rct2: 0x006EE927
+ */
+ void WindowCloseAll()
+ {
+ WindowCloseByClass(WindowClass::Dropdown);
+ WindowCloseByCondition([](WindowBase* w) -> bool { return !(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)); });
+ }
+
+ void WindowCloseAllExceptClass(WindowClass cls)
+ {
+ WindowCloseByClass(WindowClass::Dropdown);
+ WindowCloseByCondition([cls](WindowBase* w) -> bool {
+ return w->classification != cls && !(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT));
+ });
+ }
+
+ /**
+ * Closes all windows, save for those having any of the passed flags.
+ */
+ void WindowCloseAllExceptFlags(uint16_t flags)
+ {
+ WindowCloseByCondition([flags](WindowBase* w) -> bool { return !(w->flags & flags); });
+ }
+
+ /**
+ * Closes all windows except the specified window number and class.
+ * @param number (dx)
+ * @param cls (cl) without bit 15 set
+ */
+ void WindowCloseAllExceptNumberAndClass(rct_windownumber number, WindowClass cls)
+ {
+ WindowCloseByClass(WindowClass::Dropdown);
+ WindowCloseByCondition([cls, number](WindowBase* w) -> bool {
+ return (!(w->number == number && w->classification == cls) && !(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)));
+ });
+ }
+
+ /**
+ * Invalidates the specified window.
+ * rct2: 0x006EB13A
+ *
+ * @param window The window to invalidate (esi).
+ */
+ template
+ static void WindowInvalidateByCondition(TPred pred)
+ {
+ WindowVisitEach([pred](WindowBase* w) {
+ if (pred(w))
+ {
+ w->Invalidate();
+ }
+ });
+ }
+
+ /**
+ * Invalidates all windows with the specified window class.
+ * rct2: 0x006EC3AC
+ * @param cls (al) with bit 14 set
+ */
+ void WindowInvalidateByClass(WindowClass cls)
+ {
+ WindowInvalidateByCondition([cls](WindowBase* w) -> bool { return w->classification == cls; });
+ }
+
+ /**
+ * Invalidates all windows with the specified window class and number.
+ * rct2: 0x006EC3AC
+ */
+ void WindowInvalidateByNumber(WindowClass cls, rct_windownumber number)
+ {
+ WindowInvalidateByCondition(
+ [cls, number](WindowBase* w) -> bool { return w->classification == cls && w->number == number; });
+ }
+
+ // TODO: Use variant for this once the window framework is done.
+ void WindowInvalidateByNumber(WindowClass cls, EntityId id)
+ {
+ WindowInvalidateByNumber(cls, static_cast(id.ToUnderlying()));
+ }
+
+ /**
+ * Invalidates all windows.
+ */
+ void WindowInvalidateAll()
+ {
+ WindowVisitEach([](WindowBase* w) { w->Invalidate(); });
+ }
+
+ /**
+ * Invalidates the specified widget of a window.
+ * rct2: 0x006EC402
+ */
+ void WidgetInvalidate(WindowBase& w, WidgetIndex widgetIndex)
+ {
+ if (w.widgets.empty())
+ {
+ // This might be called before the window is fully created.
+ return;
+ }
+
+ assert(widgetIndex < w.widgets.size());
+
+ const auto& widget = w.widgets[widgetIndex];
+ if (widget.left == -2)
+ return;
+
+ GfxSetDirtyBlocks({ { w.windowPos + ScreenCoordsXY{ widget.left, widget.top } },
+ { w.windowPos + ScreenCoordsXY{ widget.right + 1, widget.bottom + 1 } } });
+ }
+
+ template
+ static void widget_invalidate_by_condition(TPred pred)
+ {
+ WindowVisitEach([pred](WindowBase* w) {
+ if (pred(w))
+ {
+ w->Invalidate();
+ }
+ });
+ }
+
+ /**
+ * Invalidates the specified widget of all windows that match the specified window class.
+ */
+ void WidgetInvalidateByClass(WindowClass cls, WidgetIndex widgetIndex)
+ {
+ WindowVisitEach([cls, widgetIndex](WindowBase* w) {
+ if (w->classification == cls)
+ {
+ WidgetInvalidate(*w, widgetIndex);
+ }
+ });
+ }
+
+ /**
+ * Invalidates the specified widget of all windows that match the specified window class and number.
+ * rct2: 0x006EC3AC
+ */
+ void WidgetInvalidateByNumber(WindowClass cls, rct_windownumber number, WidgetIndex widgetIndex)
+ {
+ WindowVisitEach([cls, number, widgetIndex](WindowBase* w) {
+ if (w->classification == cls && w->number == number)
+ {
+ WidgetInvalidate(*w, widgetIndex);
+ }
+ });
+ }
+
+ int32_t WindowGetScrollDataIndex(const WindowBase& w, WidgetIndex widget_index)
+ {
+ int32_t i, result;
+
+ result = 0;
+ for (i = 0; i < widget_index; i++)
+ {
+ const auto& widget = w.widgets[i];
+ if (widget.type == WindowWidgetType::Scroll)
+ result++;
+ }
+ return result;
+ }
+
+ /**
+ *
+ * rct2: 0x006ECDA4
+ */
+ WindowBase* WindowBringToFront(WindowBase& w)
+ {
+ if (!(w.flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)))
+ {
+ auto itSourcePos = WindowGetIterator(&w);
+ if (itSourcePos != g_window_list.end())
+ {
+ // Insert in front of the first non-stick-to-front window
+ auto itDestPos = g_window_list.begin();
+ for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++)
+ {
+ auto& w2 = *it;
+ if (!(w2->flags & WF_STICK_TO_FRONT))
{
- if (y2 >= y1 && y2 <= w2->height + y1 + 20)
- {
- // window is covering this area, try the next one
- i++;
- found = false;
- break;
- }
+ itDestPos = it.base();
+ break;
}
}
- if (it == g_window_list.end())
+
+ g_window_list.splice(itDestPos, g_window_list, itSourcePos);
+ w.Invalidate();
+
+ if (w.windowPos.x + w.width < 20)
{
- found = true;
- }
- if (i >= static_cast(std::size(window_scroll_locations)))
- {
- i = 0;
- found = true;
+ int32_t i = 20 - w.windowPos.x;
+ w.windowPos.x += i;
+ if (w.viewport != nullptr)
+ w.viewport->pos.x += i;
+ w.Invalidate();
}
}
}
- // rct2: 0x006E7C76
- if (w.viewport_target_sprite.IsNull())
+ return &w;
+ }
+
+ WindowBase* WindowBringToFrontByClassWithFlags(WindowClass cls, uint16_t flags)
+ {
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ WindowBase* w = windowMgr->FindByClass(cls);
+ if (w != nullptr)
{
- if (!(w.flags & WF_NO_SCROLLING))
+ w->flags |= flags;
+ w->Invalidate();
+ w = WindowBringToFront(*w);
+ }
+
+ return w;
+ }
+
+ WindowBase* WindowBringToFrontByClass(WindowClass cls)
+ {
+ return WindowBringToFrontByClassWithFlags(cls, WF_WHITE_BORDER_MASK);
+ }
+
+ /**
+ *
+ * rct2: 0x006ED78A
+ * cls (cl)
+ * number (dx)
+ */
+ WindowBase* WindowBringToFrontByNumber(WindowClass cls, rct_windownumber number)
+ {
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ WindowBase* w = windowMgr->FindByNumber(cls, number);
+ if (w != nullptr)
+ {
+ w->flags |= WF_WHITE_BORDER_MASK;
+ w->Invalidate();
+ w = WindowBringToFront(*w);
+ }
+
+ return w;
+ }
+
+ /**
+ *
+ * rct2: 0x006EE65A
+ */
+ void WindowPushOthersRight(WindowBase& window)
+ {
+ WindowVisitEach([&window](WindowBase* w) {
+ if (w == &window)
+ return;
+ if (w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT))
+ return;
+ if (w->windowPos.x >= window.windowPos.x + window.width)
+ return;
+ if (w->windowPos.x + w->width <= window.windowPos.x)
+ return;
+ if (w->windowPos.y >= window.windowPos.y + window.height)
+ return;
+ if (w->windowPos.y + w->height <= window.windowPos.y)
+ return;
+
+ w->Invalidate();
+ if (window.windowPos.x + window.width + 13 >= ContextGetWidth())
+ return;
+ auto push_amount = window.windowPos.x + window.width - w->windowPos.x + 3;
+ w->windowPos.x += push_amount;
+ w->Invalidate();
+ if (w->viewport != nullptr)
+ w->viewport->pos.x += push_amount;
+ });
+ }
+
+ /**
+ *
+ * rct2: 0x006EE6EA
+ */
+ void WindowPushOthersBelow(WindowBase& w1)
+ {
+ // Enumerate through all other windows
+ WindowVisitEach([&w1](WindowBase* w2) {
+ if (&w1 == w2)
+ return;
+ // ?
+ if (w2->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT))
+ return;
+ // Check if w2 intersects with w1
+ if (w2->windowPos.x > (w1.windowPos.x + w1.width) || w2->windowPos.x + w2->width < w1.windowPos.x)
+ return;
+ if (w2->windowPos.y > (w1.windowPos.y + w1.height) || w2->windowPos.y + w2->height < w1.windowPos.y)
+ return;
+
+ // Check if there is room to push it down
+ if (w1.windowPos.y + w1.height + 80 >= ContextGetHeight())
+ return;
+
+ // Invalidate the window's current area
+ w2->Invalidate();
+
+ int32_t push_amount = w1.windowPos.y + w1.height - w2->windowPos.y + 3;
+ w2->windowPos.y += push_amount;
+
+ // Invalidate the window's new area
+ w2->Invalidate();
+
+ // Update viewport position if necessary
+ if (w2->viewport != nullptr)
+ w2->viewport->pos.y += push_amount;
+ });
+ }
+
+ /**
+ *
+ * rct2: 0x006EE2E4
+ */
+ WindowBase* WindowGetMain()
+ {
+ for (auto& w : g_window_list)
+ {
+ if (w->flags & WF_DEAD)
+ continue;
+ if (w->classification == WindowClass::MainWindow)
{
- w.savedViewPos = screenCoords
- - ScreenCoordsXY{ static_cast(w.viewport->ViewWidth() * window_scroll_locations[i][0]),
- static_cast(w.viewport->ViewHeight() * window_scroll_locations[i][1]) };
- w.flags |= WF_SCROLLING_TO_LOCATION;
+ return w.get();
}
}
- }
-}
-
-void WindowViewportGetMapCoordsByCursor(
- const WindowBase& w, int32_t* map_x, int32_t* map_y, int32_t* offset_x, int32_t* offset_y)
-{
- // Get mouse position to offset against.
- auto mouseCoords = ContextGetCursorPositionScaled();
-
- // Compute map coordinate by mouse position.
- auto viewportPos = w.viewport->ScreenToViewportCoord(mouseCoords);
- auto coordsXYZ = ViewportAdjustForMapHeight(viewportPos, w.viewport->rotation);
- auto mapCoords = ViewportPosToMapPos(viewportPos, coordsXYZ.z, w.viewport->rotation);
- *map_x = mapCoords.x;
- *map_y = mapCoords.y;
-
- // Get viewport coordinates centring around the tile.
- int32_t z = TileElementHeight(mapCoords);
-
- auto centreLoc = centre_2d_coordinates({ mapCoords.x, mapCoords.y, z }, w.viewport);
- if (!centreLoc)
- {
- LOG_ERROR("Invalid location.");
- return;
- }
-
- // Rebase mouse position onto centre of window, and compensate for zoom level.
- int32_t rebased_x = w.viewport->zoom.ApplyTo(w.width / 2 - mouseCoords.x);
- int32_t rebased_y = w.viewport->zoom.ApplyTo(w.height / 2 - mouseCoords.y);
-
- // Compute cursor offset relative to tile.
- *offset_x = w.viewport->zoom.ApplyTo(w.savedViewPos.x - (centreLoc->x + rebased_x));
- *offset_y = w.viewport->zoom.ApplyTo(w.savedViewPos.y - (centreLoc->y + rebased_y));
-}
-
-void WindowViewportCentreTileAroundCursor(WindowBase& w, int32_t map_x, int32_t map_y, int32_t offset_x, int32_t offset_y)
-{
- // Get viewport coordinates centring around the tile.
- int32_t z = TileElementHeight({ map_x, map_y });
- auto centreLoc = centre_2d_coordinates({ map_x, map_y, z }, w.viewport);
-
- if (!centreLoc.has_value())
- {
- LOG_ERROR("Invalid location.");
- return;
- }
-
- // Get mouse position to offset against.
- auto mouseCoords = ContextGetCursorPositionScaled();
-
- // Rebase mouse position onto centre of window, and compensate for zoom level.
- int32_t rebased_x = w.viewport->zoom.ApplyTo((w.width >> 1) - mouseCoords.x);
- int32_t rebased_y = w.viewport->zoom.ApplyTo((w.height >> 1) - mouseCoords.y);
-
- // Apply offset to the viewport.
- w.savedViewPos = { centreLoc->x + rebased_x + w.viewport->zoom.ApplyInversedTo(offset_x),
- centreLoc->y + rebased_y + w.viewport->zoom.ApplyInversedTo(offset_y) };
-}
-
-/**
- * For all windows with viewports, ensure they do not have a zoom level less than the minimum.
- */
-void WindowCheckAllValidZoom()
-{
- WindowVisitEach([](WindowBase* w) {
- if (w->viewport != nullptr && w->viewport->zoom < ZoomLevel::min())
- {
- WindowZoomSet(*w, ZoomLevel::min(), false);
- }
- });
-}
-
-void WindowZoomSet(WindowBase& w, ZoomLevel zoomLevel, bool atCursor)
-{
- Viewport* v = w.viewport;
- if (v == nullptr)
- return;
-
- zoomLevel = std::clamp(zoomLevel, ZoomLevel::min(), ZoomLevel::max());
- if (v->zoom == zoomLevel)
- return;
-
- // Zooming to cursor? Remember where we're pointing at the moment.
- int32_t saved_map_x = 0;
- int32_t saved_map_y = 0;
- int32_t offset_x = 0;
- int32_t offset_y = 0;
- if (Config::Get().general.ZoomToCursor && atCursor)
- {
- WindowViewportGetMapCoordsByCursor(w, &saved_map_x, &saved_map_y, &offset_x, &offset_y);
- }
-
- // Zoom in
- while (v->zoom > zoomLevel)
- {
- v->zoom--;
- w.savedViewPos.x += v->ViewWidth() / 2;
- w.savedViewPos.y += v->ViewHeight() / 2;
- }
-
- // Zoom out
- while (v->zoom < zoomLevel)
- {
- v->zoom++;
- w.savedViewPos.x -= v->ViewWidth() / 4;
- w.savedViewPos.y -= v->ViewHeight() / 4;
- }
-
- // Zooming to cursor? Centre around the tile we were hovering over just now.
- if (Config::Get().general.ZoomToCursor && atCursor)
- {
- WindowViewportCentreTileAroundCursor(w, saved_map_x, saved_map_y, offset_x, offset_y);
- }
-
- // HACK: Prevents the redraw from failing when there is
- // a window on top of the viewport.
- WindowBringToFront(w);
- w.Invalidate();
-}
-
-/**
- * Splits a drawing of a window into regions that can be seen and are not hidden
- * by other opaque overlapping windows.
- */
-void WindowDraw(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom)
-{
- if (!WindowIsVisible(w))
- return;
-
- // Divide the draws up for only the visible regions of the window recursively
- auto itPos = WindowGetIterator(&w);
- for (auto it = std::next(itPos); it != g_window_list.end(); it++)
- {
- // Check if this window overlaps w
- auto topwindow = it->get();
- if (topwindow->windowPos.x >= right || topwindow->windowPos.y >= bottom)
- continue;
- if (topwindow->windowPos.x + topwindow->width <= left || topwindow->windowPos.y + topwindow->height <= top)
- continue;
- if (topwindow->flags & WF_TRANSPARENT)
- continue;
-
- // A window overlaps w, split up the draw into two regions where the window starts to overlap
- if (topwindow->windowPos.x > left)
- {
- // Split draw at topwindow.left
- WindowDrawCore(dpi, w, left, top, topwindow->windowPos.x, bottom);
- WindowDrawCore(dpi, w, topwindow->windowPos.x, top, right, bottom);
- }
- else if (topwindow->windowPos.x + topwindow->width < right)
- {
- // Split draw at topwindow.right
- WindowDrawCore(dpi, w, left, top, topwindow->windowPos.x + topwindow->width, bottom);
- WindowDrawCore(dpi, w, topwindow->windowPos.x + topwindow->width, top, right, bottom);
- }
- else if (topwindow->windowPos.y > top)
- {
- // Split draw at topwindow.top
- WindowDrawCore(dpi, w, left, top, right, topwindow->windowPos.y);
- WindowDrawCore(dpi, w, left, topwindow->windowPos.y, right, bottom);
- }
- else if (topwindow->windowPos.y + topwindow->height < bottom)
- {
- // Split draw at topwindow.bottom
- WindowDrawCore(dpi, w, left, top, right, topwindow->windowPos.y + topwindow->height);
- WindowDrawCore(dpi, w, left, topwindow->windowPos.y + topwindow->height, right, bottom);
- }
-
- // Drawing for this region should be done now, exit
- return;
- }
-
- // No windows overlap
- WindowDrawCore(dpi, w, left, top, right, bottom);
-}
-
-/**
- * Draws the given window and any other overlapping transparent windows.
- */
-static void WindowDrawCore(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom)
-{
- // Clamp region
- left = std::max(left, w.windowPos.x);
- top = std::max(top, w.windowPos.y);
- right = std::min(right, w.windowPos.x + w.width);
- bottom = std::min(bottom, w.windowPos.y + w.height);
- if (left >= right)
- return;
- if (top >= bottom)
- return;
-
- // Draw the window and any other overlapping transparent windows
- for (auto it = WindowGetIterator(&w); it != g_window_list.end(); it++)
- {
- auto* v = (*it).get();
- if (v->flags & WF_DEAD)
- continue;
- if ((&w == v || (v->flags & WF_TRANSPARENT)) && WindowIsVisible(*v))
- {
- WindowDrawSingle(dpi, *v, left, top, right, bottom);
- }
- }
-}
-
-static void WindowDrawSingle(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom)
-{
- assert(dpi.zoom_level == ZoomLevel{ 0 });
- // Copy dpi so we can crop it
- DrawPixelInfo copy = dpi;
-
- // Clamp left to 0
- int32_t overflow = left - copy.x;
- if (overflow > 0)
- {
- copy.x += overflow;
- copy.width -= overflow;
- if (copy.width <= 0)
- return;
- copy.pitch += overflow;
- copy.bits += overflow;
- }
-
- // Clamp width to right
- overflow = copy.x + copy.width - right;
- if (overflow > 0)
- {
- copy.width -= overflow;
- if (copy.width <= 0)
- return;
- copy.pitch += overflow;
- }
-
- // Clamp top to 0
- overflow = top - copy.y;
- if (overflow > 0)
- {
- copy.y += overflow;
- copy.height -= overflow;
- if (copy.height <= 0)
- return;
- copy.bits += copy.LineStride() * overflow;
- }
-
- // Clamp height to bottom
- overflow = copy.y + copy.height - bottom;
- if (overflow > 0)
- {
- copy.height -= overflow;
- if (copy.height <= 0)
- return;
- }
-
- // Invalidate modifies the window colours so first get the correct
- // colour before setting the global variables for the string painting
- w.OnPrepareDraw();
-
- // Text colouring
- gCurrentWindowColours[0] = w.colours[0].colour;
- gCurrentWindowColours[1] = w.colours[1].colour;
- gCurrentWindowColours[2] = w.colours[2].colour;
-
- w.OnDraw(copy);
-}
-
-bool isToolActive(WindowClass cls)
-{
- return InputTestFlag(INPUT_FLAG_TOOL_ACTIVE) && gCurrentToolWidget.window_classification == cls;
-}
-
-bool isToolActive(WindowClass cls, rct_windownumber number)
-{
- return isToolActive(cls) && gCurrentToolWidget.window_number == number;
-}
-
-bool isToolActive(WindowClass cls, WidgetIndex widgetIndex)
-{
- return isToolActive(cls) && gCurrentToolWidget.widget_index == widgetIndex;
-}
-
-bool isToolActive(WindowClass cls, WidgetIndex widgetIndex, rct_windownumber number)
-{
- return isToolActive(cls, widgetIndex) && gCurrentToolWidget.window_number == number;
-}
-
-bool isToolActive(const WindowBase& w, WidgetIndex widgetIndex)
-{
- return isToolActive(w.classification, widgetIndex, w.number);
-}
-
-/**
- *
- * rct2: 0x006EE212
- *
- * @param tool (al)
- * @param widgetIndex (dx)
- * @param w (esi)
- */
-bool ToolSet(const WindowBase& w, WidgetIndex widgetIndex, Tool tool)
-{
- if (InputTestFlag(INPUT_FLAG_TOOL_ACTIVE))
- {
- if (w.classification == gCurrentToolWidget.window_classification && w.number == gCurrentToolWidget.window_number
- && widgetIndex == gCurrentToolWidget.widget_index)
- {
- ToolCancel();
- return true;
- }
-
- ToolCancel();
- }
-
- InputSetFlag(INPUT_FLAG_TOOL_ACTIVE, true);
- InputSetFlag(INPUT_FLAG_4, false);
- InputSetFlag(INPUT_FLAG_6, false);
- gCurrentToolId = tool;
- gCurrentToolWidget.window_classification = w.classification;
- gCurrentToolWidget.window_number = w.number;
- gCurrentToolWidget.widget_index = widgetIndex;
- return false;
-}
-
-/**
- *
- * rct2: 0x006EE281
- */
-void ToolCancel()
-{
- if (InputTestFlag(INPUT_FLAG_TOOL_ACTIVE))
- {
- InputSetFlag(INPUT_FLAG_TOOL_ACTIVE, false);
-
- MapInvalidateSelectionRect();
- MapInvalidateMapSelectionTiles();
-
- // Reset map selection
- gMapSelectFlags = 0;
-
- if (gCurrentToolWidget.widget_index != -1)
- {
- // Invalidate tool widget
- WidgetInvalidateByNumber(
- gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number, gCurrentToolWidget.widget_index);
-
- // Abort tool event
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- WindowBase* w = windowMgr->FindByNumber(gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number);
- if (w != nullptr)
- w->OnToolAbort(gCurrentToolWidget.widget_index);
- }
- }
-}
-
-/**
- * rct2: 0x0066B905
- */
-void WindowResizeGui(int32_t width, int32_t height)
-{
- WindowResizeGuiScenarioEditor(width, height);
- if (gScreenFlags & SCREEN_FLAGS_EDITOR)
- return;
-
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
- WindowBase* titleWind = windowMgr->FindByClass(WindowClass::TitleMenu);
- if (titleWind != nullptr)
- {
- titleWind->windowPos.x = (width - titleWind->width) / 2;
- titleWind->windowPos.y = height - 182;
- }
-
- WindowBase* versionWind = windowMgr->FindByClass(WindowClass::TitleVersion);
- if (versionWind != nullptr)
- versionWind->windowPos.y = height - 30;
-
- WindowBase* exitWind = windowMgr->FindByClass(WindowClass::TitleExit);
- if (exitWind != nullptr)
- {
- exitWind->windowPos.x = width - 40;
- exitWind->windowPos.y = height - 64;
- }
-
- WindowBase* optionsWind = windowMgr->FindByClass(WindowClass::TitleOptions);
- if (optionsWind != nullptr)
- {
- optionsWind->windowPos.x = width - 80;
- }
-
- // Keep options window centred after a resize
- WindowBase* optionsWindow = windowMgr->FindByClass(WindowClass::Options);
- if (optionsWindow != nullptr)
- {
- optionsWindow->windowPos.x = (ContextGetWidth() - optionsWindow->width) / 2;
- optionsWindow->windowPos.y = (ContextGetHeight() - optionsWindow->height) / 2;
- }
-
- // Keep progress bar window centred after a resize
- WindowBase* ProgressWindow = windowMgr->FindByClass(WindowClass::ProgressWindow);
- if (ProgressWindow != nullptr)
- {
- ProgressWindow->windowPos.x = (ContextGetWidth() - ProgressWindow->width) / 2;
- ProgressWindow->windowPos.y = (ContextGetHeight() - ProgressWindow->height) / 2;
- }
-
- GfxInvalidateScreen();
-}
-
-/**
- * rct2: 0x0066F0DD
- */
-void WindowResizeGuiScenarioEditor(int32_t width, int32_t height)
-{
- auto* mainWind = WindowGetMain();
- if (mainWind != nullptr)
- {
- Viewport* viewport = mainWind->viewport;
- mainWind->width = width;
- mainWind->height = height;
- viewport->width = width;
- viewport->height = height;
- if (mainWind->widgets != nullptr && mainWind->widgets[WC_MAIN_WINDOW__0].type == WindowWidgetType::Viewport)
- {
- mainWind->widgets[WC_MAIN_WINDOW__0].right = width;
- mainWind->widgets[WC_MAIN_WINDOW__0].bottom = height;
- }
- }
-
- auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
-
- WindowBase* topWind = windowMgr->FindByClass(WindowClass::TopToolbar);
- if (topWind != nullptr)
- {
- topWind->width = std::max(640, width);
- }
-
- WindowBase* bottomWind = windowMgr->FindByClass(WindowClass::BottomToolbar);
- if (bottomWind != nullptr)
- {
- bottomWind->windowPos.y = height - 32;
- bottomWind->width = std::max(640, width);
- }
-}
-
-/**
- *
- * rct2: 0x006CBCC3
- */
-void WindowCloseConstructionWindows()
-{
- WindowCloseByClass(WindowClass::RideConstruction);
- WindowCloseByClass(WindowClass::Footpath);
- WindowCloseByClass(WindowClass::TrackDesignList);
- WindowCloseByClass(WindowClass::TrackDesignPlace);
-}
-
-/**
- * Update zoom based volume attenuation for ride music and clear music list.
- * rct2: 0x006BC348
- */
-void WindowUpdateViewportRideMusic()
-{
- RideAudio::ClearAllViewportInstances();
- g_music_tracking_viewport = nullptr;
-
- for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++)
- {
- auto w = it->get();
- auto viewport = w->viewport;
- if (viewport == nullptr || !(viewport->flags & VIEWPORT_FLAG_SOUND_ON))
- continue;
-
- g_music_tracking_viewport = viewport;
- gWindowAudioExclusive = w;
-
- if (viewport->zoom <= ZoomLevel{ 0 })
- Audio::gVolumeAdjustZoom = 0;
- else if (viewport->zoom == ZoomLevel{ 1 })
- Audio::gVolumeAdjustZoom = 30;
- else
- Audio::gVolumeAdjustZoom = 60;
- break;
- }
-}
-
-/**
- *
- * rct2: 0x006EE3C3
- */
-void TextinputCancel()
-{
- WindowCloseByClass(WindowClass::Textinput);
-}
-
-bool WindowIsVisible(WindowBase& w)
-{
- // w->visibility is used to prevent repeat calculations within an iteration by caching the result
-
- if (w.visibility == VisibilityCache::Visible)
- return true;
- if (w.visibility == VisibilityCache::Covered)
- return false;
-
- // only consider viewports, consider the main window always visible
- if (w.viewport == nullptr || w.classification == WindowClass::MainWindow)
- {
- // default to previous behaviour
- w.visibility = VisibilityCache::Visible;
- return true;
- }
-
- // start from the window above the current
- auto itPos = WindowGetIterator(&w);
- for (auto it = std::next(itPos); it != g_window_list.end(); it++)
- {
- auto& w_other = *(*it);
- if (w_other.flags & WF_DEAD)
- continue;
-
- // if covered by a higher window, no rendering needed
- if (w_other.windowPos.x <= w.windowPos.x && w_other.windowPos.y <= w.windowPos.y
- && w_other.windowPos.x + w_other.width >= w.windowPos.x + w.width
- && w_other.windowPos.y + w_other.height >= w.windowPos.y + w.height)
- {
- w.visibility = VisibilityCache::Covered;
- w.viewport->visibility = VisibilityCache::Covered;
- return false;
- }
- }
-
- // default to previous behaviour
- w.visibility = VisibilityCache::Visible;
- w.viewport->visibility = VisibilityCache::Visible;
- return true;
-}
-
-/**
- *
- * rct2: 0x006E7499
- * left (ax)
- * top (bx)
- * right (dx)
- * bottom (bp)
- */
-void WindowDrawAll(DrawPixelInfo& dpi, int32_t left, int32_t top, int32_t right, int32_t bottom)
-{
- auto windowDPI = dpi.Crop({ left, top }, { right - left, bottom - top });
- WindowVisitEach([&windowDPI, left, top, right, bottom](WindowBase* w) {
- if (w->flags & WF_TRANSPARENT)
- return;
- if (right <= w->windowPos.x || bottom <= w->windowPos.y)
- return;
- if (left >= w->windowPos.x + w->width || top >= w->windowPos.y + w->height)
- return;
- WindowDraw(windowDPI, *w, left, top, right, bottom);
- });
-}
-
-Viewport* WindowGetPreviousViewport(Viewport* current)
-{
- bool foundPrevious = (current == nullptr);
- for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++)
- {
- auto& w = **it;
- if (w.flags & WF_DEAD)
- continue;
- if (w.viewport != nullptr)
- {
- if (foundPrevious)
- {
- return w.viewport;
- }
- if (w.viewport == current)
- {
- foundPrevious = true;
- }
- }
- }
- return nullptr;
-}
-
-void WindowResetVisibilities()
-{
- // reset window visibility status to unknown
- WindowVisitEach([](WindowBase* w) {
- w->visibility = VisibilityCache::Unknown;
- if (w->viewport != nullptr)
- {
- w->viewport->visibility = VisibilityCache::Unknown;
- }
- });
-}
-
-void WindowInitAll()
-{
- WindowCloseAllExceptFlags(0);
-}
-
-void WindowFollowSprite(WindowBase& w, EntityId spriteIndex)
-{
- if (spriteIndex.ToUnderlying() < MAX_ENTITIES || spriteIndex.IsNull())
- {
- w.viewport_smart_follow_sprite = spriteIndex;
- }
-}
-
-void WindowUnfollowSprite(WindowBase& w)
-{
- w.viewport_smart_follow_sprite = EntityId::GetNull();
- w.viewport_target_sprite = EntityId::GetNull();
-}
-
-Viewport* WindowGetViewport(WindowBase* w)
-{
- if (w == nullptr)
- {
return nullptr;
}
- return w->viewport;
-}
+ /**
+ *
+ * rct2: 0x006E7C9C
+ * @param w (esi)
+ * @param x (eax)
+ * @param y (ecx)
+ * @param z (edx)
+ */
+ void WindowScrollToLocation(WindowBase& w, const CoordsXYZ& coords)
+ {
+ WindowUnfollowSprite(w);
+ if (w.viewport != nullptr)
+ {
+ int16_t height = TileElementHeight(coords);
+ if (coords.z < height - 16)
+ {
+ if (!(w.viewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE))
+ {
+ w.viewport->flags |= VIEWPORT_FLAG_UNDERGROUND_INSIDE;
+ w.Invalidate();
+ }
+ }
+ else
+ {
+ if (w.viewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE)
+ {
+ w.viewport->flags &= ~VIEWPORT_FLAG_UNDERGROUND_INSIDE;
+ w.Invalidate();
+ }
+ }
+
+ auto screenCoords = Translate3DTo2DWithZ(w.viewport->rotation, coords);
+
+ int32_t i = 0;
+ if (!(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO))
+ {
+ bool found = false;
+ while (!found)
+ {
+ auto x2 = w.viewport->pos.x + static_cast(w.viewport->width * window_scroll_locations[i][0]);
+ auto y2 = w.viewport->pos.y + static_cast(w.viewport->height * window_scroll_locations[i][1]);
+
+ auto it = WindowGetIterator(&w);
+ for (; it != g_window_list.end(); it++)
+ {
+ auto w2 = (*it).get();
+ auto x1 = w2->windowPos.x - 10;
+ auto y1 = w2->windowPos.y - 10;
+ if (x2 >= x1 && x2 <= w2->width + x1 + 20)
+ {
+ if (y2 >= y1 && y2 <= w2->height + y1 + 20)
+ {
+ // window is covering this area, try the next one
+ i++;
+ found = false;
+ break;
+ }
+ }
+ }
+ if (it == g_window_list.end())
+ {
+ found = true;
+ }
+ if (i >= static_cast(std::size(window_scroll_locations)))
+ {
+ i = 0;
+ found = true;
+ }
+ }
+ }
+ // rct2: 0x006E7C76
+ if (w.viewport_target_sprite.IsNull())
+ {
+ if (!(w.flags & WF_NO_SCROLLING))
+ {
+ w.savedViewPos = screenCoords
+ - ScreenCoordsXY{ static_cast(w.viewport->ViewWidth() * window_scroll_locations[i][0]),
+ static_cast(w.viewport->ViewHeight() * window_scroll_locations[i][1]) };
+ w.flags |= WF_SCROLLING_TO_LOCATION;
+ }
+ }
+ }
+ }
+
+ void WindowViewportGetMapCoordsByCursor(
+ const WindowBase& w, int32_t* map_x, int32_t* map_y, int32_t* offset_x, int32_t* offset_y)
+ {
+ // Get mouse position to offset against.
+ auto mouseCoords = ContextGetCursorPositionScaled();
+
+ // Compute map coordinate by mouse position.
+ auto viewportPos = w.viewport->ScreenToViewportCoord(mouseCoords);
+ auto coordsXYZ = ViewportAdjustForMapHeight(viewportPos, w.viewport->rotation);
+ auto mapCoords = ViewportPosToMapPos(viewportPos, coordsXYZ.z, w.viewport->rotation);
+ *map_x = mapCoords.x;
+ *map_y = mapCoords.y;
+
+ // Get viewport coordinates centring around the tile.
+ int32_t z = TileElementHeight(mapCoords);
+
+ auto centreLoc = centre_2d_coordinates({ mapCoords.x, mapCoords.y, z }, w.viewport);
+ if (!centreLoc)
+ {
+ LOG_ERROR("Invalid location.");
+ return;
+ }
+
+ // Rebase mouse position onto centre of window, and compensate for zoom level.
+ int32_t rebased_x = w.viewport->zoom.ApplyTo(w.width / 2 - mouseCoords.x);
+ int32_t rebased_y = w.viewport->zoom.ApplyTo(w.height / 2 - mouseCoords.y);
+
+ // Compute cursor offset relative to tile.
+ *offset_x = w.viewport->zoom.ApplyTo(w.savedViewPos.x - (centreLoc->x + rebased_x));
+ *offset_y = w.viewport->zoom.ApplyTo(w.savedViewPos.y - (centreLoc->y + rebased_y));
+ }
+
+ void WindowViewportCentreTileAroundCursor(WindowBase& w, int32_t map_x, int32_t map_y, int32_t offset_x, int32_t offset_y)
+ {
+ // Get viewport coordinates centring around the tile.
+ int32_t z = TileElementHeight({ map_x, map_y });
+ auto centreLoc = centre_2d_coordinates({ map_x, map_y, z }, w.viewport);
+
+ if (!centreLoc.has_value())
+ {
+ LOG_ERROR("Invalid location.");
+ return;
+ }
+
+ // Get mouse position to offset against.
+ auto mouseCoords = ContextGetCursorPositionScaled();
+
+ // Rebase mouse position onto centre of window, and compensate for zoom level.
+ int32_t rebased_x = w.viewport->zoom.ApplyTo((w.width >> 1) - mouseCoords.x);
+ int32_t rebased_y = w.viewport->zoom.ApplyTo((w.height >> 1) - mouseCoords.y);
+
+ // Apply offset to the viewport.
+ w.savedViewPos = { centreLoc->x + rebased_x + w.viewport->zoom.ApplyInversedTo(offset_x),
+ centreLoc->y + rebased_y + w.viewport->zoom.ApplyInversedTo(offset_y) };
+ }
+
+ /**
+ * For all windows with viewports, ensure they do not have a zoom level less than the minimum.
+ */
+ void WindowCheckAllValidZoom()
+ {
+ WindowVisitEach([](WindowBase* w) {
+ if (w->viewport != nullptr && w->viewport->zoom < ZoomLevel::min())
+ {
+ WindowZoomSet(*w, ZoomLevel::min(), false);
+ }
+ });
+ }
+
+ void WindowZoomSet(WindowBase& w, ZoomLevel zoomLevel, bool atCursor)
+ {
+ Viewport* v = w.viewport;
+ if (v == nullptr)
+ return;
+
+ zoomLevel = std::clamp(zoomLevel, ZoomLevel::min(), ZoomLevel::max());
+ if (v->zoom == zoomLevel)
+ return;
+
+ // Zooming to cursor? Remember where we're pointing at the moment.
+ int32_t saved_map_x = 0;
+ int32_t saved_map_y = 0;
+ int32_t offset_x = 0;
+ int32_t offset_y = 0;
+ if (Config::Get().general.ZoomToCursor && atCursor)
+ {
+ WindowViewportGetMapCoordsByCursor(w, &saved_map_x, &saved_map_y, &offset_x, &offset_y);
+ }
+
+ // Zoom in
+ while (v->zoom > zoomLevel)
+ {
+ v->zoom--;
+ w.savedViewPos.x += v->ViewWidth() / 2;
+ w.savedViewPos.y += v->ViewHeight() / 2;
+ }
+
+ // Zoom out
+ while (v->zoom < zoomLevel)
+ {
+ v->zoom++;
+ w.savedViewPos.x -= v->ViewWidth() / 4;
+ w.savedViewPos.y -= v->ViewHeight() / 4;
+ }
+
+ // Zooming to cursor? Centre around the tile we were hovering over just now.
+ if (Config::Get().general.ZoomToCursor && atCursor)
+ {
+ WindowViewportCentreTileAroundCursor(w, saved_map_x, saved_map_y, offset_x, offset_y);
+ }
+
+ // HACK: Prevents the redraw from failing when there is
+ // a window on top of the viewport.
+ WindowBringToFront(w);
+ w.Invalidate();
+ }
+
+ /**
+ * Splits a drawing of a window into regions that can be seen and are not hidden
+ * by other opaque overlapping windows.
+ */
+ void WindowDraw(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom)
+ {
+ if (!WindowIsVisible(w))
+ return;
+
+ // Divide the draws up for only the visible regions of the window recursively
+ auto itPos = WindowGetIterator(&w);
+ for (auto it = std::next(itPos); it != g_window_list.end(); it++)
+ {
+ // Check if this window overlaps w
+ auto topwindow = it->get();
+ if (topwindow->windowPos.x >= right || topwindow->windowPos.y >= bottom)
+ continue;
+ if (topwindow->windowPos.x + topwindow->width <= left || topwindow->windowPos.y + topwindow->height <= top)
+ continue;
+ if (topwindow->flags & WF_TRANSPARENT)
+ continue;
+
+ // A window overlaps w, split up the draw into two regions where the window starts to overlap
+ if (topwindow->windowPos.x > left)
+ {
+ // Split draw at topwindow.left
+ WindowDrawCore(dpi, w, left, top, topwindow->windowPos.x, bottom);
+ WindowDrawCore(dpi, w, topwindow->windowPos.x, top, right, bottom);
+ }
+ else if (topwindow->windowPos.x + topwindow->width < right)
+ {
+ // Split draw at topwindow.right
+ WindowDrawCore(dpi, w, left, top, topwindow->windowPos.x + topwindow->width, bottom);
+ WindowDrawCore(dpi, w, topwindow->windowPos.x + topwindow->width, top, right, bottom);
+ }
+ else if (topwindow->windowPos.y > top)
+ {
+ // Split draw at topwindow.top
+ WindowDrawCore(dpi, w, left, top, right, topwindow->windowPos.y);
+ WindowDrawCore(dpi, w, left, topwindow->windowPos.y, right, bottom);
+ }
+ else if (topwindow->windowPos.y + topwindow->height < bottom)
+ {
+ // Split draw at topwindow.bottom
+ WindowDrawCore(dpi, w, left, top, right, topwindow->windowPos.y + topwindow->height);
+ WindowDrawCore(dpi, w, left, topwindow->windowPos.y + topwindow->height, right, bottom);
+ }
+
+ // Drawing for this region should be done now, exit
+ return;
+ }
+
+ // No windows overlap
+ WindowDrawCore(dpi, w, left, top, right, bottom);
+ }
+
+ /**
+ * Draws the given window and any other overlapping transparent windows.
+ */
+ static void WindowDrawCore(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom)
+ {
+ // Clamp region
+ left = std::max(left, w.windowPos.x);
+ top = std::max(top, w.windowPos.y);
+ right = std::min(right, w.windowPos.x + w.width);
+ bottom = std::min(bottom, w.windowPos.y + w.height);
+ if (left >= right)
+ return;
+ if (top >= bottom)
+ return;
+
+ // Draw the window and any other overlapping transparent windows
+ for (auto it = WindowGetIterator(&w); it != g_window_list.end(); it++)
+ {
+ auto* v = (*it).get();
+ if (v->flags & WF_DEAD)
+ continue;
+ if ((&w == v || (v->flags & WF_TRANSPARENT)) && WindowIsVisible(*v))
+ {
+ WindowDrawSingle(dpi, *v, left, top, right, bottom);
+ }
+ }
+ }
+
+ static void WindowDrawSingle(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom)
+ {
+ assert(dpi.zoom_level == ZoomLevel{ 0 });
+ // Copy dpi so we can crop it
+ DrawPixelInfo copy = dpi;
+
+ // Clamp left to 0
+ int32_t overflow = left - copy.x;
+ if (overflow > 0)
+ {
+ copy.x += overflow;
+ copy.width -= overflow;
+ if (copy.width <= 0)
+ return;
+ copy.pitch += overflow;
+ copy.bits += overflow;
+ }
+
+ // Clamp width to right
+ overflow = copy.x + copy.width - right;
+ if (overflow > 0)
+ {
+ copy.width -= overflow;
+ if (copy.width <= 0)
+ return;
+ copy.pitch += overflow;
+ }
+
+ // Clamp top to 0
+ overflow = top - copy.y;
+ if (overflow > 0)
+ {
+ copy.y += overflow;
+ copy.height -= overflow;
+ if (copy.height <= 0)
+ return;
+ copy.bits += copy.LineStride() * overflow;
+ }
+
+ // Clamp height to bottom
+ overflow = copy.y + copy.height - bottom;
+ if (overflow > 0)
+ {
+ copy.height -= overflow;
+ if (copy.height <= 0)
+ return;
+ }
+
+ // Invalidate modifies the window colours so first get the correct
+ // colour before setting the global variables for the string painting
+ w.OnPrepareDraw();
+
+ // Text colouring
+ gCurrentWindowColours[0] = w.colours[0].colour;
+ gCurrentWindowColours[1] = w.colours[1].colour;
+ gCurrentWindowColours[2] = w.colours[2].colour;
+
+ w.OnDraw(copy);
+ }
+
+ bool isToolActive(WindowClass cls)
+ {
+ return InputTestFlag(INPUT_FLAG_TOOL_ACTIVE) && gCurrentToolWidget.window_classification == cls;
+ }
+
+ bool isToolActive(WindowClass cls, rct_windownumber number)
+ {
+ return isToolActive(cls) && gCurrentToolWidget.window_number == number;
+ }
+
+ bool isToolActive(WindowClass cls, WidgetIndex widgetIndex)
+ {
+ return isToolActive(cls) && gCurrentToolWidget.widget_index == widgetIndex;
+ }
+
+ bool isToolActive(WindowClass cls, WidgetIndex widgetIndex, rct_windownumber number)
+ {
+ return isToolActive(cls, widgetIndex) && gCurrentToolWidget.window_number == number;
+ }
+
+ bool isToolActive(const WindowBase& w, WidgetIndex widgetIndex)
+ {
+ return isToolActive(w.classification, widgetIndex, w.number);
+ }
+
+ /**
+ *
+ * rct2: 0x006EE212
+ *
+ * @param tool (al)
+ * @param widgetIndex (dx)
+ * @param w (esi)
+ */
+ bool ToolSet(const WindowBase& w, WidgetIndex widgetIndex, Tool tool)
+ {
+ if (InputTestFlag(INPUT_FLAG_TOOL_ACTIVE))
+ {
+ if (w.classification == gCurrentToolWidget.window_classification && w.number == gCurrentToolWidget.window_number
+ && widgetIndex == gCurrentToolWidget.widget_index)
+ {
+ ToolCancel();
+ return true;
+ }
+
+ ToolCancel();
+ }
+
+ InputSetFlag(INPUT_FLAG_TOOL_ACTIVE, true);
+ InputSetFlag(INPUT_FLAG_4, false);
+ InputSetFlag(INPUT_FLAG_6, false);
+ gCurrentToolId = tool;
+ gCurrentToolWidget.window_classification = w.classification;
+ gCurrentToolWidget.window_number = w.number;
+ gCurrentToolWidget.widget_index = widgetIndex;
+ return false;
+ }
+
+ /**
+ *
+ * rct2: 0x006EE281
+ */
+ void ToolCancel()
+ {
+ if (InputTestFlag(INPUT_FLAG_TOOL_ACTIVE))
+ {
+ InputSetFlag(INPUT_FLAG_TOOL_ACTIVE, false);
+
+ MapInvalidateSelectionRect();
+ MapInvalidateMapSelectionTiles();
+
+ // Reset map selection
+ gMapSelectFlags = 0;
+
+ if (gCurrentToolWidget.widget_index != kWidgetIndexNull)
+ {
+ // Invalidate tool widget
+ WidgetInvalidateByNumber(
+ gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number,
+ gCurrentToolWidget.widget_index);
+
+ // Abort tool event
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ WindowBase* w = windowMgr->FindByNumber(
+ gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number);
+ if (w != nullptr)
+ w->OnToolAbort(gCurrentToolWidget.widget_index);
+ }
+ }
+ }
+
+ /**
+ * rct2: 0x0066B905
+ */
+ void WindowResizeGui(int32_t width, int32_t height)
+ {
+ WindowResizeGuiScenarioEditor(width, height);
+ if (gScreenFlags & SCREEN_FLAGS_EDITOR)
+ return;
+
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+ WindowBase* titleWind = windowMgr->FindByClass(WindowClass::TitleMenu);
+ if (titleWind != nullptr)
+ {
+ titleWind->windowPos.x = (width - titleWind->width) / 2;
+ titleWind->windowPos.y = height - 182;
+ }
+
+ WindowBase* versionWind = windowMgr->FindByClass(WindowClass::TitleVersion);
+ if (versionWind != nullptr)
+ versionWind->windowPos.y = height - 30;
+
+ WindowBase* exitWind = windowMgr->FindByClass(WindowClass::TitleExit);
+ if (exitWind != nullptr)
+ {
+ exitWind->windowPos.x = width - 40;
+ exitWind->windowPos.y = height - 64;
+ }
+
+ WindowBase* optionsWind = windowMgr->FindByClass(WindowClass::TitleOptions);
+ if (optionsWind != nullptr)
+ {
+ optionsWind->windowPos.x = width - 80;
+ }
+
+ // Keep options window centred after a resize
+ WindowBase* optionsWindow = windowMgr->FindByClass(WindowClass::Options);
+ if (optionsWindow != nullptr)
+ {
+ optionsWindow->windowPos.x = (ContextGetWidth() - optionsWindow->width) / 2;
+ optionsWindow->windowPos.y = (ContextGetHeight() - optionsWindow->height) / 2;
+ }
+
+ // Keep progress bar window centred after a resize
+ WindowBase* ProgressWindow = windowMgr->FindByClass(WindowClass::ProgressWindow);
+ if (ProgressWindow != nullptr)
+ {
+ ProgressWindow->windowPos.x = (ContextGetWidth() - ProgressWindow->width) / 2;
+ ProgressWindow->windowPos.y = (ContextGetHeight() - ProgressWindow->height) / 2;
+ }
+
+ GfxInvalidateScreen();
+ }
+
+ /**
+ * rct2: 0x0066F0DD
+ */
+ void WindowResizeGuiScenarioEditor(int32_t width, int32_t height)
+ {
+ auto* mainWind = WindowGetMain();
+ if (mainWind != nullptr)
+ {
+ Viewport* viewport = mainWind->viewport;
+ mainWind->width = width;
+ mainWind->height = height;
+ viewport->width = width;
+ viewport->height = height;
+ if (!mainWind->widgets.empty() && mainWind->widgets[WC_MAIN_WINDOW__0].type == WindowWidgetType::Viewport)
+ {
+ mainWind->widgets[WC_MAIN_WINDOW__0].right = width;
+ mainWind->widgets[WC_MAIN_WINDOW__0].bottom = height;
+ }
+ }
+
+ auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager();
+
+ WindowBase* topWind = windowMgr->FindByClass(WindowClass::TopToolbar);
+ if (topWind != nullptr)
+ {
+ topWind->width = std::max(640, width);
+ }
+
+ WindowBase* bottomWind = windowMgr->FindByClass(WindowClass::BottomToolbar);
+ if (bottomWind != nullptr)
+ {
+ bottomWind->windowPos.y = height - 32;
+ bottomWind->width = std::max(640, width);
+ }
+ }
+
+ /**
+ *
+ * rct2: 0x006CBCC3
+ */
+ void WindowCloseConstructionWindows()
+ {
+ WindowCloseByClass(WindowClass::RideConstruction);
+ WindowCloseByClass(WindowClass::Footpath);
+ WindowCloseByClass(WindowClass::TrackDesignList);
+ WindowCloseByClass(WindowClass::TrackDesignPlace);
+ }
+
+ /**
+ * Update zoom based volume attenuation for ride music and clear music list.
+ * rct2: 0x006BC348
+ */
+ void WindowUpdateViewportRideMusic()
+ {
+ RideAudio::ClearAllViewportInstances();
+ g_music_tracking_viewport = nullptr;
+
+ for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++)
+ {
+ auto w = it->get();
+ auto viewport = w->viewport;
+ if (viewport == nullptr || !(viewport->flags & VIEWPORT_FLAG_SOUND_ON))
+ continue;
+
+ g_music_tracking_viewport = viewport;
+ gWindowAudioExclusive = w;
+
+ if (viewport->zoom <= ZoomLevel{ 0 })
+ Audio::gVolumeAdjustZoom = 0;
+ else if (viewport->zoom == ZoomLevel{ 1 })
+ Audio::gVolumeAdjustZoom = 30;
+ else
+ Audio::gVolumeAdjustZoom = 60;
+ break;
+ }
+ }
+
+ /**
+ *
+ * rct2: 0x006EE3C3
+ */
+ void TextinputCancel()
+ {
+ WindowCloseByClass(WindowClass::Textinput);
+ }
+
+ bool WindowIsVisible(WindowBase& w)
+ {
+ // w->visibility is used to prevent repeat calculations within an iteration by caching the result
+
+ if (w.visibility == VisibilityCache::Visible)
+ return true;
+ if (w.visibility == VisibilityCache::Covered)
+ return false;
+
+ // only consider viewports, consider the main window always visible
+ if (w.viewport == nullptr || w.classification == WindowClass::MainWindow)
+ {
+ // default to previous behaviour
+ w.visibility = VisibilityCache::Visible;
+ return true;
+ }
+
+ // start from the window above the current
+ auto itPos = WindowGetIterator(&w);
+ for (auto it = std::next(itPos); it != g_window_list.end(); it++)
+ {
+ auto& w_other = *(*it);
+ if (w_other.flags & WF_DEAD)
+ continue;
+
+ // if covered by a higher window, no rendering needed
+ if (w_other.windowPos.x <= w.windowPos.x && w_other.windowPos.y <= w.windowPos.y
+ && w_other.windowPos.x + w_other.width >= w.windowPos.x + w.width
+ && w_other.windowPos.y + w_other.height >= w.windowPos.y + w.height)
+ {
+ w.visibility = VisibilityCache::Covered;
+ w.viewport->visibility = VisibilityCache::Covered;
+ return false;
+ }
+ }
+
+ // default to previous behaviour
+ w.visibility = VisibilityCache::Visible;
+ w.viewport->visibility = VisibilityCache::Visible;
+ return true;
+ }
+
+ /**
+ *
+ * rct2: 0x006E7499
+ * left (ax)
+ * top (bx)
+ * right (dx)
+ * bottom (bp)
+ */
+ void WindowDrawAll(DrawPixelInfo& dpi, int32_t left, int32_t top, int32_t right, int32_t bottom)
+ {
+ auto windowDPI = dpi.Crop({ left, top }, { right - left, bottom - top });
+ WindowVisitEach([&windowDPI, left, top, right, bottom](WindowBase* w) {
+ if (w->flags & WF_TRANSPARENT)
+ return;
+ if (right <= w->windowPos.x || bottom <= w->windowPos.y)
+ return;
+ if (left >= w->windowPos.x + w->width || top >= w->windowPos.y + w->height)
+ return;
+ WindowDraw(windowDPI, *w, left, top, right, bottom);
+ });
+ }
+
+ Viewport* WindowGetPreviousViewport(Viewport* current)
+ {
+ bool foundPrevious = (current == nullptr);
+ for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++)
+ {
+ auto& w = **it;
+ if (w.flags & WF_DEAD)
+ continue;
+ if (w.viewport != nullptr)
+ {
+ if (foundPrevious)
+ {
+ return w.viewport;
+ }
+ if (w.viewport == current)
+ {
+ foundPrevious = true;
+ }
+ }
+ }
+ return nullptr;
+ }
+
+ void WindowResetVisibilities()
+ {
+ // reset window visibility status to unknown
+ WindowVisitEach([](WindowBase* w) {
+ w->visibility = VisibilityCache::Unknown;
+ if (w->viewport != nullptr)
+ {
+ w->viewport->visibility = VisibilityCache::Unknown;
+ }
+ });
+ }
+
+ void WindowInitAll()
+ {
+ WindowCloseAllExceptFlags(0);
+ }
+
+ void WindowFollowSprite(WindowBase& w, EntityId spriteIndex)
+ {
+ if (spriteIndex.ToUnderlying() < MAX_ENTITIES || spriteIndex.IsNull())
+ {
+ w.viewport_smart_follow_sprite = spriteIndex;
+ }
+ }
+
+ void WindowUnfollowSprite(WindowBase& w)
+ {
+ w.viewport_smart_follow_sprite = EntityId::GetNull();
+ w.viewport_target_sprite = EntityId::GetNull();
+ }
+
+ Viewport* WindowGetViewport(WindowBase* w)
+ {
+ if (w == nullptr)
+ {
+ return nullptr;
+ }
+
+ return w->viewport;
+ }
+} // namespace OpenRCT2
diff --git a/src/openrct2/interface/Window.h b/src/openrct2/interface/Window.h
index 72c8446e25..668e9445d8 100644
--- a/src/openrct2/interface/Window.h
+++ b/src/openrct2/interface/Window.h
@@ -11,303 +11,202 @@
#include "../Identifiers.h"
#include "../core/EnumUtils.hpp"
-#include "../drawing/ImageId.hpp"
-#include "../localisation/Formatter.h"
-#include "../ride/RideTypes.h"
#include "../windows/TileInspectorGlobals.h"
#include "../world/Location.hpp"
-#include "../world/ScenerySelection.h"
#include "Colour.h"
#include "Widget.h"
#include "WindowClasses.h"
#include "ZoomLevel.h"
#include
-#include
#include
#include
-#include
#include
struct DrawPixelInfo;
-struct WindowBase;
struct TrackDesignFileRef;
struct ScenarioIndexEntry;
-struct WindowCloseModifier;
enum class VisibilityCache : uint8_t;
enum class CursorID : uint8_t;
enum class CloseWindowModifier : uint8_t;
-using rct_windownumber = uint16_t;
-
namespace OpenRCT2
{
+ using rct_windownumber = int16_t;
+
+ struct WindowBase;
+ struct WindowCloseModifier;
+
enum class RideConstructionState : uint8_t;
-}
-struct WindowIdentifier
-{
- WindowClass classification;
- rct_windownumber number;
-};
-
-struct WidgetIdentifier
-{
- WindowIdentifier window;
- WidgetIndex widget_index;
-};
-
-extern WindowCloseModifier gLastCloseModifier;
-
-using WidgetFlags = uint32_t;
-namespace OpenRCT2::WIDGET_FLAGS
-{
- const WidgetFlags TEXT_IS_STRING = 1 << 0;
- const WidgetFlags IS_PRESSED = 1 << 2;
- const WidgetFlags IS_DISABLED = 1 << 3;
- const WidgetFlags TOOLTIP_IS_STRING = 1 << 4;
- const WidgetFlags IS_HIDDEN = 1 << 5;
- const WidgetFlags IS_HOLDABLE = 1 << 6;
-} // namespace OpenRCT2::WIDGET_FLAGS
-
-enum class WindowWidgetType : uint8_t;
-
-struct Widget
-{
- WindowWidgetType type;
- uint8_t colour;
- int16_t left;
- int16_t right;
- int16_t top;
- int16_t bottom;
- union
+ struct WindowIdentifier
{
- uint32_t content;
- ImageId image;
- StringId text;
- utf8* string;
+ WindowClass classification;
+ rct_windownumber number;
};
- StringId tooltip;
- // New properties
- WidgetFlags flags{};
- utf8* sztooltip{};
-
- int16_t width() const
+ struct WidgetIdentifier
{
- return right - left;
- }
+ WindowIdentifier window;
+ WidgetIndex widget_index;
+ };
- int16_t height() const
+ extern WindowCloseModifier gLastCloseModifier;
+
+ /**
+ * Viewport structure
+ */
+ struct Viewport
{
- return bottom - top;
- }
+ int32_t width{};
+ int32_t height{};
+ ScreenCoordsXY pos{};
+ ScreenCoordsXY viewPos{};
+ uint32_t flags{};
+ ZoomLevel zoom{};
+ uint8_t rotation{};
+ VisibilityCache visibility{};
- int16_t midX() const
- {
- return (left + right) / 2;
- }
-
- int16_t midY() const
- {
- return (top + bottom) / 2;
- }
-
- int16_t textTop() const
- {
- if (height() >= 10)
- return std::max(top, top + (height() / 2) - 5);
-
- return top - 1;
- }
-
- void moveRight(int32_t amount)
- {
- left += amount;
- right += amount;
- }
-
- void moveDown(int32_t amount)
- {
- top += amount;
- bottom += amount;
- }
-
- void moveTo(ScreenCoordsXY coords)
- {
- moveRight(coords.x - left);
- moveDown(coords.y - top);
- }
-
- void moveToX(int16_t x)
- {
- moveRight(x - left);
- }
-
- void moveToY(int16_t y)
- {
- moveDown(y - top);
- }
-
- bool IsVisible() const
- {
- return !(flags & OpenRCT2::WIDGET_FLAGS::IS_HIDDEN);
- }
-};
-
-/**
- * Viewport structure
- */
-struct Viewport
-{
- int32_t width{};
- int32_t height{};
- ScreenCoordsXY pos{};
- ScreenCoordsXY viewPos{};
- uint32_t flags{};
- ZoomLevel zoom{};
- uint8_t rotation{};
- VisibilityCache visibility{};
-
- [[nodiscard]] constexpr int32_t ViewWidth() const
- {
- return zoom.ApplyTo(width);
- }
-
- [[nodiscard]] constexpr int32_t ViewHeight() const
- {
- return zoom.ApplyTo(height);
- }
-
- // Use this function on coordinates that are relative to the viewport zoom i.e. a peeps x, y position after transforming
- // from its x, y, z
- [[nodiscard]] constexpr bool Contains(const ScreenCoordsXY& vpos) const
- {
- return (
- vpos.y >= viewPos.y && vpos.y < viewPos.y + ViewHeight() && vpos.x >= viewPos.x
- && vpos.x < viewPos.x + ViewWidth());
- }
-
- // Use this function on coordinates that are relative to the screen that is been drawn i.e. the cursor position
- [[nodiscard]] constexpr bool ContainsScreen(const ScreenCoordsXY& sPos) const
- {
- return (sPos.x >= pos.x && sPos.x < pos.x + width && sPos.y >= pos.y && sPos.y < pos.y + height);
- }
-
- [[nodiscard]] ScreenCoordsXY ScreenToViewportCoord(const ScreenCoordsXY& screenCoord) const;
-
- void Invalidate() const;
-};
-
-struct Focus
-{
- using CoordinateFocus = CoordsXYZ;
- using EntityFocus = EntityId;
-
- ZoomLevel zoom{};
- std::variant data;
-
- template
- constexpr explicit Focus(T newValue, ZoomLevel newZoom = {})
- {
- data = newValue;
- zoom = newZoom;
- }
-
- CoordsXYZ GetPos() const;
-
- constexpr bool operator==(const Focus& other) const
- {
- if (zoom != other.zoom)
+ [[nodiscard]] constexpr int32_t ViewWidth() const
{
- return false;
+ return zoom.ApplyTo(width);
}
- return data == other.data;
- }
- constexpr bool operator!=(const Focus& other) const
+
+ [[nodiscard]] constexpr int32_t ViewHeight() const
+ {
+ return zoom.ApplyTo(height);
+ }
+
+ // Use this function on coordinates that are relative to the viewport zoom i.e. a peeps x, y position after transforming
+ // from its x, y, z
+ [[nodiscard]] constexpr bool Contains(const ScreenCoordsXY& vpos) const
+ {
+ return (
+ vpos.y >= viewPos.y && vpos.y < viewPos.y + ViewHeight() && vpos.x >= viewPos.x
+ && vpos.x < viewPos.x + ViewWidth());
+ }
+
+ // Use this function on coordinates that are relative to the screen that is been drawn i.e. the cursor position
+ [[nodiscard]] constexpr bool ContainsScreen(const ScreenCoordsXY& sPos) const
+ {
+ return (sPos.x >= pos.x && sPos.x < pos.x + width && sPos.y >= pos.y && sPos.y < pos.y + height);
+ }
+
+ [[nodiscard]] ScreenCoordsXY ScreenToViewportCoord(const ScreenCoordsXY& screenCoord) const;
+
+ void Invalidate() const;
+ };
+
+ struct Focus
{
- return !(*this == other);
- }
-};
+ using CoordinateFocus = CoordsXYZ;
+ using EntityFocus = EntityId;
-struct WindowCloseModifier
-{
- WindowIdentifier window;
- CloseWindowModifier modifier;
-};
+ ZoomLevel zoom{};
+ std::variant data;
-struct WindowBase;
+ template
+ constexpr explicit Focus(T newValue, ZoomLevel newZoom = {})
+ {
+ data = newValue;
+ zoom = newZoom;
+ }
+
+ CoordsXYZ GetPos() const;
+
+ constexpr bool operator==(const Focus& other) const
+ {
+ if (zoom != other.zoom)
+ {
+ return false;
+ }
+ return data == other.data;
+ }
+ constexpr bool operator!=(const Focus& other) const
+ {
+ return !(*this == other);
+ }
+ };
+
+ struct WindowCloseModifier
+ {
+ WindowIdentifier window;
+ CloseWindowModifier modifier;
+ };
+
+ struct WindowBase;
#define RCT_WINDOW_RIGHT(w) ((w)->windowPos.x + (w)->width)
#define RCT_WINDOW_BOTTOM(w) ((w)->windowPos.y + (w)->height)
-enum WINDOW_FLAGS
-{
- /*
- WF_TIMEOUT_SHL = 0,
- WF_TIMEOUT_MASK = 7,
- WF_DRAGGING = 1 << 3,
- WF_SCROLLER_UP = 1 << 4,
- WF_SCROLLER_DOWN = 1 << 5,
- WF_SCROLLER_MIDDLE = 1 << 6,
- WF_DISABLE_VP_SCROLL = 1 << 9,
- */
+ enum WINDOW_FLAGS
+ {
+ /*
+ WF_TIMEOUT_SHL = 0,
+ WF_TIMEOUT_MASK = 7,
+ WF_DRAGGING = 1 << 3,
+ WF_SCROLLER_UP = 1 << 4,
+ WF_SCROLLER_DOWN = 1 << 5,
+ WF_SCROLLER_MIDDLE = 1 << 6,
+ WF_DISABLE_VP_SCROLL = 1 << 9,
+ */
- WF_STICK_TO_BACK = (1 << 0),
- WF_STICK_TO_FRONT = (1 << 1),
- WF_NO_SCROLLING = (1 << 2), // User is unable to scroll this viewport
- WF_SCROLLING_TO_LOCATION = (1 << 3),
- WF_TRANSPARENT = (1 << 4),
- WF_NO_BACKGROUND = (1 << 5), // Instead of half transparency, completely remove the window background
- WF_DEAD = (1u << 6), // Window is closed and will be deleted in the next update.
- WF_7 = (1 << 7),
- WF_RESIZABLE = (1 << 8),
- WF_NO_AUTO_CLOSE = (1 << 9), // Don't auto close this window if too many windows are open
- WF_10 = (1 << 10),
- WF_WHITE_BORDER_ONE = (1 << 12),
- WF_WHITE_BORDER_MASK = (1 << 12) | (1 << 13),
+ WF_STICK_TO_BACK = (1 << 0),
+ WF_STICK_TO_FRONT = (1 << 1),
+ WF_NO_SCROLLING = (1 << 2), // User is unable to scroll this viewport
+ WF_SCROLLING_TO_LOCATION = (1 << 3),
+ WF_TRANSPARENT = (1 << 4),
+ WF_NO_BACKGROUND = (1 << 5), // Instead of half transparency, completely remove the window background
+ WF_DEAD = (1u << 6), // Window is closed and will be deleted in the next update.
+ WF_7 = (1 << 7),
+ WF_RESIZABLE = (1 << 8),
+ WF_NO_AUTO_CLOSE = (1 << 9), // Don't auto close this window if too many windows are open
+ WF_10 = (1 << 10),
+ WF_WHITE_BORDER_ONE = (1 << 12),
+ WF_WHITE_BORDER_MASK = (1 << 12) | (1 << 13),
- WF_NO_SNAPPING = (1 << 15),
+ WF_NO_SNAPPING = (1 << 15),
- // Create only flags
- WF_AUTO_POSITION = (1 << 16),
- WF_CENTRE_SCREEN = (1 << 17),
-};
+ // Create only flags
+ WF_AUTO_POSITION = (1 << 16),
+ WF_CENTRE_SCREEN = (1 << 17),
+ };
-enum
-{
- WV_PARK_AWARDS,
- WV_PARK_RATING,
- WV_PARK_OBJECTIVE,
- WV_PARK_GUESTS,
- WV_FINANCES_RESEARCH,
- WV_RIDE_RESEARCH,
- WV_MAZE_CONSTRUCTION,
- WV_NETWORK_PASSWORD,
- WV_EDITOR_BOTTOM_TOOLBAR,
- WV_CHANGELOG,
- WV_NEW_VERSION_INFO,
- WV_FINANCE_MARKETING,
- WV_CONTRIBUTORS,
-};
+ enum
+ {
+ WV_PARK_AWARDS,
+ WV_PARK_RATING,
+ WV_PARK_OBJECTIVE,
+ WV_PARK_GUESTS,
+ WV_FINANCES_RESEARCH,
+ WV_RIDE_RESEARCH,
+ WV_MAZE_CONSTRUCTION,
+ WV_NETWORK_PASSWORD,
+ WV_EDITOR_BOTTOM_TOOLBAR,
+ WV_CHANGELOG,
+ WV_NEW_VERSION_INFO,
+ WV_FINANCE_MARKETING,
+ WV_CONTRIBUTORS,
+ };
-enum WindowDetail
-{
- WD_BANNER,
- WD_NEW_CAMPAIGN,
- WD_DEMOLISH_RIDE,
- WD_REFURBISH_RIDE,
- WD_SIGN,
- WD_SIGN_SMALL,
+ enum WindowDetail
+ {
+ WD_BANNER,
+ WD_NEW_CAMPAIGN,
+ WD_DEMOLISH_RIDE,
+ WD_REFURBISH_RIDE,
+ WD_SIGN,
+ WD_SIGN_SMALL,
- WD_PLAYER,
+ WD_PLAYER,
- WD_VEHICLE,
- WD_TRACK,
+ WD_VEHICLE,
+ WD_TRACK,
- WD_NULL = 255,
-};
+ WD_NULL = 255,
+ };
+} // namespace OpenRCT2
#define validate_global_widx(wc, widx) \
static_assert(widx == wc##__##widx, "Global WIDX of " #widx " doesn't match actual value.")
@@ -344,29 +243,29 @@ constexpr int32_t WC_TILE_INSPECTOR__WIDX_SPINNER_X_DECREASE = 7;
constexpr int32_t WC_TILE_INSPECTOR__WIDX_SPINNER_Y_INCREASE = 10;
constexpr int32_t WC_TILE_INSPECTOR__WIDX_SPINNER_Y_DECREASE = 11;
constexpr int32_t WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_SURFACE = EnumValue(TileInspectorPage::Surface);
-constexpr int32_t WC_TILE_INSPECTOR__WIDX_SURFACE_SPINNER_HEIGHT_INCREASE = 27;
-constexpr int32_t WC_TILE_INSPECTOR__WIDX_SURFACE_SPINNER_HEIGHT_DECREASE = 28;
+constexpr int32_t WC_TILE_INSPECTOR__WIDX_SURFACE_SPINNER_HEIGHT_INCREASE = 29;
+constexpr int32_t WC_TILE_INSPECTOR__WIDX_SURFACE_SPINNER_HEIGHT_DECREASE = 30;
constexpr int32_t WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_PATH = EnumValue(TileInspectorPage::Path);
-constexpr int32_t WC_TILE_INSPECTOR__WIDX_PATH_SPINNER_HEIGHT_INCREASE = 27;
-constexpr int32_t WC_TILE_INSPECTOR__WIDX_PATH_SPINNER_HEIGHT_DECREASE = 28;
+constexpr int32_t WC_TILE_INSPECTOR__WIDX_PATH_SPINNER_HEIGHT_INCREASE = 29;
+constexpr int32_t WC_TILE_INSPECTOR__WIDX_PATH_SPINNER_HEIGHT_DECREASE = 30;
constexpr int32_t WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_TRACK = EnumValue(TileInspectorPage::Track);
-constexpr int32_t WC_TILE_INSPECTOR__WIDX_TRACK_SPINNER_HEIGHT_INCREASE = 28;
-constexpr int32_t WC_TILE_INSPECTOR__WIDX_TRACK_SPINNER_HEIGHT_DECREASE = 29;
+constexpr int32_t WC_TILE_INSPECTOR__WIDX_TRACK_SPINNER_HEIGHT_INCREASE = 30;
+constexpr int32_t WC_TILE_INSPECTOR__WIDX_TRACK_SPINNER_HEIGHT_DECREASE = 31;
constexpr int32_t WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_SCENERY = EnumValue(TileInspectorPage::Scenery);
-constexpr int32_t WC_TILE_INSPECTOR__WIDX_SCENERY_SPINNER_HEIGHT_INCREASE = 27;
-constexpr int32_t WC_TILE_INSPECTOR__WIDX_SCENERY_SPINNER_HEIGHT_DECREASE = 28;
+constexpr int32_t WC_TILE_INSPECTOR__WIDX_SCENERY_SPINNER_HEIGHT_INCREASE = 29;
+constexpr int32_t WC_TILE_INSPECTOR__WIDX_SCENERY_SPINNER_HEIGHT_DECREASE = 30;
constexpr int32_t WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_ENTRANCE = EnumValue(TileInspectorPage::Entrance);
-constexpr int32_t WC_TILE_INSPECTOR__WIDX_ENTRANCE_SPINNER_HEIGHT_INCREASE = 27;
-constexpr int32_t WC_TILE_INSPECTOR__WIDX_ENTRANCE_SPINNER_HEIGHT_DECREASE = 28;
+constexpr int32_t WC_TILE_INSPECTOR__WIDX_ENTRANCE_SPINNER_HEIGHT_INCREASE = 29;
+constexpr int32_t WC_TILE_INSPECTOR__WIDX_ENTRANCE_SPINNER_HEIGHT_DECREASE = 30;
constexpr int32_t WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_WALL = EnumValue(TileInspectorPage::Wall);
-constexpr int32_t WC_TILE_INSPECTOR__WIDX_WALL_SPINNER_HEIGHT_INCREASE = 27;
-constexpr int32_t WC_TILE_INSPECTOR__WIDX_WALL_SPINNER_HEIGHT_DECREASE = 28;
+constexpr int32_t WC_TILE_INSPECTOR__WIDX_WALL_SPINNER_HEIGHT_INCREASE = 29;
+constexpr int32_t WC_TILE_INSPECTOR__WIDX_WALL_SPINNER_HEIGHT_DECREASE = 30;
constexpr int32_t WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_LARGE_SCENERY = EnumValue(TileInspectorPage::LargeScenery);
-constexpr int32_t WC_TILE_INSPECTOR__WIDX_LARGE_SCENERY_SPINNER_HEIGHT_INCREASE = 27;
-constexpr int32_t WC_TILE_INSPECTOR__WIDX_LARGE_SCENERY_SPINNER_HEIGHT_DECREASE = 28;
+constexpr int32_t WC_TILE_INSPECTOR__WIDX_LARGE_SCENERY_SPINNER_HEIGHT_INCREASE = 29;
+constexpr int32_t WC_TILE_INSPECTOR__WIDX_LARGE_SCENERY_SPINNER_HEIGHT_DECREASE = 30;
constexpr int32_t WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_BANNER = EnumValue(TileInspectorPage::Banner);
-constexpr int32_t WC_TILE_INSPECTOR__WIDX_BANNER_SPINNER_HEIGHT_INCREASE = 27;
-constexpr int32_t WC_TILE_INSPECTOR__WIDX_BANNER_SPINNER_HEIGHT_DECREASE = 28;
+constexpr int32_t WC_TILE_INSPECTOR__WIDX_BANNER_SPINNER_HEIGHT_INCREASE = 29;
+constexpr int32_t WC_TILE_INSPECTOR__WIDX_BANNER_SPINNER_HEIGHT_DECREASE = 30;
enum class PromptMode : uint8_t
{
@@ -444,105 +343,109 @@ enum class Tool
Bulldozer = 27,
};
-struct WidgetRef
+namespace OpenRCT2
{
- WindowClass window_classification;
- rct_windownumber window_number;
- WidgetIndex widget_index;
-};
+ struct WidgetRef
+ {
+ WindowClass window_classification;
+ rct_windownumber window_number;
+ WidgetIndex widget_index;
+ };
-extern Tool gCurrentToolId;
-extern WidgetRef gCurrentToolWidget;
+ extern Tool gCurrentToolId;
+ extern WidgetRef gCurrentToolWidget;
-using modal_callback = void (*)(int32_t result);
-using CloseCallback = void (*)();
+ using modal_callback = void (*)(int32_t result);
+ using CloseCallback = void (*)();
-constexpr int8_t kWindowLimitMin = 4;
-constexpr int8_t kWindowLimitMax = 64;
-constexpr int8_t kWindowLimitReserved = 4; // Used to reserve room for the main viewport, toolbars, etc.
+ constexpr int8_t kWindowLimitMin = 4;
+ constexpr int8_t kWindowLimitMax = 64;
+ constexpr int8_t kWindowLimitReserved = 4; // Used to reserve room for the main viewport, toolbars, etc.
-extern WindowBase* gWindowAudioExclusive;
+ extern WindowBase* gWindowAudioExclusive;
-extern uint32_t gWindowUpdateTicks;
+ extern uint32_t gWindowUpdateTicks;
-extern colour_t gCurrentWindowColours[3];
+ extern colour_t gCurrentWindowColours[3];
-std::list>::iterator WindowGetIterator(const WindowBase* w);
-void WindowVisitEach(std::function func);
+ std::list>::iterator WindowGetIterator(const WindowBase* w);
+ void WindowVisitEach(std::function func);
-void WindowSetFlagForAllViewports(uint32_t viewportFlag, bool enabled);
+ void WindowSetFlagForAllViewports(uint32_t viewportFlag, bool enabled);
-void WindowDispatchUpdateAll();
-void WindowUpdateAllViewports();
-void WindowUpdateAll();
-void WindowNotifyLanguageChange();
+ void WindowDispatchUpdateAll();
+ void WindowUpdateAllViewports();
+ void WindowUpdateAll();
+ void WindowNotifyLanguageChange();
-void WindowSetWindowLimit(int32_t value);
+ void WindowSetWindowLimit(int32_t value);
-WindowBase* WindowBringToFront(WindowBase& w);
-WindowBase* WindowBringToFrontByClass(WindowClass cls);
-WindowBase* WindowBringToFrontByClassWithFlags(WindowClass cls, uint16_t flags);
-WindowBase* WindowBringToFrontByNumber(WindowClass cls, rct_windownumber number);
+ WindowBase* WindowBringToFront(WindowBase& w);
+ WindowBase* WindowBringToFrontByClass(WindowClass cls);
+ WindowBase* WindowBringToFrontByClassWithFlags(WindowClass cls, uint16_t flags);
+ WindowBase* WindowBringToFrontByNumber(WindowClass cls, rct_windownumber number);
-void WindowClose(WindowBase& window);
-void WindowCloseByClass(WindowClass cls);
-void WindowCloseByNumber(WindowClass cls, rct_windownumber number);
-void WindowCloseByNumber(WindowClass cls, EntityId number);
-void WindowCloseTop();
-void WindowCloseAll();
-void WindowCloseAllExceptClass(WindowClass cls);
-void WindowCloseAllExceptFlags(uint16_t flags);
-void WindowCloseAllExceptNumberAndClass(rct_windownumber number, WindowClass cls);
-void WindowInvalidateByClass(WindowClass cls);
-void WindowInvalidateByNumber(WindowClass cls, rct_windownumber number);
-void WindowInvalidateByNumber(WindowClass cls, EntityId id);
-void WindowInvalidateAll();
-void WidgetInvalidate(WindowBase& w, WidgetIndex widgetIndex);
-void WidgetInvalidateByClass(WindowClass cls, WidgetIndex widgetIndex);
-void WidgetInvalidateByNumber(WindowClass cls, rct_windownumber number, WidgetIndex widgetIndex);
+ void WindowClose(WindowBase& window);
+ void WindowCloseByClass(WindowClass cls);
+ void WindowCloseByNumber(WindowClass cls, rct_windownumber number);
+ void WindowCloseByNumber(WindowClass cls, EntityId number);
+ void WindowCloseTop();
+ void WindowCloseAll();
+ void WindowCloseAllExceptClass(WindowClass cls);
+ void WindowCloseAllExceptFlags(uint16_t flags);
+ void WindowCloseAllExceptNumberAndClass(rct_windownumber number, WindowClass cls);
+ void WindowInvalidateByClass(WindowClass cls);
+ void WindowInvalidateByNumber(WindowClass cls, rct_windownumber number);
+ void WindowInvalidateByNumber(WindowClass cls, EntityId id);
+ void WindowInvalidateAll();
+ void WidgetInvalidate(WindowBase& w, WidgetIndex widgetIndex);
+ void WidgetInvalidateByClass(WindowClass cls, WidgetIndex widgetIndex);
+ void WidgetInvalidateByNumber(WindowClass cls, rct_windownumber number, WidgetIndex widgetIndex);
-int32_t WindowGetScrollDataIndex(const WindowBase& w, WidgetIndex widget_index);
+ int32_t WindowGetScrollDataIndex(const WindowBase& w, WidgetIndex widget_index);
-void WindowPushOthersRight(WindowBase& w);
-void WindowPushOthersBelow(WindowBase& w1);
+ void WindowPushOthersRight(WindowBase& w);
+ void WindowPushOthersBelow(WindowBase& w1);
-WindowBase* WindowGetMain();
+ WindowBase* WindowGetMain();
-void WindowScrollToLocation(WindowBase& w, const CoordsXYZ& coords);
-void WindowViewportGetMapCoordsByCursor(
- const WindowBase& w, int32_t* map_x, int32_t* map_y, int32_t* offset_x, int32_t* offset_y);
-void WindowViewportCentreTileAroundCursor(WindowBase& w, int32_t map_x, int32_t map_y, int32_t offset_x, int32_t offset_y);
-void WindowCheckAllValidZoom();
-void WindowZoomSet(WindowBase& w, ZoomLevel zoomLevel, bool atCursor);
+ void WindowScrollToLocation(WindowBase& w, const CoordsXYZ& coords);
+ void WindowViewportGetMapCoordsByCursor(
+ const WindowBase& w, int32_t* map_x, int32_t* map_y, int32_t* offset_x, int32_t* offset_y);
+ void WindowViewportCentreTileAroundCursor(WindowBase& w, int32_t map_x, int32_t map_y, int32_t offset_x, int32_t offset_y);
+ void WindowCheckAllValidZoom();
+ void WindowZoomSet(WindowBase& w, ZoomLevel zoomLevel, bool atCursor);
-void WindowDrawAll(DrawPixelInfo& dpi, int32_t left, int32_t top, int32_t right, int32_t bottom);
-void WindowDraw(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom);
+ void WindowDrawAll(DrawPixelInfo& dpi, int32_t left, int32_t top, int32_t right, int32_t bottom);
+ void WindowDraw(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom);
-bool isToolActive(WindowClass cls);
-bool isToolActive(WindowClass cls, rct_windownumber number);
-bool isToolActive(WindowClass cls, WidgetIndex widgetIndex);
-bool isToolActive(WindowClass cls, WidgetIndex widgetIndex, rct_windownumber number);
-bool isToolActive(const WindowBase& w, WidgetIndex widgetIndex);
-bool ToolSet(const WindowBase& w, WidgetIndex widgetIndex, Tool tool);
-void ToolCancel();
+ bool isToolActive(WindowClass cls);
+ bool isToolActive(WindowClass cls, rct_windownumber number);
+ bool isToolActive(WindowClass cls, WidgetIndex widgetIndex);
+ bool isToolActive(WindowClass cls, WidgetIndex widgetIndex, rct_windownumber number);
+ bool isToolActive(const WindowBase& w, WidgetIndex widgetIndex);
+ bool ToolSet(const WindowBase& w, WidgetIndex widgetIndex, Tool tool);
+ void ToolCancel();
-void WindowCloseConstructionWindows();
+ void WindowCloseConstructionWindows();
-void WindowUpdateViewportRideMusic();
+ void WindowUpdateViewportRideMusic();
-Viewport* WindowGetViewport(WindowBase* window);
+ Viewport* WindowGetViewport(WindowBase* window);
-// Open window functions
-void WindowResizeGui(int32_t width, int32_t height);
-void WindowResizeGuiScenarioEditor(int32_t width, int32_t height);
+ // Open window functions
+ void WindowResizeGui(int32_t width, int32_t height);
+ void WindowResizeGuiScenarioEditor(int32_t width, int32_t height);
-void TextinputCancel();
+ void TextinputCancel();
-bool WindowIsVisible(WindowBase& w);
+ bool WindowIsVisible(WindowBase& w);
-Viewport* WindowGetPreviousViewport(Viewport* current);
-void WindowResetVisibilities();
-void WindowInitAll();
+ Viewport* WindowGetPreviousViewport(Viewport* current);
+ void WindowResetVisibilities();
+ void WindowInitAll();
-void WindowFollowSprite(WindowBase& w, EntityId spriteIndex);
-void WindowUnfollowSprite(WindowBase& w);
+ void WindowFollowSprite(WindowBase& w, EntityId spriteIndex);
+ void WindowUnfollowSprite(WindowBase& w);
+
+} // namespace OpenRCT2
diff --git a/src/openrct2/interface/Window_internal.cpp b/src/openrct2/interface/Window_internal.cpp
index fce2f83985..bded773da8 100644
--- a/src/openrct2/interface/Window_internal.cpp
+++ b/src/openrct2/interface/Window_internal.cpp
@@ -5,27 +5,36 @@
#include "Cursors.h"
#include "Viewport.h"
-void WindowBase::SetLocation(const CoordsXYZ& coords)
+namespace OpenRCT2
{
- WindowScrollToLocation(*this, coords);
- flags &= ~WF_SCROLLING_TO_LOCATION;
-}
+ void WindowBase::SetLocation(const CoordsXYZ& coords)
+ {
+ WindowScrollToLocation(*this, coords);
+ flags &= ~WF_SCROLLING_TO_LOCATION;
+ }
-void WindowBase::Invalidate()
-{
- GfxSetDirtyBlocks({ windowPos, windowPos + ScreenCoordsXY{ width, height } });
-}
+ void WindowBase::Invalidate()
+ {
+ GfxSetDirtyBlocks({ windowPos, windowPos + ScreenCoordsXY{ width, height } });
+ }
-void WindowBase::RemoveViewport()
-{
- if (viewport == nullptr)
- return;
+ void WindowBase::RemoveViewport()
+ {
+ if (viewport == nullptr)
+ return;
- ViewportRemove(viewport);
- viewport = nullptr;
-}
+ ViewportRemove(viewport);
+ viewport = nullptr;
+ }
-CursorID WindowBase::OnCursor(WidgetIndex, const ScreenCoordsXY&, CursorID)
-{
- return CursorID::Arrow;
-}
+ void WindowBase::SetWidgets(const std::span newWidgets)
+ {
+ widgets.clear();
+ widgets.insert(widgets.end(), newWidgets.begin(), newWidgets.end());
+ }
+
+ CursorID WindowBase::OnCursor(WidgetIndex, const ScreenCoordsXY&, CursorID)
+ {
+ return CursorID::Arrow;
+ }
+} // namespace OpenRCT2
diff --git a/src/openrct2/interface/Window_internal.h b/src/openrct2/interface/Window_internal.h
index 83e4305012..471989b5eb 100644
--- a/src/openrct2/interface/Window_internal.h
+++ b/src/openrct2/interface/Window_internal.h
@@ -9,12 +9,15 @@
#pragma once
+#include "../localisation/Formatter.h"
#include "Colour.h"
#include "ScrollArea.h"
#include "Window.h"
#include
#include
+#include
+#include
enum class TileInspectorPage : int16_t;
@@ -27,154 +30,158 @@ struct RCTObjectEntry;
#pragma GCC diagnostic ignored "-Wsuggest-final-types"
#endif
-/**
- * Window structure
- * size: 0x4C0
- */
-struct WindowBase
+namespace OpenRCT2
{
- Viewport* viewport{};
- uint64_t disabled_widgets{};
- uint64_t pressed_widgets{};
- uint64_t hold_down_widgets{};
- Widget* widgets{};
- ScreenCoordsXY windowPos;
- int16_t width{};
- int16_t height{};
- int16_t min_width{};
- int16_t max_width{};
- int16_t min_height{};
- int16_t max_height{};
- union
+ /**
+ * Window structure
+ * size: 0x4C0
+ */
+ struct WindowBase
{
- rct_windownumber number{};
- RideId rideId;
+ Viewport* viewport{};
+ uint64_t disabled_widgets{};
+ uint64_t pressed_widgets{};
+ uint64_t hold_down_widgets{};
+ std::vector widgets{};
+ ScreenCoordsXY windowPos;
+ int16_t width{};
+ int16_t height{};
+ int16_t min_width{};
+ int16_t max_width{};
+ int16_t min_height{};
+ int16_t max_height{};
+ union
+ {
+ rct_windownumber number{};
+ RideId rideId;
+ };
+ uint16_t flags{};
+ OpenRCT2::ScrollArea scrolls[3];
+ uint16_t no_list_items{}; // 0 for no items
+ int16_t selected_list_item{}; // -1 for none selected
+ std::optional focus;
+ union
+ {
+ int16_t page{};
+ TileInspectorPage tileInspectorPage;
+ };
+ uint16_t frame_no{}; // updated every tic for motion in windows sprites
+ uint16_t list_information_type{}; // 0 for none
+ int16_t picked_peep_frame; // Animation frame of picked peep in staff window and guest window
+ int16_t selected_tab{};
+ EntityId viewport_target_sprite{ EntityId::GetNull() };
+ ScreenCoordsXY savedViewPos{};
+ WindowClass classification{};
+ ColourWithFlags colours[6]{};
+ VisibilityCache visibility{};
+ EntityId viewport_smart_follow_sprite{ EntityId::GetNull() }; // Handles setting viewport target sprite etc
+
+ void SetLocation(const CoordsXYZ& coords);
+ void Invalidate();
+ void RemoveViewport();
+ void SetWidgets(const std::span newWidgets);
+
+ WindowBase() = default;
+ WindowBase(WindowBase&) = delete;
+ virtual ~WindowBase() = default;
+
+ WindowBase& operator=(const WindowBase&) = delete;
+
+ // Events
+ virtual void OnOpen()
+ {
+ }
+ virtual bool CanClose()
+ {
+ return true;
+ }
+ virtual void OnClose()
+ {
+ }
+ virtual void OnResize()
+ {
+ }
+ virtual void OnUpdate()
+ {
+ }
+ virtual void OnPeriodicUpdate()
+ {
+ }
+ virtual void OnPrepareDraw()
+ {
+ }
+ virtual void OnDraw(DrawPixelInfo& dpi)
+ {
+ }
+ virtual void OnDrawWidget(WidgetIndex widgetIndex, DrawPixelInfo& dpi)
+ {
+ }
+ virtual OpenRCT2String OnTooltip(WidgetIndex widgetIndex, StringId fallback)
+ {
+ return { fallback, {} };
+ }
+ virtual void OnMouseDown(WidgetIndex widgetIndex)
+ {
+ }
+ virtual void OnMouseUp(WidgetIndex widgetIndex)
+ {
+ }
+ virtual void OnDropdown(WidgetIndex widgetIndex, int32_t selectedIndex)
+ {
+ }
+ virtual void OnTextInput(WidgetIndex widgetIndex, std::string_view text)
+ {
+ }
+ virtual ScreenSize OnScrollGetSize(int32_t scrollIndex)
+ {
+ return {};
+ }
+ virtual void OnScrollSelect(int32_t scrollIndex, int32_t scrollAreaType)
+ {
+ }
+ virtual void OnScrollMouseDrag(int32_t scrollIndex, const ScreenCoordsXY& screenCoords)
+ {
+ }
+ virtual void OnScrollMouseOver(int32_t scrollIndex, const ScreenCoordsXY& screenCoords)
+ {
+ }
+ virtual void OnScrollMouseDown(int32_t scrollIndex, const ScreenCoordsXY& screenCoords)
+ {
+ }
+ virtual void OnScrollDraw(int32_t scrollIndex, DrawPixelInfo& dpi)
+ {
+ }
+ virtual void OnToolUpdate(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
+ {
+ }
+ virtual void OnToolDown(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
+ {
+ }
+ virtual void OnToolDrag(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
+ {
+ }
+ virtual void OnToolUp(WidgetIndex widgetIndex, const ScreenCoordsXY&)
+ {
+ }
+ virtual void OnToolAbort(WidgetIndex widgetIndex)
+ {
+ }
+ virtual void OnViewportRotate()
+ {
+ }
+ virtual void OnMoved(const ScreenCoordsXY&)
+ {
+ }
+ virtual CursorID OnCursor(WidgetIndex, const ScreenCoordsXY&, CursorID);
+ virtual void OnLanguageChange()
+ {
+ }
};
- uint16_t flags{};
- OpenRCT2::ScrollArea scrolls[3];
- uint16_t no_list_items{}; // 0 for no items
- int16_t selected_list_item{}; // -1 for none selected
- std::optional focus;
- union
- {
- int16_t page{};
- TileInspectorPage tileInspectorPage;
- };
- uint16_t frame_no{}; // updated every tic for motion in windows sprites
- uint16_t list_information_type{}; // 0 for none
- int16_t picked_peep_frame; // Animation frame of picked peep in staff window and guest window
- int16_t selected_tab{};
- EntityId viewport_target_sprite{ EntityId::GetNull() };
- ScreenCoordsXY savedViewPos{};
- WindowClass classification{};
- ColourWithFlags colours[6]{};
- VisibilityCache visibility{};
- EntityId viewport_smart_follow_sprite{ EntityId::GetNull() }; // Handles setting viewport target sprite etc
-
- void SetLocation(const CoordsXYZ& coords);
- void Invalidate();
- void RemoveViewport();
-
- WindowBase() = default;
- WindowBase(WindowBase&) = delete;
- virtual ~WindowBase() = default;
-
- WindowBase& operator=(const WindowBase&) = delete;
-
- // Events
- virtual void OnOpen()
- {
- }
- virtual bool CanClose()
- {
- return true;
- }
- virtual void OnClose()
- {
- }
- virtual void OnResize()
- {
- }
- virtual void OnUpdate()
- {
- }
- virtual void OnPeriodicUpdate()
- {
- }
- virtual void OnPrepareDraw()
- {
- }
- virtual void OnDraw(DrawPixelInfo& dpi)
- {
- }
- virtual void OnDrawWidget(WidgetIndex widgetIndex, DrawPixelInfo& dpi)
- {
- }
- virtual OpenRCT2String OnTooltip(WidgetIndex widgetIndex, StringId fallback)
- {
- return { fallback, {} };
- }
- virtual void OnMouseDown(WidgetIndex widgetIndex)
- {
- }
- virtual void OnMouseUp(WidgetIndex widgetIndex)
- {
- }
- virtual void OnDropdown(WidgetIndex widgetIndex, int32_t selectedIndex)
- {
- }
- virtual void OnTextInput(WidgetIndex widgetIndex, std::string_view text)
- {
- }
- virtual ScreenSize OnScrollGetSize(int32_t scrollIndex)
- {
- return {};
- }
- virtual void OnScrollSelect(int32_t scrollIndex, int32_t scrollAreaType)
- {
- }
- virtual void OnScrollMouseDrag(int32_t scrollIndex, const ScreenCoordsXY& screenCoords)
- {
- }
- virtual void OnScrollMouseOver(int32_t scrollIndex, const ScreenCoordsXY& screenCoords)
- {
- }
- virtual void OnScrollMouseDown(int32_t scrollIndex, const ScreenCoordsXY& screenCoords)
- {
- }
- virtual void OnScrollDraw(int32_t scrollIndex, DrawPixelInfo& dpi)
- {
- }
- virtual void OnToolUpdate(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
- {
- }
- virtual void OnToolDown(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
- {
- }
- virtual void OnToolDrag(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
- {
- }
- virtual void OnToolUp(WidgetIndex widgetIndex, const ScreenCoordsXY&)
- {
- }
- virtual void OnToolAbort(WidgetIndex widgetIndex)
- {
- }
- virtual void OnViewportRotate()
- {
- }
- virtual void OnMoved(const ScreenCoordsXY&)
- {
- }
- virtual CursorID OnCursor(WidgetIndex, const ScreenCoordsXY&, CursorID);
- virtual void OnLanguageChange()
- {
- }
-};
#ifdef __WARN_SUGGEST_FINAL_METHODS__
#pragma GCC diagnostic pop
#endif
-// rct2: 0x01420078
-extern std::list