From 5985163dcd67d7234c1f713817c24191f0c62cac Mon Sep 17 00:00:00 2001 From: David Griswold Date: Mon, 3 Mar 2025 14:28:51 -0300 Subject: [PATCH 1/2] implement screen gap --- .../features/settings/model/IntSetting.kt | 1 + .../settings/ui/SettingsFragmentPresenter.kt | 12 ++++++ src/android/app/src/main/jni/config.cpp | 2 + src/android/app/src/main/jni/default_ini.h | 6 +++ .../app/src/main/res/values/strings.xml | 2 + src/citra_qt/configuration/config.cpp | 2 + .../configuration/configure_layout.cpp | 2 + .../configuration/configure_layout.ui | 38 +++++++++++++++++++ src/common/settings.cpp | 2 + src/common/settings.h | 1 + src/core/frontend/framebuffer_layout.cpp | 37 +++++++++--------- 11 files changed, 88 insertions(+), 17 deletions(-) diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntSetting.kt index 0f1ca8d43..6b81b5111 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntSetting.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntSetting.kt @@ -33,6 +33,7 @@ enum class IntSetting( LANDSCAPE_BOTTOM_Y("custom_bottom_y",Settings.SECTION_LAYOUT,480), LANDSCAPE_BOTTOM_WIDTH("custom_bottom_width",Settings.SECTION_LAYOUT,640), LANDSCAPE_BOTTOM_HEIGHT("custom_bottom_height",Settings.SECTION_LAYOUT,480), + SCREEN_GAP("screen_gap",Settings.SECTION_LAYOUT,0), PORTRAIT_SCREEN_LAYOUT("portrait_layout_option",Settings.SECTION_LAYOUT,0), PORTRAIT_TOP_X("custom_portrait_top_x",Settings.SECTION_LAYOUT,0), PORTRAIT_TOP_Y("custom_portrait_top_y",Settings.SECTION_LAYOUT,0), diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt index 31401567f..2098616d6 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -973,6 +973,18 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) IntSetting.SMALL_SCREEN_POSITION.defaultValue ) ) + add( + SliderSetting( + IntSetting.SCREEN_GAP, + R.string.screen_gap, + R.string.screen_gap_description, + 0, + 480, + "px", + IntSetting.SCREEN_GAP.key, + IntSetting.SCREEN_GAP.defaultValue.toFloat() + ) + ) add( SliderSetting( FloatSetting.LARGE_SCREEN_PROPORTION, diff --git a/src/android/app/src/main/jni/config.cpp b/src/android/app/src/main/jni/config.cpp index 19e422324..53690764c 100644 --- a/src/android/app/src/main/jni/config.cpp +++ b/src/android/app/src/main/jni/config.cpp @@ -183,11 +183,13 @@ void Config::ReadValues() { layoutInt = static_cast(Settings::LayoutOption::LargeScreen); } Settings::values.layout_option = static_cast(layoutInt); + Settings::values.screen_gap = static_cast(sdl2_config->GetReal("Layout","screen_gap",0)); Settings::values.large_screen_proportion = static_cast(sdl2_config->GetReal("Layout", "large_screen_proportion", 2.25)); Settings::values.small_screen_position = static_cast( sdl2_config->GetInteger("Layout", "small_screen_position", static_cast(Settings::SmallScreenPosition::TopRight))); + ReadSetting("Layout",Settings::values.screen_gap); ReadSetting("Layout", Settings::values.custom_top_x); ReadSetting("Layout", Settings::values.custom_top_y); ReadSetting("Layout", Settings::values.custom_top_width); diff --git a/src/android/app/src/main/jni/default_ini.h b/src/android/app/src/main/jni/default_ini.h index 5c802856e..48f204e7d 100644 --- a/src/android/app/src/main/jni/default_ini.h +++ b/src/android/app/src/main/jni/default_ini.h @@ -197,6 +197,12 @@ disable_right_eye_render = # 5: Custom Layout layout_option = +# Screen Gap - adds a gap between screens in all two-screen modes +# Measured in pixels relative to the 240px default height of the screens +# Scales with the larger screen (so 24 is 10% of the larger screen height) +# Default value is 0.0 +screen_gap = + # Large Screen Proportion - Relative size of large:small in large screen mode # Default value is 2.25 large_screen_proportion = diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 5495a2a23..667ebfb1a 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -391,6 +391,8 @@ Bottom Left Above Below + Screen Gap + Gap between screens in all two-screen modes. Measured in px relative to the 240px height of the larger screen. Large Screen Proportion How many times larger is the large screen than the small screen in Large Screen layout? Adjust Custom Layout in Settings diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index a925ca3b2..2f029fab6 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -519,6 +519,7 @@ void QtConfig::ReadLayoutValues() { ReadGlobalSetting(Settings::values.swap_screen); ReadGlobalSetting(Settings::values.upright_screen); ReadGlobalSetting(Settings::values.large_screen_proportion); + ReadGlobalSetting(Settings::values.screen_gap); ReadGlobalSetting(Settings::values.small_screen_position); if (global) { @@ -1085,6 +1086,7 @@ void QtConfig::SaveLayoutValues() { WriteGlobalSetting(Settings::values.swap_screen); WriteGlobalSetting(Settings::values.upright_screen); WriteGlobalSetting(Settings::values.large_screen_proportion); + WriteGlobalSetting(Settings::values.screen_gap); WriteGlobalSetting(Settings::values.small_screen_position); if (global) { WriteBasicSetting(Settings::values.mono_render_option); diff --git a/src/citra_qt/configuration/configure_layout.cpp b/src/citra_qt/configuration/configure_layout.cpp index cc78d8948..f62767838 100644 --- a/src/citra_qt/configuration/configure_layout.cpp +++ b/src/citra_qt/configuration/configure_layout.cpp @@ -124,6 +124,7 @@ void ConfigureLayout::SetConfiguration() { ui->toggle_swap_screen->setChecked(Settings::values.swap_screen.GetValue()); ui->toggle_upright_screen->setChecked(Settings::values.upright_screen.GetValue()); + ui->screen_gap->setValue(Settings::values.screen_gap.GetValue()); ui->large_screen_proportion->setValue(Settings::values.large_screen_proportion.GetValue()); ui->small_screen_position_combobox->setCurrentIndex( static_cast(Settings::values.small_screen_position.GetValue())); @@ -163,6 +164,7 @@ void ConfigureLayout::RetranslateUI() { void ConfigureLayout::ApplyConfiguration() { Settings::values.large_screen_proportion = ui->large_screen_proportion->value(); + Settings::values.screen_gap = ui->screen_gap->value(); Settings::values.small_screen_position = static_cast( ui->small_screen_position_combobox->currentIndex()); Settings::values.custom_top_x = ui->custom_top_x->value(); diff --git a/src/citra_qt/configuration/configure_layout.ui b/src/citra_qt/configuration/configure_layout.ui index 3b564515b..33ef4fc68 100644 --- a/src/citra_qt/configuration/configure_layout.ui +++ b/src/citra_qt/configuration/configure_layout.ui @@ -107,6 +107,44 @@ + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Screen Gap + + + + + + + 0.0 + + + 720.0 + + + 0.0 + + + + + + diff --git a/src/common/settings.cpp b/src/common/settings.cpp index d5e57fbc2..8cb37480e 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -113,6 +113,7 @@ void LogSettings() { log_setting("Layout_PortraitLayoutOption", values.portrait_layout_option.GetValue()); log_setting("Layout_SwapScreen", values.swap_screen.GetValue()); log_setting("Layout_UprightScreen", values.upright_screen.GetValue()); + log_setting("Layout_ScreenGap",values.screen_gap.GetValue()); log_setting("Layout_LargeScreenProportion", values.large_screen_proportion.GetValue()); log_setting("Layout_SmallScreenPosition", values.small_screen_position.GetValue()); log_setting("Utility_DumpTextures", values.dump_textures.GetValue()); @@ -206,6 +207,7 @@ void RestoreGlobalState(bool is_powered_on) { values.swap_screen.SetGlobal(true); values.upright_screen.SetGlobal(true); values.large_screen_proportion.SetGlobal(true); + values.screen_gap.SetGlobal(true); values.small_screen_position.SetGlobal(true); values.bg_red.SetGlobal(true); values.bg_green.SetGlobal(true); diff --git a/src/common/settings.h b/src/common/settings.h index f8e9e3e2e..7326704f8 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -505,6 +505,7 @@ struct Values { SwitchableSetting upright_screen{false, "upright_screen"}; SwitchableSetting large_screen_proportion{4.f, 1.f, 16.f, "large_screen_proportion"}; + SwitchableSetting screen_gap{0.f,"screen_gap"}; SwitchableSetting small_screen_position{SmallScreenPosition::BottomRight, "small_screen_position"}; Setting custom_top_x{0, "custom_top_x"}; diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index 7cf52a29c..108ea8013 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp @@ -115,7 +115,7 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upr // To do that, find the total emulation box and maximize that based on window size const float window_aspect_ratio = static_cast(height) / width; float emulation_aspect_ratio; - + u32 gap = (u32)(Settings::values.screen_gap.GetValue() * scale_factor); float large_height = swapped ? Core::kScreenBottomHeight * scale_factor : Core::kScreenTopHeight * scale_factor; float small_height = @@ -129,9 +129,9 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upr if (vertical) { // width is just the larger size at this point emulation_width = std::max(large_width, small_width); - emulation_height = large_height + small_height; + emulation_height = large_height + small_height + gap; } else { - emulation_width = large_width + small_width; + emulation_width = large_width + small_width + gap; emulation_height = std::max(large_height, small_height); } @@ -156,47 +156,48 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upr // shift the large screen so it is at the top position of the bounding rectangle large_screen = large_screen.TranslateY((height - total_rect.GetHeight()) / 2); } + gap *= scale_amount; switch (small_screen_position) { case Settings::SmallScreenPosition::TopRight: // Shift the small screen to the top right corner - small_screen = small_screen.TranslateX(large_screen.right); + small_screen = small_screen.TranslateX(large_screen.right + gap); small_screen = small_screen.TranslateY(large_screen.top); break; case Settings::SmallScreenPosition::MiddleRight: // Shift the small screen to the center right - small_screen = small_screen.TranslateX(large_screen.right); + small_screen = small_screen.TranslateX(large_screen.right + gap); small_screen = small_screen.TranslateY( ((large_screen.GetHeight() - small_screen.GetHeight()) / 2) + large_screen.top); break; case Settings::SmallScreenPosition::BottomRight: // Shift the small screen to the bottom right corner - small_screen = small_screen.TranslateX(large_screen.right); + small_screen = small_screen.TranslateX(large_screen.right + gap); small_screen = small_screen.TranslateY(large_screen.bottom - small_screen.GetHeight()); break; case Settings::SmallScreenPosition::TopLeft: // shift the small screen to the upper left then shift the large screen to its right small_screen = small_screen.TranslateX(large_screen.left); - large_screen = large_screen.TranslateX(small_screen.GetWidth()); + large_screen = large_screen.TranslateX(small_screen.GetWidth() + gap); small_screen = small_screen.TranslateY(large_screen.top); break; case Settings::SmallScreenPosition::MiddleLeft: // shift the small screen to the middle left and shift the large screen to its right small_screen = small_screen.TranslateX(large_screen.left); - large_screen = large_screen.TranslateX(small_screen.GetWidth()); + large_screen = large_screen.TranslateX(small_screen.GetWidth() + gap); small_screen = small_screen.TranslateY( ((large_screen.GetHeight() - small_screen.GetHeight()) / 2) + large_screen.top); break; case Settings::SmallScreenPosition::BottomLeft: // shift the small screen to the bottom left and shift the large screen to its right small_screen = small_screen.TranslateX(large_screen.left); - large_screen = large_screen.TranslateX(small_screen.GetWidth()); + large_screen = large_screen.TranslateX(small_screen.GetWidth() + gap); small_screen = small_screen.TranslateY(large_screen.bottom - small_screen.GetHeight()); break; case Settings::SmallScreenPosition::AboveLarge: // shift the large screen down and the bottom screen above it small_screen = small_screen.TranslateY(large_screen.top); - large_screen = large_screen.TranslateY(small_screen.GetHeight()); + large_screen = large_screen.TranslateY(small_screen.GetHeight() + gap); // If the "large screen" is actually smaller, center it if (large_screen.GetWidth() < total_rect.GetWidth()) { large_screen = @@ -212,7 +213,7 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upr large_screen = large_screen.TranslateX((total_rect.GetWidth() - large_screen.GetWidth()) / 2); } - small_screen = small_screen.TranslateY(large_screen.bottom); + small_screen = small_screen.TranslateY(large_screen.bottom + gap); small_screen = small_screen.TranslateX(large_screen.left + large_screen.GetWidth() / 2 - small_screen.GetWidth() / 2); break; @@ -346,7 +347,8 @@ FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped, bool FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondary, bool is_portrait) { - int width, height; + int width, height, gap; + gap = (int)(Settings::values.screen_gap.GetValue()) * res_scale; if (is_portrait) { auto layout_option = Settings::values.portrait_layout_option.GetValue(); switch (layout_option) { @@ -363,7 +365,8 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondar Settings::values.swap_screen.GetValue(), is_portrait); case Settings::PortraitLayoutOption::PortraitTopFullWidth: width = Core::kScreenTopWidth * res_scale; - height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale; + height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale + gap; + return PortraitTopFullFrameLayout(width, height, Settings::values.swap_screen.GetValue()); } @@ -418,9 +421,9 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondar Settings::SmallScreenPosition::BelowLarge) { // vertical, so height is sum of heights, width is larger of widths width = std::max(largeWidth, smallWidth) * res_scale; - height = (largeHeight + smallHeight) * res_scale; + height = (largeHeight + smallHeight) * res_scale + gap; } else { - width = (largeWidth + smallWidth) * res_scale; + width = (largeWidth + smallWidth) * res_scale + gap; height = std::max(largeHeight, smallHeight) * res_scale; } @@ -433,7 +436,7 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondar Settings::values.small_screen_position.GetValue()); } case Settings::LayoutOption::SideScreen: - width = (Core::kScreenTopWidth + Core::kScreenBottomWidth) * res_scale; + width = (Core::kScreenTopWidth + Core::kScreenBottomWidth) * res_scale + gap; height = Core::kScreenTopHeight * res_scale; if (Settings::values.upright_screen.GetValue()) { @@ -446,7 +449,7 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondar case Settings::LayoutOption::Default: default: width = Core::kScreenTopWidth * res_scale; - height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale; + height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale + gap; if (Settings::values.upright_screen.GetValue()) { std::swap(width, height); From 501ac3a5734c498f372774b4a88f6ce15350c585 Mon Sep 17 00:00:00 2001 From: David Griswold Date: Tue, 4 Mar 2025 14:37:57 -0300 Subject: [PATCH 2/2] type conversion fix for windows --- src/core/frontend/framebuffer_layout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index 108ea8013..4933b792f 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp @@ -156,7 +156,7 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upr // shift the large screen so it is at the top position of the bounding rectangle large_screen = large_screen.TranslateY((height - total_rect.GetHeight()) / 2); } - gap *= scale_amount; + gap = static_cast(static_cast(gap) * scale_amount); switch (small_screen_position) { case Settings::SmallScreenPosition::TopRight: