Merge pull request #8082 from LunaMoo/DisplayEditing

Add "Display layout editor"
This commit is contained in:
Henrik Rydgård 2015-11-02 19:31:05 +01:00
commit fbb30260e3
19 changed files with 481 additions and 34 deletions

View File

@ -861,6 +861,8 @@ set(NativeAppSource
UI/NativeApp.cpp
UI/BackgroundAudio.cpp
UI/DevScreens.cpp
UI/DisplayLayoutEditor.cpp
UI/DisplayLayoutScreen.cpp
UI/EmuScreen.cpp
UI/GameInfoCache.cpp
UI/MainScreen.cpp

View File

@ -436,14 +436,17 @@ static ConfigSetting graphicsSettings[] = {
ReportedConfigSetting("TextureSecondaryCache", &g_Config.bTextureSecondaryCache, false, true, true),
ReportedConfigSetting("VertexDecJit", &g_Config.bVertexDecoderJit, &DefaultJit, false),
#ifdef _WIN32
#ifndef MOBILE_DEVICE
ConfigSetting("FullScreen", &g_Config.bFullScreen, false),
#endif
// TODO: Replace these settings with a list of options
ConfigSetting("PartialStretch", &g_Config.bPartialStretch, &DefaultPartialStretch, true, true),
ConfigSetting("StretchToDisplay", &g_Config.bStretchToDisplay, false, true, true),
ConfigSetting("SmallDisplay", &g_Config.bSmallDisplay, false, true, true),
ConfigSetting("SmallDisplayZoom", &g_Config.iSmallDisplayZoom, 0, true, true),
ConfigSetting("SmallDisplayOffsetX", &g_Config.fSmallDisplayOffsetX, 0.5f, true, true),
ConfigSetting("SmallDisplayOffsetY", &g_Config.fSmallDisplayOffsetY, 0.5f, true, true),
ConfigSetting("SmallDisplayCustomZoom", &g_Config.fSmallDisplayCustomZoom, 8.0f, true, true),
ConfigSetting("ImmersiveMode", &g_Config.bImmersiveMode, false, true, true),
ReportedConfigSetting("TrueColor", &g_Config.bTrueColor, true, true, true),

View File

@ -144,7 +144,10 @@ public:
int iBufFilter; // 1 = linear, 2 = nearest
bool bPartialStretch;
bool bStretchToDisplay;
bool bSmallDisplay; // Useful on large tablets with touch controls to not overlap the image. Temporary setting - will be replaced by more comprehensive display size settings.
int iSmallDisplayZoom; // Used to fit display into screen 0 = auto, anything higher is used to set's integer zoom of psp resolution and allows manual editing
float fSmallDisplayOffsetX; // Along with Y it goes from 0.0 to 1.0, XY (0.5, 0.5) = center of the screen
float fSmallDisplayOffsetY;
float fSmallDisplayCustomZoom; //This is actually used for zoom, both in and out.
bool bImmersiveMode; // Mode on Android Kitkat 4.4 that hides the back button etc.
bool bVSync;
int iFrameSkip;

View File

@ -30,7 +30,7 @@
#include "GPU/GPUState.h"
#include "UI/OnScreenDisplay.h" // Gross dependency!
void CenterRect(float *x, float *y, float *w, float *h, float origW, float origH, float frameW, float frameH, int rotation) {
void CenterDisplayOutputRect(float *x, float *y, float *w, float *h, float origW, float origH, float frameW, float frameH, int rotation, bool invertY) {
float outW;
float outH;
@ -40,16 +40,50 @@ void CenterRect(float *x, float *y, float *w, float *h, float origW, float origH
outW = frameW;
outH = frameH;
} else {
// Add special case for 1080p displays, cutting off the bottom and top 1-pixel rows from the original 480x272.
// This will be what 99.9% of users want.
if (origW == 480 && origH == 272 && frameW == 1920 && frameH == 1080 && !rotated) {
*x = 0;
*y = -4;
*w = 1920;
*h = 1088;
return;
bool fullScreenZoom = true;
#ifndef MOBILE_DEVICE
fullScreenZoom = g_Config.bFullScreen;
#endif
if (fullScreenZoom) {
if (g_Config.iSmallDisplayZoom != 0) {
float offsetX = (g_Config.fSmallDisplayOffsetX - 0.5f) * 2.0f * frameW;
float offsetY = (g_Config.fSmallDisplayOffsetY - 0.5f) * 2.0f * frameH;
// Have to invert Y coordinates for software rendering as well as non buffered mode for GL
#if defined(USING_WIN_UI)
if (g_Config.bSoftwareRendering || (g_Config.iRenderingMode == FB_NON_BUFFERED_MODE && g_Config.iGPUBackend == GPU_BACKEND_OPENGL && !invertY)) { offsetY = offsetY * -1.0f; }
#else
if (g_Config.bSoftwareRendering || (g_Config.iRenderingMode == FB_NON_BUFFERED_MODE && !invertY)) { offsetY = offsetY * -1.0f; }
#endif
float customZoom = g_Config.fSmallDisplayCustomZoom / 8.0f;
float smallDisplayW = origW * customZoom;
float smallDisplayH = origH * customZoom;
if (!rotated) {
*x = ((frameW - smallDisplayW) / 2.0f) + offsetX;
*y = ((frameH - smallDisplayH) / 2.0f) + offsetY;
*w = smallDisplayW;
*h = smallDisplayH;
return;
} else {
*x = ((frameW - smallDisplayH) / 2.0f) + offsetX;
*y = ((frameH - smallDisplayW) / 2.0f) + offsetY;
*w = smallDisplayH;
*h = smallDisplayW;
return;
}
} else {
float pixelCrop = frameH / 270.0f;
float resCommonWidescreen = pixelCrop - floor(pixelCrop);
if (!rotated && resCommonWidescreen == 0.0f) {
*x = 0;
*y = -pixelCrop;
*w = frameW;
*h = pixelCrop * 272.0f;
return;
}
}
}
float origRatio = !rotated ? origW / origH : origH / origW;
float frameRatio = frameW / frameH;
@ -67,11 +101,6 @@ void CenterRect(float *x, float *y, float *w, float *h, float origW, float origH
}
}
if (g_Config.bSmallDisplay) {
outW /= 2.0f;
outH /= 2.0f;
}
*x = (frameW - outW) / 2.0f;
*y = (frameH - outH) / 2.0f;
*w = outW;

View File

@ -284,4 +284,4 @@ protected:
};
};
void CenterRect(float *x, float *y, float *w, float *h, float origW, float origH, float frameW, float frameH, int rotation);
void CenterDisplayOutputRect(float *x, float *y, float *w, float *h, float origW, float origH, float frameW, float frameH, int rotation, bool invertY);

View File

@ -185,8 +185,12 @@ namespace DX9 {
void FramebufferManagerDX9::DrawPixels(VirtualFramebuffer *vfb, int dstX, int dstY, const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height) {
if (useBufferedRendering_ && vfb->fbo) {
fbo_bind_as_render_target(vfb->fbo);
dxstate.viewport.set(0, 0, vfb->renderWidth, vfb->renderHeight);
} else {
float x, y, w, h;
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, false, false);
dxstate.viewport.set(x, y, w, h);
}
dxstate.viewport.set(0, 0, vfb->renderWidth, vfb->renderHeight);
MakePixelTexture(srcPixels, srcPixelFormat, srcStride, width, height);
DisableState();
DrawActiveTexture(drawPixelsTex_, dstX, dstY, width, height, vfb->bufferWidth, vfb->bufferHeight, false, 0.0f, 0.0f, 1.0f, 1.0f);
@ -203,7 +207,7 @@ namespace DX9 {
// (it always runs at output resolution so FXAA may look odd).
float x, y, w, h;
int uvRotation = (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) ? g_Config.iInternalScreenRotation : ROTATION_LOCKED_HORIZONTAL;
CenterRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, uvRotation);
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, uvRotation, false);
DrawActiveTexture(drawPixelsTex_, x, y, w, h, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, false, 0.0f, 0.0f, 480.0f / 512.0f, uvRotation);
}
@ -764,7 +768,7 @@ namespace DX9 {
// Output coordinates
float x, y, w, h;
int uvRotation = (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) ? g_Config.iInternalScreenRotation : ROTATION_LOCKED_HORIZONTAL;
CenterRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, uvRotation);
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, uvRotation, false);
const float u0 = offsetX / (float)vfb->bufferWidth;
const float v0 = offsetY / (float)vfb->bufferHeight;

View File

@ -649,7 +649,7 @@ void TransformDrawEngineDX9::ApplyDrawState(int prim) {
} else {
float pixelW = PSP_CoreParameter().pixelWidth;
float pixelH = PSP_CoreParameter().pixelHeight;
CenterRect(&renderX, &renderY, &renderWidth, &renderHeight, 480, 272, pixelW, pixelH, ROTATION_LOCKED_HORIZONTAL);
CenterDisplayOutputRect(&renderX, &renderY, &renderWidth, &renderHeight, 480, 272, pixelW, pixelH, ROTATION_LOCKED_HORIZONTAL, false);
renderWidthFactor = renderWidth / 480.0f;
renderHeightFactor = renderHeight / 272.0f;
}

View File

@ -230,7 +230,7 @@ void FramebufferManager::UpdatePostShaderUniforms(int renderWidth, int renderHei
float v_pixel_delta = v_delta;
if (postShaderAtOutputResolution_) {
float x, y, w, h;
CenterRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, ROTATION_LOCKED_HORIZONTAL);
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, ROTATION_LOCKED_HORIZONTAL, false);
u_pixel_delta = 1.0f / w;
v_pixel_delta = 1.0f / h;
}
@ -395,7 +395,7 @@ void FramebufferManager::DrawPixels(VirtualFramebuffer *vfb, int dstX, int dstY,
glViewport(0, 0, vfb->renderWidth, vfb->renderHeight);
} else {
float x, y, w, h;
CenterRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, false);
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, false, false);
glViewport(x, y, w, h);
}
MakePixelTexture(srcPixels, srcPixelFormat, srcStride, width, height);
@ -418,7 +418,7 @@ void FramebufferManager::DrawFramebuffer(const u8 *srcPixels, GEBufferFormat src
// (it always runs at output resolution so FXAA may look odd).
float x, y, w, h;
int uvRotation = (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) ? g_Config.iInternalScreenRotation : ROTATION_LOCKED_HORIZONTAL;
CenterRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, uvRotation);
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, uvRotation, true);
if (applyPostShader) {
glsl_bind(postShaderProgram_);
UpdatePostShaderUniforms(renderWidth_, renderHeight_);
@ -1049,7 +1049,7 @@ void FramebufferManager::CopyDisplayToOutput() {
// Output coordinates
float x, y, w, h;
CenterRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, uvRotation);
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, uvRotation, false);
// TODO ES3: Use glInvalidateFramebuffer to discard depth/stencil data at the end of frame.

