From 45ff80d890ba6a0cc6baa9cfecab3827bd4d6c15 Mon Sep 17 00:00:00 2001 From: Marino Rottier Date: Tue, 28 Apr 2026 09:26:02 +0200 Subject: [PATCH] Refactor widget state to single storage model (#26443) * Allow flag/bitmask coexistence in readers * Add factory helpers and bulk setters for per-widget flags * Switch coexistence from OR-both to per-window opt-in * Migrate seven small windows to per-widget flags * Migrate seven more windows to per-widget flags * Migrate Cheats, MapGen and Footpath to per-widget flags * Fix #26421: scenery tab highlight wraps when there are 64+ groups * Migrate Ride window to per-widget flags * Migrate ride and maze construction windows to per-widget flags * Migrate six more windows to per-widget flags * Migrate Banner, EditorScenarioOptions and RideList to per-widget flags * Migrate SceneryScatter and LoadSave to per-widget flags * Migrate EditorObjectSelection, GameBottomToolbar, Guest, Map, NewRide and Park to per-widget flags * Migrate TopToolbar, TrackList, Research, Player and Options to per-widget flags * Opt in remaining windows to per-widget flags * Narrow getters and setters to per-widget flags * Remove bitmask fields and useWidgetFlags switch * Restore switch statements for tab/density pressed state * Add makeHoldableSpinnerWidgets to drop per-page loops * Update tests for per-widget flag storage * Add changelog entry for #26421 * Reword narrative-tense comments from the migration * Fix clang-format violations * Remove dead holdable-widget tables from Park and Finances --- distribution/changelog.txt | 1 + src/openrct2-ui/interface/Widget.cpp | 62 ++-- src/openrct2-ui/interface/Widget.h | 28 ++ src/openrct2-ui/windows/About.cpp | 7 +- src/openrct2-ui/windows/Banner.cpp | 14 +- src/openrct2-ui/windows/Cheats.cpp | 61 ++-- src/openrct2-ui/windows/ClearScenery.cpp | 14 +- src/openrct2-ui/windows/CustomCurrency.cpp | 2 +- .../windows/EditorInventionsList.cpp | 5 +- .../windows/EditorObjectSelection.cpp | 11 +- .../windows/EditorParkEntrance.cpp | 2 +- .../windows/EditorScenarioOptions.cpp | 111 +++----- src/openrct2-ui/windows/Finances.cpp | 20 +- src/openrct2-ui/windows/Footpath.cpp | 93 +++--- src/openrct2-ui/windows/GameBottomToolbar.cpp | 12 +- src/openrct2-ui/windows/Guest.cpp | 37 +-- src/openrct2-ui/windows/InstallTrack.cpp | 11 +- src/openrct2-ui/windows/Land.cpp | 17 +- src/openrct2-ui/windows/LandRights.cpp | 8 +- src/openrct2-ui/windows/LoadSave.cpp | 12 +- src/openrct2-ui/windows/Map.cpp | 21 +- src/openrct2-ui/windows/MapGen.cpp | 116 +++----- src/openrct2-ui/windows/MazeConstruction.cpp | 54 +--- src/openrct2-ui/windows/Multiplayer.cpp | 13 +- src/openrct2-ui/windows/NewCampaign.cpp | 2 +- src/openrct2-ui/windows/NewRide.cpp | 20 +- src/openrct2-ui/windows/Options.cpp | 72 ++--- src/openrct2-ui/windows/Park.cpp | 32 +-- src/openrct2-ui/windows/PatrolArea.cpp | 2 +- src/openrct2-ui/windows/Player.cpp | 12 +- src/openrct2-ui/windows/Research.cpp | 25 +- src/openrct2-ui/windows/Ride.cpp | 266 +++++++----------- src/openrct2-ui/windows/RideConstruction.cpp | 52 ++-- src/openrct2-ui/windows/RideList.cpp | 9 +- src/openrct2-ui/windows/ScenarioSelect.cpp | 18 +- src/openrct2-ui/windows/Scenery.cpp | 26 +- src/openrct2-ui/windows/SceneryScatter.cpp | 16 +- src/openrct2-ui/windows/Staff.cpp | 4 +- src/openrct2-ui/windows/Themes.cpp | 20 +- src/openrct2-ui/windows/TileInspector.cpp | 63 ++--- src/openrct2-ui/windows/TopToolbar.cpp | 30 +- src/openrct2-ui/windows/TrackList.cpp | 18 +- src/openrct2-ui/windows/Transparency.cpp | 3 - src/openrct2-ui/windows/ViewClipping.cpp | 11 +- src/openrct2-ui/windows/Viewport.cpp | 7 +- src/openrct2-ui/windows/Water.cpp | 2 +- src/openrct2/interface/WindowBase.h | 3 - test/tests/CMakeLists.txt | 3 +- test/tests/WidgetStateTests.cpp | 140 +++++++++ test/tests/tests.vcxproj | 1 + 50 files changed, 683 insertions(+), 906 deletions(-) create mode 100644 test/tests/WidgetStateTests.cpp diff --git a/distribution/changelog.txt b/distribution/changelog.txt index dd22b2a663..0710c5c02f 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -13,6 +13,7 @@ - Fix: [#26374] Add higher resolution app icons for Android. - Fix: [#26410] Tiles with water can draw incorrectly when there is something underwater and nothing above water. - Fix: [#26419] Drop count & negative g’s stat requirements for Flying Roller Coaster don’t get nullified by having an inversion. +- Fix: [#26421] Wrong scenery tab highlighted when more than 64 scenery groups are selected. - Fix: [#26425] Benches don't reduce watching spots from 4 to 2 while other path additions do (should be reversed). - Fix: [#26432] Guests choose to head for rides they have already ridden if they don't have a map. diff --git a/src/openrct2-ui/interface/Widget.cpp b/src/openrct2-ui/interface/Widget.cpp index 7824ecc9f4..d05402f9e9 100644 --- a/src/openrct2-ui/interface/Widget.cpp +++ b/src/openrct2-ui/interface/Widget.cpp @@ -904,16 +904,12 @@ namespace OpenRCT2::Ui bool widgetIsDisabled(const WindowBase& w, WidgetIndex widgetIndex) { - if (w.classification == WindowClass::custom) - return w.widgets[widgetIndex].flags.has(WidgetFlag::isDisabled); - return (w.disabledWidgets & (1LL << widgetIndex)) != 0; + return w.widgets[widgetIndex].flags.has(WidgetFlag::isDisabled); } bool widgetIsHoldable(const WindowBase& w, WidgetIndex widgetIndex) { - if (w.classification == WindowClass::custom) - return w.widgets[widgetIndex].flags.has(WidgetFlag::isHoldable); - return (w.holdDownWidgets & (1LL << widgetIndex)) != 0; + return w.widgets[widgetIndex].flags.has(WidgetFlag::isHoldable); } bool widgetIsVisible(const WindowBase& w, WidgetIndex widgetIndex) @@ -923,20 +919,8 @@ namespace OpenRCT2::Ui bool widgetIsPressed(const WindowBase& w, WidgetIndex widgetIndex) { - if (w.classification == WindowClass::custom) - { - if (w.widgets[widgetIndex].flags.has(WidgetFlag::isPressed)) - { - return true; - } - } - else - { - if (w.pressedWidgets & (1LL << widgetIndex)) - { - return true; - } - } + if (w.widgets[widgetIndex].flags.has(WidgetFlag::isPressed)) + return true; if (InputGetState() == InputState::WidgetPressed || InputGetState() == InputState::DropdownActive) { @@ -1113,27 +1097,11 @@ namespace OpenRCT2::Ui void widgetSetDisabled(WindowBase& w, WidgetIndex widgetIndex, bool value) { SafeSetWidgetFlag(w, widgetIndex, WidgetFlag::isDisabled, value); - if (value) - { - w.disabledWidgets |= (1uLL << widgetIndex); - } - else - { - w.disabledWidgets &= ~(1uLL << widgetIndex); - } } void widgetSetHoldable(WindowBase& w, WidgetIndex widgetIndex, bool value) { SafeSetWidgetFlag(w, widgetIndex, WidgetFlag::isHoldable, value); - if (value) - { - w.holdDownWidgets |= (1uLL << widgetIndex); - } - else - { - w.holdDownWidgets &= ~(1uLL << widgetIndex); - } } void widgetSetVisible(WindowBase& w, WidgetIndex widgetIndex, bool value) @@ -1144,10 +1112,6 @@ namespace OpenRCT2::Ui void widgetSetPressed(WindowBase& w, WidgetIndex widgetIndex, bool value) { SafeSetWidgetFlag(w, widgetIndex, WidgetFlag::isPressed, value); - if (value) - w.pressedWidgets |= (1uLL << widgetIndex); - else - w.pressedWidgets &= ~(1uLL << widgetIndex); } void widgetSetCheckboxValue(WindowBase& w, WidgetIndex widgetIndex, bool value) @@ -1155,6 +1119,24 @@ namespace OpenRCT2::Ui widgetSetPressed(w, widgetIndex, value); } + void widgetsClearPressed(WindowBase& w, std::initializer_list indices) + { + for (auto i : indices) + widgetSetPressed(w, i, false); + } + + void widgetSetPressedExclusive(WindowBase& w, std::initializer_list group, WidgetIndex pressed) + { + for (auto i : group) + widgetSetPressed(w, i, i == pressed); + } + + void widgetsSetHoldable(WindowBase& w, std::initializer_list indices) + { + for (auto i : indices) + widgetSetHoldable(w, i, true); + } + static void WidgetTextBoxDraw(RenderTarget& rt, WindowBase& w, WidgetIndex widgetIndex) { // Get the widget diff --git a/src/openrct2-ui/interface/Widget.h b/src/openrct2-ui/interface/Widget.h index 0f148166fe..7d719a408b 100644 --- a/src/openrct2-ui/interface/Widget.h +++ b/src/openrct2-ui/interface/Widget.h @@ -11,6 +11,7 @@ #include "Window.h" +#include #include #include #include @@ -91,6 +92,19 @@ namespace OpenRCT2::Ui return makeWidget(origin, size, type, colour, content, tooltip); } + constexpr Widget withFlag(Widget w, WidgetFlag flag) + { + w.flags.set(flag); + return w; + } + + constexpr Widget makeHoldableWidget( + const ScreenCoordsXY& origin, const ScreenSize& size, WidgetType type, WindowColour colour, + uint32_t content = kWidgetContentEmpty, StringId tooltip = kStringIdNone) + { + return withFlag(makeWidget(origin, size, type, colour, content, tooltip), WidgetFlag::isHoldable); + } + constexpr Widget makeProgressBar( const ScreenCoordsXY& origin, const ScreenSize& size, Drawing::Colour colour, uint8_t lowerBlinkBound = 0, uint8_t upperBlinkBound = 0) @@ -220,6 +234,16 @@ namespace OpenRCT2::Ui makeSpinnerDecreaseWidget(origin, size, type, colour, content, tooltip)); }; + constexpr std::array makeHoldableSpinnerWidgets( + const ScreenCoordsXY& origin, const ScreenSize& size, WidgetType type, WindowColour colour, + uint32_t content = kWidgetContentEmpty, StringId tooltip = kStringIdNone) + { + return makeWidgets( + makeWidget(origin, size, type, colour, content, tooltip), + withFlag(makeSpinnerIncreaseWidget(origin, size, type, colour, content, tooltip), WidgetFlag::isHoldable), + withFlag(makeSpinnerDecreaseWidget(origin, size, type, colour, content, tooltip), WidgetFlag::isHoldable)); + }; + constexpr Widget makeDropdownBoxWidget( const ScreenCoordsXY& origin, const ScreenSize& size, [[maybe_unused]] WidgetType type, WindowColour colour, [[maybe_unused]] uint32_t content = kWidgetContentEmpty, StringId tooltip = kStringIdNone) @@ -266,6 +290,10 @@ namespace OpenRCT2::Ui void widgetSetPressed(WindowBase& w, WidgetIndex widgetIndex, bool value); void widgetSetCheckboxValue(WindowBase& w, WidgetIndex widgetIndex, bool value); + void widgetsClearPressed(WindowBase& w, std::initializer_list indices); + void widgetSetPressedExclusive(WindowBase& w, std::initializer_list group, WidgetIndex pressed); + void widgetsSetHoldable(WindowBase& w, std::initializer_list indices); + void widgetProgressBarSetNewPercentage(Widget& widget, uint8_t newPercentage); void widgetScrollUpdateThumbs(WindowBase& w, WidgetIndex widget_index); diff --git a/src/openrct2-ui/windows/About.cpp b/src/openrct2-ui/windows/About.cpp index df2d3c2707..013424083b 100644 --- a/src/openrct2-ui/windows/About.cpp +++ b/src/openrct2-ui/windows/About.cpp @@ -205,20 +205,21 @@ namespace OpenRCT2::Ui::Windows page = p; currentFrame = 0; - pressedWidgets = 0; WindowSetResize(*this, kWindowSize, kWindowSize); setWidgets(_windowAboutPageWidgets[p]); + WidgetIndex pressedTab = WIDX_TAB_ABOUT_OPENRCT2; switch (p) { case WINDOW_ABOUT_PAGE_OPENRCT2: - pressedWidgets |= (1uLL << WIDX_TAB_ABOUT_OPENRCT2); + pressedTab = WIDX_TAB_ABOUT_OPENRCT2; break; case WINDOW_ABOUT_PAGE_RCT2: - pressedWidgets |= (1uLL << WIDX_TAB_ABOUT_RCT2); + pressedTab = WIDX_TAB_ABOUT_RCT2; break; } + widgetSetPressedExclusive(*this, { WIDX_TAB_ABOUT_OPENRCT2, WIDX_TAB_ABOUT_RCT2 }, pressedTab); } int32_t DrawOpenRCT2Info(Drawing::RenderTarget& rt) diff --git a/src/openrct2-ui/windows/Banner.cpp b/src/openrct2-ui/windows/Banner.cpp index 854a987d25..c7058a6967 100644 --- a/src/openrct2-ui/windows/Banner.cpp +++ b/src/openrct2-ui/windows/Banner.cpp @@ -296,15 +296,11 @@ namespace OpenRCT2::Ui::Windows { colourBtn.type = WidgetType::colourBtn; } - pressedWidgets &= ~(1uLL << WIDX_BANNER_NO_ENTRY); - disabledWidgets &= ~( - (1uLL << WIDX_BANNER_TEXT) | (1uLL << WIDX_TEXT_COLOUR_DROPDOWN) | (1uLL << WIDX_TEXT_COLOUR_DROPDOWN_BUTTON)); - if (banner->flags.has(BannerFlag::noEntry)) - { - pressedWidgets |= (1uLL << WIDX_BANNER_NO_ENTRY); - disabledWidgets |= (1uLL << WIDX_BANNER_TEXT) | (1uLL << WIDX_TEXT_COLOUR_DROPDOWN) - | (1uLL << WIDX_TEXT_COLOUR_DROPDOWN_BUTTON); - } + const bool noEntry = banner->flags.has(BannerFlag::noEntry); + setWidgetPressed(WIDX_BANNER_NO_ENTRY, noEntry); + setWidgetDisabled(WIDX_BANNER_TEXT, noEntry); + setWidgetDisabled(WIDX_TEXT_COLOUR_DROPDOWN, noEntry); + setWidgetDisabled(WIDX_TEXT_COLOUR_DROPDOWN_BUTTON, noEntry); colourBtn.image = getColourButtonImage(banner->colour); Widget& dropDownWidget = widgets[WIDX_TEXT_COLOUR_DROPDOWN]; dropDownWidget.text = kBannerColouredTextFormats[EnumValue(banner->textColour)]; diff --git a/src/openrct2-ui/windows/Cheats.cpp b/src/openrct2-ui/windows/Cheats.cpp index b997208ba1..2474d3d039 100644 --- a/src/openrct2-ui/windows/Cheats.cpp +++ b/src/openrct2-ui/windows/Cheats.cpp @@ -371,29 +371,22 @@ static constexpr std::span window_cheats_page_widgets[] = window_cheats_weather_widgets, }; -static uint64_t window_cheats_page_holdDownWidgets[] = { - (1uLL << WIDX_MONEY_SPINNER_INCREMENT) | - (1uLL << WIDX_MONEY_SPINNER_DECREMENT) | - (1uLL << WIDX_ADD_MONEY), - - (1uLL << WIDX_YEAR_UP) | - (1uLL << WIDX_YEAR_DOWN) | - (1uLL << WIDX_MONTH_UP) | - (1uLL << WIDX_MONTH_DOWN) | - (1uLL << WIDX_DAY_UP) | - (1uLL << WIDX_DAY_DOWN), - - 0, - - 0, - - (1uLL << WIDX_INCREASE_PARK_RATING) | - (1uLL << WIDX_DECREASE_PARK_RATING), - - 0, - - 0, -}; +static void setPageHoldableWidgets(WindowBase& w, int32_t page) +{ + switch (page) + { + case WINDOW_CHEATS_PAGE_MONEY: + widgetsSetHoldable(w, { WIDX_MONEY_SPINNER_INCREMENT, WIDX_MONEY_SPINNER_DECREMENT, WIDX_ADD_MONEY }); + break; + case WINDOW_CHEATS_PAGE_DATE: + widgetsSetHoldable( + w, { WIDX_YEAR_UP, WIDX_YEAR_DOWN, WIDX_MONTH_UP, WIDX_MONTH_DOWN, WIDX_DAY_UP, WIDX_DAY_DOWN }); + break; + case WINDOW_CHEATS_PAGE_PARK: + widgetsSetHoldable(w, { WIDX_INCREASE_PARK_RATING, WIDX_DECREASE_PARK_RATING }); + break; + } +} static StringId window_cheats_page_titles[] = { STR_CHEAT_TITLE_FINANCIAL, @@ -509,14 +502,6 @@ static StringId window_cheats_page_titles[] = { void onPrepareDraw() override { - pressedWidgets = 0; - disabledWidgets = 0; - - // Set correct active tab - for (auto i = 0; i < WINDOW_CHEATS_PAGE_COUNT; i++) - setWidgetPressed(WIDX_TAB_1 + i, false); - setWidgetPressed(WIDX_TAB_1 + page, true); - // Set title widgets[WIDX_TITLE].text = window_cheats_page_titles[page]; @@ -525,10 +510,7 @@ static StringId window_cheats_page_titles[] = { { case WINDOW_CHEATS_PAGE_MONEY: { - if (isInEditorMode()) - { - setWidgetDisabled(WIDX_NO_MONEY, true); - } + setWidgetDisabled(WIDX_NO_MONEY, isInEditorMode()); auto moneyDisabled = (gameState.park.flags & PARK_FLAGS_NO_MONEY) != 0; setCheckboxValue(WIDX_NO_MONEY, moneyDisabled); @@ -598,10 +580,10 @@ static StringId window_cheats_page_titles[] = { widgets[WIDX_STAFF_SPEED].text = _staffSpeedNames[EnumValue(gameState.cheats.selectedStaffSpeed)]; } + setWidgetDisabled(WIDX_TAB_2, isInEditorMode()); + setWidgetDisabled(WIDX_TAB_3, isInEditorMode()); if (isInEditorMode()) { - setWidgetDisabled(WIDX_TAB_2, true); - setWidgetDisabled(WIDX_TAB_3, true); UpdateTabPositions(); } } @@ -748,9 +730,10 @@ static StringId window_cheats_page_titles[] = { page = p; currentFrame = 0; - holdDownWidgets = window_cheats_page_holdDownWidgets[p]; - pressedWidgets = 0; setWidgets(window_cheats_page_widgets[p]); + setPageHoldableWidgets(*this, p); + widgetSetPressedExclusive( + *this, { WIDX_TAB_1, WIDX_TAB_2, WIDX_TAB_3, WIDX_TAB_4, WIDX_TAB_5, WIDX_TAB_6, WIDX_TAB_7 }, WIDX_TAB_1 + p); auto maxY = 0; for (WidgetIndex widgetIdx = WIDX_TAB_CONTENT; widgetIdx < widgets.size(); widgetIdx++) diff --git a/src/openrct2-ui/windows/ClearScenery.cpp b/src/openrct2-ui/windows/ClearScenery.cpp index bc5aee1d2b..8727b1ec7a 100644 --- a/src/openrct2-ui/windows/ClearScenery.cpp +++ b/src/openrct2-ui/windows/ClearScenery.cpp @@ -71,7 +71,12 @@ namespace OpenRCT2::Ui::Windows { setWidgets(window_clear_scenery_widgets); - holdDownWidgets = (1uLL << WIDX_INCREMENT) | (1uLL << WIDX_DECREMENT); + widgetsSetHoldable(*this, { WIDX_INCREMENT, WIDX_DECREMENT }); + widgetSetPressed(*this, WIDX_PREVIEW, true); + widgetSetPressed(*this, WIDX_SMALL_SCENERY, _clearSmallScenery); + widgetSetPressed(*this, WIDX_LARGE_SCENERY, _clearLargeScenery); + widgetSetPressed(*this, WIDX_FOOTPATH, _clearFootpath); + WindowInitScrollWidgets(*this); WindowPushOthersBelow(*this); @@ -104,14 +109,17 @@ namespace OpenRCT2::Ui::Windows } case WIDX_SMALL_SCENERY: _clearSmallScenery ^= 1; + widgetSetPressed(*this, WIDX_SMALL_SCENERY, _clearSmallScenery); invalidate(); break; case WIDX_LARGE_SCENERY: _clearLargeScenery ^= 1; + widgetSetPressed(*this, WIDX_LARGE_SCENERY, _clearLargeScenery); invalidate(); break; case WIDX_FOOTPATH: _clearFootpath ^= 1; + widgetSetPressed(*this, WIDX_FOOTPATH, _clearFootpath); invalidate(); break; } @@ -166,10 +174,6 @@ namespace OpenRCT2::Ui::Windows void onPrepareDraw() override { - // Set the preview image button to be pressed down - pressedWidgets = (1uLL << WIDX_PREVIEW) | (_clearSmallScenery ? (1uLL << WIDX_SMALL_SCENERY) : 0) - | (_clearLargeScenery ? (1uLL << WIDX_LARGE_SCENERY) : 0) | (_clearFootpath ? (1uLL << WIDX_FOOTPATH) : 0); - // Update the preview image (for tool sizes up to 7) widgets[WIDX_PREVIEW].image = ImageId(LandTool::SizeToSpriteIndex(gLandToolSize)); } diff --git a/src/openrct2-ui/windows/CustomCurrency.cpp b/src/openrct2-ui/windows/CustomCurrency.cpp index 163efff2fc..0bddf8acf0 100644 --- a/src/openrct2-ui/windows/CustomCurrency.cpp +++ b/src/openrct2-ui/windows/CustomCurrency.cpp @@ -56,7 +56,7 @@ namespace OpenRCT2::Ui::Windows void onOpen() override { setWidgets(window_custom_currency_widgets); - holdDownWidgets = (1uLL << WIDX_RATE_UP) | (1uLL << WIDX_RATE_DOWN); + widgetsSetHoldable(*this, { WIDX_RATE_UP, WIDX_RATE_DOWN }); WindowInitScrollWidgets(*this); colours[0] = Drawing::Colour::lightBrown; colours[1] = Drawing::Colour::lightBrown; diff --git a/src/openrct2-ui/windows/EditorInventionsList.cpp b/src/openrct2-ui/windows/EditorInventionsList.cpp index b5fbe0bf3b..404b3b994e 100644 --- a/src/openrct2-ui/windows/EditorInventionsList.cpp +++ b/src/openrct2-ui/windows/EditorInventionsList.cpp @@ -157,6 +157,8 @@ namespace OpenRCT2::Ui::Windows ResearchRidesSetup(); setWidgets(_inventionListWidgets); + widgetSetPressed(*this, WIDX_PREVIEW, true); + widgetSetPressed(*this, WIDX_TAB_1, true); initScrollWidgets(); selectedTab = 0; _selectedResearchItem = nullptr; @@ -447,9 +449,6 @@ namespace OpenRCT2::Ui::Windows void onPrepareDraw() override { - pressedWidgets |= 1uLL << WIDX_PREVIEW; - pressedWidgets |= 1uLL << WIDX_TAB_1; - widgets[WIDX_CLOSE].type = gLegacyScene == LegacyScene::scenarioEditor ? WidgetType::empty : WidgetType::closeBox; int16_t scrollListHeight = (height - 88) / 2; diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index c632784965..3f3c293cec 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -299,7 +299,7 @@ namespace OpenRCT2::Ui::Windows _listSortType = RIDE_SORT_TYPE; _listSortDescending = false; - disabledWidgets |= 1u << WIDX_FILTER_RIDE_TAB_FRAME; + setWidgetDisabled(WIDX_FILTER_RIDE_TAB_FRAME, true); VisibleListRefresh(); } @@ -857,7 +857,7 @@ namespace OpenRCT2::Ui::Windows installTrackWidget.moveToX(dropdownWidget.left - installTrackWidget.width() - 11); // Set pressed widgets - pressedWidgets |= 1uLL << WIDX_PREVIEW; + setWidgetPressed(WIDX_PREVIEW, true); SetPressedTab(); // Set window title and buttons @@ -962,13 +962,13 @@ namespace OpenRCT2::Ui::Windows { widgets[WIDX_SUB_TAB_0 + i].tooltip = i < numSubTabs ? currentPage.subTabs[i].tooltip : kStringIdNone; widgets[WIDX_SUB_TAB_0 + i].type = i < numSubTabs ? WidgetType::tab : WidgetType::empty; - pressedWidgets &= ~(1uLL << (WIDX_SUB_TAB_0 + i)); + setWidgetPressed(WIDX_SUB_TAB_0 + i, false); } // Mark current sub-tab as active, and toggle tab frame if (hasSubTabs) { - pressedWidgets |= (1uLL << (WIDX_SUB_TAB_0 + _selectedSubTab)); + setWidgetPressed(WIDX_SUB_TAB_0 + _selectedSubTab, true); widgets[WIDX_FILTER_RIDE_TAB_FRAME].type = WidgetType::imgBtn; } else @@ -1597,9 +1597,8 @@ namespace OpenRCT2::Ui::Windows { for (size_t i = 0; i < std::size(ObjectSelectionPages); i++) { - pressedWidgets &= ~(1ull << (WIDX_TAB_1 + i)); + setWidgetPressed(WIDX_TAB_1 + static_cast(i), static_cast(i) == selectedTab); } - pressedWidgets |= 1LL << (WIDX_TAB_1 + selectedTab); } /** diff --git a/src/openrct2-ui/windows/EditorParkEntrance.cpp b/src/openrct2-ui/windows/EditorParkEntrance.cpp index 903e3266fb..11632ba198 100644 --- a/src/openrct2-ui/windows/EditorParkEntrance.cpp +++ b/src/openrct2-ui/windows/EditorParkEntrance.cpp @@ -272,7 +272,7 @@ namespace OpenRCT2::Ui::Windows auto newMaxHeight = static_cast(kWindowSize.height + kImageSize * (GetNumRows() - 1)); WindowSetResize(*this, kWindowSize, { kWindowSize.width, newMaxHeight }); - pressedWidgets |= 1LL << WIDX_TAB; + widgetSetPressed(*this, WIDX_TAB, true); ToolSet(*this, WIDX_LIST, Tool::entranceDown); gInputFlags.set(InputFlag::allowRightMouseRemoval); diff --git a/src/openrct2-ui/windows/EditorScenarioOptions.cpp b/src/openrct2-ui/windows/EditorScenarioOptions.cpp index 2d602b7ce8..e406684331 100644 --- a/src/openrct2-ui/windows/EditorScenarioOptions.cpp +++ b/src/openrct2-ui/windows/EditorScenarioOptions.cpp @@ -222,10 +222,10 @@ namespace OpenRCT2::Ui::Windows makeWidget ({ 8, 48}, {344, 12}, WidgetType::label, WindowColour::secondary, STR_OBJECTIVE_DROPDOWN_LABEL ), makeWidget ({ 98, 47}, {344, 14}, WidgetType::dropdownMenu, WindowColour::secondary, kStringIdNone, STR_SELECT_OBJECTIVE_FOR_THIS_SCENARIO_TIP), makeWidget ({430, 48}, { 11, 12}, WidgetType::button, WindowColour::secondary, STR_DROPDOWN_GLYPH, STR_SELECT_OBJECTIVE_FOR_THIS_SCENARIO_TIP), - makeWidget ({ 28, 66}, {140, 12}, WidgetType::label, WindowColour::secondary, kStringIdEmpty ), - makeSpinnerWidgets({158, 65}, {120, 14}, WidgetType::button, WindowColour::secondary ), // NB: 3 widgets - makeWidget ({ 28, 85}, {140, 12}, WidgetType::label, WindowColour::secondary, STR_WINDOW_OBJECTIVE_DATE ), - makeSpinnerWidgets({158, 84}, {120, 14}, WidgetType::button, WindowColour::secondary ), // NB: 3 widgets + makeWidget ({ 28, 66}, {140, 12}, WidgetType::label, WindowColour::secondary, kStringIdEmpty ), + makeHoldableSpinnerWidgets({158, 65}, {120, 14}, WidgetType::button, WindowColour::secondary ), // NB: 3 widgets + makeWidget ({ 28, 85}, {140, 12}, WidgetType::label, WindowColour::secondary, STR_WINDOW_OBJECTIVE_DATE ), + makeHoldableSpinnerWidgets({158, 84}, {120, 14}, WidgetType::button, WindowColour::secondary ), // NB: 3 widgets makeWidget ({ 14, 103}, {340, 12}, WidgetType::checkbox, WindowColour::secondary, STR_HARD_PARK_RATING, STR_HARD_PARK_RATING_TIP ) ); @@ -242,48 +242,48 @@ namespace OpenRCT2::Ui::Windows makeOptionsWidgets(STR_SCENARIO_OPTIONS_FINANCIAL, kSizeFinancial), makeWidget ({ 8, 48}, {kSizeFinancial.width - 16, 12}, WidgetType::checkbox, WindowColour::secondary, STR_MAKE_PARK_NO_MONEY, STR_MAKE_PARK_NO_MONEY_TIP ), - makeWidget ({ 5, 63}, {kSizeFinancial.width - 10, 72}, WidgetType::groupbox, WindowColour::secondary, STR_GROUP_LOAN_OPTIONS ), - makeWidget ({ 9, 78}, { 250, 12}, WidgetType::label, WindowColour::secondary, STR_INIT_LOAN_LABEL ), - makeSpinnerWidgets({268, 77}, { 100, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets - makeWidget ({ 9, 97}, { 250, 12}, WidgetType::label, WindowColour::secondary, STR_MAX_LOAN_LABEL ), - makeSpinnerWidgets({268, 96}, { 100, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets - makeWidget ({ 9, 116}, { 280, 12}, WidgetType::label, WindowColour::secondary, STR_INTEREST_RATE_LABEL ), - makeSpinnerWidgets({298, 115}, { 70, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets - makeWidget ({ 10, 115}, {kSizeFinancial.width - 16, 12}, WidgetType::checkbox, WindowColour::secondary, STR_RCT1_INTEREST, STR_RCT1_INTEREST_TIP ), + makeWidget ({ 5, 63}, {kSizeFinancial.width - 10, 72}, WidgetType::groupbox, WindowColour::secondary, STR_GROUP_LOAN_OPTIONS ), + makeWidget ({ 9, 78}, { 250, 12}, WidgetType::label, WindowColour::secondary, STR_INIT_LOAN_LABEL ), + makeHoldableSpinnerWidgets({268, 77}, { 100, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets + makeWidget ({ 9, 97}, { 250, 12}, WidgetType::label, WindowColour::secondary, STR_MAX_LOAN_LABEL ), + makeHoldableSpinnerWidgets({268, 96}, { 100, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets + makeWidget ({ 9, 116}, { 280, 12}, WidgetType::label, WindowColour::secondary, STR_INTEREST_RATE_LABEL ), + makeHoldableSpinnerWidgets({298, 115}, { 70, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets + makeWidget ({ 10, 115}, {kSizeFinancial.width - 16, 12}, WidgetType::checkbox, WindowColour::secondary, STR_RCT1_INTEREST, STR_RCT1_INTEREST_TIP ), - makeWidget ({ 5, 137}, {kSizeFinancial.width - 10, 89}, WidgetType::groupbox, WindowColour::secondary, STR_GROUP_BUSINESS_MODEL ), - makeWidget ({ 9, 155}, { 250, 12}, WidgetType::label, WindowColour::secondary, STR_INIT_CASH_LABEL ), - makeSpinnerWidgets({268, 154}, { 100, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets - makeWidget ({ 9, 173}, { 150, 12}, WidgetType::label, WindowColour::secondary, STR_EARNINGS_LABEL ), - makeWidget ({158, 172}, { 210, 14}, WidgetType::dropdownMenu, WindowColour::secondary, kStringIdNone, STR_PAY_FOR_PARK_PAY_FOR_RIDES_TIP), - makeWidget ({356, 173}, { 11, 12}, WidgetType::button, WindowColour::secondary, STR_DROPDOWN_GLYPH, STR_PAY_FOR_PARK_PAY_FOR_RIDES_TIP), - makeWidget ({ 9, 191}, { 280, 12}, WidgetType::label, WindowColour::secondary, STR_ENTRY_PRICE_LABEL ), - makeSpinnerWidgets({298, 190}, { 70, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets - makeWidget ({ 10, 208}, {kSizeFinancial.width - 16, 12}, WidgetType::checkbox, WindowColour::secondary, STR_FORBID_MARKETING, STR_FORBID_MARKETING_TIP ) + makeWidget ({ 5, 137}, {kSizeFinancial.width - 10, 89}, WidgetType::groupbox, WindowColour::secondary, STR_GROUP_BUSINESS_MODEL ), + makeWidget ({ 9, 155}, { 250, 12}, WidgetType::label, WindowColour::secondary, STR_INIT_CASH_LABEL ), + makeHoldableSpinnerWidgets({268, 154}, { 100, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets + makeWidget ({ 9, 173}, { 150, 12}, WidgetType::label, WindowColour::secondary, STR_EARNINGS_LABEL ), + makeWidget ({158, 172}, { 210, 14}, WidgetType::dropdownMenu, WindowColour::secondary, kStringIdNone, STR_PAY_FOR_PARK_PAY_FOR_RIDES_TIP), + makeWidget ({356, 173}, { 11, 12}, WidgetType::button, WindowColour::secondary, STR_DROPDOWN_GLYPH, STR_PAY_FOR_PARK_PAY_FOR_RIDES_TIP), + makeWidget ({ 9, 191}, { 280, 12}, WidgetType::label, WindowColour::secondary, STR_ENTRY_PRICE_LABEL ), + makeSpinnerWidgets ({298, 190}, { 70, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets + makeWidget ({ 10, 208}, {kSizeFinancial.width - 16, 12}, WidgetType::checkbox, WindowColour::secondary, STR_FORBID_MARKETING, STR_FORBID_MARKETING_TIP ) ); static constexpr auto window_editor_scenario_options_guests_widgets = makeWidgets( makeOptionsWidgets(STR_SCENARIO_OPTIONS_GUESTS, kSizeGuests), - makeWidget ({ 8, 49}, { 280, 12}, WidgetType::label, WindowColour::secondary, STR_CASH_PER_GUEST_LABEL ), - makeSpinnerWidgets({298, 48}, { 70, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets - makeWidget ({ 8, 68}, { 280, 12}, WidgetType::label, WindowColour::secondary, STR_GUEST_INIT_HAPPINESS ), - makeSpinnerWidgets({298, 67}, { 70, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets - makeWidget ({ 8, 87}, { 280, 12}, WidgetType::label, WindowColour::secondary, STR_GUEST_INIT_HUNGER ), - makeSpinnerWidgets({298, 86}, { 70, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets - makeWidget ({ 8, 106}, { 280, 12}, WidgetType::label, WindowColour::secondary, STR_GUEST_INIT_THIRST ), - makeSpinnerWidgets({298, 105}, { 70, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets - makeWidget ({ 8, 124}, { 180, 12}, WidgetType::label, WindowColour::secondary, STR_GUESTS_PREFER_INTENSITY_LABEL ), - makeWidget ({198, 123}, { 170, 14}, WidgetType::dropdownMenu, WindowColour::secondary, kStringIdNone, STR_GUESTS_PREFER_INTENSITY_TIP ), - makeWidget ({357, 124}, { 11, 12}, WidgetType::button, WindowColour::secondary, STR_DROPDOWN_GLYPH, STR_GUESTS_PREFER_INTENSITY_TIP ), - makeWidget ({ 8, 143}, { 350, 12}, WidgetType::checkbox, WindowColour::secondary, STR_HARD_GUEST_GENERATION, STR_HARD_GUEST_GENERATION_TIP ) + makeWidget ({ 8, 49}, { 280, 12}, WidgetType::label, WindowColour::secondary, STR_CASH_PER_GUEST_LABEL ), + makeHoldableSpinnerWidgets({298, 48}, { 70, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets + makeWidget ({ 8, 68}, { 280, 12}, WidgetType::label, WindowColour::secondary, STR_GUEST_INIT_HAPPINESS ), + makeHoldableSpinnerWidgets({298, 67}, { 70, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets + makeWidget ({ 8, 87}, { 280, 12}, WidgetType::label, WindowColour::secondary, STR_GUEST_INIT_HUNGER ), + makeHoldableSpinnerWidgets({298, 86}, { 70, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets + makeWidget ({ 8, 106}, { 280, 12}, WidgetType::label, WindowColour::secondary, STR_GUEST_INIT_THIRST ), + makeHoldableSpinnerWidgets({298, 105}, { 70, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets + makeWidget ({ 8, 124}, { 180, 12}, WidgetType::label, WindowColour::secondary, STR_GUESTS_PREFER_INTENSITY_LABEL ), + makeWidget ({198, 123}, { 170, 14}, WidgetType::dropdownMenu, WindowColour::secondary, kStringIdNone, STR_GUESTS_PREFER_INTENSITY_TIP ), + makeWidget ({357, 124}, { 11, 12}, WidgetType::button, WindowColour::secondary, STR_DROPDOWN_GLYPH, STR_GUESTS_PREFER_INTENSITY_TIP ), + makeWidget ({ 8, 143}, { 350, 12}, WidgetType::checkbox, WindowColour::secondary, STR_HARD_GUEST_GENERATION, STR_HARD_GUEST_GENERATION_TIP ) ); static constexpr auto window_editor_scenario_options_land_widgets = makeWidgets( makeOptionsWidgets(STR_SCENARIO_OPTIONS_LAND_RESTRICTIONS, kSizeLand), - makeWidget ({ 8, 49}, { 170, 12}, WidgetType::label, WindowColour::secondary, STR_LAND_COST_LABEL ), - makeSpinnerWidgets({188, 48}, { 70, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets - makeWidget ({ 8, 66}, { 170, 12}, WidgetType::label, WindowColour::secondary, STR_RIGHTS_COST_LABEL ), - makeSpinnerWidgets({188, 65}, { 70, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets + makeWidget ({ 8, 49}, { 170, 12}, WidgetType::label, WindowColour::secondary, STR_LAND_COST_LABEL ), + makeHoldableSpinnerWidgets({188, 48}, { 70, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets + makeWidget ({ 8, 66}, { 170, 12}, WidgetType::label, WindowColour::secondary, STR_RIGHTS_COST_LABEL ), + makeHoldableSpinnerWidgets({188, 65}, { 70, 14}, WidgetType::spinner, WindowColour::secondary ), // NB: 3 widgets makeWidget ({ 8, 82}, {kSizeLand.width - 16, 12}, WidgetType::checkbox, WindowColour::secondary, STR_FORBID_TREE_REMOVAL, STR_FORBID_TREE_REMOVAL_TIP ), makeWidget ({ 8, 99}, {kSizeLand.width - 16, 12}, WidgetType::checkbox, WindowColour::secondary, STR_FORBID_LANDSCAPE_CHANGES, STR_FORBID_LANDSCAPE_CHANGES_TIP ), makeWidget ({ 8, 116}, {kSizeLand.width - 16, 12}, WidgetType::checkbox, WindowColour::secondary, STR_FORBID_HIGH_CONSTRUCTION, STR_FORBID_HIGH_CONSTRUCTION_TIP ) @@ -304,40 +304,6 @@ namespace OpenRCT2::Ui::Windows window_editor_scenario_options_rides_widgets, }; -#pragma endregion - -#pragma region Enabled widgets - - static uint64_t window_editor_scenario_options_page_holdDownWidgets[] = { - (1uLL << WIDX_OBJECTIVE_ARG_1_INCREASE) | - (1uLL << WIDX_OBJECTIVE_ARG_1_DECREASE) | - (1uLL << WIDX_OBJECTIVE_ARG_2_INCREASE) | - (1uLL << WIDX_OBJECTIVE_ARG_2_DECREASE), - 0, - (1uLL << WIDX_INITIAL_CASH_INCREASE) | - (1uLL << WIDX_INITIAL_CASH_DECREASE) | - (1uLL << WIDX_INITIAL_LOAN_INCREASE) | - (1uLL << WIDX_INITIAL_LOAN_DECREASE) | - (1uLL << WIDX_MAXIMUM_LOAN_INCREASE) | - (1uLL << WIDX_MAXIMUM_LOAN_DECREASE) | - (1uLL << WIDX_INTEREST_RATE_INCREASE) | - (1uLL << WIDX_INTEREST_RATE_DECREASE), - (1uLL << WIDX_CASH_PER_GUEST_INCREASE) | - (1uLL << WIDX_CASH_PER_GUEST_DECREASE) | - (1uLL << WIDX_GUEST_INITIAL_HAPPINESS_INCREASE) | - (1uLL << WIDX_GUEST_INITIAL_HAPPINESS_DECREASE) | - (1uLL << WIDX_GUEST_INITIAL_HUNGER_INCREASE) | - (1uLL << WIDX_GUEST_INITIAL_HUNGER_DECREASE) | - (1uLL << WIDX_GUEST_INITIAL_THIRST_INCREASE) | - (1uLL << WIDX_GUEST_INITIAL_THIRST_DECREASE), - (1uLL << WIDX_LAND_COST_INCREASE) | - (1uLL << WIDX_LAND_COST_DECREASE) | - (1uLL << WIDX_CONSTRUCTION_RIGHTS_COST_INCREASE) | - (1uLL << WIDX_CONSTRUCTION_RIGHTS_COST_DECREASE) | - (1uLL << WIDX_ENTRY_PRICE_INCREASE) | - (1uLL << WIDX_ENTRY_PRICE_DECREASE), - 0 - }; // clang-format on #pragma endregion @@ -669,9 +635,6 @@ namespace OpenRCT2::Ui::Windows page = newPage; currentFrame = 0; - disabledWidgets = 0; - holdDownWidgets = window_editor_scenario_options_page_holdDownWidgets[page]; - pressedWidgets = 0; setWidgets(window_editor_scenario_options_widgets[page]); invalidate(); diff --git a/src/openrct2-ui/windows/Finances.cpp b/src/openrct2-ui/windows/Finances.cpp index be92c7193d..0a2924be33 100644 --- a/src/openrct2-ui/windows/Finances.cpp +++ b/src/openrct2-ui/windows/Finances.cpp @@ -206,17 +206,6 @@ namespace OpenRCT2::Ui::Windows static constexpr int32_t kExpenditureColumnWidth = 80; - static constexpr uint32_t _windowFinancesPageHoldDownWidgets[] = { - (1uLL << WIDX_LOAN_INCREASE) | (1uLL << WIDX_LOAN_DECREASE), // WINDOW_FINANCES_PAGE_SUMMARY - - 0, // WINDOW_FINANCES_PAGE_FINANCIAL_GRAPH - 0, // WINDOW_FINANCES_PAGE_VALUE_GRAPH - 0, // WINDOW_FINANCES_PAGE_PROFIT_GRAPH - 0, // WINDOW_FINANCES_PAGE_MARKETING - 0, // WINDOW_FINANCES_PAGE_RESEARCH - }; - static_assert(std::size(_windowFinancesPageHoldDownWidgets) == WINDOW_FINANCES_PAGE_COUNT); - static constexpr ScreenCoordsXY kGraphTopLeftPadding{ 88, 20 }; static constexpr ScreenCoordsXY kGraphBottomRightPadding{ 15, 18 }; static constexpr uint8_t kGraphNumYLabels = 5; @@ -234,7 +223,7 @@ namespace OpenRCT2::Ui::Windows void SetDisabledTabs() { - disabledWidgets = (getGameState().park.flags & PARK_FLAGS_FORBID_MARKETING_CAMPAIGN) ? (1uLL << WIDX_TAB_5) : 0; + setWidgetDisabled(WIDX_TAB_5, (getGameState().park.flags & PARK_FLAGS_FORBID_MARKETING_CAMPAIGN) != 0); } public: @@ -525,8 +514,11 @@ namespace OpenRCT2::Ui::Windows setWidgets(_windowFinancesPageWidgets[p]); SetDisabledTabs(); - holdDownWidgets = _windowFinancesPageHoldDownWidgets[p]; - pressedWidgets = 0; + if (p == WINDOW_FINANCES_PAGE_SUMMARY) + widgetsSetHoldable(*this, { WIDX_LOAN_INCREASE, WIDX_LOAN_DECREASE }); + + widgetSetPressedExclusive( + *this, { WIDX_TAB_1, WIDX_TAB_2, WIDX_TAB_3, WIDX_TAB_4, WIDX_TAB_5, WIDX_TAB_6 }, WIDX_TAB_1 + p); resizeFrame(); onPrepareDraw(); diff --git a/src/openrct2-ui/windows/Footpath.cpp b/src/openrct2-ui/windows/Footpath.cpp index c922e97eb5..72eacf7c17 100644 --- a/src/openrct2-ui/windows/Footpath.cpp +++ b/src/openrct2-ui/windows/Footpath.cpp @@ -237,6 +237,7 @@ namespace OpenRCT2::Ui::Windows void onOpen() override { setWidgets(kWindowFootpathWidgets); + widgetsSetHoldable(*this, { WIDX_CONSTRUCT, WIDX_REMOVE }); WindowInitScrollWidgets(*this); WindowPushOthersRight(*this); @@ -251,8 +252,6 @@ namespace OpenRCT2::Ui::Windows _footpathPlaceCtrlState = false; _footpathPlaceShiftState = false; - - holdDownWidgets = (1u << WIDX_CONSTRUCT) | (1u << WIDX_REMOVE); } void onClose() override @@ -527,9 +526,8 @@ namespace OpenRCT2::Ui::Windows void onPrepareDraw() override { // Press / unpress footpath and queue type buttons - pressedWidgets &= ~(1uLL << WIDX_FOOTPATH_TYPE); - pressedWidgets &= ~(1uLL << WIDX_QUEUELINE_TYPE); - pressedWidgets |= gFootpathSelection.isQueueSelected ? (1uLL << WIDX_QUEUELINE_TYPE) : (1uLL << WIDX_FOOTPATH_TYPE); + setWidgetPressed(WIDX_FOOTPATH_TYPE, !gFootpathSelection.isQueueSelected); + setWidgetPressed(WIDX_QUEUELINE_TYPE, gFootpathSelection.isQueueSelected); // Enable / disable construct button widgets[WIDX_CONSTRUCT].type = _footpathConstructionMode == PathConstructionMode::bridgeOrTunnel @@ -542,10 +540,7 @@ namespace OpenRCT2::Ui::Windows { canDrag = Network::CanPerformAction(Network::GetCurrentPlayerGroupIndex(), Network::Permission::dragPathArea); } - if (canDrag) - disabledWidgets &= ~(1uLL << WIDX_CONSTRUCT_DRAG_AREA); - else - disabledWidgets |= (1uLL << WIDX_CONSTRUCT_DRAG_AREA); + setWidgetDisabled(WIDX_CONSTRUCT_DRAG_AREA, !canDrag); #endif if (gFootpathSelection.legacyPath == kObjectEntryIndexNull) @@ -1666,53 +1661,47 @@ namespace OpenRCT2::Ui::Windows _footpathConstructFromPosition.y + CoordsDirectionDelta[direction].y }); } - uint64_t newPressedWidgets = pressedWidgets - & ~((1LL << WIDX_DIRECTION_NW) | (1LL << WIDX_DIRECTION_NE) | (1LL << WIDX_DIRECTION_SW) - | (1LL << WIDX_DIRECTION_SE) | (1LL << WIDX_SLOPEDOWN) | (1LL << WIDX_LEVEL) | (1LL << WIDX_SLOPEUP)); - uint64_t newDisabledWidgets = 0; - int32_t currentRotation = GetCurrentRotation(); - if (_footpathConstructionMode == PathConstructionMode::bridgeOrTunnel) - { - // Set pressed directional widget - int32_t direction = (_footpathConstructDirection + currentRotation) & 3; - newPressedWidgets |= (1LL << (WIDX_DIRECTION_NW + direction)); + const int32_t currentRotation = GetCurrentRotation(); + const bool bridgeMode = _footpathConstructionMode == PathConstructionMode::bridgeOrTunnel; - // Set pressed slope widget - switch (_footpathConstructSlope) - { - case SlopePitch::flat: - newPressedWidgets |= (1uLL << WIDX_LEVEL); - break; - case SlopePitch::upwards: - newPressedWidgets |= (1uLL << WIDX_SLOPEUP); - break; - case SlopePitch::downwards: - newPressedWidgets |= (1uLL << WIDX_SLOPEDOWN); - break; - } + // Pressed directional widgets + const int32_t pressedDir = bridgeMode ? ((_footpathConstructDirection + currentRotation) & 3) : -1; + setWidgetPressed(WIDX_DIRECTION_NW, pressedDir == 0); + setWidgetPressed(WIDX_DIRECTION_NE, pressedDir == 1); + setWidgetPressed(WIDX_DIRECTION_SW, pressedDir == 2); + setWidgetPressed(WIDX_DIRECTION_SE, pressedDir == 3); - // Enable / disable directional widgets - direction = _footpathConstructValidDirections; - if (direction != kInvalidDirection) - { - newDisabledWidgets |= (1uLL << WIDX_DIRECTION_NW) | (1uLL << WIDX_DIRECTION_NE) - | (1uLL << WIDX_DIRECTION_SW) | (1uLL << WIDX_DIRECTION_SE); + // Pressed slope widget + setWidgetPressed(WIDX_LEVEL, bridgeMode && _footpathConstructSlope == SlopePitch::flat); + setWidgetPressed(WIDX_SLOPEUP, bridgeMode && _footpathConstructSlope == SlopePitch::upwards); + setWidgetPressed(WIDX_SLOPEDOWN, bridgeMode && _footpathConstructSlope == SlopePitch::downwards); - direction = (direction + currentRotation) & 3; - newDisabledWidgets &= ~(1 << (WIDX_DIRECTION_NW + direction)); - } - } - else - { - // Disable all bridge mode widgets - newDisabledWidgets |= (1uLL << WIDX_DIRECTION_GROUP) | (1uLL << WIDX_DIRECTION_NW) | (1uLL << WIDX_DIRECTION_NE) - | (1uLL << WIDX_DIRECTION_SW) | (1uLL << WIDX_DIRECTION_SE) | (1uLL << WIDX_SLOPE_GROUP) - | (1uLL << WIDX_SLOPEDOWN) | (1uLL << WIDX_LEVEL) | (1uLL << WIDX_SLOPEUP) | (1uLL << WIDX_CONSTRUCT) - | (1uLL << WIDX_REMOVE); - } + // Enabled directional widgets + int32_t validDirections = bridgeMode ? _footpathConstructValidDirections : kInvalidDirection; + const int32_t onlyEnabledDir = (bridgeMode && validDirections != kInvalidDirection) + ? ((validDirections + currentRotation) & 3) + : -1; + auto directionDisabled = [&](int32_t idx) { + if (!bridgeMode) + return true; + if (onlyEnabledDir < 0) + return false; + return idx != onlyEnabledDir; + }; + setWidgetDisabled(WIDX_DIRECTION_NW, directionDisabled(0)); + setWidgetDisabled(WIDX_DIRECTION_NE, directionDisabled(1)); + setWidgetDisabled(WIDX_DIRECTION_SW, directionDisabled(2)); + setWidgetDisabled(WIDX_DIRECTION_SE, directionDisabled(3)); + + // Bridge-mode group / slope widgets + setWidgetDisabled(WIDX_DIRECTION_GROUP, !bridgeMode); + setWidgetDisabled(WIDX_SLOPE_GROUP, !bridgeMode); + setWidgetDisabled(WIDX_SLOPEDOWN, !bridgeMode); + setWidgetDisabled(WIDX_LEVEL, !bridgeMode); + setWidgetDisabled(WIDX_SLOPEUP, !bridgeMode); + setWidgetDisabled(WIDX_CONSTRUCT, !bridgeMode); + setWidgetDisabled(WIDX_REMOVE, !bridgeMode); - pressedWidgets = newPressedWidgets; - disabledWidgets = newDisabledWidgets; invalidate(); } diff --git a/src/openrct2-ui/windows/GameBottomToolbar.cpp b/src/openrct2-ui/windows/GameBottomToolbar.cpp index 8efb98d4b9..7b5ff3ea0f 100644 --- a/src/openrct2-ui/windows/GameBottomToolbar.cpp +++ b/src/openrct2-ui/windows/GameBottomToolbar.cpp @@ -601,25 +601,25 @@ namespace OpenRCT2::Ui::Windows widgets[WIDX_NEWS_LOCATE].type = WidgetType::flatBtn; widgets[WIDX_MIDDLE_OUTSET].colour = 2; widgets[WIDX_MIDDLE_INSET].colour = 2; - disabledWidgets &= ~(1uLL << WIDX_NEWS_SUBJECT); - disabledWidgets &= ~(1uLL << WIDX_NEWS_LOCATE); + setWidgetDisabled(WIDX_NEWS_SUBJECT, false); + setWidgetDisabled(WIDX_NEWS_LOCATE, false); // Find out if the news item is no longer valid auto subjectLoc = News::GetSubjectLocation(newsItem->type, newsItem->assoc); if (!subjectLoc.has_value()) - disabledWidgets |= (1uLL << WIDX_NEWS_LOCATE); + setWidgetDisabled(WIDX_NEWS_LOCATE, true); if (!(newsItem->typeHasSubject())) { - disabledWidgets |= (1uLL << WIDX_NEWS_SUBJECT); + setWidgetDisabled(WIDX_NEWS_SUBJECT, true); widgets[WIDX_NEWS_SUBJECT].type = WidgetType::empty; } if (newsItem->hasButton()) { - disabledWidgets |= (1uLL << WIDX_NEWS_SUBJECT); - disabledWidgets |= (1uLL << WIDX_NEWS_LOCATE); + setWidgetDisabled(WIDX_NEWS_SUBJECT, true); + setWidgetDisabled(WIDX_NEWS_LOCATE, true); } } } diff --git a/src/openrct2-ui/windows/Guest.cpp b/src/openrct2-ui/windows/Guest.cpp index 2115e5522c..a1652914a9 100644 --- a/src/openrct2-ui/windows/Guest.cpp +++ b/src/openrct2-ui/windows/Guest.cpp @@ -465,7 +465,7 @@ namespace OpenRCT2::Ui::Windows void onPrepareDrawCommon() { - pressedWidgets |= 1uLL << (page + WIDX_TAB_1); + setWidgetPressed(page + WIDX_TAB_1, true); const auto peep = GetGuest(); if (peep == nullptr) @@ -486,28 +486,13 @@ namespace OpenRCT2::Ui::Windows { return; } - uint64_t newDisabledWidgets = 0; - if (peep->CanBePickedUp()) - { - if (widgetIsDisabled(*this, WIDX_PICKUP)) - invalidate(); - } - else - { - newDisabledWidgets = (1uLL << WIDX_PICKUP); - if (!widgetIsDisabled(*this, WIDX_PICKUP)) - invalidate(); - } - if (getGameState().park.flags & PARK_FLAGS_NO_MONEY) - { - newDisabledWidgets |= (1uLL << WIDX_TAB_4); // Disable finance tab if no money - } - if (!Config::Get().general.debuggingTools) - { - newDisabledWidgets |= (1uLL << WIDX_TAB_7); // Disable debug tab when debug tools not turned on - } - disabledWidgets = newDisabledWidgets; + const bool disablePickup = !peep->CanBePickedUp(); + if (disablePickup != isWidgetDisabled(WIDX_PICKUP)) + invalidate(); + setWidgetDisabled(WIDX_PICKUP, disablePickup); + setWidgetDisabled(WIDX_TAB_4, (getGameState().park.flags & PARK_FLAGS_NO_MONEY) != 0); + setWidgetDisabled(WIDX_TAB_7, !Config::Get().general.debuggingTools); } void setPage(int32_t newPage) @@ -533,8 +518,6 @@ namespace OpenRCT2::Ui::Windows removeViewport(); - holdDownWidgets = 0; - pressedWidgets = 0; setWidgets(_guestWindowPageWidgets[page]); DisableWidgets(); invalidate(); @@ -870,11 +853,7 @@ namespace OpenRCT2::Ui::Windows { return; } - pressedWidgets &= ~(1uLL << WIDX_TRACK); - if (peep->PeepFlags & PEEP_FLAGS_TRACKING) - { - pressedWidgets |= (1uLL << WIDX_TRACK); - } + setWidgetPressed(WIDX_TRACK, (peep->PeepFlags & PEEP_FLAGS_TRACKING) != 0); widgets[WIDX_VIEWPORT].right = width - 26; widgets[WIDX_VIEWPORT].bottom = height - 14; diff --git a/src/openrct2-ui/windows/InstallTrack.cpp b/src/openrct2-ui/windows/InstallTrack.cpp index e0dac46b47..5fcd1e93a6 100644 --- a/src/openrct2-ui/windows/InstallTrack.cpp +++ b/src/openrct2-ui/windows/InstallTrack.cpp @@ -89,6 +89,7 @@ namespace OpenRCT2::Ui::Windows void onOpen() override { setWidgets(window_install_track_widgets); + setWidgetPressed(WIDX_TRACK_PREVIEW, true); WindowInitScrollWidgets(*this); WindowPushOthersRight(*this); @@ -139,15 +140,7 @@ namespace OpenRCT2::Ui::Windows void onPrepareDraw() override { - pressedWidgets |= 1uLL << WIDX_TRACK_PREVIEW; - if (!gTrackDesignSceneryToggle) - { - pressedWidgets |= (1uLL << WIDX_TOGGLE_SCENERY); - } - else - { - pressedWidgets &= ~(1uLL << WIDX_TOGGLE_SCENERY); - } + setWidgetPressed(WIDX_TOGGLE_SCENERY, !gTrackDesignSceneryToggle); } void onDraw(RenderTarget& rt) override diff --git a/src/openrct2-ui/windows/Land.cpp b/src/openrct2-ui/windows/Land.cpp index e6660635fc..aa1b5b3090 100644 --- a/src/openrct2-ui/windows/Land.cpp +++ b/src/openrct2-ui/windows/Land.cpp @@ -101,7 +101,8 @@ namespace OpenRCT2::Ui::Windows { setWidgets(window_land_widgets); - holdDownWidgets = (1uLL << WIDX_DECREMENT) | (1uLL << WIDX_INCREMENT); + widgetsSetHoldable(*this, { WIDX_DECREMENT, WIDX_INCREMENT }); + setWidgetPressed(WIDX_PREVIEW, true); WindowInitScrollWidgets(*this); WindowPushOthersBelow(*this); @@ -246,16 +247,10 @@ namespace OpenRCT2::Ui::Windows void onPrepareDraw() override { - pressedWidgets = 0; - setWidgetPressed(WIDX_PREVIEW, true); - if (gLandToolTerrainSurface != kObjectEntryIndexNull) - setWidgetPressed(WIDX_FLOOR, true); - if (gLandToolTerrainEdge != kObjectEntryIndexNull) - setWidgetPressed(WIDX_WALL, true); - if (_landToolMountainMode) - setWidgetPressed(WIDX_MOUNTAINMODE, true); - if (_landToolPaintMode) - setWidgetPressed(WIDX_PAINTMODE, true); + setWidgetPressed(WIDX_FLOOR, gLandToolTerrainSurface != kObjectEntryIndexNull); + setWidgetPressed(WIDX_WALL, gLandToolTerrainEdge != kObjectEntryIndexNull); + setWidgetPressed(WIDX_MOUNTAINMODE, _landToolMountainMode); + setWidgetPressed(WIDX_PAINTMODE, _landToolPaintMode); // Update the preview image (for tool sizes up to 7) widgets[WIDX_PREVIEW].image = ImageId(LandTool::SizeToSpriteIndex(gLandToolSize)); diff --git a/src/openrct2-ui/windows/LandRights.cpp b/src/openrct2-ui/windows/LandRights.cpp index fdd966916e..c22b38989b 100644 --- a/src/openrct2-ui/windows/LandRights.cpp +++ b/src/openrct2-ui/windows/LandRights.cpp @@ -107,7 +107,11 @@ namespace OpenRCT2::Ui::Windows void SwitchToMode(LandRightsMode mode) { auto widgetIndex = WIDX_BUY_LAND_RIGHTS + EnumValue(mode); - pressedWidgets = (1uLL << widgetIndex); + widgetSetPressedExclusive( + *this, + { WIDX_BUY_LAND_RIGHTS, WIDX_BUY_CONSTRUCTION_RIGHTS, WIDX_LAND_OWNED_CHECKBOX, WIDX_LAND_SALE_CHECKBOX, + WIDX_CONSTRUCTION_RIGHTS_OWNED_CHECKBOX, WIDX_CONSTRUCTION_RIGHTS_SALE_CHECKBOX, WIDX_UNOWNED_LAND_CHECKBOX }, + widgetIndex); _landRightsMode = mode; ToolSet(*this, widgetIndex, Tool::upArrow); @@ -130,7 +134,7 @@ namespace OpenRCT2::Ui::Windows { setWidgets(window_land_rights_widgets); - holdDownWidgets = (1uLL << WIDX_INCREMENT) | (1uLL << WIDX_DECREMENT); + widgetsSetHoldable(*this, { WIDX_INCREMENT, WIDX_DECREMENT }); WindowInitScrollWidgets(*this); WindowPushOthersBelow(*this); diff --git a/src/openrct2-ui/windows/LoadSave.cpp b/src/openrct2-ui/windows/LoadSave.cpp index 424c6a85a9..ded3ac4010 100644 --- a/src/openrct2-ui/windows/LoadSave.cpp +++ b/src/openrct2-ui/windows/LoadSave.cpp @@ -178,7 +178,8 @@ namespace OpenRCT2::Ui::Windows if (directory.empty() && drives) { // List Windows drives - disabledWidgets |= (1uLL << WIDX_NEW_FOLDER) | (1uLL << WIDX_PARENT_FOLDER); + setWidgetDisabled(WIDX_NEW_FOLDER, true); + setWidgetDisabled(WIDX_PARENT_FOLDER, true); static constexpr auto NumDriveLetters = 26; for (int32_t x = 0; x < NumDriveLetters; x++) { @@ -222,13 +223,10 @@ namespace OpenRCT2::Ui::Windows } // Disable the Up button if the current directory is the root directory - if (String::isNullOrEmpty(_parentDirectory) && !drives) - disabledWidgets |= (1uLL << WIDX_PARENT_FOLDER); - else - disabledWidgets &= ~(1uLL << WIDX_PARENT_FOLDER); + setWidgetDisabled(WIDX_PARENT_FOLDER, String::isNullOrEmpty(_parentDirectory) && !drives); // Re-enable the "new" button if it was disabled - disabledWidgets &= ~(1uLL << WIDX_NEW_FOLDER); + setWidgetDisabled(WIDX_NEW_FOLDER, false); // List all directories auto subDirectories = Path::GetDirectories(absoluteDirectory); @@ -547,7 +545,7 @@ namespace OpenRCT2::Ui::Windows const auto& uiContext = GetContext()->GetUiContext(); if (!uiContext.HasFilePicker()) { - disabledWidgets |= (1uLL << WIDX_SYSTEM_BROWSER); + setWidgetDisabled(WIDX_SYSTEM_BROWSER, true); widgets[WIDX_SYSTEM_BROWSER].type = WidgetType::empty; } diff --git a/src/openrct2-ui/windows/Map.cpp b/src/openrct2-ui/windows/Map.cpp index bf089f0a79..a750f44279 100644 --- a/src/openrct2-ui/windows/Map.cpp +++ b/src/openrct2-ui/windows/Map.cpp @@ -252,8 +252,10 @@ namespace OpenRCT2::Ui::Windows { setWidgets(window_map_widgets); - holdDownWidgets = (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); + widgetsSetHoldable( + *this, + { WIDX_MAP_SIZE_SPINNER_Y_UP, WIDX_MAP_SIZE_SPINNER_Y_DOWN, WIDX_MAP_SIZE_SPINNER_X_UP, + WIDX_MAP_SIZE_SPINNER_X_DOWN }); flags |= WindowFlag::resizable; @@ -613,18 +615,11 @@ namespace OpenRCT2::Ui::Windows auto* windowMgr = GetWindowManager(); // Set the pressed widgets - pressedWidgets = 0; setWidgetPressed(WIDX_MAP_SIZE_LINK, _mapWidthAndHeightLinked); - pressedWidgets |= (1uLL << (WIDX_PEOPLE_TAB + selectedTab)); - - if (windowMgr->FindByClass(WindowClass::editorParkEntrance)) - pressedWidgets |= (1uLL << WIDX_BUILD_PARK_ENTRANCE); - - if (windowMgr->FindByClass(WindowClass::landRights)) - pressedWidgets |= (1uLL << WIDX_SET_LAND_RIGHTS); - - if (windowMgr->FindByClass(WindowClass::mapgen)) - pressedWidgets |= (1uLL << WIDX_MAP_GENERATOR); + widgetSetPressedExclusive(*this, { WIDX_PEOPLE_TAB, WIDX_RIDES_TAB }, WIDX_PEOPLE_TAB + selectedTab); + setWidgetPressed(WIDX_BUILD_PARK_ENTRANCE, windowMgr->FindByClass(WindowClass::editorParkEntrance) != nullptr); + setWidgetPressed(WIDX_SET_LAND_RIGHTS, windowMgr->FindByClass(WindowClass::landRights) != nullptr); + setWidgetPressed(WIDX_MAP_GENERATOR, windowMgr->FindByClass(WindowClass::mapgen) != nullptr); // Set disabled widgets auto& gameState = getGameState(); diff --git a/src/openrct2-ui/windows/MapGen.cpp b/src/openrct2-ui/windows/MapGen.cpp index 4aaf82c74c..4ec897d639 100644 --- a/src/openrct2-ui/windows/MapGen.cpp +++ b/src/openrct2-ui/windows/MapGen.cpp @@ -183,56 +183,32 @@ namespace OpenRCT2::Ui::Windows #pragma region Widget flags - // clang-format off - static uint64_t PageDisabledWidgets[WINDOW_MAPGEN_PAGE_COUNT] = { - (1uLL << WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP) | - (1uLL << WIDX_HEIGHTMAP_STRENGTH) | - (1uLL << WIDX_HEIGHTMAP_STRENGTH_UP) | - (1uLL << WIDX_HEIGHTMAP_STRENGTH_DOWN) | - (1uLL << WIDX_HEIGHTMAP_NORMALIZE), - - 0, - - 0, - - 0 - }; - - static uint64_t HoldDownWidgets[WINDOW_MAPGEN_PAGE_COUNT] = { - (1uLL << WIDX_MAP_SIZE_Y_UP) | - (1uLL << WIDX_MAP_SIZE_Y_DOWN) | - (1uLL << WIDX_MAP_SIZE_X_UP) | - (1uLL << WIDX_MAP_SIZE_X_DOWN) | - (1uLL << WIDX_SIMPLEX_BASE_FREQ_UP) | - (1uLL << WIDX_SIMPLEX_BASE_FREQ_DOWN) | - (1uLL << WIDX_SIMPLEX_OCTAVES_UP) | - (1uLL << WIDX_SIMPLEX_OCTAVES_DOWN) | - (1uLL << WIDX_HEIGHTMAP_STRENGTH_UP) | - (1uLL << WIDX_HEIGHTMAP_STRENGTH_DOWN), - - (1uLL << WIDX_HEIGHTMAP_LOW_UP) | - (1uLL << WIDX_HEIGHTMAP_LOW_DOWN) | - (1uLL << WIDX_HEIGHTMAP_HIGH_UP) | - (1uLL << WIDX_HEIGHTMAP_HIGH_DOWN), - - (1uLL << WIDX_WATER_LEVEL_UP) | - (1uLL << WIDX_WATER_LEVEL_DOWN), - - (1uLL << WIDX_TREE_LAND_RATIO_UP) | - (1uLL << WIDX_TREE_LAND_RATIO_DOWN) | - (1uLL << WIDX_TREE_ALTITUDE_MIN_UP) | - (1uLL << WIDX_TREE_ALTITUDE_MIN_DOWN) | - (1uLL << WIDX_TREE_ALTITUDE_MAX_UP) | - (1uLL << WIDX_TREE_ALTITUDE_MAX_DOWN), - }; - - static uint64_t PressedWidgets[WINDOW_MAPGEN_PAGE_COUNT] = { - 0, - (1uLL << WIDX_HEIGHTMAP_SMOOTH_TILE_EDGES), - 0, - 0, - }; - // clang-format on + static void setPageHoldableWidgets(WindowBase& w, int32_t page) + { + switch (page) + { + case WINDOW_MAPGEN_PAGE_BASE: + widgetsSetHoldable( + w, + { WIDX_MAP_SIZE_Y_UP, WIDX_MAP_SIZE_Y_DOWN, WIDX_MAP_SIZE_X_UP, WIDX_MAP_SIZE_X_DOWN, + WIDX_SIMPLEX_BASE_FREQ_UP, WIDX_SIMPLEX_BASE_FREQ_DOWN, WIDX_SIMPLEX_OCTAVES_UP, + WIDX_SIMPLEX_OCTAVES_DOWN, WIDX_HEIGHTMAP_STRENGTH_UP, WIDX_HEIGHTMAP_STRENGTH_DOWN }); + break; + case WINDOW_MAPGEN_PAGE_TERRAIN: + widgetsSetHoldable( + w, { WIDX_HEIGHTMAP_LOW_UP, WIDX_HEIGHTMAP_LOW_DOWN, WIDX_HEIGHTMAP_HIGH_UP, WIDX_HEIGHTMAP_HIGH_DOWN }); + break; + case WINDOW_MAPGEN_PAGE_WATER: + widgetsSetHoldable(w, { WIDX_WATER_LEVEL_UP, WIDX_WATER_LEVEL_DOWN }); + break; + case WINDOW_MAPGEN_PAGE_FORESTS: + widgetsSetHoldable( + w, + { WIDX_TREE_LAND_RATIO_UP, WIDX_TREE_LAND_RATIO_DOWN, WIDX_TREE_ALTITUDE_MIN_UP, + WIDX_TREE_ALTITUDE_MIN_DOWN, WIDX_TREE_ALTITUDE_MAX_UP, WIDX_TREE_ALTITUDE_MAX_DOWN }); + break; + } + } #pragma endregion @@ -290,22 +266,14 @@ namespace OpenRCT2::Ui::Windows removeViewport(); setWidgets(PageWidgets[newPage]); - holdDownWidgets = HoldDownWidgets[newPage]; - disabledWidgets = PageDisabledWidgets[newPage]; - pressedWidgets = PressedWidgets[newPage]; + setPageHoldableWidgets(*this, newPage); + widgetSetPressedExclusive(*this, { WIDX_TAB_1, WIDX_TAB_2, WIDX_TAB_3, WIDX_TAB_4 }, WIDX_TAB_1 + newPage); initScrollWidgets(); invalidate(); onResize(); } - void SetPressedTab() - { - for (auto i = 0; i < WINDOW_MAPGEN_PAGE_COUNT; i++) - pressedWidgets &= ~(1 << (WIDX_TAB_1 + i)); - pressedWidgets |= 1LL << (WIDX_TAB_1 + page); - } - void DrawTabImage(RenderTarget& rt, int32_t newPage, int32_t spriteIndex) { WidgetIndex widgetIndex = WIDX_TAB_1 + newPage; @@ -538,16 +506,12 @@ namespace OpenRCT2::Ui::Windows setWidgetDisabled(WIDX_MAP_SIZE_X_DOWN, isHeightMapImage); // Enable heightmap widgets if one is loaded - if (isHeightMapImage) - { - setWidgetEnabled(WIDX_HEIGHTMAP_NORMALIZE, _heightmapLoaded); - setWidgetEnabled(WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP, _heightmapLoaded); - setWidgetEnabled(WIDX_HEIGHTMAP_STRENGTH, _heightmapLoaded && _settings.smooth_height_map); - setWidgetEnabled(WIDX_HEIGHTMAP_STRENGTH_UP, _heightmapLoaded && _settings.smooth_height_map); - setWidgetEnabled(WIDX_HEIGHTMAP_STRENGTH_DOWN, _heightmapLoaded && _settings.smooth_height_map); - } - - SetPressedTab(); + const bool heightmapEnabled = isHeightMapImage && _heightmapLoaded; + setWidgetEnabled(WIDX_HEIGHTMAP_NORMALIZE, heightmapEnabled); + setWidgetEnabled(WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP, heightmapEnabled); + setWidgetEnabled(WIDX_HEIGHTMAP_STRENGTH, heightmapEnabled && _settings.smooth_height_map); + setWidgetEnabled(WIDX_HEIGHTMAP_STRENGTH_UP, heightmapEnabled && _settings.smooth_height_map); + setWidgetEnabled(WIDX_HEIGHTMAP_STRENGTH_DOWN, heightmapEnabled && _settings.smooth_height_map); _xSpinnerCaption = std::to_string(_settings.mapSize.x - 2); widgets[WIDX_MAP_SIZE_X].setString(_xSpinnerCaption.c_str()); @@ -746,11 +710,7 @@ namespace OpenRCT2::Ui::Windows void ForestsPrepareDraw() { - pressedWidgets = 0; - if (_settings.trees) - pressedWidgets |= 1uLL << WIDX_FORESTS_PLACE_TREES; - - SetPressedTab(); + setWidgetPressed(WIDX_FORESTS_PLACE_TREES, _settings.trees); const bool isFlatland = _settings.algorithm == MapGenerator::Algorithm::blank; @@ -1226,7 +1186,6 @@ namespace OpenRCT2::Ui::Windows // only offer terrain edge smoothing if we don't use flatland terrain setWidgetEnabled(WIDX_HEIGHTMAP_SMOOTH_TILE_EDGES, _settings.algorithm != MapGenerator::Algorithm::blank); - SetPressedTab(); } void TerrainDraw(RenderTarget& rt) @@ -1336,8 +1295,6 @@ namespace OpenRCT2::Ui::Windows void WaterPrepareDraw() { setCheckboxValue(WIDX_ADD_BEACHES, _settings.beaches != 0); - - SetPressedTab(); } void WaterDraw(RenderTarget& rt) @@ -1366,9 +1323,6 @@ namespace OpenRCT2::Ui::Windows setPage(WINDOW_MAPGEN_PAGE_BASE); invalidate(); - holdDownWidgets = HoldDownWidgets[WINDOW_MAPGEN_PAGE_BASE]; - pressedWidgets = PressedWidgets[WINDOW_MAPGEN_PAGE_BASE]; - disabledWidgets = PageDisabledWidgets[WINDOW_MAPGEN_PAGE_BASE]; initScrollWidgets(); _heightmapLoaded = false; diff --git a/src/openrct2-ui/windows/MazeConstruction.cpp b/src/openrct2-ui/windows/MazeConstruction.cpp index 4ea4953577..1c3103a525 100644 --- a/src/openrct2-ui/windows/MazeConstruction.cpp +++ b/src/openrct2-ui/windows/MazeConstruction.cpp @@ -189,19 +189,17 @@ namespace OpenRCT2::Ui::Windows | (1uLL << WIDX_MAZE_DIRECTION_SW) | (1uLL << WIDX_MAZE_DIRECTION_SE); } - // Set and invalidate the changed widgets - uint64_t currentDisabledWidgets = disabledWidgets; - if (currentDisabledWidgets == newDisabledWidgets) - return; - - for (WidgetIndex i = 0; i < 64; i++) + // Invalidate only widgets whose disabled state changes. + const auto widgetCount = static_cast(widgets.size()); + for (WidgetIndex i = 0; i < widgetCount && i < 64; i++) { - if ((newDisabledWidgets & (1uLL << i)) != (currentDisabledWidgets & (1uLL << i))) + const bool shouldBeDisabled = (newDisabledWidgets & (1uLL << i)) != 0; + if (isWidgetDisabled(i) != shouldBeDisabled) { + setWidgetDisabled(i, shouldBeDisabled); invalidateWidget(i); } } - disabledWidgets = newDisabledWidgets; } void onMouseDown(WidgetIndex widgetIndex) override @@ -461,41 +459,15 @@ namespace OpenRCT2::Ui::Windows if (w == nullptr) return; - uint64_t newPressedWidgets = w->pressedWidgets; + const bool isEntranceExit = _rideConstructionState == RideConstructionState::EntranceExit; + const bool entranceToolActive = isToolActive(WindowClass::rideConstruction, WIDX_MAZE_ENTRANCE); - // Unpress all the mode buttons - newPressedWidgets &= ~EnumToFlag(WIDX_MAZE_BUILD_MODE); - newPressedWidgets &= ~EnumToFlag(WIDX_MAZE_MOVE_MODE); - newPressedWidgets &= ~EnumToFlag(WIDX_MAZE_FILL_MODE); - newPressedWidgets &= ~EnumToFlag(WIDX_MAZE_ENTRANCE); - newPressedWidgets &= ~EnumToFlag(WIDX_MAZE_EXIT); + widgetSetPressed(*w, WIDX_MAZE_BUILD_MODE, _rideConstructionState == RideConstructionState::MazeBuild); + widgetSetPressed(*w, WIDX_MAZE_MOVE_MODE, _rideConstructionState == RideConstructionState::MazeMove); + widgetSetPressed(*w, WIDX_MAZE_FILL_MODE, _rideConstructionState == RideConstructionState::MazeFill); + widgetSetPressed(*w, WIDX_MAZE_ENTRANCE, isEntranceExit && entranceToolActive); + widgetSetPressed(*w, WIDX_MAZE_EXIT, isEntranceExit && !entranceToolActive); - switch (_rideConstructionState) - { - case RideConstructionState::EntranceExit: - if (isToolActive(WindowClass::rideConstruction, WIDX_MAZE_ENTRANCE)) - { - newPressedWidgets |= EnumToFlag(WIDX_MAZE_ENTRANCE); - } - else - { - newPressedWidgets |= EnumToFlag(WIDX_MAZE_EXIT); - } - break; - case RideConstructionState::MazeBuild: - newPressedWidgets |= EnumToFlag(WIDX_MAZE_BUILD_MODE); - break; - case RideConstructionState::MazeMove: - newPressedWidgets |= EnumToFlag(WIDX_MAZE_MOVE_MODE); - break; - case RideConstructionState::MazeFill: - newPressedWidgets |= EnumToFlag(WIDX_MAZE_FILL_MODE); - break; - default: - break; - } - - w->pressedWidgets = newPressedWidgets; w->invalidate(); } } // namespace OpenRCT2::Ui::Windows diff --git a/src/openrct2-ui/windows/Multiplayer.cpp b/src/openrct2-ui/windows/Multiplayer.cpp index 03d56a2fdd..018acc312d 100644 --- a/src/openrct2-ui/windows/Multiplayer.cpp +++ b/src/openrct2-ui/windows/Multiplayer.cpp @@ -155,14 +155,6 @@ namespace OpenRCT2::Ui::Windows uint8_t _selectedGroup{ 0 }; private: - void resetPressedWidgets() - { - for (int32_t i = WIDX_TAB1; i <= WIDX_TAB4; i++) - { - setWidgetPressed(i, false); - } - } - void showGroupDropdown(WidgetIndex widgetIndex) { auto widget = &widgets[widgetIndex]; @@ -523,10 +515,9 @@ namespace OpenRCT2::Ui::Windows numListItems = 0; selectedListItem = -1; - holdDownWidgets = 0; - pressedWidgets = 0; setWidgets(window_multiplayer_page_widgets[page]); widgets[WIDX_TITLE].text = WindowMultiplayerPageTitles[page]; + setWidgetPressed(WIDX_TAB1 + page, true); onResize(); onPrepareDraw(); @@ -654,8 +645,6 @@ namespace OpenRCT2::Ui::Windows void onPrepareDraw() override { - resetPressedWidgets(); - setWidgetPressed(WIDX_TAB1 + page, true); switch (page) { case WINDOW_MULTIPLAYER_PAGE_INFORMATION: diff --git a/src/openrct2-ui/windows/NewCampaign.cpp b/src/openrct2-ui/windows/NewCampaign.cpp index 3dc8ac692f..2ee436a356 100644 --- a/src/openrct2-ui/windows/NewCampaign.cpp +++ b/src/openrct2-ui/windows/NewCampaign.cpp @@ -178,7 +178,7 @@ namespace OpenRCT2::Ui::Windows void onOpen() override { setWidgets(window_new_campaign_widgets); - holdDownWidgets = (1uLL << WIDX_WEEKS_INCREASE_BUTTON) | (1uLL << WIDX_WEEKS_DECREASE_BUTTON); + widgetsSetHoldable(*this, { WIDX_WEEKS_INCREASE_BUTTON, WIDX_WEEKS_DECREASE_BUTTON }); WindowInitScrollWidgets(*this); } diff --git a/src/openrct2-ui/windows/NewRide.cpp b/src/openrct2-ui/windows/NewRide.cpp index 9dcae8b711..54e30e66f0 100644 --- a/src/openrct2-ui/windows/NewRide.cpp +++ b/src/openrct2-ui/windows/NewRide.cpp @@ -411,10 +411,7 @@ namespace OpenRCT2::Ui::Windows { SetPressedTab(); - if (!Config::Get().interface.listRideVehiclesSeparately) - pressedWidgets |= (1LL << WIDX_GROUP_BY_TRACK_TYPE); - else - pressedWidgets &= ~(1LL << WIDX_GROUP_BY_TRACK_TYPE); + setWidgetPressed(WIDX_GROUP_BY_TRACK_TYPE, !Config::Get().interface.listRideVehiclesSeparately); widgets[WIDX_TITLE].text = RideTitles[_currentTab]; widgets[WIDX_TAB_7].type = WidgetType::tab; @@ -815,24 +812,15 @@ namespace OpenRCT2::Ui::Windows void SetPressedTab() { - int32_t i{}; - for (i = 0; i < TAB_COUNT; i++) + for (int32_t i = 0; i < TAB_COUNT; i++) { - pressedWidgets &= ~(1 << (WIDX_TAB_1 + i)); + setWidgetPressed(WIDX_TAB_1 + i, i == static_cast(_currentTab)); } - pressedWidgets |= 1LL << (WIDX_TAB_1 + static_cast(_currentTab)); } void RefreshWidgetSizing() { - if (_currentTab < SHOP_TAB) - { - disabledWidgets &= ~(1 << WIDX_GROUP_BY_TRACK_TYPE); - } - else - { - disabledWidgets |= 1LL << WIDX_GROUP_BY_TRACK_TYPE; - } + setWidgetDisabled(WIDX_GROUP_BY_TRACK_TYPE, _currentTab >= SHOP_TAB); // Show or hide unrelated widgets diff --git a/src/openrct2-ui/windows/Options.cpp b/src/openrct2-ui/windows/Options.cpp index a4382b692b..e4106fd520 100644 --- a/src/openrct2-ui/windows/Options.cpp +++ b/src/openrct2-ui/windows/Options.cpp @@ -752,12 +752,12 @@ namespace OpenRCT2::Ui::Windows { SetPressedTab(); - disabledWidgets = 0; auto hasFilePicker = GetContext()->GetUiContext().HasFilePicker(); const bool advancedTabSelected = (WIDX_FIRST_TAB + page) == WIDX_TAB_ADVANCED; - if (!hasFilePicker && advancedTabSelected) + const bool disableAlwaysNative = !hasFilePicker && advancedTabSelected; + setWidgetDisabled(WIDX_ALWAYS_NATIVE_LOADSAVE, disableAlwaysNative); + if (disableAlwaysNative) { - disabledWidgets |= (1uLL << WIDX_ALWAYS_NATIVE_LOADSAVE); widgets[WIDX_ALWAYS_NATIVE_LOADSAVE].type = WidgetType::empty; } } @@ -990,18 +990,11 @@ namespace OpenRCT2::Ui::Windows widgets[WIDX_RESOLUTION].setString(_dropdownCaption.c_str()); // Disable resolution dropdown on "Windowed" and "Fullscreen (desktop)" - if (Config::Get().general.fullscreenMode != static_cast(FullscreenMode::fullscreen)) - { - disabledWidgets |= (1uLL << WIDX_RESOLUTION_DROPDOWN); - disabledWidgets |= (1uLL << WIDX_RESOLUTION); - disabledWidgets |= (1uLL << WIDX_RESOLUTION_LABEL); - } - else - { - disabledWidgets &= ~(1uLL << WIDX_RESOLUTION_DROPDOWN); - disabledWidgets &= ~(1uLL << WIDX_RESOLUTION); - disabledWidgets &= ~(1uLL << WIDX_RESOLUTION_LABEL); - } + const bool disableResolution = Config::Get().general.fullscreenMode + != static_cast(FullscreenMode::fullscreen); + setWidgetDisabled(WIDX_RESOLUTION_DROPDOWN, disableResolution); + setWidgetDisabled(WIDX_RESOLUTION, disableResolution); + setWidgetDisabled(WIDX_RESOLUTION_LABEL, disableResolution); setCheckboxValue(WIDX_SHOW_FPS_CHECKBOX, Config::Get().general.showFPS); setCheckboxValue(WIDX_MULTITHREADING_CHECKBOX, Config::Get().general.multiThreading); @@ -1154,43 +1147,26 @@ namespace OpenRCT2::Ui::Windows widgets[WIDX_VIRTUAL_FLOOR].text = _virtualFloorStyleStrings[EnumValue(Config::Get().general.virtualFloorStyle)]; setCheckboxValue(WIDX_ENABLE_LIGHT_FX_CHECKBOX, Config::Get().general.enableLightFx); - if (Config::Get().general.dayNightCycle - && Config::Get().general.drawingEngine == DrawingEngine::SoftwareWithHardwareDisplay) - { - disabledWidgets &= ~(1uLL << WIDX_ENABLE_LIGHT_FX_CHECKBOX); - } - else - { - disabledWidgets |= (1uLL << WIDX_ENABLE_LIGHT_FX_CHECKBOX); + const bool lightFxEnabled = Config::Get().general.dayNightCycle + && Config::Get().general.drawingEngine == DrawingEngine::SoftwareWithHardwareDisplay; + setWidgetDisabled(WIDX_ENABLE_LIGHT_FX_CHECKBOX, !lightFxEnabled); + if (!lightFxEnabled) Config::Get().general.enableLightFx = false; - } setCheckboxValue(WIDX_ENABLE_LIGHT_FX_FOR_VEHICLES_CHECKBOX, Config::Get().general.enableLightFxForVehicles); - if (Config::Get().general.dayNightCycle - && Config::Get().general.drawingEngine == DrawingEngine::SoftwareWithHardwareDisplay - && Config::Get().general.enableLightFx) - { - disabledWidgets &= ~(1uLL << WIDX_ENABLE_LIGHT_FX_FOR_VEHICLES_CHECKBOX); - } - else - { - disabledWidgets |= (1uLL << WIDX_ENABLE_LIGHT_FX_FOR_VEHICLES_CHECKBOX); + const bool lightFxForVehiclesEnabled = lightFxEnabled && Config::Get().general.enableLightFx; + setWidgetDisabled(WIDX_ENABLE_LIGHT_FX_FOR_VEHICLES_CHECKBOX, !lightFxForVehiclesEnabled); + if (!lightFxForVehiclesEnabled) Config::Get().general.enableLightFxForVehicles = false; - } setCheckboxValue( WIDX_RENDER_WEATHER_EFFECTS_CHECKBOX, Config::Get().general.renderWeatherEffects || Config::Get().general.renderWeatherGloom); setCheckboxValue(WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX, Config::Get().general.disableLightningEffect); - if (!Config::Get().general.renderWeatherEffects && !Config::Get().general.renderWeatherGloom) - { + const bool noWeather = !Config::Get().general.renderWeatherEffects && !Config::Get().general.renderWeatherGloom; + if (noWeather) setCheckboxValue(WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX, true); - disabledWidgets |= (1uLL << WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX); - } - else - { - disabledWidgets &= ~(1uLL << WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX); - } + setWidgetDisabled(WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX, noWeather); } #pragma endregion @@ -2005,9 +1981,12 @@ namespace OpenRCT2::Ui::Windows // The real name setting of clients is fixed to that of the server // and the server cannot change the setting during gameplay to prevent desyncs - if (Network::GetMode() != Network::Mode::none) + const bool inNetwork = Network::GetMode() != Network::Mode::none; + setWidgetDisabled(WIDX_REAL_NAMES_GUESTS_CHECKBOX, inNetwork); + setWidgetDisabled(WIDX_REAL_NAMES_STAFF_CHECKBOX, inNetwork); + setWidgetDisabled(WIDX_ALLOW_EARLY_COMPLETION, Network::GetMode() == Network::Mode::client); + if (inNetwork) { - disabledWidgets |= (1uLL << WIDX_REAL_NAMES_GUESTS_CHECKBOX) | (1uLL << WIDX_REAL_NAMES_STAFF_CHECKBOX); widgets[WIDX_REAL_NAMES_GUESTS_CHECKBOX].tooltip = STR_OPTION_DISABLED_DURING_NETWORK_PLAY; widgets[WIDX_REAL_NAMES_STAFF_CHECKBOX].tooltip = STR_OPTION_DISABLED_DURING_NETWORK_PLAY; @@ -2016,7 +1995,6 @@ namespace OpenRCT2::Ui::Windows // the way scenarios are completed during this network-session if (Network::GetMode() == Network::Mode::client) { - disabledWidgets |= (1uLL << WIDX_ALLOW_EARLY_COMPLETION); widgets[WIDX_ALLOW_EARLY_COMPLETION].tooltip = STR_OPTION_DISABLED_DURING_NETWORK_PLAY; } } @@ -2270,7 +2248,6 @@ namespace OpenRCT2::Ui::Windows page = p; currentFrame = 0; - pressedWidgets = 0; setWidgets(window_options_page_widgets[page]); invalidate(); @@ -2283,8 +2260,7 @@ namespace OpenRCT2::Ui::Windows void SetPressedTab() { for (int32_t i = 0; i < WINDOW_OPTIONS_PAGE_COUNT; i++) - pressedWidgets &= ~(1 << (WIDX_FIRST_TAB + i)); - pressedWidgets |= 1LL << (WIDX_FIRST_TAB + page); + setWidgetPressed(WIDX_FIRST_TAB + i, i == page); } void ShowDropdown(Widget* widget, int32_t num_items) diff --git a/src/openrct2-ui/windows/Park.cpp b/src/openrct2-ui/windows/Park.cpp index 975de6bcc8..c554bc7015 100644 --- a/src/openrct2-ui/windows/Park.cpp +++ b/src/openrct2-ui/windows/Park.cpp @@ -161,19 +161,6 @@ namespace OpenRCT2::Ui::Windows #pragma endregion - // clang-format off - static std::array _pagedHoldDownWidgets = { - 0, - 0, - 0, - (1uLL << WIDX_INCREASE_PRICE) | - (1uLL << WIDX_DECREASE_PRICE), - 0, - 0, - 0, - }; - // clang-format on - class ParkWindow final : public Window { int32_t _numberOfStaff = -1; @@ -401,7 +388,7 @@ namespace OpenRCT2::Ui::Windows void SetDisabledTabs() { // Disable price tab if money is disabled - disabledWidgets = (getGameState().park.flags & PARK_FLAGS_NO_MONEY) ? (1uLL << WIDX_TAB_4) : 0; + setWidgetDisabled(WIDX_TAB_4, (getGameState().park.flags & PARK_FLAGS_NO_MONEY) != 0); } void PrepareWindowTitleText() @@ -518,10 +505,10 @@ namespace OpenRCT2::Ui::Windows widgets[WIDX_OPEN_LIGHT].image = ImageId(openLightImage); // only allow closing of park for guest / rating objective - if (gameState.scenarioOptions.objective.Type == Scenario::ObjectiveType::guestsAndRating) - disabledWidgets |= (1uLL << WIDX_OPEN_OR_CLOSE) | (1uLL << WIDX_CLOSE_LIGHT) | (1uLL << WIDX_OPEN_LIGHT); - else - disabledWidgets &= ~((1uLL << WIDX_OPEN_OR_CLOSE) | (1uLL << WIDX_CLOSE_LIGHT) | (1uLL << WIDX_OPEN_LIGHT)); + const bool disableOpenClose = gameState.scenarioOptions.objective.Type == Scenario::ObjectiveType::guestsAndRating; + setWidgetDisabled(WIDX_OPEN_OR_CLOSE, disableOpenClose); + setWidgetDisabled(WIDX_CLOSE_LIGHT, disableOpenClose); + setWidgetDisabled(WIDX_OPEN_LIGHT, disableOpenClose); // only allow purchase of land when there is money if (gameState.park.flags & PARK_FLAGS_NO_MONEY) @@ -1181,8 +1168,9 @@ namespace OpenRCT2::Ui::Windows _peepAnimationFrame = 0; removeViewport(); - holdDownWidgets = _pagedHoldDownWidgets[newPage]; setWidgets(_pagedWidgets[newPage]); + if (newPage == WINDOW_PARK_PAGE_PRICE) + widgetsSetHoldable(*this, { WIDX_INCREASE_PRICE, WIDX_DECREASE_PRICE }); SetDisabledTabs(); invalidate(); initScrollWidgets(); @@ -1204,9 +1192,9 @@ namespace OpenRCT2::Ui::Windows void SetPressedTab() { - for (int32_t i = WIDX_TAB_1; i <= WIDX_TAB_7; i++) - pressedWidgets &= ~(1 << i); - pressedWidgets |= 1LL << (WIDX_TAB_1 + page); + widgetSetPressedExclusive( + *this, { WIDX_TAB_1, WIDX_TAB_2, WIDX_TAB_3, WIDX_TAB_4, WIDX_TAB_5, WIDX_TAB_6, WIDX_TAB_7 }, + WIDX_TAB_1 + page); } void DrawTabImages(RenderTarget& rt) diff --git a/src/openrct2-ui/windows/PatrolArea.cpp b/src/openrct2-ui/windows/PatrolArea.cpp index 63426dd910..47ae1d2a3c 100644 --- a/src/openrct2-ui/windows/PatrolArea.cpp +++ b/src/openrct2-ui/windows/PatrolArea.cpp @@ -62,7 +62,7 @@ namespace OpenRCT2::Ui::Windows { setWidgets(PatrolAreaWidgets); - holdDownWidgets = (1uLL << WIDX_INCREMENT) | (1uLL << WIDX_DECREMENT); + widgetsSetHoldable(*this, { WIDX_INCREMENT, WIDX_DECREMENT }); WindowInitScrollWidgets(*this); WindowPushOthersBelow(*this); gLandToolSize = 4; diff --git a/src/openrct2-ui/windows/Player.cpp b/src/openrct2-ui/windows/Player.cpp index 10c16ef185..25b245143c 100644 --- a/src/openrct2-ui/windows/Player.cpp +++ b/src/openrct2-ui/windows/Player.cpp @@ -106,8 +106,6 @@ namespace OpenRCT2::Ui::Windows WindowSetResize(*this, { 210, 134 }, { 500, 450 }); - holdDownWidgets = 0; - pressedWidgets = 0; setPage(WINDOW_PLAYER_PAGE_OVERVIEW); } @@ -222,8 +220,6 @@ namespace OpenRCT2::Ui::Windows page = newPage; currentFrame = 0; - holdDownWidgets = 0; - pressedWidgets = 0; setWidgets(window_player_page_widgets[newPage]); invalidate(); onResize(); @@ -378,9 +374,7 @@ namespace OpenRCT2::Ui::Windows return; } - pressedWidgets &= ~(WIDX_TAB_1); - pressedWidgets &= ~(WIDX_TAB_2); - pressedWidgets |= 1uLL << (page + WIDX_TAB_1); + widgetSetPressedExclusive(*this, { WIDX_TAB_1, WIDX_TAB_2 }, page + WIDX_TAB_1); UpdateTitle(); @@ -589,9 +583,7 @@ namespace OpenRCT2::Ui::Windows void onPrepareDrawStatistics() { - pressedWidgets &= ~(WIDX_TAB_1); - pressedWidgets &= ~(WIDX_TAB_2); - pressedWidgets |= 1uLL << (page + WIDX_TAB_1); + widgetSetPressedExclusive(*this, { WIDX_TAB_1, WIDX_TAB_2 }, page + WIDX_TAB_1); UpdateTitle(); diff --git a/src/openrct2-ui/windows/Research.cpp b/src/openrct2-ui/windows/Research.cpp index 1464d3cb64..f4523cc1c8 100644 --- a/src/openrct2-ui/windows/Research.cpp +++ b/src/openrct2-ui/windows/Research.cpp @@ -148,9 +148,6 @@ namespace OpenRCT2::Ui::Windows invalidate(); setWidgets(window_research_page_widgets[newPageIndex]); - holdDownWidgets = 0; - disabledWidgets = 0; - pressedWidgets = 0; } private: @@ -555,24 +552,10 @@ namespace OpenRCT2::Ui::Windows for (int32_t i = 0; i < 7; i++) { int32_t mask = 1 << i; - int32_t widgetMask = 1uLL << (i + WIDX_TRANSPORT_RIDES + widgetOffset); - - // Set checkbox disabled if research type is complete - if (uncompletedResearchTypes & mask) - { - w->disabledWidgets &= ~widgetMask; - - // Set checkbox ticked if research type is active - if (activeResearchTypes & mask) - w->pressedWidgets |= widgetMask; - else - w->pressedWidgets &= ~widgetMask; - } - else - { - w->disabledWidgets |= widgetMask; - w->pressedWidgets &= ~widgetMask; - } + const WidgetIndex widgetIdx = static_cast(i + WIDX_TRANSPORT_RIDES + widgetOffset); + const bool uncompleted = (uncompletedResearchTypes & mask) != 0; + widgetSetDisabled(*w, widgetIdx, !uncompleted); + widgetSetPressed(*w, widgetIdx, uncompleted && (activeResearchTypes & mask) != 0); } } diff --git a/src/openrct2-ui/windows/Ride.cpp b/src/openrct2-ui/windows/Ride.cpp index 707a987c34..cef5727d22 100644 --- a/src/openrct2-ui/windows/Ride.cpp +++ b/src/openrct2-ui/windows/Ride.cpp @@ -428,36 +428,35 @@ namespace OpenRCT2::Ui::Windows }; static_assert(std::size(PageWidgets) == WINDOW_RIDE_PAGE_COUNT); - static constexpr std::array PageHoldDownWidgets = { - 0uLL, - (1uLL << WIDX_VEHICLE_TRAINS_INCREASE) | - (1uLL << WIDX_VEHICLE_TRAINS_DECREASE) | - (1uLL << WIDX_VEHICLE_CARS_PER_TRAIN_INCREASE) | - (1uLL << WIDX_VEHICLE_CARS_PER_TRAIN_DECREASE), - (1uLL << WIDX_MODE_TWEAK_INCREASE) | - (1uLL << WIDX_MODE_TWEAK_DECREASE) | - (1uLL << WIDX_LIFT_HILL_SPEED_INCREASE) | - (1uLL << WIDX_LIFT_HILL_SPEED_DECREASE) | - (1uLL << WIDX_MINIMUM_LENGTH_INCREASE) | - (1uLL << WIDX_MINIMUM_LENGTH_DECREASE) | - (1uLL << WIDX_MAXIMUM_LENGTH_INCREASE) | - (1uLL << WIDX_MAXIMUM_LENGTH_DECREASE) | - (1uLL << WIDX_OPERATE_NUMBER_OF_CIRCUITS_INCREASE) | - (1uLL << WIDX_OPERATE_NUMBER_OF_CIRCUITS_DECREASE), - 0uLL, - 0uLL, - 0uLL, - 0uLL, - 0uLL, - (1uLL << WIDX_PRIMARY_PRICE_INCREASE) | - (1uLL << WIDX_PRIMARY_PRICE_DECREASE) | - (1uLL << WIDX_SECONDARY_PRICE_INCREASE) | - (1uLL << WIDX_SECONDARY_PRICE_DECREASE), - 0uLL, - }; - static_assert(std::size(PageHoldDownWidgets) == WINDOW_RIDE_PAGE_COUNT); // clang-format on + static void setPageHoldableWidgets(WindowBase& w, int32_t page) + { + switch (page) + { + case WINDOW_RIDE_PAGE_VEHICLE: + widgetsSetHoldable( + w, + { WIDX_VEHICLE_TRAINS_INCREASE, WIDX_VEHICLE_TRAINS_DECREASE, WIDX_VEHICLE_CARS_PER_TRAIN_INCREASE, + WIDX_VEHICLE_CARS_PER_TRAIN_DECREASE }); + break; + case WINDOW_RIDE_PAGE_OPERATING: + widgetsSetHoldable( + w, + { WIDX_MODE_TWEAK_INCREASE, WIDX_MODE_TWEAK_DECREASE, WIDX_LIFT_HILL_SPEED_INCREASE, + WIDX_LIFT_HILL_SPEED_DECREASE, WIDX_MINIMUM_LENGTH_INCREASE, WIDX_MINIMUM_LENGTH_DECREASE, + WIDX_MAXIMUM_LENGTH_INCREASE, WIDX_MAXIMUM_LENGTH_DECREASE, WIDX_OPERATE_NUMBER_OF_CIRCUITS_INCREASE, + WIDX_OPERATE_NUMBER_OF_CIRCUITS_DECREASE }); + break; + case WINDOW_RIDE_PAGE_INCOME: + widgetsSetHoldable( + w, + { WIDX_PRIMARY_PRICE_INCREASE, WIDX_PRIMARY_PRICE_DECREASE, WIDX_SECONDARY_PRICE_INCREASE, + WIDX_SECONDARY_PRICE_DECREASE }); + break; + } + } + #pragma endregion static void CancelScenerySelection(); @@ -778,7 +777,6 @@ namespace OpenRCT2::Ui::Windows void onOpen() override { setWidgets(PageWidgets[WINDOW_RIDE_PAGE_MAIN]); - holdDownWidgets = PageHoldDownWidgets[WINDOW_RIDE_PAGE_MAIN]; setPage(WINDOW_RIDE_PAGE_MAIN); listInformationType = 0; @@ -1212,9 +1210,13 @@ namespace OpenRCT2::Ui::Windows removeViewport(); - holdDownWidgets = PageHoldDownWidgets[page]; - pressedWidgets = 0; setWidgets(PageWidgets[page]); + setPageHoldableWidgets(*this, page); + widgetSetPressedExclusive( + *this, + { WIDX_TAB_1, WIDX_TAB_2, WIDX_TAB_3, WIDX_TAB_4, WIDX_TAB_5, WIDX_TAB_6, WIDX_TAB_7, WIDX_TAB_8, WIDX_TAB_9, + WIDX_TAB_10 }, + WIDX_TAB_1 + page); DisableTabs(); invalidate(); @@ -1393,57 +1395,43 @@ namespace OpenRCT2::Ui::Windows void DisableTabs() { - uint32_t disabledTabs = 0; auto ride = GetRide(rideId); if (ride == nullptr) return; const auto& rtd = ride->getRideTypeDescriptor(); - - if (!rtd.flags.has(RtdFlag::hasDataLogging)) - disabledTabs |= (1uLL << WIDX_TAB_8); // 0x800 - - if (rtd.specialType == RtdSpecialType::miniGolf) - disabledTabs |= (1uLL << WIDX_TAB_2 | 1uLL << WIDX_TAB_3 | 1uLL << WIDX_TAB_4); // 0xE0 - - if (rtd.flags.has(RtdFlag::noVehicles)) - disabledTabs |= (1uLL << WIDX_TAB_2); // 0x20 - - if (!rtd.flags.hasAny( - RtdFlag::hasTrackColourMain, RtdFlag::hasTrackColourAdditional, RtdFlag::hasTrackColourSupports, - RtdFlag::hasVehicleColours, RtdFlag::hasEntranceAndExit)) - { - disabledTabs |= (1uLL << WIDX_TAB_5); // 0x100 - } - - if (rtd.flags.has(RtdFlag::isShopOrFacility)) - disabledTabs |= (1uLL << WIDX_TAB_3 | 1uLL << WIDX_TAB_4 | 1uLL << WIDX_TAB_7); // 0x4C0 - - if (!rtd.flags.has(RtdFlag::allowMusic)) - { - disabledTabs |= (1uLL << WIDX_TAB_6); // 0x200 - } - - if (rtd.specialType == RtdSpecialType::cashMachine || rtd.specialType == RtdSpecialType::firstAid - || (getGameState().park.flags & PARK_FLAGS_NO_MONEY) != 0) - disabledTabs |= (1uLL << WIDX_TAB_9); // 0x1000 - - if (gLegacyScene == LegacyScene::trackDesigner) - disabledTabs |= (1uLL << WIDX_TAB_4 | 1uLL << WIDX_TAB_6 | 1uLL << WIDX_TAB_9 | 1uLL << WIDX_TAB_10); // 0x3280 - const auto* rideEntry = GetRideEntryByIndex(ride->subtype); + const bool noRideEntry = rideEntry == nullptr; - if (rideEntry == nullptr) - { - disabledTabs |= 1uLL << WIDX_TAB_2 | 1uLL << WIDX_TAB_3 | 1uLL << WIDX_TAB_4 | 1uLL << WIDX_TAB_5 - | 1uLL << WIDX_TAB_6 | 1uLL << WIDX_TAB_7 | 1uLL << WIDX_TAB_8 | 1uLL << WIDX_TAB_9 | 1uLL << WIDX_TAB_10; - } - else if (rideEntry->flags.has(RideEntryFlag::disableColourTab)) - { - disabledTabs |= (1uLL << WIDX_TAB_5); - } + const bool disableTab2 = noRideEntry || rtd.specialType == RtdSpecialType::miniGolf + || rtd.flags.has(RtdFlag::noVehicles); + const bool disableTab3 = noRideEntry || rtd.specialType == RtdSpecialType::miniGolf + || rtd.flags.has(RtdFlag::isShopOrFacility); + const bool disableTab4 = noRideEntry || rtd.specialType == RtdSpecialType::miniGolf + || rtd.flags.has(RtdFlag::isShopOrFacility) || gLegacyScene == LegacyScene::trackDesigner; + const bool disableTab5 = noRideEntry + || !rtd.flags.hasAny( + RtdFlag::hasTrackColourMain, RtdFlag::hasTrackColourAdditional, RtdFlag::hasTrackColourSupports, + RtdFlag::hasVehicleColours, RtdFlag::hasEntranceAndExit) + || (!noRideEntry && rideEntry->flags.has(RideEntryFlag::disableColourTab)); + const bool disableTab6 = noRideEntry || !rtd.flags.has(RtdFlag::allowMusic) + || gLegacyScene == LegacyScene::trackDesigner; + const bool disableTab7 = noRideEntry || rtd.flags.has(RtdFlag::isShopOrFacility); + const bool disableTab8 = noRideEntry || !rtd.flags.has(RtdFlag::hasDataLogging); + const bool disableTab9 = noRideEntry || rtd.specialType == RtdSpecialType::cashMachine + || rtd.specialType == RtdSpecialType::firstAid || (getGameState().park.flags & PARK_FLAGS_NO_MONEY) != 0 + || gLegacyScene == LegacyScene::trackDesigner; + const bool disableTab10 = noRideEntry || gLegacyScene == LegacyScene::trackDesigner; - disabledWidgets = disabledTabs; + setWidgetDisabled(WIDX_TAB_2, disableTab2); + setWidgetDisabled(WIDX_TAB_3, disableTab3); + setWidgetDisabled(WIDX_TAB_4, disableTab4); + setWidgetDisabled(WIDX_TAB_5, disableTab5); + setWidgetDisabled(WIDX_TAB_6, disableTab6); + setWidgetDisabled(WIDX_TAB_7, disableTab7); + setWidgetDisabled(WIDX_TAB_8, disableTab8); + setWidgetDisabled(WIDX_TAB_9, disableTab9); + setWidgetDisabled(WIDX_TAB_10, disableTab10); } void UpdateOverallView(const Ride& ride) const @@ -1507,13 +1495,6 @@ namespace OpenRCT2::Ui::Windows } } - void SetPressedTab() - { - for (int32_t i = 0; i < WINDOW_RIDE_PAGE_COUNT; i++) - pressedWidgets &= ~(1 << (WIDX_TAB_1 + i)); - pressedWidgets |= 1LL << (WIDX_TAB_1 + page); - } - #pragma region Main std::optional GetStationIndexFromViewSelection() const @@ -2424,17 +2405,16 @@ namespace OpenRCT2::Ui::Windows { int32_t i, widgetHeight; - SetPressedTab(); - auto ride = GetRide(rideId); if (ride == nullptr) return; const auto& gameState = getGameState(); - disabledWidgets &= ~((1uLL << WIDX_DEMOLISH) | (1uLL << WIDX_CONSTRUCTION)); - if (ride->flags.hasAny(RideFlag::indestructible, RideFlag::indestructibleTrack) - && !gameState.cheats.makeAllDestructible) - disabledWidgets |= (1uLL << WIDX_DEMOLISH); + setWidgetDisabled(WIDX_CONSTRUCTION, false); + setWidgetDisabled( + WIDX_DEMOLISH, + ride->flags.hasAny(RideFlag::indestructible, RideFlag::indestructibleTrack) + && !gameState.cheats.makeAllDestructible); uint32_t spriteIds[] = { SPR_CLOSED, @@ -2874,8 +2854,6 @@ namespace OpenRCT2::Ui::Windows void VehicleOnPrepareDraw() { - SetPressedTab(); - auto ride = GetRide(rideId); if (ride == nullptr) return; @@ -2922,14 +2900,7 @@ namespace OpenRCT2::Ui::Windows || (gameState.cheats.disableTrainLengthLimit && !ride->getRideTypeDescriptor().flags.has(RtdFlag::isFlatRide))) { widgets[WIDX_VEHICLE_REVERSED_TRAINS_CHECKBOX].type = WidgetType::checkbox; - if (ride->flags.has(RideFlag::reversedTrains)) - { - pressedWidgets |= (1uLL << WIDX_VEHICLE_REVERSED_TRAINS_CHECKBOX); - } - else - { - pressedWidgets &= ~(1uLL << WIDX_VEHICLE_REVERSED_TRAINS_CHECKBOX); - } + setWidgetPressed(WIDX_VEHICLE_REVERSED_TRAINS_CHECKBOX, ride->flags.has(RideFlag::reversedTrains)); } else { @@ -3555,17 +3526,16 @@ namespace OpenRCT2::Ui::Windows { StringId format, caption, tooltip; - SetPressedTab(); - auto ride = GetRide(rideId); if (ride == nullptr) return; // Widget setup - pressedWidgets &= ~( - (1uLL << WIDX_LOAD_CHECKBOX) | (1uLL << WIDX_LEAVE_WHEN_ANOTHER_ARRIVES_CHECKBOX) - | (1uLL << WIDX_MINIMUM_LENGTH_CHECKBOX) | (1uLL << WIDX_MAXIMUM_LENGTH_CHECKBOX) - | (1uLL << WIDX_SYNCHRONISE_WITH_ADJACENT_STATIONS_CHECKBOX)); + setWidgetPressed(WIDX_LOAD_CHECKBOX, false); + setWidgetPressed(WIDX_LEAVE_WHEN_ANOTHER_ARRIVES_CHECKBOX, false); + setWidgetPressed(WIDX_MINIMUM_LENGTH_CHECKBOX, false); + setWidgetPressed(WIDX_MAXIMUM_LENGTH_CHECKBOX, false); + setWidgetPressed(WIDX_SYNCHRONISE_WITH_ADJACENT_STATIONS_CHECKBOX, false); // Sometimes, only one of the alternatives support lift hill pieces. Make sure to check both. const auto& rtd = ride->getRideTypeDescriptor(); @@ -3661,7 +3631,7 @@ namespace OpenRCT2::Ui::Windows widgets[WIDX_MAXIMUM_LENGTH].setString(_spinnerCaption4.c_str()); if (ride->departFlags & RIDE_DEPART_WAIT_FOR_LOAD) - pressedWidgets |= (1uLL << WIDX_LOAD_CHECKBOX); + setWidgetPressed(WIDX_LOAD_CHECKBOX, true); } else { @@ -3681,13 +3651,13 @@ namespace OpenRCT2::Ui::Windows } if (ride->departFlags & RIDE_DEPART_LEAVE_WHEN_ANOTHER_ARRIVES) - pressedWidgets |= (1uLL << WIDX_LEAVE_WHEN_ANOTHER_ARRIVES_CHECKBOX); + setWidgetPressed(WIDX_LEAVE_WHEN_ANOTHER_ARRIVES_CHECKBOX, true); if (ride->departFlags & RIDE_DEPART_SYNCHRONISE_WITH_ADJACENT_STATIONS) - pressedWidgets |= (1uLL << WIDX_SYNCHRONISE_WITH_ADJACENT_STATIONS_CHECKBOX); + setWidgetPressed(WIDX_SYNCHRONISE_WITH_ADJACENT_STATIONS_CHECKBOX, true); if (ride->departFlags & RIDE_DEPART_WAIT_FOR_MINIMUM_LENGTH) - pressedWidgets |= (1uLL << WIDX_MINIMUM_LENGTH_CHECKBOX); + setWidgetPressed(WIDX_MINIMUM_LENGTH_CHECKBOX, true); if (ride->departFlags & RIDE_DEPART_WAIT_FOR_MAXIMUM_LENGTH) - pressedWidgets |= (1uLL << WIDX_MAXIMUM_LENGTH_CHECKBOX); + setWidgetPressed(WIDX_MAXIMUM_LENGTH_CHECKBOX, true); // Mode specific functionality auto multiplier = ride->getRideTypeDescriptor().OperatingSettings.OperatingSettingMultiplier; @@ -3752,7 +3722,7 @@ namespace OpenRCT2::Ui::Windows widgets[WIDX_MODE_TWEAK].setString(_spinnerCaption0.c_str()); widgets[WIDX_MODE_TWEAK_INCREASE].type = WidgetType::button; widgets[WIDX_MODE_TWEAK_DECREASE].type = WidgetType::button; - pressedWidgets &= ~(1uLL << WIDX_LEAVE_WHEN_ANOTHER_ARRIVES_CHECKBOX); + setWidgetPressed(WIDX_LEAVE_WHEN_ANOTHER_ARRIVES_CHECKBOX, false); } else { @@ -4070,8 +4040,6 @@ namespace OpenRCT2::Ui::Windows void MaintenanceOnPrepareDraw() { - SetPressedTab(); - auto ride = GetRide(rideId); if (ride == nullptr) return; @@ -4091,12 +4059,12 @@ namespace OpenRCT2::Ui::Windows if (ride->getRideTypeDescriptor().availableBreakdowns.isEmpty() || !ride->flags.has(RideFlag::everBeenOpened)) { - disabledWidgets |= (1uLL << WIDX_REFURBISH_RIDE); + setWidgetDisabled(WIDX_REFURBISH_RIDE, true); widgets[WIDX_REFURBISH_RIDE].tooltip = STR_CANT_REFURBISH_NOT_NEEDED; } else { - disabledWidgets &= ~(1uLL << WIDX_REFURBISH_RIDE); + setWidgetDisabled(WIDX_REFURBISH_RIDE, false); widgets[WIDX_REFURBISH_RIDE].tooltip = STR_REFURBISH_RIDE_TIP; } } @@ -4651,7 +4619,6 @@ namespace OpenRCT2::Ui::Windows void ColourOnPrepareDraw() { - SetPressedTab(); WindowAlignTabs(this, WIDX_TAB_1, WIDX_TAB_10); auto ride = GetRide(rideId); @@ -4736,14 +4703,7 @@ namespace OpenRCT2::Ui::Windows if (ride->hasRecolourableShopItems()) { widgets[WIDX_SELL_ITEM_RANDOM_COLOUR_CHECKBOX].type = WidgetType::checkbox; - if (ride->flags.has(RideFlag::randomShopColours)) - { - pressedWidgets |= (1uLL << WIDX_SELL_ITEM_RANDOM_COLOUR_CHECKBOX); - } - else - { - pressedWidgets &= ~(1uLL << WIDX_SELL_ITEM_RANDOM_COLOUR_CHECKBOX); - } + setWidgetPressed(WIDX_SELL_ITEM_RANDOM_COLOUR_CHECKBOX, ride->flags.has(RideFlag::randomShopColours)); } else { @@ -5386,8 +5346,6 @@ namespace OpenRCT2::Ui::Windows void MusicOnPrepareDraw() { - SetPressedTab(); - auto ride = GetRide(rideId); if (ride == nullptr) return; @@ -5427,14 +5385,19 @@ namespace OpenRCT2::Ui::Windows widgets[WIDX_MUSIC_DATA].right = width - 8; } - pressedWidgets |= (1uLL << WIDX_PLAY_MUSIC) | (1uLL << WIDX_MUSIC_IMAGE); - disabledWidgets &= ~((1uLL << WIDX_MUSIC) | (1uLL << WIDX_MUSIC_DROPDOWN) | (1uLL << WIDX_MUSIC_DATA)); + setWidgetPressed(WIDX_PLAY_MUSIC, true); + setWidgetPressed(WIDX_MUSIC_IMAGE, true); + setWidgetDisabled(WIDX_MUSIC, false); + setWidgetDisabled(WIDX_MUSIC_DROPDOWN, false); + setWidgetDisabled(WIDX_MUSIC_DATA, false); } else { - pressedWidgets &= ~(1uLL << WIDX_PLAY_MUSIC); - pressedWidgets |= (1uLL << WIDX_MUSIC_IMAGE); - disabledWidgets |= (1uLL << WIDX_MUSIC) | (1uLL << WIDX_MUSIC_DROPDOWN) | (1uLL << WIDX_MUSIC_DATA); + setWidgetPressed(WIDX_PLAY_MUSIC, false); + setWidgetPressed(WIDX_MUSIC_IMAGE, true); + setWidgetDisabled(WIDX_MUSIC, true); + setWidgetDisabled(WIDX_MUSIC_DROPDOWN, true); + setWidgetDisabled(WIDX_MUSIC_DATA, true); } WindowAlignTabs(this, WIDX_TAB_1, WIDX_TAB_10); @@ -5779,8 +5742,6 @@ namespace OpenRCT2::Ui::Windows void MeasurementsOnPrepareDraw() { - SetPressedTab(); - auto ride = GetRide(rideId); if (ride == nullptr) return; @@ -5802,15 +5763,10 @@ namespace OpenRCT2::Ui::Windows widgets[WIDX_CANCEL_DESIGN].type = WidgetType::empty; widgets[WIDX_SAVE_TRACK_DESIGN].type = WidgetType::flatBtn; - disabledWidgets |= (1uLL << WIDX_SAVE_TRACK_DESIGN); - if (ride->flags.has(RideFlag::tested)) - { - if (!ride->ratings.isNull()) - { - disabledWidgets &= ~(1uLL << WIDX_SAVE_TRACK_DESIGN); - widgets[WIDX_SAVE_TRACK_DESIGN].tooltip = STR_SAVE_TRACK_DESIGN; - } - } + const bool canSaveTrackDesign = ride->flags.has(RideFlag::tested) && !ride->ratings.isNull(); + setWidgetDisabled(WIDX_SAVE_TRACK_DESIGN, !canSaveTrackDesign); + if (canSaveTrackDesign) + widgets[WIDX_SAVE_TRACK_DESIGN].tooltip = STR_SAVE_TRACK_DESIGN; } WindowAlignTabs(this, WIDX_TAB_1, WIDX_TAB_10); @@ -6211,18 +6167,14 @@ namespace OpenRCT2::Ui::Windows void GraphsOnPrepareDraw() { - SetPressedTab(); - auto ride = GetRide(rideId); if (ride == nullptr) return; // Set pressed graph button type - pressedWidgets &= ~(1uLL << WIDX_GRAPH_VELOCITY); - pressedWidgets &= ~(1uLL << WIDX_GRAPH_ALTITUDE); - pressedWidgets &= ~(1uLL << WIDX_GRAPH_VERTICAL); - pressedWidgets &= ~(1uLL << WIDX_GRAPH_LATERAL); - pressedWidgets |= (1LL << (WIDX_GRAPH_VELOCITY + listInformationType)); + widgetSetPressedExclusive( + *this, { WIDX_GRAPH_VELOCITY, WIDX_GRAPH_ALTITUDE, WIDX_GRAPH_VERTICAL, WIDX_GRAPH_LATERAL }, + WIDX_GRAPH_VELOCITY + listInformationType); // Hide graph buttons that are not applicable if (ride->getRideTypeDescriptor().flags.has(RtdFlag::hasGForces)) @@ -6720,8 +6672,6 @@ namespace OpenRCT2::Ui::Windows void IncomeOnPrepareDraw() { - SetPressedTab(); - auto ride = GetRide(rideId); if (ride == nullptr) return; @@ -6731,8 +6681,7 @@ namespace OpenRCT2::Ui::Windows return; // Primary item - pressedWidgets &= ~(1uLL << WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK); - disabledWidgets &= ~(1uLL << WIDX_PRIMARY_PRICE); + setWidgetPressed(WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK, false); widgets[WIDX_PRIMARY_PRICE_LABEL].tooltip = kStringIdNone; widgets[WIDX_PRIMARY_PRICE].tooltip = kStringIdNone; @@ -6741,10 +6690,11 @@ namespace OpenRCT2::Ui::Windows // If ride prices are locked, do not allow setting the price, unless we're dealing with a shop or toilet. const auto& rtd = ride->getRideTypeDescriptor(); - if (!Park::RidePricesUnlocked(park) && rideEntry->shop_item[0] == ShopItem::none - && rtd.specialType != RtdSpecialType::toilet) + const bool primaryPriceLocked = !Park::RidePricesUnlocked(park) && rideEntry->shop_item[0] == ShopItem::none + && rtd.specialType != RtdSpecialType::toilet; + setWidgetDisabled(WIDX_PRIMARY_PRICE, primaryPriceLocked); + if (primaryPriceLocked) { - disabledWidgets |= (1uLL << WIDX_PRIMARY_PRICE); widgets[WIDX_PRIMARY_PRICE_LABEL].tooltip = STR_RIDE_INCOME_ADMISSION_PAY_FOR_ENTRY_TIP; widgets[WIDX_PRIMARY_PRICE].tooltip = STR_RIDE_INCOME_ADMISSION_PAY_FOR_ENTRY_TIP; } @@ -6770,7 +6720,7 @@ namespace OpenRCT2::Ui::Windows widgets[WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK].type = WidgetType::checkbox; if (ShopItemHasCommonPrice(primaryItem)) - pressedWidgets |= (1uLL << WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK); + setWidgetPressed(WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK, true); widgets[WIDX_PRIMARY_PRICE_LABEL].text = GetShopItemDescriptor(primaryItem).Naming.PriceLabel; } @@ -6797,9 +6747,7 @@ namespace OpenRCT2::Ui::Windows else { // Set same price throughout park checkbox - pressedWidgets &= ~(1uLL << WIDX_SECONDARY_PRICE_SAME_THROUGHOUT_PARK); - if (ShopItemHasCommonPrice(secondaryItem)) - pressedWidgets |= (1uLL << WIDX_SECONDARY_PRICE_SAME_THROUGHOUT_PARK); + setWidgetPressed(WIDX_SECONDARY_PRICE_SAME_THROUGHOUT_PARK, ShopItemHasCommonPrice(secondaryItem)); // Show widgets widgets[WIDX_SECONDARY_PRICE_LABEL].type = WidgetType::label; @@ -6998,8 +6946,6 @@ namespace OpenRCT2::Ui::Windows void CustomerOnPrepareDraw() { - SetPressedTab(); - auto ride = GetRide(rideId); if (ride != nullptr) { diff --git a/src/openrct2-ui/windows/RideConstruction.cpp b/src/openrct2-ui/windows/RideConstruction.cpp index a616c0ac5b..082d9ef6ba 100644 --- a/src/openrct2-ui/windows/RideConstruction.cpp +++ b/src/openrct2-ui/windows/RideConstruction.cpp @@ -1009,19 +1009,17 @@ namespace OpenRCT2::Ui::Windows newDisabledWidgets &= ~(1uLL << WIDX_CHAIN_LIFT); } - // Set and invalidate the changed widgets - uint64_t currentDisabledWidgets = disabledWidgets; - if (currentDisabledWidgets == newDisabledWidgets) - return; - - for (WidgetIndex i = 0; i < 64; i++) + // Invalidate only widgets whose disabled state changes. + const auto widgetCount = static_cast(widgets.size()); + for (WidgetIndex i = 0; i < widgetCount && i < 64; i++) { - if ((newDisabledWidgets & (1uLL << i)) != (currentDisabledWidgets & (1uLL << i))) + const bool shouldBeDisabled = (newDisabledWidgets & (1uLL << i)) != 0; + if (isWidgetDisabled(i) != shouldBeDisabled) { + setWidgetDisabled(i, shouldBeDisabled); invalidateWidget(i); } } - disabledWidgets = newDisabledWidgets; } void onUpdate() override @@ -1647,14 +1645,7 @@ namespace OpenRCT2::Ui::Windows if (currentRide->supportsStatus(RideStatus::simulating)) { simulateWidget.type = WidgetType::flatBtn; - if (currentRide->status == RideStatus::simulating) - { - pressedWidgets |= (1uLL << WIDX_SIMULATE); - } - else - { - pressedWidgets &= ~(1uLL << WIDX_SIMULATE); - } + setWidgetPressed(WIDX_SIMULATE, currentRide->status == RideStatus::simulating); } _windowTitle = FormatStringID(STR_RIDE_CONSTRUCTION_WINDOW_TITLE, currentRide->getName().c_str()); widgets[WIDX_TITLE].setString(_windowTitle.c_str()); @@ -1744,8 +1735,7 @@ namespace OpenRCT2::Ui::Windows const auto& rtd = GetRideTypeDescriptor(currentRide->type); auto trackDrawerDescriptor = getCurrentTrackDrawerDescriptor(rtd); - holdDownWidgets = (1u << WIDX_CONSTRUCT) | (1u << WIDX_DEMOLISH) | (1u << WIDX_NEXT_SECTION) - | (1u << WIDX_PREVIOUS_SECTION); + widgetsSetHoldable(*this, { WIDX_CONSTRUCT, WIDX_DEMOLISH, WIDX_NEXT_SECTION, WIDX_PREVIOUS_SECTION }); if (rtd.flags.has(RtdFlag::isShopOrFacility) || !currentRide->hasStation()) { widgets[WIDX_ENTRANCE_EXIT_GROUPBOX].type = WidgetType::empty; @@ -2041,7 +2031,7 @@ namespace OpenRCT2::Ui::Windows auto spinnerStart = 124 + widgets[WIDX_TITLE].bottom; resizeSpinner(WIDX_SPEED_SETTING_SPINNER, { 12, spinnerStart }, { 85, kSpinnerHeight }); - holdDownWidgets |= (1uLL << WIDX_SPEED_SETTING_SPINNER_UP) | (1uLL << WIDX_SPEED_SETTING_SPINNER_DOWN); + widgetsSetHoldable(*this, { WIDX_SPEED_SETTING_SPINNER_UP, WIDX_SPEED_SETTING_SPINNER_DOWN }); } static constexpr int16_t bankingGroupboxRightNoSeatRotation = kGroupWidth; @@ -2084,11 +2074,14 @@ namespace OpenRCT2::Ui::Windows } } - uint64_t newPressedWidgets = pressedWidgets - & ((1uLL << WIDX_BACKGROUND) | (1uLL << WIDX_TITLE) | (1uLL << WIDX_CLOSE) | (1uLL << WIDX_DIRECTION_GROUPBOX) - | (1uLL << WIDX_SLOPE_GROUPBOX) | (1uLL << WIDX_BANKING_GROUPBOX) | (1uLL << WIDX_CONSTRUCT) - | (1uLL << WIDX_DEMOLISH) | (1uLL << WIDX_PREVIOUS_SECTION) | (1uLL << WIDX_NEXT_SECTION) - | (1uLL << WIDX_ENTRANCE_EXIT_GROUPBOX) | (1uLL << WIDX_ENTRANCE) | (1uLL << WIDX_EXIT)); + uint64_t newPressedWidgets = 0; + for (auto preservedIndex : { WIDX_BACKGROUND, WIDX_TITLE, WIDX_CLOSE, WIDX_DIRECTION_GROUPBOX, WIDX_SLOPE_GROUPBOX, + WIDX_BANKING_GROUPBOX, WIDX_CONSTRUCT, WIDX_DEMOLISH, WIDX_PREVIOUS_SECTION, + WIDX_NEXT_SECTION, WIDX_ENTRANCE_EXIT_GROUPBOX, WIDX_ENTRANCE, WIDX_EXIT }) + { + if (isWidgetPressed(preservedIndex)) + newPressedWidgets |= (1uLL << preservedIndex); + } widgets[WIDX_CONSTRUCT].type = WidgetType::empty; widgets[WIDX_DEMOLISH].type = WidgetType::flatBtn; @@ -2127,7 +2120,7 @@ namespace OpenRCT2::Ui::Windows widgets[WIDX_PREVIOUS_SECTION].type = WidgetType::empty; break; default: - pressedWidgets = newPressedWidgets; + applyPressedBits(newPressedWidgets); invalidate(); return; } @@ -2226,10 +2219,17 @@ namespace OpenRCT2::Ui::Windows if (_currentTrackHasLiftHill) newPressedWidgets |= (1uLL << WIDX_CHAIN_LIFT); - pressedWidgets = newPressedWidgets; + applyPressedBits(newPressedWidgets); invalidate(); } + void applyPressedBits(uint64_t bits) + { + const auto widgetCount = static_cast(widgets.size()); + for (WidgetIndex i = 0; i < widgetCount && i < 64; i++) + setWidgetPressed(i, (bits & (1uLL << i)) != 0); + } + void updatePossibleRideConfigurations() { auto currentRide = GetRide(_currentRideIndex); diff --git a/src/openrct2-ui/windows/RideList.cpp b/src/openrct2-ui/windows/RideList.cpp index aae88b8d9f..8fb9cf17f3 100644 --- a/src/openrct2-ui/windows/RideList.cpp +++ b/src/openrct2-ui/windows/RideList.cpp @@ -506,16 +506,11 @@ namespace OpenRCT2::Ui::Windows ft.Add(STR_UP); // Set correct active tab - for (int32_t i = 0; i < 3; i++) - pressedWidgets &= ~(1 << (WIDX_TAB_1 + i)); - pressedWidgets |= 1LL << (WIDX_TAB_1 + page); + widgetSetPressedExclusive(*this, { WIDX_TAB_1, WIDX_TAB_2, WIDX_TAB_3 }, WIDX_TAB_1 + page); widgets[WIDX_TITLE].text = page_names[page]; - if (_quickDemolishMode) - pressedWidgets |= (1uLL << WIDX_QUICK_DEMOLISH); - else - pressedWidgets &= ~(1uLL << WIDX_QUICK_DEMOLISH); + setWidgetPressed(WIDX_QUICK_DEMOLISH, _quickDemolishMode); widgets[WIDX_LIST].right = width - 26; widgets[WIDX_LIST].bottom = height - 15; diff --git a/src/openrct2-ui/windows/ScenarioSelect.cpp b/src/openrct2-ui/windows/ScenarioSelect.cpp index 5c8eec7a71..f57459694c 100644 --- a/src/openrct2-ui/windows/ScenarioSelect.cpp +++ b/src/openrct2-ui/windows/ScenarioSelect.cpp @@ -149,6 +149,7 @@ namespace OpenRCT2::Ui::Windows _highlightedScenario = nullptr; initTabs(); + updatePressedTab(); initialiseListItems(); initScrollWidgets(); } @@ -179,6 +180,7 @@ namespace OpenRCT2::Ui::Windows _highlightedScenario = nullptr; _preview = {}; + updatePressedTab(); initialiseListItems(); invalidate(); onResize(); @@ -429,13 +431,6 @@ namespace OpenRCT2::Ui::Windows void onPrepareDraw() override { - pressedWidgets &= ~( - (1uLL << WIDX_CLOSE) | (1uLL << WIDX_TAB1) | (1uLL << WIDX_TAB2) | (1uLL << WIDX_TAB3) | (1uLL << WIDX_TAB4) - | (1uLL << WIDX_TAB5) | (1uLL << WIDX_TAB6) | (1uLL << WIDX_TAB7) | (1uLL << WIDX_TAB8) | (1uLL << WIDX_TAB9) - | (1uLL << WIDX_TAB10)); - - pressedWidgets |= 1LL << (selectedTab + WIDX_TAB1); - const int32_t bottomMargin = Config::Get().general.debuggingTools ? 17 : 5; widgets[WIDX_SCENARIOLIST].right = width - GetPreviewPaneWidth() - 2 * kPadding; widgets[WIDX_SCENARIOLIST].bottom = height - bottomMargin; @@ -637,6 +632,15 @@ namespace OpenRCT2::Ui::Windows } private: + void updatePressedTab() + { + widgetSetPressedExclusive( + *this, + { WIDX_TAB1, WIDX_TAB2, WIDX_TAB3, WIDX_TAB4, WIDX_TAB5, WIDX_TAB6, WIDX_TAB7, WIDX_TAB8, WIDX_TAB9, + WIDX_TAB10 }, + selectedTab + WIDX_TAB1); + } + void DrawCategoryHeading(RenderTarget& rt, int32_t left, int32_t right, int32_t y, StringId stringId) const { auto baseColour = colours[1]; diff --git a/src/openrct2-ui/windows/Scenery.cpp b/src/openrct2-ui/windows/Scenery.cpp index b7ba7cefa1..3ceda67f12 100644 --- a/src/openrct2-ui/windows/Scenery.cpp +++ b/src/openrct2-ui/windows/Scenery.cpp @@ -271,11 +271,18 @@ namespace OpenRCT2::Ui::Windows { _activeTabIndex = 0; } + updatePressedTab(); WindowMovePosition(*this, { ContextGetWidth() - GetRequiredWidth(), 0x1D }); WindowPushOthersBelow(*this); } + void updatePressedTab() + { + for (size_t i = 0; i < _tabEntries.size(); i++) + widgetSetPressed(*this, static_cast(WIDX_SCENERY_TAB_1 + i), i == _activeTabIndex); + } + void onClose() override { SceneryRemoveGhostToolPlacement(); @@ -423,6 +430,7 @@ namespace OpenRCT2::Ui::Windows if (widgetIndex >= WIDX_SCENERY_TAB_1) { _activeTabIndex = widgetIndex - WIDX_SCENERY_TAB_1; + updatePressedTab(); invalidate(); gSceneryPlaceCost = kMoney64Undefined; @@ -711,14 +719,9 @@ namespace OpenRCT2::Ui::Windows widgets[WIDX_SCENERY_TITLE].text = titleStringId; widgets[WIDX_FILTER_TEXT_BOX].string = _filteredSceneryTab.Filter.data(); - pressedWidgets = 0; - pressedWidgets |= 1uLL << (tabIndex + WIDX_SCENERY_TAB_1); - if (_sceneryPaintEnabled) - pressedWidgets |= (1uLL << WIDX_SCENERY_REPAINT_SCENERY_BUTTON); - if (gWindowSceneryEyedropperEnabled) - pressedWidgets |= (1uLL << WIDX_SCENERY_EYEDROPPER_BUTTON); - if (gWindowSceneryScatterEnabled) - pressedWidgets |= (1uLL << WIDX_SCENERY_BUILD_CLUSTER_BUTTON); + setWidgetPressed(WIDX_SCENERY_REPAINT_SCENERY_BUTTON, _sceneryPaintEnabled); + setWidgetPressed(WIDX_SCENERY_EYEDROPPER_BUTTON, gWindowSceneryEyedropperEnabled); + setWidgetPressed(WIDX_SCENERY_BUILD_CLUSTER_BUTTON, gWindowSceneryScatterEnabled); widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WidgetType::empty; widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].type = WidgetType::empty; @@ -745,10 +748,7 @@ namespace OpenRCT2::Ui::Windows if (gLegacyScene == LegacyScene::scenarioEditor || getGameState().cheats.sandboxMode) { widgets[WIDX_RESTRICT_SCENERY].type = WidgetType::button; - if (IsSceneryItemRestricted(tabSelectedScenery)) - pressedWidgets |= (1uLL << WIDX_RESTRICT_SCENERY); - else - pressedWidgets &= ~(1uLL << WIDX_RESTRICT_SCENERY); + setWidgetPressed(WIDX_RESTRICT_SCENERY, IsSceneryItemRestricted(tabSelectedScenery)); } } @@ -956,6 +956,7 @@ namespace OpenRCT2::Ui::Windows } _activeTabIndex = tabIndex.value(); + updatePressedTab(); SetSelectedScenery(tabIndex.value(), scenery); if (primary.has_value()) { @@ -1089,6 +1090,7 @@ namespace OpenRCT2::Ui::Windows _requiredWidth = std::min(static_cast(_tabEntries.size()), kMaxTabsPerRow) * kTabWidth + 5; PrepareWidgets(); + updatePressedTab(); auto* windowMgr = GetWindowManager(); windowMgr->InvalidateByClass(WindowClass::scenery); diff --git a/src/openrct2-ui/windows/SceneryScatter.cpp b/src/openrct2-ui/windows/SceneryScatter.cpp index 5070db9c1d..29f82f3006 100644 --- a/src/openrct2-ui/windows/SceneryScatter.cpp +++ b/src/openrct2-ui/windows/SceneryScatter.cpp @@ -62,8 +62,9 @@ namespace OpenRCT2::Ui::Windows void onOpen() override { setWidgets(_sceneryScatterWidgets); + setWidgetPressed(WIDX_PREVIEW, true); - holdDownWidgets = (1uLL << WIDX_INCREMENT) | (1uLL << WIDX_DECREMENT); + widgetsSetHoldable(*this, { WIDX_INCREMENT, WIDX_DECREMENT }); WindowInitScrollWidgets(*this); WindowPushOthersBelow(*this); @@ -160,24 +161,21 @@ namespace OpenRCT2::Ui::Windows void onPrepareDraw() override { - // Set the preview image button to be pressed down - pressedWidgets = (1uLL << WIDX_PREVIEW); - // Set density buttons' pressed state. + WidgetIndex pressedDensity = WIDX_DENSITY_HIGH; switch (gWindowSceneryScatterDensity) { case ScatterToolDensity::LowDensity: - pressedWidgets |= (1uLL << WIDX_DENSITY_LOW); + pressedDensity = WIDX_DENSITY_LOW; break; - case ScatterToolDensity::MediumDensity: - pressedWidgets |= (1uLL << WIDX_DENSITY_MEDIUM); + pressedDensity = WIDX_DENSITY_MEDIUM; break; - case ScatterToolDensity::HighDensity: - pressedWidgets |= (1uLL << WIDX_DENSITY_HIGH); + pressedDensity = WIDX_DENSITY_HIGH; break; } + widgetSetPressedExclusive(*this, { WIDX_DENSITY_LOW, WIDX_DENSITY_MEDIUM, WIDX_DENSITY_HIGH }, pressedDensity); // Update the preview image (for tool sizes up to 7) widgets[WIDX_PREVIEW].image = ImageId(LandTool::SizeToSpriteIndex(gWindowSceneryScatterSize)); diff --git a/src/openrct2-ui/windows/Staff.cpp b/src/openrct2-ui/windows/Staff.cpp index 04bb608f54..b187d89776 100644 --- a/src/openrct2-ui/windows/Staff.cpp +++ b/src/openrct2-ui/windows/Staff.cpp @@ -349,7 +349,6 @@ namespace OpenRCT2::Ui::Windows { ColourSchemeUpdateByClass(this, static_cast(WindowClass::staff)); - SetPressedTab(); DisableWidgets(); auto staff = GetStaff(); @@ -1073,9 +1072,8 @@ namespace OpenRCT2::Ui::Windows page = newPage; currentFrame = 0; - pressedWidgets = 0; - holdDownWidgets = 0; setWidgets(window_staff_page_widgets[page]); + SetPressedTab(); removeViewport(); diff --git a/src/openrct2-ui/windows/Themes.cpp b/src/openrct2-ui/windows/Themes.cpp index 4534428be5..11bf9437dc 100644 --- a/src/openrct2-ui/windows/Themes.cpp +++ b/src/openrct2-ui/windows/Themes.cpp @@ -275,12 +275,23 @@ namespace OpenRCT2::Ui::Windows WindowThemesInitVars(); WindowInitScrollWidgets(*this); WindowSetResize(*this, kWindowSize, kWindowSize); + updatePressedTab(); listInformationType = 0; _classIndex = -1; _buttonIndex = -1; } + void updatePressedTab() + { + widgetSetPressedExclusive( + *this, + { WIDX_THEMES_SETTINGS_TAB, WIDX_THEMES_MAIN_UI_TAB, WIDX_THEMES_PARK_TAB, WIDX_THEMES_TOOLS_TAB, + WIDX_THEMES_RIDE_PEEPS_TAB, WIDX_THEMES_EDITORS_TAB, WIDX_THEMES_MISC_TAB, WIDX_THEMES_PROMPTS_TAB, + WIDX_THEMES_FEATURES_TAB }, + _selectedTab + WIDX_THEMES_SETTINGS_TAB); + } + void onResize() override { if (_selectedTab == WINDOW_THEMES_TAB_SETTINGS) @@ -310,14 +321,6 @@ namespace OpenRCT2::Ui::Windows void onPrepareDraw() override { - int32_t newPressedWidgets = pressedWidgets - & ~((1LL << WIDX_THEMES_SETTINGS_TAB) | (1LL << WIDX_THEMES_MAIN_UI_TAB) | (1LL << WIDX_THEMES_PARK_TAB) - | (1LL << WIDX_THEMES_TOOLS_TAB) | (1LL << WIDX_THEMES_RIDE_PEEPS_TAB) | (1LL << WIDX_THEMES_EDITORS_TAB) - | (1LL << WIDX_THEMES_MISC_TAB) | (1LL << WIDX_THEMES_PROMPTS_TAB) | (1LL << WIDX_THEMES_FEATURES_TAB)); - WidgetIndex widgetIndex = _selectedTab + WIDX_THEMES_SETTINGS_TAB; - - pressedWidgets = newPressedWidgets | (1 << widgetIndex); - auto* windowMgr = GetWindowManager(); if (windowMgr->FindByClass(WindowClass::dropdown) == nullptr) { @@ -438,6 +441,7 @@ namespace OpenRCT2::Ui::Windows _selectedTab = static_cast(newSelectedTab); scrolls[0].contentOffsetY = 0; currentFrame = 0; + updatePressedTab(); onResize(); invalidate(); break; diff --git a/src/openrct2-ui/windows/TileInspector.cpp b/src/openrct2-ui/windows/TileInspector.cpp index 54fd985d53..2ea53b250d 100644 --- a/src/openrct2-ui/windows/TileInspector.cpp +++ b/src/openrct2-ui/windows/TileInspector.cpp @@ -283,10 +283,10 @@ namespace OpenRCT2::Ui::Windows makeWindowShim(kWindowTitle, kWindowSize), makeWidget({3, 57}, {kWindowSize.width - 6, kWindowSize.height - kBottomPadding - 58}, WidgetType::scroll, WindowColour::secondary, SCROLL_VERTICAL), /* Element list */ /* X and Y spinners */ - makeWidget ({ 4, 24}, {38, 12}, WidgetType::label, WindowColour::secondary, STR_TILE_INSPECTOR_X_LABEL), - makeSpinnerWidgets({20, 23}, {51, 14}, WidgetType::spinner, WindowColour::secondary), /* Spinner X (3 widgets) */ - makeWidget ({74, 24}, {38, 12}, WidgetType::label, WindowColour::secondary, STR_TILE_INSPECTOR_Y_LABEL), - makeSpinnerWidgets({90, 23}, {51, 14}, WidgetType::spinner, WindowColour::secondary), /* Spinner Y (3 widgets) */ + makeWidget ({ 4, 24}, {38, 12}, WidgetType::label, WindowColour::secondary, STR_TILE_INSPECTOR_X_LABEL), + makeHoldableSpinnerWidgets({20, 23}, {51, 14}, WidgetType::spinner, WindowColour::secondary), /* Spinner X (3 widgets) */ + makeWidget ({74, 24}, {38, 12}, WidgetType::label, WindowColour::secondary, STR_TILE_INSPECTOR_Y_LABEL), + makeHoldableSpinnerWidgets({90, 23}, {51, 14}, WidgetType::spinner, WindowColour::secondary), /* Spinner Y (3 widgets) */ /* Top buttons */ makeWidget(kToolbarButtonAnchor + kToolbarButtonOffsetX * 0, kToolbarButtonSize, WidgetType::flatBtn, WindowColour::secondary, ImageId(SPR_DEMOLISH), STR_REMOVE_SELECTED_ELEMENT_TIP ), /* Remove button */ makeWidget(kToolbarButtonAnchor + kToolbarButtonOffsetX * 1, kToolbarButtonHalfSize, WidgetType::button, WindowColour::secondary, STR_UP, STR_MOVE_SELECTED_ELEMENT_UP_TIP), /* Move up */ @@ -318,7 +318,7 @@ namespace OpenRCT2::Ui::Windows constexpr int32_t kSurfaceDetailsHeight = 20 + kNumSurfaceDetails * 11; static constexpr auto kSurfaceWidgets = makeWidgets( kMainTileInspectorWidgets, - makeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), kPropertySpinnerSize, WidgetType::spinner, WindowColour::secondary), // WIDX_SURFACE_SPINNER_HEIGHT{,_INCREASE,_DECREASE} + makeHoldableSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), kPropertySpinnerSize, WidgetType::spinner, WindowColour::secondary), // WIDX_SURFACE_SPINNER_HEIGHT{,_INCREASE,_DECREASE} makeWidget(PropertyRowCol({ 12, 0 }, 1, 0), kPropertyButtonSize, WidgetType::button, WindowColour::secondary, STR_TILE_INSPECTOR_SURFACE_REMOVE_FENCES), // WIDX_SURFACE_BUTTON_REMOVE_FENCES makeWidget(PropertyRowCol({ 12, 0 }, 1, 1), kPropertyButtonSize, WidgetType::button, WindowColour::secondary, STR_TILE_INSPECTOR_SURFACE_RESTORE_FENCES), // WIDX_SURFACE_BUTTON_RESTORE_FENCES makeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 2, 1), 1, 0), { 12, 12 }, WidgetType::checkbox, WindowColour::secondary), // WIDX_SURFACE_CHECK_CORNER_N @@ -334,7 +334,7 @@ namespace OpenRCT2::Ui::Windows constexpr int32_t kPathDetailsHeight = 20 + kNumPathDetails * 11; static constexpr auto kPathWidgets = makeWidgets( kMainTileInspectorWidgets, - makeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), kPropertySpinnerSize, WidgetType::spinner, WindowColour::secondary), // WIDX_PATH_SPINNER_HEIGHT{,_INCREASE,_DECREASE} + makeHoldableSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), kPropertySpinnerSize, WidgetType::spinner, WindowColour::secondary), // WIDX_PATH_SPINNER_HEIGHT{,_INCREASE,_DECREASE} makeWidget(PropertyRowCol({ 12, 0 }, 1, 0), kPropertyFullWidth, WidgetType::checkbox, WindowColour::secondary, STR_TILE_INSPECTOR_PATH_BROKEN), // WIDX_PATH_CHECK_BROKEN makeWidget(PropertyRowCol({ 12, 0 }, 2, 0), kPropertyFullWidth, WidgetType::checkbox, WindowColour::secondary, STR_TILE_INSPECTOR_PATH_SLOPED), // WIDX_PATH_CHECK_SLOPED makeWidget(PropertyRowCol({ 12, 0 }, 3, 0), kPropertyFullWidth, WidgetType::checkbox, WindowColour::secondary, STR_TILE_INSPECTOR_PATH_JUNCTION_RAILINGS), // WIDX_PATH_CHECK_JUNCTION_RAILINGS @@ -355,7 +355,7 @@ namespace OpenRCT2::Ui::Windows static constexpr auto kTrackWidgets = makeWidgets( kMainTileInspectorWidgets, makeWidget(PropertyRowCol({ 12, 0}, 0, 0), kPropertyFullWidth, WidgetType::checkbox, WindowColour::secondary, STR_TILE_INSPECTOR_TRACK_ENTIRE_TRACK_PIECE), // WIDX_TRACK_CHECK_APPLY_TO_ALL - makeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 1, 1), kPropertySpinnerSize, WidgetType::spinner, WindowColour::secondary), // WIDX_TRACK_SPINNER_HEIGHT{,_INCREASE,_DECREASE} + makeHoldableSpinnerWidgets(PropertyRowCol({ 12, 0 }, 1, 1), kPropertySpinnerSize, WidgetType::spinner, WindowColour::secondary), // WIDX_TRACK_SPINNER_HEIGHT{,_INCREASE,_DECREASE} makeWidget(PropertyRowCol({ 12, 0}, 2, 0), kPropertyFullWidth, WidgetType::checkbox, WindowColour::secondary, STR_TILE_INSPECTOR_TRACK_CHAIN_LIFT), // WIDX_TRACK_CHECK_CHAIN_LIFT makeWidget(PropertyRowCol({ 12, 0}, 3, 0), kPropertyFullWidth, WidgetType::checkbox, WindowColour::secondary, STR_TILE_INSPECTOR_TRACK_BRAKE_CLOSED), // WIDX_TRACK_CHECK_BRAKE_CLOSED makeWidget(PropertyRowCol({ 12, 0}, 4, 0), kPropertyFullWidth, WidgetType::checkbox, WindowColour::secondary, STR_TILE_INSPECTOR_TRACK_IS_INDESTRUCTIBLE) // WIDX_TRACK_CHECK_IS_INDESTRUCTIBLE @@ -367,7 +367,7 @@ namespace OpenRCT2::Ui::Windows constexpr int32_t kSceneryDetailsHeight = 20 + kNumSceneryDetails * 11; static constexpr auto kSceneryWidgets = makeWidgets( kMainTileInspectorWidgets, - makeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), kPropertySpinnerSize, WidgetType::spinner, WindowColour::secondary), // WIDX_SCENERY_SPINNER_HEIGHT{,_INCREASE,_DECREASE} + makeHoldableSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), kPropertySpinnerSize, WidgetType::spinner, WindowColour::secondary), // WIDX_SCENERY_SPINNER_HEIGHT{,_INCREASE,_DECREASE} makeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 1, 1), 1, 0 + 0), { 12, 12 }, WidgetType::checkbox, WindowColour::secondary), // WIDX_SCENERY_CHECK_QUARTER_N makeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 1, 1), 2, 0 + 1), { 12, 12 }, WidgetType::checkbox, WindowColour::secondary), // WIDX_SCENERY_CHECK_QUARTER_E makeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 1, 1), 1, 0 + 2), { 12, 12 }, WidgetType::checkbox, WindowColour::secondary), // WIDX_SCENERY_CHECK_QUARTER_S @@ -384,7 +384,7 @@ namespace OpenRCT2::Ui::Windows constexpr int32_t kEntranceDetailsHeight = 20 + kNumEntranceDetails * 11; static constexpr auto kEntranceWidgets = makeWidgets( kMainTileInspectorWidgets, - makeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), kPropertySpinnerSize, WidgetType::spinner, WindowColour::secondary), // WIDX_ENTRANCE_SPINNER_HEIGHT{,_INCREASE,_DECREASE} + makeHoldableSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), kPropertySpinnerSize, WidgetType::spinner, WindowColour::secondary), // WIDX_ENTRANCE_SPINNER_HEIGHT{,_INCREASE,_DECREASE} makeWidget(PropertyRowCol({ 12, 0 }, 1, 0), kPropertyButtonSize, WidgetType::button, WindowColour::secondary, STR_TILE_INSPECTOR_ENTRANCE_MAKE_USABLE, STR_TILE_INSPECTOR_ENTRANCE_MAKE_USABLE_TIP) // WIDX_ENTRANCE_BUTTON_MAKE_USABLE ); @@ -394,10 +394,10 @@ namespace OpenRCT2::Ui::Windows constexpr int32_t kWallDetailsHeight = 20 + kNumWallDetails * 11; static constexpr auto kWallWidgets = makeWidgets( kMainTileInspectorWidgets, - makeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), kPropertySpinnerSize, WidgetType::spinner, WindowColour::secondary), // WIDX_WALL_SPINNER_HEIGHT{,_INCREASE,_DECREASE} + makeHoldableSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), kPropertySpinnerSize, WidgetType::spinner, WindowColour::secondary), // WIDX_WALL_SPINNER_HEIGHT{,_INCREASE,_DECREASE} makeWidget(PropertyRowCol({ 12, 0 }, 1, 1), kPropertyButtonSize, WidgetType::dropdownMenu, WindowColour::secondary), // WIDX_WALL_DROPDOWN_SLOPE makeWidget(PropertyRowCol({ 12 + kPropertyButtonSize.width - 12, 0 }, 1, 1), { 11, 12}, WidgetType::button, WindowColour::secondary, STR_DROPDOWN_GLYPH), // WIDX_WALL_DROPDOWN_SLOPE_BUTTON - makeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 2, 1), kPropertySpinnerSize, WidgetType::spinner, WindowColour::secondary), // WIDX_WALL_SPINNER_ANIMATION_FRAME{,_INCREASE,_DECREASE} + makeHoldableSpinnerWidgets(PropertyRowCol({ 12, 0 }, 2, 1), kPropertySpinnerSize, WidgetType::spinner, WindowColour::secondary), // WIDX_WALL_SPINNER_ANIMATION_FRAME{,_INCREASE,_DECREASE} makeWidget(PropertyRowCol({ 12, 0 }, 3, 0), kPropertyFullWidth, WidgetType::checkbox, WindowColour::secondary, STR_TILE_INSPECTOR_WALL_ANIMATION_IS_BACKWARDS) // WIDX_WALL_ANIMATION_IS_BACKWARDS ); @@ -407,7 +407,7 @@ namespace OpenRCT2::Ui::Windows constexpr int32_t kLargeSceneryDetailsHeight = 20 + kNumLargeSceneryDetails * 11; static constexpr auto kLargeSceneryWidgets = makeWidgets( kMainTileInspectorWidgets, - makeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), kPropertySpinnerSize, WidgetType::spinner, WindowColour::secondary) // WIDX_LARGE_SCENERY_SPINNER_HEIGHT{,_INCREASE,_DECREASE} + makeHoldableSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), kPropertySpinnerSize, WidgetType::spinner, WindowColour::secondary) // WIDX_LARGE_SCENERY_SPINNER_HEIGHT{,_INCREASE,_DECREASE} ); constexpr int32_t kNumBannerProperties = 3; @@ -416,7 +416,7 @@ namespace OpenRCT2::Ui::Windows constexpr int32_t kBannerDetailsHeight = 20 + kNumBannerDetails * 11; static constexpr auto kBannerWidgets = makeWidgets( kMainTileInspectorWidgets, - makeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), kPropertySpinnerSize, WidgetType::spinner, WindowColour::secondary), // WIDX_BANNER_SPINNER_HEIGHT{,_INCREASE,_DECREASE} + makeHoldableSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), kPropertySpinnerSize, WidgetType::spinner, WindowColour::secondary), // WIDX_BANNER_SPINNER_HEIGHT{,_INCREASE,_DECREASE} makeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 1, 1), 3, 1), { 12, 12 }, WidgetType::checkbox, WindowColour::secondary), // WIDX_BANNER_CHECK_BLOCK_NE makeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 1, 1), 3, 3), { 12, 12 }, WidgetType::checkbox, WindowColour::secondary), // WIDX_BANNER_CHECK_BLOCK_SE makeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 1, 1), 1, 3), { 12, 12 }, WidgetType::checkbox, WindowColour::secondary), // WIDX_BANNER_CHECK_BLOCK_SW @@ -475,28 +475,16 @@ namespace OpenRCT2::Ui::Windows ViewportInteractionItem::wall, ViewportInteractionItem::largeScenery, ViewportInteractionItem::banner); // clang-format off - static uint64_t kHoldableWidgetsByPage[] = { - (1uLL << WIDX_SPINNER_X_INCREASE) | (1uLL << WIDX_SPINNER_X_DECREASE) | (1uLL << WIDX_SPINNER_Y_INCREASE) | (1uLL << WIDX_SPINNER_Y_DECREASE), - (1uLL << WIDX_SPINNER_X_INCREASE) | (1uLL << WIDX_SPINNER_X_DECREASE) | (1uLL << WIDX_SPINNER_Y_INCREASE) | (1uLL << WIDX_SPINNER_Y_DECREASE) | (1uLL << WIDX_SURFACE_SPINNER_HEIGHT_INCREASE) | (1uLL << WIDX_SURFACE_SPINNER_HEIGHT_DECREASE), - (1uLL << WIDX_SPINNER_X_INCREASE) | (1uLL << WIDX_SPINNER_X_DECREASE) | (1uLL << WIDX_SPINNER_Y_INCREASE) | (1uLL << WIDX_SPINNER_Y_DECREASE) | (1uLL << WIDX_PATH_SPINNER_HEIGHT_INCREASE) | (1uLL << WIDX_PATH_SPINNER_HEIGHT_DECREASE), - (1uLL << WIDX_SPINNER_X_INCREASE) | (1uLL << WIDX_SPINNER_X_DECREASE) | (1uLL << WIDX_SPINNER_Y_INCREASE) | (1uLL << WIDX_SPINNER_Y_DECREASE) | (1uLL << WIDX_TRACK_SPINNER_HEIGHT_INCREASE) | (1uLL << WIDX_TRACK_SPINNER_HEIGHT_DECREASE), - (1uLL << WIDX_SPINNER_X_INCREASE) | (1uLL << WIDX_SPINNER_X_DECREASE) | (1uLL << WIDX_SPINNER_Y_INCREASE) | (1uLL << WIDX_SPINNER_Y_DECREASE) | (1uLL << WIDX_SCENERY_SPINNER_HEIGHT_INCREASE) | (1uLL << WIDX_SCENERY_SPINNER_HEIGHT_DECREASE), - (1uLL << WIDX_SPINNER_X_INCREASE) | (1uLL << WIDX_SPINNER_X_DECREASE) | (1uLL << WIDX_SPINNER_Y_INCREASE) | (1uLL << WIDX_SPINNER_Y_DECREASE) | (1uLL << WIDX_ENTRANCE_SPINNER_HEIGHT_INCREASE) | (1uLL << WIDX_ENTRANCE_SPINNER_HEIGHT_DECREASE), - (1uLL << WIDX_SPINNER_X_INCREASE) | (1uLL << WIDX_SPINNER_X_DECREASE) | (1uLL << WIDX_SPINNER_Y_INCREASE) | (1uLL << WIDX_SPINNER_Y_DECREASE) | (1uLL << WIDX_WALL_SPINNER_HEIGHT_INCREASE) | (1uLL << WIDX_WALL_SPINNER_HEIGHT_DECREASE) | (1uLL << WIDX_WALL_SPINNER_ANIMATION_FRAME_INCREASE) | (1uLL << WIDX_WALL_SPINNER_ANIMATION_FRAME_DECREASE), - (1uLL << WIDX_SPINNER_X_INCREASE) | (1uLL << WIDX_SPINNER_X_DECREASE) | (1uLL << WIDX_SPINNER_Y_INCREASE) | (1uLL << WIDX_SPINNER_Y_DECREASE) | (1uLL << WIDX_LARGE_SCENERY_SPINNER_HEIGHT_INCREASE) | (1uLL << WIDX_LARGE_SCENERY_SPINNER_HEIGHT_DECREASE), - (1uLL << WIDX_SPINNER_X_INCREASE) | (1uLL << WIDX_SPINNER_X_DECREASE) | (1uLL << WIDX_SPINNER_Y_INCREASE) | (1uLL << WIDX_SPINNER_Y_DECREASE) | (1uLL << WIDX_BANNER_SPINNER_HEIGHT_INCREASE) | (1uLL << WIDX_BANNER_SPINNER_HEIGHT_DECREASE), - }; - - static uint64_t kDisabledWidgetsByPage[] = { - (1uLL << WIDX_BUTTON_MOVE_UP) | (1uLL << WIDX_BUTTON_MOVE_DOWN) | (1uLL << WIDX_BUTTON_REMOVE) | (1uLL << WIDX_BUTTON_ROTATE) | (1uLL << WIDX_BUTTON_COPY), - 0, - 0, - 0, - 0, - 0, - 0, - (1uLL << WIDX_BUTTON_ROTATE), - 0, + static constexpr std::initializer_list kDisabledWidgetsByPage[] = { + { WIDX_BUTTON_MOVE_UP, WIDX_BUTTON_MOVE_DOWN, WIDX_BUTTON_REMOVE, WIDX_BUTTON_ROTATE, WIDX_BUTTON_COPY }, + {}, + {}, + {}, + {}, + {}, + {}, + { WIDX_BUTTON_ROTATE }, + {}, }; // clang-format on @@ -1799,9 +1787,8 @@ namespace OpenRCT2::Ui::Windows tileInspectorPage = p; auto pageIndex = EnumValue(p); setWidgets(kWidgetsByPage[pageIndex]); - holdDownWidgets = kHoldableWidgetsByPage[pageIndex]; - disabledWidgets = kDisabledWidgetsByPage[pageIndex]; - pressedWidgets = 0; + for (auto widgetIndex : kDisabledWidgetsByPage[pageIndex]) + setWidgetDisabled(widgetIndex, true); invalidate(); } diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp index 0b67cadee1..e972c67ef2 100644 --- a/src/openrct2-ui/windows/TopToolbar.cpp +++ b/src/openrct2-ui/windows/TopToolbar.cpp @@ -1224,31 +1224,16 @@ namespace OpenRCT2::Ui::Windows return; } - if (mainWindow->viewport->zoom == ZoomLevel::min()) - { - disabledWidgets |= (1uLL << WIDX_ZOOM_IN); - } - else if (mainWindow->viewport->zoom >= ZoomLevel::max()) - { - disabledWidgets |= (1uLL << WIDX_ZOOM_OUT); - } - else - { - disabledWidgets &= ~((1uLL << WIDX_ZOOM_IN) | (1uLL << WIDX_ZOOM_OUT)); - } + setWidgetDisabled(WIDX_ZOOM_IN, mainWindow->viewport->zoom == ZoomLevel::min()); + setWidgetDisabled(WIDX_ZOOM_OUT, mainWindow->viewport->zoom >= ZoomLevel::max()); } void ApplyPausedState() { bool paused = (gGamePaused & GAME_PAUSED_NORMAL); - if (paused || _waitingForPause) - { - pressedWidgets |= (1uLL << WIDX_PAUSE); - if (paused) - _waitingForPause = false; - } - else - pressedWidgets &= ~(1uLL << WIDX_PAUSE); + if (paused) + _waitingForPause = false; + setWidgetPressed(WIDX_PAUSE, paused || _waitingForPause); } void ApplyMapRotation() @@ -1280,10 +1265,7 @@ namespace OpenRCT2::Ui::Windows { // Footpath button pressed down auto* windowMgr = GetWindowManager(); - if (windowMgr->FindByClass(WindowClass::footpath) == nullptr) - pressedWidgets &= ~(1uLL << WIDX_PATH); - else - pressedWidgets |= (1uLL << WIDX_PATH); + setWidgetPressed(WIDX_PATH, windowMgr->FindByClass(WindowClass::footpath) != nullptr); } // TODO: look into using std::span diff --git a/src/openrct2-ui/windows/TrackList.cpp b/src/openrct2-ui/windows/TrackList.cpp index e1267a7349..8d1f725c45 100644 --- a/src/openrct2-ui/windows/TrackList.cpp +++ b/src/openrct2-ui/windows/TrackList.cpp @@ -407,25 +407,17 @@ namespace OpenRCT2::Ui::Windows _windowTitle = FormatStringID(titleFormat, stringId); widgets[WIDX_TITLE].setString(_windowTitle.c_str()); - if ((gLegacyScene == LegacyScene::trackDesignsManager) || selectedListItem != 0) + const bool showPreview = (gLegacyScene == LegacyScene::trackDesignsManager) || selectedListItem != 0; + setWidgetPressed(WIDX_TRACK_PREVIEW, showPreview); + setWidgetDisabled(WIDX_TRACK_PREVIEW, !showPreview); + if (showPreview) { - pressedWidgets |= 1uLL << WIDX_TRACK_PREVIEW; - disabledWidgets &= ~(1uLL << WIDX_TRACK_PREVIEW); widgets[WIDX_ROTATE].type = WidgetType::flatBtn; widgets[WIDX_TOGGLE_SCENERY].type = WidgetType::flatBtn; - if (gTrackDesignSceneryToggle) - { - pressedWidgets &= ~(1uLL << WIDX_TOGGLE_SCENERY); - } - else - { - pressedWidgets |= (1uLL << WIDX_TOGGLE_SCENERY); - } + setWidgetPressed(WIDX_TOGGLE_SCENERY, !gTrackDesignSceneryToggle); } else { - pressedWidgets &= ~(1uLL << WIDX_TRACK_PREVIEW); - disabledWidgets |= (1uLL << WIDX_TRACK_PREVIEW); widgets[WIDX_ROTATE].type = WidgetType::empty; widgets[WIDX_TOGGLE_SCENERY].type = WidgetType::empty; } diff --git a/src/openrct2-ui/windows/Transparency.cpp b/src/openrct2-ui/windows/Transparency.cpp index af27647988..99788735e1 100644 --- a/src/openrct2-ui/windows/Transparency.cpp +++ b/src/openrct2-ui/windows/Transparency.cpp @@ -115,9 +115,6 @@ namespace OpenRCT2::Ui::Windows uint32_t wflags = 0; WindowBase* w = WindowGetMain(); - pressedWidgets = 0; - disabledWidgets = 0; - if (w != nullptr) wflags = w->viewport->flags; diff --git a/src/openrct2-ui/windows/ViewClipping.cpp b/src/openrct2-ui/windows/ViewClipping.cpp index 7a1df8aacd..99eb52da29 100644 --- a/src/openrct2-ui/windows/ViewClipping.cpp +++ b/src/openrct2-ui/windows/ViewClipping.cpp @@ -279,14 +279,7 @@ namespace OpenRCT2::Ui::Windows WIDX_CLIP_SEE_THROUGH_CHECKBOX_ENABLE, mainWindow->viewport->flags & VIEWPORT_FLAG_CLIP_VIEW_SEE_THROUGH); } - if (IsActive()) - { - this->pressedWidgets |= 1uLL << WIDX_CLIP_SELECTOR; - } - else - { - this->pressedWidgets &= ~(1uLL << WIDX_CLIP_SELECTOR); - } + setWidgetPressed(WIDX_CLIP_SELECTOR, IsActive()); } void onDraw(Drawing::RenderTarget& rt) override @@ -362,7 +355,7 @@ namespace OpenRCT2::Ui::Windows { setWidgets(_viewClippingWidgets); - this->holdDownWidgets = (1uLL << WIDX_CLIP_HEIGHT_INCREASE) | (1uL << WIDX_CLIP_HEIGHT_DECREASE); + widgetsSetHoldable(*this, { WIDX_CLIP_HEIGHT_INCREASE, WIDX_CLIP_HEIGHT_DECREASE }); WindowInitScrollWidgets(*this); _clipHeightDisplayType = DisplayType::DisplayUnits; diff --git a/src/openrct2-ui/windows/Viewport.cpp b/src/openrct2-ui/windows/Viewport.cpp index acb40352f6..70edb8a93e 100644 --- a/src/openrct2-ui/windows/Viewport.cpp +++ b/src/openrct2-ui/windows/Viewport.cpp @@ -192,11 +192,8 @@ namespace OpenRCT2::Ui::Windows widgets[WIDX_TITLE].setString(_windowTitle.c_str()); // Set disabled widgets - disabledWidgets = 0; - if (viewport != nullptr && viewport->zoom == ZoomLevel::min()) - disabledWidgets |= 1uLL << WIDX_ZOOM_IN; - if (viewport != nullptr && viewport->zoom >= ZoomLevel::max()) - disabledWidgets |= 1uLL << WIDX_ZOOM_OUT; + setWidgetDisabled(WIDX_ZOOM_IN, viewport != nullptr && viewport->zoom == ZoomLevel::min()); + setWidgetDisabled(WIDX_ZOOM_OUT, viewport != nullptr && viewport->zoom >= ZoomLevel::max()); if (viewport != nullptr) { diff --git a/src/openrct2-ui/windows/Water.cpp b/src/openrct2-ui/windows/Water.cpp index d374000515..38dc715935 100644 --- a/src/openrct2-ui/windows/Water.cpp +++ b/src/openrct2-ui/windows/Water.cpp @@ -61,7 +61,7 @@ namespace OpenRCT2::Ui::Windows { setWidgets(_waterWidgets); - holdDownWidgets = (1uLL << WIDX_INCREMENT) | (1uLL << WIDX_DECREMENT); + widgetsSetHoldable(*this, { WIDX_INCREMENT, WIDX_DECREMENT }); WindowInitScrollWidgets(*this); WindowPushOthersBelow(*this); diff --git a/src/openrct2/interface/WindowBase.h b/src/openrct2/interface/WindowBase.h index 7b66281dc3..ce1a57272e 100644 --- a/src/openrct2/interface/WindowBase.h +++ b/src/openrct2/interface/WindowBase.h @@ -77,9 +77,6 @@ namespace OpenRCT2 struct WindowBase { Viewport* viewport{}; - uint64_t disabledWidgets{}; - uint64_t pressedWidgets{}; - uint64_t holdDownWidgets{}; std::vector widgets{}; ScreenCoordsXY windowPos; int16_t width{}; diff --git a/test/tests/CMakeLists.txt b/test/tests/CMakeLists.txt index 42f8c7bf12..7860b466eb 100644 --- a/test/tests/CMakeLists.txt +++ b/test/tests/CMakeLists.txt @@ -36,7 +36,8 @@ set(test_files "${CMAKE_CURRENT_SOURCE_DIR}/TestData.h" "${CMAKE_CURRENT_SOURCE_DIR}/tests.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/TileElements.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/TileElementsView.cpp") + "${CMAKE_CURRENT_SOURCE_DIR}/TileElementsView.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/WidgetStateTests.cpp") add_executable(OpenRCT2Tests ${test_files}) add_executable(OpenRCT2::OpenRCT2Tests ALIAS OpenRCT2Tests) diff --git a/test/tests/WidgetStateTests.cpp b/test/tests/WidgetStateTests.cpp new file mode 100644 index 0000000000..b2bcc9cb87 --- /dev/null +++ b/test/tests/WidgetStateTests.cpp @@ -0,0 +1,140 @@ +/***************************************************************************** + * Copyright (c) 2014-2026 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +using namespace OpenRCT2; + +TEST(WidgetStateTest, WidgetDefaultConstructedHasNoFlags) +{ + Widget widget{}; + ASSERT_TRUE(widget.flags.isEmpty()); + ASSERT_FALSE(widget.flags.has(WidgetFlag::isPressed)); + ASSERT_FALSE(widget.flags.has(WidgetFlag::isDisabled)); + ASSERT_FALSE(widget.flags.has(WidgetFlag::isHoldable)); +} + +TEST(WidgetStateTest, FlagHolderSetConditional) +{ + WidgetFlags flags; + flags.set(WidgetFlag::isPressed, true); + ASSERT_TRUE(flags.has(WidgetFlag::isPressed)); + flags.set(WidgetFlag::isPressed, false); + ASSERT_FALSE(flags.has(WidgetFlag::isPressed)); +} + +TEST(WidgetStateTest, FlagsAreIndependent) +{ + WidgetFlags flags; + flags.set(WidgetFlag::isPressed); + flags.set(WidgetFlag::isHoldable); + ASSERT_TRUE(flags.has(WidgetFlag::isPressed)); + ASSERT_TRUE(flags.has(WidgetFlag::isHoldable)); + ASSERT_FALSE(flags.has(WidgetFlag::isDisabled)); + flags.unset(WidgetFlag::isPressed); + ASSERT_FALSE(flags.has(WidgetFlag::isPressed)); + ASSERT_TRUE(flags.has(WidgetFlag::isHoldable)); +} + +// Regression guard for #26421: widgets at index >= 64 must round-trip cleanly. +// The scenery window's 65th tab has widget index 79. A uint64 bitmask indexed +// by widget index would wrap (1uLL << 79 == 1uLL << 15) and cause the first +// tab to falsely report as pressed. Per-widget flags have no such cap. +TEST(WidgetStateTest, HighIndexRoundTripsWithoutShiftWrap) +{ + WindowBase w; + w.widgets.resize(300); + w.widgets[79].flags.set(WidgetFlag::isPressed); + + ASSERT_TRUE(w.widgets[79].flags.has(WidgetFlag::isPressed)); + // Must not false-positive at any prior shift-wrap alias. + ASSERT_FALSE(w.widgets[15].flags.has(WidgetFlag::isPressed)); // 79 % 64 + ASSERT_FALSE(w.widgets[143].flags.has(WidgetFlag::isPressed)); // 143 % 64 == 15 + ASSERT_FALSE(w.widgets[271].flags.has(WidgetFlag::isPressed)); +} + +TEST(WidgetStateTest, SetWidgetsPreservesFlags) +{ + Widget mutableSource[3] = { Widget{}, Widget{}, Widget{} }; + mutableSource[1].flags.set(WidgetFlag::isPressed); + mutableSource[1].flags.set(WidgetFlag::isHoldable); + + WindowBase w; + w.setWidgets(std::span(mutableSource, 3)); + + ASSERT_EQ(w.widgets.size(), 3u); + ASSERT_TRUE(w.widgets[1].flags.has(WidgetFlag::isPressed)); + ASSERT_TRUE(w.widgets[1].flags.has(WidgetFlag::isHoldable)); + ASSERT_FALSE(w.widgets[0].flags.has(WidgetFlag::isPressed)); + ASSERT_FALSE(w.widgets[2].flags.has(WidgetFlag::isPressed)); +} + +TEST(WidgetStateTest, WithFlagSetsFlagWithoutDisturbingOthers) +{ + using Ui::withFlag; + + Widget base{}; + base.flags.set(WidgetFlag::isPressed); + + auto holdable = withFlag(base, WidgetFlag::isHoldable); + ASSERT_TRUE(holdable.flags.has(WidgetFlag::isPressed)); + ASSERT_TRUE(holdable.flags.has(WidgetFlag::isHoldable)); + ASSERT_FALSE(holdable.flags.has(WidgetFlag::isDisabled)); +} + +TEST(WidgetStateTest, MakeHoldableWidgetHasHoldableFlag) +{ + using Ui::makeHoldableWidget; + using Ui::WindowColour; + + constexpr auto w = makeHoldableWidget({ 0, 0 }, { 10, 10 }, WidgetType::button, WindowColour::primary); + static_assert(w.flags.has(WidgetFlag::isHoldable)); + static_assert(!w.flags.has(WidgetFlag::isPressed)); + static_assert(!w.flags.has(WidgetFlag::isDisabled)); + ASSERT_TRUE(w.flags.has(WidgetFlag::isHoldable)); +} + +TEST(WidgetStateTest, MakeWidgetDefaultHasNoFlags) +{ + using Ui::makeWidget; + using Ui::WindowColour; + + constexpr auto w = makeWidget({ 0, 0 }, { 10, 10 }, WidgetType::button, WindowColour::primary); + static_assert(w.flags.isEmpty()); + ASSERT_TRUE(w.flags.isEmpty()); +} + +TEST(WidgetStateTest, MakeSpinnerWidgetsHasNoHoldableFlag) +{ + using Ui::makeSpinnerWidgets; + using Ui::WindowColour; + + constexpr auto widgets = makeSpinnerWidgets({ 0, 0 }, { 100, 14 }, WidgetType::spinner, WindowColour::primary); + static_assert(!widgets[0].flags.has(WidgetFlag::isHoldable)); + static_assert(!widgets[1].flags.has(WidgetFlag::isHoldable)); + static_assert(!widgets[2].flags.has(WidgetFlag::isHoldable)); +} + +TEST(WidgetStateTest, MakeHoldableSpinnerWidgetsHasHoldableOnIncrementButtons) +{ + using Ui::makeHoldableSpinnerWidgets; + using Ui::WindowColour; + + constexpr auto widgets = makeHoldableSpinnerWidgets({ 0, 0 }, { 100, 14 }, WidgetType::spinner, WindowColour::primary); + // Element [0] is the spinner input field; increment/decrement buttons are + // [1] and [2] and must be holdable for press-and-hold repeat. + static_assert(!widgets[0].flags.has(WidgetFlag::isHoldable)); + static_assert(widgets[1].flags.has(WidgetFlag::isHoldable)); + static_assert(widgets[2].flags.has(WidgetFlag::isHoldable)); +} diff --git a/test/tests/tests.vcxproj b/test/tests/tests.vcxproj index aec8785bab..a68573185d 100644 --- a/test/tests/tests.vcxproj +++ b/test/tests/tests.vcxproj @@ -112,6 +112,7 @@ +