From eba2041aaa94fa68c793b4a4254e06024f6d8305 Mon Sep 17 00:00:00 2001 From: hjort96 <31574839+hjort96@users.noreply.github.com> Date: Fri, 15 Oct 2021 11:41:30 +0200 Subject: [PATCH] Close #13791: Refactor window to class Options (#15558) * Create class OptionsWindow. Moving functions to class. * Move functions to class OptionsWindow * Fix coding style Co-authored-by: hjort96 --- src/openrct2-ui/windows/Options.cpp | 3522 ++++++++++++++------------- 1 file changed, 1803 insertions(+), 1719 deletions(-) diff --git a/src/openrct2-ui/windows/Options.cpp b/src/openrct2-ui/windows/Options.cpp index 469e01bfeb..b7e1105413 100644 --- a/src/openrct2-ui/windows/Options.cpp +++ b/src/openrct2-ui/windows/Options.cpp @@ -422,13 +422,6 @@ const int32_t window_options_tab_animation_frames[] = 16, // WINDOW_OPTIONS_PAGE_ADVANCED, }; -static void window_options_set_page(rct_window *w, int32_t page); -static void window_options_set_pressed_tab(rct_window *w); -static void window_options_draw_tab_image(rct_drawpixelinfo *dpi, rct_window *w, int32_t page, int32_t spriteIndex); -static void window_options_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w); -static void window_options_show_dropdown(rct_window *w, rct_widget *widget, int32_t num_items); -static void window_options_update_height_markers(); - #pragma region Enabled Widgets #define MAIN_OPTIONS_ENABLED_WIDGETS \ @@ -549,1817 +542,1908 @@ static uint64_t window_options_page_enabled_widgets[] = { }; // clang-format on -#pragma region Common tab events - -static void window_options_common_mouseup(rct_window* w, rct_widgetindex widgetIndex) +class OptionsWindow final : public Window { - switch (widgetIndex) +public: + void OnOpen() override { - case WIDX_CLOSE: - window_close(w); - return; - case WIDX_TAB_1: - case WIDX_TAB_2: - case WIDX_TAB_3: - case WIDX_TAB_4: - case WIDX_TAB_5: - case WIDX_TAB_6: - case WIDX_TAB_7: - window_options_set_page(w, widgetIndex - WIDX_TAB_1); - break; + this->widgets = window_options_display_widgets; + this->enabled_widgets = window_options_page_enabled_widgets[WINDOW_OPTIONS_PAGE_DISPLAY]; + this->page = WINDOW_OPTIONS_PAGE_DISPLAY; + this->frame_no = 0; + WindowInitScrollWidgets(this); } -} -static void window_options_common_invalidate_before(rct_window* w) -{ - if (window_options_page_widgets[w->page] != w->widgets) + void OnMouseUp(rct_widgetindex widgetIndex) override { - w->widgets = window_options_page_widgets[w->page]; - WindowInitScrollWidgets(w); - } - window_options_set_pressed_tab(w); - - w->disabled_widgets = 0; - auto hasFilePicker = OpenRCT2::GetContext()->GetUiContext()->HasFilePicker(); - if (!hasFilePicker) - { - w->enabled_widgets &= ~(1ULL << WIDX_ALWAYS_NATIVE_LOADSAVE); - w->disabled_widgets |= (1ULL << WIDX_ALWAYS_NATIVE_LOADSAVE); - w->widgets[WIDX_ALWAYS_NATIVE_LOADSAVE].type = WindowWidgetType::Empty; - } -} - -static void window_options_common_invalidate_after(rct_window* w) -{ - // Automatically adjust window height to fit widgets - int32_t y = 0; - for (auto widget = &w->widgets[WIDX_PAGE_START]; widget->type != WindowWidgetType::Last; widget++) - { - y = std::max(y, widget->bottom); - } - w->height = y + 6; - w->widgets[WIDX_BACKGROUND].bottom = w->height - 1; - w->widgets[WIDX_PAGE_BACKGROUND].bottom = w->height - 1; -} - -static void window_options_common_update(rct_window* w) -{ - // Tab animation - w->frame_no++; - widget_invalidate(w, WIDX_TAB_1 + w->page); -} - -#pragma region Display Tab - -static void window_options_display_mouseup(rct_window* w, rct_widgetindex widgetIndex) -{ - if (widgetIndex < WIDX_PAGE_START) - return window_options_common_mouseup(w, widgetIndex); - - switch (widgetIndex) - { - case WIDX_UNCAP_FPS_CHECKBOX: - gConfigGeneral.uncap_fps ^= 1; - drawing_engine_set_vsync(gConfigGeneral.use_vsync); - config_save_default(); - w->Invalidate(); - break; - case WIDX_USE_VSYNC_CHECKBOX: - gConfigGeneral.use_vsync ^= 1; - drawing_engine_set_vsync(gConfigGeneral.use_vsync); - config_save_default(); - w->Invalidate(); - break; - case WIDX_SHOW_FPS_CHECKBOX: - gConfigGeneral.show_fps ^= 1; - config_save_default(); - w->Invalidate(); - break; - case WIDX_MULTITHREADING_CHECKBOX: - gConfigGeneral.multithreading ^= 1; - config_save_default(); - w->Invalidate(); - break; - case WIDX_MINIMIZE_FOCUS_LOSS: - gConfigGeneral.minimize_fullscreen_focus_loss ^= 1; - platform_refresh_video(false); - config_save_default(); - w->Invalidate(); - break; - case WIDX_STEAM_OVERLAY_PAUSE: - gConfigGeneral.steam_overlay_pause ^= 1; - config_save_default(); - w->Invalidate(); - break; - case WIDX_DISABLE_SCREENSAVER_LOCK: - gConfigGeneral.disable_screensaver ^= 1; - ApplyScreenSaverLockSetting(); - config_save_default(); - w->Invalidate(); - break; - } -} - -static void window_options_display_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget) -{ - widget = &w->widgets[widgetIndex - 1]; - - switch (widgetIndex) - { - case WIDX_RESOLUTION_DROPDOWN: + if (widgetIndex < WIDX_PAGE_START) + CommonMouseUp(widgetIndex); + else { - const auto& resolutions = OpenRCT2::GetContext()->GetUiContext()->GetFullscreenResolutions(); - - int32_t selectedResolution = -1; - for (size_t i = 0; i < resolutions.size(); i++) + switch (page) { - const Resolution& resolution = resolutions[i]; + case WINDOW_OPTIONS_PAGE_DISPLAY: + DisplayMouseUp(widgetIndex); + break; + case WINDOW_OPTIONS_PAGE_RENDERING: + RenderingMouseUp(widgetIndex); + break; + case WINDOW_OPTIONS_PAGE_AUDIO: + AudioMouseUp(widgetIndex); + break; + case WINDOW_OPTIONS_PAGE_CONTROLS_AND_INTERFACE: + ControlsMouseUp(widgetIndex); + break; + case WINDOW_OPTIONS_PAGE_MISC: + MiscMouseUp(widgetIndex); + break; + case WINDOW_OPTIONS_PAGE_ADVANCED: + AdvancedMouseUp(widgetIndex); + break; + case WINDOW_OPTIONS_PAGE_CULTURE: + default: + break; + } + } + } - gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL; + void OnMouseDown(rct_widgetindex widgetIndex) override + { + switch (page) + { + case WINDOW_OPTIONS_PAGE_DISPLAY: + DisplayMouseDown(widgetIndex); + break; + case WINDOW_OPTIONS_PAGE_RENDERING: + RenderingMouseDown(widgetIndex); + break; + case WINDOW_OPTIONS_PAGE_CULTURE: + CultureMouseDown(widgetIndex); + break; + case WINDOW_OPTIONS_PAGE_AUDIO: + AudioMouseDown(widgetIndex); + break; + case WINDOW_OPTIONS_PAGE_CONTROLS_AND_INTERFACE: + ControlsMouseDown(widgetIndex); + break; + case WINDOW_OPTIONS_PAGE_MISC: + MiscMouseDown(widgetIndex); + break; + case WINDOW_OPTIONS_PAGE_ADVANCED: + AdvancedMouseDown(widgetIndex); + break; + default: + break; + } + } - uint16_t* args = reinterpret_cast(&gDropdownItemsArgs[i]); - args[0] = STR_RESOLUTION_X_BY_Y; - args[1] = resolution.Width; - args[2] = resolution.Height; + void OnDropdown(rct_widgetindex widgetIndex, int32_t dropdownIndex) override + { + switch (page) + { + case WINDOW_OPTIONS_PAGE_DISPLAY: + DisplayDropdown(widgetIndex, dropdownIndex); + break; + case WINDOW_OPTIONS_PAGE_RENDERING: + RenderingDropdown(widgetIndex, dropdownIndex); + break; + case WINDOW_OPTIONS_PAGE_CULTURE: + CultureDropdown(widgetIndex, dropdownIndex); + break; + case WINDOW_OPTIONS_PAGE_AUDIO: + AudioDropdown(widgetIndex, dropdownIndex); + break; + case WINDOW_OPTIONS_PAGE_CONTROLS_AND_INTERFACE: + ControlsDropdown(widgetIndex, dropdownIndex); + break; + case WINDOW_OPTIONS_PAGE_MISC: + MiscDropdown(widgetIndex, dropdownIndex); + break; + case WINDOW_OPTIONS_PAGE_ADVANCED: + AdvancedDropdown(widgetIndex, dropdownIndex); + break; + default: + break; + } + } - if (resolution.Width == gConfigGeneral.fullscreen_width - && resolution.Height == gConfigGeneral.fullscreen_height) + void OnPrepareDraw() override + { + switch (page) + { + case WINDOW_OPTIONS_PAGE_DISPLAY: + DisplayPrepareDraw(); + break; + case WINDOW_OPTIONS_PAGE_RENDERING: + RenderingPrepareDraw(); + break; + case WINDOW_OPTIONS_PAGE_CULTURE: + CulturePrepareDraw(); + break; + case WINDOW_OPTIONS_PAGE_AUDIO: + AudioPrepareDraw(); + break; + case WINDOW_OPTIONS_PAGE_CONTROLS_AND_INTERFACE: + ControlsPrepareDraw(); + break; + case WINDOW_OPTIONS_PAGE_MISC: + MiscPrepareDraw(); + break; + case WINDOW_OPTIONS_PAGE_ADVANCED: + AdvancedPrepareDraw(); + break; + default: + break; + } + } + + void OnDraw(rct_drawpixelinfo& dpi) override + { + switch (page) + { + case WINDOW_OPTIONS_PAGE_DISPLAY: + DisplayDraw(&dpi); + break; + case WINDOW_OPTIONS_PAGE_RENDERING: + RenderingDraw(&dpi); + break; + case WINDOW_OPTIONS_PAGE_CULTURE: + CultureDraw(&dpi); + break; + case WINDOW_OPTIONS_PAGE_AUDIO: + AudioDraw(&dpi); + break; + case WINDOW_OPTIONS_PAGE_CONTROLS_AND_INTERFACE: + ControlsDraw(&dpi); + break; + case WINDOW_OPTIONS_PAGE_MISC: + MiscDraw(&dpi); + break; + case WINDOW_OPTIONS_PAGE_ADVANCED: + AdvancedDraw(&dpi); + break; + default: + break; + } + } + + void OnUpdate() override + { + CommonUpdate(); + + switch (page) + { + case WINDOW_OPTIONS_PAGE_AUDIO: + AudioUpdate(); + break; + case WINDOW_OPTIONS_PAGE_DISPLAY: + case WINDOW_OPTIONS_PAGE_RENDERING: + case WINDOW_OPTIONS_PAGE_CULTURE: + case WINDOW_OPTIONS_PAGE_CONTROLS_AND_INTERFACE: + case WINDOW_OPTIONS_PAGE_MISC: + case WINDOW_OPTIONS_PAGE_ADVANCED: + default: + break; + } + } + + ScreenSize OnScrollGetSize(int32_t scrollIndex) override + { + switch (this->page) + { + case WINDOW_OPTIONS_PAGE_AUDIO: + return AudioScrollGetSize(scrollIndex); + case WINDOW_OPTIONS_PAGE_DISPLAY: + case WINDOW_OPTIONS_PAGE_RENDERING: + case WINDOW_OPTIONS_PAGE_CULTURE: + case WINDOW_OPTIONS_PAGE_CONTROLS_AND_INTERFACE: + case WINDOW_OPTIONS_PAGE_MISC: + case WINDOW_OPTIONS_PAGE_ADVANCED: + default: + return { WW, WH }; + } + } + +private: +#pragma region Common events + void CommonMouseUp(rct_widgetindex widgetIndex) + { + switch (widgetIndex) + { + case WIDX_CLOSE: + window_close(this); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + case WIDX_TAB_5: + case WIDX_TAB_6: + case WIDX_TAB_7: + SetPage(widgetIndex - WIDX_TAB_1); + break; + } + } + + void CommonPrepareDrawBefore() + { + if (window_options_page_widgets[this->page] != this->widgets) + { + this->widgets = window_options_page_widgets[this->page]; + WindowInitScrollWidgets(this); + } + SetPressedTab(); + + this->disabled_widgets = 0; + auto hasFilePicker = OpenRCT2::GetContext()->GetUiContext()->HasFilePicker(); + if (!hasFilePicker) + { + this->enabled_widgets &= ~(1ULL << WIDX_ALWAYS_NATIVE_LOADSAVE); + this->disabled_widgets |= (1ULL << WIDX_ALWAYS_NATIVE_LOADSAVE); + this->widgets[WIDX_ALWAYS_NATIVE_LOADSAVE].type = WindowWidgetType::Empty; + } + } + + void CommonPrepareDrawAfter() + { + // Automatically adjust window height to fit widgets + int32_t y = 0; + for (auto widget = &this->widgets[WIDX_PAGE_START]; widget->type != WindowWidgetType::Last; widget++) + { + y = std::max(y, widget->bottom); + } + this->height = y + 6; + this->widgets[WIDX_BACKGROUND].bottom = this->height - 1; + this->widgets[WIDX_PAGE_BACKGROUND].bottom = this->height - 1; + } + + void CommonUpdate() + { + // Tab animation + this->frame_no++; + widget_invalidate(this, WIDX_TAB_1 + this->page); + } +#pragma endregion + +#pragma region Display tab events + void DisplayMouseUp(rct_widgetindex widgetIndex) + { + switch (widgetIndex) + { + case WIDX_UNCAP_FPS_CHECKBOX: + gConfigGeneral.uncap_fps ^= 1; + drawing_engine_set_vsync(gConfigGeneral.use_vsync); + config_save_default(); + this->Invalidate(); + break; + case WIDX_USE_VSYNC_CHECKBOX: + gConfigGeneral.use_vsync ^= 1; + drawing_engine_set_vsync(gConfigGeneral.use_vsync); + config_save_default(); + this->Invalidate(); + break; + case WIDX_SHOW_FPS_CHECKBOX: + gConfigGeneral.show_fps ^= 1; + config_save_default(); + this->Invalidate(); + break; + case WIDX_MULTITHREADING_CHECKBOX: + gConfigGeneral.multithreading ^= 1; + config_save_default(); + this->Invalidate(); + break; + case WIDX_MINIMIZE_FOCUS_LOSS: + gConfigGeneral.minimize_fullscreen_focus_loss ^= 1; + platform_refresh_video(false); + config_save_default(); + this->Invalidate(); + break; + case WIDX_STEAM_OVERLAY_PAUSE: + gConfigGeneral.steam_overlay_pause ^= 1; + config_save_default(); + this->Invalidate(); + break; + case WIDX_DISABLE_SCREENSAVER_LOCK: + gConfigGeneral.disable_screensaver ^= 1; + ApplyScreenSaverLockSetting(); + config_save_default(); + this->Invalidate(); + break; + } + } + + void DisplayMouseDown(rct_widgetindex widgetIndex) + { + rct_widget* widget = &this->widgets[widgetIndex - 1]; + + switch (widgetIndex) + { + case WIDX_RESOLUTION_DROPDOWN: + { + const auto& resolutions = OpenRCT2::GetContext()->GetUiContext()->GetFullscreenResolutions(); + + int32_t selectedResolution = -1; + for (size_t i = 0; i < resolutions.size(); i++) { - selectedResolution = static_cast(i); + const Resolution& resolution = resolutions[i]; + + gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL; + + uint16_t* args = reinterpret_cast(&gDropdownItemsArgs[i]); + args[0] = STR_RESOLUTION_X_BY_Y; + args[1] = resolution.Width; + args[2] = resolution.Height; + + if (resolution.Width == gConfigGeneral.fullscreen_width + && resolution.Height == gConfigGeneral.fullscreen_height) + { + selectedResolution = static_cast(i); + } + } + + this->ShowDropdown(widget, static_cast(resolutions.size())); + + if (selectedResolution != -1 && selectedResolution < 32) + { + Dropdown::SetChecked(selectedResolution, true); } } - window_options_show_dropdown(w, widget, static_cast(resolutions.size())); - - if (selectedResolution != -1 && selectedResolution < 32) - { - Dropdown::SetChecked(selectedResolution, true); - } - } - - break; - case WIDX_FULLSCREEN_DROPDOWN: - gDropdownItemsFormat[0] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsFormat[1] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsFormat[2] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsArgs[0] = STR_OPTIONS_DISPLAY_WINDOWED; - gDropdownItemsArgs[1] = STR_OPTIONS_DISPLAY_FULLSCREEN; - gDropdownItemsArgs[2] = STR_OPTIONS_DISPLAY_FULLSCREEN_BORDERLESS; - - window_options_show_dropdown(w, widget, 3); - - Dropdown::SetChecked(gConfigGeneral.fullscreen_mode, true); break; - case WIDX_DRAWING_ENGINE_DROPDOWN: - { - int32_t numItems = 3; + case WIDX_FULLSCREEN_DROPDOWN: + gDropdownItemsFormat[0] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsFormat[1] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsFormat[2] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsArgs[0] = STR_OPTIONS_DISPLAY_WINDOWED; + gDropdownItemsArgs[1] = STR_OPTIONS_DISPLAY_FULLSCREEN; + gDropdownItemsArgs[2] = STR_OPTIONS_DISPLAY_FULLSCREEN_BORDERLESS; + + this->ShowDropdown(widget, 3); + + Dropdown::SetChecked(gConfigGeneral.fullscreen_mode, true); + break; + case WIDX_DRAWING_ENGINE_DROPDOWN: + { + int32_t numItems = 3; #ifdef DISABLE_OPENGL - numItems = 2; + numItems = 2; #endif - for (int32_t i = 0; i < numItems; i++) - { - gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsArgs[i] = DrawingEngineStringIds[i]; + for (int32_t i = 0; i < numItems; i++) + { + gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsArgs[i] = DrawingEngineStringIds[i]; + } + this->ShowDropdown(widget, numItems); + Dropdown::SetChecked(EnumValue(gConfigGeneral.drawing_engine), true); + break; } - window_options_show_dropdown(w, widget, numItems); - Dropdown::SetChecked(EnumValue(gConfigGeneral.drawing_engine), true); - break; - } - case WIDX_SCALE_UP: - gConfigGeneral.window_scale += 0.25f; - config_save_default(); - gfx_invalidate_screen(); - context_trigger_resize(); - context_update_cursor_scale(); - break; - case WIDX_SCALE_DOWN: - gConfigGeneral.window_scale -= 0.25f; - gConfigGeneral.window_scale = std::max(0.5f, gConfigGeneral.window_scale); - config_save_default(); - gfx_invalidate_screen(); - context_trigger_resize(); - context_update_cursor_scale(); - break; - case WIDX_SCALE_QUALITY_DROPDOWN: - gDropdownItemsFormat[0] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsFormat[1] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsArgs[0] = STR_SCALING_QUALITY_LINEAR; - gDropdownItemsArgs[1] = STR_SCALING_QUALITY_SMOOTH_NN; - - window_options_show_dropdown(w, widget, 2); - - // Note: offset by one to compensate for lack of NN option. - Dropdown::SetChecked(static_cast(gConfigGeneral.scale_quality) - 1, true); - break; - } -} - -static void window_options_display_dropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex) -{ - if (dropdownIndex == -1) - return; - - switch (widgetIndex) - { - case WIDX_RESOLUTION_DROPDOWN: - { - const auto& resolutions = OpenRCT2::GetContext()->GetUiContext()->GetFullscreenResolutions(); - - const Resolution& resolution = resolutions[dropdownIndex]; - if (resolution.Width != gConfigGeneral.fullscreen_width || resolution.Height != gConfigGeneral.fullscreen_height) - { - gConfigGeneral.fullscreen_width = resolution.Width; - gConfigGeneral.fullscreen_height = resolution.Height; - - if (gConfigGeneral.fullscreen_mode == static_cast(OpenRCT2::Ui::FULLSCREEN_MODE::FULLSCREEN)) - context_set_fullscreen_mode(static_cast(OpenRCT2::Ui::FULLSCREEN_MODE::FULLSCREEN)); - - config_save_default(); - gfx_invalidate_screen(); - } - } - break; - case WIDX_FULLSCREEN_DROPDOWN: - if (dropdownIndex != gConfigGeneral.fullscreen_mode) - { - context_set_fullscreen_mode(dropdownIndex); - - gConfigGeneral.fullscreen_mode = static_cast(dropdownIndex); - config_save_default(); - gfx_invalidate_screen(); - } - break; - case WIDX_DRAWING_ENGINE_DROPDOWN: - if (dropdownIndex != EnumValue(gConfigGeneral.drawing_engine)) - { - DrawingEngine srcEngine = drawing_engine_get_type(); - DrawingEngine dstEngine = static_cast(dropdownIndex); - - gConfigGeneral.drawing_engine = dstEngine; - bool recreate_window = drawing_engine_requires_new_window(srcEngine, dstEngine); - platform_refresh_video(recreate_window); - config_save_default(); - w->Invalidate(); - } - break; - case WIDX_SCALE_QUALITY_DROPDOWN: - // Note: offset by one to compensate for lack of NN option. - if (static_cast(dropdownIndex + 1) != gConfigGeneral.scale_quality) - { - gConfigGeneral.scale_quality = static_cast(dropdownIndex + 1); + case WIDX_SCALE_UP: + gConfigGeneral.window_scale += 0.25f; config_save_default(); gfx_invalidate_screen(); context_trigger_resize(); - } - break; - } -} - -static void window_options_display_invalidate(rct_window* w) -{ - window_options_common_invalidate_before(w); - - // Resolution dropdown caption. - auto ft = Formatter::Common(); - ft.Increment(16); - ft.Add(static_cast(gConfigGeneral.fullscreen_width)); - ft.Add(static_cast(gConfigGeneral.fullscreen_height)); - - // Disable resolution dropdown on "Windowed" and "Fullscreen (desktop)" - if (gConfigGeneral.fullscreen_mode != static_cast(OpenRCT2::Ui::FULLSCREEN_MODE::FULLSCREEN)) - { - w->disabled_widgets |= (1ULL << WIDX_RESOLUTION_DROPDOWN); - w->disabled_widgets |= (1ULL << WIDX_RESOLUTION); - } - else - { - w->disabled_widgets &= ~(1ULL << WIDX_RESOLUTION_DROPDOWN); - w->disabled_widgets &= ~(1ULL << WIDX_RESOLUTION); - } - - // Disable Steam Overlay checkbox when using software rendering. - if (gConfigGeneral.drawing_engine == DrawingEngine::Software) - { - w->disabled_widgets |= (1ULL << WIDX_STEAM_OVERLAY_PAUSE); - } - else - { - w->disabled_widgets &= ~(1ULL << WIDX_STEAM_OVERLAY_PAUSE); - } - - // Disable scaling quality dropdown when using software rendering or when using an integer scalar. - // In the latter case, nearest neighbour rendering will be used to scale. - if (gConfigGeneral.drawing_engine == DrawingEngine::Software - || gConfigGeneral.window_scale == std::floor(gConfigGeneral.window_scale)) - { - w->disabled_widgets |= (1ULL << WIDX_SCALE_QUALITY); - w->disabled_widgets |= (1ULL << WIDX_SCALE_QUALITY_DROPDOWN); - } - else - { - w->disabled_widgets &= ~(1ULL << WIDX_SCALE_QUALITY); - w->disabled_widgets &= ~(1ULL << WIDX_SCALE_QUALITY_DROPDOWN); - } - - // Disable changing VSync for Software engine, as we can't control its use of VSync - if (gConfigGeneral.drawing_engine == DrawingEngine::Software) - { - w->disabled_widgets |= (1ULL << WIDX_USE_VSYNC_CHECKBOX); - } - else - { - w->disabled_widgets &= ~(1ULL << WIDX_USE_VSYNC_CHECKBOX); - } - - WidgetSetCheckboxValue(w, WIDX_UNCAP_FPS_CHECKBOX, gConfigGeneral.uncap_fps); - WidgetSetCheckboxValue(w, WIDX_USE_VSYNC_CHECKBOX, gConfigGeneral.use_vsync); - WidgetSetCheckboxValue(w, WIDX_SHOW_FPS_CHECKBOX, gConfigGeneral.show_fps); - WidgetSetCheckboxValue(w, WIDX_MULTITHREADING_CHECKBOX, gConfigGeneral.multithreading); - WidgetSetCheckboxValue(w, WIDX_MINIMIZE_FOCUS_LOSS, gConfigGeneral.minimize_fullscreen_focus_loss); - WidgetSetCheckboxValue(w, WIDX_STEAM_OVERLAY_PAUSE, gConfigGeneral.steam_overlay_pause); - WidgetSetCheckboxValue(w, WIDX_DISABLE_SCREENSAVER_LOCK, gConfigGeneral.disable_screensaver); - - // Dropdown captions for straightforward strings. - window_options_display_widgets[WIDX_FULLSCREEN].text = window_options_fullscreen_mode_names[gConfigGeneral.fullscreen_mode]; - window_options_display_widgets[WIDX_DRAWING_ENGINE].text = DrawingEngineStringIds[EnumValue(gConfigGeneral.drawing_engine)]; - window_options_display_widgets[WIDX_SCALE_QUALITY].text = window_options_scale_quality_names - [static_cast(gConfigGeneral.scale_quality) - 1]; - - window_options_common_invalidate_after(w); -} - -static void window_options_display_paint(rct_window* w, rct_drawpixelinfo* dpi) -{ - WindowDrawWidgets(w, dpi); - window_options_draw_tab_images(dpi, w); - - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ 10, window_options_display_widgets[WIDX_FULLSCREEN].top + 1 }, STR_FULLSCREEN_MODE, - {}, { w->colours[1] }); - - // Disable resolution dropdown on "Windowed" and "Fullscreen (desktop)" - colour_t colour = w->colours[1]; - if (gConfigGeneral.fullscreen_mode != static_cast(OpenRCT2::Ui::FULLSCREEN_MODE::FULLSCREEN)) - { - colour |= COLOUR_FLAG_INSET; - } - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ 10 + 15, window_options_display_widgets[WIDX_RESOLUTION].top + 1 }, - STR_DISPLAY_RESOLUTION, {}, { colour }); - - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ 10, window_options_display_widgets[WIDX_SCALE].top + 1 }, STR_UI_SCALING_DESC, {}, - { w->colours[1] }); - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ 10, window_options_display_widgets[WIDX_DRAWING_ENGINE].top + 1 }, - STR_DRAWING_ENGINE, {}, { w->colours[1] }); - - auto ft = Formatter(); - ft.Add(static_cast(gConfigGeneral.window_scale * 100)); - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ w->widgets[WIDX_SCALE].left + 1, w->widgets[WIDX_SCALE].top + 1 }, - STR_WINDOW_OBJECTIVE_VALUE_RATING, ft, { w->colours[1] }); - - colour = w->colours[1]; - if (gConfigGeneral.drawing_engine == DrawingEngine::Software - || gConfigGeneral.window_scale == std::floor(gConfigGeneral.window_scale)) - { - colour |= COLOUR_FLAG_INSET; - } - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ 25, window_options_display_widgets[WIDX_SCALE_QUALITY].top + 1 }, - STR_SCALING_QUALITY, {}, { colour }); -} - -#pragma region Rendering Tab - -static void window_options_rendering_mouseup(rct_window* w, rct_widgetindex widgetIndex) -{ - if (widgetIndex < WIDX_PAGE_START) - return window_options_common_mouseup(w, widgetIndex); - - switch (widgetIndex) - { - case WIDX_TILE_SMOOTHING_CHECKBOX: - gConfigGeneral.landscape_smoothing ^= 1; - config_save_default(); - gfx_invalidate_screen(); - break; - case WIDX_GRIDLINES_CHECKBOX: - gConfigGeneral.always_show_gridlines ^= 1; - config_save_default(); - gfx_invalidate_screen(); - if ((w = window_get_main()) != nullptr) - { - if (gConfigGeneral.always_show_gridlines) - w->viewport->flags |= VIEWPORT_FLAG_GRIDLINES; - else - w->viewport->flags &= ~VIEWPORT_FLAG_GRIDLINES; - } - break; - case WIDX_DAY_NIGHT_CHECKBOX: - gConfigGeneral.day_night_cycle ^= 1; - config_save_default(); - w->Invalidate(); - break; - case WIDX_ENABLE_LIGHT_FX_CHECKBOX: - gConfigGeneral.enable_light_fx ^= 1; - config_save_default(); - w->Invalidate(); - break; - case WIDX_ENABLE_LIGHT_FX_FOR_VEHICLES_CHECKBOX: - gConfigGeneral.enable_light_fx_for_vehicles ^= 1; - config_save_default(); - w->Invalidate(); - break; - case WIDX_UPPER_CASE_BANNERS_CHECKBOX: - gConfigGeneral.upper_case_banners ^= 1; - config_save_default(); - w->Invalidate(); - break; - case WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX: - gConfigGeneral.disable_lightning_effect ^= 1; - config_save_default(); - w->Invalidate(); - break; - case WIDX_RENDER_WEATHER_EFFECTS_CHECKBOX: - gConfigGeneral.render_weather_effects ^= 1; - gConfigGeneral.render_weather_gloom = gConfigGeneral.render_weather_effects; - config_save_default(); - w->Invalidate(); - gfx_invalidate_screen(); - break; - case WIDX_SHOW_GUEST_PURCHASES_CHECKBOX: - gConfigGeneral.show_guest_purchases ^= 1; - config_save_default(); - w->Invalidate(); - break; - case WIDX_TRANSPARENT_SCREENSHOTS_CHECKBOX: - gConfigGeneral.transparent_screenshot ^= 1; - config_save_default(); - w->Invalidate(); - break; - } -} - -static void window_options_rendering_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget) -{ - switch (widgetIndex) - { - case WIDX_VIRTUAL_FLOOR_DROPDOWN: - gDropdownItemsFormat[0] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsFormat[1] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsFormat[2] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsArgs[0] = STR_VIRTUAL_FLOOR_STYLE_DISABLED; - gDropdownItemsArgs[1] = STR_VIRTUAL_FLOOR_STYLE_TRANSPARENT; - gDropdownItemsArgs[2] = STR_VIRTUAL_FLOOR_STYLE_GLASSY; - - widget = &w->widgets[widgetIndex - 1]; - window_options_show_dropdown(w, widget, 3); - - Dropdown::SetChecked(static_cast(gConfigGeneral.virtual_floor_style), true); - break; - } -} - -static void window_options_rendering_dropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex) -{ - if (dropdownIndex == -1) - return; - - switch (widgetIndex) - { - case WIDX_VIRTUAL_FLOOR_DROPDOWN: - gConfigGeneral.virtual_floor_style = static_cast(dropdownIndex); - config_save_default(); - break; - } -} - -static void window_options_rendering_invalidate(rct_window* w) -{ - window_options_common_invalidate_before(w); - - WidgetSetCheckboxValue(w, WIDX_TILE_SMOOTHING_CHECKBOX, gConfigGeneral.landscape_smoothing); - WidgetSetCheckboxValue(w, WIDX_GRIDLINES_CHECKBOX, gConfigGeneral.always_show_gridlines); - WidgetSetCheckboxValue(w, WIDX_DAY_NIGHT_CHECKBOX, gConfigGeneral.day_night_cycle); - WidgetSetCheckboxValue(w, WIDX_SHOW_GUEST_PURCHASES_CHECKBOX, gConfigGeneral.show_guest_purchases); - WidgetSetCheckboxValue(w, WIDX_TRANSPARENT_SCREENSHOTS_CHECKBOX, gConfigGeneral.transparent_screenshot); - WidgetSetCheckboxValue(w, WIDX_UPPER_CASE_BANNERS_CHECKBOX, gConfigGeneral.upper_case_banners); - - rct_string_id VirtualFloorStyleStrings[] = { STR_VIRTUAL_FLOOR_STYLE_DISABLED, STR_VIRTUAL_FLOOR_STYLE_TRANSPARENT, - STR_VIRTUAL_FLOOR_STYLE_GLASSY }; - - window_options_rendering_widgets[WIDX_VIRTUAL_FLOOR].text = VirtualFloorStyleStrings[static_cast( - gConfigGeneral.virtual_floor_style)]; - - WidgetSetCheckboxValue(w, WIDX_ENABLE_LIGHT_FX_CHECKBOX, gConfigGeneral.enable_light_fx); - if (gConfigGeneral.day_night_cycle && gConfigGeneral.drawing_engine == DrawingEngine::SoftwareWithHardwareDisplay) - { - w->disabled_widgets &= ~(1ULL << WIDX_ENABLE_LIGHT_FX_CHECKBOX); - } - else - { - w->disabled_widgets |= (1ULL << WIDX_ENABLE_LIGHT_FX_CHECKBOX); - gConfigGeneral.enable_light_fx = false; - } - - WidgetSetCheckboxValue(w, WIDX_ENABLE_LIGHT_FX_FOR_VEHICLES_CHECKBOX, gConfigGeneral.enable_light_fx_for_vehicles); - if (gConfigGeneral.day_night_cycle && gConfigGeneral.drawing_engine == DrawingEngine::SoftwareWithHardwareDisplay - && gConfigGeneral.enable_light_fx) - { - w->disabled_widgets &= ~(1ULL << WIDX_ENABLE_LIGHT_FX_FOR_VEHICLES_CHECKBOX); - } - else - { - w->disabled_widgets |= (1ULL << WIDX_ENABLE_LIGHT_FX_FOR_VEHICLES_CHECKBOX); - gConfigGeneral.enable_light_fx_for_vehicles = false; - } - - WidgetSetCheckboxValue( - w, WIDX_RENDER_WEATHER_EFFECTS_CHECKBOX, gConfigGeneral.render_weather_effects || gConfigGeneral.render_weather_gloom); - WidgetSetCheckboxValue(w, WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX, gConfigGeneral.disable_lightning_effect); - if (!gConfigGeneral.render_weather_effects && !gConfigGeneral.render_weather_gloom) - { - WidgetSetCheckboxValue(w, WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX, true); - w->enabled_widgets &= ~(1ULL << WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX); - w->disabled_widgets |= (1ULL << WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX); - } - else - { - w->enabled_widgets |= (1ULL << WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX); - w->disabled_widgets &= ~(1ULL << WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX); - } - - window_options_common_invalidate_after(w); -} - -static void window_options_rendering_paint(rct_window* w, rct_drawpixelinfo* dpi) -{ - WindowDrawWidgets(w, dpi); - window_options_draw_tab_images(dpi, w); -} - -#pragma region Culture Tab - -static void window_options_culture_mouseup(rct_window* w, rct_widgetindex widgetIndex) -{ - if (widgetIndex < WIDX_PAGE_START) - return window_options_common_mouseup(w, widgetIndex); -} - -static void window_options_culture_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget) -{ - widget = &w->widgets[widgetIndex - 1]; - - switch (widgetIndex) - { - case WIDX_HEIGHT_LABELS_DROPDOWN: - gDropdownItemsFormat[0] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsFormat[1] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsArgs[0] = STR_HEIGHT_IN_UNITS; - gDropdownItemsArgs[1] = STR_REAL_VALUES; - - window_options_show_dropdown(w, widget, 2); - - Dropdown::SetChecked(gConfigGeneral.show_height_as_units ? 0 : 1, true); - break; - case WIDX_CURRENCY_DROPDOWN: - { - constexpr auto num_items = EnumValue(CurrencyType::Count) + 1; // All the currencies plus the separator - size_t num_ordinary_currencies = EnumValue(CurrencyType::Count) - 1; // All the currencies except custom currency - - for (size_t i = 0; i < num_ordinary_currencies; i++) - { - gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsArgs[i] = CurrencyDescriptors[i].stringId; - } - - gDropdownItemsFormat[num_ordinary_currencies] = Dropdown::SeparatorString; - - gDropdownItemsFormat[num_ordinary_currencies + 1] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsArgs[num_ordinary_currencies + 1] = CurrencyDescriptors[EnumValue(CurrencyType::Custom)].stringId; - - window_options_show_dropdown(w, widget, num_items); - - if (gConfigGeneral.currency_format == CurrencyType::Custom) - { - Dropdown::SetChecked(EnumValue(gConfigGeneral.currency_format) + 1, true); - } - else - { - Dropdown::SetChecked(EnumValue(gConfigGeneral.currency_format), true); - } - break; - } - case WIDX_DISTANCE_DROPDOWN: - gDropdownItemsFormat[0] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsFormat[1] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsFormat[2] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsArgs[0] = STR_IMPERIAL; - gDropdownItemsArgs[1] = STR_METRIC; - gDropdownItemsArgs[2] = STR_SI; - - window_options_show_dropdown(w, widget, 3); - - Dropdown::SetChecked(static_cast(gConfigGeneral.measurement_format), true); - break; - case WIDX_TEMPERATURE_DROPDOWN: - gDropdownItemsFormat[0] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsFormat[1] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsArgs[0] = STR_CELSIUS; - gDropdownItemsArgs[1] = STR_FAHRENHEIT; - - window_options_show_dropdown(w, widget, 2); - - Dropdown::SetChecked(static_cast(gConfigGeneral.temperature_format), true); - break; - case WIDX_LANGUAGE_DROPDOWN: - for (size_t i = 1; i < LANGUAGE_COUNT; i++) - { - gDropdownItemsFormat[i - 1] = STR_OPTIONS_DROPDOWN_ITEM; - gDropdownItemsArgs[i - 1] = reinterpret_cast(LanguagesDescriptors[i].native_name); - } - window_options_show_dropdown(w, widget, LANGUAGE_COUNT - 1); - Dropdown::SetChecked(LocalisationService_GetCurrentLanguage() - 1, true); - break; - case WIDX_DATE_FORMAT_DROPDOWN: - for (size_t i = 0; i < 4; i++) - { - gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsArgs[i] = DateFormatStringIds[i]; - } - window_options_show_dropdown(w, widget, 4); - Dropdown::SetChecked(gConfigGeneral.date_format, true); - break; - } -} - -static void window_options_culture_dropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex) -{ - if (dropdownIndex == -1) - return; - - switch (widgetIndex) - { - case WIDX_HEIGHT_LABELS_DROPDOWN: - // reset flag and set it to 1 if height as units is selected - gConfigGeneral.show_height_as_units = 0; - - if (dropdownIndex == 0) - { - gConfigGeneral.show_height_as_units = 1; - } - config_save_default(); - window_options_update_height_markers(); - break; - case WIDX_CURRENCY_DROPDOWN: - if (dropdownIndex == EnumValue(CurrencyType::Custom) + 1) - { // Add 1 because the separator occupies a position - gConfigGeneral.currency_format = static_cast(dropdownIndex - 1); - context_open_window(WC_CUSTOM_CURRENCY_CONFIG); - } - else - { - gConfigGeneral.currency_format = static_cast(dropdownIndex); - } - config_save_default(); - gfx_invalidate_screen(); - break; - case WIDX_DISTANCE_DROPDOWN: - gConfigGeneral.measurement_format = static_cast(dropdownIndex); - config_save_default(); - window_options_update_height_markers(); - break; - case WIDX_TEMPERATURE_DROPDOWN: - if (dropdownIndex != static_cast(gConfigGeneral.temperature_format)) - { - gConfigGeneral.temperature_format = static_cast(dropdownIndex); + context_update_cursor_scale(); + break; + case WIDX_SCALE_DOWN: + gConfigGeneral.window_scale -= 0.25f; + gConfigGeneral.window_scale = std::max(0.5f, gConfigGeneral.window_scale); config_save_default(); gfx_invalidate_screen(); - } - break; - case WIDX_LANGUAGE_DROPDOWN: + context_trigger_resize(); + context_update_cursor_scale(); + break; + case WIDX_SCALE_QUALITY_DROPDOWN: + gDropdownItemsFormat[0] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsFormat[1] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsArgs[0] = STR_SCALING_QUALITY_LINEAR; + gDropdownItemsArgs[1] = STR_SCALING_QUALITY_SMOOTH_NN; + + this->ShowDropdown(widget, 2); + + // Note: offset by one to compensate for lack of NN option. + Dropdown::SetChecked(static_cast(gConfigGeneral.scale_quality) - 1, true); + break; + } + } + + void DisplayDropdown(rct_widgetindex widgetIndex, int32_t dropdownIndex) + { + if (dropdownIndex == -1) + return; + + switch (widgetIndex) { - auto fallbackLanguage = LocalisationService_GetCurrentLanguage(); - if (dropdownIndex != LocalisationService_GetCurrentLanguage() - 1) + case WIDX_RESOLUTION_DROPDOWN: { - if (!language_open(dropdownIndex + 1)) + const auto& resolutions = OpenRCT2::GetContext()->GetUiContext()->GetFullscreenResolutions(); + + const Resolution& resolution = resolutions[dropdownIndex]; + if (resolution.Width != gConfigGeneral.fullscreen_width + || resolution.Height != gConfigGeneral.fullscreen_height) { - // Failed to open language file, try to recover by falling - // back to previously used language - if (language_open(fallbackLanguage)) - { - // It worked, so we can say it with error message in-game - context_show_error(STR_LANGUAGE_LOAD_FAILED, STR_NONE, {}); - } - // report error to console regardless - log_error("Failed to open language file."); - } - else - { - gConfigGeneral.language = dropdownIndex + 1; + gConfigGeneral.fullscreen_width = resolution.Width; + gConfigGeneral.fullscreen_height = resolution.Height; + + if (gConfigGeneral.fullscreen_mode == static_cast(OpenRCT2::Ui::FULLSCREEN_MODE::FULLSCREEN)) + context_set_fullscreen_mode(static_cast(OpenRCT2::Ui::FULLSCREEN_MODE::FULLSCREEN)); + config_save_default(); gfx_invalidate_screen(); } } + break; + case WIDX_FULLSCREEN_DROPDOWN: + if (dropdownIndex != gConfigGeneral.fullscreen_mode) + { + context_set_fullscreen_mode(dropdownIndex); + + gConfigGeneral.fullscreen_mode = static_cast(dropdownIndex); + config_save_default(); + gfx_invalidate_screen(); + } + break; + case WIDX_DRAWING_ENGINE_DROPDOWN: + if (dropdownIndex != EnumValue(gConfigGeneral.drawing_engine)) + { + DrawingEngine srcEngine = drawing_engine_get_type(); + DrawingEngine dstEngine = static_cast(dropdownIndex); + + gConfigGeneral.drawing_engine = dstEngine; + bool recreate_window = drawing_engine_requires_new_window(srcEngine, dstEngine); + platform_refresh_video(recreate_window); + config_save_default(); + this->Invalidate(); + } + break; + case WIDX_SCALE_QUALITY_DROPDOWN: + // Note: offset by one to compensate for lack of NN option. + if (static_cast(dropdownIndex + 1) != gConfigGeneral.scale_quality) + { + gConfigGeneral.scale_quality = static_cast(dropdownIndex + 1); + config_save_default(); + gfx_invalidate_screen(); + context_trigger_resize(); + } + break; } - break; - case WIDX_DATE_FORMAT_DROPDOWN: - if (dropdownIndex != gConfigGeneral.date_format) - { - gConfigGeneral.date_format = static_cast(dropdownIndex); + } + + void DisplayPrepareDraw() + { + CommonPrepareDrawBefore(); + + // Resolution dropdown caption. + auto ft = Formatter::Common(); + ft.Increment(16); + ft.Add(static_cast(gConfigGeneral.fullscreen_width)); + ft.Add(static_cast(gConfigGeneral.fullscreen_height)); + + // Disable resolution dropdown on "Windowed" and "Fullscreen (desktop)" + if (gConfigGeneral.fullscreen_mode != static_cast(OpenRCT2::Ui::FULLSCREEN_MODE::FULLSCREEN)) + { + this->disabled_widgets |= (1ULL << WIDX_RESOLUTION_DROPDOWN); + this->disabled_widgets |= (1ULL << WIDX_RESOLUTION); + } + else + { + this->disabled_widgets &= ~(1ULL << WIDX_RESOLUTION_DROPDOWN); + this->disabled_widgets &= ~(1ULL << WIDX_RESOLUTION); + } + + // Disable Steam Overlay checkbox when using software rendering. + if (gConfigGeneral.drawing_engine == DrawingEngine::Software) + { + this->disabled_widgets |= (1ULL << WIDX_STEAM_OVERLAY_PAUSE); + } + else + { + this->disabled_widgets &= ~(1ULL << WIDX_STEAM_OVERLAY_PAUSE); + } + + // Disable scaling quality dropdown when using software rendering or when using an integer scalar. + // In the latter case, nearest neighbour rendering will be used to scale. + if (gConfigGeneral.drawing_engine == DrawingEngine::Software + || gConfigGeneral.window_scale == std::floor(gConfigGeneral.window_scale)) + { + this->disabled_widgets |= (1ULL << WIDX_SCALE_QUALITY); + this->disabled_widgets |= (1ULL << WIDX_SCALE_QUALITY_DROPDOWN); + } + else + { + this->disabled_widgets &= ~(1ULL << WIDX_SCALE_QUALITY); + this->disabled_widgets &= ~(1ULL << WIDX_SCALE_QUALITY_DROPDOWN); + } + + // Disable changing VSync for Software engine, as we can't control its use of VSync + if (gConfigGeneral.drawing_engine == DrawingEngine::Software) + { + this->disabled_widgets |= (1ULL << WIDX_USE_VSYNC_CHECKBOX); + } + else + { + this->disabled_widgets &= ~(1ULL << WIDX_USE_VSYNC_CHECKBOX); + } + + WidgetSetCheckboxValue(this, WIDX_UNCAP_FPS_CHECKBOX, gConfigGeneral.uncap_fps); + WidgetSetCheckboxValue(this, WIDX_USE_VSYNC_CHECKBOX, gConfigGeneral.use_vsync); + WidgetSetCheckboxValue(this, WIDX_SHOW_FPS_CHECKBOX, gConfigGeneral.show_fps); + WidgetSetCheckboxValue(this, WIDX_MULTITHREADING_CHECKBOX, gConfigGeneral.multithreading); + WidgetSetCheckboxValue(this, WIDX_MINIMIZE_FOCUS_LOSS, gConfigGeneral.minimize_fullscreen_focus_loss); + WidgetSetCheckboxValue(this, WIDX_STEAM_OVERLAY_PAUSE, gConfigGeneral.steam_overlay_pause); + WidgetSetCheckboxValue(this, WIDX_DISABLE_SCREENSAVER_LOCK, gConfigGeneral.disable_screensaver); + + // Dropdown captions for straightforward strings. + this->widgets[WIDX_FULLSCREEN].text = window_options_fullscreen_mode_names[gConfigGeneral.fullscreen_mode]; + this->widgets[WIDX_DRAWING_ENGINE].text = DrawingEngineStringIds[EnumValue(gConfigGeneral.drawing_engine)]; + this->widgets[WIDX_SCALE_QUALITY].text = window_options_scale_quality_names + [static_cast(gConfigGeneral.scale_quality) - 1]; + + CommonPrepareDrawAfter(); + } + + void DisplayDraw(rct_drawpixelinfo* dpi) + { + WindowDrawWidgets(this, dpi); + this->DrawTabImages(dpi); + + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ 10, this->widgets[WIDX_FULLSCREEN].top + 1 }, STR_FULLSCREEN_MODE, {}, + { this->colours[1] }); + + // Disable resolution dropdown on "Windowed" and "Fullscreen (desktop)" + colour_t colour = this->colours[1]; + if (gConfigGeneral.fullscreen_mode != static_cast(OpenRCT2::Ui::FULLSCREEN_MODE::FULLSCREEN)) + { + colour |= COLOUR_FLAG_INSET; + } + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ 10 + 15, this->widgets[WIDX_RESOLUTION].top + 1 }, STR_DISPLAY_RESOLUTION, + {}, { colour }); + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ 10, this->widgets[WIDX_SCALE].top + 1 }, STR_UI_SCALING_DESC, {}, + { this->colours[1] }); + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ 10, this->widgets[WIDX_DRAWING_ENGINE].top + 1 }, STR_DRAWING_ENGINE, {}, + { this->colours[1] }); + + auto ft = Formatter(); + ft.Add(static_cast(gConfigGeneral.window_scale * 100)); + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ this->widgets[WIDX_SCALE].left + 1, this->widgets[WIDX_SCALE].top + 1 }, + STR_WINDOW_OBJECTIVE_VALUE_RATING, ft, { this->colours[1] }); + + colour = this->colours[1]; + if (gConfigGeneral.drawing_engine == DrawingEngine::Software + || gConfigGeneral.window_scale == std::floor(gConfigGeneral.window_scale)) + { + colour |= COLOUR_FLAG_INSET; + } + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ 25, this->widgets[WIDX_SCALE_QUALITY].top + 1 }, STR_SCALING_QUALITY, {}, + { colour }); + } +#pragma endregion + +#pragma region Rendering tab events + void RenderingMouseUp(rct_widgetindex widgetIndex) + { + switch (widgetIndex) + { + case WIDX_TILE_SMOOTHING_CHECKBOX: + gConfigGeneral.landscape_smoothing ^= 1; config_save_default(); gfx_invalidate_screen(); + break; + case WIDX_GRIDLINES_CHECKBOX: + { + gConfigGeneral.always_show_gridlines ^= 1; + config_save_default(); + gfx_invalidate_screen(); + rct_window* mainWindow = window_get_main(); + if (mainWindow != nullptr) + { + if (gConfigGeneral.always_show_gridlines) + mainWindow->viewport->flags |= VIEWPORT_FLAG_GRIDLINES; + else + mainWindow->viewport->flags &= ~VIEWPORT_FLAG_GRIDLINES; + } + break; } - break; - } -} - -static void window_options_culture_invalidate(rct_window* w) -{ - window_options_common_invalidate_before(w); - - // Language - auto ft = Formatter::Common(); - ft.Add(LanguagesDescriptors[LocalisationService_GetCurrentLanguage()].native_name); - - // Currency: pounds, dollars, etc. (10 total) - window_options_culture_widgets[WIDX_CURRENCY].text = CurrencyDescriptors[EnumValue(gConfigGeneral.currency_format)] - .stringId; - - // Distance: metric / imperial / si - { - rct_string_id stringId = STR_NONE; - switch (gConfigGeneral.measurement_format) - { - case MeasurementFormat::Imperial: - stringId = STR_IMPERIAL; + case WIDX_DAY_NIGHT_CHECKBOX: + gConfigGeneral.day_night_cycle ^= 1; + config_save_default(); + this->Invalidate(); break; - case MeasurementFormat::Metric: - stringId = STR_METRIC; + case WIDX_ENABLE_LIGHT_FX_CHECKBOX: + gConfigGeneral.enable_light_fx ^= 1; + config_save_default(); + this->Invalidate(); break; - case MeasurementFormat::SI: - stringId = STR_SI; + case WIDX_ENABLE_LIGHT_FX_FOR_VEHICLES_CHECKBOX: + gConfigGeneral.enable_light_fx_for_vehicles ^= 1; + config_save_default(); + this->Invalidate(); + break; + case WIDX_UPPER_CASE_BANNERS_CHECKBOX: + gConfigGeneral.upper_case_banners ^= 1; + config_save_default(); + this->Invalidate(); + break; + case WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX: + gConfigGeneral.disable_lightning_effect ^= 1; + config_save_default(); + this->Invalidate(); + break; + case WIDX_RENDER_WEATHER_EFFECTS_CHECKBOX: + gConfigGeneral.render_weather_effects ^= 1; + gConfigGeneral.render_weather_gloom = gConfigGeneral.render_weather_effects; + config_save_default(); + this->Invalidate(); + gfx_invalidate_screen(); + break; + case WIDX_SHOW_GUEST_PURCHASES_CHECKBOX: + gConfigGeneral.show_guest_purchases ^= 1; + config_save_default(); + this->Invalidate(); + break; + case WIDX_TRANSPARENT_SCREENSHOTS_CHECKBOX: + gConfigGeneral.transparent_screenshot ^= 1; + config_save_default(); + this->Invalidate(); break; } - window_options_culture_widgets[WIDX_DISTANCE].text = stringId; } - // Date format - window_options_culture_widgets[WIDX_DATE_FORMAT].text = DateFormatStringIds[gConfigGeneral.date_format]; - - // Temperature: celsius/fahrenheit - window_options_culture_widgets[WIDX_TEMPERATURE].text = gConfigGeneral.temperature_format == TemperatureUnit::Fahrenheit - ? STR_FAHRENHEIT - : STR_CELSIUS; - - // Height: units/real values - window_options_culture_widgets[WIDX_HEIGHT_LABELS].text = gConfigGeneral.show_height_as_units ? STR_HEIGHT_IN_UNITS - : STR_REAL_VALUES; - - window_options_common_invalidate_after(w); -} - -static void window_options_culture_paint(rct_window* w, rct_drawpixelinfo* dpi) -{ - WindowDrawWidgets(w, dpi); - window_options_draw_tab_images(dpi, w); - - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ 10, window_options_culture_widgets[WIDX_LANGUAGE].top + 1 }, STR_OPTIONS_LANGUAGE, - {}, { w->colours[1] }); - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ 10, window_options_culture_widgets[WIDX_CURRENCY].top + 1 }, STR_CURRENCY, {}, - { w->colours[1] }); - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ 10, window_options_culture_widgets[WIDX_DISTANCE].top + 1 }, STR_DISTANCE_AND_SPEED, - {}, { w->colours[1] }); - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ 10, window_options_culture_widgets[WIDX_TEMPERATURE].top + 1 }, STR_TEMPERATURE, {}, - { w->colours[1] }); - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ 10, window_options_culture_widgets[WIDX_HEIGHT_LABELS].top + 1 }, STR_HEIGHT_LABELS, - {}, { w->colours[1] }); - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ 10, window_options_culture_widgets[WIDX_DATE_FORMAT].top + 1 }, STR_DATE_FORMAT, {}, - { w->colours[1] }); -} - -#pragma region Audio Tab - -static void window_options_audio_mouseup(rct_window* w, rct_widgetindex widgetIndex) -{ - if (widgetIndex < WIDX_PAGE_START) - return window_options_common_mouseup(w, widgetIndex); - - switch (widgetIndex) + void RenderingMouseDown(rct_widgetindex widgetIndex) { - case WIDX_SOUND_CHECKBOX: - gConfigSound.sound_enabled = !gConfigSound.sound_enabled; - config_save_default(); - w->Invalidate(); - break; + switch (widgetIndex) + { + case WIDX_VIRTUAL_FLOOR_DROPDOWN: + gDropdownItemsFormat[0] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsFormat[1] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsFormat[2] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsArgs[0] = STR_VIRTUAL_FLOOR_STYLE_DISABLED; + gDropdownItemsArgs[1] = STR_VIRTUAL_FLOOR_STYLE_TRANSPARENT; + gDropdownItemsArgs[2] = STR_VIRTUAL_FLOOR_STYLE_GLASSY; - case WIDX_MASTER_SOUND_CHECKBOX: - gConfigSound.master_sound_enabled = !gConfigSound.master_sound_enabled; - if (!gConfigSound.master_sound_enabled) - OpenRCT2::Audio::Pause(); - else - OpenRCT2::Audio::Resume(); - window_invalidate_by_class(WC_TOP_TOOLBAR); - config_save_default(); - w->Invalidate(); - break; + rct_widget* widget = &this->widgets[widgetIndex - 1]; + this->ShowDropdown(widget, 3); - case WIDX_MUSIC_CHECKBOX: - gConfigSound.ride_music_enabled = !gConfigSound.ride_music_enabled; - if (!gConfigSound.ride_music_enabled) - { - OpenRCT2::RideAudio::StopAllChannels(); - } - config_save_default(); - w->Invalidate(); - break; - - case WIDX_AUDIO_FOCUS_CHECKBOX: - gConfigSound.audio_focus = !gConfigSound.audio_focus; - config_save_default(); - w->Invalidate(); - break; + Dropdown::SetChecked(static_cast(gConfigGeneral.virtual_floor_style), true); + break; + } } -} -static void window_options_audio_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget) -{ - widget = &w->widgets[widgetIndex - 1]; - - switch (widgetIndex) + void RenderingDropdown(rct_widgetindex widgetIndex, int32_t dropdownIndex) { - case WIDX_SOUND_DROPDOWN: - OpenRCT2::Audio::PopulateDevices(); + if (dropdownIndex == -1) + return; - // populate the list with the sound devices - for (int32_t i = 0; i < OpenRCT2::Audio::GetDeviceCount(); i++) - { - gDropdownItemsFormat[i] = STR_OPTIONS_DROPDOWN_ITEM; - gDropdownItemsArgs[i] = reinterpret_cast(OpenRCT2::Audio::GetDeviceName(i).c_str()); - } - - window_options_show_dropdown(w, widget, OpenRCT2::Audio::GetDeviceCount()); - - Dropdown::SetChecked(OpenRCT2::Audio::GetCurrentDeviceIndex(), true); - break; - case WIDX_TITLE_MUSIC_DROPDOWN: - uint32_t num_items = 4; - - for (size_t i = 0; i < num_items; i++) - { - gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsArgs[i] = window_options_title_music_names[i]; - } - - window_options_show_dropdown(w, widget, num_items); - - Dropdown::SetChecked(gConfigSound.title_music, true); - break; + switch (widgetIndex) + { + case WIDX_VIRTUAL_FLOOR_DROPDOWN: + gConfigGeneral.virtual_floor_style = static_cast(dropdownIndex); + config_save_default(); + break; + } } -} -static void window_options_audio_dropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex) -{ - if (dropdownIndex == -1) - return; - - switch (widgetIndex) + void RenderingPrepareDraw() { - case WIDX_SOUND_DROPDOWN: - OpenRCT2::Audio::InitRideSounds(dropdownIndex); - if (dropdownIndex < OpenRCT2::Audio::GetDeviceCount()) + CommonPrepareDrawBefore(); + + WidgetSetCheckboxValue(this, WIDX_TILE_SMOOTHING_CHECKBOX, gConfigGeneral.landscape_smoothing); + WidgetSetCheckboxValue(this, WIDX_GRIDLINES_CHECKBOX, gConfigGeneral.always_show_gridlines); + WidgetSetCheckboxValue(this, WIDX_DAY_NIGHT_CHECKBOX, gConfigGeneral.day_night_cycle); + WidgetSetCheckboxValue(this, WIDX_SHOW_GUEST_PURCHASES_CHECKBOX, gConfigGeneral.show_guest_purchases); + WidgetSetCheckboxValue(this, WIDX_TRANSPARENT_SCREENSHOTS_CHECKBOX, gConfigGeneral.transparent_screenshot); + WidgetSetCheckboxValue(this, WIDX_UPPER_CASE_BANNERS_CHECKBOX, gConfigGeneral.upper_case_banners); + + rct_string_id VirtualFloorStyleStrings[] = { STR_VIRTUAL_FLOOR_STYLE_DISABLED, STR_VIRTUAL_FLOOR_STYLE_TRANSPARENT, + STR_VIRTUAL_FLOOR_STYLE_GLASSY }; + + this->widgets[WIDX_VIRTUAL_FLOOR].text = VirtualFloorStyleStrings[static_cast( + gConfigGeneral.virtual_floor_style)]; + + WidgetSetCheckboxValue(this, WIDX_ENABLE_LIGHT_FX_CHECKBOX, gConfigGeneral.enable_light_fx); + if (gConfigGeneral.day_night_cycle && gConfigGeneral.drawing_engine == DrawingEngine::SoftwareWithHardwareDisplay) + { + this->disabled_widgets &= ~(1ULL << WIDX_ENABLE_LIGHT_FX_CHECKBOX); + } + else + { + this->disabled_widgets |= (1ULL << WIDX_ENABLE_LIGHT_FX_CHECKBOX); + gConfigGeneral.enable_light_fx = false; + } + + WidgetSetCheckboxValue(this, WIDX_ENABLE_LIGHT_FX_FOR_VEHICLES_CHECKBOX, gConfigGeneral.enable_light_fx_for_vehicles); + if (gConfigGeneral.day_night_cycle && gConfigGeneral.drawing_engine == DrawingEngine::SoftwareWithHardwareDisplay + && gConfigGeneral.enable_light_fx) + { + this->disabled_widgets &= ~(1ULL << WIDX_ENABLE_LIGHT_FX_FOR_VEHICLES_CHECKBOX); + } + else + { + this->disabled_widgets |= (1ULL << WIDX_ENABLE_LIGHT_FX_FOR_VEHICLES_CHECKBOX); + gConfigGeneral.enable_light_fx_for_vehicles = false; + } + + WidgetSetCheckboxValue( + this, WIDX_RENDER_WEATHER_EFFECTS_CHECKBOX, + gConfigGeneral.render_weather_effects || gConfigGeneral.render_weather_gloom); + WidgetSetCheckboxValue(this, WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX, gConfigGeneral.disable_lightning_effect); + if (!gConfigGeneral.render_weather_effects && !gConfigGeneral.render_weather_gloom) + { + WidgetSetCheckboxValue(this, WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX, true); + this->enabled_widgets &= ~(1ULL << WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX); + this->disabled_widgets |= (1ULL << WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX); + } + else + { + this->enabled_widgets |= (1ULL << WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX); + this->disabled_widgets &= ~(1ULL << WIDX_DISABLE_LIGHTNING_EFFECT_CHECKBOX); + } + + CommonPrepareDrawAfter(); + } + + void RenderingDraw(rct_drawpixelinfo* dpi) + { + WindowDrawWidgets(this, dpi); + DrawTabImages(dpi); + } + +#pragma endregion + +#pragma region Culture tab events + void CultureMouseDown(rct_widgetindex widgetIndex) + { + rct_widget* widget = &this->widgets[widgetIndex - 1]; + + switch (widgetIndex) + { + case WIDX_HEIGHT_LABELS_DROPDOWN: + gDropdownItemsFormat[0] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsFormat[1] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsArgs[0] = STR_HEIGHT_IN_UNITS; + gDropdownItemsArgs[1] = STR_REAL_VALUES; + + this->ShowDropdown(widget, 2); + + Dropdown::SetChecked(gConfigGeneral.show_height_as_units ? 0 : 1, true); + break; + case WIDX_CURRENCY_DROPDOWN: { - if (dropdownIndex == 0) + // All the currencies plus the separator + constexpr auto numItems = EnumValue(CurrencyType::Count) + 1; + + // All the currencies except custom currency + size_t numOrdinaryCurrencies = EnumValue(CurrencyType::Count) - 1; + + for (size_t i = 0; i < numOrdinaryCurrencies; i++) { - Mixer_Init(nullptr); - gConfigSound.device = nullptr; + gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsArgs[i] = CurrencyDescriptors[i].stringId; + } + + gDropdownItemsFormat[numOrdinaryCurrencies] = Dropdown::SeparatorString; + + gDropdownItemsFormat[numOrdinaryCurrencies + 1] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsArgs[numOrdinaryCurrencies + 1] = CurrencyDescriptors[EnumValue(CurrencyType::Custom)].stringId; + + this->ShowDropdown(widget, numItems); + + if (gConfigGeneral.currency_format == CurrencyType::Custom) + { + Dropdown::SetChecked(EnumValue(gConfigGeneral.currency_format) + 1, true); } else { - const char* devicename = OpenRCT2::Audio::GetDeviceName(dropdownIndex).c_str(); - Mixer_Init(devicename); - SafeFree(gConfigSound.device); - gConfigSound.device = strndup(devicename, OpenRCT2::Audio::MaxDeviceNameSize); + Dropdown::SetChecked(EnumValue(gConfigGeneral.currency_format), true); + } + break; + } + case WIDX_DISTANCE_DROPDOWN: + gDropdownItemsFormat[0] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsFormat[1] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsFormat[2] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsArgs[0] = STR_IMPERIAL; + gDropdownItemsArgs[1] = STR_METRIC; + gDropdownItemsArgs[2] = STR_SI; + + this->ShowDropdown(widget, 3); + + Dropdown::SetChecked(static_cast(gConfigGeneral.measurement_format), true); + break; + case WIDX_TEMPERATURE_DROPDOWN: + gDropdownItemsFormat[0] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsFormat[1] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsArgs[0] = STR_CELSIUS; + gDropdownItemsArgs[1] = STR_FAHRENHEIT; + + this->ShowDropdown(widget, 2); + + Dropdown::SetChecked(static_cast(gConfigGeneral.temperature_format), true); + break; + case WIDX_LANGUAGE_DROPDOWN: + for (size_t i = 1; i < LANGUAGE_COUNT; i++) + { + gDropdownItemsFormat[i - 1] = STR_OPTIONS_DROPDOWN_ITEM; + gDropdownItemsArgs[i - 1] = reinterpret_cast(LanguagesDescriptors[i].native_name); + } + this->ShowDropdown(widget, LANGUAGE_COUNT - 1); + Dropdown::SetChecked(LocalisationService_GetCurrentLanguage() - 1, true); + break; + case WIDX_DATE_FORMAT_DROPDOWN: + for (size_t i = 0; i < 4; i++) + { + gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsArgs[i] = DateFormatStringIds[i]; + } + this->ShowDropdown(widget, 4); + Dropdown::SetChecked(gConfigGeneral.date_format, true); + break; + } + } + + void CultureDropdown(rct_widgetindex widgetIndex, int32_t dropdownIndex) + { + if (dropdownIndex == -1) + return; + + switch (widgetIndex) + { + case WIDX_HEIGHT_LABELS_DROPDOWN: + // reset flag and set it to 1 if height as units is selected + gConfigGeneral.show_height_as_units = 0; + + if (dropdownIndex == 0) + { + gConfigGeneral.show_height_as_units = 1; } config_save_default(); - OpenRCT2::Audio::PlayTitleMusic(); - } - w->Invalidate(); - break; - case WIDX_TITLE_MUSIC_DROPDOWN: - if ((dropdownIndex == 1 || dropdownIndex == 3) && !Platform::FileExists(context_get_path_legacy(PATH_ID_CSS50))) - { - context_show_error(STR_OPTIONS_MUSIC_ERR_CSS50_NOT_FOUND, STR_OPTIONS_MUSIC_ERR_CSS50_NOT_FOUND_HINT, {}); - } - else - { - gConfigSound.title_music = static_cast(dropdownIndex); - config_save_default(); - w->Invalidate(); - } - - OpenRCT2::Audio::StopTitleMusic(); - if (dropdownIndex != 0) - OpenRCT2::Audio::PlayTitleMusic(); - break; - } -} - -static uint8_t get_scroll_percentage(const rct_widget& widget, const rct_scroll& scroll) -{ - uint8_t width = widget.width() - 1; - return static_cast(scroll.h_left) / (scroll.h_right - width) * 100; -} - -static void window_options_audio_update(rct_window* w) -{ - window_options_common_update(w); - - if (w->page == WINDOW_OPTIONS_PAGE_AUDIO) - { - const auto& masterVolumeWidget = window_options_audio_widgets[WIDX_MASTER_VOLUME]; - const auto& masterVolumeScroll = w->scrolls[0]; - uint8_t master_volume = get_scroll_percentage(masterVolumeWidget, masterVolumeScroll); - if (master_volume != gConfigSound.master_volume) - { - gConfigSound.master_volume = master_volume; - config_save_default(); - widget_invalidate(w, WIDX_MASTER_VOLUME); - } - - const auto& soundVolumeWidget = window_options_audio_widgets[WIDX_MASTER_VOLUME]; - const auto& soundVolumeScroll = w->scrolls[1]; - uint8_t sound_volume = get_scroll_percentage(soundVolumeWidget, soundVolumeScroll); - if (sound_volume != gConfigSound.sound_volume) - { - gConfigSound.sound_volume = sound_volume; - config_save_default(); - widget_invalidate(w, WIDX_SOUND_VOLUME); - } - - const auto& musicVolumeWidget = window_options_audio_widgets[WIDX_MASTER_VOLUME]; - const auto& musicVolumeScroll = w->scrolls[2]; - uint8_t ride_music_volume = get_scroll_percentage(musicVolumeWidget, musicVolumeScroll); - if (ride_music_volume != gConfigSound.ride_music_volume) - { - gConfigSound.ride_music_volume = ride_music_volume; - config_save_default(); - widget_invalidate(w, WIDX_MUSIC_VOLUME); - } - } -} - -static void window_options_audio_scrollgetsize(rct_window* w, int32_t scrollIndex, int32_t* width, int32_t* height) -{ - *width = 500; -} - -static void initialize_scroll_position(rct_window* w, rct_widgetindex widget_index, int32_t scroll_id, uint8_t volume) -{ - const auto& widget = window_options_audio_widgets[widget_index]; - auto& scroll = w->scrolls[scroll_id]; - - int32_t widget_size = scroll.h_right - (widget.width() - 1); - scroll.h_left = ceil(volume / 100.0f * widget_size); - - WidgetScrollUpdateThumbs(w, widget_index); -} - -static void window_options_audio_invalidate(rct_window* w) -{ - window_options_common_invalidate_before(w); - - // Sound device - rct_string_id audioDeviceStringId = STR_OPTIONS_SOUND_VALUE_DEFAULT; - const char* audioDeviceName = nullptr; - const int32_t currentDeviceIndex = OpenRCT2::Audio::GetCurrentDeviceIndex(); - if (currentDeviceIndex == -1) - { - audioDeviceStringId = STR_SOUND_NONE; - } - else - { - audioDeviceStringId = STR_STRING; -#ifndef __linux__ - if (currentDeviceIndex == 0) - { - audioDeviceStringId = STR_OPTIONS_SOUND_VALUE_DEFAULT; - } -#endif // __linux__ - if (audioDeviceStringId == STR_STRING) - { - audioDeviceName = OpenRCT2::Audio::GetDeviceName(currentDeviceIndex).c_str(); - } - } - - window_options_audio_widgets[WIDX_SOUND].text = audioDeviceStringId; - auto ft = Formatter::Common(); - ft.Add(audioDeviceName); - - window_options_audio_widgets[WIDX_TITLE_MUSIC].text = window_options_title_music_names[gConfigSound.title_music]; - - WidgetSetCheckboxValue(w, WIDX_SOUND_CHECKBOX, gConfigSound.sound_enabled); - WidgetSetCheckboxValue(w, WIDX_MASTER_SOUND_CHECKBOX, gConfigSound.master_sound_enabled); - WidgetSetCheckboxValue(w, WIDX_MUSIC_CHECKBOX, gConfigSound.ride_music_enabled); - WidgetSetCheckboxValue(w, WIDX_AUDIO_FOCUS_CHECKBOX, gConfigSound.audio_focus); - WidgetSetEnabled(w, WIDX_SOUND_CHECKBOX, gConfigSound.master_sound_enabled); - WidgetSetEnabled(w, WIDX_MUSIC_CHECKBOX, gConfigSound.master_sound_enabled); - - // Initialize only on first frame, otherwise the scrollbars won't be able to be modified - if (w->frame_no == 0) - { - initialize_scroll_position(w, WIDX_MASTER_VOLUME, 0, gConfigSound.master_volume); - initialize_scroll_position(w, WIDX_SOUND_VOLUME, 1, gConfigSound.sound_volume); - initialize_scroll_position(w, WIDX_MUSIC_VOLUME, 2, gConfigSound.ride_music_volume); - } - - window_options_common_invalidate_after(w); -} - -static void window_options_audio_paint(rct_window* w, rct_drawpixelinfo* dpi) -{ - WindowDrawWidgets(w, dpi); - window_options_draw_tab_images(dpi, w); -} - -#pragma region Controls and Interface Tab - -static void window_options_controls_mouseup(rct_window* w, rct_widgetindex widgetIndex) -{ - if (widgetIndex < WIDX_PAGE_START) - return window_options_common_mouseup(w, widgetIndex); - - switch (widgetIndex) - { - case WIDX_HOTKEY_DROPDOWN: - context_open_window(WC_KEYBOARD_SHORTCUT_LIST); - break; - case WIDX_SCREEN_EDGE_SCROLLING: - gConfigGeneral.edge_scrolling ^= 1; - config_save_default(); - w->Invalidate(); - break; - case WIDX_TRAP_CURSOR: - gConfigGeneral.trap_cursor ^= 1; - config_save_default(); - context_set_cursor_trap(gConfigGeneral.trap_cursor); - w->Invalidate(); - break; - case WIDX_ZOOM_TO_CURSOR: - gConfigGeneral.zoom_to_cursor ^= 1; - config_save_default(); - w->Invalidate(); - break; - case WIDX_TOOLBAR_SHOW_FINANCES: - gConfigInterface.toolbar_show_finances ^= 1; - config_save_default(); - w->Invalidate(); - window_invalidate_by_class(WC_TOP_TOOLBAR); - break; - case WIDX_TOOLBAR_SHOW_RESEARCH: - gConfigInterface.toolbar_show_research ^= 1; - config_save_default(); - w->Invalidate(); - window_invalidate_by_class(WC_TOP_TOOLBAR); - break; - case WIDX_TOOLBAR_SHOW_CHEATS: - gConfigInterface.toolbar_show_cheats ^= 1; - config_save_default(); - w->Invalidate(); - window_invalidate_by_class(WC_TOP_TOOLBAR); - break; - case WIDX_TOOLBAR_SHOW_NEWS: - gConfigInterface.toolbar_show_news ^= 1; - config_save_default(); - w->Invalidate(); - window_invalidate_by_class(WC_TOP_TOOLBAR); - break; - case WIDX_TOOLBAR_SHOW_MUTE: - gConfigInterface.toolbar_show_mute ^= 1; - config_save_default(); - w->Invalidate(); - window_invalidate_by_class(WC_TOP_TOOLBAR); - break; - case WIDX_TOOLBAR_SHOW_CHAT: - gConfigInterface.toolbar_show_chat ^= 1; - config_save_default(); - w->Invalidate(); - window_invalidate_by_class(WC_TOP_TOOLBAR); - break; - case WIDX_TOOLBAR_SHOW_ZOOM: - gConfigInterface.toolbar_show_zoom ^= 1; - config_save_default(); - w->Invalidate(); - window_invalidate_by_class(WC_TOP_TOOLBAR); - break; - case WIDX_INVERT_DRAG: - gConfigGeneral.invert_viewport_drag ^= 1; - config_save_default(); - w->Invalidate(); - break; - case WIDX_THEMES_BUTTON: - context_open_window(WC_THEMES); - w->Invalidate(); - break; - } -} - -static void window_options_controls_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget) -{ - widget = &w->widgets[widgetIndex - 1]; - - switch (widgetIndex) - { - case WIDX_THEMES_DROPDOWN: - uint32_t num_items = static_cast(ThemeManagerGetNumAvailableThemes()); - - for (size_t i = 0; i < num_items; i++) - { - gDropdownItemsFormat[i] = STR_OPTIONS_DROPDOWN_ITEM; - gDropdownItemsArgs[i] = reinterpret_cast(ThemeManagerGetAvailableThemeName(i)); - } - - WindowDropdownShowTextCustomWidth( - { w->windowPos.x + widget->left, w->windowPos.y + widget->top }, widget->height() + 1, w->colours[1], 0, - Dropdown::Flag::StayOpen, num_items, widget->width() - 3); - - Dropdown::SetChecked(static_cast(ThemeManagerGetAvailableThemeIndex()), true); - widget_invalidate(w, WIDX_THEMES_DROPDOWN); - break; - } -} - -static void window_options_controls_dropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex) -{ - if (dropdownIndex == -1) - return; - - switch (widgetIndex) - { - case WIDX_THEMES_DROPDOWN: - if (dropdownIndex != -1) - { - ThemeManagerSetActiveAvailableTheme(dropdownIndex); - } - config_save_default(); - break; - } -} - -static void window_options_controls_invalidate(rct_window* w) -{ - window_options_common_invalidate_before(w); - - WidgetSetCheckboxValue(w, WIDX_SCREEN_EDGE_SCROLLING, gConfigGeneral.edge_scrolling); - WidgetSetCheckboxValue(w, WIDX_TRAP_CURSOR, gConfigGeneral.trap_cursor); - WidgetSetCheckboxValue(w, WIDX_INVERT_DRAG, gConfigGeneral.invert_viewport_drag); - WidgetSetCheckboxValue(w, WIDX_ZOOM_TO_CURSOR, gConfigGeneral.zoom_to_cursor); - WidgetSetCheckboxValue(w, WIDX_TOOLBAR_SHOW_FINANCES, gConfigInterface.toolbar_show_finances); - WidgetSetCheckboxValue(w, WIDX_TOOLBAR_SHOW_RESEARCH, gConfigInterface.toolbar_show_research); - WidgetSetCheckboxValue(w, WIDX_TOOLBAR_SHOW_CHEATS, gConfigInterface.toolbar_show_cheats); - WidgetSetCheckboxValue(w, WIDX_TOOLBAR_SHOW_NEWS, gConfigInterface.toolbar_show_news); - WidgetSetCheckboxValue(w, WIDX_TOOLBAR_SHOW_MUTE, gConfigInterface.toolbar_show_mute); - WidgetSetCheckboxValue(w, WIDX_TOOLBAR_SHOW_CHAT, gConfigInterface.toolbar_show_chat); - WidgetSetCheckboxValue(w, WIDX_TOOLBAR_SHOW_ZOOM, gConfigInterface.toolbar_show_zoom); - - size_t activeAvailableThemeIndex = ThemeManagerGetAvailableThemeIndex(); - const utf8* activeThemeName = ThemeManagerGetAvailableThemeName(activeAvailableThemeIndex); - auto ft = Formatter::Common(); - ft.Add(activeThemeName); - - window_options_common_invalidate_after(w); -} - -static void window_options_controls_paint(rct_window* w, rct_drawpixelinfo* dpi) -{ - WindowDrawWidgets(w, dpi); - window_options_draw_tab_images(dpi, w); - - DrawTextBasic( - dpi, - w->windowPos + ScreenCoordsXY{ 10, window_options_controls_and_interface_widgets[WIDX_TOOLBAR_BUTTONS_GROUP].top + 15 }, - STR_SHOW_TOOLBAR_BUTTONS_FOR, {}, { w->colours[1] }); - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ 10, window_options_controls_and_interface_widgets[WIDX_THEMES].top + 1 }, - STR_THEMES_LABEL_CURRENT_THEME, {}, { w->colours[1] }); -} - -#pragma region Miscellaneous Tab - -static void window_options_misc_mouseup(rct_window* w, rct_widgetindex widgetIndex) -{ - if (widgetIndex < WIDX_PAGE_START) - return window_options_common_mouseup(w, widgetIndex); - - switch (widgetIndex) - { - case WIDX_REAL_NAME_CHECKBOX: - gConfigGeneral.show_real_names_of_guests ^= 1; - config_save_default(); - w->Invalidate(); - peep_update_names(gConfigGeneral.show_real_names_of_guests); - break; - case WIDX_AUTO_STAFF_PLACEMENT: - gConfigGeneral.auto_staff_placement ^= 1; - config_save_default(); - w->Invalidate(); - break; - case WIDX_TITLE_SEQUENCE_BUTTON: - window_title_editor_open(0); - break; - case WIDX_SCENARIO_UNLOCKING: - gConfigGeneral.scenario_unlocking_enabled ^= 1; - config_save_default(); - window_close_by_class(WC_SCENARIO_SELECT); - break; - case WIDX_TITLE_SEQUENCE_RANDOM: - gConfigInterface.random_title_sequence ^= 1; - config_save_default(); - w->Invalidate(); - break; - case WIDX_AUTO_OPEN_SHOPS: - gConfigGeneral.auto_open_shops = !gConfigGeneral.auto_open_shops; - config_save_default(); - w->Invalidate(); - break; - case WIDX_ALLOW_EARLY_COMPLETION: - gConfigGeneral.allow_early_completion ^= 1; - // Only the server can control this setting and needs to send the - // current value of allow_early_completion to all clients - if (network_get_mode() == NETWORK_MODE_SERVER) - { - auto setAllowEarlyCompletionAction = ScenarioSetSettingAction( - ScenarioSetSetting::AllowEarlyCompletion, gConfigGeneral.allow_early_completion); - GameActions::Execute(&setAllowEarlyCompletionAction); - } - config_save_default(); - w->Invalidate(); - break; - } -} - -static void window_options_misc_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget) -{ - uint32_t num_items; - - widget = &w->widgets[widgetIndex - 1]; - - switch (widgetIndex) - { - case WIDX_TITLE_SEQUENCE_DROPDOWN: - num_items = static_cast(title_sequence_manager_get_count()); - for (size_t i = 0; i < num_items; i++) - { - gDropdownItemsFormat[i] = STR_OPTIONS_DROPDOWN_ITEM; - gDropdownItemsArgs[i] = reinterpret_cast(title_sequence_manager_get_name(i)); - } - - WindowDropdownShowText( - { w->windowPos.x + widget->left, w->windowPos.y + widget->top }, widget->height() + 1, w->colours[1], - Dropdown::Flag::StayOpen, num_items); - - Dropdown::SetChecked(static_cast(title_get_current_sequence()), true); - break; - case WIDX_SCENARIO_GROUPING_DROPDOWN: - num_items = 2; - - gDropdownItemsFormat[0] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsArgs[0] = STR_OPTIONS_SCENARIO_DIFFICULTY; - gDropdownItemsFormat[1] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsArgs[1] = STR_OPTIONS_SCENARIO_ORIGIN; - - WindowDropdownShowTextCustomWidth( - { w->windowPos.x + widget->left, w->windowPos.y + widget->top }, widget->height() + 1, w->colours[1], 0, - Dropdown::Flag::StayOpen, num_items, widget->width() - 3); - - Dropdown::SetChecked(gConfigGeneral.scenario_select_mode, true); - break; - case WIDX_DEFAULT_INSPECTION_INTERVAL_DROPDOWN: - for (size_t i = 0; i < 7; i++) - { - gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsArgs[i] = RideInspectionIntervalNames[i]; - } - - window_options_show_dropdown(w, widget, 7); - Dropdown::SetChecked(gConfigGeneral.default_inspection_interval, true); - break; - } -} - -static void window_options_misc_dropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex) -{ - if (dropdownIndex == -1) - return; - - switch (widgetIndex) - { - case WIDX_TITLE_SEQUENCE_DROPDOWN: - if (dropdownIndex != static_cast(title_get_current_sequence())) - { - title_sequence_change_preset(static_cast(dropdownIndex)); - config_save_default(); - w->Invalidate(); - } - break; - case WIDX_DEFAULT_INSPECTION_INTERVAL_DROPDOWN: - if (dropdownIndex != gConfigGeneral.default_inspection_interval) - { - gConfigGeneral.default_inspection_interval = static_cast(dropdownIndex); - config_save_default(); - w->Invalidate(); - } - break; - case WIDX_SCENARIO_GROUPING_DROPDOWN: - if (dropdownIndex != gConfigGeneral.scenario_select_mode) - { - gConfigGeneral.scenario_select_mode = dropdownIndex; - gConfigInterface.scenarioselect_last_tab = 0; - config_save_default(); - w->Invalidate(); - window_close_by_class(WC_SCENARIO_SELECT); - } - break; - } -} - -static void window_options_misc_invalidate(rct_window* w) -{ - window_options_common_invalidate_before(w); - - const utf8* name = title_sequence_manager_get_name(title_get_config_sequence()); - auto ft = Formatter::Common(); - ft.Add(name); - - // The real name setting of clients is fixed to that of the server - // and the server cannot change the setting during gameplay to prevent desyncs - if (network_get_mode() != NETWORK_MODE_NONE) - { - w->disabled_widgets |= (1ULL << WIDX_REAL_NAME_CHECKBOX); - window_options_misc_widgets[WIDX_REAL_NAME_CHECKBOX].tooltip = STR_OPTION_DISABLED_DURING_NETWORK_PLAY; - // Disable the use of the allow_early_completion option during network play on clients. - // This is to prevent confusion on clients because changing this setting during network play wouldn't change - // the way scenarios are completed during this network-session - if (network_get_mode() == NETWORK_MODE_CLIENT) - { - w->disabled_widgets |= (1ULL << WIDX_ALLOW_EARLY_COMPLETION); - window_options_misc_widgets[WIDX_ALLOW_EARLY_COMPLETION].tooltip = STR_OPTION_DISABLED_DURING_NETWORK_PLAY; - } - } - - WidgetSetCheckboxValue(w, WIDX_REAL_NAME_CHECKBOX, gConfigGeneral.show_real_names_of_guests); - WidgetSetCheckboxValue(w, WIDX_AUTO_STAFF_PLACEMENT, gConfigGeneral.auto_staff_placement); - WidgetSetCheckboxValue(w, WIDX_AUTO_OPEN_SHOPS, gConfigGeneral.auto_open_shops); - WidgetSetCheckboxValue(w, WIDX_TITLE_SEQUENCE_RANDOM, gConfigInterface.random_title_sequence); - WidgetSetCheckboxValue(w, WIDX_ALLOW_EARLY_COMPLETION, gConfigGeneral.allow_early_completion); - - // Disable title sequence dropdown if set to random - if (gConfigInterface.random_title_sequence) - { - w->disabled_widgets |= (1ULL << WIDX_TITLE_SEQUENCE_DROPDOWN); - w->disabled_widgets |= (1ULL << WIDX_TITLE_SEQUENCE); - } - else - { - w->disabled_widgets &= ~(1ULL << WIDX_TITLE_SEQUENCE_DROPDOWN); - w->disabled_widgets &= ~(1ULL << WIDX_TITLE_SEQUENCE); - } - - if (gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_DIFFICULTY) - window_options_misc_widgets[WIDX_SCENARIO_GROUPING].text = STR_OPTIONS_SCENARIO_DIFFICULTY; - else - window_options_misc_widgets[WIDX_SCENARIO_GROUPING].text = STR_OPTIONS_SCENARIO_ORIGIN; - - WidgetSetCheckboxValue(w, WIDX_SCENARIO_UNLOCKING, gConfigGeneral.scenario_unlocking_enabled); - - if (gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_ORIGIN) - { - w->disabled_widgets &= ~(1ULL << WIDX_SCENARIO_UNLOCKING); - } - else - { - w->disabled_widgets |= (1ULL << WIDX_SCENARIO_UNLOCKING); - } - - window_options_misc_widgets[WIDX_DEFAULT_INSPECTION_INTERVAL].text = RideInspectionIntervalNames - [gConfigGeneral.default_inspection_interval]; - - window_options_common_invalidate_after(w); -} - -static void window_options_misc_paint(rct_window* w, rct_drawpixelinfo* dpi) -{ - WindowDrawWidgets(w, dpi); - window_options_draw_tab_images(dpi, w); - - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ 10, window_options_misc_widgets[WIDX_TITLE_SEQUENCE].top + 1 }, STR_TITLE_SEQUENCE, - {}, { w->colours[1] }); - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ 10, window_options_misc_widgets[WIDX_SCENARIO_GROUPING].top + 1 }, - STR_OPTIONS_SCENARIO_GROUPING, {}, { w->colours[1] }); - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ 10, window_options_misc_widgets[WIDX_DEFAULT_INSPECTION_INTERVAL].top + 1 }, - STR_DEFAULT_INSPECTION_INTERVAL, {}, { w->colours[1] }); -} - -#pragma region Advanced Tab - -static void window_options_advanced_mouseup(rct_window* w, rct_widgetindex widgetIndex) -{ - if (widgetIndex < WIDX_PAGE_START) - return window_options_common_mouseup(w, widgetIndex); - - switch (widgetIndex) - { - case WIDX_DEBUGGING_TOOLS: - gConfigGeneral.debugging_tools ^= 1; - config_save_default(); - gfx_invalidate_screen(); - break; - case WIDX_ALLOW_LOADING_WITH_INCORRECT_CHECKSUM: - gConfigGeneral.allow_loading_with_incorrect_checksum = !gConfigGeneral.allow_loading_with_incorrect_checksum; - config_save_default(); - w->Invalidate(); - break; - case WIDX_SAVE_PLUGIN_DATA_CHECKBOX: - gConfigGeneral.save_plugin_data ^= 1; - config_save_default(); - w->Invalidate(); - break; - case WIDX_STAY_CONNECTED_AFTER_DESYNC: - gConfigNetwork.stay_connected = !gConfigNetwork.stay_connected; - config_save_default(); - w->Invalidate(); - break; - case WIDX_ALWAYS_NATIVE_LOADSAVE: - gConfigGeneral.use_native_browse_dialog = !gConfigGeneral.use_native_browse_dialog; - config_save_default(); - w->Invalidate(); - break; - case WIDX_PATH_TO_RCT1_BUTTON: - { - utf8string rct1path = platform_open_directory_browser(language_get_string(STR_PATH_TO_RCT1_BROWSER)); - if (rct1path != nullptr) - { - // Check if this directory actually contains RCT1 - if (Csg1datPresentAtLocation(rct1path)) + this->UpdateHeightMarkers(); + break; + case WIDX_CURRENCY_DROPDOWN: + if (dropdownIndex == EnumValue(CurrencyType::Custom) + 1) + { // Add 1 because the separator occupies a position + gConfigGeneral.currency_format = static_cast(dropdownIndex - 1); + context_open_window(WC_CUSTOM_CURRENCY_CONFIG); + } + else { - if (Csg1idatPresentAtLocation(rct1path)) + gConfigGeneral.currency_format = static_cast(dropdownIndex); + } + config_save_default(); + gfx_invalidate_screen(); + break; + case WIDX_DISTANCE_DROPDOWN: + gConfigGeneral.measurement_format = static_cast(dropdownIndex); + config_save_default(); + this->UpdateHeightMarkers(); + break; + case WIDX_TEMPERATURE_DROPDOWN: + if (dropdownIndex != static_cast(gConfigGeneral.temperature_format)) + { + gConfigGeneral.temperature_format = static_cast(dropdownIndex); + config_save_default(); + gfx_invalidate_screen(); + } + break; + case WIDX_LANGUAGE_DROPDOWN: + { + auto fallbackLanguage = LocalisationService_GetCurrentLanguage(); + if (dropdownIndex != LocalisationService_GetCurrentLanguage() - 1) + { + if (!language_open(dropdownIndex + 1)) { - if (CsgAtLocationIsUsable(rct1path)) + // Failed to open language file, try to recover by falling + // back to previously used language + if (language_open(fallbackLanguage)) { - SafeFree(gConfigGeneral.rct1_path); - gConfigGeneral.rct1_path = rct1path; - gConfigInterface.scenarioselect_last_tab = 0; - config_save_default(); - context_show_error(STR_RESTART_REQUIRED, STR_NONE, {}); + // It worked, so we can say it with error message in-game + context_show_error(STR_LANGUAGE_LOAD_FAILED, STR_NONE, {}); + } + // report error to console regardless + log_error("Failed to open language file."); + } + else + { + gConfigGeneral.language = dropdownIndex + 1; + config_save_default(); + gfx_invalidate_screen(); + } + } + } + break; + case WIDX_DATE_FORMAT_DROPDOWN: + if (dropdownIndex != gConfigGeneral.date_format) + { + gConfigGeneral.date_format = static_cast(dropdownIndex); + config_save_default(); + gfx_invalidate_screen(); + } + break; + } + } + + void CulturePrepareDraw() + { + this->CommonPrepareDrawBefore(); + + // Language + auto ft = Formatter::Common(); + ft.Add(LanguagesDescriptors[LocalisationService_GetCurrentLanguage()].native_name); + + // Currency: pounds, dollars, etc. (10 total) + this->widgets[WIDX_CURRENCY].text = CurrencyDescriptors[EnumValue(gConfigGeneral.currency_format)].stringId; + + // Distance: metric / imperial / si + { + rct_string_id stringId = STR_NONE; + switch (gConfigGeneral.measurement_format) + { + case MeasurementFormat::Imperial: + stringId = STR_IMPERIAL; + break; + case MeasurementFormat::Metric: + stringId = STR_METRIC; + break; + case MeasurementFormat::SI: + stringId = STR_SI; + break; + } + this->widgets[WIDX_DISTANCE].text = stringId; + } + + // Date format + this->widgets[WIDX_DATE_FORMAT].text = DateFormatStringIds[gConfigGeneral.date_format]; + + // Temperature: celsius/fahrenheit + this->widgets[WIDX_TEMPERATURE].text = gConfigGeneral.temperature_format == TemperatureUnit::Fahrenheit ? STR_FAHRENHEIT + : STR_CELSIUS; + + // Height: units/real values + this->widgets[WIDX_HEIGHT_LABELS].text = gConfigGeneral.show_height_as_units ? STR_HEIGHT_IN_UNITS : STR_REAL_VALUES; + + this->CommonPrepareDrawAfter(); + } + + void CultureDraw(rct_drawpixelinfo* dpi) + { + WindowDrawWidgets(this, dpi); + this->DrawTabImages(dpi); + + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ 10, this->widgets[WIDX_LANGUAGE].top + 1 }, STR_OPTIONS_LANGUAGE, {}, + { this->colours[1] }); + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ 10, this->widgets[WIDX_CURRENCY].top + 1 }, STR_CURRENCY, {}, + { this->colours[1] }); + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ 10, this->widgets[WIDX_DISTANCE].top + 1 }, STR_DISTANCE_AND_SPEED, {}, + { this->colours[1] }); + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ 10, this->widgets[WIDX_TEMPERATURE].top + 1 }, STR_TEMPERATURE, {}, + { this->colours[1] }); + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ 10, this->widgets[WIDX_HEIGHT_LABELS].top + 1 }, STR_HEIGHT_LABELS, {}, + { this->colours[1] }); + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ 10, this->widgets[WIDX_DATE_FORMAT].top + 1 }, STR_DATE_FORMAT, {}, + { this->colours[1] }); + } + +#pragma endregion + +#pragma region Audio tab events + void AudioMouseUp(rct_widgetindex widgetIndex) + { + switch (widgetIndex) + { + case WIDX_SOUND_CHECKBOX: + gConfigSound.sound_enabled = !gConfigSound.sound_enabled; + config_save_default(); + this->Invalidate(); + break; + + case WIDX_MASTER_SOUND_CHECKBOX: + gConfigSound.master_sound_enabled = !gConfigSound.master_sound_enabled; + if (!gConfigSound.master_sound_enabled) + OpenRCT2::Audio::Pause(); + else + OpenRCT2::Audio::Resume(); + window_invalidate_by_class(WC_TOP_TOOLBAR); + config_save_default(); + this->Invalidate(); + break; + + case WIDX_MUSIC_CHECKBOX: + gConfigSound.ride_music_enabled = !gConfigSound.ride_music_enabled; + if (!gConfigSound.ride_music_enabled) + { + OpenRCT2::RideAudio::StopAllChannels(); + } + config_save_default(); + this->Invalidate(); + break; + + case WIDX_AUDIO_FOCUS_CHECKBOX: + gConfigSound.audio_focus = !gConfigSound.audio_focus; + config_save_default(); + this->Invalidate(); + break; + } + } + + void AudioMouseDown(rct_widgetindex widgetIndex) + { + rct_widget* widget = &this->widgets[widgetIndex - 1]; + + switch (widgetIndex) + { + case WIDX_SOUND_DROPDOWN: + OpenRCT2::Audio::PopulateDevices(); + + // populate the list with the sound devices + for (int32_t i = 0; i < OpenRCT2::Audio::GetDeviceCount(); i++) + { + gDropdownItemsFormat[i] = STR_OPTIONS_DROPDOWN_ITEM; + gDropdownItemsArgs[i] = reinterpret_cast(OpenRCT2::Audio::GetDeviceName(i).c_str()); + } + + this->ShowDropdown(widget, OpenRCT2::Audio::GetDeviceCount()); + + Dropdown::SetChecked(OpenRCT2::Audio::GetCurrentDeviceIndex(), true); + break; + case WIDX_TITLE_MUSIC_DROPDOWN: + uint32_t numItems = 4; + + for (size_t i = 0; i < numItems; i++) + { + gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsArgs[i] = window_options_title_music_names[i]; + } + + this->ShowDropdown(widget, numItems); + + Dropdown::SetChecked(gConfigSound.title_music, true); + break; + } + } + + void AudioDropdown(rct_widgetindex widgetIndex, int32_t dropdownIndex) + { + if (dropdownIndex == -1) + return; + + switch (widgetIndex) + { + case WIDX_SOUND_DROPDOWN: + OpenRCT2::Audio::InitRideSounds(dropdownIndex); + if (dropdownIndex < OpenRCT2::Audio::GetDeviceCount()) + { + if (dropdownIndex == 0) + { + Mixer_Init(nullptr); + gConfigSound.device = nullptr; + } + else + { + const char* devicename = OpenRCT2::Audio::GetDeviceName(dropdownIndex).c_str(); + Mixer_Init(devicename); + SafeFree(gConfigSound.device); + gConfigSound.device = strndup(devicename, OpenRCT2::Audio::MaxDeviceNameSize); + } + config_save_default(); + OpenRCT2::Audio::PlayTitleMusic(); + } + this->Invalidate(); + break; + case WIDX_TITLE_MUSIC_DROPDOWN: + if ((dropdownIndex == 1 || dropdownIndex == 3) && !Platform::FileExists(context_get_path_legacy(PATH_ID_CSS50))) + { + context_show_error(STR_OPTIONS_MUSIC_ERR_CSS50_NOT_FOUND, STR_OPTIONS_MUSIC_ERR_CSS50_NOT_FOUND_HINT, {}); + } + else + { + gConfigSound.title_music = static_cast(dropdownIndex); + config_save_default(); + this->Invalidate(); + } + + OpenRCT2::Audio::StopTitleMusic(); + if (dropdownIndex != 0) + OpenRCT2::Audio::PlayTitleMusic(); + break; + } + } + + void AudioUpdate() + { + const auto& masterVolumeWidget = this->widgets[WIDX_MASTER_VOLUME]; + const auto& masterVolumeScroll = this->scrolls[0]; + uint8_t masterVolume = this->GetScrollPercentage(masterVolumeWidget, masterVolumeScroll); + if (masterVolume != gConfigSound.master_volume) + { + gConfigSound.master_volume = masterVolume; + config_save_default(); + widget_invalidate(this, WIDX_MASTER_VOLUME); + } + + const auto& soundVolumeWidget = this->widgets[WIDX_MASTER_VOLUME]; + const auto& soundVolumeScroll = this->scrolls[1]; + uint8_t soundVolume = this->GetScrollPercentage(soundVolumeWidget, soundVolumeScroll); + if (soundVolume != gConfigSound.sound_volume) + { + gConfigSound.sound_volume = soundVolume; + config_save_default(); + widget_invalidate(this, WIDX_SOUND_VOLUME); + } + + const auto& musicVolumeWidget = this->widgets[WIDX_MASTER_VOLUME]; + const auto& musicVolumeScroll = this->scrolls[2]; + uint8_t rideMusicVolume = this->GetScrollPercentage(musicVolumeWidget, musicVolumeScroll); + if (rideMusicVolume != gConfigSound.ride_music_volume) + { + gConfigSound.ride_music_volume = rideMusicVolume; + config_save_default(); + widget_invalidate(this, WIDX_MUSIC_VOLUME); + } + } + + ScreenSize AudioScrollGetSize(int32_t scrollIndex) + { + return { 500, 0 }; + } + + void AudioPrepareDraw() + { + this->CommonPrepareDrawBefore(); + + // Sound device + rct_string_id audioDeviceStringId = STR_OPTIONS_SOUND_VALUE_DEFAULT; + const char* audioDeviceName = nullptr; + const int32_t currentDeviceIndex = OpenRCT2::Audio::GetCurrentDeviceIndex(); + if (currentDeviceIndex == -1) + { + audioDeviceStringId = STR_SOUND_NONE; + } + else + { + audioDeviceStringId = STR_STRING; +#ifndef __linux__ + if (currentDeviceIndex == 0) + { + audioDeviceStringId = STR_OPTIONS_SOUND_VALUE_DEFAULT; + } +#endif // __linux__ + if (audioDeviceStringId == STR_STRING) + { + audioDeviceName = OpenRCT2::Audio::GetDeviceName(currentDeviceIndex).c_str(); + } + } + + this->widgets[WIDX_SOUND].text = audioDeviceStringId; + auto ft = Formatter::Common(); + ft.Add(audioDeviceName); + + this->widgets[WIDX_TITLE_MUSIC].text = window_options_title_music_names[gConfigSound.title_music]; + + WidgetSetCheckboxValue(this, WIDX_SOUND_CHECKBOX, gConfigSound.sound_enabled); + WidgetSetCheckboxValue(this, WIDX_MASTER_SOUND_CHECKBOX, gConfigSound.master_sound_enabled); + WidgetSetCheckboxValue(this, WIDX_MUSIC_CHECKBOX, gConfigSound.ride_music_enabled); + WidgetSetCheckboxValue(this, WIDX_AUDIO_FOCUS_CHECKBOX, gConfigSound.audio_focus); + WidgetSetEnabled(this, WIDX_SOUND_CHECKBOX, gConfigSound.master_sound_enabled); + WidgetSetEnabled(this, WIDX_MUSIC_CHECKBOX, gConfigSound.master_sound_enabled); + + // Initialize only on first frame, otherwise the scrollbars won't be able to be modified + if (this->frame_no == 0) + { + this->InitializeScrollPosition(WIDX_MASTER_VOLUME, 0, gConfigSound.master_volume); + this->InitializeScrollPosition(WIDX_SOUND_VOLUME, 1, gConfigSound.sound_volume); + this->InitializeScrollPosition(WIDX_MUSIC_VOLUME, 2, gConfigSound.ride_music_volume); + } + + this->CommonPrepareDrawAfter(); + } + + void AudioDraw(rct_drawpixelinfo* dpi) + { + WindowDrawWidgets(this, dpi); + this->DrawTabImages(dpi); + } + +#pragma endregion + +#pragma region Controls tab events + void ControlsMouseUp(rct_widgetindex widgetIndex) + { + switch (widgetIndex) + { + case WIDX_HOTKEY_DROPDOWN: + context_open_window(WC_KEYBOARD_SHORTCUT_LIST); + break; + case WIDX_SCREEN_EDGE_SCROLLING: + gConfigGeneral.edge_scrolling ^= 1; + config_save_default(); + this->Invalidate(); + break; + case WIDX_TRAP_CURSOR: + gConfigGeneral.trap_cursor ^= 1; + config_save_default(); + context_set_cursor_trap(gConfigGeneral.trap_cursor); + this->Invalidate(); + break; + case WIDX_ZOOM_TO_CURSOR: + gConfigGeneral.zoom_to_cursor ^= 1; + config_save_default(); + this->Invalidate(); + break; + case WIDX_TOOLBAR_SHOW_FINANCES: + gConfigInterface.toolbar_show_finances ^= 1; + config_save_default(); + this->Invalidate(); + window_invalidate_by_class(WC_TOP_TOOLBAR); + break; + case WIDX_TOOLBAR_SHOW_RESEARCH: + gConfigInterface.toolbar_show_research ^= 1; + config_save_default(); + this->Invalidate(); + window_invalidate_by_class(WC_TOP_TOOLBAR); + break; + case WIDX_TOOLBAR_SHOW_CHEATS: + gConfigInterface.toolbar_show_cheats ^= 1; + config_save_default(); + this->Invalidate(); + window_invalidate_by_class(WC_TOP_TOOLBAR); + break; + case WIDX_TOOLBAR_SHOW_NEWS: + gConfigInterface.toolbar_show_news ^= 1; + config_save_default(); + this->Invalidate(); + window_invalidate_by_class(WC_TOP_TOOLBAR); + break; + case WIDX_TOOLBAR_SHOW_MUTE: + gConfigInterface.toolbar_show_mute ^= 1; + config_save_default(); + this->Invalidate(); + window_invalidate_by_class(WC_TOP_TOOLBAR); + break; + case WIDX_TOOLBAR_SHOW_CHAT: + gConfigInterface.toolbar_show_chat ^= 1; + config_save_default(); + this->Invalidate(); + window_invalidate_by_class(WC_TOP_TOOLBAR); + break; + case WIDX_TOOLBAR_SHOW_ZOOM: + gConfigInterface.toolbar_show_zoom ^= 1; + config_save_default(); + this->Invalidate(); + window_invalidate_by_class(WC_TOP_TOOLBAR); + break; + case WIDX_INVERT_DRAG: + gConfigGeneral.invert_viewport_drag ^= 1; + config_save_default(); + this->Invalidate(); + break; + case WIDX_THEMES_BUTTON: + context_open_window(WC_THEMES); + this->Invalidate(); + break; + } + } + + void ControlsMouseDown(rct_widgetindex widgetIndex) + { + rct_widget* widget = &this->widgets[widgetIndex - 1]; + + switch (widgetIndex) + { + case WIDX_THEMES_DROPDOWN: + uint32_t numItems = static_cast(ThemeManagerGetNumAvailableThemes()); + + for (size_t i = 0; i < numItems; i++) + { + gDropdownItemsFormat[i] = STR_OPTIONS_DROPDOWN_ITEM; + gDropdownItemsArgs[i] = reinterpret_cast(ThemeManagerGetAvailableThemeName(i)); + } + + WindowDropdownShowTextCustomWidth( + { this->windowPos.x + widget->left, this->windowPos.y + widget->top }, widget->height() + 1, + this->colours[1], 0, Dropdown::Flag::StayOpen, numItems, widget->width() - 3); + + Dropdown::SetChecked(static_cast(ThemeManagerGetAvailableThemeIndex()), true); + widget_invalidate(this, WIDX_THEMES_DROPDOWN); + break; + } + } + + void ControlsDropdown(rct_widgetindex widgetIndex, int32_t dropdownIndex) + { + if (dropdownIndex == -1) + return; + + switch (widgetIndex) + { + case WIDX_THEMES_DROPDOWN: + if (dropdownIndex != -1) + { + ThemeManagerSetActiveAvailableTheme(dropdownIndex); + } + config_save_default(); + break; + } + } + + void ControlsPrepareDraw() + { + this->CommonPrepareDrawBefore(); + + WidgetSetCheckboxValue(this, WIDX_SCREEN_EDGE_SCROLLING, gConfigGeneral.edge_scrolling); + WidgetSetCheckboxValue(this, WIDX_TRAP_CURSOR, gConfigGeneral.trap_cursor); + WidgetSetCheckboxValue(this, WIDX_INVERT_DRAG, gConfigGeneral.invert_viewport_drag); + WidgetSetCheckboxValue(this, WIDX_ZOOM_TO_CURSOR, gConfigGeneral.zoom_to_cursor); + WidgetSetCheckboxValue(this, WIDX_TOOLBAR_SHOW_FINANCES, gConfigInterface.toolbar_show_finances); + WidgetSetCheckboxValue(this, WIDX_TOOLBAR_SHOW_RESEARCH, gConfigInterface.toolbar_show_research); + WidgetSetCheckboxValue(this, WIDX_TOOLBAR_SHOW_CHEATS, gConfigInterface.toolbar_show_cheats); + WidgetSetCheckboxValue(this, WIDX_TOOLBAR_SHOW_NEWS, gConfigInterface.toolbar_show_news); + WidgetSetCheckboxValue(this, WIDX_TOOLBAR_SHOW_MUTE, gConfigInterface.toolbar_show_mute); + WidgetSetCheckboxValue(this, WIDX_TOOLBAR_SHOW_CHAT, gConfigInterface.toolbar_show_chat); + WidgetSetCheckboxValue(this, WIDX_TOOLBAR_SHOW_ZOOM, gConfigInterface.toolbar_show_zoom); + + size_t activeAvailableThemeIndex = ThemeManagerGetAvailableThemeIndex(); + const utf8* activeThemeName = ThemeManagerGetAvailableThemeName(activeAvailableThemeIndex); + auto ft = Formatter::Common(); + ft.Add(activeThemeName); + + this->CommonPrepareDrawAfter(); + } + + void ControlsDraw(rct_drawpixelinfo* dpi) + { + WindowDrawWidgets(this, dpi); + this->DrawTabImages(dpi); + + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ 10, this->widgets[WIDX_TOOLBAR_BUTTONS_GROUP].top + 15 }, + STR_SHOW_TOOLBAR_BUTTONS_FOR, {}, { this->colours[1] }); + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ 10, this->widgets[WIDX_THEMES].top + 1 }, STR_THEMES_LABEL_CURRENT_THEME, {}, + { this->colours[1] }); + } + +#pragma endregion + +#pragma region Misc tab events + void MiscMouseUp(rct_widgetindex widgetIndex) + { + switch (widgetIndex) + { + case WIDX_REAL_NAME_CHECKBOX: + gConfigGeneral.show_real_names_of_guests ^= 1; + config_save_default(); + this->Invalidate(); + peep_update_names(gConfigGeneral.show_real_names_of_guests); + break; + case WIDX_AUTO_STAFF_PLACEMENT: + gConfigGeneral.auto_staff_placement ^= 1; + config_save_default(); + this->Invalidate(); + break; + case WIDX_TITLE_SEQUENCE_BUTTON: + window_title_editor_open(0); + break; + case WIDX_SCENARIO_UNLOCKING: + gConfigGeneral.scenario_unlocking_enabled ^= 1; + config_save_default(); + window_close_by_class(WC_SCENARIO_SELECT); + break; + case WIDX_TITLE_SEQUENCE_RANDOM: + gConfigInterface.random_title_sequence ^= 1; + config_save_default(); + this->Invalidate(); + break; + case WIDX_AUTO_OPEN_SHOPS: + gConfigGeneral.auto_open_shops = !gConfigGeneral.auto_open_shops; + config_save_default(); + this->Invalidate(); + break; + case WIDX_ALLOW_EARLY_COMPLETION: + gConfigGeneral.allow_early_completion ^= 1; + // Only the server can control this setting and needs to send the + // current value of allow_early_completion to all clients + if (network_get_mode() == NETWORK_MODE_SERVER) + { + auto setAllowEarlyCompletionAction = ScenarioSetSettingAction( + ScenarioSetSetting::AllowEarlyCompletion, gConfigGeneral.allow_early_completion); + GameActions::Execute(&setAllowEarlyCompletionAction); + } + config_save_default(); + this->Invalidate(); + break; + } + } + + void MiscMouseDown(rct_widgetindex widgetIndex) + { + rct_widget* widget = &this->widgets[widgetIndex - 1]; + + switch (widgetIndex) + { + case WIDX_TITLE_SEQUENCE_DROPDOWN: + { + uint32_t numItems = static_cast(title_sequence_manager_get_count()); + for (size_t i = 0; i < numItems; i++) + { + gDropdownItemsFormat[i] = STR_OPTIONS_DROPDOWN_ITEM; + gDropdownItemsArgs[i] = reinterpret_cast(title_sequence_manager_get_name(i)); + } + + WindowDropdownShowText( + { this->windowPos.x + widget->left, this->windowPos.y + widget->top }, widget->height() + 1, + this->colours[1], Dropdown::Flag::StayOpen, numItems); + + Dropdown::SetChecked(static_cast(title_get_current_sequence()), true); + break; + } + case WIDX_SCENARIO_GROUPING_DROPDOWN: + { + uint32_t numItems = 2; + + gDropdownItemsFormat[0] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsArgs[0] = STR_OPTIONS_SCENARIO_DIFFICULTY; + gDropdownItemsFormat[1] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsArgs[1] = STR_OPTIONS_SCENARIO_ORIGIN; + + WindowDropdownShowTextCustomWidth( + { this->windowPos.x + widget->left, this->windowPos.y + widget->top }, widget->height() + 1, + this->colours[1], 0, Dropdown::Flag::StayOpen, numItems, widget->width() - 3); + + Dropdown::SetChecked(gConfigGeneral.scenario_select_mode, true); + break; + } + case WIDX_DEFAULT_INSPECTION_INTERVAL_DROPDOWN: + for (size_t i = 0; i < 7; i++) + { + gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsArgs[i] = RideInspectionIntervalNames[i]; + } + + this->ShowDropdown(widget, 7); + Dropdown::SetChecked(gConfigGeneral.default_inspection_interval, true); + break; + } + } + + void MiscDropdown(rct_widgetindex widgetIndex, int32_t dropdownIndex) + { + if (dropdownIndex == -1) + return; + + switch (widgetIndex) + { + case WIDX_TITLE_SEQUENCE_DROPDOWN: + if (dropdownIndex != static_cast(title_get_current_sequence())) + { + title_sequence_change_preset(static_cast(dropdownIndex)); + config_save_default(); + this->Invalidate(); + } + break; + case WIDX_DEFAULT_INSPECTION_INTERVAL_DROPDOWN: + if (dropdownIndex != gConfigGeneral.default_inspection_interval) + { + gConfigGeneral.default_inspection_interval = static_cast(dropdownIndex); + config_save_default(); + this->Invalidate(); + } + break; + case WIDX_SCENARIO_GROUPING_DROPDOWN: + if (dropdownIndex != gConfigGeneral.scenario_select_mode) + { + gConfigGeneral.scenario_select_mode = dropdownIndex; + gConfigInterface.scenarioselect_last_tab = 0; + config_save_default(); + this->Invalidate(); + window_close_by_class(WC_SCENARIO_SELECT); + } + break; + } + } + + void MiscPrepareDraw() + { + this->CommonPrepareDrawBefore(); + + const utf8* name = title_sequence_manager_get_name(title_get_config_sequence()); + auto ft = Formatter::Common(); + ft.Add(name); + + // The real name setting of clients is fixed to that of the server + // and the server cannot change the setting during gameplay to prevent desyncs + if (network_get_mode() != NETWORK_MODE_NONE) + { + this->disabled_widgets |= (1ULL << WIDX_REAL_NAME_CHECKBOX); + this->widgets[WIDX_REAL_NAME_CHECKBOX].tooltip = STR_OPTION_DISABLED_DURING_NETWORK_PLAY; + // Disable the use of the allow_early_completion option during network play on clients. + // This is to prevent confusion on clients because changing this setting during network play wouldn't change + // the way scenarios are completed during this network-session + if (network_get_mode() == NETWORK_MODE_CLIENT) + { + this->disabled_widgets |= (1ULL << WIDX_ALLOW_EARLY_COMPLETION); + this->widgets[WIDX_ALLOW_EARLY_COMPLETION].tooltip = STR_OPTION_DISABLED_DURING_NETWORK_PLAY; + } + } + + WidgetSetCheckboxValue(this, WIDX_REAL_NAME_CHECKBOX, gConfigGeneral.show_real_names_of_guests); + WidgetSetCheckboxValue(this, WIDX_AUTO_STAFF_PLACEMENT, gConfigGeneral.auto_staff_placement); + WidgetSetCheckboxValue(this, WIDX_AUTO_OPEN_SHOPS, gConfigGeneral.auto_open_shops); + WidgetSetCheckboxValue(this, WIDX_TITLE_SEQUENCE_RANDOM, gConfigInterface.random_title_sequence); + WidgetSetCheckboxValue(this, WIDX_ALLOW_EARLY_COMPLETION, gConfigGeneral.allow_early_completion); + + // Disable title sequence dropdown if set to random + if (gConfigInterface.random_title_sequence) + { + this->disabled_widgets |= (1ULL << WIDX_TITLE_SEQUENCE_DROPDOWN); + this->disabled_widgets |= (1ULL << WIDX_TITLE_SEQUENCE); + } + else + { + this->disabled_widgets &= ~(1ULL << WIDX_TITLE_SEQUENCE_DROPDOWN); + this->disabled_widgets &= ~(1ULL << WIDX_TITLE_SEQUENCE); + } + + if (gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_DIFFICULTY) + this->widgets[WIDX_SCENARIO_GROUPING].text = STR_OPTIONS_SCENARIO_DIFFICULTY; + else + this->widgets[WIDX_SCENARIO_GROUPING].text = STR_OPTIONS_SCENARIO_ORIGIN; + + WidgetSetCheckboxValue(this, WIDX_SCENARIO_UNLOCKING, gConfigGeneral.scenario_unlocking_enabled); + + if (gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_ORIGIN) + { + this->disabled_widgets &= ~(1ULL << WIDX_SCENARIO_UNLOCKING); + } + else + { + this->disabled_widgets |= (1ULL << WIDX_SCENARIO_UNLOCKING); + } + + this->widgets[WIDX_DEFAULT_INSPECTION_INTERVAL].text = RideInspectionIntervalNames[gConfigGeneral + .default_inspection_interval]; + + this->CommonPrepareDrawAfter(); + } + + void MiscDraw(rct_drawpixelinfo* dpi) + { + WindowDrawWidgets(this, dpi); + this->DrawTabImages(dpi); + + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ 10, this->widgets[WIDX_TITLE_SEQUENCE].top + 1 }, STR_TITLE_SEQUENCE, {}, + { this->colours[1] }); + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ 10, this->widgets[WIDX_SCENARIO_GROUPING].top + 1 }, + STR_OPTIONS_SCENARIO_GROUPING, {}, { this->colours[1] }); + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ 10, this->widgets[WIDX_DEFAULT_INSPECTION_INTERVAL].top + 1 }, + STR_DEFAULT_INSPECTION_INTERVAL, {}, { this->colours[1] }); + } + +#pragma endregion + +#pragma region Advanced tab events + void AdvancedMouseUp(rct_widgetindex widgetIndex) + { + switch (widgetIndex) + { + case WIDX_DEBUGGING_TOOLS: + gConfigGeneral.debugging_tools ^= 1; + config_save_default(); + gfx_invalidate_screen(); + break; + case WIDX_ALLOW_LOADING_WITH_INCORRECT_CHECKSUM: + gConfigGeneral.allow_loading_with_incorrect_checksum = !gConfigGeneral.allow_loading_with_incorrect_checksum; + config_save_default(); + this->Invalidate(); + break; + case WIDX_SAVE_PLUGIN_DATA_CHECKBOX: + gConfigGeneral.save_plugin_data ^= 1; + config_save_default(); + this->Invalidate(); + break; + case WIDX_STAY_CONNECTED_AFTER_DESYNC: + gConfigNetwork.stay_connected = !gConfigNetwork.stay_connected; + config_save_default(); + this->Invalidate(); + break; + case WIDX_ALWAYS_NATIVE_LOADSAVE: + gConfigGeneral.use_native_browse_dialog = !gConfigGeneral.use_native_browse_dialog; + config_save_default(); + this->Invalidate(); + break; + case WIDX_PATH_TO_RCT1_BUTTON: + { + utf8string rct1path = platform_open_directory_browser(language_get_string(STR_PATH_TO_RCT1_BROWSER)); + if (rct1path != nullptr) + { + // Check if this directory actually contains RCT1 + if (Csg1datPresentAtLocation(rct1path)) + { + if (Csg1idatPresentAtLocation(rct1path)) + { + if (CsgAtLocationIsUsable(rct1path)) + { + SafeFree(gConfigGeneral.rct1_path); + gConfigGeneral.rct1_path = rct1path; + gConfigInterface.scenarioselect_last_tab = 0; + config_save_default(); + context_show_error(STR_RESTART_REQUIRED, STR_NONE, {}); + } + else + { + SafeFree(rct1path); + context_show_error(STR_PATH_TO_RCT1_IS_WRONG_VERSION, STR_NONE, {}); + } } else { SafeFree(rct1path); - context_show_error(STR_PATH_TO_RCT1_IS_WRONG_VERSION, STR_NONE, {}); + context_show_error(STR_PATH_TO_RCT1_DOES_NOT_CONTAIN_CSG1I_DAT, STR_NONE, {}); } } else { SafeFree(rct1path); - context_show_error(STR_PATH_TO_RCT1_DOES_NOT_CONTAIN_CSG1I_DAT, STR_NONE, {}); + context_show_error(STR_PATH_TO_RCT1_WRONG_ERROR, STR_NONE, {}); } } - else + this->Invalidate(); + break; + } + case WIDX_PATH_TO_RCT1_CLEAR: + if (!str_is_null_or_empty(gConfigGeneral.rct1_path)) { - SafeFree(rct1path); - context_show_error(STR_PATH_TO_RCT1_WRONG_ERROR, STR_NONE, {}); + SafeFree(gConfigGeneral.rct1_path); + config_save_default(); } - } - w->Invalidate(); - break; + this->Invalidate(); + break; } - case WIDX_PATH_TO_RCT1_CLEAR: - if (!str_is_null_or_empty(gConfigGeneral.rct1_path)) - { - SafeFree(gConfigGeneral.rct1_path); - config_save_default(); - } - w->Invalidate(); - break; } -} -static void window_options_advanced_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget) -{ - widget = &w->widgets[widgetIndex - 1]; - - switch (widgetIndex) + void AdvancedMouseDown(rct_widgetindex widgetIndex) { - case WIDX_AUTOSAVE_DROPDOWN: - for (size_t i = AUTOSAVE_EVERY_MINUTE; i <= AUTOSAVE_NEVER; i++) - { - gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsArgs[i] = window_options_autosave_names[i]; - } + rct_widget* widget = &this->widgets[widgetIndex - 1]; - window_options_show_dropdown(w, widget, AUTOSAVE_NEVER + 1); - Dropdown::SetChecked(gConfigGeneral.autosave_frequency, true); - break; - case WIDX_AUTOSAVE_AMOUNT_UP: - gConfigGeneral.autosave_amount += 1; - config_save_default(); - widget_invalidate(w, WIDX_AUTOSAVE); - widget_invalidate(w, WIDX_AUTOSAVE_DROPDOWN); - widget_invalidate(w, WIDX_AUTOSAVE_AMOUNT); - break; - case WIDX_AUTOSAVE_AMOUNT_DOWN: - if (gConfigGeneral.autosave_amount > 1) - { - gConfigGeneral.autosave_amount -= 1; - config_save_default(); - widget_invalidate(w, WIDX_AUTOSAVE); - widget_invalidate(w, WIDX_AUTOSAVE_DROPDOWN); - widget_invalidate(w, WIDX_AUTOSAVE_AMOUNT); - } - } -} - -static void window_options_advanced_dropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex) -{ - if (dropdownIndex == -1) - return; - - switch (widgetIndex) - { - case WIDX_AUTOSAVE_DROPDOWN: - if (dropdownIndex != gConfigGeneral.autosave_frequency) - { - gConfigGeneral.autosave_frequency = static_cast(dropdownIndex); - config_save_default(); - w->Invalidate(); - } - break; - } -} - -static void window_options_advanced_invalidate(rct_window* w) -{ - window_options_common_invalidate_before(w); - - WidgetSetCheckboxValue(w, WIDX_DEBUGGING_TOOLS, gConfigGeneral.debugging_tools); - WidgetSetCheckboxValue(w, WIDX_ALLOW_LOADING_WITH_INCORRECT_CHECKSUM, gConfigGeneral.allow_loading_with_incorrect_checksum); - WidgetSetCheckboxValue(w, WIDX_SAVE_PLUGIN_DATA_CHECKBOX, gConfigGeneral.save_plugin_data); - WidgetSetCheckboxValue(w, WIDX_STAY_CONNECTED_AFTER_DESYNC, gConfigNetwork.stay_connected); - WidgetSetCheckboxValue(w, WIDX_ALWAYS_NATIVE_LOADSAVE, gConfigGeneral.use_native_browse_dialog); - - window_options_common_invalidate_after(w); -} - -static void window_options_advanced_paint(rct_window* w, rct_drawpixelinfo* dpi) -{ - WindowDrawWidgets(w, dpi); - window_options_draw_tab_images(dpi, w); - - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ 24, window_options_advanced_widgets[WIDX_AUTOSAVE].top + 1 }, - STR_OPTIONS_AUTOSAVE_FREQUENCY_LABEL, {}, { w->colours[1] }); - DrawTextBasic( - dpi, - w->windowPos - + ScreenCoordsXY{ window_options_advanced_widgets[WIDX_AUTOSAVE].left + 1, - window_options_advanced_widgets[WIDX_AUTOSAVE].top }, - window_options_autosave_names[gConfigGeneral.autosave_frequency], {}, { w->colours[1] }); - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ 24, window_options_advanced_widgets[WIDX_AUTOSAVE_AMOUNT].top + 1 }, - STR_AUTOSAVE_AMOUNT, {}, { w->colours[1] }); - auto ft = Formatter(); - ft.Add(static_cast(gConfigGeneral.autosave_amount)); - DrawTextBasic( - dpi, - w->windowPos + ScreenCoordsXY{ w->widgets[WIDX_AUTOSAVE_AMOUNT].left + 1, w->widgets[WIDX_AUTOSAVE_AMOUNT].top + 1 }, - STR_WINDOW_OBJECTIVE_VALUE_GUEST_COUNT, ft, { w->colours[1] }); - - ft = Formatter(); - ft.Add(Platform::StrDecompToPrecomp(gConfigGeneral.rct1_path)); - - rct_widget pathWidget = window_options_advanced_widgets[WIDX_PATH_TO_RCT1_BUTTON]; - - // Apply vertical alignment if appropriate. - int32_t widgetHeight = pathWidget.bottom - pathWidget.top; - int32_t lineHeight = font_get_line_height(FontSpriteBase::MEDIUM); - uint32_t padding = widgetHeight > lineHeight ? (widgetHeight - lineHeight) / 2 : 0; - ScreenCoordsXY screenCoords = { w->windowPos.x + pathWidget.left + 1, - w->windowPos.y + pathWidget.top + static_cast(padding) }; - DrawTextEllipsised(dpi, screenCoords, 277, STR_STRING, ft, { w->colours[1] }); -} - -static OpenRCT2String window_options_advanced_tooltip( - rct_window* w, const rct_widgetindex widgetIndex, const rct_string_id fallback) -{ - if (widgetIndex == WIDX_PATH_TO_RCT1_BUTTON) - { - if (str_is_null_or_empty(gConfigGeneral.rct1_path)) + switch (widgetIndex) { - // No tooltip if the path is empty - return { STR_NONE, {} }; + case WIDX_AUTOSAVE_DROPDOWN: + for (size_t i = AUTOSAVE_EVERY_MINUTE; i <= AUTOSAVE_NEVER; i++) + { + gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsArgs[i] = window_options_autosave_names[i]; + } + + this->ShowDropdown(widget, AUTOSAVE_NEVER + 1); + Dropdown::SetChecked(gConfigGeneral.autosave_frequency, true); + break; + case WIDX_AUTOSAVE_AMOUNT_UP: + gConfigGeneral.autosave_amount += 1; + config_save_default(); + widget_invalidate(this, WIDX_AUTOSAVE); + widget_invalidate(this, WIDX_AUTOSAVE_DROPDOWN); + widget_invalidate(this, WIDX_AUTOSAVE_AMOUNT); + break; + case WIDX_AUTOSAVE_AMOUNT_DOWN: + if (gConfigGeneral.autosave_amount > 1) + { + gConfigGeneral.autosave_amount -= 1; + config_save_default(); + widget_invalidate(this, WIDX_AUTOSAVE); + widget_invalidate(this, WIDX_AUTOSAVE_DROPDOWN); + widget_invalidate(this, WIDX_AUTOSAVE_AMOUNT); + } } - - auto ft = Formatter(); - ft.Add(gConfigGeneral.rct1_path); - return { fallback, ft }; } - return { fallback, {} }; -} -#pragma region Event lists + void AdvancedDropdown(rct_widgetindex widgetIndex, int32_t dropdownIndex) + { + if (dropdownIndex == -1) + return; -static rct_window_event_list window_options_events_display([](auto& events) { - events.mouse_up = &window_options_display_mouseup; - events.mouse_down = &window_options_display_mousedown; - events.dropdown = &window_options_display_dropdown; - events.update = &window_options_common_update; - events.invalidate = &window_options_display_invalidate; - events.paint = &window_options_display_paint; -}); + switch (widgetIndex) + { + case WIDX_AUTOSAVE_DROPDOWN: + if (dropdownIndex != gConfigGeneral.autosave_frequency) + { + gConfigGeneral.autosave_frequency = static_cast(dropdownIndex); + config_save_default(); + this->Invalidate(); + } + break; + } + } -static rct_window_event_list window_options_events_rendering([](auto& events) { - events.mouse_up = &window_options_rendering_mouseup; - events.mouse_down = &window_options_rendering_mousedown; - events.dropdown = &window_options_rendering_dropdown; - events.update = &window_options_common_update; - events.invalidate = &window_options_rendering_invalidate; - events.paint = &window_options_rendering_paint; -}); + void AdvancedPrepareDraw() + { + this->CommonPrepareDrawBefore(); -static rct_window_event_list window_options_events_culture([](auto& events) { - events.mouse_up = &window_options_culture_mouseup; - events.mouse_down = &window_options_culture_mousedown; - events.dropdown = &window_options_culture_dropdown; - events.update = &window_options_common_update; - events.invalidate = &window_options_culture_invalidate; - events.paint = &window_options_culture_paint; -}); + WidgetSetCheckboxValue(this, WIDX_DEBUGGING_TOOLS, gConfigGeneral.debugging_tools); + WidgetSetCheckboxValue( + this, WIDX_ALLOW_LOADING_WITH_INCORRECT_CHECKSUM, gConfigGeneral.allow_loading_with_incorrect_checksum); + WidgetSetCheckboxValue(this, WIDX_SAVE_PLUGIN_DATA_CHECKBOX, gConfigGeneral.save_plugin_data); + WidgetSetCheckboxValue(this, WIDX_STAY_CONNECTED_AFTER_DESYNC, gConfigNetwork.stay_connected); + WidgetSetCheckboxValue(this, WIDX_ALWAYS_NATIVE_LOADSAVE, gConfigGeneral.use_native_browse_dialog); -static rct_window_event_list window_options_events_audio([](auto& events) { - events.mouse_up = &window_options_audio_mouseup; - events.mouse_down = &window_options_audio_mousedown; - events.dropdown = &window_options_audio_dropdown; - events.update = &window_options_audio_update; - events.get_scroll_size = &window_options_audio_scrollgetsize; - events.invalidate = &window_options_audio_invalidate; - events.paint = &window_options_audio_paint; -}); + this->CommonPrepareDrawAfter(); + } -static rct_window_event_list window_options_events_controls([](auto& events) { - events.mouse_up = &window_options_controls_mouseup; - events.mouse_down = &window_options_controls_mousedown; - events.dropdown = &window_options_controls_dropdown; - events.update = &window_options_common_update; - events.invalidate = &window_options_controls_invalidate; - events.paint = &window_options_controls_paint; -}); + void AdvancedDraw(rct_drawpixelinfo* dpi) + { + WindowDrawWidgets(this, dpi); + this->DrawTabImages(dpi); -static rct_window_event_list window_options_events_misc([](auto& events) { - events.mouse_up = &window_options_misc_mouseup; - events.mouse_down = &window_options_misc_mousedown; - events.dropdown = &window_options_misc_dropdown; - events.update = &window_options_common_update; - events.invalidate = &window_options_misc_invalidate; - events.paint = &window_options_misc_paint; -}); + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ 24, this->widgets[WIDX_AUTOSAVE].top + 1 }, + STR_OPTIONS_AUTOSAVE_FREQUENCY_LABEL, {}, { this->colours[1] }); + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ this->widgets[WIDX_AUTOSAVE].left + 1, this->widgets[WIDX_AUTOSAVE].top }, + window_options_autosave_names[gConfigGeneral.autosave_frequency], {}, { this->colours[1] }); + DrawTextBasic( + dpi, this->windowPos + ScreenCoordsXY{ 24, this->widgets[WIDX_AUTOSAVE_AMOUNT].top + 1 }, STR_AUTOSAVE_AMOUNT, {}, + { this->colours[1] }); + auto ft = Formatter(); + ft.Add(static_cast(gConfigGeneral.autosave_amount)); + DrawTextBasic( + dpi, + this->windowPos + + ScreenCoordsXY{ this->widgets[WIDX_AUTOSAVE_AMOUNT].left + 1, this->widgets[WIDX_AUTOSAVE_AMOUNT].top + 1 }, + STR_WINDOW_OBJECTIVE_VALUE_GUEST_COUNT, ft, { this->colours[1] }); -static rct_window_event_list window_options_events_advanced([](auto& events) { - events.mouse_up = &window_options_advanced_mouseup; - events.mouse_down = &window_options_advanced_mousedown; - events.dropdown = &window_options_advanced_dropdown; - events.update = &window_options_common_update; - events.tooltip = &window_options_advanced_tooltip; - events.invalidate = &window_options_advanced_invalidate; - events.paint = &window_options_advanced_paint; -}); + ft = Formatter(); + ft.Add(Platform::StrDecompToPrecomp(gConfigGeneral.rct1_path)); -// clang-format off -static rct_window_event_list* window_options_event_lists[] = { - &window_options_events_display, - &window_options_events_rendering, - &window_options_events_culture, - &window_options_events_audio, - &window_options_events_controls, - &window_options_events_misc, - &window_options_events_advanced, + rct_widget pathWidget = this->widgets[WIDX_PATH_TO_RCT1_BUTTON]; + + // Apply vertical alignment if appropriate. + int32_t widgetHeight = pathWidget.bottom - pathWidget.top; + int32_t lineHeight = font_get_line_height(FontSpriteBase::MEDIUM); + uint32_t padding = widgetHeight > lineHeight ? (widgetHeight - lineHeight) / 2 : 0; + ScreenCoordsXY screenCoords = { this->windowPos.x + pathWidget.left + 1, + this->windowPos.y + pathWidget.top + static_cast(padding) }; + DrawTextEllipsised(dpi, screenCoords, 277, STR_STRING, ft, { this->colours[1] }); + } + + OpenRCT2String AdvancedTooltip(rct_widgetindex widgetIndex, rct_string_id fallback) + { + if (widgetIndex == WIDX_PATH_TO_RCT1_BUTTON) + { + if (str_is_null_or_empty(gConfigGeneral.rct1_path)) + { + // No tooltip if the path is empty + return { STR_NONE, {} }; + } + + auto ft = Formatter(); + ft.Add(gConfigGeneral.rct1_path); + return { fallback, ft }; + } + return { fallback, {} }; + } + +#pragma endregion + + void SetPage(int32_t p) + { + this->page = p; + this->frame_no = 0; + this->enabled_widgets = window_options_page_enabled_widgets[this->page]; + this->pressed_widgets = 0; + this->widgets = window_options_page_widgets[this->page]; + + this->Invalidate(); + window_event_resize_call(this); + window_event_invalidate_call(this); + WindowInitScrollWidgets(this); + this->Invalidate(); + } + + void SetPressedTab() + { + for (int32_t i = 0; i < WINDOW_OPTIONS_PAGE_COUNT; i++) + this->pressed_widgets &= ~(1 << (WIDX_TAB_1 + i)); + this->pressed_widgets |= 1LL << (WIDX_TAB_1 + this->page); + } + + void ShowDropdown(rct_widget* widget, int32_t num_items) + { + // helper function, all dropdown boxes have similar properties + WindowDropdownShowTextCustomWidth( + { this->windowPos.x + widget->left, this->windowPos.y + widget->top }, widget->height() + 1, this->colours[1], 0, + Dropdown::Flag::StayOpen, num_items, widget->width() - 3); + } + + void DrawTabImages(rct_drawpixelinfo* dpi) + { + this->DrawTabImage(dpi, WINDOW_OPTIONS_PAGE_DISPLAY, SPR_TAB_PAINT_0); + this->DrawTabImage(dpi, WINDOW_OPTIONS_PAGE_RENDERING, SPR_G2_TAB_TREE); + this->DrawTabImage(dpi, WINDOW_OPTIONS_PAGE_CULTURE, SPR_TAB_TIMER_0); + this->DrawTabImage(dpi, WINDOW_OPTIONS_PAGE_AUDIO, SPR_TAB_MUSIC_0); + this->DrawTabImage(dpi, WINDOW_OPTIONS_PAGE_CONTROLS_AND_INTERFACE, SPR_TAB_GEARS_0); + this->DrawTabImage(dpi, WINDOW_OPTIONS_PAGE_MISC, SPR_TAB_RIDE_0); + this->DrawTabImage(dpi, WINDOW_OPTIONS_PAGE_ADVANCED, SPR_TAB_WRENCH_0); + } + + void DrawTabImage(rct_drawpixelinfo* dpi, int32_t p, int32_t spriteIndex) + { + rct_widgetindex widgetIndex = WIDX_TAB_1 + p; + rct_widget* widget = &this->widgets[widgetIndex]; + + auto screenCoords = this->windowPos + ScreenCoordsXY{ widget->left, widget->top }; + + if (!(this->disabled_widgets & (1LL << widgetIndex))) + { + if (this->page == p) + { + int32_t frame = this->frame_no / window_options_tab_animation_divisor[this->page]; + spriteIndex += (frame % window_options_tab_animation_frames[this->page]); + } + + // Draw normal, enabled sprite. + gfx_draw_sprite(dpi, ImageId(spriteIndex), screenCoords); + } + else + { + // Get the window background colour + uint8_t window_colour = NOT_TRANSLUCENT(this->colours[widget->colour]); + + // Draw greyed out (light border bottom right shadow) + gfx_draw_sprite_solid(dpi, spriteIndex, screenCoords + ScreenCoordsXY{ 1, 1 }, ColourMapA[window_colour].lighter); + + // Draw greyed out (dark) + gfx_draw_sprite_solid(dpi, spriteIndex, screenCoords, ColourMapA[window_colour].mid_light); + } + } + + void UpdateHeightMarkers() + { + config_save_default(); + gfx_invalidate_screen(); + } + + uint8_t GetScrollPercentage(const rct_widget& widget, const rct_scroll& scroll) + { + uint8_t w = widget.width() - 1; + return static_cast(scroll.h_left) / (scroll.h_right - w) * 100; + } + + void InitializeScrollPosition(rct_widgetindex widgetIndex, int32_t scrollId, uint8_t volume) + { + const auto& widget = this->widgets[widgetIndex]; + auto& scroll = this->scrolls[scrollId]; + + int32_t widgetSize = scroll.h_right - (widget.width() - 1); + scroll.h_left = ceil(volume / 100.0f * widgetSize); + + WidgetScrollUpdateThumbs(this, widgetIndex); + } }; + // clang-format on - -#pragma region Common - /** * * rct2: 0x006BAC5B */ rct_window* window_options_open() { - rct_window* w; - - // Check if window is already open - w = window_bring_to_front_by_class(WC_OPTIONS); - if (w != nullptr) - return w; - - w = WindowCreateCentred(WW, WH, &window_options_events_display, WC_OPTIONS, 0); - w->widgets = window_options_display_widgets; - w->enabled_widgets = window_options_page_enabled_widgets[WINDOW_OPTIONS_PAGE_DISPLAY]; - w->page = WINDOW_OPTIONS_PAGE_DISPLAY; - w->frame_no = 0; - WindowInitScrollWidgets(w); - - return w; -} - -static void window_options_set_page(rct_window* w, int32_t page) -{ - w->page = page; - w->frame_no = 0; - w->event_handlers = window_options_event_lists[page]; - w->enabled_widgets = window_options_page_enabled_widgets[page]; - w->pressed_widgets = 0; - w->widgets = window_options_page_widgets[page]; - - w->Invalidate(); - window_event_resize_call(w); - window_event_invalidate_call(w); - WindowInitScrollWidgets(w); - w->Invalidate(); -} - -static void window_options_set_pressed_tab(rct_window* w) -{ - int32_t i; - for (i = 0; i < WINDOW_OPTIONS_PAGE_COUNT; i++) - w->pressed_widgets &= ~(1 << (WIDX_TAB_1 + i)); - w->pressed_widgets |= 1LL << (WIDX_TAB_1 + w->page); -} - -static void window_options_draw_tab_image(rct_drawpixelinfo* dpi, rct_window* w, int32_t page, int32_t spriteIndex) -{ - rct_widgetindex widgetIndex = WIDX_TAB_1 + page; - rct_widget* widget = &w->widgets[widgetIndex]; - - auto screenCoords = w->windowPos + ScreenCoordsXY{ widget->left, widget->top }; - - if (!(w->disabled_widgets & (1LL << widgetIndex))) + auto* window = window_bring_to_front_by_class(WC_OPTIONS); + if (window == nullptr) { - if (w->page == page) - { - int32_t frame = w->frame_no / window_options_tab_animation_divisor[w->page]; - spriteIndex += (frame % window_options_tab_animation_frames[w->page]); - } - - // Draw normal, enabled sprite. - gfx_draw_sprite(dpi, ImageId(spriteIndex), screenCoords); - } - else - { - // Get the window background colour - uint8_t window_colour = NOT_TRANSLUCENT(w->colours[widget->colour]); - - // Draw greyed out (light border bottom right shadow) - gfx_draw_sprite_solid(dpi, spriteIndex, screenCoords + ScreenCoordsXY{ 1, 1 }, ColourMapA[window_colour].lighter); - - // Draw greyed out (dark) - gfx_draw_sprite_solid(dpi, spriteIndex, screenCoords, ColourMapA[window_colour].mid_light); + window = WindowCreate(WC_OPTIONS, WW, WH, WF_CENTRE_SCREEN); } + return window; } - -static void window_options_draw_tab_images(rct_drawpixelinfo* dpi, rct_window* w) -{ - window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_DISPLAY, SPR_TAB_PAINT_0); - window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_RENDERING, SPR_G2_TAB_TREE); - window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_CULTURE, SPR_TAB_TIMER_0); - window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_AUDIO, SPR_TAB_MUSIC_0); - window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_CONTROLS_AND_INTERFACE, SPR_TAB_GEARS_0); - window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_MISC, SPR_TAB_RIDE_0); - window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_ADVANCED, SPR_TAB_WRENCH_0); -} - -// helper function, all dropdown boxes have similar properties -static void window_options_show_dropdown(rct_window* w, rct_widget* widget, int32_t num_items) -{ - WindowDropdownShowTextCustomWidth( - { w->windowPos.x + widget->left, w->windowPos.y + widget->top }, widget->height() + 1, w->colours[1], 0, - Dropdown::Flag::StayOpen, num_items, widget->width() - 3); -} - -static void window_options_update_height_markers() -{ - config_save_default(); - gfx_invalidate_screen(); -} - -#pragma endregion