View File

@ -740,7 +740,7 @@ void TransformDrawEngine::ApplyDrawState(int prim) {
} else {
float pixelW = PSP_CoreParameter().pixelWidth;
float pixelH = PSP_CoreParameter().pixelHeight;
CenterRect(&displayOffsetX, &displayOffsetY, &renderWidth, &renderHeight, 480, 272, pixelW, pixelH, ROTATION_LOCKED_HORIZONTAL);
CenterDisplayOutputRect(&displayOffsetX, &displayOffsetY, &renderWidth, &renderHeight, 480, 272, pixelW, pixelH, ROTATION_LOCKED_HORIZONTAL, false);
renderWidthFactor = renderWidth / 480.0f;
renderHeightFactor = renderHeight / 272.0f;
}

View File

@ -34,6 +34,7 @@
#include "GPU/Software/SoftGpu.h"
#include "GPU/Software/TransformUnit.h"
#include "GPU/Software/Rasterizer.h"
#include "GPU/Common/FramebufferCommon.h"
static GLuint temp_texture = 0;
@ -48,9 +49,6 @@ FormatBuffer fb;
FormatBuffer depthbuf;
u32 clut[4096];
// TODO: This one lives in GPU/GLES/Framebuffer.cpp, move it to somewhere common.
void CenterRect(float *x, float *y, float *w, float *h,
float origW, float origH, float frameW, float frameH, int rotation);
GLuint OpenGL_CompileProgram(const char* vertexShader, const char* fragmentShader)
{
@ -247,7 +245,7 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight)
glUseProgram(program);
float x, y, w, h;
CenterRect(&x, &y, &w, &h, 480.0f, 272.0f, dstwidth, dstheight, ROTATION_LOCKED_HORIZONTAL);
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, dstwidth, dstheight, ROTATION_LOCKED_HORIZONTAL, false);
x /= 0.5f * dstwidth;
y /= 0.5f * dstheight;

