mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-23 07:43:01 +01:00
* Fix #24888: Add search for ride list * Cache ride name * Hide unwanted ride list entries rather than rebuilding the list * Minor touchups * Display count of filtered rides/stalls in ride list --------- Co-authored-by: Aaron van Geffen <aaron@aaronweb.net>
This commit is contained in:
committed by
GitHub
parent
1436d8ef2a
commit
b32d29330b
@@ -2,6 +2,7 @@
|
||||
------------------------------------------------------------------------
|
||||
- Feature: [#24949] Add an option to the command line screenshot function to draw debug bounding boxes.
|
||||
- Improved: [#24734] Save files now use Zstd compression for faster saving and smaller files.
|
||||
- Improved: [#24890] The ride list is now searchable.
|
||||
- Improved: [#24893] The ride list now has headers, and can be sorted in both directions.
|
||||
- Improved: [#24921] The command line sprite build command now prints out the images table entry for the compiled sprite file.
|
||||
- Improved: [#24953] Opening the Scenario Editor, Track Designer or Track Designs Manager now display the progress bar.
|
||||
|
||||
@@ -52,6 +52,8 @@ namespace OpenRCT2::Ui::Windows
|
||||
WIDX_TAB_1,
|
||||
WIDX_TAB_2,
|
||||
WIDX_TAB_3,
|
||||
WIDX_SEARCH_TEXT_BOX,
|
||||
WIDX_SEARCH_CLEAR_BUTTON,
|
||||
WIDX_HEADER_NAME,
|
||||
WIDX_HEADER_OTHER,
|
||||
WIDX_HEADER_CUSTOMISE,
|
||||
@@ -69,13 +71,15 @@ namespace OpenRCT2::Ui::Windows
|
||||
makeTab ({ 3, 17}, STR_LIST_RIDES_TIP ), // tab 1
|
||||
makeTab ({ 34, 17}, STR_LIST_SHOPS_AND_STALLS_TIP ), // tab 2
|
||||
makeTab ({ 65, 17}, STR_LIST_KIOSKS_AND_FACILITIES_TIP ), // tab 3
|
||||
makeWidget({ 3, 47}, {150, 14}, WidgetType::tableHeader, WindowColour::secondary ), // name header
|
||||
makeWidget({153, 47}, {147, 14}, WidgetType::tableHeader, WindowColour::secondary ), // other header
|
||||
makeWidget({300, 47}, { 14, 14}, WidgetType::button, WindowColour::secondary, STR_DROPDOWN_GLYPH ), // customise button
|
||||
makeWidget({ 3, 60}, {334, 177}, WidgetType::scroll, WindowColour::secondary, SCROLL_VERTICAL ), // list
|
||||
makeWidget({320, 62}, { 14, 14}, WidgetType::imgBtn, WindowColour::secondary, ImageId(SPR_G2_RCT1_CLOSE_BUTTON_0) ),
|
||||
makeWidget({320, 76}, { 14, 14}, WidgetType::imgBtn, WindowColour::secondary, ImageId(SPR_G2_RCT1_OPEN_BUTTON_0) ),
|
||||
makeWidget({315, 90}, { 24, 24}, WidgetType::flatBtn, WindowColour::secondary, ImageId(SPR_DEMOLISH), STR_QUICK_DEMOLISH_RIDE )
|
||||
makeWidget({ 3, 47}, {284, 14}, WidgetType::textBox, WindowColour::secondary ), // search text box
|
||||
makeWidget({284, 47}, { 50, 14}, WidgetType::button, WindowColour::secondary, STR_OBJECT_SEARCH_CLEAR, STR_CLEAR_SCENERY_TIP ), // search clear button
|
||||
makeWidget({ 3, 62}, {150, 14}, WidgetType::tableHeader, WindowColour::secondary ), // name header
|
||||
makeWidget({153, 62}, {147, 14}, WidgetType::tableHeader, WindowColour::secondary ), // other header
|
||||
makeWidget({300, 62}, { 14, 14}, WidgetType::button, WindowColour::secondary, STR_DROPDOWN_GLYPH ), // customise button
|
||||
makeWidget({ 3, 75}, {334, 177}, WidgetType::scroll, WindowColour::secondary, SCROLL_VERTICAL ), // list
|
||||
makeWidget({320, 77}, { 14, 14}, WidgetType::imgBtn, WindowColour::secondary, ImageId(SPR_G2_RCT1_CLOSE_BUTTON_0) ),
|
||||
makeWidget({320, 91}, { 14, 14}, WidgetType::imgBtn, WindowColour::secondary, ImageId(SPR_G2_RCT1_OPEN_BUTTON_0) ),
|
||||
makeWidget({315,105}, { 24, 24}, WidgetType::flatBtn, WindowColour::secondary, ImageId(SPR_DEMOLISH), STR_QUICK_DEMOLISH_RIDE )
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
@@ -165,11 +169,13 @@ namespace OpenRCT2::Ui::Windows
|
||||
bool _quickDemolishMode = false;
|
||||
InformationType _windowRideListInformationType = INFORMATION_TYPE_STATUS;
|
||||
bool _windowListSortDescending = false;
|
||||
u8string _searchFilter;
|
||||
|
||||
struct RideListEntry
|
||||
{
|
||||
RideId Id;
|
||||
u8string Name;
|
||||
bool Visible;
|
||||
};
|
||||
std::vector<RideListEntry> _rideList;
|
||||
|
||||
@@ -188,6 +194,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
|
||||
_windowRideListInformationType = INFORMATION_TYPE_STATUS;
|
||||
_quickDemolishMode = false;
|
||||
_searchFilter.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -257,6 +264,14 @@ namespace OpenRCT2::Ui::Windows
|
||||
RefreshList();
|
||||
}
|
||||
break;
|
||||
case WIDX_SEARCH_TEXT_BOX:
|
||||
WindowStartTextbox(*this, widgetIndex, _searchFilter, kTextInputSize);
|
||||
break;
|
||||
case WIDX_SEARCH_CLEAR_BUTTON:
|
||||
_searchFilter.clear();
|
||||
ApplySearchQuery();
|
||||
InvalidateWidget(WIDX_SEARCH_TEXT_BOX);
|
||||
break;
|
||||
case WIDX_CLOSE_LIGHT:
|
||||
CloseAllRides();
|
||||
break;
|
||||
@@ -399,13 +414,25 @@ namespace OpenRCT2::Ui::Windows
|
||||
SortList();
|
||||
}
|
||||
|
||||
void OnTextInput(WidgetIndex widgetIndex, std::string_view text) override
|
||||
{
|
||||
if (widgetIndex != WIDX_SEARCH_TEXT_BOX)
|
||||
return;
|
||||
|
||||
if (text == _searchFilter)
|
||||
return;
|
||||
|
||||
_searchFilter.assign(text);
|
||||
ApplySearchQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006B35A1
|
||||
*/
|
||||
ScreenSize OnScrollGetSize(int32_t scrollIndex) override
|
||||
{
|
||||
const auto newHeight = static_cast<int32_t>(_rideList.size() * kScrollableRowHeight);
|
||||
const auto newHeight = static_cast<int32_t>(CountVisibleItems() * kScrollableRowHeight);
|
||||
auto top = std::max(0, newHeight - widgets[WIDX_LIST].bottom + widgets[WIDX_LIST].top + 21);
|
||||
if (top < scrolls[0].contentOffsetY)
|
||||
{
|
||||
@@ -416,14 +443,30 @@ namespace OpenRCT2::Ui::Windows
|
||||
return { 0, newHeight };
|
||||
}
|
||||
|
||||
int32_t GetNthVisibleItemIndex(int32_t target) const
|
||||
{
|
||||
auto j = 0;
|
||||
for (auto i = 0u; i < _rideList.size(); i++)
|
||||
{
|
||||
if (!_rideList[i].Visible)
|
||||
continue;
|
||||
|
||||
if (j == target)
|
||||
return i;
|
||||
|
||||
j++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006B361F
|
||||
*/
|
||||
void OnScrollMouseDown(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override
|
||||
{
|
||||
const auto index = screenCoords.y / kScrollableRowHeight;
|
||||
if (index < 0 || static_cast<size_t>(index) >= _rideList.size())
|
||||
const auto index = GetNthVisibleItemIndex(screenCoords.y / kScrollableRowHeight);
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
// Open ride window
|
||||
@@ -448,8 +491,8 @@ namespace OpenRCT2::Ui::Windows
|
||||
*/
|
||||
void OnScrollMouseOver(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override
|
||||
{
|
||||
const auto index = screenCoords.y / kScrollableRowHeight;
|
||||
if (index < 0 || static_cast<size_t>(index) >= _rideList.size())
|
||||
const auto index = GetNthVisibleItemIndex(screenCoords.y / kScrollableRowHeight);
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
selected_list_item = index;
|
||||
@@ -480,6 +523,11 @@ namespace OpenRCT2::Ui::Windows
|
||||
widgets[WIDX_LIST].right = width - 26;
|
||||
widgets[WIDX_LIST].bottom = height - 15;
|
||||
|
||||
widgets[WIDX_SEARCH_CLEAR_BUTTON].right = widgets[WIDX_LIST].right - 1;
|
||||
widgets[WIDX_SEARCH_CLEAR_BUTTON].left = widgets[WIDX_SEARCH_CLEAR_BUTTON].right - 40;
|
||||
widgets[WIDX_SEARCH_TEXT_BOX].right = widgets[WIDX_SEARCH_CLEAR_BUTTON].left - 2;
|
||||
widgets[WIDX_SEARCH_TEXT_BOX].string = _searchFilter.data();
|
||||
|
||||
widgets[WIDX_HEADER_CUSTOMISE].right = widgets[WIDX_LIST].right - 1;
|
||||
widgets[WIDX_HEADER_CUSTOMISE].left = widgets[WIDX_HEADER_CUSTOMISE].right - 14;
|
||||
|
||||
@@ -570,7 +618,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
|
||||
// Draw number of attractions on bottom
|
||||
auto ft = Formatter();
|
||||
ft.Add<uint16_t>(static_cast<uint16_t>(_rideList.size()));
|
||||
ft.Add<uint16_t>(static_cast<uint16_t>(CountVisibleItems()));
|
||||
DrawTextBasic(
|
||||
rt, windowPos + ScreenCoordsXY{ 4, widgets[WIDX_LIST].bottom + 2 }, ride_list_statusbar_count_strings[page],
|
||||
ft);
|
||||
@@ -589,6 +637,9 @@ namespace OpenRCT2::Ui::Windows
|
||||
auto y = 0;
|
||||
for (size_t i = 0; i < _rideList.size(); i++)
|
||||
{
|
||||
if (!_rideList[i].Visible)
|
||||
continue;
|
||||
|
||||
StringId format = STR_BLACK_STRING;
|
||||
if (_quickDemolishMode)
|
||||
format = STR_RED_STRINGID;
|
||||
@@ -882,6 +933,28 @@ namespace OpenRCT2::Ui::Windows
|
||||
});
|
||||
}
|
||||
|
||||
bool IsFiltered(const u8string& rideName)
|
||||
{
|
||||
if (_searchFilter.empty())
|
||||
return true;
|
||||
|
||||
// Check if the filter matches the ride name
|
||||
return String::contains(u8string_view(rideName), _searchFilter, true);
|
||||
}
|
||||
|
||||
void ApplySearchQuery()
|
||||
{
|
||||
for (auto& entry : _rideList)
|
||||
{
|
||||
entry.Visible = IsFiltered(entry.Name);
|
||||
}
|
||||
}
|
||||
|
||||
size_t CountVisibleItems() const
|
||||
{
|
||||
return std::count_if(_rideList.begin(), _rideList.end(), [](const RideListEntry& entry) { return entry.Visible; });
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006B39A8
|
||||
@@ -897,14 +970,19 @@ namespace OpenRCT2::Ui::Windows
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the ride name once and use it for both filtering and storage
|
||||
auto rideName = rideRef.getName();
|
||||
|
||||
if (rideRef.windowInvalidateFlags & RIDE_INVALIDATE_RIDE_LIST)
|
||||
{
|
||||
rideRef.windowInvalidateFlags &= ~RIDE_INVALIDATE_RIDE_LIST;
|
||||
}
|
||||
|
||||
RideListEntry entry{};
|
||||
entry.Id = rideRef.id;
|
||||
entry.Name = rideRef.getName();
|
||||
RideListEntry entry{
|
||||
.Id = rideRef.id,
|
||||
.Name = std::move(rideName),
|
||||
.Visible = IsFiltered(rideName),
|
||||
};
|
||||
|
||||
_rideList.push_back(std::move(entry));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user