From 82ab76824f93231d730943b11f8e3f0c3c72e2f2 Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Fri, 18 Jul 2025 14:41:52 +0200 Subject: [PATCH 1/3] Config.cpp: fix serialisation for sorting by file size --- src/openrct2/config/Config.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/openrct2/config/Config.cpp b/src/openrct2/config/Config.cpp index 3597aa7f55..32c2d675ed 100644 --- a/src/openrct2/config/Config.cpp +++ b/src/openrct2/config/Config.cpp @@ -113,6 +113,8 @@ namespace OpenRCT2::Config static const auto Enum_FileBrowserSort = ConfigEnum({ ConfigEnumEntry("NAME_ASCENDING", FileBrowserSort::NameAscending), ConfigEnumEntry("NAME_DESCENDING", FileBrowserSort::NameDescending), + ConfigEnumEntry("SIZE_ASCENDING", FileBrowserSort::SizeAscending), + ConfigEnumEntry("SIZE_DESCENDING", FileBrowserSort::SizeDescending), ConfigEnumEntry("DATE_ASCENDING", FileBrowserSort::DateAscending), ConfigEnumEntry("DATE_DESCENDING", FileBrowserSort::DateDescending), }); From 091da9bdef548470d6539a209087f0c5ef74c9ba Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Fri, 18 Jul 2025 15:02:05 +0200 Subject: [PATCH 2/3] Fix LoadSave window frame not resizing when toggling previews --- distribution/changelog.txt | 1 + src/openrct2-ui/windows/LoadSave.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 5bd84ba4c1..79ddccc4d4 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -9,6 +9,7 @@ - Fix: [#24711] The map smoothing function only partially works for custom height map image files. - Fix: [#24773] The new ride window debug authors does not show the correct authors for non legacy ride objects. - Fix: [#24775] The scenery and new ride windows do not filter by file name or identifier correctly for non legacy objects. +- Fix: [#24794] The load/save browser does not resize cleanly when toggling the preview sidebar. - Fix: [#24824] The Air Powered Vertical Coaster top section track piece has vertical tunnels (original bug). - Fix: [#24825] The River Rapids flat-to-gentle track piece tunnels are incorrect on the gentle side. - Fix: [#24826] The Junior Roller Coaster flat-to-steep track piece tunnels are incorrect. diff --git a/src/openrct2-ui/windows/LoadSave.cpp b/src/openrct2-ui/windows/LoadSave.cpp index ffd4376388..41d4ea666f 100644 --- a/src/openrct2-ui/windows/LoadSave.cpp +++ b/src/openrct2-ui/windows/LoadSave.cpp @@ -918,6 +918,8 @@ namespace OpenRCT2::Ui::Windows { Config::Save(); Invalidate(); + ResizeFrame(); + OnResize(); } } From 2e219ec1e7a1d3f33561814c7bbcc276e1b4b256 Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Fri, 18 Jul 2025 15:53:29 +0200 Subject: [PATCH 3/3] Introduce option to show minimap previews in LoadSave browser --- data/language/en-GB.txt | 5 + distribution/changelog.txt | 1 + src/openrct2-ui/UiStringIds.h | 5 + src/openrct2-ui/windows/LoadSave.cpp | 151 ++++++++++++++++++--------- src/openrct2/config/Config.cpp | 11 +- src/openrct2/config/Config.h | 2 +- src/openrct2/config/ConfigTypes.h | 7 ++ 7 files changed, 129 insertions(+), 53 deletions(-) diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index 339d94b91b..6b8c3e6c30 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -3833,3 +3833,8 @@ STR_6791 :Sensitivity: {COMMA32}% STR_6792 :Entrance Buildings STR_6793 :Guests and Staff STR_6794 :Scenery and Themes +STR_6795 :{MOVE_X}{10}{STRINGID} +STR_6796 :•{MOVE_X}{10}{STRINGID} +STR_6797 :No preview +STR_6798 :Screenshot +STR_6799 :Mini map diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 79ddccc4d4..5f45d982e3 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -2,6 +2,7 @@ ------------------------------------------------------------------------ - Feature: [#24468] [Plugin] Add awards to plugin API. - Feature: [#24702] [Plugin] Add bindings for missing cheats (forcedParkRating, ignoreRidePrice, makeAllDestructible). +- Feature: [#24794] The load/save browser can now optionally show mini map previews instead of screenshots. - Improved: [#24812] Taiwan Park has been added to the Extras tab if it is present. - Change: [#24730] Security guards now only walk slowly in crowded areas. - Fix: [#24598] Cannot load .park files that use official legacy footpaths by accident. diff --git a/src/openrct2-ui/UiStringIds.h b/src/openrct2-ui/UiStringIds.h index 6a00ba404a..d8c2c4532a 100644 --- a/src/openrct2-ui/UiStringIds.h +++ b/src/openrct2-ui/UiStringIds.h @@ -278,6 +278,8 @@ namespace OpenRCT2 // Widgets STR_CLOSE_X = 824, STR_CLOSE_X_WHITE = 6164, + STR_DROPDOWN_BULLET_OPTION = 6795, + STR_DROPDOWN_BULLET_OPTION_CHECKED = 6796, // Used as STR_DROPDOWN_BULLET_OPTION + 1 STR_DROPDOWN_GLYPH = 876, STR_NUMERIC_DOWN = 1219, STR_NUMERIC_UP = 1218, @@ -854,6 +856,9 @@ namespace OpenRCT2 STR_FILEBROWSER_CUSTOMISE_FILENAME = 6714, STR_FILEBROWSER_CUSTOMISE_SIZE = 6716, STR_FILEBROWSER_CUSTOMISE_PREVIEW = 6736, + STR_FILEBROWSER_PREVIEW_DISABLED = 6797, + STR_FILEBROWSER_PREVIEW_MINIMAP = 6799, + STR_FILEBROWSER_PREVIEW_SCREENSHOT = 6798, STR_FILEBROWSER_FILE_SIZE_VALUE = 6713, STR_FILEBROWSER_FOLDER_NAME_PROMPT = 5986, STR_FILEBROWSER_OVERWRITE_PROMPT = 2708, diff --git a/src/openrct2-ui/windows/LoadSave.cpp b/src/openrct2-ui/windows/LoadSave.cpp index 41d4ea666f..cfb548815b 100644 --- a/src/openrct2-ui/windows/LoadSave.cpp +++ b/src/openrct2-ui/windows/LoadSave.cpp @@ -61,8 +61,8 @@ namespace OpenRCT2::Ui::Windows static constexpr auto kPadding = 5; - static constexpr auto kPreviewWidth = 250; - static constexpr auto kWindowSizeMinPreview = ScreenSize{ kWindowSize.width + kPreviewWidth, kWindowSize.height }; + static constexpr auto kPreviewWidthScreenshot = 250; + static constexpr auto kPreviewWidthMiniMap = 180; static constexpr int kKibiByte = 1024; static constexpr int kMebiByte = kKibiByte * 1024; @@ -136,7 +136,27 @@ namespace OpenRCT2::Ui::Windows bool ShowPreviews() { auto& config = Config::Get().general; - return config.FileBrowserShowPreviews; + return config.FileBrowserPreviewType != ParkPreviewPref::disabled; + } + + ScreenSize GetPreviewSize() const + { + auto& config = Config::Get().general; + switch (config.FileBrowserPreviewType) + { + case ParkPreviewPref::screenshot: + return { kPreviewWidthScreenshot, kPreviewWidthScreenshot / 5 * 4 }; + case ParkPreviewPref::miniMap: + return { kPreviewWidthMiniMap, kPreviewWidthMiniMap }; + case ParkPreviewPref::disabled: + default: + return { 0, 0 }; + } + } + + ScreenSize GetMinimumWindowSize() const + { + return kWindowSizeMin + GetPreviewSize(); } void PopulateList(const u8string& directory, std::string_view extensionPattern) @@ -383,44 +403,66 @@ namespace OpenRCT2::Ui::Windows void DrawPreview(RenderTarget& rt) { - constexpr auto kPreviewHeight = kPreviewWidth / 5 * 4; - - // Draw frame - auto& widget = widgets[WIDX_SCROLL]; - auto frameStartPos = windowPos + ScreenCoordsXY(width - kPreviewWidth - kPadding - 1, widget.top); - auto frameEndPos = frameStartPos + ScreenCoordsXY(kPreviewWidth + 1, kPreviewHeight + 1); - GfxFillRectInset(rt, { frameStartPos, frameEndPos }, colours[1], INSET_RECT_F_60 | INSET_RECT_FLAG_FILL_MID_LIGHT); - - // Draw park name + // Find preview image to draw + PreviewImage* image = nullptr; + auto targetPref = Config::Get().general.FileBrowserPreviewType; + auto targetType = targetPref == ParkPreviewPref::screenshot ? PreviewImageType::screenshot + : PreviewImageType::miniMap; + for (auto& candidate : _preview.images) { - auto namePos = frameStartPos + ScreenCoordsXY{ kPreviewWidth / 2, -kButtonFaceHeight }; - auto ft = Formatter(); - ft.Add(STR_STRING); - ft.Add(_preview.parkName.c_str()); - DrawTextEllipsised(rt, namePos, kPreviewWidth, STR_WINDOW_COLOUR_2_STRINGID, ft, { TextAlignment::CENTRE }); - } - - // Draw image, if available - bool foundImage = false; - for (auto& image : _preview.images) - { - if (image.type == PreviewImageType::screenshot) + if (candidate.type == targetType) { - auto imagePos = frameStartPos + ScreenCoordsXY(1, 1); - drawPreviewImage(image, rt, imagePos); - foundImage = true; + image = &candidate; break; } } - // Draw OpenRCT2 logo if no preview was found - if (!foundImage) + const auto previewPaneSize = GetPreviewSize(); + auto& widget = widgets[WIDX_SCROLL]; + + // Draw park name + { + auto namePos = windowPos + + ScreenCoordsXY(width - previewPaneSize.width / 2 - kPadding, widget.top - kButtonFaceHeight); + auto ft = Formatter(); + ft.Add(STR_STRING); + ft.Add(_preview.parkName.c_str()); + DrawTextEllipsised( + rt, namePos, previewPaneSize.width - kPadding * 2, STR_WINDOW_COLOUR_2_STRINGID, ft, + { TextAlignment::CENTRE }); + } + + const bool drawFrame = image != nullptr || targetType == PreviewImageType::screenshot; + const auto previewWidth = image != nullptr ? image->width : previewPaneSize.width; + const auto previewHeight = image != nullptr ? image->height : previewPaneSize.height; + + auto hCentre = (previewPaneSize.width - previewWidth) / 2 - kPadding; + auto frameStartPos = windowPos + ScreenCoordsXY(width - previewPaneSize.width + hCentre - 1, widget.top); + auto frameEndPos = frameStartPos + ScreenCoordsXY(previewWidth + 1, previewHeight + 1); + + if (drawFrame) + { + GfxFillRectInset( + rt, { frameStartPos, frameEndPos }, colours[1], INSET_RECT_F_60 | INSET_RECT_FLAG_FILL_MID_LIGHT); + } + + // Draw image, or placeholder if no preview was found + if (image != nullptr) + { + auto imagePos = frameStartPos + ScreenCoordsXY(1, 1); + drawPreviewImage(*image, rt, imagePos); + } + else { auto imagePos = frameStartPos + ScreenCoordsXY(1, 1); - auto colour = ColourMapA[colours[1].colour].dark; - GfxDrawSpriteSolid(rt, ImageId(SPR_G2_LOGO_MONO_DITHERED), imagePos, colour); - auto textPos = imagePos + ScreenCoordsXY(kPreviewWidth / 2, kPreviewHeight / 2 - 6); + if (targetType == PreviewImageType::screenshot) + { + auto colour = ColourMapA[colours[1].colour].dark; + GfxDrawSpriteSolid(rt, ImageId(SPR_G2_LOGO_MONO_DITHERED), imagePos, colour); + } + + auto textPos = imagePos + ScreenCoordsXY(previewWidth / 2, previewHeight / 2 - 6); // NOTE: Can't simplify this as the compiler complains about different enumeration types. StringId previewText = STR_NO_PREVIEW_AVAILABLE; @@ -435,7 +477,8 @@ namespace OpenRCT2::Ui::Windows return; } - auto summaryCoords = frameStartPos + ScreenCoordsXY(0, kPreviewHeight + kListRowHeight); + auto summaryCoords = windowPos + + ScreenCoordsXY(width - previewPaneSize.width - kPadding, widget.top + previewHeight + kListRowHeight); // Date { @@ -538,8 +581,7 @@ namespace OpenRCT2::Ui::Windows InitScrollWidgets(); ComputeMaxDateWidth(); - auto minSize = ShowPreviews() ? kWindowSizeMinPreview : kWindowSizeMin; - WindowSetResize(*this, minSize, kWindowSizeMax); + WindowSetResize(*this, GetMinimumWindowSize(), kWindowSizeMax); } void OnClose() override @@ -561,8 +603,7 @@ namespace OpenRCT2::Ui::Windows void OnResize() override { - auto minSize = ShowPreviews() ? kWindowSizeMinPreview : kWindowSizeMin; - WindowSetResize(*this, minSize, kWindowSizeMax); + WindowSetResize(*this, GetMinimumWindowSize(), kWindowSizeMax); auto& config = Config::Get().general; config.FileBrowserWidth = width; @@ -594,7 +635,7 @@ namespace OpenRCT2::Ui::Windows widgets[WIDX_SCROLL].right = width - kPadding; widgets[WIDX_SCROLL].bottom = height - paddingBottom; if (ShowPreviews()) - widgets[WIDX_SCROLL].right -= kPreviewWidth + kPadding; + widgets[WIDX_SCROLL].right -= GetPreviewSize().width + kPadding; Widget& customiseWidget = widgets[WIDX_SORT_CUSTOMISE]; customiseWidget.right = widgets[WIDX_SCROLL].right; @@ -864,24 +905,32 @@ namespace OpenRCT2::Ui::Windows gDropdownItems[0].Format = STR_TOGGLE_OPTION; gDropdownItems[1].Format = STR_TOGGLE_OPTION; gDropdownItems[2].Format = STR_TOGGLE_OPTION; - gDropdownItems[3].Format = STR_TOGGLE_OPTION; + gDropdownItems[3].Format = kStringIdEmpty; + gDropdownItems[4].Format = STR_DROPDOWN_BULLET_OPTION; + gDropdownItems[5].Format = STR_DROPDOWN_BULLET_OPTION; + gDropdownItems[6].Format = STR_DROPDOWN_BULLET_OPTION; + gDropdownItems[0].Args = STR_FILEBROWSER_CUSTOMISE_FILENAME; gDropdownItems[1].Args = STR_FILEBROWSER_CUSTOMISE_SIZE; gDropdownItems[2].Args = STR_FILEBROWSER_CUSTOMISE_DATE; - gDropdownItems[3].Args = STR_FILEBROWSER_CUSTOMISE_PREVIEW; + gDropdownItems[4].Args = STR_FILEBROWSER_PREVIEW_DISABLED; + gDropdownItems[5].Args = STR_FILEBROWSER_PREVIEW_MINIMAP; + gDropdownItems[6].Args = STR_FILEBROWSER_PREVIEW_SCREENSHOT; Widget* widget = &widgets[WIDX_SORT_CUSTOMISE]; WindowDropdownShowTextCustomWidth( { windowPos.x + widget->left - 70, windowPos.y + widget->top }, widget->height() + 1, colours[1], 0, - Dropdown::Flag::StayOpen, 4, 90); + Dropdown::Flag::StayOpen, 7, 90); auto& config = Config::Get().general; Dropdown::SetChecked(0, true); Dropdown::SetChecked(1, config.FileBrowserShowSizeColumn); Dropdown::SetChecked(2, config.FileBrowserShowDateColumn); - Dropdown::SetChecked(3, config.FileBrowserShowPreviews); + Dropdown::SetChecked(4, config.FileBrowserPreviewType == ParkPreviewPref::disabled); + Dropdown::SetChecked(5, config.FileBrowserPreviewType == ParkPreviewPref::miniMap); + Dropdown::SetChecked(6, config.FileBrowserPreviewType == ParkPreviewPref::screenshot); } void OnDropdown(WidgetIndex widgetIndex, int32_t selectedIndex) override @@ -901,17 +950,19 @@ namespace OpenRCT2::Ui::Windows config.FileBrowserShowDateColumn ^= true; changed = true; } - else if (selectedIndex == 3) + else if (selectedIndex >= 4 && selectedIndex <= 6) { - config.FileBrowserShowPreviews ^= true; + auto newPref = ParkPreviewPref(selectedIndex - 4); + if (config.FileBrowserPreviewType != newPref) + { + Invalidate(); + width -= GetPreviewSize().width; - Invalidate(); - if (config.FileBrowserShowPreviews) - width += kPreviewWidth; - else - width -= kPreviewWidth; + config.FileBrowserPreviewType = newPref; + width += GetPreviewSize().width; - changed = true; + changed = true; + } } if (changed) diff --git a/src/openrct2/config/Config.cpp b/src/openrct2/config/Config.cpp index 32c2d675ed..b03e350c0c 100644 --- a/src/openrct2/config/Config.cpp +++ b/src/openrct2/config/Config.cpp @@ -119,6 +119,12 @@ namespace OpenRCT2::Config ConfigEnumEntry("DATE_DESCENDING", FileBrowserSort::DateDescending), }); + static const auto Enum_ParkPreviewPref = ConfigEnum({ + ConfigEnumEntry("DISABLED", ParkPreviewPref::disabled), + ConfigEnumEntry("SCREENSHOT", ParkPreviewPref::screenshot), + ConfigEnumEntry("MINIMAP", ParkPreviewPref::miniMap), + }); + static const auto Enum_VirtualFloorStyle = ConfigEnum({ ConfigEnumEntry("OFF", VirtualFloorStyles::Off), ConfigEnumEntry("CLEAR", VirtualFloorStyles::Clear), @@ -261,7 +267,8 @@ namespace OpenRCT2::Config model->FileBrowserHeight = reader->GetInt32("file_browser_height", 0); model->FileBrowserShowSizeColumn = reader->GetBoolean("file_browser_show_size_column", true); model->FileBrowserShowDateColumn = reader->GetBoolean("file_browser_show_date_column", true); - model->FileBrowserShowPreviews = reader->GetBoolean("file_browser_show_previews", true); + model->FileBrowserPreviewType = reader->GetEnum( + "file_browser_preview_type", ParkPreviewPref::screenshot, Enum_ParkPreviewPref); } } @@ -354,7 +361,7 @@ namespace OpenRCT2::Config writer->WriteInt32("file_browser_height", model->FileBrowserHeight); writer->WriteBoolean("file_browser_show_size_column", model->FileBrowserShowSizeColumn); writer->WriteBoolean("file_browser_show_date_column", model->FileBrowserShowDateColumn); - writer->WriteBoolean("file_browser_show_previews", model->FileBrowserShowPreviews); + writer->WriteEnum("file_browser_preview_type", model->FileBrowserPreviewType, Enum_ParkPreviewPref); } static void ReadInterface(IIniReader* reader) diff --git a/src/openrct2/config/Config.h b/src/openrct2/config/Config.h index 8e1707b3c7..5daa723e7f 100644 --- a/src/openrct2/config/Config.h +++ b/src/openrct2/config/Config.h @@ -123,7 +123,7 @@ namespace OpenRCT2::Config int16_t FileBrowserHeight; bool FileBrowserShowSizeColumn; bool FileBrowserShowDateColumn; - bool FileBrowserShowPreviews; + ParkPreviewPref FileBrowserPreviewType; }; struct Interface diff --git a/src/openrct2/config/ConfigTypes.h b/src/openrct2/config/ConfigTypes.h index 0419ec4fee..4850d8ea84 100644 --- a/src/openrct2/config/ConfigTypes.h +++ b/src/openrct2/config/ConfigTypes.h @@ -29,6 +29,13 @@ enum class FileBrowserSort : int32_t DateDescending, }; +enum class ParkPreviewPref : int32_t +{ + disabled, + miniMap, + screenshot, +}; + enum class TemperatureUnit : int32_t { Celsius,