View File

@ -0,0 +1,54 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "DisplayLayoutEditor.h"
#include "ui/ui_context.h"
#include "ui_atlas.h"
#include <algorithm>
void MultiTouchDisplay::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
const AtlasImage &image = dc.Draw()->GetAtlas()->images[img_];
w = image.w * scale_;
h = image.h * scale_;
}
void MultiTouchDisplay::Touch(const TouchInput &input) {
if ((input.flags & TOUCH_DOWN) && bounds_.Contains(input.x, input.y)) {
pointerDownMask_ |= 1 << input.id;
}
if (input.flags & TOUCH_MOVE) {
if (bounds_.Contains(input.x, input.y))
pointerDownMask_ |= 1 << input.id;
else
pointerDownMask_ &= ~(1 << input.id);
}
if (input.flags & TOUCH_UP) {
pointerDownMask_ &= ~(1 << input.id);
}
if (input.flags & TOUCH_RELEASE_ALL) {
pointerDownMask_ = 0;
}
}
void MultiTouchDisplay::Draw(UIContext &dc) {
float opacity = 0.5f;
float scale = scale_;
uint32_t color = colorAlpha(0xFFFFFF, opacity);
dc.Draw()->DrawImageRotated(img_, bounds_.centerX(), bounds_.centerY(), scale, angle_ * (M_PI * 2 / 360.0f), color, flipImageH_);
}

