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);