From a2a6deaf7b92f4b09a2dcabdedf923a908943398 Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Mon, 22 Jul 2024 15:47:34 +0200 Subject: [PATCH 01/12] Object selection window: generalise sub-tab logic * Introduce ObjectSubTab struct and kRideObjectSubTabs * Make subtab frame non-interactible * Give sub-tab widgets a more general name * Integrate TabOrder into ObjectSelectionPages * Apply filter from subpage definition * Rewrite GetSelectedObjectType to account for sub-tabs * Improve sub-tab toggling behaviour --- .../windows/EditorObjectSelection.cpp | 268 ++++++++++-------- 1 file changed, 144 insertions(+), 124 deletions(-) diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index 5f9a8b8d25..b353d56061 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -38,12 +38,13 @@ #include #include #include +#include #include #include namespace OpenRCT2::Ui::Windows { - enum + enum : uint16_t { FILTER_RCT1 = (1 << 0), FILTER_AA = (1 << 1), @@ -121,44 +122,65 @@ namespace OpenRCT2::Ui::Windows static constexpr int32_t WH = 400; static constexpr int32_t WW = 755; + enum ObjectPageFlags : uint8_t + { + none = 0, + isAdvanced = 1 << 0, + hasSubTabs = 1 << 1, + }; + + struct ObjectSubTab + { + StringId tooltip; + ObjectType subObjectType; + uint16_t flagFilter; + uint32_t baseImage; + uint8_t animationLength; + uint8_t animationDivisor; + }; + struct ObjectPageDesc { StringId Caption; + ObjectType mainObjectType; uint32_t Image; - bool IsAdvanced; + uint8_t Flags; + std::span subTabs; }; // clang-format off -// Order of which the object tabs are displayed. -static constexpr ObjectPageDesc ObjectSelectionPages[] = { - { STR_OBJECT_SELECTION_RIDE_VEHICLES_ATTRACTIONS, SPR_TAB_RIDE_16, false }, - { STR_OBJECT_SELECTION_STATIONS, SPR_G2_RIDE_STATION_TAB, true }, - { STR_OBJECT_SELECTION_MUSIC, SPR_TAB_MUSIC_0, true }, - { STR_OBJECT_SELECTION_SCENERY_GROUPS, SPR_TAB_SCENERY_STATUES, false }, - { STR_OBJECT_SELECTION_SMALL_SCENERY, SPR_TAB_SCENERY_TREES, true }, - { STR_OBJECT_SELECTION_LARGE_SCENERY, SPR_TAB_SCENERY_URBAN, true }, - { STR_OBJECT_SELECTION_WALLS_FENCES, SPR_TAB_SCENERY_WALLS, true }, - { STR_OBJECT_SELECTION_FOOTPATH_SURFACES, SPR_G2_PATH_SURFACE_TAB, false }, - { STR_OBJECT_SELECTION_FOOTPATH_RAILINGS, SPR_G2_PATH_RAILINGS_TAB, false }, - { STR_OBJECT_SELECTION_FOOTPATHS, SPR_G2_LEGACY_PATH_TAB, true }, - { STR_OBJECT_SELECTION_PATH_EXTRAS, SPR_TAB_SCENERY_PATH_ITEMS, false }, - { STR_OBJECT_SELECTION_PATH_SIGNS, SPR_TAB_SCENERY_SIGNAGE, true }, - { STR_OBJECT_SELECTION_PARK_ENTRANCE, SPR_TAB_PARK, false }, - { STR_OBJECT_SELECTION_TERRAIN_SURFACES, SPR_G2_TAB_LAND, true }, - { STR_OBJECT_SELECTION_TERRAIN_EDGES, SPR_G2_TERRAIN_EDGE_TAB, true }, - { STR_OBJECT_SELECTION_WATER, SPR_TAB_WATER, false }, -}; + static ObjectSubTab kRideObjectSubTabs[] = { + { STR_OBJECT_FILTER_ALL_RIDES_TIP, ObjectType::Ride, FILTER_RIDES, SPR_G2_INFINITY, 1, 1 }, + { STR_TRANSPORT_RIDES_TIP, ObjectType::Ride, FILTER_RIDE_TRANSPORT, SPR_TAB_RIDES_TRANSPORT_0, 20, 4 }, + { STR_GENTLE_RIDES_TIP, ObjectType::Ride, FILTER_RIDE_GENTLE, SPR_TAB_RIDES_GENTLE_0, 32, 8 }, + { STR_ROLLER_COASTERS_TIP, ObjectType::Ride, FILTER_RIDE_COASTER, SPR_TAB_RIDES_ROLLER_COASTERS_0, 10, 2 }, + { STR_THRILL_RIDES_TIP, ObjectType::Ride, FILTER_RIDE_THRILL, SPR_TAB_RIDES_THRILL_0, 72, 4 }, + { STR_WATER_RIDES_TIP, ObjectType::Ride, FILTER_RIDE_WATER, SPR_TAB_RIDES_WATER_0, 24, 4 }, + { STR_SHOPS_STALLS_TIP, ObjectType::Ride, FILTER_RIDE_STALL, SPR_TAB_RIDES_SHOP_0, 28, 4 }, + }; // clang-format on - // Order of which the contents of each tab is displayed. - ObjectType static TabOrder[] = { - ObjectType::Ride, ObjectType::Station, ObjectType::Music, - ObjectType::SceneryGroup, ObjectType::SmallScenery, ObjectType::LargeScenery, - ObjectType::Walls, ObjectType::FootpathSurface, ObjectType::FootpathRailings, - ObjectType::Paths, ObjectType::PathAdditions, ObjectType::Banners, - ObjectType::ParkEntrance, ObjectType::TerrainSurface, ObjectType::TerrainEdge, - ObjectType::Water, + // clang-format off + // Order of which the object tabs are displayed. + static constexpr ObjectPageDesc ObjectSelectionPages[] = { + { STR_OBJECT_SELECTION_RIDE_VEHICLES_ATTRACTIONS, ObjectType::Ride, SPR_TAB_RIDE_16, ObjectPageFlags::hasSubTabs, kRideObjectSubTabs }, + { STR_OBJECT_SELECTION_STATIONS, ObjectType::Station, SPR_G2_RIDE_STATION_TAB, ObjectPageFlags::isAdvanced, {} }, + { STR_OBJECT_SELECTION_MUSIC, ObjectType::Music, SPR_TAB_MUSIC_0, ObjectPageFlags::isAdvanced, {} }, + { STR_OBJECT_SELECTION_SCENERY_GROUPS, ObjectType::SceneryGroup, SPR_TAB_SCENERY_STATUES, ObjectPageFlags::none , {} }, + { STR_OBJECT_SELECTION_SMALL_SCENERY, ObjectType::SmallScenery, SPR_TAB_SCENERY_TREES, ObjectPageFlags::isAdvanced, {} }, + { STR_OBJECT_SELECTION_LARGE_SCENERY, ObjectType::LargeScenery, SPR_TAB_SCENERY_URBAN, ObjectPageFlags::isAdvanced, {} }, + { STR_OBJECT_SELECTION_WALLS_FENCES, ObjectType::Walls, SPR_TAB_SCENERY_WALLS, ObjectPageFlags::isAdvanced, {} }, + { STR_OBJECT_SELECTION_FOOTPATH_SURFACES, ObjectType::FootpathSurface, SPR_G2_PATH_SURFACE_TAB, ObjectPageFlags::none , {} }, + { STR_OBJECT_SELECTION_FOOTPATH_RAILINGS, ObjectType::FootpathRailings, SPR_G2_PATH_RAILINGS_TAB, ObjectPageFlags::none , {} }, + { STR_OBJECT_SELECTION_FOOTPATHS, ObjectType::Paths, SPR_G2_LEGACY_PATH_TAB, ObjectPageFlags::isAdvanced, {} }, + { STR_OBJECT_SELECTION_PATH_EXTRAS, ObjectType::PathAdditions, SPR_TAB_SCENERY_PATH_ITEMS, ObjectPageFlags::none , {} }, + { STR_OBJECT_SELECTION_PATH_SIGNS, ObjectType::Banners, SPR_TAB_SCENERY_SIGNAGE, ObjectPageFlags::isAdvanced, {} }, + { STR_OBJECT_SELECTION_PARK_ENTRANCE, ObjectType::ParkEntrance, SPR_TAB_PARK, ObjectPageFlags::none , {} }, + { STR_OBJECT_SELECTION_TERRAIN_SURFACES, ObjectType::TerrainSurface, SPR_G2_TAB_LAND, ObjectPageFlags::isAdvanced, {} }, + { STR_OBJECT_SELECTION_TERRAIN_EDGES, ObjectType::TerrainEdge, SPR_G2_TERRAIN_EDGE_TAB, ObjectPageFlags::isAdvanced, {} }, + { STR_OBJECT_SELECTION_WATER, ObjectType::Water, SPR_TAB_WATER, ObjectPageFlags::none , {} }, }; + // clang-format on #pragma region Widgets @@ -176,13 +198,13 @@ static constexpr ObjectPageDesc ObjectSelectionPages[] = { WIDX_FILTER_TEXT_BOX, WIDX_FILTER_CLEAR_BUTTON, WIDX_FILTER_RIDE_TAB_FRAME, - WIDX_FILTER_RIDE_TAB_ALL, - WIDX_FILTER_RIDE_TAB_TRANSPORT, - WIDX_FILTER_RIDE_TAB_GENTLE, - WIDX_FILTER_RIDE_TAB_COASTER, - WIDX_FILTER_RIDE_TAB_THRILL, - WIDX_FILTER_RIDE_TAB_WATER, - WIDX_FILTER_RIDE_TAB_STALL, + WIDX_SUB_TAB_0, + WIDX_SUB_TAB_1, + WIDX_SUB_TAB_2, + WIDX_SUB_TAB_3, + WIDX_SUB_TAB_4, + WIDX_SUB_TAB_5, + WIDX_SUB_TAB_6, WIDX_LIST_SORT_TYPE, WIDX_LIST_SORT_RIDE, WIDX_RELOAD_OBJECT, @@ -202,16 +224,16 @@ static std::vector _window_editor_object_selection_widgets = { MakeWidget({391, 45}, {114, 114}, WindowWidgetType::FlatBtn, WindowColour::Secondary ), MakeWidget({470, 22}, {122, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_INSTALL_NEW_TRACK_DESIGN, STR_INSTALL_NEW_TRACK_DESIGN_TIP ), MakeWidget({350, 22}, {114, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_OBJECT_FILTER, STR_OBJECT_FILTER_TIP ), - MakeWidget({ 4, 45}, {211, 14}, WindowWidgetType::TextBox, WindowColour::Secondary ), + MakeWidget({ 4, 45}, {211, 14}, WindowWidgetType::TextBox, WindowColour::Secondary ), MakeWidget({218, 45}, { 70, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_OBJECT_SEARCH_CLEAR ), MakeWidget({ 3, 73}, {285, 4}, WindowWidgetType::ImgBtn, WindowColour::Secondary ), - MakeTab ({ 3, 47}, STR_OBJECT_FILTER_ALL_RIDES_TIP ), - MakeTab ({ 34, 47}, STR_TRANSPORT_RIDES_TIP ), - MakeTab ({ 65, 47}, STR_GENTLE_RIDES_TIP ), - MakeTab ({ 96, 47}, STR_ROLLER_COASTERS_TIP ), - MakeTab ({127, 47}, STR_THRILL_RIDES_TIP ), - MakeTab ({158, 47}, STR_WATER_RIDES_TIP ), - MakeTab ({189, 47}, STR_SHOPS_STALLS_TIP ), + MakeTab ({ 3, 47}), + MakeTab ({ 34, 47}), + MakeTab ({ 65, 47}), + MakeTab ({ 96, 47}), + MakeTab ({127, 47}), + MakeTab ({158, 47}), + MakeTab ({189, 47}), MakeWidget({ 4, 80}, {145, 14}, WindowWidgetType::TableHeader, WindowColour::Secondary ), MakeWidget({149, 80}, {143, 14}, WindowWidgetType::TableHeader, WindowColour::Secondary ), MakeWidget({700, 50}, { 24, 24}, WindowWidgetType::ImgBtn, WindowColour::Primary, SPR_G2_RELOAD, STR_RELOAD_OBJECT_TIP ), @@ -224,23 +246,6 @@ static std::vector _window_editor_object_selection_widgets = { #pragma endregion - static constexpr int32_t window_editor_object_selection_animation_loops[] = { - 20, // Transport - 32, // Gentle - 10, // Coaster - 72, // Thrill - 24, // Water - 28, // Stall - }; - static constexpr int32_t window_editor_object_selection_animation_divisor[] = { - 4, // Transport - 8, // Gentle - 2, // Coaster - 4, // Thrill - 4, // Water - 4, // Stall - }; - static StringId GetRideTypeStringId(const ObjectRepositoryItem* item); static bool VisibleListSortRideType(const ObjectListItem& a, const ObjectListItem& b); static bool VisibleListSortRideName(const ObjectListItem& a, const ObjectListItem& b); @@ -271,7 +276,7 @@ static std::vector _window_editor_object_selection_widgets = { widgets[WIDX_FILTER_TEXT_BOX].string = _filter_string; - _filter_flags = Config::Get().interface.ObjectSelectionFilterFlags; + _filter_flags = FILTER_RIDES | Config::Get().interface.ObjectSelectionFilterFlags; std::fill_n(_filter_string, sizeof(_filter_string), 0x00); WindowInitScrollWidgets(*this); @@ -286,6 +291,8 @@ static std::vector _window_editor_object_selection_widgets = { _listSortType = RIDE_SORT_TYPE; _listSortDescending = false; + disabled_widgets |= 1u << WIDX_FILTER_RIDE_TAB_FRAME; + VisibleListRefresh(); } @@ -338,11 +345,13 @@ static std::vector _window_editor_object_selection_widgets = { if (_selectedSubTab == 0) return; + auto& subTabDef = currentPage.subTabs[_selectedSubTab]; + frame_no++; - if (frame_no >= window_editor_object_selection_animation_loops[_selectedSubTab - 1]) + if (frame_no >= subTabDef.animationLength) frame_no = 0; - WidgetInvalidate(*this, WIDX_FILTER_RIDE_TAB_ALL + _selectedSubTab); + WidgetInvalidate(*this, WIDX_SUB_TAB_0 + _selectedSubTab); } /** @@ -370,22 +379,21 @@ static std::vector _window_editor_object_selection_widgets = { context->SetActiveScene(context->GetTitleScene()); } break; - case WIDX_FILTER_RIDE_TAB_ALL: - case WIDX_FILTER_RIDE_TAB_TRANSPORT: - case WIDX_FILTER_RIDE_TAB_GENTLE: - case WIDX_FILTER_RIDE_TAB_COASTER: - case WIDX_FILTER_RIDE_TAB_THRILL: - case WIDX_FILTER_RIDE_TAB_WATER: - case WIDX_FILTER_RIDE_TAB_STALL: + + case WIDX_SUB_TAB_0: + case WIDX_SUB_TAB_1: + case WIDX_SUB_TAB_2: + case WIDX_SUB_TAB_3: + case WIDX_SUB_TAB_4: + case WIDX_SUB_TAB_5: + case WIDX_SUB_TAB_6: { - _selectedSubTab = widgetIndex - WIDX_FILTER_RIDE_TAB_ALL; - if (widgetIndex != WIDX_FILTER_RIDE_TAB_ALL) - { - _filter_flags &= ~FILTER_RIDES; - _filter_flags |= (1 << (_numSourceGameItems + _selectedSubTab - 1)); - } - else - _filter_flags |= FILTER_RIDES; + _selectedSubTab = widgetIndex - WIDX_SUB_TAB_0; + + auto& currentPage = ObjectSelectionPages[selected_tab]; + auto& subTabDef = currentPage.subTabs[_selectedSubTab]; + _filter_flags &= ~FILTER_RIDES; + _filter_flags |= subTabDef.flagFilter; Config::Get().interface.ObjectSelectionFilterFlags = _filter_flags; Config::Save(); @@ -887,7 +895,7 @@ static std::vector _window_editor_object_selection_widgets = { for (size_t i = 0; i < std::size(ObjectSelectionPages); i++) { auto& widget = widgets[WIDX_TAB_1 + i]; - if ((!advancedMode && ObjectSelectionPages[i].IsAdvanced) + if ((!advancedMode && (ObjectSelectionPages[i].Flags & ObjectPageFlags::isAdvanced)) || ObjectSelectionPages[i].Image == static_cast(SPR_NONE)) { widget.type = WindowWidgetType::Empty; @@ -927,36 +935,41 @@ static std::vector _window_editor_object_selection_widgets = { widgets[WIDX_PREVIEW].right = widgets[WIDX_PREVIEW].left + 113; widgets[WIDX_FILTER_RIDE_TAB_FRAME].right = widgets[WIDX_LIST].right; - bool ridePage = (GetSelectedObjectType() == ObjectType::Ride); - widgets[WIDX_LIST].top = (ridePage ? 118 : 60); + // Do we have any sub-tabs? + const auto& currentPage = ObjectSelectionPages[selected_tab]; + const bool hasSubTabs = !currentPage.subTabs.empty(); + + widgets[WIDX_LIST].top = (hasSubTabs ? 118 : 60); widgets[WIDX_FILTER_TEXT_BOX].right = widgets[WIDX_LIST].right - 77; - widgets[WIDX_FILTER_TEXT_BOX].top = (ridePage ? 79 : 45); - widgets[WIDX_FILTER_TEXT_BOX].bottom = (ridePage ? 92 : 58); + widgets[WIDX_FILTER_TEXT_BOX].top = (hasSubTabs ? 79 : 45); + widgets[WIDX_FILTER_TEXT_BOX].bottom = (hasSubTabs ? 92 : 58); widgets[WIDX_FILTER_CLEAR_BUTTON].left = widgets[WIDX_LIST].right - 73; widgets[WIDX_FILTER_CLEAR_BUTTON].right = widgets[WIDX_LIST].right; - widgets[WIDX_FILTER_CLEAR_BUTTON].top = (ridePage ? 79 : 45); - widgets[WIDX_FILTER_CLEAR_BUTTON].bottom = (ridePage ? 92 : 58); + widgets[WIDX_FILTER_CLEAR_BUTTON].top = (hasSubTabs ? 79 : 45); + widgets[WIDX_FILTER_CLEAR_BUTTON].bottom = (hasSubTabs ? 92 : 58); - if (ridePage) + // Toggle sub-tab visibility + const auto numSubTabs = static_cast(currentPage.subTabs.size()); + for (int8_t i = 0; i <= 6; i++) { - for (int32_t i = WIDX_FILTER_RIDE_TAB_ALL; i <= WIDX_FILTER_RIDE_TAB_STALL; i++) - pressed_widgets &= ~(1 << i); - - if ((_filter_flags & FILTER_RIDES) == FILTER_RIDES) - pressed_widgets |= (1uLL << WIDX_FILTER_RIDE_TAB_ALL); - else - { - for (int32_t i = 0; i < 6; i++) - { - if (_filter_flags & (1 << (_numSourceGameItems + i))) - pressed_widgets |= 1uLL << (WIDX_FILTER_RIDE_TAB_TRANSPORT + i); - } - } + widgets[WIDX_SUB_TAB_0 + i].tooltip = i < numSubTabs ? currentPage.subTabs[i].tooltip : STR_NONE; + widgets[WIDX_SUB_TAB_0 + i].type = i < numSubTabs ? WindowWidgetType::Tab : WindowWidgetType::Empty; + pressed_widgets &= ~(1uLL << (WIDX_SUB_TAB_0 + i)); + } + // Mark current sub-tab as active, and toggle tab frame + if (hasSubTabs) + { + pressed_widgets |= (1uLL << (WIDX_SUB_TAB_0 + _selectedSubTab)); widgets[WIDX_FILTER_RIDE_TAB_FRAME].type = WindowWidgetType::ImgBtn; - for (int32_t i = WIDX_FILTER_RIDE_TAB_ALL; i <= WIDX_FILTER_RIDE_TAB_STALL; i++) - widgets[i].type = WindowWidgetType::Tab; + } + else + widgets[WIDX_FILTER_RIDE_TAB_FRAME].type = WindowWidgetType::Empty; + // The ride tab has two headers for the list + bool isRideTab = GetSelectedObjectType() == ObjectType::Ride; + if (isRideTab) + { int32_t width_limit = (widgets[WIDX_LIST].width() - 15) / 2; widgets[WIDX_LIST_SORT_TYPE].type = WindowWidgetType::TableHeader; @@ -975,11 +988,10 @@ static std::vector _window_editor_object_selection_widgets = { } else { - for (int32_t i = WIDX_FILTER_RIDE_TAB_FRAME; i <= WIDX_FILTER_RIDE_TAB_STALL; i++) - widgets[i].type = WindowWidgetType::Empty; - widgets[WIDX_LIST_SORT_TYPE].type = WindowWidgetType::Empty; widgets[WIDX_LIST_SORT_RIDE].type = WindowWidgetType::Empty; + + widgets[WIDX_LIST].top = widgets[WIDX_FILTER_TEXT_BOX].bottom + 2; } } @@ -989,7 +1001,7 @@ static std::vector _window_editor_object_selection_widgets = { DrawWidgets(dpi); - // Draw tabs + // Draw main tab images for (size_t i = 0; i < std::size(ObjectSelectionPages); i++) { const auto& widget = widgets[WIDX_TAB_1 + i]; @@ -1001,30 +1013,33 @@ static std::vector _window_editor_object_selection_widgets = { } } - const int32_t ride_tabs[] = { - SPR_G2_INFINITY, SPR_TAB_RIDES_TRANSPORT_0, SPR_TAB_RIDES_GENTLE_0, SPR_TAB_RIDES_ROLLER_COASTERS_0, - SPR_TAB_RIDES_THRILL_0, SPR_TAB_RIDES_WATER_0, SPR_TAB_RIDES_SHOP_0, SPR_TAB_FINANCES_RESEARCH_0, - }; - const int32_t ThrillRidesTabAnimationSequence[] = { + constexpr int32_t ThrillRidesTabAnimationSequence[] = { 5, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, }; - // Draw ride tabs - if (GetSelectedObjectType() == ObjectType::Ride) + // Draw sub-tab images, if applicable + auto& currentPage = ObjectSelectionPages[selected_tab]; + if (currentPage.Flags & ObjectPageFlags::hasSubTabs) { - for (int32_t i = 0; i < 7; i++) + for (auto i = 0u; i < currentPage.subTabs.size(); i++) { - const auto& widget = widgets[WIDX_FILTER_RIDE_TAB_ALL + i]; + const auto& widget = widgets[WIDX_SUB_TAB_0 + i]; if (widget.type == WindowWidgetType::Empty) continue; - int32_t spriteIndex = ride_tabs[i]; + auto& subTabDef = currentPage.subTabs[i]; + int32_t spriteIndex = subTabDef.baseImage; int32_t frame = 0; - if (i != 0 && _selectedSubTab == i) + if (subTabDef.animationLength > 1 && _selectedSubTab == i) { - frame = frame_no / window_editor_object_selection_animation_divisor[i - 1]; + frame = frame_no / subTabDef.animationDivisor; } - spriteIndex += (i == 4 ? ThrillRidesTabAnimationSequence[frame] : frame); + + // TODO: generalise this? + if (currentPage.Caption == STR_OBJECT_SELECTION_RIDE_VEHICLES_ATTRACTIONS && i == 4) + spriteIndex += ThrillRidesTabAnimationSequence[frame]; + else + spriteIndex += frame; auto screenPos = windowPos + ScreenCoordsXY{ widget.left, widget.top }; GfxDrawSprite(dpi, ImageId(spriteIndex, colours[1].colour), screenPos); @@ -1108,11 +1123,11 @@ static std::vector _window_editor_object_selection_widgets = { void GoToTab(ObjectType objectType) { - for (size_t offset = 0; offset < std::size(TabOrder); offset++) + for (auto offset = 0u; offset < std::size(ObjectSelectionPages); offset++) { - if (TabOrder[offset] == objectType) + if (ObjectSelectionPages[offset].mainObjectType == objectType) { - SetPage(static_cast(offset)); + SetPage(offset); return; } } @@ -1142,6 +1157,7 @@ static std::vector _window_editor_object_selection_widgets = { selected_tab = _page; _selectedSubTab = 0; + _filter_flags |= FILTER_RIDES; selected_list_item = -1; scrolls[0].v_top = 0; frame_no = 0; @@ -1520,8 +1536,12 @@ static std::vector _window_editor_object_selection_widgets = { ObjectType GetSelectedObjectType() { - const bool inBounds = selected_tab >= 0 && selected_tab < static_cast(std::size(TabOrder)); - return inBounds ? TabOrder[selected_tab] : ObjectType::Ride; + auto& currentPage = ObjectSelectionPages[selected_tab]; + auto& subTabs = currentPage.subTabs; + if (!subTabs.empty()) + return subTabs[_selectedSubTab].subObjectType; + else + return currentPage.mainObjectType; } /** From 3b4c5ce3effac77633dfd48b2933a449bcf77f24 Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Tue, 23 Jul 2024 13:26:23 +0200 Subject: [PATCH 02/12] Introduce sub-tabs for path-related object types --- .../windows/EditorObjectSelection.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index b353d56061..b2eaeb92fa 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -46,6 +46,8 @@ namespace OpenRCT2::Ui::Windows { enum : uint16_t { + FILTER_NONE = 0, + FILTER_RCT1 = (1 << 0), FILTER_AA = (1 << 1), FILTER_LL = (1 << 2), @@ -158,10 +160,15 @@ namespace OpenRCT2::Ui::Windows { STR_WATER_RIDES_TIP, ObjectType::Ride, FILTER_RIDE_WATER, SPR_TAB_RIDES_WATER_0, 24, 4 }, { STR_SHOPS_STALLS_TIP, ObjectType::Ride, FILTER_RIDE_STALL, SPR_TAB_RIDES_SHOP_0, 28, 4 }, }; - // clang-format on - // clang-format off - // Order of which the object tabs are displayed. + static ObjectSubTab kPathObjectSubTabs[] = { + { STR_OBJECT_SELECTION_FOOTPATH_SURFACES, ObjectType::FootpathSurface, FILTER_NONE, SPR_G2_PATH_SURFACE_TAB, 1, 1 }, + { STR_OBJECT_SELECTION_FOOTPATH_RAILINGS, ObjectType::FootpathRailings, FILTER_NONE, SPR_G2_PATH_RAILINGS_TAB, 1, 1 }, + { STR_OBJECT_SELECTION_FOOTPATHS, ObjectType::Paths, FILTER_NONE, SPR_G2_LEGACY_PATH_TAB, 1, 1 }, + { STR_OBJECT_SELECTION_PATH_EXTRAS, ObjectType::PathAdditions, FILTER_NONE, SPR_TAB_SCENERY_PATH_ITEMS, 1, 1 }, + { STR_OBJECT_SELECTION_PATH_SIGNS, ObjectType::Banners, FILTER_NONE, SPR_TAB_SCENERY_SIGNAGE, 1, 1 }, + }; + static constexpr ObjectPageDesc ObjectSelectionPages[] = { { STR_OBJECT_SELECTION_RIDE_VEHICLES_ATTRACTIONS, ObjectType::Ride, SPR_TAB_RIDE_16, ObjectPageFlags::hasSubTabs, kRideObjectSubTabs }, { STR_OBJECT_SELECTION_STATIONS, ObjectType::Station, SPR_G2_RIDE_STATION_TAB, ObjectPageFlags::isAdvanced, {} }, @@ -170,11 +177,7 @@ namespace OpenRCT2::Ui::Windows { STR_OBJECT_SELECTION_SMALL_SCENERY, ObjectType::SmallScenery, SPR_TAB_SCENERY_TREES, ObjectPageFlags::isAdvanced, {} }, { STR_OBJECT_SELECTION_LARGE_SCENERY, ObjectType::LargeScenery, SPR_TAB_SCENERY_URBAN, ObjectPageFlags::isAdvanced, {} }, { STR_OBJECT_SELECTION_WALLS_FENCES, ObjectType::Walls, SPR_TAB_SCENERY_WALLS, ObjectPageFlags::isAdvanced, {} }, - { STR_OBJECT_SELECTION_FOOTPATH_SURFACES, ObjectType::FootpathSurface, SPR_G2_PATH_SURFACE_TAB, ObjectPageFlags::none , {} }, - { STR_OBJECT_SELECTION_FOOTPATH_RAILINGS, ObjectType::FootpathRailings, SPR_G2_PATH_RAILINGS_TAB, ObjectPageFlags::none , {} }, - { STR_OBJECT_SELECTION_FOOTPATHS, ObjectType::Paths, SPR_G2_LEGACY_PATH_TAB, ObjectPageFlags::isAdvanced, {} }, - { STR_OBJECT_SELECTION_PATH_EXTRAS, ObjectType::PathAdditions, SPR_TAB_SCENERY_PATH_ITEMS, ObjectPageFlags::none , {} }, - { STR_OBJECT_SELECTION_PATH_SIGNS, ObjectType::Banners, SPR_TAB_SCENERY_SIGNAGE, ObjectPageFlags::isAdvanced, {} }, + { STR_OBJECT_SELECTION_FOOTPATH_SURFACES, ObjectType::FootpathSurface, SPR_G2_LEGACY_PATH_TAB, ObjectPageFlags::hasSubTabs, kPathObjectSubTabs }, { STR_OBJECT_SELECTION_PARK_ENTRANCE, ObjectType::ParkEntrance, SPR_TAB_PARK, ObjectPageFlags::none , {} }, { STR_OBJECT_SELECTION_TERRAIN_SURFACES, ObjectType::TerrainSurface, SPR_G2_TAB_LAND, ObjectPageFlags::isAdvanced, {} }, { STR_OBJECT_SELECTION_TERRAIN_EDGES, ObjectType::TerrainEdge, SPR_G2_TERRAIN_EDGE_TAB, ObjectPageFlags::isAdvanced, {} }, From 1de7cb433e496ef8ed25a6e9e5f2b6d3a85a710f Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Tue, 23 Jul 2024 13:28:59 +0200 Subject: [PATCH 03/12] Introduce sub-tabs for scenery-related object types --- src/openrct2-ui/windows/EditorObjectSelection.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index b2eaeb92fa..292d89a7a1 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -161,6 +161,13 @@ namespace OpenRCT2::Ui::Windows { STR_SHOPS_STALLS_TIP, ObjectType::Ride, FILTER_RIDE_STALL, SPR_TAB_RIDES_SHOP_0, 28, 4 }, }; + static ObjectSubTab kSceneryObjectSubTabs[] = { + { STR_OBJECT_SELECTION_SCENERY_GROUPS, ObjectType::SceneryGroup, FILTER_NONE, SPR_TAB_SCENERY_STATUES, 1, 1 }, + { STR_OBJECT_SELECTION_SMALL_SCENERY, ObjectType::SmallScenery, FILTER_NONE, SPR_TAB_SCENERY_TREES, 1, 1 }, + { STR_OBJECT_SELECTION_LARGE_SCENERY, ObjectType::LargeScenery, FILTER_NONE, SPR_TAB_SCENERY_URBAN, 1, 1 }, + { STR_OBJECT_SELECTION_WALLS_FENCES, ObjectType::Walls, FILTER_NONE, SPR_TAB_SCENERY_WALLS, 1, 1 }, + }; + static ObjectSubTab kPathObjectSubTabs[] = { { STR_OBJECT_SELECTION_FOOTPATH_SURFACES, ObjectType::FootpathSurface, FILTER_NONE, SPR_G2_PATH_SURFACE_TAB, 1, 1 }, { STR_OBJECT_SELECTION_FOOTPATH_RAILINGS, ObjectType::FootpathRailings, FILTER_NONE, SPR_G2_PATH_RAILINGS_TAB, 1, 1 }, @@ -173,10 +180,7 @@ namespace OpenRCT2::Ui::Windows { STR_OBJECT_SELECTION_RIDE_VEHICLES_ATTRACTIONS, ObjectType::Ride, SPR_TAB_RIDE_16, ObjectPageFlags::hasSubTabs, kRideObjectSubTabs }, { STR_OBJECT_SELECTION_STATIONS, ObjectType::Station, SPR_G2_RIDE_STATION_TAB, ObjectPageFlags::isAdvanced, {} }, { STR_OBJECT_SELECTION_MUSIC, ObjectType::Music, SPR_TAB_MUSIC_0, ObjectPageFlags::isAdvanced, {} }, - { STR_OBJECT_SELECTION_SCENERY_GROUPS, ObjectType::SceneryGroup, SPR_TAB_SCENERY_STATUES, ObjectPageFlags::none , {} }, - { STR_OBJECT_SELECTION_SMALL_SCENERY, ObjectType::SmallScenery, SPR_TAB_SCENERY_TREES, ObjectPageFlags::isAdvanced, {} }, - { STR_OBJECT_SELECTION_LARGE_SCENERY, ObjectType::LargeScenery, SPR_TAB_SCENERY_URBAN, ObjectPageFlags::isAdvanced, {} }, - { STR_OBJECT_SELECTION_WALLS_FENCES, ObjectType::Walls, SPR_TAB_SCENERY_WALLS, ObjectPageFlags::isAdvanced, {} }, + { STR_OBJECT_SELECTION_SCENERY_GROUPS, ObjectType::SceneryGroup, SPR_TAB_SCENERY_STATUES, ObjectPageFlags::hasSubTabs, kSceneryObjectSubTabs }, { STR_OBJECT_SELECTION_FOOTPATH_SURFACES, ObjectType::FootpathSurface, SPR_G2_LEGACY_PATH_TAB, ObjectPageFlags::hasSubTabs, kPathObjectSubTabs }, { STR_OBJECT_SELECTION_PARK_ENTRANCE, ObjectType::ParkEntrance, SPR_TAB_PARK, ObjectPageFlags::none , {} }, { STR_OBJECT_SELECTION_TERRAIN_SURFACES, ObjectType::TerrainSurface, SPR_G2_TAB_LAND, ObjectPageFlags::isAdvanced, {} }, From 92c92e63163b5f123e1974d3af2c8fad33859d9a Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Tue, 23 Jul 2024 13:29:54 +0200 Subject: [PATCH 04/12] Move tabs with sub-tabs to start of the tab strip --- src/openrct2-ui/windows/EditorObjectSelection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index 292d89a7a1..ddc9da8362 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -178,11 +178,11 @@ namespace OpenRCT2::Ui::Windows static constexpr ObjectPageDesc ObjectSelectionPages[] = { { STR_OBJECT_SELECTION_RIDE_VEHICLES_ATTRACTIONS, ObjectType::Ride, SPR_TAB_RIDE_16, ObjectPageFlags::hasSubTabs, kRideObjectSubTabs }, - { STR_OBJECT_SELECTION_STATIONS, ObjectType::Station, SPR_G2_RIDE_STATION_TAB, ObjectPageFlags::isAdvanced, {} }, - { STR_OBJECT_SELECTION_MUSIC, ObjectType::Music, SPR_TAB_MUSIC_0, ObjectPageFlags::isAdvanced, {} }, { STR_OBJECT_SELECTION_SCENERY_GROUPS, ObjectType::SceneryGroup, SPR_TAB_SCENERY_STATUES, ObjectPageFlags::hasSubTabs, kSceneryObjectSubTabs }, { STR_OBJECT_SELECTION_FOOTPATH_SURFACES, ObjectType::FootpathSurface, SPR_G2_LEGACY_PATH_TAB, ObjectPageFlags::hasSubTabs, kPathObjectSubTabs }, { STR_OBJECT_SELECTION_PARK_ENTRANCE, ObjectType::ParkEntrance, SPR_TAB_PARK, ObjectPageFlags::none , {} }, + { STR_OBJECT_SELECTION_STATIONS, ObjectType::Station, SPR_G2_RIDE_STATION_TAB, ObjectPageFlags::isAdvanced, {} }, + { STR_OBJECT_SELECTION_MUSIC, ObjectType::Music, SPR_TAB_MUSIC_0, ObjectPageFlags::isAdvanced, {} }, { STR_OBJECT_SELECTION_TERRAIN_SURFACES, ObjectType::TerrainSurface, SPR_G2_TAB_LAND, ObjectPageFlags::isAdvanced, {} }, { STR_OBJECT_SELECTION_TERRAIN_EDGES, ObjectType::TerrainEdge, SPR_G2_TERRAIN_EDGE_TAB, ObjectPageFlags::isAdvanced, {} }, { STR_OBJECT_SELECTION_WATER, ObjectType::Water, SPR_TAB_WATER, ObjectPageFlags::none , {} }, From 76f295b7be7e0e6f6ecacc4961fe9eb8cbabf61a Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Tue, 23 Jul 2024 13:37:01 +0200 Subject: [PATCH 05/12] Make 'advanced' object selection mode the only mode This removes the ObjectPageFlags again --- .../windows/EditorObjectSelection.cpp | 72 ++++++------------- src/openrct2/interface/Window.h | 2 +- 2 files changed, 23 insertions(+), 51 deletions(-) diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index ddc9da8362..e2b6d95758 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -124,13 +124,6 @@ namespace OpenRCT2::Ui::Windows static constexpr int32_t WH = 400; static constexpr int32_t WW = 755; - enum ObjectPageFlags : uint8_t - { - none = 0, - isAdvanced = 1 << 0, - hasSubTabs = 1 << 1, - }; - struct ObjectSubTab { StringId tooltip; @@ -146,7 +139,6 @@ namespace OpenRCT2::Ui::Windows StringId Caption; ObjectType mainObjectType; uint32_t Image; - uint8_t Flags; std::span subTabs; }; @@ -177,15 +169,15 @@ namespace OpenRCT2::Ui::Windows }; static constexpr ObjectPageDesc ObjectSelectionPages[] = { - { STR_OBJECT_SELECTION_RIDE_VEHICLES_ATTRACTIONS, ObjectType::Ride, SPR_TAB_RIDE_16, ObjectPageFlags::hasSubTabs, kRideObjectSubTabs }, - { STR_OBJECT_SELECTION_SCENERY_GROUPS, ObjectType::SceneryGroup, SPR_TAB_SCENERY_STATUES, ObjectPageFlags::hasSubTabs, kSceneryObjectSubTabs }, - { STR_OBJECT_SELECTION_FOOTPATH_SURFACES, ObjectType::FootpathSurface, SPR_G2_LEGACY_PATH_TAB, ObjectPageFlags::hasSubTabs, kPathObjectSubTabs }, - { STR_OBJECT_SELECTION_PARK_ENTRANCE, ObjectType::ParkEntrance, SPR_TAB_PARK, ObjectPageFlags::none , {} }, - { STR_OBJECT_SELECTION_STATIONS, ObjectType::Station, SPR_G2_RIDE_STATION_TAB, ObjectPageFlags::isAdvanced, {} }, - { STR_OBJECT_SELECTION_MUSIC, ObjectType::Music, SPR_TAB_MUSIC_0, ObjectPageFlags::isAdvanced, {} }, - { STR_OBJECT_SELECTION_TERRAIN_SURFACES, ObjectType::TerrainSurface, SPR_G2_TAB_LAND, ObjectPageFlags::isAdvanced, {} }, - { STR_OBJECT_SELECTION_TERRAIN_EDGES, ObjectType::TerrainEdge, SPR_G2_TERRAIN_EDGE_TAB, ObjectPageFlags::isAdvanced, {} }, - { STR_OBJECT_SELECTION_WATER, ObjectType::Water, SPR_TAB_WATER, ObjectPageFlags::none , {} }, + { STR_OBJECT_SELECTION_RIDE_VEHICLES_ATTRACTIONS, ObjectType::Ride, SPR_TAB_RIDE_16, kRideObjectSubTabs }, + { STR_OBJECT_SELECTION_SCENERY_GROUPS, ObjectType::SceneryGroup, SPR_TAB_SCENERY_STATUES, kSceneryObjectSubTabs }, + { STR_OBJECT_SELECTION_FOOTPATH_SURFACES, ObjectType::FootpathSurface, SPR_G2_LEGACY_PATH_TAB, kPathObjectSubTabs }, + { STR_OBJECT_SELECTION_PARK_ENTRANCE, ObjectType::ParkEntrance, SPR_TAB_PARK, {} }, + { STR_OBJECT_SELECTION_STATIONS, ObjectType::Station, SPR_G2_RIDE_STATION_TAB, {} }, + { STR_OBJECT_SELECTION_MUSIC, ObjectType::Music, SPR_TAB_MUSIC_0, {} }, + { STR_OBJECT_SELECTION_TERRAIN_SURFACES, ObjectType::TerrainSurface, SPR_G2_TAB_LAND, {} }, + { STR_OBJECT_SELECTION_TERRAIN_EDGES, ObjectType::TerrainEdge, SPR_G2_TERRAIN_EDGE_TAB, {} }, + { STR_OBJECT_SELECTION_WATER, ObjectType::Water, SPR_TAB_WATER, {} }, }; // clang-format on @@ -197,7 +189,6 @@ namespace OpenRCT2::Ui::Windows WIDX_TITLE, WIDX_CLOSE, WIDX_TAB_CONTENT_PANEL, - WIDX_ADVANCED, WIDX_LIST, WIDX_PREVIEW, WIDX_INSTALL_TRACK, @@ -226,11 +217,10 @@ namespace OpenRCT2::Ui::Windows static std::vector _window_editor_object_selection_widgets = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ 0, 43}, {WW, 357}, WindowWidgetType::Resize, WindowColour::Secondary ), - MakeWidget({470, 22}, {122, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_OBJECT_SELECTION_ADVANCED, STR_OBJECT_SELECTION_ADVANCED_TIP), MakeWidget({ 4, 60}, {288, 277}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL ), MakeWidget({391, 45}, {114, 114}, WindowWidgetType::FlatBtn, WindowColour::Secondary ), - MakeWidget({470, 22}, {122, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_INSTALL_NEW_TRACK_DESIGN, STR_INSTALL_NEW_TRACK_DESIGN_TIP ), - MakeWidget({350, 22}, {114, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_OBJECT_FILTER, STR_OBJECT_FILTER_TIP ), + MakeWidget({350, 22}, {122, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_INSTALL_NEW_TRACK_DESIGN, STR_INSTALL_NEW_TRACK_DESIGN_TIP ), + MakeWidget({470, 22}, {114, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_OBJECT_FILTER, STR_OBJECT_FILTER_TIP ), MakeWidget({ 4, 45}, {211, 14}, WindowWidgetType::TextBox, WindowColour::Secondary ), MakeWidget({218, 45}, { 70, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_OBJECT_SEARCH_CLEAR ), MakeWidget({ 3, 73}, {285, 4}, WindowWidgetType::ImgBtn, WindowColour::Secondary ), @@ -346,7 +336,8 @@ static std::vector _window_editor_object_selection_widgets = { WidgetInvalidate(*this, WIDX_FILTER_TEXT_BOX); } - if (GetSelectedObjectType() != ObjectType::Ride) + auto& currentPage = ObjectSelectionPages[selected_tab]; + if (currentPage.subTabs.empty()) return; if (_selectedSubTab == 0) @@ -415,11 +406,6 @@ static std::vector _window_editor_object_selection_widgets = { break; } - case WIDX_ADVANCED: - list_information_type ^= 1; - Invalidate(); - break; - case WIDX_INSTALL_TRACK: { if (selected_list_item != -1) @@ -854,26 +840,20 @@ static std::vector _window_editor_object_selection_widgets = { { // Resize widgets ResizeFrameWithPage(); - widgets[WIDX_ADVANCED].left = width - 130; - widgets[WIDX_ADVANCED].right = width - 9; widgets[WIDX_LIST].right = width - 309; widgets[WIDX_LIST].bottom = height - 14; widgets[WIDX_PREVIEW].left = width - 209; widgets[WIDX_PREVIEW].right = width - 96; - widgets[WIDX_INSTALL_TRACK].left = width - 130; - widgets[WIDX_INSTALL_TRACK].right = width - 9; - widgets[WIDX_FILTER_DROPDOWN].left = width - 250; - widgets[WIDX_FILTER_DROPDOWN].right = width - 137; + widgets[WIDX_FILTER_DROPDOWN].left = width - 130; + widgets[WIDX_FILTER_DROPDOWN].right = width - 9; + widgets[WIDX_INSTALL_TRACK].left = width - 250; + widgets[WIDX_INSTALL_TRACK].right = width - 137; widgets[WIDX_RELOAD_OBJECT].left = width - 9 - 24; widgets[WIDX_RELOAD_OBJECT].right = width - 9; // Set pressed widgets pressed_widgets |= 1uLL << WIDX_PREVIEW; SetPressedTab(); - if (list_information_type & 1) - pressed_widgets |= (1uLL << WIDX_ADVANCED); - else - pressed_widgets &= ~(1uLL << WIDX_ADVANCED); // Set window title and buttons auto ft = Formatter::Common(); @@ -896,24 +876,20 @@ static std::vector _window_editor_object_selection_widgets = { installTrackWidget.type = WindowWidgetType::Empty; } - // Align tabs, hide advanced ones - bool advancedMode = (list_information_type & 1) != 0; + // Align main tabs int32_t x = 3; for (size_t i = 0; i < std::size(ObjectSelectionPages); i++) { auto& widget = widgets[WIDX_TAB_1 + i]; - if ((!advancedMode && (ObjectSelectionPages[i].Flags & ObjectPageFlags::isAdvanced)) - || ObjectSelectionPages[i].Image == static_cast(SPR_NONE)) - { - widget.type = WindowWidgetType::Empty; - } - else + if (ObjectSelectionPages[i].Image != static_cast(SPR_NONE)) { widget.type = WindowWidgetType::Tab; widget.left = x; widget.right = x + 30; x += 31; } + else + widget.type = WindowWidgetType::Empty; } if (Config::Get().general.DebuggingTools) @@ -923,7 +899,6 @@ static std::vector _window_editor_object_selection_widgets = { if (gScreenFlags & (SCREEN_FLAGS_TRACK_MANAGER | SCREEN_FLAGS_TRACK_DESIGNER)) { - widgets[WIDX_ADVANCED].type = WindowWidgetType::Empty; for (size_t i = 1; i < std::size(ObjectSelectionPages); i++) { widgets[WIDX_TAB_1 + i].type = WindowWidgetType::Empty; @@ -931,10 +906,7 @@ static std::vector _window_editor_object_selection_widgets = { x = 150; } else - { - widgets[WIDX_ADVANCED].type = WindowWidgetType::Button; x = 300; - } widgets[WIDX_FILTER_DROPDOWN].type = WindowWidgetType::Button; widgets[WIDX_LIST].right = width - (WW - 587) - x; @@ -1026,7 +998,7 @@ static std::vector _window_editor_object_selection_widgets = { // Draw sub-tab images, if applicable auto& currentPage = ObjectSelectionPages[selected_tab]; - if (currentPage.Flags & ObjectPageFlags::hasSubTabs) + if (!currentPage.subTabs.empty()) { for (auto i = 0u; i < currentPage.subTabs.size(); i++) { diff --git a/src/openrct2/interface/Window.h b/src/openrct2/interface/Window.h index ccb8f87b88..8d5ee51541 100644 --- a/src/openrct2/interface/Window.h +++ b/src/openrct2/interface/Window.h @@ -364,7 +364,7 @@ constexpr int32_t WC_PEEP__WIDX_PICKUP = 14; constexpr int32_t WC_TRACK_DESIGN_LIST__WIDX_ROTATE = 8; constexpr int32_t WC_TRACK_DESIGN_PLACE__WIDX_ROTATE = 3; constexpr int32_t WC_MAP__WIDX_ROTATE_90 = 24; -constexpr int32_t WC_EDITOR_OBJECT_SELECTION__WIDX_TAB_1 = 22; +constexpr int32_t WC_EDITOR_OBJECT_SELECTION__WIDX_TAB_1 = 21; constexpr int32_t WC_STAFF__WIDX_PICKUP = 9; constexpr int32_t WC_TILE_INSPECTOR__WIDX_BUTTON_ROTATE = 13; constexpr int32_t WC_TILE_INSPECTOR__WIDX_BUTTON_COPY = 16; From bc04f2be65b3e6cf4208562e91df149033e654ce Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Tue, 23 Jul 2024 14:29:09 +0200 Subject: [PATCH 06/12] Make filter dropdown an actual dropdown --- .../windows/EditorObjectSelection.cpp | 62 +++++++++---------- src/openrct2/interface/Window.h | 2 +- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index e2b6d95758..a7ff723dbb 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -193,6 +193,7 @@ namespace OpenRCT2::Ui::Windows WIDX_PREVIEW, WIDX_INSTALL_TRACK, WIDX_FILTER_DROPDOWN, + WIDX_FILTER_DROPDOWN_BTN, WIDX_FILTER_TEXT_BOX, WIDX_FILTER_CLEAR_BUTTON, WIDX_FILTER_RIDE_TAB_FRAME, @@ -214,31 +215,31 @@ namespace OpenRCT2::Ui::Windows static bool _window_editor_object_selection_widgets_initialised; // clang-format off -static std::vector _window_editor_object_selection_widgets = { - WINDOW_SHIM(WINDOW_TITLE, WW, WH), - MakeWidget({ 0, 43}, {WW, 357}, WindowWidgetType::Resize, WindowColour::Secondary ), - MakeWidget({ 4, 60}, {288, 277}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL ), - MakeWidget({391, 45}, {114, 114}, WindowWidgetType::FlatBtn, WindowColour::Secondary ), - MakeWidget({350, 22}, {122, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_INSTALL_NEW_TRACK_DESIGN, STR_INSTALL_NEW_TRACK_DESIGN_TIP ), - MakeWidget({470, 22}, {114, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_OBJECT_FILTER, STR_OBJECT_FILTER_TIP ), - MakeWidget({ 4, 45}, {211, 14}, WindowWidgetType::TextBox, WindowColour::Secondary ), - MakeWidget({218, 45}, { 70, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_OBJECT_SEARCH_CLEAR ), - MakeWidget({ 3, 73}, {285, 4}, WindowWidgetType::ImgBtn, WindowColour::Secondary ), - MakeTab ({ 3, 47}), - MakeTab ({ 34, 47}), - MakeTab ({ 65, 47}), - MakeTab ({ 96, 47}), - MakeTab ({127, 47}), - MakeTab ({158, 47}), - MakeTab ({189, 47}), - MakeWidget({ 4, 80}, {145, 14}, WindowWidgetType::TableHeader, WindowColour::Secondary ), - MakeWidget({149, 80}, {143, 14}, WindowWidgetType::TableHeader, WindowColour::Secondary ), - MakeWidget({700, 50}, { 24, 24}, WindowWidgetType::ImgBtn, WindowColour::Primary, SPR_G2_RELOAD, STR_RELOAD_OBJECT_TIP ), - MakeTab ({ 3, 17}, STR_STRING_DEFINED_TOOLTIP ), - // Copied object type times... + static std::vector _window_editor_object_selection_widgets = { + WINDOW_SHIM(WINDOW_TITLE, WW, WH), + MakeWidget ({ 0, 43}, {WW, 357}, WindowWidgetType::Resize, WindowColour::Secondary ), + MakeWidget ({ 4, 60}, {288, 277}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL ), + MakeWidget ({391, 45}, {114, 114}, WindowWidgetType::FlatBtn, WindowColour::Secondary ), + MakeWidget ({350, 22}, {122, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_INSTALL_NEW_TRACK_DESIGN, STR_INSTALL_NEW_TRACK_DESIGN_TIP ), + MakeDropdownWidgets({470, 22}, {114, 14}, WindowWidgetType::DropdownMenu, WindowColour::Primary, STR_OBJECT_FILTER, STR_OBJECT_FILTER_TIP ), + MakeWidget ({ 4, 45}, {211, 14}, WindowWidgetType::TextBox, WindowColour::Secondary ), + MakeWidget ({218, 45}, { 70, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_OBJECT_SEARCH_CLEAR ), + MakeWidget ({ 3, 73}, {285, 4}, WindowWidgetType::ImgBtn, WindowColour::Secondary ), + MakeTab ({ 3, 47}), + MakeTab ({ 34, 47}), + MakeTab ({ 65, 47}), + MakeTab ({ 96, 47}), + MakeTab ({127, 47}), + MakeTab ({158, 47}), + MakeTab ({189, 47}), + MakeWidget ({ 4, 80}, {145, 14}, WindowWidgetType::TableHeader, WindowColour::Secondary ), + MakeWidget ({149, 80}, {143, 14}, WindowWidgetType::TableHeader, WindowColour::Secondary ), + MakeWidget ({700, 50}, { 24, 24}, WindowWidgetType::ImgBtn, WindowColour::Primary, SPR_G2_RELOAD, STR_RELOAD_OBJECT_TIP ), + MakeTab ({ 3, 17}, STR_STRING_DEFINED_TOOLTIP ), + // Copied object type times... - kWidgetsEnd, -}; + kWidgetsEnd, + }; // clang-format on #pragma endregion @@ -487,7 +488,7 @@ static std::vector _window_editor_object_selection_widgets = { switch (widgetIndex) { - case WIDX_FILTER_DROPDOWN: + case WIDX_FILTER_DROPDOWN_BTN: gDropdownItems[DDIX_FILTER_RCT1].Format = STR_TOGGLE_OPTION; gDropdownItems[DDIX_FILTER_AA].Format = STR_TOGGLE_OPTION; @@ -519,10 +520,10 @@ static std::vector _window_editor_object_selection_widgets = { gDropdownItems[DDIX_FILTER_NONSELECTED].Args = STR_NON_SELECTED_ONLY; } + auto& ddWidget = widgets[WIDX_FILTER_DROPDOWN]; WindowDropdownShowText( - { windowPos.x + widgets[widgetIndex].left, windowPos.y + widgets[widgetIndex].top }, - widgets[widgetIndex].height() + 1, colours[widgets[widgetIndex].colour], Dropdown::Flag::StayOpen, - _numSourceGameItems + numSelectionItems); + { windowPos.x + ddWidget.left, windowPos.y + ddWidget.top }, ddWidget.height() + 1, + colours[ddWidget.colour], Dropdown::Flag::StayOpen, _numSourceGameItems + numSelectionItems); for (int32_t i = 0; i < _numSourceGameItems; i++) { @@ -548,7 +549,7 @@ static std::vector _window_editor_object_selection_widgets = { switch (widgetIndex) { - case WIDX_FILTER_DROPDOWN: + case WIDX_FILTER_DROPDOWN_BTN: if (dropdownIndex == DDIX_FILTER_SELECTED) { _filter_flags ^= FILTER_SELECTED; @@ -844,8 +845,7 @@ static std::vector _window_editor_object_selection_widgets = { widgets[WIDX_LIST].bottom = height - 14; widgets[WIDX_PREVIEW].left = width - 209; widgets[WIDX_PREVIEW].right = width - 96; - widgets[WIDX_FILTER_DROPDOWN].left = width - 130; - widgets[WIDX_FILTER_DROPDOWN].right = width - 9; + ResizeDropdown(WIDX_FILTER_DROPDOWN, { width - 130, 22 }, { 122, 14 }); widgets[WIDX_INSTALL_TRACK].left = width - 250; widgets[WIDX_INSTALL_TRACK].right = width - 137; widgets[WIDX_RELOAD_OBJECT].left = width - 9 - 24; diff --git a/src/openrct2/interface/Window.h b/src/openrct2/interface/Window.h index 8d5ee51541..ccb8f87b88 100644 --- a/src/openrct2/interface/Window.h +++ b/src/openrct2/interface/Window.h @@ -364,7 +364,7 @@ constexpr int32_t WC_PEEP__WIDX_PICKUP = 14; constexpr int32_t WC_TRACK_DESIGN_LIST__WIDX_ROTATE = 8; constexpr int32_t WC_TRACK_DESIGN_PLACE__WIDX_ROTATE = 3; constexpr int32_t WC_MAP__WIDX_ROTATE_90 = 24; -constexpr int32_t WC_EDITOR_OBJECT_SELECTION__WIDX_TAB_1 = 21; +constexpr int32_t WC_EDITOR_OBJECT_SELECTION__WIDX_TAB_1 = 22; constexpr int32_t WC_STAFF__WIDX_PICKUP = 9; constexpr int32_t WC_TILE_INSPECTOR__WIDX_BUTTON_ROTATE = 13; constexpr int32_t WC_TILE_INSPECTOR__WIDX_BUTTON_COPY = 16; From a55b1ec17c84ce98bcb880e5606d1e3297b02b1f Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Tue, 23 Jul 2024 14:10:39 +0200 Subject: [PATCH 07/12] Refactor preview pane positioning logic --- .../windows/EditorObjectSelection.cpp | 89 ++++++++++--------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index a7ff723dbb..f9e5078fc9 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -122,7 +122,8 @@ namespace OpenRCT2::Ui::Windows static constexpr StringId WINDOW_TITLE = STR_OBJECT_SELECTION; static constexpr int32_t WH = 400; - static constexpr int32_t WW = 755; + static constexpr int32_t WW = 600; + static constexpr auto kPreviewSize = 113; struct ObjectSubTab { @@ -234,7 +235,7 @@ namespace OpenRCT2::Ui::Windows MakeTab ({189, 47}), MakeWidget ({ 4, 80}, {145, 14}, WindowWidgetType::TableHeader, WindowColour::Secondary ), MakeWidget ({149, 80}, {143, 14}, WindowWidgetType::TableHeader, WindowColour::Secondary ), - MakeWidget ({700, 50}, { 24, 24}, WindowWidgetType::ImgBtn, WindowColour::Primary, SPR_G2_RELOAD, STR_RELOAD_OBJECT_TIP ), + MakeWidget ({700, 50}, { 24, 24}, WindowWidgetType::ImgBtn, WindowColour::Secondary, SPR_G2_RELOAD, STR_RELOAD_OBJECT_TIP ), MakeTab ({ 3, 17}, STR_STRING_DEFINED_TOOLTIP ), // Copied object type times... @@ -903,29 +904,23 @@ namespace OpenRCT2::Ui::Windows { widgets[WIDX_TAB_1 + i].type = WindowWidgetType::Empty; } - x = 150; } - else - x = 300; - - widgets[WIDX_FILTER_DROPDOWN].type = WindowWidgetType::Button; - widgets[WIDX_LIST].right = width - (WW - 587) - x; - widgets[WIDX_PREVIEW].left = width - (WW - 537) - (x / 2); - widgets[WIDX_PREVIEW].right = widgets[WIDX_PREVIEW].left + 113; - widgets[WIDX_FILTER_RIDE_TAB_FRAME].right = widgets[WIDX_LIST].right; // Do we have any sub-tabs? const auto& currentPage = ObjectSelectionPages[selected_tab]; const bool hasSubTabs = !currentPage.subTabs.empty(); - widgets[WIDX_LIST].top = (hasSubTabs ? 118 : 60); + widgets[WIDX_LIST].right = width / 2 - 2; + widgets[WIDX_FILTER_RIDE_TAB_FRAME].right = widgets[WIDX_LIST].right; + widgets[WIDX_FILTER_TEXT_BOX].right = widgets[WIDX_LIST].right - 77; - widgets[WIDX_FILTER_TEXT_BOX].top = (hasSubTabs ? 79 : 45); - widgets[WIDX_FILTER_TEXT_BOX].bottom = (hasSubTabs ? 92 : 58); + widgets[WIDX_FILTER_TEXT_BOX].top = (hasSubTabs ? 79 : 48); + widgets[WIDX_FILTER_TEXT_BOX].bottom = (hasSubTabs ? 92 : 61); + widgets[WIDX_FILTER_CLEAR_BUTTON].left = widgets[WIDX_LIST].right - 73; widgets[WIDX_FILTER_CLEAR_BUTTON].right = widgets[WIDX_LIST].right; - widgets[WIDX_FILTER_CLEAR_BUTTON].top = (hasSubTabs ? 79 : 45); - widgets[WIDX_FILTER_CLEAR_BUTTON].bottom = (hasSubTabs ? 92 : 58); + widgets[WIDX_FILTER_CLEAR_BUTTON].top = (hasSubTabs ? 79 : 48); + widgets[WIDX_FILTER_CLEAR_BUTTON].bottom = (hasSubTabs ? 92 : 61); // Toggle sub-tab visibility const auto numSubTabs = static_cast(currentPage.subTabs.size()); @@ -972,12 +967,15 @@ namespace OpenRCT2::Ui::Windows widgets[WIDX_LIST].top = widgets[WIDX_FILTER_TEXT_BOX].bottom + 2; } + + widgets[WIDX_PREVIEW].top = widgets[WIDX_FILTER_TEXT_BOX].top; + widgets[WIDX_PREVIEW].bottom = widgets[WIDX_PREVIEW].top + kPreviewSize; + widgets[WIDX_PREVIEW].left = width * 3 / 4 - kPreviewSize / 2; + widgets[WIDX_PREVIEW].right = widgets[WIDX_PREVIEW].left + kPreviewSize; } void OnDraw(DrawPixelInfo& dpi) override { - int32_t _width; - DrawWidgets(dpi); // Draw main tab images @@ -1072,30 +1070,18 @@ namespace OpenRCT2::Ui::Windows if (selected_list_item == -1 || _loadedObject == nullptr) return; - ObjectListItem* listItem = &_listItems[selected_list_item]; - // Draw preview { DrawPixelInfo clipDPI; auto screenPos = windowPos + ScreenCoordsXY{ previewWidget.left + 1, previewWidget.top + 1 }; - _width = previewWidget.width() - 1; - int32_t _height = previewWidget.height() - 1; - if (ClipDrawPixelInfo(clipDPI, dpi, screenPos, _width, _height)) + int32_t previewWidth = previewWidget.width() - 1; + int32_t previewHeight = previewWidget.height() - 1; + if (ClipDrawPixelInfo(clipDPI, dpi, screenPos, previewWidth, previewHeight)) { - _loadedObject->DrawPreview(clipDPI, _width, _height); + _loadedObject->DrawPreview(clipDPI, previewWidth, previewHeight); } } - // Draw name of object - { - auto screenPos = windowPos + ScreenCoordsXY{ previewWidget.midX() + 1, previewWidget.bottom + 3 }; - _width = this->width - widgets[WIDX_LIST].right - 6; - auto ft = Formatter(); - ft.Add(STR_STRING); - ft.Add(listItem->repositoryItem->Name.c_str()); - DrawTextEllipsised(dpi, screenPos, _width, STR_WINDOW_COLOUR_2_STRINGID, ft, { TextAlignment::CENTRE }); - } - DrawDescriptions(dpi); DrawDebugData(dpi); } @@ -1224,14 +1210,30 @@ namespace OpenRCT2::Ui::Windows void DrawDescriptions(DrawPixelInfo& dpi) { - const auto& widget = widgets[WIDX_PREVIEW]; - auto screenPos = windowPos + ScreenCoordsXY{ widgets[WIDX_LIST].right + 4, widget.bottom + 23 }; - auto _width2 = windowPos.x + this->width - screenPos.x - 4; + auto screenPos = windowPos + ScreenCoordsXY{ widgets[WIDX_PREVIEW].midX(), widgets[WIDX_PREVIEW].bottom + 3 }; + auto descriptionWidth = width - widgets[WIDX_LIST].right - 12; + // Draw name of object + { + ObjectListItem* listItem = &_listItems[selected_list_item]; + + auto ft = Formatter(); + ft.Add(STR_STRING); + ft.Add(listItem->repositoryItem->Name.c_str()); + screenPos.y += DrawTextWrapped( + dpi, screenPos, descriptionWidth, STR_WINDOW_COLOUR_2_STRINGID, ft, { TextAlignment::CENTRE }); + + // Leave some space between name and description + screenPos.y += kListRowHeight; + } + + screenPos.x = windowPos.x + widgets[WIDX_LIST].right + 6; + + // Compatibility object? if (_loadedObject->IsCompatibilityObject()) { screenPos.y += DrawTextWrapped( - dpi, screenPos, _width2, STR_OBJECT_SELECTION_COMPAT_OBJECT_DESCRIPTION, {}, + dpi, screenPos, descriptionWidth, STR_OBJECT_SELECTION_COMPAT_OBJECT_DESCRIPTION, {}, { COLOUR_BRIGHT_RED }) + kListRowHeight; } @@ -1243,7 +1245,8 @@ namespace OpenRCT2::Ui::Windows ft.Add(STR_STRING); ft.Add(description.c_str()); - screenPos.y += DrawTextWrapped(dpi, screenPos, _width2, STR_WINDOW_COLOUR_2_STRINGID, ft) + kListRowHeight; + screenPos.y += DrawTextWrapped(dpi, screenPos, descriptionWidth, STR_WINDOW_COLOUR_2_STRINGID, ft); + screenPos.y += kListRowHeight; } if (GetSelectedObjectType() == ObjectType::Ride) { @@ -1264,7 +1267,7 @@ namespace OpenRCT2::Ui::Windows } auto ft = Formatter(); ft.Add(sells.c_str()); - screenPos.y += DrawTextWrapped(dpi, screenPos, _width2, STR_RIDE_OBJECT_SHOP_SELLS, ft) + 2; + screenPos.y += DrawTextWrapped(dpi, screenPos, descriptionWidth, STR_RIDE_OBJECT_SHOP_SELLS, ft) + 2; } } else if (GetSelectedObjectType() == ObjectType::SceneryGroup) @@ -1272,11 +1275,11 @@ namespace OpenRCT2::Ui::Windows const auto* sceneryGroupObject = reinterpret_cast(_loadedObject.get()); auto ft = Formatter(); ft.Add(sceneryGroupObject->GetNumIncludedObjects()); - screenPos.y += DrawTextWrapped(dpi, screenPos, _width2, STR_INCLUDES_X_OBJECTS, ft) + 2; + screenPos.y += DrawTextWrapped(dpi, screenPos, descriptionWidth, STR_INCLUDES_X_OBJECTS, ft) + 2; } else if (GetSelectedObjectType() == ObjectType::Music) { - screenPos.y += DrawTextWrapped(dpi, screenPos, _width2, STR_MUSIC_OBJECT_TRACK_HEADER) + 2; + screenPos.y += DrawTextWrapped(dpi, screenPos, descriptionWidth, STR_MUSIC_OBJECT_TRACK_HEADER) + 2; const auto* musicObject = reinterpret_cast(_loadedObject.get()); for (size_t i = 0; i < musicObject->GetTrackCount(); i++) { @@ -1289,7 +1292,7 @@ namespace OpenRCT2::Ui::Windows auto ft = Formatter(); ft.Add(track->Name.c_str()); ft.Add(track->Composer.c_str()); - screenPos.y += DrawTextWrapped(dpi, screenPos + ScreenCoordsXY{ 10, 0 }, _width2, stringId, ft); + screenPos.y += DrawTextWrapped(dpi, screenPos + ScreenCoordsXY{ 10, 0 }, descriptionWidth, stringId, ft); } } } From b87e8fd1937b97ee2336e38d60da578f841f0a0c Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Sun, 28 Jul 2024 14:52:35 +0200 Subject: [PATCH 08/12] Group entrances and terrain objects as well --- .../windows/EditorObjectSelection.cpp | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index f9e5078fc9..b2f5cfd10a 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -169,16 +169,24 @@ namespace OpenRCT2::Ui::Windows { STR_OBJECT_SELECTION_PATH_SIGNS, ObjectType::Banners, FILTER_NONE, SPR_TAB_SCENERY_SIGNAGE, 1, 1 }, }; + static ObjectSubTab kEntrancesObjectSubTabs[] = { + { STR_OBJECT_SELECTION_PARK_ENTRANCE, ObjectType::ParkEntrance, FILTER_NONE, SPR_TAB_PARK, 1, 1 }, + { STR_OBJECT_SELECTION_STATIONS, ObjectType::Station, FILTER_NONE, SPR_G2_RIDE_STATION_TAB, 1, 1 }, + }; + + static ObjectSubTab kTerrainObjectSubTabs[] = { + { STR_OBJECT_SELECTION_TERRAIN_SURFACES, ObjectType::TerrainSurface, FILTER_NONE, SPR_G2_TAB_LAND, 1, 1 }, + { STR_OBJECT_SELECTION_TERRAIN_EDGES, ObjectType::TerrainEdge, FILTER_NONE, SPR_G2_TERRAIN_EDGE_TAB, 1, 1 }, + { STR_OBJECT_SELECTION_WATER, ObjectType::Water, FILTER_NONE, SPR_TAB_WATER, 1, 1 }, + }; + static constexpr ObjectPageDesc ObjectSelectionPages[] = { - { STR_OBJECT_SELECTION_RIDE_VEHICLES_ATTRACTIONS, ObjectType::Ride, SPR_TAB_RIDE_16, kRideObjectSubTabs }, - { STR_OBJECT_SELECTION_SCENERY_GROUPS, ObjectType::SceneryGroup, SPR_TAB_SCENERY_STATUES, kSceneryObjectSubTabs }, - { STR_OBJECT_SELECTION_FOOTPATH_SURFACES, ObjectType::FootpathSurface, SPR_G2_LEGACY_PATH_TAB, kPathObjectSubTabs }, - { STR_OBJECT_SELECTION_PARK_ENTRANCE, ObjectType::ParkEntrance, SPR_TAB_PARK, {} }, - { STR_OBJECT_SELECTION_STATIONS, ObjectType::Station, SPR_G2_RIDE_STATION_TAB, {} }, - { STR_OBJECT_SELECTION_MUSIC, ObjectType::Music, SPR_TAB_MUSIC_0, {} }, - { STR_OBJECT_SELECTION_TERRAIN_SURFACES, ObjectType::TerrainSurface, SPR_G2_TAB_LAND, {} }, - { STR_OBJECT_SELECTION_TERRAIN_EDGES, ObjectType::TerrainEdge, SPR_G2_TERRAIN_EDGE_TAB, {} }, - { STR_OBJECT_SELECTION_WATER, ObjectType::Water, SPR_TAB_WATER, {} }, + { STR_OBJECT_SELECTION_RIDE_VEHICLES_ATTRACTIONS, ObjectType::Ride, SPR_TAB_RIDE_16, kRideObjectSubTabs }, + { STR_OBJECT_SELECTION_SCENERY_GROUPS, ObjectType::SceneryGroup, SPR_TAB_SCENERY_STATUES, kSceneryObjectSubTabs }, + { STR_OBJECT_SELECTION_FOOTPATH_SURFACES, ObjectType::FootpathSurface, SPR_G2_LEGACY_PATH_TAB, kPathObjectSubTabs }, + { STR_OBJECT_SELECTION_PARK_ENTRANCE, ObjectType::ParkEntrance, SPR_TAB_PARK, kEntrancesObjectSubTabs }, + { STR_OBJECT_SELECTION_TERRAIN_SURFACES, ObjectType::TerrainSurface, SPR_G2_TAB_LAND, kTerrainObjectSubTabs }, + { STR_OBJECT_SELECTION_MUSIC, ObjectType::Music, SPR_TAB_MUSIC_0, {} }, }; // clang-format on From 2be82c280dc372175794d78505b17039013cec40 Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Sun, 28 Jul 2024 14:57:56 +0200 Subject: [PATCH 09/12] Replace macros with isFilterActive function --- .../windows/EditorObjectSelection.cpp | 61 ++++++++----------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index b2f5cfd10a..c4e157fa6d 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -108,17 +108,10 @@ namespace OpenRCT2::Ui::Windows static char _filter_string[MAX_PATH]; -#define _FILTER_ALL ((_filter_flags & FILTER_ALL) == FILTER_ALL) -#define _FILTER_RCT1 (_filter_flags & FILTER_RCT1) -#define _FILTER_AA (_filter_flags & FILTER_AA) -#define _FILTER_LL (_filter_flags & FILTER_LL) -#define _FILTER_RCT2 (_filter_flags & FILTER_RCT2) -#define _FILTER_WW (_filter_flags & FILTER_WW) -#define _FILTER_TT (_filter_flags & FILTER_TT) -#define _FILTER_OO (_filter_flags & FILTER_OO) -#define _FILTER_CUSTOM (_filter_flags & FILTER_CUSTOM) -#define _FILTER_SELECTED (_filter_flags & FILTER_SELECTED) -#define _FILTER_NONSELECTED (_filter_flags & FILTER_NONSELECTED) + static bool isFilterActive(const uint16_t filter) + { + return (_filter_flags & filter) == filter; + } static constexpr StringId WINDOW_TITLE = STR_OBJECT_SELECTION; static constexpr int32_t WH = 400; @@ -544,8 +537,8 @@ namespace OpenRCT2::Ui::Windows if (!(gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER)) { - Dropdown::SetChecked(DDIX_FILTER_SELECTED, _FILTER_SELECTED != 0); - Dropdown::SetChecked(DDIX_FILTER_NONSELECTED, _FILTER_NONSELECTED != 0); + Dropdown::SetChecked(DDIX_FILTER_SELECTED, isFilterActive(FILTER_SELECTED)); + Dropdown::SetChecked(DDIX_FILTER_NONSELECTED, isFilterActive(FILTER_NONSELECTED)); } break; } @@ -659,7 +652,7 @@ namespace OpenRCT2::Ui::Windows return; } - if (_FILTER_SELECTED || _FILTER_NONSELECTED) + if (isFilterActive(FILTER_SELECTED) || isFilterActive(FILTER_NONSELECTED)) { FilterUpdateCounts(); VisibleListRefresh(); @@ -1370,15 +1363,15 @@ namespace OpenRCT2::Ui::Windows { return true; } - if (_FILTER_SELECTED == _FILTER_NONSELECTED) + if (isFilterActive(FILTER_SELECTED) == isFilterActive(FILTER_NONSELECTED)) { return true; } - if (_FILTER_SELECTED && objectFlag & ObjectSelectionFlags::Selected) + if (isFilterActive(FILTER_SELECTED) && (objectFlag & ObjectSelectionFlags::Selected)) { return true; } - if (_FILTER_NONSELECTED && !(objectFlag & ObjectSelectionFlags::Selected)) + if (isFilterActive(FILTER_NONSELECTED) && !(objectFlag & ObjectSelectionFlags::Selected)) { return true; } @@ -1439,27 +1432,27 @@ namespace OpenRCT2::Ui::Windows bool SourcesMatch(ObjectSourceGame source) { // clang-format off - return (_FILTER_RCT1 && source == ObjectSourceGame::RCT1) || - (_FILTER_AA && source == ObjectSourceGame::AddedAttractions) || - (_FILTER_LL && source == ObjectSourceGame::LoopyLandscapes) || - (_FILTER_RCT2 && source == ObjectSourceGame::RCT2) || - (_FILTER_WW && source == ObjectSourceGame::WackyWorlds) || - (_FILTER_TT && source == ObjectSourceGame::TimeTwister) || - (_FILTER_OO && source == ObjectSourceGame::OpenRCT2Official) || - (_FILTER_CUSTOM && - source != ObjectSourceGame::RCT1 && - source != ObjectSourceGame::AddedAttractions && - source != ObjectSourceGame::LoopyLandscapes && - source != ObjectSourceGame::RCT2 && - source != ObjectSourceGame::WackyWorlds && - source != ObjectSourceGame::TimeTwister && - source != ObjectSourceGame::OpenRCT2Official); + return (isFilterActive(FILTER_RCT1) && source == ObjectSourceGame::RCT1) || + (isFilterActive(FILTER_AA) && source == ObjectSourceGame::AddedAttractions) || + (isFilterActive(FILTER_LL) && source == ObjectSourceGame::LoopyLandscapes) || + (isFilterActive(FILTER_RCT2) && source == ObjectSourceGame::RCT2) || + (isFilterActive(FILTER_WW) && source == ObjectSourceGame::WackyWorlds) || + (isFilterActive(FILTER_TT) && source == ObjectSourceGame::TimeTwister) || + (isFilterActive(FILTER_OO) && source == ObjectSourceGame::OpenRCT2Official) || + (isFilterActive(FILTER_CUSTOM) && + source != ObjectSourceGame::RCT1 && + source != ObjectSourceGame::AddedAttractions && + source != ObjectSourceGame::LoopyLandscapes && + source != ObjectSourceGame::RCT2 && + source != ObjectSourceGame::WackyWorlds && + source != ObjectSourceGame::TimeTwister && + source != ObjectSourceGame::OpenRCT2Official); // clang-format on } bool FilterSource(const ObjectRepositoryItem* item) { - if (_FILTER_ALL) + if (isFilterActive(FILTER_ALL)) return true; for (auto source : item->Sources) @@ -1491,7 +1484,7 @@ namespace OpenRCT2::Ui::Windows void FilterUpdateCounts() { - if (!_FILTER_ALL || _filter_string[0] != '\0') + if (!isFilterActive(FILTER_ALL) || _filter_string[0] != '\0') { const auto& selectionFlags = _objectSelectionFlags; std::fill(std::begin(_filter_object_counts), std::end(_filter_object_counts), 0); From 15944738c79dbd30195bc30eb92f7235d1390d40 Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Sun, 28 Jul 2024 15:40:44 +0200 Subject: [PATCH 10/12] Update filter dropdown caption with (number of) active source(s) --- data/language/en-GB.txt | 3 + src/openrct2-ui/UiStringIds.h | 3 + .../windows/EditorObjectSelection.cpp | 73 ++++++++++++------- 3 files changed, 51 insertions(+), 28 deletions(-) diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index f653caea1d..49eae24781 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -3724,6 +3724,9 @@ STR_6649 :Loading scenario… STR_6650 :Loading saved game… STR_6651 :{STRING} ({COMMA32}%) STR_6652 :Error Window +STR_6653 :All sources shown +STR_6654 :Showing {POP16}{UINT16} sources +STR_6655 :Only ‘{POP16}{STRINGID}’ ############# # Scenarios # diff --git a/src/openrct2-ui/UiStringIds.h b/src/openrct2-ui/UiStringIds.h index a5fd2e306c..4af48460ae 100644 --- a/src/openrct2-ui/UiStringIds.h +++ b/src/openrct2-ui/UiStringIds.h @@ -493,6 +493,7 @@ namespace OpenRCT2 STR_OBJECT_SELECTION = 3181, STR_OBJECT_SELECTION_ADVANCED = 3364, STR_OBJECT_SELECTION_ADVANCED_TIP = 3365, + STR_OBJECT_SELECTION_ALL_SOURCES_SHOWN = 6653, STR_OBJECT_SELECTION_COMPAT_OBJECT_DESCRIPTION = 6550, STR_OBJECT_SELECTION_FALLBACK_IMAGES_WARNING = 6516, STR_OBJECT_SELECTION_FOOTPATHS = 3189, @@ -500,6 +501,7 @@ namespace OpenRCT2 STR_OBJECT_SELECTION_FOOTPATH_SURFACES = 6444, STR_OBJECT_SELECTION_LARGE_SCENERY = 3186, STR_OBJECT_SELECTION_MUSIC = 6273, + STR_OBJECT_SELECTION_ONLY_STRINGID = 6655, STR_OBJECT_SELECTION_PATH_EXTRAS = 3190, STR_OBJECT_SELECTION_PATH_SIGNS = 3188, STR_OBJECT_SELECTION_RIDE_VEHICLES_ATTRACTIONS = 3184, @@ -511,6 +513,7 @@ namespace OpenRCT2 STR_OBJECT_SELECTION_TERRAIN_SURFACES = 6270, STR_OBJECT_SELECTION_WALLS_FENCES = 3187, STR_OBJECT_SELECTION_WATER = 3193, + STR_OBJECT_SELECTION_SHOWING_N_SOURCES = 6654, STR_OBJECT_USES_FALLBACK_IMAGES = 6515, STR_RELOAD_OBJECT_TIP = 6613, STR_RIDE_OBJECT_SHOP_SELLS = 6452, diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index c4e157fa6d..89abf26fa4 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -7,6 +7,7 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include #include #include #include @@ -67,10 +68,11 @@ namespace OpenRCT2::Ui::Windows FILTER_SELECTED = (1 << 14), FILTER_NONSELECTED = (1 << 15), - FILTER_RIDES = FILTER_RIDE_TRANSPORT | FILTER_RIDE_GENTLE | FILTER_RIDE_COASTER | FILTER_RIDE_THRILL | FILTER_RIDE_WATER - | FILTER_RIDE_STALL, - FILTER_ALL = FILTER_RIDES | FILTER_RCT1 | FILTER_AA | FILTER_LL | FILTER_RCT2 | FILTER_WW | FILTER_TT | FILTER_OO - | FILTER_CUSTOM | FILTER_SELECTED | FILTER_NONSELECTED, + FILTER_RIDES_ALL = FILTER_RIDE_TRANSPORT | FILTER_RIDE_GENTLE | FILTER_RIDE_COASTER | FILTER_RIDE_THRILL + | FILTER_RIDE_WATER | FILTER_RIDE_STALL, + FILTER_SOURCES_ALL = FILTER_RCT1 | FILTER_AA | FILTER_LL | FILTER_RCT2 | FILTER_WW | FILTER_TT | FILTER_OO + | FILTER_CUSTOM, + FILTER_ALL = FILTER_RIDES_ALL | FILTER_SOURCES_ALL | FILTER_SELECTED | FILTER_NONSELECTED, }; enum @@ -79,7 +81,7 @@ namespace OpenRCT2::Ui::Windows RIDE_SORT_RIDE }; - enum + enum : uint8_t { DDIX_FILTER_RCT1, DDIX_FILTER_AA, @@ -116,6 +118,7 @@ namespace OpenRCT2::Ui::Windows static constexpr StringId WINDOW_TITLE = STR_OBJECT_SELECTION; static constexpr int32_t WH = 400; static constexpr int32_t WW = 600; + static constexpr auto kFilterWidth = 150; static constexpr auto kPreviewSize = 113; struct ObjectSubTab @@ -138,7 +141,7 @@ namespace OpenRCT2::Ui::Windows // clang-format off static ObjectSubTab kRideObjectSubTabs[] = { - { STR_OBJECT_FILTER_ALL_RIDES_TIP, ObjectType::Ride, FILTER_RIDES, SPR_G2_INFINITY, 1, 1 }, + { STR_OBJECT_FILTER_ALL_RIDES_TIP, ObjectType::Ride, FILTER_RIDES_ALL, SPR_G2_INFINITY, 1, 1 }, { STR_TRANSPORT_RIDES_TIP, ObjectType::Ride, FILTER_RIDE_TRANSPORT, SPR_TAB_RIDES_TRANSPORT_0, 20, 4 }, { STR_GENTLE_RIDES_TIP, ObjectType::Ride, FILTER_RIDE_GENTLE, SPR_TAB_RIDES_GENTLE_0, 32, 8 }, { STR_ROLLER_COASTERS_TIP, ObjectType::Ride, FILTER_RIDE_COASTER, SPR_TAB_RIDES_ROLLER_COASTERS_0, 10, 2 }, @@ -276,7 +279,7 @@ namespace OpenRCT2::Ui::Windows widgets[WIDX_FILTER_TEXT_BOX].string = _filter_string; - _filter_flags = FILTER_RIDES | Config::Get().interface.ObjectSelectionFilterFlags; + _filter_flags = FILTER_RIDES_ALL | Config::Get().interface.ObjectSelectionFilterFlags; std::fill_n(_filter_string, sizeof(_filter_string), 0x00); WindowInitScrollWidgets(*this); @@ -393,7 +396,7 @@ namespace OpenRCT2::Ui::Windows auto& currentPage = ObjectSelectionPages[selected_tab]; auto& subTabDef = currentPage.subTabs[_selectedSubTab]; - _filter_flags &= ~FILTER_RIDES; + _filter_flags &= ~FILTER_RIDES_ALL; _filter_flags |= subTabDef.flagFilter; Config::Get().interface.ObjectSelectionFilterFlags = _filter_flags; @@ -484,6 +487,12 @@ namespace OpenRCT2::Ui::Windows WindowSetResize(*this, WW, WH, 1200, 1000); } + static constexpr StringId kSourceStringIds[] = { + STR_SCENARIO_CATEGORY_RCT1, STR_SCENARIO_CATEGORY_RCT1_AA, STR_SCENARIO_CATEGORY_RCT1_LL, + STR_ROLLERCOASTER_TYCOON_2_DROPDOWN, STR_OBJECT_FILTER_WW, STR_OBJECT_FILTER_TT, + STR_OBJECT_FILTER_OPENRCT2_OFFICIAL, STR_OBJECT_FILTER_CUSTOM, + }; + void OnMouseDown(WidgetIndex widgetIndex) override { int32_t numSelectionItems = 0; @@ -491,24 +500,11 @@ namespace OpenRCT2::Ui::Windows switch (widgetIndex) { case WIDX_FILTER_DROPDOWN_BTN: - - gDropdownItems[DDIX_FILTER_RCT1].Format = STR_TOGGLE_OPTION; - gDropdownItems[DDIX_FILTER_AA].Format = STR_TOGGLE_OPTION; - gDropdownItems[DDIX_FILTER_LL].Format = STR_TOGGLE_OPTION; - gDropdownItems[DDIX_FILTER_RCT2].Format = STR_TOGGLE_OPTION; - gDropdownItems[DDIX_FILTER_WW].Format = STR_TOGGLE_OPTION; - gDropdownItems[DDIX_FILTER_TT].Format = STR_TOGGLE_OPTION; - gDropdownItems[DDIX_FILTER_OO].Format = STR_TOGGLE_OPTION; - gDropdownItems[DDIX_FILTER_CUSTOM].Format = STR_TOGGLE_OPTION; - - gDropdownItems[DDIX_FILTER_RCT1].Args = STR_SCENARIO_CATEGORY_RCT1; - gDropdownItems[DDIX_FILTER_AA].Args = STR_SCENARIO_CATEGORY_RCT1_AA; - gDropdownItems[DDIX_FILTER_LL].Args = STR_SCENARIO_CATEGORY_RCT1_LL; - gDropdownItems[DDIX_FILTER_RCT2].Args = STR_ROLLERCOASTER_TYCOON_2_DROPDOWN; - gDropdownItems[DDIX_FILTER_WW].Args = STR_OBJECT_FILTER_WW; - gDropdownItems[DDIX_FILTER_TT].Args = STR_OBJECT_FILTER_TT; - gDropdownItems[DDIX_FILTER_OO].Args = STR_OBJECT_FILTER_OPENRCT2_OFFICIAL; - gDropdownItems[DDIX_FILTER_CUSTOM].Args = STR_OBJECT_FILTER_CUSTOM; + for (auto ddIdx = EnumValue(DDIX_FILTER_RCT1); ddIdx <= EnumValue(DDIX_FILTER_CUSTOM); ddIdx++) + { + gDropdownItems[ddIdx].Args = kSourceStringIds[ddIdx]; + gDropdownItems[ddIdx].Format = STR_TOGGLE_OPTION; + } // Track manager cannot select multiple, so only show selection filters if not in track manager if (!(gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER)) @@ -847,7 +843,7 @@ namespace OpenRCT2::Ui::Windows widgets[WIDX_LIST].bottom = height - 14; widgets[WIDX_PREVIEW].left = width - 209; widgets[WIDX_PREVIEW].right = width - 96; - ResizeDropdown(WIDX_FILTER_DROPDOWN, { width - 130, 22 }, { 122, 14 }); + ResizeDropdown(WIDX_FILTER_DROPDOWN, { width - kFilterWidth - 10, 22 }, { kFilterWidth, 14 }); widgets[WIDX_INSTALL_TRACK].left = width - 250; widgets[WIDX_INSTALL_TRACK].right = width - 137; widgets[WIDX_RELOAD_OBJECT].left = width - 9 - 24; @@ -878,6 +874,27 @@ namespace OpenRCT2::Ui::Windows installTrackWidget.type = WindowWidgetType::Empty; } + // Set filter dropdown caption + if (!isFilterActive(FILTER_SOURCES_ALL)) + { + // Only one source active? + uint32_t sources = _filter_flags & FILTER_SOURCES_ALL; + auto numSourcesActive = std::popcount(sources); + if (numSourcesActive == 1) + { + widgets[WIDX_FILTER_DROPDOWN].text = STR_OBJECT_SELECTION_ONLY_STRINGID; + auto firstActiveSource = UtilBitScanForward(sources); + ft.Add(kSourceStringIds[firstActiveSource]); + } + else + { + widgets[WIDX_FILTER_DROPDOWN].text = STR_OBJECT_SELECTION_SHOWING_N_SOURCES; + ft.Add(numSourcesActive); + } + } + else + widgets[WIDX_FILTER_DROPDOWN].text = STR_OBJECT_SELECTION_ALL_SOURCES_SHOWN; + // Align main tabs int32_t x = 3; for (size_t i = 0; i < std::size(ObjectSelectionPages); i++) @@ -1123,7 +1140,7 @@ namespace OpenRCT2::Ui::Windows selected_tab = _page; _selectedSubTab = 0; - _filter_flags |= FILTER_RIDES; + _filter_flags |= FILTER_RIDES_ALL; selected_list_item = -1; scrolls[0].v_top = 0; frame_no = 0; From ed5f53e652ba6e469d497a6a9fcf6055389e44af Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Sun, 28 Jul 2024 18:34:02 +0200 Subject: [PATCH 11/12] Set window title for sub-tabs as well --- src/openrct2-ui/windows/EditorObjectSelection.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index 89abf26fa4..fccfc6141c 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -854,8 +854,6 @@ namespace OpenRCT2::Ui::Windows SetPressedTab(); // Set window title and buttons - auto ft = Formatter::Common(); - ft.Add(ObjectSelectionPages[selected_tab].Caption); auto& titleWidget = widgets[WIDX_TITLE]; auto& installTrackWidget = widgets[WIDX_INSTALL_TRACK]; if (gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER) @@ -874,6 +872,14 @@ namespace OpenRCT2::Ui::Windows installTrackWidget.type = WindowWidgetType::Empty; } + // Set title parameters for current page + const auto& currentPage = ObjectSelectionPages[selected_tab]; + auto ft = Formatter::Common(); + if (!currentPage.subTabs.empty()) + ft.Add(currentPage.subTabs[_selectedSubTab].tooltip); + else + ft.Add(currentPage.Caption); + // Set filter dropdown caption if (!isFilterActive(FILTER_SOURCES_ALL)) { @@ -925,7 +931,6 @@ namespace OpenRCT2::Ui::Windows } // Do we have any sub-tabs? - const auto& currentPage = ObjectSelectionPages[selected_tab]; const bool hasSubTabs = !currentPage.subTabs.empty(); widgets[WIDX_LIST].right = width / 2 - 2; From 021a49fd1923ad6909da383ad8639cd16f87d3e8 Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Sun, 28 Jul 2024 22:24:08 +0200 Subject: [PATCH 12/12] Amend changelog --- distribution/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 40762ab10a..eb1c46ba6b 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -9,6 +9,7 @@ - Feature: [#22272] [Plugin] Expose ride vehicle’s current track type via car trackLocation. - Feature: [#22301] Loading save games or scenarios now indicates loading progress. - Feature: [OpenMusic#54] Added Progressive ride music style (feat. Approaching Nirvana). +- Improved: [#22352] The object selection window now groups relevant object tabs together. - Improved: [#22357] Error messages are now themeable and easier to read. - Improved: [#22361] Add additional colour preset for the Observation Tower. - Change: [#21494] Display pixel density is now taken into account for the initial window scale setting.