51
UI/DisplayLayoutEditor.h Normal file
View File

@ -0,0 +1,51 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include "gfx_es2/draw_buffer.h"
#include "ui/view.h"
#include "ui/viewgroup.h"
class MultiTouchDisplay : public UI::View {
public:
MultiTouchDisplay(int img, float scale, UI::LayoutParams *layoutParams)
: UI::View(layoutParams), pointerDownMask_(0), scale_(scale), img_(img), angle_(0.0f), flipImageH_(false) {
}
virtual void Touch(const TouchInput &input) override;
virtual void Draw(UIContext &dc) override;
virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) const override;
// chainable
MultiTouchDisplay *FlipImageH(bool flip) { flipImageH_ = flip; return this; }
MultiTouchDisplay *SetAngle(float angle) { angle_ = angle; return this; }
protected:
uint32_t pointerDownMask_;
float scale_;
private:
int img_;
float angle_;
bool flipImageH_;
};
class PSPDisplay : public MultiTouchDisplay {
public:
PSPDisplay(int img, float scale, UI::LayoutParams *layoutParams)
: MultiTouchDisplay(img, scale, layoutParams) {
}
};

227
UI/DisplayLayoutScreen.cpp Normal file
View File

@ -0,0 +1,227 @@
// Copyright (c) 2013- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <vector>
#include "base/colorutil.h"
#include "gfx_es2/draw_buffer.h"
#include "i18n/i18n.h"
#include "ui/ui_context.h"
#include "ui_atlas.h"
#include "DisplayLayoutScreen.h"
#include "Core/Config.h"
#include "Core/System.h"
#include "DisplayLayoutEditor.h"
static const int leftColumnWidth = 200;
// Ugly hackery, need to rework some stuff to get around this
static float local_dp_xres;
static float local_dp_yres;
class DragDropDisplay : public MultiTouchDisplay {
public:
DragDropDisplay(float &x, float &y, int img, float &scale)
: MultiTouchDisplay(img, scale, new UI::AnchorLayoutParams(x*local_dp_xres, y*local_dp_yres, UI::NONE, UI::NONE, true)),
x_(x), y_(y), theScale_(scale) {
scale_ = theScale_;
}
virtual void SaveDisplayPosition() {
x_ = bounds_.centerX() / local_dp_xres;
y_ = bounds_.centerY() / local_dp_yres;
scale_ = theScale_;
}
virtual float GetScale() const { return theScale_; }
virtual void SetScale(float s) { theScale_ = s; scale_ = s; }
private:
float &x_, &y_;
float &theScale_;
};
DisplayLayoutScreen::DisplayLayoutScreen() {
picked_ = 0;
};
bool DisplayLayoutScreen::touch(const TouchInput &touch) {
UIScreen::touch(touch);
using namespace UI;
int mode = mode_->GetSelection();
if (g_Config.iSmallDisplayZoom == 0) { mode = -1; }
const Bounds &screen_bounds = screenManager()->getUIContext()->GetBounds();
if ((touch.flags & TOUCH_MOVE) && picked_ != 0) {
if (mode == 0) {
const Bounds &bounds = picked_->GetBounds();
int mintouchX = screen_bounds.w / 4;
int maxTouchX = screen_bounds.w - screen_bounds.w / 4;
int minTouchY = screen_bounds.h / 4;
int maxTouchY = screen_bounds.h - screen_bounds.h / 4;
int newX = bounds.centerX(), newY = bounds.centerY();
// we have to handle x and y separately since even if x is blocked, y may not be.
if (touch.x > mintouchX && touch.x < maxTouchX) {
// if the leftmost point of the control is ahead of the margin,
// move it. Otherwise, don't.
newX = touch.x;
}
if (touch.y > minTouchY && touch.y < maxTouchY) {
newY = touch.y;
}
picked_->ReplaceLayoutParams(new UI::AnchorLayoutParams(newX, newY, NONE, NONE, true));
}
else if (mode == 1) {
// Resize. Vertical = scaling, horizontal = spacing;
// Up should be bigger so let's negate in that direction
float diffX = (touch.x - startX_);
float diffY = -(touch.y - startY_);
float movementScale = 0.5f;
float newScale = startScale_ + diffY * movementScale;
if (newScale > 100.0f) newScale = 100.0f;
if (newScale < 1.0f) newScale = 1.0f;
picked_->SetScale(newScale);
}
}
if ((touch.flags & TOUCH_DOWN) && picked_ == 0) {
picked_ = displayRepresentation_;
if (picked_) {
startX_ = touch.x;
startY_ = touch.y;
startScale_ = picked_->GetScale();
}
}
if ((touch.flags & TOUCH_UP) && picked_ != 0) {
const Bounds &bounds = picked_->GetBounds();
float saveX_ = touch.x;
float saveY_ = touch.y;
startScale_ = picked_->GetScale();
picked_->SaveDisplayPosition();
picked_ = 0;
}
return true;
};
void DisplayLayoutScreen::onFinish(DialogResult reason) {
g_Config.Save();
}
UI::EventReturn DisplayLayoutScreen::OnCenter(UI::EventParams &e) {
g_Config.fSmallDisplayOffsetX = 0.5f;
g_Config.fSmallDisplayOffsetY = 0.5f;
RecreateViews();
return UI::EVENT_DONE;
};
UI::EventReturn DisplayLayoutScreen::OnZoomChange(UI::EventParams &e) {
if (g_Config.iSmallDisplayZoom > 0) {
g_Config.fSmallDisplayCustomZoom = (float)(g_Config.iSmallDisplayZoom * 8);
} else {
const Bounds &bounds = screenManager()->getUIContext()->GetBounds();
float autoBound = bounds.w / 480.0f * 8.0f;
g_Config.fSmallDisplayCustomZoom = autoBound;
g_Config.fSmallDisplayOffsetX = 0.5f;
g_Config.fSmallDisplayOffsetY = 0.5f;
}
RecreateViews();
return UI::EVENT_DONE;
};
void DisplayLayoutScreen::dialogFinished(const Screen *dialog, DialogResult result) {
RecreateViews();
}
void DisplayLayoutScreen::CreateViews() {
if (g_Config.bStretchToDisplay) {
// Shouldn't even be able to get here as the way into this dialog should be closed.
return;
}
const Bounds &bounds = screenManager()->getUIContext()->GetBounds();
local_dp_xres = bounds.w;
local_dp_yres = bounds.h;
using namespace UI;
I18NCategory *gr = GetI18NCategory("Graphics");
root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
// Just visual boundaries of the screen, should be easier to use than imagination
float verticalBoundaryPositionL = local_dp_xres / 4.0f;
float verticalBoundaryPositionR = local_dp_xres - verticalBoundaryPositionL;
float horizontalBoundaryPositionL = local_dp_yres / 4.0f;
float horizontalBoundaryPositionR = local_dp_yres - horizontalBoundaryPositionL;
TabHolder *verticalBoundaryL = new TabHolder(ORIENT_VERTICAL, verticalBoundaryPositionL, new AnchorLayoutParams(0, 0, 0, 0, false));
TabHolder *verticalBoundaryR = new TabHolder(ORIENT_VERTICAL, verticalBoundaryPositionR, new AnchorLayoutParams(0, 0, 0, 0, false));
TabHolder *horizontalBoundaryL = new TabHolder(ORIENT_VERTICAL, verticalBoundaryPositionL * 2.0f, new AnchorLayoutParams(verticalBoundaryPositionL * 2.0f, horizontalBoundaryPositionL - 31.0f, 0, 0, true));
TabHolder *horizontalBoundaryR = new TabHolder(ORIENT_VERTICAL, verticalBoundaryPositionL * 2.0f, new AnchorLayoutParams(verticalBoundaryPositionL * 2.0f, horizontalBoundaryPositionR + 31.0f, 0, 0, true));
AnchorLayout *topBoundary = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
AnchorLayout *bottomBoundary = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
root_->Add(verticalBoundaryL);
root_->Add(verticalBoundaryR);
root_->Add(horizontalBoundaryL);
root_->Add(horizontalBoundaryR);
horizontalBoundaryL->AddTab("", topBoundary);
horizontalBoundaryR->AddTab("", bottomBoundary);
Choice *back = new Choice(gr->T("Back"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 10));
static const char *zoomLevels[] = { "Auto", "1x", "2x", "3x", "4x", "5x", "6x", "7x", "8x", "9x", "10x" };
zoom_ = new PopupMultiChoice(&g_Config.iSmallDisplayZoom, gr->T("Zoom settings"), zoomLevels, 0, ARRAY_SIZE(zoomLevels), gr->GetName(), screenManager(), new AnchorLayoutParams(300, WRAP_CONTENT, verticalBoundaryPositionL * 2 - 150, NONE, NONE, 10));
zoom_->OnChoice.Handle(this, &DisplayLayoutScreen::OnZoomChange);
mode_ = new ChoiceStrip(ORIENT_VERTICAL, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 158 + 64 + 10));
if (g_Config.iSmallDisplayZoom == 0) {
mode_->AddChoice(gr->T("Active (Auto)"));
float autoBound = bounds.w / 480.0f * 8.0f;
g_Config.fSmallDisplayCustomZoom = autoBound;
g_Config.fSmallDisplayOffsetX = 0.5f;
g_Config.fSmallDisplayOffsetY = 0.5f;
} else {
Choice *center = new Choice(gr->T("Center"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 84));
center->OnClick.Handle(this, &DisplayLayoutScreen::OnCenter);
root_->Add(center);
mode_->AddChoice(gr->T("Move"));
mode_->AddChoice(gr->T("Resize"));
mode_->SetSelection(0);
}
back->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
root_->Add(mode_);
root_->Add(zoom_);
root_->Add(back);
displayRepresentation_ = new DragDropDisplay(g_Config.fSmallDisplayOffsetX, g_Config.fSmallDisplayOffsetY, I_PSP_DISPLAY, g_Config.fSmallDisplayCustomZoom);
if (g_Config.iInternalScreenRotation == 2 || g_Config.iInternalScreenRotation == 4) {
displayRepresentation_->SetAngle(90.0f);
}
root_->Add(displayRepresentation_);
}

