From 7b0fbdf884f18e17ba748a99eb0f7e38e4828ab5 Mon Sep 17 00:00:00 2001 From: PabloMK7 Date: Sat, 15 Jun 2024 20:49:08 +0200 Subject: [PATCH 01/19] Fix crash when cubemap face id is invalid --- src/video_core/rasterizer_cache/rasterizer_cache.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/video_core/rasterizer_cache/rasterizer_cache.h b/src/video_core/rasterizer_cache/rasterizer_cache.h index cd9c080ef..0144cbd61 100644 --- a/src/video_core/rasterizer_cache/rasterizer_cache.h +++ b/src/video_core/rasterizer_cache/rasterizer_cache.h @@ -647,10 +647,11 @@ typename T::Surface& RasterizerCache::GetTextureCube(const TextureCubeConfig& Surface& cube_surface = slot_surfaces[cube.surface_id]; for (u32 i = 0; i < addresses.size(); i++) { - if (!addresses[i]) { + const SurfaceId& face_id = cube.face_ids[i]; + if (!addresses[i] || !face_id) { continue; } - Surface& surface = slot_surfaces[cube.face_ids[i]]; + Surface& surface = slot_surfaces[face_id]; if (cube.ticks[i] == surface.modification_tick) { continue; } From b93e51ca7c0e6ae1ce5238545deadc405902206f Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Tue, 6 Aug 2024 21:28:21 +0100 Subject: [PATCH 02/19] Changed how pausing the emulator is handled to allow frame advancing Where previously the emulator thread was halted, frame advancing mode is now enabled instead This commit also removes the "Enable Frame Advancing" option due to being obsolete --- src/lime_qt/main.cpp | 28 ++++++++-------------------- src/lime_qt/main.ui | 17 +---------------- 2 files changed, 9 insertions(+), 36 deletions(-) diff --git a/src/lime_qt/main.cpp b/src/lime_qt/main.cpp index 5d54c00e9..f08aa4991 100644 --- a/src/lime_qt/main.cpp +++ b/src/lime_qt/main.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -639,8 +639,6 @@ void GMainWindow::InitializeHotkeys() { // TODO: This code kind of sucks link_action_shortcut(ui->action_Capture_Screenshot, QStringLiteral("Capture Screenshot")); link_action_shortcut(ui->action_Screen_Layout_Swap_Screens, swap_screens); link_action_shortcut(ui->action_Screen_Layout_Upright_Screens, rotate_screens); - link_action_shortcut(ui->action_Enable_Frame_Advancing, - QStringLiteral("Toggle Frame Advancing")); link_action_shortcut(ui->action_Advance_Frame, QStringLiteral("Advance Frame")); link_action_shortcut(ui->action_Load_from_Newest_Slot, QStringLiteral("Load from Newest Slot")); link_action_shortcut(ui->action_Save_to_Oldest_Slot, QStringLiteral("Save to Oldest Slot")); @@ -946,16 +944,8 @@ void GMainWindow::ConnectMenuEvents() { connect_menu(ui->action_Save_Movie, &GMainWindow::OnSaveMovie); connect_menu(ui->action_Movie_Read_Only_Mode, [this](bool checked) { movie.SetReadOnly(checked); }); - connect_menu(ui->action_Enable_Frame_Advancing, [this] { - if (emulation_running) { - system.frame_limiter.SetFrameAdvancing(ui->action_Enable_Frame_Advancing->isChecked()); - ui->action_Advance_Frame->setEnabled(ui->action_Enable_Frame_Advancing->isChecked()); - } - }); connect_menu(ui->action_Advance_Frame, [this] { if (emulation_running && system.frame_limiter.IsFrameAdvancing()) { - ui->action_Enable_Frame_Advancing->setChecked(true); - ui->action_Advance_Frame->setEnabled(true); system.frame_limiter.AdvanceFrame(); } }); @@ -980,7 +970,8 @@ void GMainWindow::ConnectMenuEvents() { } void GMainWindow::UpdateMenuState() { - const bool is_paused = !emu_thread || !emu_thread->IsRunning(); + const bool is_paused = + !emu_thread || !emu_thread->IsRunning() || system.frame_limiter.IsFrameAdvancing(); const std::array running_actions{ ui->action_Stop, @@ -998,6 +989,7 @@ void GMainWindow::UpdateMenuState() { } ui->action_Capture_Screenshot->setEnabled(emulation_running && !is_paused); + ui->action_Advance_Frame->setEnabled(emulation_running && is_paused); if (emulation_running && is_paused) { ui->action_Pause->setText(tr("&Continue")); @@ -1417,12 +1409,7 @@ void GMainWindow::BootGame(const QString& filename) { movie_playback_path.clear(); } - if (ui->action_Enable_Frame_Advancing->isChecked()) { - ui->action_Advance_Frame->setEnabled(true); - system.frame_limiter.SetFrameAdvancing(true); - } else { - ui->action_Advance_Frame->setEnabled(false); - } + ui->action_Advance_Frame->setEnabled(false); if (video_dumping_on_start) { StartVideoDumping(video_dumping_path); @@ -2302,6 +2289,7 @@ void GMainWindow::OnStartGame() { PreventOSSleep(); emu_thread->SetRunning(true); + system.frame_limiter.SetFrameAdvancing(false); graphics_api_button->setEnabled(false); qRegisterMetaType("Core::System::ResultStatus"); qRegisterMetaType("std::string"); @@ -2331,7 +2319,7 @@ void GMainWindow::OnRestartGame() { } void GMainWindow::OnPauseGame() { - emu_thread->SetRunning(false); + system.frame_limiter.SetFrameAdvancing(true); qt_cameras->PauseCameras(); play_time_manager->Stop(); @@ -2346,7 +2334,7 @@ void GMainWindow::OnPauseGame() { void GMainWindow::OnPauseContinueGame() { if (emulation_running) { - if (emu_thread->IsRunning()) { + if (emu_thread->IsRunning() && !system.frame_limiter.IsFrameAdvancing()) { OnPauseGame(); } else { OnStartGame(); diff --git a/src/lime_qt/main.ui b/src/lime_qt/main.ui index 8bff4a659..32a85f8ff 100644 --- a/src/lime_qt/main.ui +++ b/src/lime_qt/main.ui @@ -182,15 +182,8 @@ - - - Frame Advance - - - - + - @@ -404,14 +397,6 @@ Read-Only Mode - - - true - - - Enable Frame Advancing - - false From 138e4bcbd09254f8db895805aecfce7d6e4a5536 Mon Sep 17 00:00:00 2001 From: David Griswold Date: Sun, 11 Aug 2024 13:41:25 +0100 Subject: [PATCH 03/19] android: Added portrait-specific config values for custom layouts --- src/android/app/src/main/jni/config.cpp | 12 +++++ src/android/app/src/main/jni/default_ini.h | 17 +++++++ src/common/settings.h | 10 ++++ src/core/frontend/emu_window.cpp | 6 ++- src/core/frontend/framebuffer_layout.cpp | 53 ++++++++++++++-------- src/core/frontend/framebuffer_layout.h | 3 +- src/lime/config.cpp | 10 ++++ src/lime_qt/configuration/config.cpp | 18 ++++++++ 8 files changed, 107 insertions(+), 22 deletions(-) diff --git a/src/android/app/src/main/jni/config.cpp b/src/android/app/src/main/jni/config.cpp index 136671bff..17b0e1e9b 100644 --- a/src/android/app/src/main/jni/config.cpp +++ b/src/android/app/src/main/jni/config.cpp @@ -188,6 +188,18 @@ void Config::ReadValues() { ReadSetting("Layout", Settings::values.cardboard_x_shift); ReadSetting("Layout", Settings::values.cardboard_y_shift); +#ifdef ANDROID + ReadSetting("Layout", Settings::values.custom_portrait_layout); + ReadSetting("Layout", Settings::values.custom_portrait_top_left); + ReadSetting("Layout", Settings::values.custom_portrait_top_top); + ReadSetting("Layout", Settings::values.custom_portrait_top_right); + ReadSetting("Layout", Settings::values.custom_portrait_top_bottom); + ReadSetting("Layout", Settings::values.custom_portrait_bottom_left); + ReadSetting("Layout", Settings::values.custom_portrait_bottom_top); + ReadSetting("Layout", Settings::values.custom_portrait_bottom_right); + ReadSetting("Layout", Settings::values.custom_portrait_bottom_bottom); +#endif + // Utility ReadSetting("Utility", Settings::values.dump_textures); ReadSetting("Utility", Settings::values.custom_textures); diff --git a/src/android/app/src/main/jni/default_ini.h b/src/android/app/src/main/jni/default_ini.h index b96999da9..856ad3eb4 100644 --- a/src/android/app/src/main/jni/default_ini.h +++ b/src/android/app/src/main/jni/default_ini.h @@ -184,6 +184,7 @@ filter_mode = layout_option = # Toggle custom layout (using the settings below) on or off. +# Only applies to landscape on Android # 0 (default): Off, 1: On custom_layout = @@ -198,6 +199,22 @@ custom_bottom_y = custom_bottom_width = custom_bottom_height = +# Custom Layout Options for Android Portrait Mode +# Toggle custom layout (using the settings below) on or off. +# 0 (default): Off, 1: On +custom_portrait_layout = + +# Screen placement when using Custom layout option +# 0x, 0y is the top left corner of the render window. +custom_portrait_top_left = +custom_portrait_top_top = +custom_portrait_top_right = +custom_portrait_top_bottom = +custom_portrait_bottom_left = +custom_portrait_bottom_top = +custom_portrait_bottom_right = +custom_portrait_bottom_bottom = + # Swaps the prominent screen with the other screen. # For example, if Single Screen is chosen, setting this to 1 will display the bottom screen instead of the top screen. # 0 (default): Top Screen is prominent, 1: Bottom Screen is prominent diff --git a/src/common/settings.h b/src/common/settings.h index 580c0b65c..38c70a2bc 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -506,6 +506,16 @@ struct Values { Setting screen_bottom_leftright_padding{0, "screen_bottom_leftright_padding"}; Setting screen_bottom_topbottom_padding{0, "screen_bottom_topbottom_padding"}; + Setting custom_portrait_layout{false, "custom_portrait_layout"}; + Setting custom_portrait_top_left{0, "custom_portrait_top_left"}; + Setting custom_portrait_top_top{0, "custom_portrait_top_top"}; + Setting custom_portrait_top_right{400, "custom_portrait_top_right"}; + Setting custom_portrait_top_bottom{240, "custom_portrait_top_bottom"}; + Setting custom_portrait_bottom_left{40, "custom_portrait_bottom_left"}; + Setting custom_portrait_bottom_top{240, "custom_portrait_bottom_top"}; + Setting custom_portrait_bottom_right{360, "custom_portrait_bottom_right"}; + Setting custom_portrait_bottom_bottom{480, "custom_portrait_bottom_bottom"}; + SwitchableSetting bg_red{0.f, "bg_red"}; SwitchableSetting bg_green{0.f, "bg_green"}; SwitchableSetting bg_blue{0.f, "bg_blue"}; diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index 872cce7d1..3765986cb 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -183,8 +183,10 @@ void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height, bool is_po const auto min_size = Layout::GetMinimumSizeFromLayout(layout_option, Settings::values.upright_screen.GetValue()); - if (Settings::values.custom_layout.GetValue() == true) { - layout = Layout::CustomFrameLayout(width, height, Settings::values.swap_screen.GetValue()); + if ((Settings::values.custom_layout.GetValue() == true && !is_portrait_mode) || + (Settings::values.custom_portrait_layout.GetValue() == true && is_portrait_mode)) { + layout = Layout::CustomFrameLayout(width, height, Settings::values.swap_screen.GetValue(), + is_portrait_mode); } else { width = std::max(width, min_size.first); height = std::max(height, min_size.second); diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index fbb4667fc..44f82f012 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp @@ -382,24 +382,30 @@ FramebufferLayout SeparateWindowsLayout(u32 width, u32 height, bool is_secondary return SingleFrameLayout(width, height, is_secondary, upright); } -FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped) { +FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped, bool is_portrait_mode) { ASSERT(width > 0); ASSERT(height > 0); FramebufferLayout res{width, height, true, true, {}, {}, !Settings::values.upright_screen}; + u16 top_left = is_portrait_mode ? Settings::values.custom_portrait_top_left.GetValue() + : Settings::values.custom_top_left.GetValue(); + u16 top_right = is_portrait_mode ? Settings::values.custom_portrait_top_right.GetValue() + : Settings::values.custom_top_right.GetValue(); + u16 top_top = is_portrait_mode ? Settings::values.custom_portrait_top_top.GetValue() + : Settings::values.custom_top_top.GetValue(); + u16 top_bottom = is_portrait_mode ? Settings::values.custom_portrait_top_bottom.GetValue() + : Settings::values.custom_top_bottom.GetValue(); + u16 bottom_left = is_portrait_mode ? Settings::values.custom_portrait_bottom_left.GetValue() + : Settings::values.custom_bottom_left.GetValue(); + u16 bottom_right = is_portrait_mode ? Settings::values.custom_portrait_bottom_right.GetValue() + : Settings::values.custom_bottom_right.GetValue(); + u16 bottom_top = is_portrait_mode ? Settings::values.custom_portrait_bottom_top.GetValue() + : Settings::values.custom_bottom_top.GetValue(); + u16 bottom_bottom = is_portrait_mode ? Settings::values.custom_portrait_bottom_bottom.GetValue() + : Settings::values.custom_bottom_bottom.GetValue(); - Common::Rectangle top_screen{Settings::values.custom_top_x.GetValue(), - Settings::values.custom_top_y.GetValue(), - (u32)(Settings::values.custom_top_x.GetValue() + - Settings::values.custom_top_width.GetValue()), - (u32)(Settings::values.custom_top_y.GetValue() + - Settings::values.custom_top_height.GetValue())}; - Common::Rectangle bot_screen{Settings::values.custom_bottom_x.GetValue(), - Settings::values.custom_bottom_y.GetValue(), - (u32)(Settings::values.custom_bottom_x.GetValue() + - Settings::values.custom_bottom_width.GetValue()), - (u32)(Settings::values.custom_bottom_y.GetValue() + - Settings::values.custom_bottom_height.GetValue())}; + Common::Rectangle top_screen{top_left, top_top, top_right, top_bottom}; + Common::Rectangle bot_screen{bottom_left, bottom_top, bottom_right, bottom_bottom}; if (is_swapped) { res.top_screen = bot_screen; @@ -412,12 +418,21 @@ FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped) { } FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondary) { - if (Settings::values.custom_layout.GetValue() == true) { - return CustomFrameLayout(std::max(Settings::values.custom_top_width.GetValue(), - Settings::values.custom_bottom_width.GetValue()), - std::max(Settings::values.custom_top_height.GetValue(), - Settings::values.custom_bottom_height.GetValue()), - Settings::values.swap_screen.GetValue()); + bool is_portrait_mode = + Settings::values.layout_option.GetValue() == Settings::LayoutOption::MobilePortrait; + if (Settings::values.custom_layout.GetValue() == true && !is_portrait_mode) { + return CustomFrameLayout(std::max(Settings::values.custom_top_right.GetValue(), + Settings::values.custom_bottom_right.GetValue()), + std::max(Settings::values.custom_top_bottom.GetValue(), + Settings::values.custom_bottom_bottom.GetValue()), + Settings::values.swap_screen.GetValue(), is_portrait_mode); + } else if (Settings::values.custom_portrait_layout.GetValue() == true && is_portrait_mode) { + return CustomFrameLayout( + std::max(Settings::values.custom_portrait_top_right.GetValue(), + Settings::values.custom_portrait_bottom_right.GetValue()), + std::max(Settings::values.custom_portrait_top_bottom.GetValue(), + Settings::values.custom_portrait_bottom_bottom.GetValue()), + Settings::values.swap_screen.GetValue(), is_portrait_mode); } int width, height; diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h index f2ed553fd..37cbb564c 100644 --- a/src/core/frontend/framebuffer_layout.h +++ b/src/core/frontend/framebuffer_layout.h @@ -145,7 +145,8 @@ FramebufferLayout SeparateWindowsLayout(u32 width, u32 height, bool is_secondary * @param height Window framebuffer height in pixels * @return Newly created FramebufferLayout object with default screen regions initialized */ -FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped); +FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped, + bool is_portrait_mode = false); /** * Convenience method to get frame layout by resolution scale diff --git a/src/lime/config.cpp b/src/lime/config.cpp index e67b7ed9f..8532cf83c 100644 --- a/src/lime/config.cpp +++ b/src/lime/config.cpp @@ -183,6 +183,16 @@ void Config::ReadValues() { ReadSetting("Layout", Settings::values.screen_bottom_leftright_padding); ReadSetting("Layout", Settings::values.screen_bottom_topbottom_padding); + ReadSetting("Layout", Settings::values.custom_portrait_layout); + ReadSetting("Layout", Settings::values.custom_portrait_top_left); + ReadSetting("Layout", Settings::values.custom_portrait_top_top); + ReadSetting("Layout", Settings::values.custom_portrait_top_right); + ReadSetting("Layout", Settings::values.custom_portrait_top_bottom); + ReadSetting("Layout", Settings::values.custom_portrait_bottom_left); + ReadSetting("Layout", Settings::values.custom_portrait_bottom_top); + ReadSetting("Layout", Settings::values.custom_portrait_bottom_right); + ReadSetting("Layout", Settings::values.custom_portrait_bottom_bottom); + // Utility ReadSetting("Utility", Settings::values.dump_textures); ReadSetting("Utility", Settings::values.custom_textures); diff --git a/src/lime_qt/configuration/config.cpp b/src/lime_qt/configuration/config.cpp index 3919fe430..752fd6509 100644 --- a/src/lime_qt/configuration/config.cpp +++ b/src/lime_qt/configuration/config.cpp @@ -538,6 +538,15 @@ void Config::ReadLayoutValues() { ReadBasicSetting(Settings::values.screen_bottom_stretch); ReadBasicSetting(Settings::values.screen_bottom_leftright_padding); ReadBasicSetting(Settings::values.screen_bottom_topbottom_padding); + ReadBasicSetting(Settings::values.custom_portrait_layout); + ReadBasicSetting(Settings::values.custom_portrait_top_left); + ReadBasicSetting(Settings::values.custom_portrait_top_top); + ReadBasicSetting(Settings::values.custom_portrait_top_right); + ReadBasicSetting(Settings::values.custom_portrait_top_bottom); + ReadBasicSetting(Settings::values.custom_portrait_bottom_left); + ReadBasicSetting(Settings::values.custom_portrait_bottom_top); + ReadBasicSetting(Settings::values.custom_portrait_bottom_right); + ReadBasicSetting(Settings::values.custom_portrait_bottom_bottom); } qt_config->endGroup(); @@ -1090,6 +1099,15 @@ void Config::SaveLayoutValues() { WriteBasicSetting(Settings::values.screen_bottom_stretch); WriteBasicSetting(Settings::values.screen_bottom_leftright_padding); WriteBasicSetting(Settings::values.screen_bottom_topbottom_padding); + WriteBasicSetting(Settings::values.custom_portrait_layout); + WriteBasicSetting(Settings::values.custom_portrait_top_left); + WriteBasicSetting(Settings::values.custom_portrait_top_top); + WriteBasicSetting(Settings::values.custom_portrait_top_right); + WriteBasicSetting(Settings::values.custom_portrait_top_bottom); + WriteBasicSetting(Settings::values.custom_portrait_bottom_left); + WriteBasicSetting(Settings::values.custom_portrait_bottom_top); + WriteBasicSetting(Settings::values.custom_portrait_bottom_right); + WriteBasicSetting(Settings::values.custom_portrait_bottom_bottom); } qt_config->endGroup(); From c5ac6e84da27f54875fe012c53afa426ed3bd69c Mon Sep 17 00:00:00 2001 From: David Griswold Date: Sun, 11 Aug 2024 13:43:27 +0100 Subject: [PATCH 04/19] android: Updated custom layout coordinate system to match desktop --- src/android/app/src/main/jni/config.cpp | 18 +++---- src/android/app/src/main/jni/default_ini.h | 16 +++--- src/common/settings.h | 16 +++--- src/core/frontend/framebuffer_layout.cpp | 62 +++++++++++++--------- src/lime/config.cpp | 16 +++--- src/lime_qt/configuration/config.cpp | 32 +++++------ 6 files changed, 84 insertions(+), 76 deletions(-) diff --git a/src/android/app/src/main/jni/config.cpp b/src/android/app/src/main/jni/config.cpp index 17b0e1e9b..6abfbf2f1 100644 --- a/src/android/app/src/main/jni/config.cpp +++ b/src/android/app/src/main/jni/config.cpp @@ -188,17 +188,15 @@ void Config::ReadValues() { ReadSetting("Layout", Settings::values.cardboard_x_shift); ReadSetting("Layout", Settings::values.cardboard_y_shift); -#ifdef ANDROID ReadSetting("Layout", Settings::values.custom_portrait_layout); - ReadSetting("Layout", Settings::values.custom_portrait_top_left); - ReadSetting("Layout", Settings::values.custom_portrait_top_top); - ReadSetting("Layout", Settings::values.custom_portrait_top_right); - ReadSetting("Layout", Settings::values.custom_portrait_top_bottom); - ReadSetting("Layout", Settings::values.custom_portrait_bottom_left); - ReadSetting("Layout", Settings::values.custom_portrait_bottom_top); - ReadSetting("Layout", Settings::values.custom_portrait_bottom_right); - ReadSetting("Layout", Settings::values.custom_portrait_bottom_bottom); -#endif + ReadSetting("Layout", Settings::values.custom_portrait_top_x); + ReadSetting("Layout", Settings::values.custom_portrait_top_y); + ReadSetting("Layout", Settings::values.custom_portrait_top_width); + ReadSetting("Layout", Settings::values.custom_portrait_top_height); + ReadSetting("Layout", Settings::values.custom_portrait_bottom_x); + ReadSetting("Layout", Settings::values.custom_portrait_bottom_y); + ReadSetting("Layout", Settings::values.custom_portrait_bottom_width); + ReadSetting("Layout", Settings::values.custom_portrait_bottom_height); // Utility ReadSetting("Utility", Settings::values.dump_textures); diff --git a/src/android/app/src/main/jni/default_ini.h b/src/android/app/src/main/jni/default_ini.h index 856ad3eb4..02bc7f41b 100644 --- a/src/android/app/src/main/jni/default_ini.h +++ b/src/android/app/src/main/jni/default_ini.h @@ -206,14 +206,14 @@ custom_portrait_layout = # Screen placement when using Custom layout option # 0x, 0y is the top left corner of the render window. -custom_portrait_top_left = -custom_portrait_top_top = -custom_portrait_top_right = -custom_portrait_top_bottom = -custom_portrait_bottom_left = -custom_portrait_bottom_top = -custom_portrait_bottom_right = -custom_portrait_bottom_bottom = +custom_portrait_top_x = +custom_portrait_top_y = +custom_portrait_top_width = +custom_portrait_top_height = +custom_portrait_bottom_x = +custom_portrait_bottom_y = +custom_portrait_bottom_width = +custom_portrait_bottom_height = # Swaps the prominent screen with the other screen. # For example, if Single Screen is chosen, setting this to 1 will display the bottom screen instead of the top screen. diff --git a/src/common/settings.h b/src/common/settings.h index 38c70a2bc..3f294ae05 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -507,14 +507,14 @@ struct Values { Setting screen_bottom_topbottom_padding{0, "screen_bottom_topbottom_padding"}; Setting custom_portrait_layout{false, "custom_portrait_layout"}; - Setting custom_portrait_top_left{0, "custom_portrait_top_left"}; - Setting custom_portrait_top_top{0, "custom_portrait_top_top"}; - Setting custom_portrait_top_right{400, "custom_portrait_top_right"}; - Setting custom_portrait_top_bottom{240, "custom_portrait_top_bottom"}; - Setting custom_portrait_bottom_left{40, "custom_portrait_bottom_left"}; - Setting custom_portrait_bottom_top{240, "custom_portrait_bottom_top"}; - Setting custom_portrait_bottom_right{360, "custom_portrait_bottom_right"}; - Setting custom_portrait_bottom_bottom{480, "custom_portrait_bottom_bottom"}; + Setting custom_portrait_top_x{0, "custom_portrait_top_x"}; + Setting custom_portrait_top_y{0, "custom_portrait_top_y"}; + Setting custom_portrait_top_width{400, "custom_portrait_top_width"}; + Setting custom_portrait_top_height{240, "custom_portrait_top_height"}; + Setting custom_portrait_bottom_x{40, "custom_portrait_bottom_x"}; + Setting custom_portrait_bottom_y{240, "custom_portrait_bottom_y"}; + Setting custom_portrait_bottom_width{360, "custom_portrait_bottom_width"}; + Setting custom_portrait_bottom_height{480, "custom_portrait_bottom_height"}; SwitchableSetting bg_red{0.f, "bg_red"}; SwitchableSetting bg_green{0.f, "bg_green"}; diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index 44f82f012..c55444feb 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp @@ -387,25 +387,27 @@ FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped, bool ASSERT(height > 0); FramebufferLayout res{width, height, true, true, {}, {}, !Settings::values.upright_screen}; - u16 top_left = is_portrait_mode ? Settings::values.custom_portrait_top_left.GetValue() - : Settings::values.custom_top_left.GetValue(); - u16 top_right = is_portrait_mode ? Settings::values.custom_portrait_top_right.GetValue() - : Settings::values.custom_top_right.GetValue(); - u16 top_top = is_portrait_mode ? Settings::values.custom_portrait_top_top.GetValue() - : Settings::values.custom_top_top.GetValue(); - u16 top_bottom = is_portrait_mode ? Settings::values.custom_portrait_top_bottom.GetValue() - : Settings::values.custom_top_bottom.GetValue(); - u16 bottom_left = is_portrait_mode ? Settings::values.custom_portrait_bottom_left.GetValue() - : Settings::values.custom_bottom_left.GetValue(); - u16 bottom_right = is_portrait_mode ? Settings::values.custom_portrait_bottom_right.GetValue() - : Settings::values.custom_bottom_right.GetValue(); - u16 bottom_top = is_portrait_mode ? Settings::values.custom_portrait_bottom_top.GetValue() - : Settings::values.custom_bottom_top.GetValue(); - u16 bottom_bottom = is_portrait_mode ? Settings::values.custom_portrait_bottom_bottom.GetValue() - : Settings::values.custom_bottom_bottom.GetValue(); + u16 top_x = is_portrait_mode ? Settings::values.custom_portrait_top_x.GetValue() + : Settings::values.custom_top_x.GetValue(); + u16 top_width = is_portrait_mode ? Settings::values.custom_portrait_top_width.GetValue() + : Settings::values.custom_top_width.GetValue(); + u16 top_y = is_portrait_mode ? Settings::values.custom_portrait_top_y.GetValue() + : Settings::values.custom_top_y.GetValue(); + u16 top_height = is_portrait_mode ? Settings::values.custom_portrait_top_height.GetValue() + : Settings::values.custom_top_height.GetValue(); + u16 bottom_x = is_portrait_mode ? Settings::values.custom_portrait_bottom_x.GetValue() + : Settings::values.custom_bottom_x.GetValue(); + u16 bottom_width = is_portrait_mode ? Settings::values.custom_portrait_bottom_width.GetValue() + : Settings::values.custom_bottom_width.GetValue(); + u16 bottom_y = is_portrait_mode ? Settings::values.custom_portrait_bottom_y.GetValue() + : Settings::values.custom_bottom_y.GetValue(); + u16 bottom_height = is_portrait_mode ? Settings::values.custom_portrait_bottom_height.GetValue() + : Settings::values.custom_bottom_height.GetValue(); - Common::Rectangle top_screen{top_left, top_top, top_right, top_bottom}; - Common::Rectangle bot_screen{bottom_left, bottom_top, bottom_right, bottom_bottom}; + Common::Rectangle top_screen{top_x, top_y, (u32)(top_x + top_width), + (u32)(top_y + top_height)}; + Common::Rectangle bot_screen{bottom_x, bottom_y, (u32)(bottom_x + bottom_width), + (u32)(bottom_y + bottom_height)}; if (is_swapped) { res.top_screen = bot_screen; @@ -421,17 +423,25 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondar bool is_portrait_mode = Settings::values.layout_option.GetValue() == Settings::LayoutOption::MobilePortrait; if (Settings::values.custom_layout.GetValue() == true && !is_portrait_mode) { - return CustomFrameLayout(std::max(Settings::values.custom_top_right.GetValue(), - Settings::values.custom_bottom_right.GetValue()), - std::max(Settings::values.custom_top_bottom.GetValue(), - Settings::values.custom_bottom_bottom.GetValue()), + return CustomFrameLayout(std::max(Settings::values.custom_top_x.GetValue() + + Settings::values.custom_top_width.GetValue(), + Settings::values.custom_bottom_x.GetValue() + + Settings::values.custom_bottom_width.GetValue()), + std::max(Settings::values.custom_top_y.GetValue() + + Settings::values.custom_top_height.GetValue(), + Settings::values.custom_bottom_y.GetValue() + + Settings::values.custom_bottom_height.GetValue()), Settings::values.swap_screen.GetValue(), is_portrait_mode); } else if (Settings::values.custom_portrait_layout.GetValue() == true && is_portrait_mode) { return CustomFrameLayout( - std::max(Settings::values.custom_portrait_top_right.GetValue(), - Settings::values.custom_portrait_bottom_right.GetValue()), - std::max(Settings::values.custom_portrait_top_bottom.GetValue(), - Settings::values.custom_portrait_bottom_bottom.GetValue()), + std::max(Settings::values.custom_portrait_top_x.GetValue() + + Settings::values.custom_portrait_top_width.GetValue(), + Settings::values.custom_portrait_bottom_x.GetValue() + + Settings::values.custom_portrait_bottom_width.GetValue()), + std::max(Settings::values.custom_portrait_top_y.GetValue() + + Settings::values.custom_portrait_top_height.GetValue(), + Settings::values.custom_portrait_bottom_y.GetValue() + + Settings::values.custom_portrait_bottom_height.GetValue()), Settings::values.swap_screen.GetValue(), is_portrait_mode); } diff --git a/src/lime/config.cpp b/src/lime/config.cpp index 8532cf83c..e18de2ad2 100644 --- a/src/lime/config.cpp +++ b/src/lime/config.cpp @@ -184,14 +184,14 @@ void Config::ReadValues() { ReadSetting("Layout", Settings::values.screen_bottom_topbottom_padding); ReadSetting("Layout", Settings::values.custom_portrait_layout); - ReadSetting("Layout", Settings::values.custom_portrait_top_left); - ReadSetting("Layout", Settings::values.custom_portrait_top_top); - ReadSetting("Layout", Settings::values.custom_portrait_top_right); - ReadSetting("Layout", Settings::values.custom_portrait_top_bottom); - ReadSetting("Layout", Settings::values.custom_portrait_bottom_left); - ReadSetting("Layout", Settings::values.custom_portrait_bottom_top); - ReadSetting("Layout", Settings::values.custom_portrait_bottom_right); - ReadSetting("Layout", Settings::values.custom_portrait_bottom_bottom); + ReadSetting("Layout", Settings::values.custom_portrait_top_x); + ReadSetting("Layout", Settings::values.custom_portrait_top_y); + ReadSetting("Layout", Settings::values.custom_portrait_top_width); + ReadSetting("Layout", Settings::values.custom_portrait_top_height); + ReadSetting("Layout", Settings::values.custom_portrait_bottom_x); + ReadSetting("Layout", Settings::values.custom_portrait_bottom_y); + ReadSetting("Layout", Settings::values.custom_portrait_bottom_width); + ReadSetting("Layout", Settings::values.custom_portrait_bottom_height); // Utility ReadSetting("Utility", Settings::values.dump_textures); diff --git a/src/lime_qt/configuration/config.cpp b/src/lime_qt/configuration/config.cpp index 752fd6509..b26507fb2 100644 --- a/src/lime_qt/configuration/config.cpp +++ b/src/lime_qt/configuration/config.cpp @@ -539,14 +539,14 @@ void Config::ReadLayoutValues() { ReadBasicSetting(Settings::values.screen_bottom_leftright_padding); ReadBasicSetting(Settings::values.screen_bottom_topbottom_padding); ReadBasicSetting(Settings::values.custom_portrait_layout); - ReadBasicSetting(Settings::values.custom_portrait_top_left); - ReadBasicSetting(Settings::values.custom_portrait_top_top); - ReadBasicSetting(Settings::values.custom_portrait_top_right); - ReadBasicSetting(Settings::values.custom_portrait_top_bottom); - ReadBasicSetting(Settings::values.custom_portrait_bottom_left); - ReadBasicSetting(Settings::values.custom_portrait_bottom_top); - ReadBasicSetting(Settings::values.custom_portrait_bottom_right); - ReadBasicSetting(Settings::values.custom_portrait_bottom_bottom); + ReadBasicSetting(Settings::values.custom_portrait_top_x); + ReadBasicSetting(Settings::values.custom_portrait_top_y); + ReadBasicSetting(Settings::values.custom_portrait_top_width); + ReadBasicSetting(Settings::values.custom_portrait_top_height); + ReadBasicSetting(Settings::values.custom_portrait_bottom_x); + ReadBasicSetting(Settings::values.custom_portrait_bottom_y); + ReadBasicSetting(Settings::values.custom_portrait_bottom_width); + ReadBasicSetting(Settings::values.custom_portrait_bottom_height); } qt_config->endGroup(); @@ -1100,14 +1100,14 @@ void Config::SaveLayoutValues() { WriteBasicSetting(Settings::values.screen_bottom_leftright_padding); WriteBasicSetting(Settings::values.screen_bottom_topbottom_padding); WriteBasicSetting(Settings::values.custom_portrait_layout); - WriteBasicSetting(Settings::values.custom_portrait_top_left); - WriteBasicSetting(Settings::values.custom_portrait_top_top); - WriteBasicSetting(Settings::values.custom_portrait_top_right); - WriteBasicSetting(Settings::values.custom_portrait_top_bottom); - WriteBasicSetting(Settings::values.custom_portrait_bottom_left); - WriteBasicSetting(Settings::values.custom_portrait_bottom_top); - WriteBasicSetting(Settings::values.custom_portrait_bottom_right); - WriteBasicSetting(Settings::values.custom_portrait_bottom_bottom); + WriteBasicSetting(Settings::values.custom_portrait_top_x); + WriteBasicSetting(Settings::values.custom_portrait_top_y); + WriteBasicSetting(Settings::values.custom_portrait_top_width); + WriteBasicSetting(Settings::values.custom_portrait_top_height); + WriteBasicSetting(Settings::values.custom_portrait_bottom_x); + WriteBasicSetting(Settings::values.custom_portrait_bottom_y); + WriteBasicSetting(Settings::values.custom_portrait_bottom_width); + WriteBasicSetting(Settings::values.custom_portrait_bottom_height); } qt_config->endGroup(); From 7e5b83f126dd45878b4d7bb9e737e40d236d5570 Mon Sep 17 00:00:00 2001 From: David Griswold Date: Sun, 11 Aug 2024 15:59:41 +0100 Subject: [PATCH 05/19] Refactored layout code in preparation for Android custom layout GUI --- .../github/lime3ds/android/NativeLibrary.kt | 7 +- .../android/display/PortraitScreenLayout.kt | 17 ++ .../android/display/ScreenAdjustmentUtil.kt | 39 ++- .../lime3ds/android/display/ScreenLayout.kt | 7 +- .../features/settings/model/BooleanSetting.kt | 1 + .../features/settings/model/IntSetting.kt | 1 + .../features/settings/model/Settings.kt | 1 - .../android/fragments/EmulationFragment.kt | 104 +++++-- .../android/utils/EmulationMenuSettings.kt | 13 +- src/android/app/src/main/jni/config.cpp | 7 +- src/android/app/src/main/jni/default_ini.h | 24 +- .../src/main/jni/emu_window/emu_window.cpp | 7 + src/android/app/src/main/jni/id_cache.cpp | 7 + src/android/app/src/main/jni/id_cache.h | 1 + src/android/app/src/main/jni/native.cpp | 16 +- .../app/src/main/res/menu/menu_emulation.xml | 2 +- .../app/src/main/res/menu/menu_in_game.xml | 5 + .../res/menu/menu_landscape_screen_layout.xml | 7 +- .../res/menu/menu_portrait_screen_layout.xml | 15 + .../app/src/main/res/values/strings.xml | 5 +- src/common/settings.cpp | 2 + src/common/settings.h | 41 +-- src/core/frontend/emu_window.cpp | 51 ++-- src/core/frontend/framebuffer_layout.cpp | 266 ++++++++++-------- src/core/frontend/framebuffer_layout.h | 11 +- src/lime/config.cpp | 2 +- src/lime_qt/configuration/config.cpp | 3 +- .../renderer_opengl/renderer_opengl.cpp | 32 ++- .../renderer_opengl/renderer_opengl.h | 4 +- 29 files changed, 453 insertions(+), 245 deletions(-) create mode 100644 src/android/app/src/main/java/io/github/lime3ds/android/display/PortraitScreenLayout.kt create mode 100644 src/android/app/src/main/res/menu/menu_portrait_screen_layout.xml diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/NativeLibrary.kt b/src/android/app/src/main/java/io/github/lime3ds/android/NativeLibrary.kt index 7d91c09fd..1959eaba9 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/NativeLibrary.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/NativeLibrary.kt @@ -158,8 +158,9 @@ object NativeLibrary { /** * Notifies the core emulation that the orientation has changed. */ - external fun notifyOrientationChange(layoutOption: Int, rotation: Int) + external fun notifyOrientationChange(layoutOption: Int, rotation: Int, isPortrait: Boolean) + external fun notifyPortraitLayoutChange(layoutOption: Int, rotation: Int, isPortrait: Boolean) /** * Swaps the top and bottom screens. */ @@ -266,6 +267,10 @@ object NativeLibrary { @JvmStatic fun landscapeScreenLayout(): Int = EmulationMenuSettings.landscapeScreenLayout + @Keep + @JvmStatic + fun portraitScreenLayout(): Int = EmulationMenuSettings.portraitScreenLayout + @Keep @JvmStatic fun displayAlertMsg(title: String, message: String, yesNo: Boolean): Boolean { diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/display/PortraitScreenLayout.kt b/src/android/app/src/main/java/io/github/lime3ds/android/display/PortraitScreenLayout.kt new file mode 100644 index 000000000..74d9c1820 --- /dev/null +++ b/src/android/app/src/main/java/io/github/lime3ds/android/display/PortraitScreenLayout.kt @@ -0,0 +1,17 @@ +// Copyright 2023 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +package io.github.lime3ds.android.display + +enum class PortraitScreenLayout(val int: Int) { + // These must match what is defined in src/common/settings.h + TOP_FULL_WIDTH(0), + CUSTOM_PORTRAIT_LAYOUT(1); + + companion object { + fun from(int: Int): PortraitScreenLayout { + return entries.firstOrNull { it.int == int } ?: TOP_FULL_WIDTH; + } + } +} diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenAdjustmentUtil.kt b/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenAdjustmentUtil.kt index cd0310047..8d4734e29 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenAdjustmentUtil.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenAdjustmentUtil.kt @@ -12,8 +12,10 @@ import io.github.lime3ds.android.features.settings.model.Settings import io.github.lime3ds.android.features.settings.utils.SettingsFile import io.github.lime3ds.android.utils.EmulationMenuSettings -class ScreenAdjustmentUtil(private val windowManager: WindowManager, - private val settings: Settings) { +class ScreenAdjustmentUtil( + private val windowManager: WindowManager, + private val settings: Settings +) { fun swapScreen() { val isEnabled = !EmulationMenuSettings.swapScreens EmulationMenuSettings.swapScreens = isEnabled @@ -25,18 +27,39 @@ class ScreenAdjustmentUtil(private val windowManager: WindowManager, settings.saveSetting(BooleanSetting.SWAP_SCREEN, SettingsFile.FILE_NAME_CONFIG) } + // TODO: Consider how cycling should handle custom layout + // right now it simply skips it fun cycleLayouts() { - val nextLayout = (EmulationMenuSettings.landscapeScreenLayout + 1) % ScreenLayout.entries.size - changeScreenOrientation(ScreenLayout.from(nextLayout)) + val nextLayout = if (NativeLibrary.isPortraitMode) { + (EmulationMenuSettings.portraitScreenLayout + 1) % (PortraitScreenLayout.entries.size - 1) + } else { + (EmulationMenuSettings.landscapeScreenLayout + 1) % (ScreenLayout.entries.size - 1) + } + settings.loadSettings() + + changeScreenOrientation(nextLayout) } - fun changeScreenOrientation(layoutOption: ScreenLayout) { - EmulationMenuSettings.landscapeScreenLayout = layoutOption.int + fun changePortraitOrientation(layoutOption: Int) { + EmulationMenuSettings.portraitScreenLayout = layoutOption + NativeLibrary.notifyPortraitLayoutChange( + EmulationMenuSettings.portraitScreenLayout, + windowManager.defaultDisplay.rotation, + NativeLibrary::isPortraitMode.get() + ) + IntSetting.PORTRAIT_SCREEN_LAYOUT.int = layoutOption + settings.saveSetting(IntSetting.PORTRAIT_SCREEN_LAYOUT, SettingsFile.FILE_NAME_CONFIG) + } + + fun changeScreenOrientation(layoutOption: Int) { + EmulationMenuSettings.landscapeScreenLayout = layoutOption NativeLibrary.notifyOrientationChange( EmulationMenuSettings.landscapeScreenLayout, - windowManager.defaultDisplay.rotation + windowManager.defaultDisplay.rotation, + NativeLibrary::isPortraitMode.get() ) - IntSetting.SCREEN_LAYOUT.int = layoutOption.int + IntSetting.SCREEN_LAYOUT.int = layoutOption settings.saveSetting(IntSetting.SCREEN_LAYOUT, SettingsFile.FILE_NAME_CONFIG) + } } diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenLayout.kt b/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenLayout.kt index 1c6635a78..a6fc57e10 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenLayout.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenLayout.kt @@ -6,17 +6,18 @@ package io.github.lime3ds.android.display enum class ScreenLayout(val int: Int) { // These must match what is defined in src/common/settings.h - DEFAULT(0), + TOP_BOTTOM(0), SINGLE_SCREEN(1), LARGE_SCREEN(2), SIDE_SCREEN(3), HYBRID_SCREEN(4), - MOBILE_PORTRAIT(5), + CUSTOM_LAYOUT(5), MOBILE_LANDSCAPE(6); + companion object { fun from(int: Int): ScreenLayout { - return entries.firstOrNull { it.int == int } ?: DEFAULT + return entries.firstOrNull { it.int == int } ?: MOBILE_LANDSCAPE } } } diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/BooleanSetting.kt index ecdd19267..d4e15543a 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/BooleanSetting.kt @@ -14,6 +14,7 @@ enum class BooleanSetting( PLUGIN_LOADER("plugin_loader", Settings.SECTION_SYSTEM, false), ALLOW_PLUGIN_LOADER("allow_plugin_loader", Settings.SECTION_SYSTEM, true), SWAP_SCREEN("swap_screen", Settings.SECTION_LAYOUT, false), + CUSTOM_LAYOUT("custom_layout",Settings.SECTION_LAYOUT,false), ADRENO_GPU_BOOST("adreno_gpu_boost", Settings.SECTION_RENDERER, false); override var boolean: Boolean = defaultValue diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/IntSetting.kt index 34b5dc128..4e240c3a5 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/IntSetting.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/IntSetting.kt @@ -23,6 +23,7 @@ enum class IntSetting( CARDBOARD_X_SHIFT("cardboard_x_shift", Settings.SECTION_LAYOUT, 0), CARDBOARD_Y_SHIFT("cardboard_y_shift", Settings.SECTION_LAYOUT, 0), SCREEN_LAYOUT("layout_option", Settings.SECTION_LAYOUT, 0), + PORTRAIT_SCREEN_LAYOUT("portrait_layout_option",Settings.SECTION_LAYOUT,0), AUDIO_INPUT_TYPE("output_type", Settings.SECTION_AUDIO, 0), NEW_3DS("is_new_3ds", Settings.SECTION_SYSTEM, 1), LLE_APPLETS("lle_applets", Settings.SECTION_SYSTEM, 0), diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/Settings.kt b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/Settings.kt index eead17ecf..d13d324d7 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/Settings.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/Settings.kt @@ -131,7 +131,6 @@ class Settings { const val KEY_CSTICK_AXIS_HORIZONTAL = "cstick_axis_horizontal" const val KEY_DPAD_AXIS_VERTICAL = "dpad_axis_vertical" const val KEY_DPAD_AXIS_HORIZONTAL = "dpad_axis_horizontal" - const val HOTKEY_SCREEN_SWAP = "hotkey_screen_swap" const val HOTKEY_CYCLE_LAYOUT = "hotkey_toggle_layout" const val HOTKEY_CLOSE_GAME = "hotkey_close_game" diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/fragments/EmulationFragment.kt b/src/android/app/src/main/java/io/github/lime3ds/android/fragments/EmulationFragment.kt index de4ffb944..455ce3e89 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/fragments/EmulationFragment.kt @@ -51,6 +51,7 @@ import io.github.lime3ds.android.activities.EmulationActivity import io.github.lime3ds.android.databinding.DialogCheckboxBinding import io.github.lime3ds.android.databinding.DialogSliderBinding import io.github.lime3ds.android.databinding.FragmentEmulationBinding +import io.github.lime3ds.android.display.PortraitScreenLayout import io.github.lime3ds.android.display.ScreenAdjustmentUtil import io.github.lime3ds.android.display.ScreenLayout import io.github.lime3ds.android.features.settings.model.SettingsViewModel @@ -142,7 +143,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram retainInstance = true emulationState = EmulationState(game.path) emulationActivity = requireActivity() as EmulationActivity - screenAdjustmentUtil = ScreenAdjustmentUtil(emulationActivity.windowManager, settingsViewModel.settings) + screenAdjustmentUtil = + ScreenAdjustmentUtil(emulationActivity.windowManager, settingsViewModel.settings) EmulationLifecycleUtil.addShutdownHook(hook = { emulationState.stop() }) EmulationLifecycleUtil.addPauseResumeHook(hook = { togglePause() }) } @@ -207,16 +209,18 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram } }) binding.inGameMenu.menu.findItem(R.id.menu_lock_drawer).apply { - val titleId = if (EmulationMenuSettings.drawerLockMode == DrawerLayout.LOCK_MODE_LOCKED_CLOSED) { - R.string.unlock_drawer - } else { - R.string.lock_drawer - } - val iconId = if (EmulationMenuSettings.drawerLockMode == DrawerLayout.LOCK_MODE_UNLOCKED) { - R.drawable.ic_unlocked - } else { - R.drawable.ic_lock - } + val titleId = + if (EmulationMenuSettings.drawerLockMode == DrawerLayout.LOCK_MODE_LOCKED_CLOSED) { + R.string.unlock_drawer + } else { + R.string.lock_drawer + } + val iconId = + if (EmulationMenuSettings.drawerLockMode == DrawerLayout.LOCK_MODE_UNLOCKED) { + R.drawable.ic_unlocked + } else { + R.drawable.ic_lock + } title = getString(titleId) icon = ResourcesCompat.getDrawable( @@ -267,7 +271,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram } R.id.menu_landscape_screen_layout -> { - showScreenLayoutMenu() + showLandscapeScreenLayoutMenu() + true + } + + R.id.menu_portrait_screen_layout -> { + showPortraitScreenLayoutMenu() true } @@ -423,7 +432,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram } private fun togglePause() { - if(emulationState.isPaused) { + if (emulationState.isPaused) { emulationState.unpause() } else { emulationState.pause() @@ -769,7 +778,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram popupMenu.show() } - private fun showScreenLayoutMenu() { + private fun showLandscapeScreenLayoutMenu() { val popupMenu = PopupMenu( requireContext(), binding.inGameMenu.findViewById(R.id.menu_landscape_screen_layout) @@ -784,12 +793,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram ScreenLayout.SIDE_SCREEN.int -> R.id.menu_screen_layout_sidebyside - ScreenLayout.MOBILE_PORTRAIT.int -> - R.id.menu_screen_layout_portrait - ScreenLayout.HYBRID_SCREEN.int -> R.id.menu_screen_layout_hybrid + ScreenLayout.CUSTOM_LAYOUT.int -> + R.id.menu_screen_layout_custom + else -> R.id.menu_screen_layout_landscape } popupMenu.menu.findItem(layoutOptionMenuItem).setChecked(true) @@ -797,27 +806,68 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram popupMenu.setOnMenuItemClickListener { when (it.itemId) { R.id.menu_screen_layout_landscape -> { - screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.MOBILE_LANDSCAPE) - true - } - - R.id.menu_screen_layout_portrait -> { - screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.MOBILE_PORTRAIT) + screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.MOBILE_LANDSCAPE.int) true } R.id.menu_screen_layout_single -> { - screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.SINGLE_SCREEN) + screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.SINGLE_SCREEN.int) true } R.id.menu_screen_layout_sidebyside -> { - screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.SIDE_SCREEN) + screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.SIDE_SCREEN.int) true } R.id.menu_screen_layout_hybrid -> { - screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.HYBRID_SCREEN) + screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.HYBRID_SCREEN.int) + true + } + + R.id.menu_screen_layout_custom -> { + screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.CUSTOM_LAYOUT.int) + true + } + + else -> true + } + } + + popupMenu.show() + } + + private fun showPortraitScreenLayoutMenu() { + val popupMenu = PopupMenu( + requireContext(), + binding.inGameMenu.findViewById(R.id.menu_portrait_screen_layout) + ) + + popupMenu.menuInflater.inflate(R.menu.menu_portrait_screen_layout, popupMenu.menu) + + val layoutOptionMenuItem = when (EmulationMenuSettings.portraitScreenLayout) { + PortraitScreenLayout.TOP_FULL_WIDTH.int -> + R.id.menu_portrait_layout_top_full + + PortraitScreenLayout.CUSTOM_PORTRAIT_LAYOUT.int -> + R.id.menu_portrait_layout_custom + + else -> + R.id.menu_portrait_layout_top_full + + } + + popupMenu.menu.findItem(layoutOptionMenuItem).setChecked(true) + + popupMenu.setOnMenuItemClickListener { + when (it.itemId) { + R.id.menu_portrait_layout_top_full -> { + screenAdjustmentUtil.changePortraitOrientation(PortraitScreenLayout.TOP_FULL_WIDTH.int) + true + } + + R.id.menu_portrait_layout_custom -> { + screenAdjustmentUtil.changePortraitOrientation(PortraitScreenLayout.CUSTOM_PORTRAIT_LAYOUT.int) true } @@ -959,7 +1009,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram resetScale("controlScale-" + NativeLibrary.ButtonType.BUTTON_SWAP) binding.surfaceInputOverlay.refreshControls() } - + private fun setControlOpacity(opacity: Int) { preferences.edit() .putInt("controlOpacity", opacity) diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/utils/EmulationMenuSettings.kt b/src/android/app/src/main/java/io/github/lime3ds/android/utils/EmulationMenuSettings.kt index 904caec41..eead8dc9e 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/utils/EmulationMenuSettings.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/utils/EmulationMenuSettings.kt @@ -7,6 +7,7 @@ package io.github.lime3ds.android.utils import androidx.drawerlayout.widget.DrawerLayout import androidx.preference.PreferenceManager import io.github.lime3ds.android.LimeApplication +import io.github.lime3ds.android.display.PortraitScreenLayout import io.github.lime3ds.android.display.ScreenLayout object EmulationMenuSettings { @@ -30,13 +31,23 @@ object EmulationMenuSettings { var landscapeScreenLayout: Int get() = preferences.getInt( "EmulationMenuSettings_LandscapeScreenLayout", - ScreenLayout.MOBILE_LANDSCAPE.int + ScreenLayout.LARGE_SCREEN.int ) set(value) { preferences.edit() .putInt("EmulationMenuSettings_LandscapeScreenLayout", value) .apply() } + var portraitScreenLayout: Int + get() = preferences.getInt( + "EmulationMenuSettings_PortraitScreenLayout", + PortraitScreenLayout.TOP_FULL_WIDTH.int + ) + set(value) { + preferences.edit() + .putInt("EmulationMenuSettings_PortraitScreenLayout", value) + .apply() + } var showFps: Boolean get() = preferences.getBoolean("EmulationMenuSettings_ShowFps", false) set(value) { diff --git a/src/android/app/src/main/jni/config.cpp b/src/android/app/src/main/jni/config.cpp index 6abfbf2f1..ff016a8e5 100644 --- a/src/android/app/src/main/jni/config.cpp +++ b/src/android/app/src/main/jni/config.cpp @@ -174,7 +174,7 @@ void Config::ReadValues() { // Layout Settings::values.layout_option = static_cast(sdl2_config->GetInteger( - "Layout", "layout_option", static_cast(Settings::LayoutOption::MobileLandscape))); + "Layout", "layout_option", static_cast(Settings::LayoutOption::LargeScreen))); ReadSetting("Layout", Settings::values.custom_layout); ReadSetting("Layout", Settings::values.custom_top_x); ReadSetting("Layout", Settings::values.custom_top_y); @@ -188,7 +188,10 @@ void Config::ReadValues() { ReadSetting("Layout", Settings::values.cardboard_x_shift); ReadSetting("Layout", Settings::values.cardboard_y_shift); - ReadSetting("Layout", Settings::values.custom_portrait_layout); + Settings::values.portrait_layout_option = + static_cast(sdl2_config->GetInteger( + "Layout", "portrait_layout_option", + static_cast(Settings::PortraitLayoutOption::PortraitTopFullWidth))); ReadSetting("Layout", Settings::values.custom_portrait_top_x); ReadSetting("Layout", Settings::values.custom_portrait_top_y); ReadSetting("Layout", Settings::values.custom_portrait_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 02bc7f41b..e7e67e646 100644 --- a/src/android/app/src/main/jni/default_ini.h +++ b/src/android/app/src/main/jni/default_ini.h @@ -179,15 +179,15 @@ anaglyph_shader_name = filter_mode = [Layout] -# Layout for the screen inside the render window. -# 0 (default): Default Top Bottom Screen, 1: Single Screen Only, 2: Large Screen Small Screen, 3: Side by Side +# Layout for the screen inside the render window, landscape mode +# 0 (default): Default Top Bottom Screen, +# 1: Single Screen Only, +# 2: Large Screen Small Screen +# 3: Side by Side +# 4: Hybrid +# 5: Custom Layout layout_option = -# Toggle custom layout (using the settings below) on or off. -# Only applies to landscape on Android -# 0 (default): Off, 1: On -custom_layout = - # Screen placement when using Custom layout option # 0x, 0y is the top left corner of the render window. custom_top_x = @@ -199,12 +199,12 @@ custom_bottom_y = custom_bottom_width = custom_bottom_height = -# Custom Layout Options for Android Portrait Mode -# Toggle custom layout (using the settings below) on or off. -# 0 (default): Off, 1: On -custom_portrait_layout = +# Layout for the portrait mode +# 0 (default): Top and bottom screens at top, full width +# 1: Custom Layout +portrait_layout_option = -# Screen placement when using Custom layout option +# Screen placement when using Portrait Custom layout option # 0x, 0y is the top left corner of the render window. custom_portrait_top_x = custom_portrait_top_y = diff --git a/src/android/app/src/main/jni/emu_window/emu_window.cpp b/src/android/app/src/main/jni/emu_window/emu_window.cpp index e847cdb2b..c589ce54c 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.cpp +++ b/src/android/app/src/main/jni/emu_window/emu_window.cpp @@ -27,6 +27,12 @@ static void UpdateLandscapeScreenLayout() { IDCache::GetNativeLibraryClass(), IDCache::GetLandscapeScreenLayout())); } +static void UpdatePortraitScreenLayout() { + Settings::values.portrait_layout_option = + static_cast(IDCache::GetEnvForThread()->CallStaticIntMethod( + IDCache::GetNativeLibraryClass(), IDCache::GetPortraitScreenLayout())); +} + bool EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { if (render_window == surface) { return false; @@ -58,6 +64,7 @@ void EmuWindow_Android::OnTouchMoved(int x, int y) { void EmuWindow_Android::OnFramebufferSizeChanged() { UpdateLandscapeScreenLayout(); + UpdatePortraitScreenLayout(); const bool is_portrait_mode{IsPortraitMode()}; const int bigger{window_width > window_height ? window_width : window_height}; diff --git a/src/android/app/src/main/jni/id_cache.cpp b/src/android/app/src/main/jni/id_cache.cpp index 1b36bfd32..b3bf27f96 100644 --- a/src/android/app/src/main/jni/id_cache.cpp +++ b/src/android/app/src/main/jni/id_cache.cpp @@ -27,6 +27,7 @@ static jclass s_native_library_class; static jmethodID s_on_core_error; static jmethodID s_is_portrait_mode; static jmethodID s_landscape_screen_layout; +static jmethodID s_portrait_screen_layout; static jmethodID s_exit_emulation_activity; static jmethodID s_request_camera_permission; static jmethodID s_request_mic_permission; @@ -90,6 +91,10 @@ jmethodID GetLandscapeScreenLayout() { return s_landscape_screen_layout; } +jmethodID GetPortraitScreenLayout() { + return s_portrait_screen_layout; +} + jmethodID GetExitEmulationActivity() { return s_exit_emulation_activity; } @@ -174,6 +179,8 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) { s_is_portrait_mode = env->GetStaticMethodID(s_native_library_class, "isPortraitMode", "()Z"); s_landscape_screen_layout = env->GetStaticMethodID(s_native_library_class, "landscapeScreenLayout", "()I"); + s_portrait_screen_layout = + env->GetStaticMethodID(s_native_library_class, "portraitScreenLayout", "()I"); s_exit_emulation_activity = env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V"); s_request_camera_permission = diff --git a/src/android/app/src/main/jni/id_cache.h b/src/android/app/src/main/jni/id_cache.h index 7c08a1c0b..71a1cb67c 100644 --- a/src/android/app/src/main/jni/id_cache.h +++ b/src/android/app/src/main/jni/id_cache.h @@ -27,6 +27,7 @@ jmethodID GetDisplayAlertPrompt(); jmethodID GetAlertPromptButton(); jmethodID GetIsPortraitMode(); jmethodID GetLandscapeScreenLayout(); +jmethodID GetPortraitScreenLayout(); jmethodID GetExitEmulationActivity(); jmethodID GetRequestCameraPermission(); jmethodID GetRequestMicPermission(); diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 471be3d7c..ff1636730 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -347,9 +347,23 @@ void JNICALL Java_io_github_lime3ds_android_NativeLibrary_enableAdrenoTurboMode( } void Java_io_github_lime3ds_android_NativeLibrary_notifyOrientationChange( - [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj, jint layout_option, jint rotation) { + [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj, jint layout_option, jint rotation, + jboolean portrait) { Settings::values.layout_option = static_cast(layout_option); auto& system = Core::System::GetInstance(); + if (system.IsPoweredOn()) { + + system.GPU().Renderer().UpdateCurrentFramebufferLayout(portrait); + } + InputManager::screen_rotation = rotation; + Camera::NDK::g_rotation = rotation; +} + +void Java_io_github_lime3ds_android_NativeLibrary_notifyPortraitLayoutChange( + [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj, jint layout_option, jint rotation) { + Settings::values.portrait_layout_option = + static_cast(layout_option); + auto& system = Core::System::GetInstance(); if (system.IsPoweredOn()) { system.GPU().Renderer().UpdateCurrentFramebufferLayout(!(rotation % 2)); } diff --git a/src/android/app/src/main/res/menu/menu_emulation.xml b/src/android/app/src/main/res/menu/menu_emulation.xml index a0dec63be..d09f99d93 100644 --- a/src/android/app/src/main/res/menu/menu_emulation.xml +++ b/src/android/app/src/main/res/menu/menu_emulation.xml @@ -69,7 +69,7 @@ + + - - @@ -23,6 +19,9 @@ android:id="@+id/menu_screen_layout_hybrid" android:title="@string/emulation_screen_layout_hybrid" /> + diff --git a/src/android/app/src/main/res/menu/menu_portrait_screen_layout.xml b/src/android/app/src/main/res/menu/menu_portrait_screen_layout.xml new file mode 100644 index 000000000..33bb729a6 --- /dev/null +++ b/src/android/app/src/main/res/menu/menu_portrait_screen_layout.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 72d63373e..744683d30 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -359,12 +359,15 @@ Open Settings Open Cheats Landscape Screen Layout + Portrait Screen Layout Default Portrait Single Screen Side by Side Screens Hybrid Screens - Cycle Landscape Layouts + Default + Custom Layout + Cycle Layouts Swap Screens Reset Overlay Show Overlay diff --git a/src/common/settings.cpp b/src/common/settings.cpp index dbf85e710..e53644328 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -108,6 +108,7 @@ void LogSettings() { log_setting("Renderer_AnaglyphShader", values.anaglyph_shader_name.GetValue()); } log_setting("Layout_LayoutOption", values.layout_option.GetValue()); + 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_LargeScreenProportion", values.large_screen_proportion.GetValue()); @@ -196,6 +197,7 @@ void RestoreGlobalState(bool is_powered_on) { values.texture_filter.SetGlobal(true); values.texture_sampling.SetGlobal(true); values.layout_option.SetGlobal(true); + values.portrait_layout_option.SetGlobal(true); values.swap_screen.SetGlobal(true); values.upright_screen.SetGlobal(true); values.large_screen_proportion.SetGlobal(true); diff --git a/src/common/settings.h b/src/common/settings.h index 3f294ae05..4d91f81b4 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -33,6 +33,7 @@ enum class InitTicks : u32 { Fixed = 1, }; +/** Defines the layout option for desktop and mobile landscape */ enum class LayoutOption : u32 { Default, SingleScreen, @@ -42,18 +43,20 @@ enum class LayoutOption : u32 { SeparateWindows, #endif HybridScreen, -#ifndef ANDROID // TODO: Implement custom layouts on Android CustomLayout, -#endif - // Similiar to default, but better for mobile devices in portrait mode. Top screen in clamped to - // the top of the frame, and the bottom screen is enlarged to match the top screen. - MobilePortrait, // Similiar to LargeScreen, but better for mobile devices in landscape mode. The screens are // clamped to the top of the frame, and the bottom screen is a bit bigger. MobileLandscape, }; +/** Defines the layout option for mobile portrait */ +enum class PortraitLayoutOption : u32 { + // formerly mobile portrait + PortraitTopFullWidth, + PortraitCustomLayout, +}; + enum class StereoRenderOption : u32 { Off = 0, SideBySide = 1, @@ -482,21 +485,22 @@ struct Values { SwitchableSetting texture_filter{TextureFilter::None, "texture_filter"}; SwitchableSetting texture_sampling{TextureSampling::GameControlled, "texture_sampling"}; - SwitchableSetting layout_option{LayoutOption::Default, "layout_option"}; SwitchableSetting swap_screen{false, "swap_screen"}; SwitchableSetting upright_screen{false, "upright_screen"}; SwitchableSetting large_screen_proportion{4.f, 1.f, 16.f, "large_screen_proportion"}; + // I think the custom_layout setting below is no longer needed + // since custom layout is now just part of the layout option above? Setting custom_layout{false, "custom_layout"}; Setting custom_top_x{0, "custom_top_x"}; Setting custom_top_y{0, "custom_top_y"}; - Setting custom_top_width{400, "custom_top_width"}; - Setting custom_top_height{240, "custom_top_height"}; - Setting custom_bottom_x{40, "custom_bottom_x"}; - Setting custom_bottom_y{240, "custom_bottom_y"}; - Setting custom_bottom_width{320, "custom_bottom_width"}; - Setting custom_bottom_height{240, "custom_bottom_height"}; + Setting custom_top_width{800, "custom_top_width"}; + Setting custom_top_height{480, "custom_top_height"}; + Setting custom_bottom_x{80, "custom_bottom_x"}; + Setting custom_bottom_y{500, "custom_bottom_y"}; + Setting custom_bottom_width{640, "custom_bottom_width"}; + Setting custom_bottom_height{480, "custom_bottom_height"}; Setting custom_second_layer_opacity{100, "custom_second_layer_opacity"}; SwitchableSetting screen_top_stretch{false, "screen_top_stretch"}; @@ -506,14 +510,15 @@ struct Values { Setting screen_bottom_leftright_padding{0, "screen_bottom_leftright_padding"}; Setting screen_bottom_topbottom_padding{0, "screen_bottom_topbottom_padding"}; - Setting custom_portrait_layout{false, "custom_portrait_layout"}; + SwitchableSetting portrait_layout_option{ + PortraitLayoutOption::PortraitTopFullWidth, "portrait_layout_option"}; Setting custom_portrait_top_x{0, "custom_portrait_top_x"}; Setting custom_portrait_top_y{0, "custom_portrait_top_y"}; - Setting custom_portrait_top_width{400, "custom_portrait_top_width"}; - Setting custom_portrait_top_height{240, "custom_portrait_top_height"}; - Setting custom_portrait_bottom_x{40, "custom_portrait_bottom_x"}; - Setting custom_portrait_bottom_y{240, "custom_portrait_bottom_y"}; - Setting custom_portrait_bottom_width{360, "custom_portrait_bottom_width"}; + Setting custom_portrait_top_width{800, "custom_portrait_top_width"}; + Setting custom_portrait_top_height{480, "custom_portrait_top_height"}; + Setting custom_portrait_bottom_x{80, "custom_portrait_bottom_x"}; + Setting custom_portrait_bottom_y{500, "custom_portrait_bottom_y"}; + Setting custom_portrait_bottom_width{640, "custom_portrait_bottom_width"}; Setting custom_portrait_bottom_height{480, "custom_portrait_bottom_height"}; SwitchableSetting bg_red{0.f, "bg_red"}; diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index 3765986cb..b3733f892 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -176,22 +176,33 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) { void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height, bool is_portrait_mode) { Layout::FramebufferLayout layout; - // If in portrait mode, only the MobilePortrait option really makes sense - const Settings::LayoutOption layout_option = is_portrait_mode - ? Settings::LayoutOption::MobilePortrait - : Settings::values.layout_option.GetValue(); - const auto min_size = - Layout::GetMinimumSizeFromLayout(layout_option, Settings::values.upright_screen.GetValue()); + const Settings::LayoutOption layout_option = Settings::values.layout_option.GetValue(); + const Settings::PortraitLayoutOption portrait_layout_option = + Settings::values.portrait_layout_option.GetValue(); + const auto min_size = is_portrait_mode + ? Layout::GetMinimumSizeFromPortraitLayout() + : Layout::GetMinimumSizeFromLayout( + layout_option, Settings::values.upright_screen.GetValue()); - if ((Settings::values.custom_layout.GetValue() == true && !is_portrait_mode) || - (Settings::values.custom_portrait_layout.GetValue() == true && is_portrait_mode)) { - layout = Layout::CustomFrameLayout(width, height, Settings::values.swap_screen.GetValue(), - is_portrait_mode); + width = std::max(width, min_size.first); + height = std::max(height, min_size.second); + if (is_portrait_mode) { + switch (portrait_layout_option) { + case Settings::PortraitLayoutOption::PortraitTopFullWidth: + layout = Layout::PortraitTopFullFrameLayout(width, height, + Settings::values.swap_screen.GetValue()); + break; + case Settings::PortraitLayoutOption::PortraitCustomLayout: + layout = Layout::CustomFrameLayout( + width, height, Settings::values.swap_screen.GetValue(), is_portrait_mode); + break; + } } else { - width = std::max(width, min_size.first); - height = std::max(height, min_size.second); - switch (layout_option) { + case Settings::LayoutOption::CustomLayout: + layout = Layout::CustomFrameLayout( + width, height, Settings::values.swap_screen.GetValue(), is_portrait_mode); + break; case Settings::LayoutOption::SingleScreen: layout = Layout::SingleFrameLayout(width, height, Settings::values.swap_screen.GetValue(), @@ -221,21 +232,12 @@ void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height, bool is_po Settings::values.upright_screen.GetValue()); break; #endif - case Settings::LayoutOption::MobilePortrait: - layout = Layout::MobilePortraitFrameLayout(width, height, - Settings::values.swap_screen.GetValue()); - break; case Settings::LayoutOption::MobileLandscape: layout = Layout::LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), false, 2.25f, Layout::VerticalAlignment::Top); break; -#ifndef ANDROID // TODO: Implement custom layouts on Android - case Settings::LayoutOption::CustomLayout: - layout = - Layout::CustomFrameLayout(width, height, Settings::values.swap_screen.GetValue()); - break; -#endif + case Settings::LayoutOption::Default: default: layout = @@ -243,8 +245,9 @@ void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height, bool is_po Settings::values.upright_screen.GetValue()); break; } - UpdateMinimumWindowSize(min_size); } + UpdateMinimumWindowSize(min_size); + if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::CardboardVR) { layout = Layout::GetCardboardSettings(layout); } diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index c55444feb..8c67aa7c1 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp @@ -117,7 +117,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height, bool swapped, bool u return res; } -FramebufferLayout MobilePortraitFrameLayout(u32 width, u32 height, bool swapped) { +FramebufferLayout PortraitTopFullFrameLayout(u32 width, u32 height, bool swapped) { ASSERT(width > 0); ASSERT(height > 0); @@ -419,119 +419,126 @@ FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped, bool return res; } -FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondary) { - bool is_portrait_mode = - Settings::values.layout_option.GetValue() == Settings::LayoutOption::MobilePortrait; - if (Settings::values.custom_layout.GetValue() == true && !is_portrait_mode) { - return CustomFrameLayout(std::max(Settings::values.custom_top_x.GetValue() + - Settings::values.custom_top_width.GetValue(), - Settings::values.custom_bottom_x.GetValue() + - Settings::values.custom_bottom_width.GetValue()), - std::max(Settings::values.custom_top_y.GetValue() + - Settings::values.custom_top_height.GetValue(), - Settings::values.custom_bottom_y.GetValue() + - Settings::values.custom_bottom_height.GetValue()), - Settings::values.swap_screen.GetValue(), is_portrait_mode); - } else if (Settings::values.custom_portrait_layout.GetValue() == true && is_portrait_mode) { - return CustomFrameLayout( - std::max(Settings::values.custom_portrait_top_x.GetValue() + - Settings::values.custom_portrait_top_width.GetValue(), - Settings::values.custom_portrait_bottom_x.GetValue() + - Settings::values.custom_portrait_bottom_width.GetValue()), - std::max(Settings::values.custom_portrait_top_y.GetValue() + - Settings::values.custom_portrait_top_height.GetValue(), - Settings::values.custom_portrait_bottom_y.GetValue() + - Settings::values.custom_portrait_bottom_height.GetValue()), - Settings::values.swap_screen.GetValue(), is_portrait_mode); - } - +FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondary, + bool is_portrait) { int width, height; - switch (Settings::values.layout_option.GetValue()) { - case Settings::LayoutOption::SingleScreen: -#ifndef ANDROID - case Settings::LayoutOption::SeparateWindows: -#endif - { - const bool swap_screens = is_secondary || Settings::values.swap_screen.GetValue(); - if (swap_screens) { - width = Core::kScreenBottomWidth * res_scale; - height = Core::kScreenBottomHeight * res_scale; - } else { + if (is_portrait) { + auto layout_option = Settings::values.portrait_layout_option.GetValue(); + switch (layout_option) { + case Settings::PortraitLayoutOption::PortraitCustomLayout: + return CustomFrameLayout( + std::max(Settings::values.custom_portrait_top_x.GetValue() + + Settings::values.custom_portrait_top_width.GetValue(), + Settings::values.custom_portrait_bottom_x.GetValue() + + Settings::values.custom_portrait_bottom_width.GetValue()), + std::max(Settings::values.custom_portrait_top_y.GetValue() + + Settings::values.custom_portrait_top_height.GetValue(), + Settings::values.custom_portrait_bottom_y.GetValue() + + Settings::values.custom_portrait_bottom_height.GetValue()), + Settings::values.swap_screen.GetValue(), is_portrait); + case Settings::PortraitLayoutOption::PortraitTopFullWidth: width = Core::kScreenTopWidth * res_scale; - height = Core::kScreenTopHeight * res_scale; + height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale; + return PortraitTopFullFrameLayout(width, height, + Settings::values.swap_screen.GetValue()); } - if (Settings::values.upright_screen.GetValue()) { - std::swap(width, height); - } - return SingleFrameLayout(width, height, swap_screens, - Settings::values.upright_screen.GetValue()); - } + } else { + auto layout_option = Settings::values.layout_option.GetValue(); + switch (layout_option) { + case Settings::LayoutOption::CustomLayout: + return CustomFrameLayout(std::max(Settings::values.custom_top_x.GetValue() + + Settings::values.custom_top_width.GetValue(), + Settings::values.custom_bottom_x.GetValue() + + Settings::values.custom_bottom_width.GetValue()), + std::max(Settings::values.custom_top_y.GetValue() + + Settings::values.custom_top_height.GetValue(), + Settings::values.custom_bottom_y.GetValue() + + Settings::values.custom_bottom_height.GetValue()), + Settings::values.swap_screen.GetValue(), is_portrait); - case Settings::LayoutOption::LargeScreen: - if (Settings::values.swap_screen.GetValue()) { - width = (Core::kScreenBottomWidth + + case Settings::LayoutOption::SingleScreen: +#ifndef ANDROID + case Settings::LayoutOption::SeparateWindows: +#endif + { + const bool swap_screens = is_secondary || Settings::values.swap_screen.GetValue(); + if (swap_screens) { + width = Core::kScreenBottomWidth * res_scale; + height = Core::kScreenBottomHeight * res_scale; + } else { + width = Core::kScreenTopWidth * res_scale; + height = Core::kScreenTopHeight * res_scale; + } + if (Settings::values.upright_screen.GetValue()) { + std::swap(width, height); + } + return SingleFrameLayout(width, height, swap_screens, + Settings::values.upright_screen.GetValue()); + } + + case Settings::LayoutOption::LargeScreen: + if (Settings::values.swap_screen.GetValue()) { + width = + (Core::kScreenBottomWidth + Core::kScreenTopWidth / static_cast(Settings::values.large_screen_proportion.GetValue())) * res_scale; - height = Core::kScreenBottomHeight * res_scale; - } else { - width = (Core::kScreenTopWidth + + height = Core::kScreenBottomHeight * res_scale; + } else { + width = + (Core::kScreenTopWidth + Core::kScreenBottomWidth / static_cast(Settings::values.large_screen_proportion.GetValue())) * res_scale; + height = Core::kScreenTopHeight * res_scale; + } + if (Settings::values.upright_screen.GetValue()) { + std::swap(width, height); + } + return LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), + Settings::values.upright_screen.GetValue(), + Settings::values.large_screen_proportion.GetValue(), + VerticalAlignment::Bottom); + + case Settings::LayoutOption::SideScreen: + width = (Core::kScreenTopWidth + Core::kScreenBottomWidth) * res_scale; height = Core::kScreenTopHeight * res_scale; + + if (Settings::values.upright_screen.GetValue()) { + std::swap(width, height); + } + return LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), + Settings::values.upright_screen.GetValue(), 1, + VerticalAlignment::Middle); + + case Settings::LayoutOption::MobileLandscape: { + constexpr float large_screen_proportion = 2.25f; + if (Settings::values.swap_screen.GetValue()) { + width = (Core::kScreenBottomWidth + + static_cast(Core::kScreenTopWidth / large_screen_proportion)) * + res_scale; + height = Core::kScreenBottomHeight * res_scale; + } else { + width = (Core::kScreenTopWidth + + static_cast(Core::kScreenBottomWidth / large_screen_proportion)) * + res_scale; + height = Core::kScreenTopHeight * res_scale; + } + return LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), false, + large_screen_proportion, VerticalAlignment::Top); } - if (Settings::values.upright_screen.GetValue()) { - std::swap(width, height); + + case Settings::LayoutOption::Default: + default: + width = Core::kScreenTopWidth * res_scale; + height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale; + + if (Settings::values.upright_screen.GetValue()) { + std::swap(width, height); + } + return DefaultFrameLayout(width, height, Settings::values.swap_screen.GetValue(), + Settings::values.upright_screen.GetValue()); } - return LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), - Settings::values.upright_screen.GetValue(), - Settings::values.large_screen_proportion.GetValue(), - VerticalAlignment::Bottom); - - case Settings::LayoutOption::SideScreen: - width = (Core::kScreenTopWidth + Core::kScreenBottomWidth) * res_scale; - height = Core::kScreenTopHeight * res_scale; - - if (Settings::values.upright_screen.GetValue()) { - std::swap(width, height); - } - return LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), - Settings::values.upright_screen.GetValue(), 1, - VerticalAlignment::Middle); - - case Settings::LayoutOption::MobilePortrait: - width = Core::kScreenTopWidth * res_scale; - height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale; - return MobilePortraitFrameLayout(width, height, Settings::values.swap_screen.GetValue()); - - case Settings::LayoutOption::MobileLandscape: { - constexpr float large_screen_proportion = 2.25f; - if (Settings::values.swap_screen.GetValue()) { - width = (Core::kScreenBottomWidth + - static_cast(Core::kScreenTopWidth / large_screen_proportion)) * - res_scale; - height = Core::kScreenBottomHeight * res_scale; - } else { - width = (Core::kScreenTopWidth + - static_cast(Core::kScreenBottomWidth / large_screen_proportion)) * - res_scale; - height = Core::kScreenTopHeight * res_scale; - } - return LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), false, - large_screen_proportion, VerticalAlignment::Top); - } - - case Settings::LayoutOption::Default: - default: - width = Core::kScreenTopWidth * res_scale; - height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale; - - if (Settings::values.upright_screen.GetValue()) { - std::swap(width, height); - } - return DefaultFrameLayout(width, height, Settings::values.swap_screen.GetValue(), - Settings::values.upright_screen.GetValue()); } UNREACHABLE(); } @@ -554,11 +561,27 @@ FramebufferLayout GetCardboardSettings(const FramebufferLayout& layout) { u32 cardboard_screen_width; u32 cardboard_screen_height; - switch (Settings::values.layout_option.GetValue()) { - case Settings::LayoutOption::MobileLandscape: - case Settings::LayoutOption::SideScreen: - // If orientation is portrait, only use MobilePortrait - if (!is_portrait) { + if (is_portrait) { + switch (Settings::values.portrait_layout_option.GetValue()) { + case Settings::PortraitLayoutOption::PortraitTopFullWidth: + cardboard_screen_width = top_screen_width; + cardboard_screen_height = top_screen_height + bottom_screen_height; + bottom_screen_left += (top_screen_width - bottom_screen_width) / 2; + if (is_swapped) + top_screen_top += bottom_screen_height; + else + bottom_screen_top += top_screen_height; + break; + default: + cardboard_screen_width = is_swapped ? bottom_screen_width : top_screen_width; + cardboard_screen_height = is_swapped ? bottom_screen_height : top_screen_height; + } + } else { + switch (Settings::values.layout_option.GetValue()) { + case Settings::LayoutOption::MobileLandscape: + case Settings::LayoutOption::SideScreen: + // If orientation is portrait, only use MobilePortrait + cardboard_screen_width = top_screen_width + bottom_screen_width; cardboard_screen_height = is_swapped ? bottom_screen_height : top_screen_height; if (is_swapped) @@ -566,28 +589,14 @@ FramebufferLayout GetCardboardSettings(const FramebufferLayout& layout) { else bottom_screen_left += top_screen_width; break; - } else { - [[fallthrough]]; - } - case Settings::LayoutOption::SingleScreen: - default: - if (!is_portrait) { - // Default values when using LayoutOption::SingleScreen + + case Settings::LayoutOption::SingleScreen: + default: + cardboard_screen_width = is_swapped ? bottom_screen_width : top_screen_width; cardboard_screen_height = is_swapped ? bottom_screen_height : top_screen_height; break; - } else { - [[fallthrough]]; } - case Settings::LayoutOption::MobilePortrait: - cardboard_screen_width = top_screen_width; - cardboard_screen_height = top_screen_height + bottom_screen_height; - bottom_screen_left += (top_screen_width - bottom_screen_width) / 2; - if (is_swapped) - top_screen_top += bottom_screen_height; - else - bottom_screen_top += top_screen_height; - break; } s32 cardboard_max_x_shift = (layout.width / 2 - cardboard_screen_width) / 2; s32 cardboard_user_x_shift = @@ -620,6 +629,15 @@ FramebufferLayout GetCardboardSettings(const FramebufferLayout& layout) { return new_layout; } +/*f + * TODO: remove this? + */ +std::pair GetMinimumSizeFromPortraitLayout() { + u32 min_width, min_height; + min_width = Core::kScreenTopWidth; + min_height = Core::kScreenTopHeight + Core::kScreenBottomHeight; + return std::make_pair(min_width, min_height); +} std::pair GetMinimumSizeFromLayout(Settings::LayoutOption layout, bool upright_screen) { diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h index 37cbb564c..98565ed7c 100644 --- a/src/core/frontend/framebuffer_layout.h +++ b/src/core/frontend/framebuffer_layout.h @@ -85,13 +85,14 @@ struct FramebufferLayout { FramebufferLayout DefaultFrameLayout(u32 width, u32 height, bool is_swapped, bool upright); /** - * Factory method for constructing a mobile portrait FramebufferLayout + * Factory method for constructing the mobile Full Width Top layout + * Two screens at top, full width, no gap between them * @param width Window framebuffer width in pixels * @param height Window framebuffer height in pixels * @param is_swapped if true, the bottom screen will be displayed above the top screen * @return Newly created FramebufferLayout object with mobile portrait screen regions initialized */ -FramebufferLayout MobilePortraitFrameLayout(u32 width, u32 height, bool is_swapped); +FramebufferLayout PortraitTopFullFrameLayout(u32 width, u32 height, bool is_swapped); /** * Factory method for constructing a FramebufferLayout with only the top or bottom screen @@ -152,8 +153,10 @@ FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped, * Convenience method to get frame layout by resolution scale * Read from the current settings to determine which layout to use. * @param res_scale resolution scale factor + * @param is_portrait_mode defaults to false */ -FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondary = false); +FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondary = false, + bool is_portrait_mode = false); /** * Convenience method for transforming a frame layout when using Cardboard VR @@ -165,4 +168,6 @@ FramebufferLayout GetCardboardSettings(const FramebufferLayout& layout); std::pair GetMinimumSizeFromLayout(Settings::LayoutOption layout, bool upright_screen); +std::pair GetMinimumSizeFromPortraitLayout(); + } // namespace Layout diff --git a/src/lime/config.cpp b/src/lime/config.cpp index e18de2ad2..49962b1d2 100644 --- a/src/lime/config.cpp +++ b/src/lime/config.cpp @@ -183,7 +183,7 @@ void Config::ReadValues() { ReadSetting("Layout", Settings::values.screen_bottom_leftright_padding); ReadSetting("Layout", Settings::values.screen_bottom_topbottom_padding); - ReadSetting("Layout", Settings::values.custom_portrait_layout); + ReadSetting("Layout", Settings::values.portrait_layout_option); ReadSetting("Layout", Settings::values.custom_portrait_top_x); ReadSetting("Layout", Settings::values.custom_portrait_top_y); ReadSetting("Layout", Settings::values.custom_portrait_top_width); diff --git a/src/lime_qt/configuration/config.cpp b/src/lime_qt/configuration/config.cpp index b26507fb2..ce5c632ac 100644 --- a/src/lime_qt/configuration/config.cpp +++ b/src/lime_qt/configuration/config.cpp @@ -538,7 +538,7 @@ void Config::ReadLayoutValues() { ReadBasicSetting(Settings::values.screen_bottom_stretch); ReadBasicSetting(Settings::values.screen_bottom_leftright_padding); ReadBasicSetting(Settings::values.screen_bottom_topbottom_padding); - ReadBasicSetting(Settings::values.custom_portrait_layout); + ReadBasicSetting(Settings::values.portrait_layout_option); ReadBasicSetting(Settings::values.custom_portrait_top_x); ReadBasicSetting(Settings::values.custom_portrait_top_y); ReadBasicSetting(Settings::values.custom_portrait_top_width); @@ -1099,7 +1099,6 @@ void Config::SaveLayoutValues() { WriteBasicSetting(Settings::values.screen_bottom_stretch); WriteBasicSetting(Settings::values.screen_bottom_leftright_padding); WriteBasicSetting(Settings::values.screen_bottom_topbottom_padding); - WriteBasicSetting(Settings::values.custom_portrait_layout); WriteBasicSetting(Settings::values.custom_portrait_top_x); WriteBasicSetting(Settings::values.custom_portrait_top_y); WriteBasicSetting(Settings::values.custom_portrait_top_width); diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 514ec389b..80cf549e9 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -634,6 +634,10 @@ void RendererOpenGL::DrawSingleScreenStereo(const ScreenInfo& screen_info_l, * Draws the emulated screens to the emulator window. */ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool flipped) { + bool isPortrait = false; +#ifdef ANDROID + isPortrait = layout.height > layout.width; +#endif if (settings.bg_color_update_requested.exchange(false)) { // Update background color before drawing glClearColor(Settings::values.bg_red.GetValue(), Settings::values.bg_green.GetValue(), @@ -675,12 +679,12 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f if (!Settings::values.swap_screen.GetValue()) { DrawTopScreen(layout, top_screen); glUniform1i(uniform_layer, 0); - ApplySecondLayerOpacity(); + ApplySecondLayerOpacity(isPortrait); DrawBottomScreen(layout, bottom_screen); } else { DrawBottomScreen(layout, bottom_screen); glUniform1i(uniform_layer, 0); - ApplySecondLayerOpacity(); + ApplySecondLayerOpacity(isPortrait); DrawTopScreen(layout, top_screen); } @@ -692,11 +696,17 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f DrawBottomScreen(layout, additional_screen); } } - ResetSecondLayerOpacity(); + ResetSecondLayerOpacity(isPortrait); } -void RendererOpenGL::ApplySecondLayerOpacity() { -#ifndef ANDROID // TODO: Implement custom layouts on Android +void RendererOpenGL::ApplySecondLayerOpacity(bool isPortrait) { +#ifdef ANDROID + // TODO: Allow for second layer opacity in portrait mode android + if (isPortrait) { + return; + } +#endif + if ((Settings::values.layout_option.GetValue() == Settings::LayoutOption::CustomLayout || Settings::values.custom_layout) && Settings::values.custom_second_layer_opacity.GetValue() < 100) { @@ -706,11 +716,16 @@ void RendererOpenGL::ApplySecondLayerOpacity() { state.blend.dst_rgb_func = GL_ONE_MINUS_CONSTANT_ALPHA; state.blend.color.alpha = Settings::values.custom_second_layer_opacity.GetValue() / 100.0f; } -#endif } -void RendererOpenGL::ResetSecondLayerOpacity() { -#ifndef ANDROID // TODO: Implement custom layouts on Android +void RendererOpenGL::ResetSecondLayerOpacity(bool isPortrait) { +#ifdef ANDROID + // TODO: Allow for second layer opacity in portrait mode android + if (isPortrait) { + return; + } +#endif + if ((Settings::values.layout_option.GetValue() == Settings::LayoutOption::CustomLayout || Settings::values.custom_layout) && Settings::values.custom_second_layer_opacity.GetValue() < 100) { @@ -720,7 +735,6 @@ void RendererOpenGL::ResetSecondLayerOpacity() { state.blend.dst_a_func = GL_ZERO; state.blend.color.alpha = 0.0f; } -#endif } void RendererOpenGL::DrawTopScreen(const Layout::FramebufferLayout& layout, diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index a335f516e..7885a2f5b 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -65,8 +65,8 @@ private: void ConfigureFramebufferTexture(TextureInfo& texture, const Pica::FramebufferConfig& framebuffer); void DrawScreens(const Layout::FramebufferLayout& layout, bool flipped); - void ApplySecondLayerOpacity(); - void ResetSecondLayerOpacity(); + void ApplySecondLayerOpacity(bool isPortrait = false); + void ResetSecondLayerOpacity(bool isPortrait = false); void DrawBottomScreen(const Layout::FramebufferLayout& layout, const Common::Rectangle& bottom_screen); void DrawTopScreen(const Layout::FramebufferLayout& layout, From 862fda433261f84b5abd401f48c8f9e1c4817a43 Mon Sep 17 00:00:00 2001 From: David Griswold Date: Sun, 11 Aug 2024 16:18:59 +0100 Subject: [PATCH 06/19] android: Implemented custom layout customization GUI This commit also changes the name of the 'Portrait' landscape layout to 'Original' Co-authored-by: OpenSauce04 --- .../github/lime3ds/android/NativeLibrary.kt | 13 +- .../android/display/PortraitScreenLayout.kt | 17 -- .../android/display/ScreenAdjustmentUtil.kt | 38 +-- .../lime3ds/android/display/ScreenLayout.kt | 14 +- .../features/settings/model/IntSetting.kt | 16 + .../features/settings/model/Settings.kt | 2 + .../settings/ui/SettingsActivityPresenter.kt | 4 + .../features/settings/ui/SettingsAdapter.kt | 36 ++- .../settings/ui/SettingsFragmentPresenter.kt | 287 ++++++++++++++++++ .../android/fragments/EmulationFragment.kt | 89 +++++- .../android/utils/EmulationMenuSettings.kt | 23 +- src/android/app/src/main/jni/config.cpp | 1 - src/android/app/src/main/jni/default_ini.h | 7 +- .../src/main/jni/emu_window/emu_window.cpp | 14 - src/android/app/src/main/jni/id_cache.cpp | 4 - src/android/app/src/main/jni/native.cpp | 24 +- .../res/drawable/ic_portrait_fit_screen.xml | 6 + .../app/src/main/res/layout/dialog_slider.xml | 36 ++- .../app/src/main/res/menu/menu_emulation.xml | 127 -------- .../app/src/main/res/menu/menu_in_game.xml | 3 +- .../res/menu/menu_landscape_screen_layout.xml | 5 + .../res/menu/menu_portrait_screen_layout.xml | 1 + .../app/src/main/res/values/arrays.xml | 31 ++ .../app/src/main/res/values/strings.xml | 12 +- src/common/settings.h | 3 - src/core/frontend/framebuffer_layout.cpp | 11 +- src/core/frontend/framebuffer_layout.h | 2 +- src/lime/config.cpp | 2 - src/lime/default_ini.h | 6 +- src/lime_qt/configuration/config.cpp | 4 - .../renderer_opengl/renderer_opengl.cpp | 30 +- 31 files changed, 546 insertions(+), 322 deletions(-) delete mode 100644 src/android/app/src/main/java/io/github/lime3ds/android/display/PortraitScreenLayout.kt create mode 100644 src/android/app/src/main/res/drawable/ic_portrait_fit_screen.xml delete mode 100644 src/android/app/src/main/res/menu/menu_emulation.xml diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/NativeLibrary.kt b/src/android/app/src/main/java/io/github/lime3ds/android/NativeLibrary.kt index 1959eaba9..6aa59e513 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/NativeLibrary.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/NativeLibrary.kt @@ -156,11 +156,10 @@ object NativeLibrary { external fun getPerfStats(): DoubleArray /** - * Notifies the core emulation that the orientation has changed. + * Notifies the core emulation that the layout should be updated */ - external fun notifyOrientationChange(layoutOption: Int, rotation: Int, isPortrait: Boolean) + external fun updateFramebuffer(isPortrait: Boolean) - external fun notifyPortraitLayoutChange(layoutOption: Int, rotation: Int, isPortrait: Boolean) /** * Swaps the top and bottom screens. */ @@ -263,14 +262,6 @@ object NativeLibrary { get() = LimeApplication.appContext.resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT - @Keep - @JvmStatic - fun landscapeScreenLayout(): Int = EmulationMenuSettings.landscapeScreenLayout - - @Keep - @JvmStatic - fun portraitScreenLayout(): Int = EmulationMenuSettings.portraitScreenLayout - @Keep @JvmStatic fun displayAlertMsg(title: String, message: String, yesNo: Boolean): Boolean { diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/display/PortraitScreenLayout.kt b/src/android/app/src/main/java/io/github/lime3ds/android/display/PortraitScreenLayout.kt deleted file mode 100644 index 74d9c1820..000000000 --- a/src/android/app/src/main/java/io/github/lime3ds/android/display/PortraitScreenLayout.kt +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2023 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -package io.github.lime3ds.android.display - -enum class PortraitScreenLayout(val int: Int) { - // These must match what is defined in src/common/settings.h - TOP_FULL_WIDTH(0), - CUSTOM_PORTRAIT_LAYOUT(1); - - companion object { - fun from(int: Int): PortraitScreenLayout { - return entries.firstOrNull { it.int == int } ?: TOP_FULL_WIDTH; - } - } -} diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenAdjustmentUtil.kt b/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenAdjustmentUtil.kt index 8d4734e29..035da2487 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenAdjustmentUtil.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenAdjustmentUtil.kt @@ -3,7 +3,6 @@ // Refer to the license.txt file included. package io.github.lime3ds.android.display - import android.view.WindowManager import io.github.lime3ds.android.NativeLibrary import io.github.lime3ds.android.features.settings.model.BooleanSetting @@ -26,40 +25,35 @@ class ScreenAdjustmentUtil( BooleanSetting.SWAP_SCREEN.boolean = isEnabled settings.saveSetting(BooleanSetting.SWAP_SCREEN, SettingsFile.FILE_NAME_CONFIG) } - - // TODO: Consider how cycling should handle custom layout - // right now it simply skips it fun cycleLayouts() { - val nextLayout = if (NativeLibrary.isPortraitMode) { - (EmulationMenuSettings.portraitScreenLayout + 1) % (PortraitScreenLayout.entries.size - 1) + // TODO: figure out how to pull these from R.array + val landscape_values = intArrayOf(6,1,3,4,0,5); + val portrait_values = intArrayOf(0,1); + if (NativeLibrary.isPortraitMode) { + val current_layout = IntSetting.PORTRAIT_SCREEN_LAYOUT.int + val pos = portrait_values.indexOf(current_layout) + val layout_option = portrait_values[(pos + 1) % portrait_values.size] + changePortraitOrientation(layout_option) } else { - (EmulationMenuSettings.landscapeScreenLayout + 1) % (ScreenLayout.entries.size - 1) + val current_layout = IntSetting.SCREEN_LAYOUT.int + val pos = landscape_values.indexOf(current_layout) + val layout_option = landscape_values[(pos + 1) % landscape_values.size] + changeScreenOrientation(layout_option) } - settings.loadSettings() - changeScreenOrientation(nextLayout) } fun changePortraitOrientation(layoutOption: Int) { - EmulationMenuSettings.portraitScreenLayout = layoutOption - NativeLibrary.notifyPortraitLayoutChange( - EmulationMenuSettings.portraitScreenLayout, - windowManager.defaultDisplay.rotation, - NativeLibrary::isPortraitMode.get() - ) IntSetting.PORTRAIT_SCREEN_LAYOUT.int = layoutOption settings.saveSetting(IntSetting.PORTRAIT_SCREEN_LAYOUT, SettingsFile.FILE_NAME_CONFIG) + NativeLibrary.reloadSettings() + NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode) } fun changeScreenOrientation(layoutOption: Int) { - EmulationMenuSettings.landscapeScreenLayout = layoutOption - NativeLibrary.notifyOrientationChange( - EmulationMenuSettings.landscapeScreenLayout, - windowManager.defaultDisplay.rotation, - NativeLibrary::isPortraitMode.get() - ) IntSetting.SCREEN_LAYOUT.int = layoutOption settings.saveSetting(IntSetting.SCREEN_LAYOUT, SettingsFile.FILE_NAME_CONFIG) - + NativeLibrary.reloadSettings() + NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode) } } diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenLayout.kt b/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenLayout.kt index a6fc57e10..293b2a605 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenLayout.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenLayout.kt @@ -6,7 +6,7 @@ package io.github.lime3ds.android.display enum class ScreenLayout(val int: Int) { // These must match what is defined in src/common/settings.h - TOP_BOTTOM(0), + ORIGINAL(0), SINGLE_SCREEN(1), LARGE_SCREEN(2), SIDE_SCREEN(3), @@ -21,3 +21,15 @@ enum class ScreenLayout(val int: Int) { } } } + +enum class PortraitScreenLayout(val int: Int) { + // These must match what is defined in src/common/settings.h + TOP_FULL_WIDTH(0), + CUSTOM_PORTRAIT_LAYOUT(1); + + companion object { + fun from(int: Int): PortraitScreenLayout { + return entries.firstOrNull { it.int == int } ?: TOP_FULL_WIDTH; + } + } +} \ No newline at end of file diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/IntSetting.kt index 4e240c3a5..8e6c1942d 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/IntSetting.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/IntSetting.kt @@ -23,7 +23,23 @@ enum class IntSetting( CARDBOARD_X_SHIFT("cardboard_x_shift", Settings.SECTION_LAYOUT, 0), CARDBOARD_Y_SHIFT("cardboard_y_shift", Settings.SECTION_LAYOUT, 0), SCREEN_LAYOUT("layout_option", Settings.SECTION_LAYOUT, 0), + LANDSCAPE_TOP_X("custom_top_x",Settings.SECTION_LAYOUT,0), + LANDSCAPE_TOP_Y("custom_top_y",Settings.SECTION_LAYOUT,0), + LANDSCAPE_TOP_WIDTH("custom_top_width",Settings.SECTION_LAYOUT,800), + LANDSCAPE_TOP_HEIGHT("custom_top_height",Settings.SECTION_LAYOUT,480), + LANDSCAPE_BOTTOM_X("custom_bottom_x",Settings.SECTION_LAYOUT,80), + 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), 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), + PORTRAIT_TOP_WIDTH("custom_portrait_top_width",Settings.SECTION_LAYOUT,800), + PORTRAIT_TOP_HEIGHT("custom_portrait_top_height",Settings.SECTION_LAYOUT,480), + PORTRAIT_BOTTOM_X("custom_portrait_bottom_x",Settings.SECTION_LAYOUT,80), + PORTRAIT_BOTTOM_Y("custom_portrait_bottom_y",Settings.SECTION_LAYOUT,480), + PORTRAIT_BOTTOM_WIDTH("custom_portrait_bottom_width",Settings.SECTION_LAYOUT,640), + PORTRAIT_BOTTOM_HEIGHT("custom_portrait_bottom_height",Settings.SECTION_LAYOUT,480), AUDIO_INPUT_TYPE("output_type", Settings.SECTION_AUDIO, 0), NEW_3DS("is_new_3ds", Settings.SECTION_SYSTEM, 1), LLE_APPLETS("lle_applets", Settings.SECTION_SYSTEM, 0), diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/Settings.kt b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/Settings.kt index d13d324d7..32227833b 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/Settings.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/Settings.kt @@ -109,6 +109,8 @@ class Settings { const val SECTION_AUDIO = "Audio" const val SECTION_DEBUG = "Debugging" const val SECTION_THEME = "Theme" + const val SECTION_CUSTOM_LANDSCAPE = "Custom Landscape Layout" + const val SECTION_CUSTOM_PORTRAIT = "Custom Portrait Layout" const val KEY_BUTTON_A = "button_a" const val KEY_BUTTON_B = "button_b" diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsActivityPresenter.kt b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsActivityPresenter.kt index 65307d0d2..6e04bd8d5 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsActivityPresenter.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsActivityPresenter.kt @@ -7,6 +7,7 @@ package io.github.lime3ds.android.features.settings.ui import android.os.Bundle import android.text.TextUtils import io.github.lime3ds.android.NativeLibrary +import io.github.lime3ds.android.features.settings.model.IntSetting import io.github.lime3ds.android.features.settings.model.Settings import io.github.lime3ds.android.utils.SystemSaveGame import io.github.lime3ds.android.utils.DirectoryInitialization @@ -56,6 +57,9 @@ class SettingsActivityPresenter(private val activityView: SettingsActivityView) Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...") settings.saveSettings(activityView) SystemSaveGame.save() + //added to ensure that layout changes take effect as soon as settings window closes + NativeLibrary.reloadSettings() + NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode) } NativeLibrary.reloadSettings() } diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsAdapter.kt b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsAdapter.kt index 6806991a8..d50269eff 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsAdapter.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsAdapter.kt @@ -7,13 +7,16 @@ package io.github.lime3ds.android.features.settings.ui import android.annotation.SuppressLint import android.content.Context import android.content.DialogInterface +import android.graphics.Color import android.icu.util.Calendar import android.icu.util.TimeZone +import android.text.Editable import android.text.InputFilter +import android.text.TextWatcher import android.text.format.DateFormat import android.view.LayoutInflater import android.view.ViewGroup -import android.widget.TextView +import android.widget.EditText import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.core.widget.doOnTextChanged @@ -22,6 +25,8 @@ import androidx.recyclerview.widget.RecyclerView import com.google.android.material.datepicker.MaterialDatePicker import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.slider.Slider +import com.google.android.material.textfield.TextInputEditText +import com.google.android.material.textfield.TextInputLayout import com.google.android.material.timepicker.MaterialTimePicker import com.google.android.material.timepicker.TimeFormat import io.github.lime3ds.android.R @@ -73,7 +78,8 @@ class SettingsAdapter( private var clickedPosition: Int private var dialog: AlertDialog? = null private var sliderProgress = 0 - private var textSliderValue: TextView? = null + private var textSliderValue: TextInputEditText? = null + private var textInputLayout: TextInputLayout? = null private var textInputValue: String = "" private var defaultCancelListener = @@ -256,18 +262,36 @@ class SettingsAdapter( val inflater = LayoutInflater.from(context) val sliderBinding = DialogSliderBinding.inflate(inflater) - + textInputLayout = sliderBinding.textInput textSliderValue = sliderBinding.textValue - textSliderValue!!.text = sliderProgress.toString() - sliderBinding.textUnits.text = item.units + textSliderValue!!.setText(sliderProgress.toString()) + //sliderBinding.textUnits.text = item.units + textInputLayout!!.suffixText = item.units sliderBinding.slider.apply { valueFrom = item.min.toFloat() valueTo = item.max.toFloat() value = sliderProgress.toFloat() + textSliderValue!!.addTextChangedListener( object : TextWatcher { + override fun afterTextChanged(s: Editable) { + val textValue = s.toString().toIntOrNull(); + if (textValue == null || textValue < valueFrom || textValue > valueTo) { + textInputLayout!!.error ="Inappropriate value" + } else { + textInputLayout!!.error = null + value = textValue.toFloat(); + } + } + override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} + override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} + }) + addOnChangeListener { _: Slider, value: Float, _: Boolean -> sliderProgress = value.toInt() - textSliderValue!!.text = sliderProgress.toString() + if (textSliderValue!!.text.toString() != value.toInt().toString()) { + textSliderValue!!.setText(value.toInt().toString()) + textSliderValue!!.setSelection(textSliderValue!!.length()) + } } } diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsFragmentPresenter.kt index df0231d4f..18448ce1e 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsFragmentPresenter.kt @@ -6,6 +6,7 @@ package io.github.lime3ds.android.features.settings.ui import android.content.Context import android.content.SharedPreferences +import android.content.res.Resources import android.hardware.camera2.CameraAccessException import android.hardware.camera2.CameraCharacteristics import android.hardware.camera2.CameraManager @@ -42,6 +43,7 @@ import io.github.lime3ds.android.utils.GpuDriverHelper import io.github.lime3ds.android.utils.Log import io.github.lime3ds.android.utils.SystemSaveGame import io.github.lime3ds.android.utils.ThemeUtil +import kotlin.math.min class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) { private var menuTag: String? = null @@ -91,9 +93,12 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) Settings.SECTION_CAMERA -> addCameraSettings(sl) Settings.SECTION_CONTROLS -> addControlsSettings(sl) Settings.SECTION_RENDERER -> addGraphicsSettings(sl) + Settings.SECTION_LAYOUT -> addLayoutSettings(sl) Settings.SECTION_AUDIO -> addAudioSettings(sl) Settings.SECTION_DEBUG -> addDebugSettings(sl) Settings.SECTION_THEME -> addThemeSettings(sl) + Settings.SECTION_CUSTOM_LANDSCAPE -> addCustomLandscapeSettings(sl) + Settings.SECTION_CUSTOM_PORTRAIT -> addCustomPortraitSettings(sl) else -> { fragmentView.showToastMessage("Unimplemented menu", false) return @@ -103,6 +108,23 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) fragmentView.showSettingsList(settingsList!!) } + /** Returns the portrait mode width */ + private fun getWidth(): Int { + val dm = Resources.getSystem().displayMetrics; + return if (dm.widthPixels < dm.heightPixels) + dm.widthPixels + else + dm.heightPixels + } + + private fun getHeight(): Int { + val dm = Resources.getSystem().displayMetrics; + return if (dm.widthPixels < dm.heightPixels) + dm.heightPixels + else + dm.widthPixels + } + private fun addConfigSettings(sl: ArrayList) { settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_settings)) sl.apply { @@ -146,6 +168,14 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) Settings.SECTION_RENDERER ) ) + add( + SubmenuSetting( + R.string.preferences_layout, + 0, + R.drawable.ic_fit_screen, + Settings.SECTION_LAYOUT + ) + ) add( SubmenuSetting( R.string.preferences_audio, @@ -162,6 +192,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) Settings.SECTION_DEBUG ) ) + add( RunnableSetting( R.string.reset_to_default, @@ -873,6 +904,262 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) } } + private fun addLayoutSettings(sl: ArrayList) { + settingsActivity.setToolbarTitle("Layout") + sl.apply { + add( + SingleChoiceSetting( + IntSetting.SCREEN_LAYOUT, + R.string.emulation_switch_screen_layout, + 0, + R.array.landscapeLayouts, + R.array.landscapeLayoutValues, + IntSetting.SCREEN_LAYOUT.key, + IntSetting.SCREEN_LAYOUT.defaultValue + ) + ) + add( + SingleChoiceSetting( + IntSetting.PORTRAIT_SCREEN_LAYOUT, + R.string.emulation_switch_portrait_layout, + 0, + R.array.portraitLayouts, + R.array.portraitLayoutValues, + IntSetting.PORTRAIT_SCREEN_LAYOUT.key, + IntSetting.PORTRAIT_SCREEN_LAYOUT.defaultValue + ) + ) + add( + SubmenuSetting( + R.string.emulation_landscape_custom_layout, + 0, + R.drawable.ic_fit_screen, + Settings.SECTION_CUSTOM_LANDSCAPE + ) + ) + add( + SubmenuSetting( + R.string.emulation_portrait_custom_layout, + 0, + R.drawable.ic_portrait_fit_screen, + Settings.SECTION_CUSTOM_PORTRAIT + ) + ) + + + } + } + + private fun addCustomLandscapeSettings(sl: ArrayList) { + settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.emulation_landscape_custom_layout)) + sl.apply { + add(HeaderSetting(R.string.emulation_top_screen)) + add( + SliderSetting( + IntSetting.LANDSCAPE_TOP_X, + R.string.emulation_custom_layout_x, + 0, + 0, + getHeight(), + "px", + IntSetting.LANDSCAPE_TOP_X.key, + IntSetting.LANDSCAPE_TOP_X.defaultValue.toFloat() + ) + ) + add( + SliderSetting( + IntSetting.LANDSCAPE_TOP_Y, + R.string.emulation_custom_layout_y, + 0, + 0, + getWidth(), + "px", + IntSetting.LANDSCAPE_TOP_Y.key, + IntSetting.LANDSCAPE_TOP_Y.defaultValue.toFloat() + ) + ) + add( + SliderSetting( + IntSetting.LANDSCAPE_TOP_WIDTH, + R.string.emulation_custom_layout_width, + 0, + 0, + getHeight(), + "px", + IntSetting.LANDSCAPE_TOP_WIDTH.key, + IntSetting.LANDSCAPE_TOP_WIDTH.defaultValue.toFloat() + ) + ) + add( + SliderSetting( + IntSetting.LANDSCAPE_TOP_HEIGHT, + R.string.emulation_custom_layout_height, + 0, + 0, + getWidth(), + "px", + IntSetting.LANDSCAPE_TOP_HEIGHT.key, + IntSetting.LANDSCAPE_TOP_HEIGHT.defaultValue.toFloat() + ) + ) + add(HeaderSetting(R.string.emulation_bottom_screen)) + add( + SliderSetting( + IntSetting.LANDSCAPE_BOTTOM_X, + R.string.emulation_custom_layout_x, + 0, + 0, + getHeight(), + "px", + IntSetting.LANDSCAPE_BOTTOM_X.key, + IntSetting.LANDSCAPE_BOTTOM_X.defaultValue.toFloat() + ) + ) + add( + SliderSetting( + IntSetting.LANDSCAPE_BOTTOM_Y, + R.string.emulation_custom_layout_y, + 0, + 0, + getWidth(), + "px", + IntSetting.LANDSCAPE_BOTTOM_Y.key, + IntSetting.LANDSCAPE_BOTTOM_Y.defaultValue.toFloat() + ) + ) + add( + SliderSetting( + IntSetting.LANDSCAPE_BOTTOM_WIDTH, + R.string.emulation_custom_layout_width, + 0, + 0, + getHeight(), + "px", + IntSetting.LANDSCAPE_BOTTOM_WIDTH.key, + IntSetting.LANDSCAPE_BOTTOM_WIDTH.defaultValue.toFloat() + ) + ) + add( + SliderSetting( + IntSetting.LANDSCAPE_BOTTOM_HEIGHT, + R.string.emulation_custom_layout_height, + 0, + 0, + getWidth(), + "px", + IntSetting.LANDSCAPE_BOTTOM_HEIGHT.key, + IntSetting.LANDSCAPE_BOTTOM_HEIGHT.defaultValue.toFloat() + ) + ) + } + + } + + private fun addCustomPortraitSettings(sl: ArrayList) { + settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.emulation_portrait_custom_layout)) + sl.apply { + add(HeaderSetting(R.string.emulation_top_screen)) + add( + SliderSetting( + IntSetting.PORTRAIT_TOP_X, + R.string.emulation_custom_layout_x, + 0, + 0, + getWidth(), + "px", + IntSetting.PORTRAIT_TOP_X.key, + IntSetting.PORTRAIT_TOP_X.defaultValue.toFloat() + ) + ) + add( + SliderSetting( + IntSetting.PORTRAIT_TOP_Y, + R.string.emulation_custom_layout_y, + 0, + 0, + getHeight(), + "px", + IntSetting.PORTRAIT_TOP_Y.key, + IntSetting.PORTRAIT_TOP_Y.defaultValue.toFloat() + ) + ) + add( + SliderSetting( + IntSetting.PORTRAIT_TOP_WIDTH, + R.string.emulation_custom_layout_width, + 0, + 0, + getWidth(), + "px", + IntSetting.PORTRAIT_TOP_WIDTH.key, + IntSetting.PORTRAIT_TOP_WIDTH.defaultValue.toFloat() + ) + ) + add( + SliderSetting( + IntSetting.PORTRAIT_TOP_HEIGHT, + R.string.emulation_custom_layout_height, + 0, + 0, + getHeight(), + "px", + IntSetting.PORTRAIT_TOP_HEIGHT.key, + IntSetting.PORTRAIT_TOP_HEIGHT.defaultValue.toFloat() + ) + ) + add(HeaderSetting(R.string.emulation_bottom_screen)) + add( + SliderSetting( + IntSetting.PORTRAIT_BOTTOM_X, + R.string.emulation_custom_layout_x, + 0, + 0, + getWidth(), + "px", + IntSetting.PORTRAIT_BOTTOM_X.key, + IntSetting.PORTRAIT_BOTTOM_X.defaultValue.toFloat() + ) + ) + add( + SliderSetting( + IntSetting.PORTRAIT_BOTTOM_Y, + R.string.emulation_custom_layout_y, + 0, + 0, + getHeight(), + "px", + IntSetting.PORTRAIT_BOTTOM_Y.key, + IntSetting.PORTRAIT_BOTTOM_Y.defaultValue.toFloat() + ) + ) + add( + SliderSetting( + IntSetting.PORTRAIT_BOTTOM_WIDTH, + R.string.emulation_custom_layout_width, + 0, + 0, + getWidth(), + "px", + IntSetting.PORTRAIT_BOTTOM_WIDTH.key, + IntSetting.PORTRAIT_BOTTOM_WIDTH.defaultValue.toFloat() + ) + ) + add( + SliderSetting( + IntSetting.PORTRAIT_BOTTOM_HEIGHT, + R.string.emulation_custom_layout_height, + 0, + 0, + getHeight(), + "px", + IntSetting.PORTRAIT_BOTTOM_HEIGHT.key, + IntSetting.PORTRAIT_BOTTOM_HEIGHT.defaultValue.toFloat() + ) + ) + } + + } + private fun addAudioSettings(sl: ArrayList) { settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_audio)) sl.apply { diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/fragments/EmulationFragment.kt b/src/android/app/src/main/java/io/github/lime3ds/android/fragments/EmulationFragment.kt index 455ce3e89..a67d4a775 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/fragments/EmulationFragment.kt @@ -13,6 +13,8 @@ import android.os.Bundle import android.os.Handler import android.os.Looper import android.os.SystemClock +import android.text.Editable +import android.text.TextWatcher import android.view.Choreographer import android.view.LayoutInflater import android.view.MotionEvent @@ -54,6 +56,7 @@ import io.github.lime3ds.android.databinding.FragmentEmulationBinding import io.github.lime3ds.android.display.PortraitScreenLayout import io.github.lime3ds.android.display.ScreenAdjustmentUtil import io.github.lime3ds.android.display.ScreenLayout +import io.github.lime3ds.android.features.settings.model.IntSetting import io.github.lime3ds.android.features.settings.model.SettingsViewModel import io.github.lime3ds.android.features.settings.ui.SettingsActivity import io.github.lime3ds.android.features.settings.utils.SettingsFile @@ -324,6 +327,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram SettingsFile.FILE_NAME_CONFIG, "" ) + true } @@ -786,7 +790,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram popupMenu.menuInflater.inflate(R.menu.menu_landscape_screen_layout, popupMenu.menu) - val layoutOptionMenuItem = when (EmulationMenuSettings.landscapeScreenLayout) { + val layoutOptionMenuItem = when (IntSetting.SCREEN_LAYOUT.int) { + ScreenLayout.ORIGINAL.int -> + R.id.menu_screen_layout_original + ScreenLayout.SINGLE_SCREEN.int -> R.id.menu_screen_layout_single @@ -825,7 +832,17 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram true } + R.id.menu_screen_layout_original -> { + screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.ORIGINAL.int) + true + } + R.id.menu_screen_layout_custom -> { + Toast.makeText( + requireContext(), + R.string.emulation_adjust_custom_layout, + Toast.LENGTH_LONG + ).show() screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.CUSTOM_LAYOUT.int) true } @@ -845,7 +862,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram popupMenu.menuInflater.inflate(R.menu.menu_portrait_screen_layout, popupMenu.menu) - val layoutOptionMenuItem = when (EmulationMenuSettings.portraitScreenLayout) { + val layoutOptionMenuItem = when (IntSetting.PORTRAIT_SCREEN_LAYOUT.int) { PortraitScreenLayout.TOP_FULL_WIDTH.int -> R.id.menu_portrait_layout_top_full @@ -867,6 +884,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram } R.id.menu_portrait_layout_custom -> { + Toast.makeText( + requireContext(), + R.string.emulation_adjust_custom_layout, + Toast.LENGTH_LONG + ).show() screenAdjustmentUtil.changePortraitOrientation(PortraitScreenLayout.CUSTOM_PORTRAIT_LAYOUT.int) true } @@ -919,14 +941,32 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram sliderBinding.apply { slider.valueTo = 150f + slider.valueFrom = 0f slider.value = preferences.getInt(target, 50).toFloat() + textValue.setText((slider.value + 50).toInt().toString()) + textValue.addTextChangedListener( object : TextWatcher { + override fun afterTextChanged(s: Editable) { + val value = s.toString().toIntOrNull() + if (value == null || value < 50 || value > 150) { + textInput.error = "Inappropriate Value" + } else { + textInput.error = null + slider.value = value.toFloat() - 50 + } + } + override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} + override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} + }) slider.addOnChangeListener( Slider.OnChangeListener { slider: Slider, progress: Float, _: Boolean -> - textValue.text = (progress.toInt() + 50).toString() - setControlScale(slider.value.toInt(), target) + if (textValue.text.toString() != (slider.value + 50).toInt().toString()) { + textValue.setText((slider.value + 50).toInt().toString()) + textValue.setSelection(textValue.length()) + setControlScale(slider.value.toInt(), target) + } + }) - textValue.text = (sliderBinding.slider.value.toInt() + 50).toString() - textUnits.text = "%" + textInput.suffixText = "%" } val previousProgress = sliderBinding.slider.value.toInt() @@ -949,15 +989,36 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram val sliderBinding = DialogSliderBinding.inflate(layoutInflater) sliderBinding.apply { + slider.valueFrom = 0f slider.valueTo = 100f slider.value = preferences.getInt("controlOpacity", 50).toFloat() - slider.addOnChangeListener( - Slider.OnChangeListener { slider: Slider, progress: Float, _: Boolean -> - textValue.text = (progress.toInt()).toString() - setControlOpacity(slider.value.toInt()) - }) - textValue.text = (sliderBinding.slider.value.toInt()).toString() - textUnits.text = "%" + textValue.setText(slider.value.toInt().toString()) + + textValue.addTextChangedListener( object : TextWatcher { + override fun afterTextChanged(s: Editable) { + val value = s.toString().toIntOrNull() + if (value == null || value < slider.valueFrom || value > slider.valueTo) { + textInput.error = "Inappropriate Value" + } else { + textInput.error = null + slider.value = value.toFloat() + } + } + override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} + override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} + }) + + + slider.addOnChangeListener { _: Slider, value: Float, _: Boolean -> + + if (textValue.text.toString() != slider.value.toInt().toString()) { + textValue.setText(slider.value.toInt().toString()) + textValue.setSelection(textValue.length()) + setControlOpacity(slider.value.toInt()) + } + } + + textInput.suffixText = "%" } val previousProgress = sliderBinding.slider.value.toInt() @@ -986,7 +1047,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram private fun resetScale(target: String) { preferences.edit().putInt( target, - 50 + 100 ).apply() } diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/utils/EmulationMenuSettings.kt b/src/android/app/src/main/java/io/github/lime3ds/android/utils/EmulationMenuSettings.kt index eead8dc9e..d81db7ede 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/utils/EmulationMenuSettings.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/utils/EmulationMenuSettings.kt @@ -7,8 +7,6 @@ package io.github.lime3ds.android.utils import androidx.drawerlayout.widget.DrawerLayout import androidx.preference.PreferenceManager import io.github.lime3ds.android.LimeApplication -import io.github.lime3ds.android.display.PortraitScreenLayout -import io.github.lime3ds.android.display.ScreenLayout object EmulationMenuSettings { private val preferences = @@ -28,26 +26,7 @@ object EmulationMenuSettings { .putBoolean("EmulationMenuSettings_DpadSlideEnable", value) .apply() } - var landscapeScreenLayout: Int - get() = preferences.getInt( - "EmulationMenuSettings_LandscapeScreenLayout", - ScreenLayout.LARGE_SCREEN.int - ) - set(value) { - preferences.edit() - .putInt("EmulationMenuSettings_LandscapeScreenLayout", value) - .apply() - } - var portraitScreenLayout: Int - get() = preferences.getInt( - "EmulationMenuSettings_PortraitScreenLayout", - PortraitScreenLayout.TOP_FULL_WIDTH.int - ) - set(value) { - preferences.edit() - .putInt("EmulationMenuSettings_PortraitScreenLayout", value) - .apply() - } + var showFps: Boolean get() = preferences.getBoolean("EmulationMenuSettings_ShowFps", false) set(value) { diff --git a/src/android/app/src/main/jni/config.cpp b/src/android/app/src/main/jni/config.cpp index ff016a8e5..a880e3985 100644 --- a/src/android/app/src/main/jni/config.cpp +++ b/src/android/app/src/main/jni/config.cpp @@ -175,7 +175,6 @@ void Config::ReadValues() { // Layout Settings::values.layout_option = static_cast(sdl2_config->GetInteger( "Layout", "layout_option", static_cast(Settings::LayoutOption::LargeScreen))); - ReadSetting("Layout", Settings::values.custom_layout); 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 e7e67e646..544c0c716 100644 --- a/src/android/app/src/main/jni/default_ini.h +++ b/src/android/app/src/main/jni/default_ini.h @@ -180,16 +180,19 @@ filter_mode = [Layout] # Layout for the screen inside the render window, landscape mode -# 0 (default): Default Top Bottom Screen, +# 0: Top/Bottom *currently unsupported on android* # 1: Single Screen Only, -# 2: Large Screen Small Screen +# 2: *currently unsupported on android* # 3: Side by Side # 4: Hybrid # 5: Custom Layout +# 6: (default) Large screen / small screen layout_option = # Screen placement when using Custom layout option # 0x, 0y is the top left corner of the render window. +# suggested aspect ratio for top screen is 5:3 +# suggested aspect ratio for bottom screen is 4:3 custom_top_x = custom_top_y = custom_top_width = diff --git a/src/android/app/src/main/jni/emu_window/emu_window.cpp b/src/android/app/src/main/jni/emu_window/emu_window.cpp index c589ce54c..6442c3b88 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.cpp +++ b/src/android/app/src/main/jni/emu_window/emu_window.cpp @@ -21,18 +21,6 @@ static bool IsPortraitMode() { IDCache::GetNativeLibraryClass(), IDCache::GetIsPortraitMode()); } -static void UpdateLandscapeScreenLayout() { - Settings::values.layout_option = - static_cast(IDCache::GetEnvForThread()->CallStaticIntMethod( - IDCache::GetNativeLibraryClass(), IDCache::GetLandscapeScreenLayout())); -} - -static void UpdatePortraitScreenLayout() { - Settings::values.portrait_layout_option = - static_cast(IDCache::GetEnvForThread()->CallStaticIntMethod( - IDCache::GetNativeLibraryClass(), IDCache::GetPortraitScreenLayout())); -} - bool EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { if (render_window == surface) { return false; @@ -63,8 +51,6 @@ void EmuWindow_Android::OnTouchMoved(int x, int y) { } void EmuWindow_Android::OnFramebufferSizeChanged() { - UpdateLandscapeScreenLayout(); - UpdatePortraitScreenLayout(); const bool is_portrait_mode{IsPortraitMode()}; const int bigger{window_width > window_height ? window_width : window_height}; diff --git a/src/android/app/src/main/jni/id_cache.cpp b/src/android/app/src/main/jni/id_cache.cpp index b3bf27f96..c9cb0baca 100644 --- a/src/android/app/src/main/jni/id_cache.cpp +++ b/src/android/app/src/main/jni/id_cache.cpp @@ -177,10 +177,6 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) { s_native_library_class, "onCoreError", "(Lio/github/lime3ds/android/NativeLibrary$CoreError;Ljava/lang/String;)Z"); s_is_portrait_mode = env->GetStaticMethodID(s_native_library_class, "isPortraitMode", "()Z"); - s_landscape_screen_layout = - env->GetStaticMethodID(s_native_library_class, "landscapeScreenLayout", "()I"); - s_portrait_screen_layout = - env->GetStaticMethodID(s_native_library_class, "portraitScreenLayout", "()I"); s_exit_emulation_activity = env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V"); s_request_camera_permission = diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index ff1636730..c9ddcf863 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -346,29 +346,13 @@ void JNICALL Java_io_github_lime3ds_android_NativeLibrary_enableAdrenoTurboMode( EnableAdrenoTurboMode(enable); } -void Java_io_github_lime3ds_android_NativeLibrary_notifyOrientationChange( - [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj, jint layout_option, jint rotation, - jboolean portrait) { - Settings::values.layout_option = static_cast(layout_option); +void Java_io_github_lime3ds_android_NativeLibrary_updateFramebuffer([[maybe_unused]] JNIEnv* env, + [[maybe_unused]] jobject obj, + jboolean is_portrait_mode) { auto& system = Core::System::GetInstance(); if (system.IsPoweredOn()) { - - system.GPU().Renderer().UpdateCurrentFramebufferLayout(portrait); + system.GPU().Renderer().UpdateCurrentFramebufferLayout(is_portrait_mode); } - InputManager::screen_rotation = rotation; - Camera::NDK::g_rotation = rotation; -} - -void Java_io_github_lime3ds_android_NativeLibrary_notifyPortraitLayoutChange( - [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj, jint layout_option, jint rotation) { - Settings::values.portrait_layout_option = - static_cast(layout_option); - auto& system = Core::System::GetInstance(); - if (system.IsPoweredOn()) { - system.GPU().Renderer().UpdateCurrentFramebufferLayout(!(rotation % 2)); - } - InputManager::screen_rotation = rotation; - Camera::NDK::g_rotation = rotation; } void Java_io_github_lime3ds_android_NativeLibrary_swapScreens([[maybe_unused]] JNIEnv* env, diff --git a/src/android/app/src/main/res/drawable/ic_portrait_fit_screen.xml b/src/android/app/src/main/res/drawable/ic_portrait_fit_screen.xml new file mode 100644 index 000000000..299572089 --- /dev/null +++ b/src/android/app/src/main/res/drawable/ic_portrait_fit_screen.xml @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/src/android/app/src/main/res/layout/dialog_slider.xml b/src/android/app/src/main/res/layout/dialog_slider.xml index 59719e013..cb0cb2207 100644 --- a/src/android/app/src/main/res/layout/dialog_slider.xml +++ b/src/android/app/src/main/res/layout/dialog_slider.xml @@ -1,6 +1,7 @@ @@ -13,25 +14,30 @@ android:layout_marginRight="@dimen/spacing_large" android:layout_alignParentEnd="true" android:layout_alignParentStart="true" - android:layout_below="@+id/text_value" + android:layout_below="@+id/text_input" android:layout_marginBottom="@dimen/spacing_medlarge" /> - + + + android:id="@+id/text_value" + android:layout_alignParentTop="true" + android:layout_centerHorizontal="true" + android:layout_marginTop="@dimen/spacing_medlarge" + android:layout_marginBottom="@dimen/spacing_medlarge" /> - + diff --git a/src/android/app/src/main/res/menu/menu_emulation.xml b/src/android/app/src/main/res/menu/menu_emulation.xml deleted file mode 100644 index d09f99d93..000000000 --- a/src/android/app/src/main/res/menu/menu_emulation.xml +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/android/app/src/main/res/menu/menu_in_game.xml b/src/android/app/src/main/res/menu/menu_in_game.xml index 4dcfdcb47..d42d59264 100644 --- a/src/android/app/src/main/res/menu/menu_in_game.xml +++ b/src/android/app/src/main/res/menu/menu_in_game.xml @@ -29,12 +29,13 @@ + + + diff --git a/src/android/app/src/main/res/menu/menu_portrait_screen_layout.xml b/src/android/app/src/main/res/menu/menu_portrait_screen_layout.xml index 33bb729a6..afa9f27e0 100644 --- a/src/android/app/src/main/res/menu/menu_portrait_screen_layout.xml +++ b/src/android/app/src/main/res/menu/menu_portrait_screen_layout.xml @@ -10,6 +10,7 @@ + diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index 0cb329253..3439f727b 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -11,6 +11,37 @@ 1 + + @string/emulation_screen_layout_landscape + @string/emulation_screen_layout_single + @string/emulation_screen_layout_sidebyside + @string/emulation_screen_layout_hybrid + @string/emulation_screen_layout_original + @string/emulation_screen_layout_custom + + + + 6 + 1 + 3 + 4 + 0 + 5 + + + + @string/emulation_portrait_layout_top_full + @string/emulation_screen_layout_custom + + + + 0 + 1 + + @string/auto_select @string/system_region_jpn diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 744683d30..21a39d58e 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -330,7 +330,7 @@ Audio Debug Theme and Color - + Layout Your ROM is Encrypted Invalid ROM format @@ -365,8 +365,18 @@ Single Screen Side by Side Screens Hybrid Screens + Original Default Custom Layout + Adjust Custom Layout in Settings + Landscape Custom Layout + Portrait Custom Layout + Top Screen + Bottom Screen + X-Position + Y-Position + Width + Height Cycle Layouts Swap Screens Reset Overlay diff --git a/src/common/settings.h b/src/common/settings.h index 4d91f81b4..d2c6fd938 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -490,9 +490,6 @@ struct Values { SwitchableSetting upright_screen{false, "upright_screen"}; SwitchableSetting large_screen_proportion{4.f, 1.f, 16.f, "large_screen_proportion"}; - // I think the custom_layout setting below is no longer needed - // since custom layout is now just part of the layout option above? - Setting custom_layout{false, "custom_layout"}; Setting custom_top_x{0, "custom_top_x"}; Setting custom_top_y{0, "custom_top_y"}; Setting custom_top_width{800, "custom_top_width"}; diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index 8c67aa7c1..b2e74cf9b 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp @@ -121,7 +121,7 @@ FramebufferLayout PortraitTopFullFrameLayout(u32 width, u32 height, bool swapped ASSERT(width > 0); ASSERT(height > 0); - FramebufferLayout res{width, height, true, true, {}, {}}; + FramebufferLayout res{width, height, true, true, {}, {}, true, true}; // Default layout gives equal screen sizes to the top and bottom screen Common::Rectangle screen_window_area{0, 0, width, height / 2}; Common::Rectangle top_screen = MaxRectangle(screen_window_area, TOP_SCREEN_ASPECT_RATIO); @@ -305,7 +305,7 @@ FramebufferLayout HybridScreenLayout(u32 width, u32 height, bool swapped, bool u ASSERT(width > 0); ASSERT(height > 0); - FramebufferLayout res{width, height, true, true, {}, {}, !upright, true, {}}; + FramebufferLayout res{width, height, true, true, {}, {}, !upright, false, true, {}}; // Split the window into two parts. Give 2.25x width to the main screen, // and make a bar on the right side with 1x width top screen and 1.25x width bottom screen @@ -386,7 +386,8 @@ FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped, bool ASSERT(width > 0); ASSERT(height > 0); - FramebufferLayout res{width, height, true, true, {}, {}, !Settings::values.upright_screen}; + FramebufferLayout res{ + width, height, true, true, {}, {}, !Settings::values.upright_screen, is_portrait_mode}; u16 top_x = is_portrait_mode ? Settings::values.custom_portrait_top_x.GetValue() : Settings::values.custom_top_x.GetValue(); u16 top_width = is_portrait_mode ? Settings::values.custom_portrait_top_width.GetValue() @@ -629,9 +630,7 @@ FramebufferLayout GetCardboardSettings(const FramebufferLayout& layout) { return new_layout; } -/*f - * TODO: remove this? - */ + std::pair GetMinimumSizeFromPortraitLayout() { u32 min_width, min_height; min_width = Core::kScreenTopWidth; diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h index 98565ed7c..054072006 100644 --- a/src/core/frontend/framebuffer_layout.h +++ b/src/core/frontend/framebuffer_layout.h @@ -61,7 +61,7 @@ struct FramebufferLayout { Common::Rectangle top_screen; Common::Rectangle bottom_screen; bool is_rotated = true; - + bool is_portrait = false; bool additional_screen_enabled; Common::Rectangle additional_screen; diff --git a/src/lime/config.cpp b/src/lime/config.cpp index 49962b1d2..81c520bf5 100644 --- a/src/lime/config.cpp +++ b/src/lime/config.cpp @@ -164,8 +164,6 @@ void Config::ReadValues() { ReadSetting("Layout", Settings::values.swap_screen); ReadSetting("Layout", Settings::values.upright_screen); ReadSetting("Layout", Settings::values.large_screen_proportion); - - ReadSetting("Layout", Settings::values.custom_layout); 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/lime/default_ini.h b/src/lime/default_ini.h index fa1911971..a597a3839 100644 --- a/src/lime/default_ini.h +++ b/src/lime/default_ini.h @@ -182,7 +182,7 @@ filter_mode = [Layout] # Layout for the screen inside the render window. -# 0 (default): Default Top Bottom Screen +# 0 (default): Default Above/Below Screen # 1: Single Screen Only # 2: Large Screen Small Screen # 3: Side by Side @@ -191,10 +191,6 @@ filter_mode = # 6: Custom Layout layout_option = -# Toggle custom layout (using the settings below) on or off. -# 0 (default): Off, 1: On -custom_layout = - # Screen placement when using Custom layout option # 0x, 0y is the top left corner of the render window. custom_top_x = diff --git a/src/lime_qt/configuration/config.cpp b/src/lime_qt/configuration/config.cpp index ce5c632ac..349141dd5 100644 --- a/src/lime_qt/configuration/config.cpp +++ b/src/lime_qt/configuration/config.cpp @@ -520,8 +520,6 @@ void Config::ReadLayoutValues() { if (global) { ReadBasicSetting(Settings::values.mono_render_option); - - ReadBasicSetting(Settings::values.custom_layout); ReadBasicSetting(Settings::values.custom_top_x); ReadBasicSetting(Settings::values.custom_top_y); ReadBasicSetting(Settings::values.custom_top_width); @@ -1081,8 +1079,6 @@ void Config::SaveLayoutValues() { if (global) { WriteBasicSetting(Settings::values.mono_render_option); - - WriteBasicSetting(Settings::values.custom_layout); WriteBasicSetting(Settings::values.custom_top_x); WriteBasicSetting(Settings::values.custom_top_y); WriteBasicSetting(Settings::values.custom_top_width); diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 80cf549e9..1426ac380 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -634,10 +634,6 @@ void RendererOpenGL::DrawSingleScreenStereo(const ScreenInfo& screen_info_l, * Draws the emulated screens to the emulator window. */ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool flipped) { - bool isPortrait = false; -#ifdef ANDROID - isPortrait = layout.height > layout.width; -#endif if (settings.bg_color_update_requested.exchange(false)) { // Update background color before drawing glClearColor(Settings::values.bg_red.GetValue(), Settings::values.bg_green.GetValue(), @@ -679,12 +675,12 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f if (!Settings::values.swap_screen.GetValue()) { DrawTopScreen(layout, top_screen); glUniform1i(uniform_layer, 0); - ApplySecondLayerOpacity(isPortrait); + ApplySecondLayerOpacity(layout.is_portrait); DrawBottomScreen(layout, bottom_screen); } else { DrawBottomScreen(layout, bottom_screen); glUniform1i(uniform_layer, 0); - ApplySecondLayerOpacity(isPortrait); + ApplySecondLayerOpacity(layout.is_portrait); DrawTopScreen(layout, top_screen); } @@ -696,19 +692,14 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f DrawBottomScreen(layout, additional_screen); } } - ResetSecondLayerOpacity(isPortrait); + ResetSecondLayerOpacity(layout.is_portrait); } void RendererOpenGL::ApplySecondLayerOpacity(bool isPortrait) { -#ifdef ANDROID // TODO: Allow for second layer opacity in portrait mode android - if (isPortrait) { - return; - } -#endif - if ((Settings::values.layout_option.GetValue() == Settings::LayoutOption::CustomLayout || - Settings::values.custom_layout) && + if (!isPortrait && + (Settings::values.layout_option.GetValue() == Settings::LayoutOption::CustomLayout) && Settings::values.custom_second_layer_opacity.GetValue() < 100) { state.blend.src_rgb_func = GL_CONSTANT_ALPHA; state.blend.src_a_func = GL_CONSTANT_ALPHA; @@ -719,15 +710,8 @@ void RendererOpenGL::ApplySecondLayerOpacity(bool isPortrait) { } void RendererOpenGL::ResetSecondLayerOpacity(bool isPortrait) { -#ifdef ANDROID - // TODO: Allow for second layer opacity in portrait mode android - if (isPortrait) { - return; - } -#endif - - if ((Settings::values.layout_option.GetValue() == Settings::LayoutOption::CustomLayout || - Settings::values.custom_layout) && + if (!isPortrait && + (Settings::values.layout_option.GetValue() == Settings::LayoutOption::CustomLayout) && Settings::values.custom_second_layer_opacity.GetValue() < 100) { state.blend.src_rgb_func = GL_ONE; state.blend.dst_rgb_func = GL_ZERO; From 8b2b833d1f0f61bd430333b022e600e216f819ae Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Sun, 11 Aug 2024 16:17:35 +0100 Subject: [PATCH 07/19] Updated file license headers --- .../src/main/java/io/github/lime3ds/android/NativeLibrary.kt | 2 +- .../io/github/lime3ds/android/display/ScreenAdjustmentUtil.kt | 2 +- .../main/java/io/github/lime3ds/android/display/ScreenLayout.kt | 2 +- .../lime3ds/android/features/settings/model/BooleanSetting.kt | 2 +- .../lime3ds/android/features/settings/model/IntSetting.kt | 2 +- .../github/lime3ds/android/features/settings/model/Settings.kt | 2 +- .../android/features/settings/ui/SettingsActivityPresenter.kt | 2 +- .../lime3ds/android/features/settings/ui/SettingsAdapter.kt | 2 +- .../android/features/settings/ui/SettingsFragmentPresenter.kt | 2 +- .../io/github/lime3ds/android/fragments/EmulationFragment.kt | 2 +- .../io/github/lime3ds/android/utils/EmulationMenuSettings.kt | 2 +- src/android/app/src/main/jni/config.cpp | 2 +- src/android/app/src/main/jni/default_ini.h | 2 +- src/android/app/src/main/jni/emu_window/emu_window.cpp | 2 +- src/android/app/src/main/jni/id_cache.cpp | 2 +- src/android/app/src/main/jni/id_cache.h | 2 +- src/android/app/src/main/jni/native.cpp | 2 +- src/common/settings.cpp | 2 +- src/common/settings.h | 2 +- src/core/frontend/emu_window.cpp | 2 +- src/core/frontend/framebuffer_layout.cpp | 2 +- src/core/frontend/framebuffer_layout.h | 2 +- src/lime/config.cpp | 2 +- src/lime/default_ini.h | 2 +- src/lime_qt/configuration/config.cpp | 2 +- src/video_core/renderer_opengl/renderer_opengl.cpp | 2 +- src/video_core/renderer_opengl/renderer_opengl.h | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/NativeLibrary.kt b/src/android/app/src/main/java/io/github/lime3ds/android/NativeLibrary.kt index 6aa59e513..79b77f77c 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/NativeLibrary.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/NativeLibrary.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenAdjustmentUtil.kt b/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenAdjustmentUtil.kt index 035da2487..863b0ba2c 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenAdjustmentUtil.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenAdjustmentUtil.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenLayout.kt b/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenLayout.kt index 293b2a605..b7617a85d 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenLayout.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/display/ScreenLayout.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/BooleanSetting.kt index d4e15543a..5c2439683 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/BooleanSetting.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/IntSetting.kt index 8e6c1942d..25991f002 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/IntSetting.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/IntSetting.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/Settings.kt b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/Settings.kt index 32227833b..f0106d21c 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/Settings.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/model/Settings.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsActivityPresenter.kt b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsActivityPresenter.kt index 6e04bd8d5..9197081dd 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsActivityPresenter.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsActivityPresenter.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsAdapter.kt b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsAdapter.kt index d50269eff..4f73ec2b2 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsAdapter.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsAdapter.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsFragmentPresenter.kt index 18448ce1e..fbf4c6fcb 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsFragmentPresenter.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/fragments/EmulationFragment.kt b/src/android/app/src/main/java/io/github/lime3ds/android/fragments/EmulationFragment.kt index a67d4a775..87460d172 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/fragments/EmulationFragment.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/utils/EmulationMenuSettings.kt b/src/android/app/src/main/java/io/github/lime3ds/android/utils/EmulationMenuSettings.kt index d81db7ede..8932da0f1 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/utils/EmulationMenuSettings.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/utils/EmulationMenuSettings.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/android/app/src/main/jni/config.cpp b/src/android/app/src/main/jni/config.cpp index a880e3985..fb3549b0d 100644 --- a/src/android/app/src/main/jni/config.cpp +++ b/src/android/app/src/main/jni/config.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/android/app/src/main/jni/default_ini.h b/src/android/app/src/main/jni/default_ini.h index 544c0c716..1e2d6c8fe 100644 --- a/src/android/app/src/main/jni/default_ini.h +++ b/src/android/app/src/main/jni/default_ini.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/android/app/src/main/jni/emu_window/emu_window.cpp b/src/android/app/src/main/jni/emu_window/emu_window.cpp index 6442c3b88..677de440b 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.cpp +++ b/src/android/app/src/main/jni/emu_window/emu_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2019 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/android/app/src/main/jni/id_cache.cpp b/src/android/app/src/main/jni/id_cache.cpp index c9cb0baca..30d5a8b7b 100644 --- a/src/android/app/src/main/jni/id_cache.cpp +++ b/src/android/app/src/main/jni/id_cache.cpp @@ -1,4 +1,4 @@ -// Copyright 2019 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/android/app/src/main/jni/id_cache.h b/src/android/app/src/main/jni/id_cache.h index 71a1cb67c..5b083814f 100644 --- a/src/android/app/src/main/jni/id_cache.h +++ b/src/android/app/src/main/jni/id_cache.h @@ -1,4 +1,4 @@ -// Copyright 2019 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index c9ddcf863..a421119de 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -1,4 +1,4 @@ -// Copyright 2019 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/common/settings.cpp b/src/common/settings.cpp index e53644328..6431e9301 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/common/settings.h b/src/common/settings.h index d2c6fd938..256f6858a 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index b3733f892..4962c76f3 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index b2e74cf9b..c03926cbf 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h index 054072006..510035dc8 100644 --- a/src/core/frontend/framebuffer_layout.h +++ b/src/core/frontend/framebuffer_layout.h @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/lime/config.cpp b/src/lime/config.cpp index 81c520bf5..4bc59945c 100644 --- a/src/lime/config.cpp +++ b/src/lime/config.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/lime/default_ini.h b/src/lime/default_ini.h index a597a3839..731e0127c 100644 --- a/src/lime/default_ini.h +++ b/src/lime/default_ini.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/lime_qt/configuration/config.cpp b/src/lime_qt/configuration/config.cpp index 349141dd5..547174f0f 100644 --- a/src/lime_qt/configuration/config.cpp +++ b/src/lime_qt/configuration/config.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 1426ac380..b30e1f75e 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -1,4 +1,4 @@ -// Copyright 2022 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 7885a2f5b..c589ed68d 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -1,4 +1,4 @@ -// Copyright 2022 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. From 9a5fa363f22845473f8a158e0a3ba3409580e9de Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Sun, 11 Aug 2024 19:02:14 +0100 Subject: [PATCH 08/19] The emulator is called Lime3DS, not Lime --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- src/lime/lime.cpp | 2 +- src/lime_qt/main.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 563ae0a18..0432d4b6e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -4,7 +4,7 @@ labels: ["bug"] body: - type: markdown attributes: - value: Tech support does not belong here. You should only file an issue here if you think you have experienced an actual bug with Lime. + value: Tech support does not belong here. You should only file an issue here if you think you have experienced an actual bug with Lime3DS. - type: checkboxes attributes: label: Is there an existing issue for this? diff --git a/src/lime/lime.cpp b/src/lime/lime.cpp index e04eaef7a..f7a41cdd5 100644 --- a/src/lime/lime.cpp +++ b/src/lime/lime.cpp @@ -415,7 +415,7 @@ int main(int argc, char** argv) { return -1; case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted: LOG_CRITICAL(Frontend, "The game that you are trying to load must be decrypted before " - "being used with Lime. \n\n For more information on dumping and " + "being used with Lime3DS. \n\n For more information on dumping and " "decrypting games, please refer to: " "https://web.archive.org/web/20240304210021/https://citra-emu.org/" "wiki/dumping-game-cartridges/"); diff --git a/src/lime_qt/main.cpp b/src/lime_qt/main.cpp index f08aa4991..e763b7652 100644 --- a/src/lime_qt/main.cpp +++ b/src/lime_qt/main.cpp @@ -2196,7 +2196,7 @@ void GMainWindow::OnCIAInstallReport(Service::AM::InstallStatus status, QString case Service::AM::InstallStatus::ErrorEncrypted: QMessageBox::critical(this, tr("Encrypted File"), tr("%1 must be decrypted " - "before being used with Lime. A real 3DS is required.") + "before being used with Lime3DS. A real 3DS is required.") .arg(filename)); break; case Service::AM::InstallStatus::ErrorFileNotFound: From b825ba43bd32d351a03caaf0c3fde71f91e063ea Mon Sep 17 00:00:00 2001 From: Gamer64 <76565986+Gamer64ytb@users.noreply.github.com> Date: Tue, 13 Aug 2024 21:17:49 +0200 Subject: [PATCH 09/19] Android: Fix buttons scale reset --- .../io/github/lime3ds/android/fragments/EmulationFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/fragments/EmulationFragment.kt b/src/android/app/src/main/java/io/github/lime3ds/android/fragments/EmulationFragment.kt index 87460d172..3d7407436 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/fragments/EmulationFragment.kt @@ -1047,7 +1047,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram private fun resetScale(target: String) { preferences.edit().putInt( target, - 100 + 50 ).apply() } From 5a5e4c9de16597518efdd64f621fbc09bc9d2749 Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Tue, 13 Aug 2024 21:49:59 +0100 Subject: [PATCH 10/19] SettingsAdapter.kt: Removed stray commented code --- .../lime3ds/android/features/settings/ui/SettingsAdapter.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsAdapter.kt b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsAdapter.kt index 4f73ec2b2..0ecfb5384 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsAdapter.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsAdapter.kt @@ -265,7 +265,6 @@ class SettingsAdapter( textInputLayout = sliderBinding.textInput textSliderValue = sliderBinding.textValue textSliderValue!!.setText(sliderProgress.toString()) - //sliderBinding.textUnits.text = item.units textInputLayout!!.suffixText = item.units sliderBinding.slider.apply { From 1e1a61ed2b1da1335b5c3a1d2836736761041a95 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Mon, 12 Aug 2024 15:02:51 +0100 Subject: [PATCH 11/19] The emulator is called Lime3DS, not Lime --- src/lime_qt/main.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lime_qt/main.ui b/src/lime_qt/main.ui index 32a85f8ff..d54b17378 100644 --- a/src/lime_qt/main.ui +++ b/src/lime_qt/main.ui @@ -302,7 +302,7 @@ - About Lime + About Lime3DS QAction::AboutRole From afe9ee8e267e85a538647c3d4c26ef83a3d29b14 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Tue, 13 Aug 2024 23:14:44 +0100 Subject: [PATCH 12/19] SettingsAdapter.kt: Removed duplicate string --- .../android/features/settings/ui/SettingsFragmentPresenter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsFragmentPresenter.kt index fbf4c6fcb..68a1cab0f 100644 --- a/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/io/github/lime3ds/android/features/settings/ui/SettingsFragmentPresenter.kt @@ -905,7 +905,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) } private fun addLayoutSettings(sl: ArrayList) { - settingsActivity.setToolbarTitle("Layout") + settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_layout)) sl.apply { add( SingleChoiceSetting( From 282b22b784afbf04ff5f16e6945c0a20d190ffcd Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Wed, 14 Aug 2024 13:16:24 +0100 Subject: [PATCH 13/19] Repurposed the Report Compatibility button The button now redirects to Lime3DS's compatibility-list repository This commit also removes the `CITRA_ENABLE_COMPATIBILITY_REPORTING` cmake option for obvious reasons --- .ci/linux.sh | 1 - .ci/macos.sh | 1 - .ci/windows.sh | 1 - src/lime_qt/CMakeLists.txt | 7 -- src/lime_qt/compatdb.cpp | 81 -------------- src/lime_qt/compatdb.h | 30 ------ src/lime_qt/compatdb.ui | 215 ------------------------------------- src/lime_qt/main.cpp | 21 +--- src/lime_qt/main.h | 3 +- src/lime_qt/main.ui | 6 -- 10 files changed, 5 insertions(+), 361 deletions(-) delete mode 100644 src/lime_qt/compatdb.cpp delete mode 100644 src/lime_qt/compatdb.h delete mode 100644 src/lime_qt/compatdb.ui diff --git a/.ci/linux.sh b/.ci/linux.sh index af07c1b05..10219eef3 100755 --- a/.ci/linux.sh +++ b/.ci/linux.sh @@ -19,7 +19,6 @@ cmake .. -G Ninja \ -DCMAKE_C_COMPILER=clang-18 \ "${EXTRA_CMAKE_FLAGS[@]}" \ -DENABLE_QT_TRANSLATION=ON \ - -DCITRA_ENABLE_COMPATIBILITY_REPORTING=ON \ -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \ -DUSE_DISCORD_PRESENCE=ON ninja diff --git a/.ci/macos.sh b/.ci/macos.sh index c4e2a284b..d666e64bb 100755 --- a/.ci/macos.sh +++ b/.ci/macos.sh @@ -7,7 +7,6 @@ cmake .. -GNinja \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DENABLE_QT_TRANSLATION=ON \ - -DCITRA_ENABLE_COMPATIBILITY_REPORTING=ON \ -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \ -DUSE_DISCORD_PRESENCE=ON ninja diff --git a/.ci/windows.sh b/.ci/windows.sh index db7ea6255..2762ed43e 100644 --- a/.ci/windows.sh +++ b/.ci/windows.sh @@ -6,7 +6,6 @@ cmake .. -G Ninja \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DENABLE_QT_TRANSLATION=ON \ - -DCITRA_ENABLE_COMPATIBILITY_REPORTING=ON \ -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \ -DUSE_DISCORD_PRESENCE=ON ninja diff --git a/src/lime_qt/CMakeLists.txt b/src/lime_qt/CMakeLists.txt index e508736c5..a2f14f40a 100644 --- a/src/lime_qt/CMakeLists.txt +++ b/src/lime_qt/CMakeLists.txt @@ -28,9 +28,6 @@ add_executable(lime-qt camera/qt_multimedia_camera.cpp camera/qt_multimedia_camera.h lime-qt.rc - compatdb.cpp - compatdb.h - compatdb.ui configuration/config.cpp configuration/config.h configuration/configure.ui @@ -334,10 +331,6 @@ target_compile_definitions(lime-qt PRIVATE -DQT_NO_CAST_TO_ASCII ) -if (CITRA_ENABLE_COMPATIBILITY_REPORTING) - target_compile_definitions(lime-qt PRIVATE -DCITRA_ENABLE_COMPATIBILITY_REPORTING) -endif() - if (USE_DISCORD_PRESENCE) target_sources(lime-qt PUBLIC discord_impl.cpp diff --git a/src/lime_qt/compatdb.cpp b/src/lime_qt/compatdb.cpp deleted file mode 100644 index 506706fe9..000000000 --- a/src/lime_qt/compatdb.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include "core/core.h" -#include "lime_qt/compatdb.h" -#include "ui_compatdb.h" - -CompatDB::CompatDB(QWidget* parent) - : QWizard(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), - ui{std::make_unique()} { - ui->setupUi(this); - connect(ui->radioButton_Perfect, &QRadioButton::clicked, this, &CompatDB::EnableNext); - connect(ui->radioButton_Great, &QRadioButton::clicked, this, &CompatDB::EnableNext); - connect(ui->radioButton_Okay, &QRadioButton::clicked, this, &CompatDB::EnableNext); - connect(ui->radioButton_Bad, &QRadioButton::clicked, this, &CompatDB::EnableNext); - connect(ui->radioButton_IntroMenu, &QRadioButton::clicked, this, &CompatDB::EnableNext); - connect(ui->radioButton_WontBoot, &QRadioButton::clicked, this, &CompatDB::EnableNext); - connect(button(NextButton), &QPushButton::clicked, this, &CompatDB::Submit); - connect(&testcase_watcher, &QFutureWatcher::finished, this, - &CompatDB::OnTestcaseSubmitted); -} - -CompatDB::~CompatDB() = default; - -enum class CompatDBPage { - Intro = 0, - Selection = 1, - Final = 2, -}; - -void CompatDB::Submit() { - QButtonGroup* compatibility = new QButtonGroup(this); - compatibility->addButton(ui->radioButton_Perfect, 0); - compatibility->addButton(ui->radioButton_Great, 1); - compatibility->addButton(ui->radioButton_Okay, 2); - compatibility->addButton(ui->radioButton_Bad, 3); - compatibility->addButton(ui->radioButton_IntroMenu, 4); - compatibility->addButton(ui->radioButton_WontBoot, 5); - switch ((static_cast(currentId()))) { - case CompatDBPage::Selection: - if (compatibility->checkedId() == -1) { - button(NextButton)->setEnabled(false); - } - break; - case CompatDBPage::Final: - back(); - LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId()); - - button(NextButton)->setEnabled(false); - button(NextButton)->setText(tr("Submitting")); - button(CancelButton)->setVisible(false); - - break; - default: - LOG_ERROR(Frontend, "Unexpected page: {}", currentId()); - } -} - -void CompatDB::OnTestcaseSubmitted() { - if (!testcase_watcher.result()) { - QMessageBox::critical(this, tr("Communication error"), - tr("An error occurred while sending the Testcase")); - button(NextButton)->setEnabled(true); - button(NextButton)->setText(tr("Next")); - button(CancelButton)->setVisible(true); - } else { - next(); - // older versions of QT don't support the "NoCancelButtonOnLastPage" option, this is a - // workaround - button(CancelButton)->setVisible(false); - } -} - -void CompatDB::EnableNext() { - button(NextButton)->setEnabled(true); -} diff --git a/src/lime_qt/compatdb.h b/src/lime_qt/compatdb.h deleted file mode 100644 index 5381f67f7..000000000 --- a/src/lime_qt/compatdb.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include - -namespace Ui { -class CompatDB; -} - -class CompatDB : public QWizard { - Q_OBJECT - -public: - explicit CompatDB(QWidget* parent = nullptr); - ~CompatDB(); - -private: - QFutureWatcher testcase_watcher; - - std::unique_ptr ui; - - void Submit(); - void OnTestcaseSubmitted(); - void EnableNext(); -}; diff --git a/src/lime_qt/compatdb.ui b/src/lime_qt/compatdb.ui deleted file mode 100644 index 12e409352..000000000 --- a/src/lime_qt/compatdb.ui +++ /dev/null @@ -1,215 +0,0 @@ - - - CompatDB - - - - 0 - 0 - 600 - 482 - - - - - 500 - 410 - - - - Report Compatibility - - - QWizard::DisabledBackButtonOnLastPage|QWizard::HelpButtonOnRight|QWizard::NoBackButtonOnStartPage - - - - Report Game Compatibility - - - 0 - - - - - - <html><head/><body><p><span style=" font-size:10pt;">Should you choose to submit a test case to the </span><a href="https://citra-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Lime3DS Compatibility List</span></a><span style=" font-size:10pt;">, The following information will be collected and displayed on the site:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hardware Information (CPU / GPU / Operating System)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Which version of Lime3DS you are running</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The connected Citra account</li></ul></body></html> - - - true - - - true - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - - Report Game Compatibility - - - 1 - - - - - - Perfect - - - - - - - <html><head/><body><p>Game functions flawlessly with no audio or graphical glitches.</p></body></html> - - - true - - - - - - - Great - - - - - - - <html><head/><body><p>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.</p></body></html> - - - true - - - - - - - Okay - - - - - - - <html><head/><body><p>Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.</p></body></html> - - - true - - - - - - - Bad - - - - - - - <html><head/><body><p>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.</p></body></html> - - - true - - - - - - - Intro/Menu - - - - - - - <html><head/><body><p>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.</p></body></html> - - - true - - - - - - - Won't Boot - - - true - - - false - - - - - - - <html><head/><body><p>The game crashes when attempting to startup.</p></body></html> - - - - - - - - 10 - - - - <html><head/><body><p>Independent of speed or performance, how well does this game play from start to finish on this version of Lime?</p></body></html> - - - true - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - - Thank you for your submission! - - - 2 - - - - - - diff --git a/src/lime_qt/main.cpp b/src/lime_qt/main.cpp index e763b7652..3b964a534 100644 --- a/src/lime_qt/main.cpp +++ b/src/lime_qt/main.cpp @@ -46,7 +46,6 @@ #include "lime_qt/bootmanager.h" #include "lime_qt/camera/qt_multimedia_camera.h" #include "lime_qt/camera/still_image_camera.h" -#include "lime_qt/compatdb.h" #include "lime_qt/compatibility_list.h" #include "lime_qt/configuration/config.h" #include "lime_qt/configuration/configure_dialog.h" @@ -97,7 +96,6 @@ #include "core/savestate.h" #include "core/system_titles.h" #include "input_common/main.h" -#include "network/network_settings.h" #include "ui_main.h" #include "video_core/gpu.h" #include "video_core/renderer_base.h" @@ -339,9 +337,6 @@ GMainWindow::~GMainWindow() { } void GMainWindow::InitializeWidgets() { -#ifdef CITRA_ENABLE_COMPATIBILITY_REPORTING - ui->action_Report_Compatibility->setVisible(true); -#endif render_window = new GRenderWindow(this, emu_thread.get(), system, false); secondary_window = new GRenderWindow(this, emu_thread.get(), system, true); render_window->hide(); @@ -904,7 +899,10 @@ void GMainWindow::ConnectMenuEvents() { connect_menu(ui->action_Pause, &GMainWindow::OnPauseContinueGame); connect_menu(ui->action_Stop, &GMainWindow::OnStopGame); connect_menu(ui->action_Restart, [this] { BootGame(QString(game_path)); }); - connect_menu(ui->action_Report_Compatibility, &GMainWindow::OnMenuReportCompatibility); + connect_menu(ui->action_Report_Compatibility, []() { + QDesktopServices::openUrl(QUrl(QStringLiteral( + "https://github.com/Lime3DS/compatibility-list/blob/master/CONTRIBUTING.md"))); + }); connect_menu(ui->action_Configure, &GMainWindow::OnConfigure); connect_menu(ui->action_Configure_Current_Game, &GMainWindow::OnConfigurePerGame); @@ -2358,17 +2356,6 @@ void GMainWindow::OnLoadComplete() { UpdateSecondaryWindowVisibility(); } -void GMainWindow::OnMenuReportCompatibility() { - if (!NetSettings::values.citra_token.empty() && !NetSettings::values.citra_username.empty()) { - CompatDB compatdb{this}; - compatdb.exec(); - } else { - QMessageBox::critical(this, tr("Missing Citra Account"), - tr("You must link your Citra account to submit test cases." - "
Go to Emulation > Configure... > Web to do so.")); - } -} - void GMainWindow::ToggleFullscreen() { if (!emulation_running) { return; diff --git a/src/lime_qt/main.h b/src/lime_qt/main.h index 774668bfa..249058901 100644 --- a/src/lime_qt/main.h +++ b/src/lime_qt/main.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -230,7 +230,6 @@ private slots: void OnStopGame(); void OnSaveState(); void OnLoadState(); - void OnMenuReportCompatibility(); /// Called whenever a user selects a game in the game list widget. void OnGameListLoadFile(QString game_path); void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target); diff --git a/src/lime_qt/main.ui b/src/lime_qt/main.ui index d54b17378..cfa6b2e69 100644 --- a/src/lime_qt/main.ui +++ b/src/lime_qt/main.ui @@ -560,15 +560,9 @@
- - false - Report Compatibility - - false - From b97e2f3d708dddf32cdae464ad98610abbba28cd Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Wed, 14 Aug 2024 14:52:55 +0100 Subject: [PATCH 14/19] Re-added .aab builds for Android --- .github/workflows/build.yml | 2 +- src/android/app/build.gradle.kts | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b39b52128..ee29593f4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -256,4 +256,4 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - asset_paths: '["./**/*.tar.*","./**/*.AppImage","./**/*.zip","./**/*.apk"]' + asset_paths: '["./**/*.tar.*","./**/*.AppImage","./**/*.zip","./**/*.apk","./**/*.aab",]' diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index 53f8d7549..7561ca055 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -268,6 +268,11 @@ android.applicationVariants.configureEach { include("*.apk") into(layout.buildDirectory.dir("bundle")) } + project.copy { + from(layout.buildDirectory.dir("outputs/bundle/${variant.name}")) + include("*.aab") + into(layout.buildDirectory.dir("bundle")) + } } } tasks.named("bundle${capitalizedName}").configure { finalizedBy(copyTask) } From 1447c481c7115ed6e8bd413228e8195e53e60320 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Thu, 8 Aug 2024 21:27:56 +0100 Subject: [PATCH 15/19] Fixed shortcut creation failing if icons directory structure doesn't already exist --- src/lime_qt/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lime_qt/main.cpp b/src/lime_qt/main.cpp index 3b964a534..6c288ff4b 100644 --- a/src/lime_qt/main.cpp +++ b/src/lime_qt/main.cpp @@ -1902,10 +1902,10 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi out_icon_path = FileUtil::GetUserPath(FileUtil::UserPath::IconsDir); ico_extension = "ico"; #elif defined(__linux__) || defined(__FreeBSD__) - out_icon_path = FileUtil::GetUserDirectory("XDG_DATA_HOME") + "/icons/hicolor/256x256"; + out_icon_path = FileUtil::GetUserDirectory("XDG_DATA_HOME") + "/icons/hicolor/256x256/"; #endif // Create icons directory if it doesn't exist - if (!FileUtil::CreateDir(out_icon_path.string())) { + if (!FileUtil::CreateFullPath(out_icon_path.string())) { QMessageBox::critical( this, tr("Create Icon"), tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") From 2cd1ea127712473de19e1d86bbde827eb7260677 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Mon, 12 Aug 2024 12:57:18 +0100 Subject: [PATCH 16/19] Removed Citra references from areas of shortcut generation code --- src/lime_qt/main.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/lime_qt/main.cpp b/src/lime_qt/main.cpp index 6c288ff4b..0dc7146cd 100644 --- a/src/lime_qt/main.cpp +++ b/src/lime_qt/main.cpp @@ -1896,7 +1896,7 @@ bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int message, bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, std::filesystem::path& out_icon_path) { - // Get path to Citra icons directory & icon extension + // Get path to Lime3DS icons directory & icon extension std::string ico_extension = "png"; #if defined(_WIN32) out_icon_path = FileUtil::GetUserPath(FileUtil::UserPath::IconsDir); @@ -1916,19 +1916,19 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi } // Create icon file path - out_icon_path /= (program_id == 0 ? fmt::format("citra-{}.{}", game_file_name, ico_extension) - : fmt::format("citra-{:016X}.{}", program_id, ico_extension)); + out_icon_path /= (program_id == 0 ? fmt::format("lime-{}.{}", game_file_name, ico_extension) + : fmt::format("lime-{:016X}.{}", program_id, ico_extension)); return true; } void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, GameListShortcutTarget target) { - // Get path to citra executable + // Get path to Lime3DS executable const QStringList args = QApplication::arguments(); - std::filesystem::path citra_command = args[0].toStdString(); + std::filesystem::path lime_command = args[0].toStdString(); // If relative path, make it an absolute path - if (citra_command.c_str()[0] == '.') { - citra_command = FileUtil::GetCurrentDir().value_or("") + DIR_SEP + citra_command.string(); + if (lime_command.c_str()[0] == '.') { + lime_command = FileUtil::GetCurrentDir().value_or("") + DIR_SEP + lime_command.string(); } // Shortcut path @@ -1984,7 +1984,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga // Warn once if we are making a shortcut to a volatile AppImage const std::string appimage_ending = std::string(Common::g_scm_rev).substr(0, 9).append(".AppImage"); - if (citra_command.string().ends_with(appimage_ending) && + if (lime_command.string().ends_with(appimage_ending) && !UISettings::values.shortcut_already_warned) { if (CreateShortcutMessagesGUI(this, CREATE_SHORTCUT_MSGBOX_APPIMAGE_VOLATILE_WARNING, qt_game_title)) { @@ -1998,11 +1998,11 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga if (CreateShortcutMessagesGUI(this, CREATE_SHORTCUT_MSGBOX_FULLSCREEN_PROMPT, qt_game_title)) { arguments = "-f " + arguments; } - const std::string comment = fmt::format("Start {:s} with the Citra Emulator", game_title); + const std::string comment = fmt::format("Start {:s} with the Lime3DS Emulator", game_title); const std::string categories = "Game;Emulator;Qt;"; const std::string keywords = "3ds;Nintendo;"; - if (CreateShortcutLink(shortcut_path, comment, out_icon_path, citra_command, arguments, + if (CreateShortcutLink(shortcut_path, comment, out_icon_path, lime_command, arguments, categories, keywords, game_title)) { CreateShortcutMessagesGUI(this, CREATE_SHORTCUT_MSGBOX_SUCCESS, qt_game_title); return; From 3262515c89042bccd682d29cbd98689afcb35c89 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Mon, 12 Aug 2024 14:54:44 +0100 Subject: [PATCH 17/19] Fixed shortcuts generated via Flatpak not working --- src/lime/lime.cpp | 2 +- src/lime_qt/main.cpp | 37 +++++++++++++++++++++++-------------- src/lime_qt/main.h | 8 ++++---- 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/lime/lime.cpp b/src/lime/lime.cpp index f7a41cdd5..b89a83c2a 100644 --- a/src/lime/lime.cpp +++ b/src/lime/lime.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/lime_qt/main.cpp b/src/lime_qt/main.cpp index 0dc7146cd..bcfbaf7f0 100644 --- a/src/lime_qt/main.cpp +++ b/src/lime_qt/main.cpp @@ -1764,9 +1764,9 @@ void GMainWindow::OnGameListRemovePlayTimeData(u64 program_id) { bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment, const std::filesystem::path& icon_path, - const std::filesystem::path& command, - const std::string& arguments, const std::string& categories, - const std::string& keywords, const std::string& name) try { + const std::string& command, const std::string& arguments, + const std::string& categories, const std::string& keywords, + const std::string& name, const bool& skip_tryexec) try { #if defined(__linux__) || defined(__FreeBSD__) // Linux and FreeBSD std::filesystem::path shortcut_path_full = shortcut_path / (name + ".desktop"); std::ofstream shortcut_stream(shortcut_path_full, std::ios::binary | std::ios::trunc); @@ -1785,8 +1785,10 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, if (std::filesystem::is_regular_file(icon_path)) { fmt::print(shortcut_stream, "Icon={}\n", icon_path.string()); } - fmt::print(shortcut_stream, "TryExec={}\n", command.string()); - fmt::print(shortcut_stream, "Exec={} {}\n", command.string(), arguments); + if (!skip_tryexec) { + fmt::print(shortcut_stream, "TryExec={}\n", command); + } + fmt::print(shortcut_stream, "Exec={} {}\n", command, arguments); if (!categories.empty()) { fmt::print(shortcut_stream, "Categories={}\n", categories); } @@ -1923,12 +1925,20 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, GameListShortcutTarget target) { - // Get path to Lime3DS executable - const QStringList args = QApplication::arguments(); - std::filesystem::path lime_command = args[0].toStdString(); - // If relative path, make it an absolute path - if (lime_command.c_str()[0] == '.') { - lime_command = FileUtil::GetCurrentDir().value_or("") + DIR_SEP + lime_command.string(); + std::string lime_command{}; + bool skip_tryexec = false; + const char* env_flatpak_id = getenv("FLATPAK_ID"); + if (env_flatpak_id) { + lime_command = fmt::format("flatpak run {}", env_flatpak_id); + skip_tryexec = true; + } else { + // Get path to Lime3DS executable + const QStringList args = QApplication::arguments(); + lime_command = args[0].toStdString(); + // If relative path, make it an absolute path + if (lime_command.c_str()[0] == '.') { + lime_command = FileUtil::GetCurrentDir().value_or("") + DIR_SEP + lime_command; + } } // Shortcut path @@ -1984,8 +1994,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga // Warn once if we are making a shortcut to a volatile AppImage const std::string appimage_ending = std::string(Common::g_scm_rev).substr(0, 9).append(".AppImage"); - if (lime_command.string().ends_with(appimage_ending) && - !UISettings::values.shortcut_already_warned) { + if (lime_command.ends_with(appimage_ending) && !UISettings::values.shortcut_already_warned) { if (CreateShortcutMessagesGUI(this, CREATE_SHORTCUT_MSGBOX_APPIMAGE_VOLATILE_WARNING, qt_game_title)) { return; @@ -2003,7 +2012,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga const std::string keywords = "3ds;Nintendo;"; if (CreateShortcutLink(shortcut_path, comment, out_icon_path, lime_command, arguments, - categories, keywords, game_title)) { + categories, keywords, game_title, skip_tryexec)) { CreateShortcutMessagesGUI(this, CREATE_SHORTCUT_MSGBOX_SUCCESS, qt_game_title); return; } diff --git a/src/lime_qt/main.h b/src/lime_qt/main.h index 249058901..ccdf0ce9a 100644 --- a/src/lime_qt/main.h +++ b/src/lime_qt/main.h @@ -217,10 +217,10 @@ private: bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, std::filesystem::path& out_icon_path); bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment, - const std::filesystem::path& icon_path, - const std::filesystem::path& command, const std::string& arguments, - const std::string& categories, const std::string& keywords, - const std::string& name); + const std::filesystem::path& icon_path, const std::string& command, + const std::string& arguments, const std::string& categories, + const std::string& keywords, const std::string& name, + const bool& skip_tryexec); private slots: void OnStartGame(); From a573f0f036d33c064e7483cca04f398bd56bd1b0 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Tue, 13 Aug 2024 20:25:25 +0100 Subject: [PATCH 18/19] Fixed incorrect applications directory path while using Flatpak build --- src/common/file_util.cpp | 9 ++++++--- src/common/file_util.h | 6 +++++- src/lime/lime.cpp | 2 +- src/lime_qt/main.cpp | 3 +-- src/lime_qt/util/util.cpp | 17 ++++++++++++++++- src/lime_qt/util/util.h | 7 ++++++- 6 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 08bafc37c..c9fe12002 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp @@ -1,7 +1,10 @@ -// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +// Copyright Dolphin Emulator Project +// Licensed under GPLv2 or any later version + #include #include #include @@ -707,8 +710,8 @@ std::string AppDataRoamingDirectory() { /** * @return The user’s home directory on POSIX systems */ -static const std::string& GetHomeDirectory() { - static std::string home_path; +const std::string GetHomeDirectory() { + std::string home_path; if (home_path.empty()) { const char* envvar = getenv("HOME"); if (envvar) { diff --git a/src/common/file_util.h b/src/common/file_util.h index c0fa49d7d..f0c53c15f 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h @@ -1,7 +1,10 @@ -// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +// Copyright Dolphin Emulator Project +// Licensed under GPLv2 or any later version + #pragma once #include @@ -207,6 +210,7 @@ void UpdateUserPath(UserPath path, const std::string& filename); [[nodiscard]] const std::string& GetExeDirectory(); [[nodiscard]] std::string AppDataRoamingDirectory(); #else +[[nodiscard]] const std::string GetHomeDirectory(); [[nodiscard]] const std::string GetUserDirectory(const std::string& envvar); #endif diff --git a/src/lime/lime.cpp b/src/lime/lime.cpp index b89a83c2a..f7a41cdd5 100644 --- a/src/lime/lime.cpp +++ b/src/lime/lime.cpp @@ -1,4 +1,4 @@ -// Copyright Citra Emulator Project / Lime3DS Emulator Project +// Copyright 2014 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/lime_qt/main.cpp b/src/lime_qt/main.cpp index bcfbaf7f0..7c968d594 100644 --- a/src/lime_qt/main.cpp +++ b/src/lime_qt/main.cpp @@ -1947,8 +1947,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga shortcut_path = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).toStdString(); } else if (target == GameListShortcutTarget::Applications) { - shortcut_path = - QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString(); + shortcut_path = GetApplicationsDirectory(); } // Icon path and title diff --git a/src/lime_qt/util/util.cpp b/src/lime_qt/util/util.cpp index cb14d376b..874b81012 100644 --- a/src/lime_qt/util/util.cpp +++ b/src/lime_qt/util/util.cpp @@ -1,10 +1,13 @@ -// Copyright 2015 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include #include #include +#include +#include "common/common_paths.h" +#include "common/file_util.h" #include "common/logging/log.h" #include "core/loader/smdh.h" #include "lime_qt/util/util.h" @@ -160,3 +163,15 @@ bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image) return false; #endif } + +const std::string GetApplicationsDirectory() { +// This alternate method is required for Flatpak compatibility as +// QStandardPaths::ApplicationsLocation returns a path inside the Flatpak data directory instead of +// $HOME/.local/share +#if defined(__linux__) || defined(__FreeBSD__) + return FileUtil::GetHomeDirectory() + DIR_SEP + ".local" + DIR_SEP + "share" + DIR_SEP + + "applications"; +#else + return QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString(); +#endif +} \ No newline at end of file diff --git a/src/lime_qt/util/util.h b/src/lime_qt/util/util.h index 67bd51a90..428d69ffd 100644 --- a/src/lime_qt/util/util.h +++ b/src/lime_qt/util/util.h @@ -1,4 +1,4 @@ -// Copyright 2015 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -36,3 +36,8 @@ QPixmap GetQPixmapFromSMDH(const std::vector& smdh_data); * @return bool If the operation succeeded */ [[nodiscard]] bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image); + +/** + * @return The user’s applications directory + */ +[[nodiscard]] const std::string GetApplicationsDirectory(); From b8fb57e040d2db3feb728f150a18d76a9bc90004 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Wed, 14 Aug 2024 11:35:30 +0100 Subject: [PATCH 19/19] main.cpp: Fixed compilation failure on MSYS2 --- src/lime_qt/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lime_qt/main.cpp b/src/lime_qt/main.cpp index 7c968d594..ed3da981c 100644 --- a/src/lime_qt/main.cpp +++ b/src/lime_qt/main.cpp @@ -1819,7 +1819,7 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, LOG_ERROR(Frontend, "Failed to create IShellLinkW instance"); return false; } - hres = ps1->SetPath(command.c_str()); + hres = ps1->SetPath(Common::UTF8ToUTF16W(command).data()); if (FAILED(hres)) { LOG_ERROR(Frontend, "Failed to set path"); return false;