diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index d662670e4b..f653caea1d 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -3723,6 +3723,7 @@ STR_6648 :Loading plugin engine… STR_6649 :Loading scenario… STR_6650 :Loading saved game… STR_6651 :{STRING} ({COMMA32}%) +STR_6652 :Error Window ############# # Scenarios # diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 54d2ced5c7..40762ab10a 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: [#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. - Change: [#22230] The plugin/script engine is now initialised off the main thread. diff --git a/src/openrct2-ui/UiStringIds.h b/src/openrct2-ui/UiStringIds.h index c897f85119..a5fd2e306c 100644 --- a/src/openrct2-ui/UiStringIds.h +++ b/src/openrct2-ui/UiStringIds.h @@ -1924,7 +1924,8 @@ namespace OpenRCT2 STR_THEMES_WINDOW_EDITOR_INVENTION_LIST = 5211, STR_THEMES_WINDOW_EDITOR_OBJECT_SELECTION = 5210, STR_THEMES_WINDOW_EDITOR_SCENARIO_OPTIONS = 5212, - STR_THEMES_WINDOW_EDTIOR_OBJECTIVE_OPTIONS = 5213, + STR_THEMES_WINDOW_EDITOR_OBJECTIVE_OPTIONS = 5213, + STR_THEMES_WINDOW_ERROR = 6652, STR_THEMES_WINDOW_FINANCES = 5187, STR_THEMES_WINDOW_FIRE_PROMPT = 5225, STR_THEMES_WINDOW_FOOTPATH = 5198, diff --git a/src/openrct2-ui/interface/Theme.cpp b/src/openrct2-ui/interface/Theme.cpp index 48c3e11c6d..fb4c0e16cf 100644 --- a/src/openrct2-ui/interface/Theme.cpp +++ b/src/openrct2-ui/interface/Theme.cpp @@ -137,6 +137,7 @@ static constexpr WindowThemeDesc WindowThemeDescriptors[] = { WindowClass::SavePrompt, "WC_SAVE_PROMPT", STR_THEMES_WINDOW_SAVE_PROMPT, COLOURS_1(translucent(COLOUR_BORDEAUX_RED) ) }, { WindowClass::ConstructRide, "WC_CONSTRUCT_RIDE", STR_THEMES_WINDOW_CONSTRUCT_RIDE, COLOURS_3(opaque(COLOUR_DARK_BROWN), opaque(COLOUR_BORDEAUX_RED), opaque(COLOUR_BORDEAUX_RED) ) }, { WindowClass::DemolishRidePrompt, "WC_DEMOLISH_RIDE_PROMPT", STR_THEMES_WINDOW_DEMOLISH_RIDE_PROMPT, COLOURS_1(translucent(COLOUR_BORDEAUX_RED) ) }, + { WindowClass::Error, "WC_ERROR", STR_THEMES_WINDOW_ERROR, COLOURS_1(translucent(COLOUR_BORDEAUX_RED) ) }, { WindowClass::Scenery, "WC_SCENERY", STR_THEMES_WINDOW_SCENERY, COLOURS_3(opaque(COLOUR_DARK_BROWN), opaque(COLOUR_DARK_GREEN), opaque(COLOUR_DARK_GREEN) ) }, { WindowClass::SceneryScatter, "WC_SCENERY_SCATTER", STR_THEMES_WINDOW_SCENERY_SCATTER, COLOURS_3(opaque(COLOUR_DARK_BROWN), opaque(COLOUR_DARK_GREEN), opaque(COLOUR_DARK_GREEN) ) }, { WindowClass::Options, "WC_OPTIONS", STR_THEMES_WINDOW_OPTIONS, COLOURS_3(opaque(COLOUR_GREY), opaque(COLOUR_LIGHT_BLUE), opaque(COLOUR_LIGHT_BLUE) ) }, @@ -165,7 +166,7 @@ static constexpr WindowThemeDesc WindowThemeDescriptors[] = { WindowClass::EditorObjectSelection, "WC_EDITOR_OBJECT_SELECTION", STR_THEMES_WINDOW_EDITOR_OBJECT_SELECTION, COLOURS_3(opaque(COLOUR_LIGHT_PURPLE), opaque(COLOUR_GREY), opaque(COLOUR_GREY) ) }, { WindowClass::EditorInventionList, "WC_EDITOR_INVENTION_LIST", STR_THEMES_WINDOW_EDITOR_INVENTION_LIST, COLOURS_3(opaque(COLOUR_LIGHT_PURPLE), opaque(COLOUR_GREY), opaque(COLOUR_GREY) ) }, { WindowClass::EditorScenarioOptions, "WC_EDITOR_SCENARIO_OPTIONS", STR_THEMES_WINDOW_EDITOR_SCENARIO_OPTIONS, COLOURS_3(opaque(COLOUR_LIGHT_PURPLE), opaque(COLOUR_GREY), opaque(COLOUR_GREY) ) }, - { WindowClass::EditorObjectiveOptions, "WC_EDITOR_OBJECTIVE_OPTIONS", STR_THEMES_WINDOW_EDTIOR_OBJECTIVE_OPTIONS, COLOURS_3(opaque(COLOUR_LIGHT_PURPLE), opaque(COLOUR_GREY), opaque(COLOUR_GREY) ) }, + { WindowClass::EditorObjectiveOptions, "WC_EDITOR_OBJECTIVE_OPTIONS", STR_THEMES_WINDOW_EDITOR_OBJECTIVE_OPTIONS, COLOURS_3(opaque(COLOUR_LIGHT_PURPLE), opaque(COLOUR_GREY), opaque(COLOUR_GREY) ) }, { WindowClass::ManageTrackDesign, "WC_MANAGE_TRACK_DESIGN", STR_THEMES_WINDOW_MANAGE_TRACK_DESIGN, COLOURS_3(opaque(COLOUR_GREY), opaque(COLOUR_GREY), opaque(COLOUR_GREY) ) }, { WindowClass::TrackDeletePrompt, "WC_TRACK_DELETE_PROMPT", STR_THEMES_WINDOW_TRACK_DELETE_PROMPT, COLOURS_3(opaque(COLOUR_BORDEAUX_RED), opaque(COLOUR_BORDEAUX_RED), opaque(COLOUR_BORDEAUX_RED) ) }, { WindowClass::InstallTrack, "WC_INSTALL_TRACK", STR_THEMES_WINDOW_INSTALL_TRACK, COLOURS_3(opaque(COLOUR_BORDEAUX_RED), opaque(COLOUR_BORDEAUX_RED), opaque(COLOUR_BORDEAUX_RED) ) }, diff --git a/src/openrct2-ui/windows/Error.cpp b/src/openrct2-ui/windows/Error.cpp index 03ca90a0fb..29382e2eb6 100644 --- a/src/openrct2-ui/windows/Error.cpp +++ b/src/openrct2-ui/windows/Error.cpp @@ -21,16 +21,19 @@ namespace OpenRCT2::Ui::Windows { - // clang-format off -enum { - WIDX_BACKGROUND -}; + enum + { + WIDX_BACKGROUND, + }; -static Widget window_error_widgets[] = { - MakeWidget({0, 0}, {200, 42}, WindowWidgetType::ImgBtn, WindowColour::Primary), - kWidgetsEnd, -}; - // clang-format on + static constexpr auto kMinWidth = 70; + static constexpr auto kMaxWidth = 250; + static constexpr auto kPadding = 4; + + static Widget window_error_widgets[] = { + MakeWidget({ 0, 0 }, { 200, 42 }, WindowWidgetType::Frame, WindowColour::Primary), + kWidgetsEnd, + }; class ErrorWindow final : public Window { @@ -50,57 +53,24 @@ static Widget window_error_widgets[] = { void OnOpen() override { - window_error_widgets[WIDX_BACKGROUND].right = width; - window_error_widgets[WIDX_BACKGROUND].bottom = height; + window_error_widgets[WIDX_BACKGROUND].right = width - 1; + window_error_widgets[WIDX_BACKGROUND].bottom = height - 1; widgets = window_error_widgets; _staleCount = 0; + if (!gDisableErrorWindowSound) { - OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Error, 0, windowPos.x + (width / 2)); + Audio::Play(Audio::SoundId::Error, 0, windowPos.x + (width / 2)); } } void OnDraw(DrawPixelInfo& dpi) override { - ScreenCoordsXY leftTop{ windowPos }; - ScreenCoordsXY rightBottom{ windowPos + ScreenCoordsXY{ width - 1, height - 1 } }; - ScreenCoordsXY leftBottom{ leftTop.x, rightBottom.y }; - ScreenCoordsXY rightTop{ rightBottom.x, leftTop.y }; + WindowDrawWidgets(*this, dpi); - GfxFilterRect( - dpi, ScreenRect{ leftTop + ScreenCoordsXY{ 1, 1 }, rightBottom - ScreenCoordsXY{ 1, 1 } }, - FilterPaletteID::Palette45); - GfxFilterRect(dpi, ScreenRect{ leftTop, rightBottom }, FilterPaletteID::PaletteGlassSaturatedRed); - - GfxFilterRect( - dpi, ScreenRect{ leftTop + ScreenCoordsXY{ 0, 2 }, leftBottom - ScreenCoordsXY{ 0, 2 } }, - FilterPaletteID::PaletteDarken3); - GfxFilterRect( - dpi, ScreenRect{ rightTop + ScreenCoordsXY{ 0, 2 }, rightBottom - ScreenCoordsXY{ 0, 2 } }, - FilterPaletteID::PaletteDarken3); - GfxFilterRect( - dpi, ScreenRect{ leftBottom + ScreenCoordsXY{ 2, 0 }, rightBottom - ScreenCoordsXY{ 2, 0 } }, - FilterPaletteID::PaletteDarken3); - GfxFilterRect( - dpi, ScreenRect{ leftTop + ScreenCoordsXY{ 2, 0 }, rightTop - ScreenCoordsXY{ 2, 0 } }, - FilterPaletteID::PaletteDarken3); - - GfxFilterRect( - dpi, ScreenRect{ rightTop + ScreenCoordsXY{ 1, 1 }, rightTop + ScreenCoordsXY{ 1, 1 } }, - FilterPaletteID::PaletteDarken3); - GfxFilterRect( - dpi, ScreenRect{ rightTop + ScreenCoordsXY{ -1, 1 }, rightTop + ScreenCoordsXY{ -1, 1 } }, - FilterPaletteID::PaletteDarken3); - GfxFilterRect( - dpi, ScreenRect{ leftBottom + ScreenCoordsXY{ 1, -1 }, leftBottom + ScreenCoordsXY{ 1, -1 } }, - FilterPaletteID::PaletteDarken3); - GfxFilterRect( - dpi, ScreenRect{ rightBottom - ScreenCoordsXY{ 1, 1 }, rightBottom - ScreenCoordsXY{ 1, 1 } }, - FilterPaletteID::PaletteDarken3); - - DrawStringCentredRaw( - dpi, { leftTop + ScreenCoordsXY{ (width + 1) / 2 - 1, 1 } }, _numLines, _text.data(), FontStyle::Medium); + auto screenCoords = windowPos + ScreenCoordsXY{ (width + 1) / 2 - 1, kPadding - 1 }; + DrawStringCentredRaw(dpi, screenCoords, _numLines, _text.data(), FontStyle::Medium); } void OnPeriodicUpdate() override @@ -125,7 +95,7 @@ static Widget window_error_widgets[] = { WindowBase* ErrorOpen(std::string_view title, std::string_view message, bool autoClose) { - std::string buffer = "{BLACK}"; + std::string buffer = "{WINDOW_COLOUR_1}"; buffer.append(title); // Format the message @@ -152,30 +122,24 @@ static Widget window_error_widgets[] = { // Close any existing error windows if they exist. WindowCloseByClass(WindowClass::Error); + // How wide is the error string? int32_t width = GfxGetStringWidthNewLined(buffer.data(), FontStyle::Medium); - width = std::clamp(width, 64, 196); + width = std::clamp(width + 2 * kPadding, kMinWidth, kMaxWidth); + // How high is the error string? int32_t numLines{}; GfxWrapString(buffer, width + 1, FontStyle::Medium, &buffer, &numLines); + int32_t height = (numLines + 1) * FontGetLineHeight(FontStyle::Medium) + (2 * kPadding); - width = width + 3; - int32_t height = (numLines + 1) * FontGetLineHeight(FontStyle::Medium) + 4; - int32_t screenWidth = ContextGetWidth(); - int32_t screenHeight = ContextGetHeight(); + // Position error message around the cursor const CursorState* state = ContextGetCursorState(); ScreenCoordsXY windowPosition = state->position - ScreenCoordsXY(width / 2, -26); - windowPosition.x = std::clamp(windowPosition.x, 0, screenWidth); - windowPosition.y = std::max(22, windowPosition.y); - int32_t maxY = screenHeight - height; - if (windowPosition.y > maxY) - { - windowPosition.y = std::min(windowPosition.y - height - 40, maxY); - } + windowPosition.x = std::clamp(windowPosition.x, 0, ContextGetWidth() - width - 40); + windowPosition.y = std::clamp(windowPosition.y, 22, ContextGetHeight() - height - 40); auto errorWindow = std::make_unique(std::move(buffer), numLines, autoClose); return WindowCreate( - std::move(errorWindow), WindowClass::Error, windowPosition, width, height, - WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_RESIZABLE); + std::move(errorWindow), WindowClass::Error, windowPosition, width, height, WF_STICK_TO_FRONT | WF_TRANSPARENT); } WindowBase* ErrorOpen(StringId title, StringId message, const Formatter& args, bool autoClose) diff --git a/src/openrct2-ui/windows/Themes.cpp b/src/openrct2-ui/windows/Themes.cpp index 2baf90aa42..3e7814d0ec 100644 --- a/src/openrct2-ui/windows/Themes.cpp +++ b/src/openrct2-ui/windows/Themes.cpp @@ -213,6 +213,7 @@ static WindowClass window_themes_tab_6_classes[] = { }; static WindowClass window_themes_tab_7_classes[] = { + WindowClass::Error, WindowClass::SavePrompt, WindowClass::DemolishRidePrompt, WindowClass::FirePrompt, @@ -221,7 +222,6 @@ static WindowClass window_themes_tab_7_classes[] = { WindowClass::ProgressWindow, WindowClass::NetworkStatus, }; - // clang-format on static WindowClass* window_themes_tab_classes[] = { nullptr, @@ -233,6 +233,7 @@ static WindowClass window_themes_tab_7_classes[] = { window_themes_tab_6_classes, window_themes_tab_7_classes, }; + // clang-format on #pragma endregion