From 080470d041f0e7842c2f4a79e25c6cedf5d51ffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 22 Oct 2026 23:06:07 +0200 Subject: [PATCH] Display layout: No editing while the TV shows a layout for another orientation With the game on a TV (landscape) and the device in portrait, the display layout screen edited the portrait layout, which the TV doesn't use, so nothing seemed to change. Its controls are now disabled in that case, and work as before with the device held the same way as the TV. The screen rotation hotkeys change the layout the game is shown with, the TV's, instead. Co-Authored-By: Claude Opus 5.5 (1M context) --- UI/DisplayLayoutScreen.cpp | 22 ++++++++++++++++++++++ UI/EmuScreen.cpp | 32 ++++++++++++++++++++++++++------ UI/EmuScreen.h | 3 +++ 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 6bb565d497..288f075283 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -38,6 +38,7 @@ #include "Common/Data/Color/RGBAUtil.h" #include "Common/Data/Text/I18n.h" #include "UI/DisplayLayoutScreen.h" +#include "UI/EmuScreen.h" #include "UI/Background.h" #include "UI/MiscViews.h" #include "Core/Config.h" @@ -200,6 +201,21 @@ void DisplayLayoutScreen::sendMessage(UIMessage message, const char *value) { } } +// Disables every control in the group, except keep. +static void DisableControls(UI::ViewGroup *group, const UI::View *keep) { + for (int i = 0; i < group->GetNumSubviews(); i++) { + UI::View *view = group->GetViewByIndex(i); + if (view == keep) { + continue; + } + if (view->IsViewGroup()) { + DisableControls((UI::ViewGroup *)view, keep); + } else { + view->SetEnabled(false); + } + } +} + void DisplayLayoutScreen::CreateViews() { const Bounds &bounds = screenManager()->getUIContext()->GetBounds(); @@ -568,6 +584,12 @@ void DisplayLayoutScreen::CreateViews() { } } + // With the game on a TV and the device held the other way, these would edit a layout that isn't shown. + DeviceOrientation gameOrientation; + if (GetGameOutputOrientation(screenManager(), &gameOrientation) && gameOrientation != GetDeviceOrientation()) { + DisableControls(root_, back); + } + root_->Add(new DisplayLayoutBackground(mode_, GetDeviceOrientation(), new AnchorLayoutParams(FILL_PARENT, FILL_PARENT, 0.0f, 0.0f, 0.0f, 0.0f))); } diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 48b2db3857..50e1229ce1 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -861,27 +861,28 @@ void EmuScreen::ProcessVKey(VirtKey virtKey, bool down) { } break; + // These change the layout the game is shown with, which on a TV isn't the device orientation's. case VIRTKEY_SCREEN_ROTATION_VERTICAL: if (down) { - DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(GetDeviceOrientation()); + DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(GameLayoutOrientation()); config.iInternalScreenRotation = ROTATION_LOCKED_VERTICAL; } break; case VIRTKEY_SCREEN_ROTATION_VERTICAL180: if (down) { - DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(GetDeviceOrientation()); + DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(GameLayoutOrientation()); config.iInternalScreenRotation = ROTATION_LOCKED_VERTICAL180; } break; case VIRTKEY_SCREEN_ROTATION_HORIZONTAL: if (down) { - DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(GetDeviceOrientation()); + DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(GameLayoutOrientation()); config.iInternalScreenRotation = ROTATION_LOCKED_HORIZONTAL; } break; case VIRTKEY_SCREEN_ROTATION_HORIZONTAL180: if (down) { - DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(GetDeviceOrientation()); + DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(GameLayoutOrientation()); config.iInternalScreenRotation = ROTATION_LOCKED_HORIZONTAL180; } break; @@ -1672,6 +1673,21 @@ ScreenRenderFlags EmuScreen::PreRender(ScreenRenderMode mode) { // Sends the game to a Game output, if there is one. Not in non-buffered mode, which draws straight // into the backbuffer during emulation. +static DeviceOrientation OutputOrientation(int width, int height) { + return height > width * 1.1f ? DeviceOrientation::Portrait : DeviceOrientation::Landscape; +} + +bool GetGameOutputOrientation(ScreenManager *screenManager, DeviceOrientation *orientation) { + const OutputDisplay *output = screenManager->FindOutput(OutputRole::Game); + if (!output || !output->swapchain) { + return false; + } + int width, height; + screenManager->getDrawContext()->GetFramebufferDimensions(output->swapchain, &width, &height); + *orientation = OutputOrientation(width, height); + return true; +} + void EmuScreen::UpdateGameOutput() { const OutputDisplay *output = screenManager()->FindOutput(OutputRole::Game); gameOnOutput_ = output && gpu && !skipBufferEffects_ && GPUIsBuffered(); @@ -1684,13 +1700,17 @@ void EmuScreen::UpdateGameOutput() { } OutputParams params; screenManager()->getDrawContext()->GetFramebufferDimensions(output->swapchain, ¶ms.pixelWidth, ¶ms.pixelHeight); - params.orientation = params.pixelHeight > params.pixelWidth * 1.1f ? DeviceOrientation::Portrait : DeviceOrientation::Landscape; + params.orientation = OutputOrientation(params.pixelWidth, params.pixelHeight); gameOutputOrientation_ = params.orientation; gpu->SetPresentationOutput(¶ms); } +DeviceOrientation EmuScreen::GameLayoutOrientation() const { + return gameOnOutput_ ? gameOutputOrientation_ : GetDeviceOrientation(); +} + const DisplayLayoutConfig &EmuScreen::GameLayoutConfig() const { - return g_Config.GetDisplayLayoutConfig(gameOnOutput_ ? gameOutputOrientation_ : GetDeviceOrientation()); + return g_Config.GetDisplayLayoutConfig(GameLayoutOrientation()); } bool EmuScreen::renderOutput(const OutputDisplay &output) { diff --git a/UI/EmuScreen.h b/UI/EmuScreen.h index 86b1a25368..7536e6b49c 100644 --- a/UI/EmuScreen.h +++ b/UI/EmuScreen.h @@ -83,6 +83,7 @@ private: void CreateViews() override; ScreenRenderFlags RunEmulation(bool skipBufferEffects); void UpdateGameOutput(); + DeviceOrientation GameLayoutOrientation() const; const DisplayLayoutConfig &GameLayoutConfig() const; void OnDevTools(UI::EventParams ¶ms); void OpenChat(bool focus); @@ -167,3 +168,5 @@ private: bool MustRunBehind(); bool ShouldRunBehind(); +// The orientation of the output the game goes to (like a TV), if there's one. Its display layout is the one for that. +bool GetGameOutputOrientation(ScreenManager *screenManager, DeviceOrientation *orientation);