50
UI/DisplayLayoutScreen.h Normal file
View File

@ -0,0 +1,50 @@
// Copyright (c) 2013- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include "ui/view.h"
#include "ui/viewgroup.h"
#include "MiscScreens.h"
#include <vector>
class DragDropDisplay;
class DisplayLayoutScreen : public UIDialogScreenWithBackground {
public:
DisplayLayoutScreen();
virtual void CreateViews() override;
virtual bool touch(const TouchInput &touch) override;
virtual void dialogFinished(const Screen *dialog, DialogResult result) override;
virtual void onFinish(DialogResult reason) override;
protected:
virtual UI::EventReturn OnCenter(UI::EventParams &e);
virtual UI::EventReturn OnZoomChange(UI::EventParams &e);
private:
DragDropDisplay *picked_;
DragDropDisplay *displayRepresentation_;
UI::ChoiceStrip *mode_;
UI::PopupMultiChoice *zoom_;
// Touch down state for drag to resize etc
float startX_;
float startY_;
float startScale_;
};

View File

@ -33,6 +33,7 @@
#include "UI/MiscScreens.h"
#include "UI/ControlMappingScreen.h"
#include "UI/DevScreens.h"
#include "UI/DisplayLayoutScreen.h"
#include "UI/SavedataScreen.h"
#include "UI/TouchControlLayoutScreen.h"
#include "UI/TouchControlVisibilityScreen.h"
@ -163,8 +164,12 @@ void GameSettingsScreen::CreateViews() {
graphicsSettings->Add(new CheckBox(&g_Config.bFullScreen, gr->T("FullScreen")))->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenChange);
#endif
graphicsSettings->Add(new CheckBox(&g_Config.bStretchToDisplay, gr->T("Stretch to Display")));
// Small Display: To avoid overlapping touch controls on large tablets. Better control over this will be coming later.
graphicsSettings->Add(new CheckBox(&g_Config.bSmallDisplay, gr->T("Small Display")));
// Display Layout Editor: To avoid overlapping touch controls on large tablets, meet geeky demands for integer zoom/unstretched image etc.
displayEditor_ = graphicsSettings->Add(new Choice(gr->T("Display layout editor")));
displayEditor_->OnClick.Handle(this, &GameSettingsScreen::OnDisplayLayoutEditor);
displayEditor_->SetDisabledPtr(&g_Config.bStretchToDisplay);
if (pixel_xres < pixel_yres * 1.3) // Smaller than 4:3
graphicsSettings->Add(new CheckBox(&g_Config.bPartialStretch, gr->T("Partial Vertical Stretch")));
@ -774,6 +779,11 @@ UI::EventReturn GameSettingsScreen::OnFullscreenChange(UI::EventParams &e) {
return UI::EVENT_DONE;
}
UI::EventReturn GameSettingsScreen::OnDisplayLayoutEditor(UI::EventParams &e) {
screenManager()->push(new DisplayLayoutScreen());
return UI::EVENT_DONE;
};
UI::EventReturn GameSettingsScreen::OnResolutionChange(UI::EventParams &e) {
if (gpu) {
gpu->Resized();

View File

@ -49,6 +49,7 @@ private:
UI::CheckBox *enableReportsCheckbox_;
UI::Choice *layoutEditorChoice_;
UI::Choice *postProcChoice_;
UI::Choice *displayEditor_;
UI::PopupMultiChoice *resolutionChoice_;
UI::CheckBox *frameSkipAuto_;
#ifdef _WIN32
@ -80,6 +81,7 @@ private:
UI::EventReturn OnChangeMacAddress(UI::EventParams &e);
UI::EventReturn OnClearRecents(UI::EventParams &e);
UI::EventReturn OnFullscreenChange(UI::EventParams &e);
UI::EventReturn OnDisplayLayoutEditor(UI::EventParams &e);
UI::EventReturn OnResolutionChange(UI::EventParams &e);
UI::EventReturn OnHwScaleChange(UI::EventParams &e);
UI::EventReturn OnShaderChange(UI::EventParams &e);

View File

@ -24,6 +24,8 @@
<ClCompile Include="ControlMappingScreen.cpp" />
<ClCompile Include="CwCheatScreen.cpp" />
<ClCompile Include="DevScreens.cpp" />
<ClCompile Include="DisplayLayoutEditor.cpp" />
<ClCompile Include="DisplayLayoutScreen.cpp" />
<ClCompile Include="EmuScreen.cpp" />
<ClCompile Include="GameInfoCache.cpp" />
<ClCompile Include="GamepadEmu.cpp" />
@ -50,6 +52,8 @@
<ClInclude Include="ComboKeyMappingScreen.h" />
<ClInclude Include="ControlMappingScreen.h" />
<ClInclude Include="DevScreens.h" />
<ClInclude Include="DisplayLayoutEditor.h" />
<ClInclude Include="DisplayLayoutScreen.h" />
<ClInclude Include="EmuScreen.h" />
<ClInclude Include="GameInfoCache.h" />
<ClInclude Include="GamepadEmu.h" />

View File

@ -62,6 +62,10 @@
<ClCompile Include="ComboKeyMappingScreen.cpp">
<Filter>Screens</Filter>
</ClCompile>
<ClCompile Include="DisplayLayoutScreen.cpp">
<Filter>Screens</Filter>
</ClCompile>
<ClCompile Include="DisplayLayoutEditor.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="GameInfoCache.h" />
@ -124,10 +128,14 @@
<ClInclude Include="ComboKeyMappingScreen.h">
<Filter>Screens</Filter>
</ClInclude>
<ClInclude Include="DisplayLayoutScreen.h">
<Filter>Screens</Filter>
</ClInclude>
<ClInclude Include="DisplayLayoutEditor.h" />
</ItemGroup>
<ItemGroup>
<Filter Include="Screens">
<UniqueIdentifier>{faee5dce-633b-4ba6-b19d-ea70ee3c1c38}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>
</Project>

View File

@ -334,6 +334,8 @@ LOCAL_SRC_FILES := \
$(SRC)/android/jni/native-audio-so.cpp \
$(SRC)/UI/BackgroundAudio.cpp \
$(SRC)/UI/DevScreens.cpp \
$(SRC)/UI/DisplayLayoutEditor.cpp \
$(SRC)/UI/DisplayLayoutScreen.cpp \
$(SRC)/UI/EmuScreen.cpp \
$(SRC)/UI/MainScreen.cpp \
$(SRC)/UI/MiscScreens.cpp \