Touch control layout screen: Resize the game image to fit the editing surface

Makes it easier to place controls properly.

Note, if you have disabled "Transparent UI background" in settings, this
won't do much.

This is a long-requested feature: #16228
This commit is contained in:
Henrik Rydgård 2025-03-05 17:59:36 +01:00
parent 20290b0202
commit 5549fddae5
5 changed files with 38 additions and 11 deletions

View file

@ -44,7 +44,15 @@ struct Vertex {
uint32_t rgba;
};
extern Bounds g_imguiCentralNodeBounds;
static bool g_overrideScreenBounds;
static Bounds g_screenBounds;
void SetOverrideScreenFrame(const Bounds *bounds) {
g_overrideScreenBounds = bounds != nullptr;
if (bounds) {
g_screenBounds = *bounds;
}
}
FRect GetScreenFrame(float pixelWidth, float pixelHeight) {
FRect rc = FRect{
@ -70,12 +78,12 @@ FRect GetScreenFrame(float pixelWidth, float pixelHeight) {
rc.h -= (top + bottom);
}
if (g_Config.bShowImDebugger) {
if (g_overrideScreenBounds) {
// Set rectangle to match central node. Here we ignore bIgnoreScreenInsets.
rc.x = g_imguiCentralNodeBounds.x;
rc.y = g_imguiCentralNodeBounds.y;
rc.w = g_imguiCentralNodeBounds.w;
rc.h = g_imguiCentralNodeBounds.h;
rc.x = g_screenBounds.x;
rc.y = g_screenBounds.y;
rc.w = g_screenBounds.w;
rc.h = g_screenBounds.h;
}
return rc;

View file

@ -46,7 +46,10 @@ struct FRect {
float h;
};
struct Bounds; // from geom2d
FRect GetScreenFrame(float pixelWidth, float pixelHeight);
void SetOverrideScreenFrame(const Bounds *bounds);
void CalculateDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &frame, int rotation);
namespace Draw {

View file

@ -57,6 +57,7 @@ using namespace std::placeholders;
#include "Core/MemFault.h"
#include "Core/Reporting.h"
#include "Core/System.h"
#include "GPU/Common/PresentationCommon.h"
#include "Core/FileSystems/VirtualDiscFileSystem.h"
#include "GPU/GPUState.h"
#include "GPU/GPUCommon.h"
@ -1787,7 +1788,8 @@ void EmuScreen::runImDebugger() {
ImGuiDockNode* node = ImGui::DockBuilderGetCentralNode(dockID);
// Not elegant! But don't know how else to pass through the bounds, without making a mess.
g_imguiCentralNodeBounds = Bounds(node->Pos.x, node->Pos.y, node->Size.x, node->Size.y);
Bounds centralNode(node->Pos.x, node->Pos.y, node->Size.x, node->Size.y);
SetOverrideScreenFrame(&centralNode);
if (!io.WantCaptureKeyboard) {
// Draw a focus rectangle to indicate inputs will be passed through.

View file

@ -112,6 +112,7 @@
#include "Core/ThreadPools.h"
#include "GPU/GPUCommon.h"
#include "GPU/Common/PresentationCommon.h"
#include "UI/AudioCommon.h"
#include "UI/BackgroundAudio.h"
#include "UI/ControlMappingScreen.h"
@ -1025,6 +1026,8 @@ void NativeFrame(GraphicsContext *graphicsContext) {
ProcessWheelRelease(NKCODE_EXT_MOUSEWHEEL_UP, startTime, false);
ProcessWheelRelease(NKCODE_EXT_MOUSEWHEEL_DOWN, startTime, false);
SetOverrideScreenFrame(nullptr);
// it's ok to call this redundantly with DoFrame from EmuScreen
Achievements::Idle();

View file

@ -29,6 +29,7 @@
#include "Common/Log.h"
#include "Core/Config.h"
#include "Core/System.h"
#include "GPU/Common/PresentationCommon.h"
#include "UI/GamepadEmu.h"
#include "UI/TouchControlLayoutScreen.h"
#include "UI/TouchControlVisibilityScreen.h"
@ -609,13 +610,23 @@ UI::EventReturn TouchControlLayoutScreen::OnMode(UI::EventParams &e) {
void TouchControlLayoutScreen::update() {
UIDialogScreenWithGameBackground::update();
if (!layoutView_) {
return;
}
// TODO: We really, really need a cleaner solution for creating sub-views
// of custom compound controls.
if (layoutView_) {
if (!layoutView_->HasCreatedViews()) {
layoutView_->CreateViews();
}
if (!layoutView_->HasCreatedViews()) {
layoutView_->CreateViews();
}
Bounds bounds = layoutView_->GetBounds();
// Convert virtual pixels to real pixels.
bounds.x /= g_display.dpi_scale;
bounds.y /= g_display.dpi_scale;
bounds.w /= g_display.dpi_scale;
bounds.h /= g_display.dpi_scale;
SetOverrideScreenFrame(&bounds);
}
void TouchControlLayoutScreen::CreateViews() {