2015-10-24 12:40:29 +00:00
// 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"
2015-11-13 21:30:32 +00:00
# include "ui/view.h"
2015-10-24 12:40:29 +00:00
# include "ui_atlas.h"
# include "DisplayLayoutScreen.h"
# include "Core/Config.h"
# include "Core/System.h"
# include "DisplayLayoutEditor.h"
2015-11-07 00:10:43 +00:00
# include "GPU/GLES/Framebuffer.h"
2015-10-24 12:40:29 +00:00
static const int leftColumnWidth = 200 ;
2016-05-31 17:40:14 +00:00
static const float orgRatio = 1.764706f ;
2015-10-24 12:40:29 +00:00
// 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 ;
2016-09-04 16:46:42 +00:00
mode_ = nullptr ;
2015-10-24 12:40:29 +00:00
} ;
bool DisplayLayoutScreen : : touch ( const TouchInput & touch ) {
UIScreen : : touch ( touch ) ;
using namespace UI ;
2016-09-04 16:46:42 +00:00
int mode = mode_ ? mode_ - > GetSelection ( ) : 0 ;
2015-12-21 05:32:05 +00:00
if ( g_Config . iSmallDisplayZoomType = = 2 ) { mode = - 1 ; }
2015-10-24 12:40:29 +00:00
const Bounds & screen_bounds = screenManager ( ) - > getUIContext ( ) - > GetBounds ( ) ;
if ( ( touch . flags & TOUCH_MOVE ) & & picked_ ! = 0 ) {
2016-01-17 21:05:32 +00:00
int touchX = touch . x - offsetTouchX ;
int touchY = touch . y - offsetTouchY ;
2015-10-24 12:40:29 +00:00
if ( mode = = 0 ) {
const Bounds & bounds = picked_ - > GetBounds ( ) ;
2016-01-17 21:56:42 +00:00
int minTouchX = screen_bounds . w / 4 ;
int maxTouchX = screen_bounds . w - minTouchX ;
2015-10-24 12:40:29 +00:00
int minTouchY = screen_bounds . h / 4 ;
2016-01-17 21:05:32 +00:00
int maxTouchY = screen_bounds . h - minTouchY ;
2015-10-24 12:40:29 +00:00
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.
2016-01-17 21:56:42 +00:00
if ( touchX > minTouchX & & touchX < maxTouchX ) {
2015-10-24 12:40:29 +00:00
// if the leftmost point of the control is ahead of the margin,
// move it. Otherwise, don't.
2016-01-17 21:05:32 +00:00
newX = touchX ;
2015-10-24 12:40:29 +00:00
}
2016-01-17 21:05:32 +00:00
if ( touchY > minTouchY & & touchY < maxTouchY ) {
newY = touchY ;
2015-10-24 12:40:29 +00:00
}
picked_ - > ReplaceLayoutParams ( new UI : : AnchorLayoutParams ( newX , newY , NONE , NONE , true ) ) ;
2016-01-17 21:05:32 +00:00
} else if ( mode = = 1 ) {
2015-10-24 12:40:29 +00:00
// Resize. Vertical = scaling, horizontal = spacing;
// Up should be bigger so let's negate in that direction
2016-01-17 21:05:32 +00:00
float diffX = ( touchX - startX_ ) ;
float diffY = - ( touchY - startY_ ) ;
2015-10-24 12:40:29 +00:00
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 ) ;
2016-01-17 21:05:32 +00:00
scaleUpdate_ = picked_ - > GetScale ( ) ;
g_Config . fSmallDisplayZoomLevel = scaleUpdate_ / 8.0f ;
2015-10-24 12:40:29 +00:00
}
}
if ( ( touch . flags & TOUCH_DOWN ) & & picked_ = = 0 ) {
picked_ = displayRepresentation_ ;
if ( picked_ ) {
2016-01-17 21:05:32 +00:00
const Bounds & bounds = picked_ - > GetBounds ( ) ;
startX_ = bounds . centerX ( ) ;
startY_ = bounds . centerY ( ) ;
offsetTouchX = touch . x - startX_ ;
offsetTouchY = touch . y - startY_ ;
2015-10-24 12:40:29 +00:00
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 ;
} ;
2015-12-21 05:32:05 +00:00
UI : : EventReturn DisplayLayoutScreen : : OnZoomTypeChange ( UI : : EventParams & e ) {
if ( g_Config . iSmallDisplayZoomType < 3 ) {
2015-10-24 12:40:29 +00:00
const Bounds & bounds = screenManager ( ) - > getUIContext ( ) - > GetBounds ( ) ;
2015-12-21 05:32:05 +00:00
float autoBound = bounds . w / 480.0f ;
g_Config . fSmallDisplayZoomLevel = autoBound ;
displayRepresentationScale_ = g_Config . fSmallDisplayZoomLevel * 8.0f ;
2015-10-24 12:40:29 +00:00
g_Config . fSmallDisplayOffsetX = 0.5f ;
g_Config . fSmallDisplayOffsetY = 0.5f ;
}
RecreateViews ( ) ;
return UI : : EVENT_DONE ;
} ;
void DisplayLayoutScreen : : dialogFinished ( const Screen * dialog , DialogResult result ) {
RecreateViews ( ) ;
}
2016-09-04 01:09:44 +00:00
class Boundary : public UI : : View {
public :
Boundary ( UI : : LayoutParams * layoutParams ) : UI : : View ( layoutParams ) {
}
void Draw ( UIContext & dc ) override {
dc . Draw ( ) - > DrawImageStretch ( dc . theme - > whiteImage , bounds_ . x , bounds_ . y , bounds_ . x2 ( ) , bounds_ . y2 ( ) , dc . theme - > itemDownStyle . background . color ) ;
}
} ;
2016-09-04 16:46:42 +00:00
// Stealing StickyChoice's layout and text rendering.
class HighlightLabel : public UI : : StickyChoice {
public :
HighlightLabel ( const std : : string & text , UI : : LayoutParams * layoutParams )
: UI : : StickyChoice ( text , " " , layoutParams ) {
Press ( ) ;
}
bool CanBeFocused ( ) const override { return false ; }
} ;
2015-10-24 12:40:29 +00:00
void DisplayLayoutScreen : : CreateViews ( ) {
const Bounds & bounds = screenManager ( ) - > getUIContext ( ) - > GetBounds ( ) ;
local_dp_xres = bounds . w ;
local_dp_yres = bounds . h ;
using namespace UI ;
2015-11-02 22:10:44 +00:00
I18NCategory * di = GetI18NCategory ( " Dialog " ) ;
2015-10-24 12:40:29 +00:00
I18NCategory * gr = GetI18NCategory ( " Graphics " ) ;
2016-01-23 18:49:57 +00:00
I18NCategory * co = GetI18NCategory ( " Controls " ) ;
2015-10-24 12:40:29 +00:00
root_ = new AnchorLayout ( new LayoutParams ( FILL_PARENT , FILL_PARENT ) ) ;
2016-09-04 01:09:44 +00:00
const float previewWidth = local_dp_xres / 2.0f ;
const float previewHeight = local_dp_yres / 2.0f ;
2015-10-24 12:40:29 +00:00
// Just visual boundaries of the screen, should be easier to use than imagination
2016-09-04 01:09:44 +00:00
const float horizPreviewPadding = local_dp_xres / 4.0f ;
const float vertPreviewPadding = local_dp_yres / 4.0f ;
const float horizBoundariesWidth = 4.0f ;
// This makes it have at least 10.0f padding below at 1x.
const float vertBoundariesHeight = 52.0f ;
// Left side, right, top, bottom.
root_ - > Add ( new Boundary ( new AnchorLayoutParams ( horizBoundariesWidth , FILL_PARENT , NONE , 0 , horizPreviewPadding + previewWidth , 0 ) ) ) ;
root_ - > Add ( new Boundary ( new AnchorLayoutParams ( horizBoundariesWidth , FILL_PARENT , horizPreviewPadding + previewWidth , 0 , NONE , 0 ) ) ) ;
root_ - > Add ( new Boundary ( new AnchorLayoutParams ( previewWidth , vertBoundariesHeight , horizPreviewPadding , vertPreviewPadding - vertBoundariesHeight , NONE , NONE ) ) ) ;
root_ - > Add ( new Boundary ( new AnchorLayoutParams ( previewWidth , vertBoundariesHeight , horizPreviewPadding , NONE , NONE , vertPreviewPadding - vertBoundariesHeight ) ) ) ;
2015-10-24 12:40:29 +00:00
2015-12-21 05:32:05 +00:00
static const char * zoomLevels [ ] = { " Stretching " , " Partial Stretch " , " Auto Scaling " , " Manual Scaling " } ;
2016-09-04 01:09:44 +00:00
zoom_ = new PopupMultiChoice ( & g_Config . iSmallDisplayZoomType , di - > T ( " Options " ) , zoomLevels , 0 , ARRAY_SIZE ( zoomLevels ) , gr - > GetName ( ) , screenManager ( ) , new AnchorLayoutParams ( 400 , WRAP_CONTENT , previewWidth - 200.0f , NONE , NONE , 10 ) ) ;
2015-12-21 05:32:05 +00:00
zoom_ - > OnChoice . Handle ( this , & DisplayLayoutScreen : : OnZoomTypeChange ) ;
2015-10-24 12:40:29 +00:00
2015-11-07 00:10:43 +00:00
static const char * displayRotation [ ] = { " Landscape " , " Portrait " , " Landscape Reversed " , " Portrait Reversed " } ;
2016-09-04 01:09:44 +00:00
rotation_ = new PopupMultiChoice ( & g_Config . iInternalScreenRotation , gr - > T ( " Rotation " ) , displayRotation , 1 , ARRAY_SIZE ( displayRotation ) , co - > GetName ( ) , screenManager ( ) , new AnchorLayoutParams ( 400 , WRAP_CONTENT , previewWidth - 200.0f , 10 , NONE , local_dp_yres - 64 - 10 ) ) ;
2015-11-07 00:10:43 +00:00
rotation_ - > SetEnabledPtr ( & displayRotEnable_ ) ;
displayRotEnable_ = ( g_Config . iRenderingMode ! = FB_NON_BUFFERED_MODE ) ;
2015-11-13 21:30:32 +00:00
bool bRotated = false ;
2016-01-17 10:47:01 +00:00
if ( displayRotEnable_ & & ( g_Config . iInternalScreenRotation = = ROTATION_LOCKED_VERTICAL | | g_Config . iInternalScreenRotation = = ROTATION_LOCKED_VERTICAL180 ) ) {
bRotated = true ;
}
2015-12-21 05:32:05 +00:00
displayRepresentationScale_ = g_Config . fSmallDisplayZoomLevel * 8.0f ; // Visual representation image is just icon size and have to be scaled 8 times to match PSP native resolution which is used as 1.0 for zoom
2016-09-04 16:46:42 +00:00
HighlightLabel * label = nullptr ;
mode_ = nullptr ;
2015-12-21 05:32:05 +00:00
if ( g_Config . iSmallDisplayZoomType > 1 ) { // Scaling
if ( g_Config . iSmallDisplayZoomType = = 2 ) { // Auto Scaling
2016-09-04 16:46:42 +00:00
label = new HighlightLabel ( gr - > T ( " Auto Scaling " ) , new AnchorLayoutParams ( WRAP_CONTENT , 64.0f , local_dp_xres / 2.0f , local_dp_yres / 2.0f , NONE , NONE , true ) ) ;
2015-12-21 05:32:05 +00:00
float autoBound = local_dp_yres / 270.0f ;
2015-11-13 21:30:32 +00:00
// Case of screen rotated ~ only works with buffered rendering
if ( bRotated ) {
2015-12-21 05:32:05 +00:00
autoBound = local_dp_yres / 480.0f ;
2015-11-13 21:30:32 +00:00
}
else { // Without rotation in common cases like 1080p we cut off 2 pixels of height, this reflects other cases
float resCommonWidescreen = autoBound - floor ( autoBound ) ;
if ( resCommonWidescreen ! = 0.0f ) {
float ratio = local_dp_xres / local_dp_yres ;
if ( ratio < orgRatio ) {
2015-12-21 05:32:05 +00:00
autoBound = local_dp_xres / 480.0f ;
2015-11-13 21:30:32 +00:00
}
else {
2015-12-21 05:32:05 +00:00
autoBound = local_dp_yres / 272.0f ;
2015-11-13 21:30:32 +00:00
}
2015-11-13 07:50:10 +00:00
}
}
2015-12-21 05:32:05 +00:00
g_Config . fSmallDisplayZoomLevel = autoBound ;
displayRepresentationScale_ = g_Config . fSmallDisplayZoomLevel * 8.0f ;
2015-11-13 21:30:32 +00:00
g_Config . fSmallDisplayOffsetX = 0.5f ;
g_Config . fSmallDisplayOffsetY = 0.5f ;
2015-12-21 05:32:05 +00:00
} else { // Manual Scaling
2015-11-13 21:30:32 +00:00
Choice * center = new Choice ( di - > T ( " Center " ) , " " , false , new AnchorLayoutParams ( leftColumnWidth , WRAP_CONTENT , 10 , NONE , NONE , 74 ) ) ;
center - > OnClick . Handle ( this , & DisplayLayoutScreen : : OnCenter ) ;
root_ - > Add ( center ) ;
2016-09-04 16:46:42 +00:00
PopupSliderChoiceFloat * zoomlvl = new PopupSliderChoiceFloat ( & g_Config . fSmallDisplayZoomLevel , 1.0f , 10.0f , di - > T ( " Zoom " ) , 1.0f , screenManager ( ) , di - > T ( " * PSP res " ) , new AnchorLayoutParams ( leftColumnWidth , WRAP_CONTENT , 10 , NONE , NONE , 10 + 64 + 64 ) ) ;
2016-03-21 06:14:08 +00:00
root_ - > Add ( zoomlvl ) ;
2016-09-04 16:46:42 +00:00
mode_ = new ChoiceStrip ( ORIENT_VERTICAL , new AnchorLayoutParams ( leftColumnWidth , WRAP_CONTENT , 10 , NONE , NONE , 158 + 64 + 10 ) ) ;
2015-11-13 21:30:32 +00:00
mode_ - > AddChoice ( di - > T ( " Move " ) ) ;
mode_ - > AddChoice ( di - > T ( " Resize " ) ) ;
mode_ - > SetSelection ( 0 ) ;
2015-11-13 07:50:10 +00:00
}
2015-12-21 05:32:05 +00:00
displayRepresentation_ = new DragDropDisplay ( g_Config . fSmallDisplayOffsetX , g_Config . fSmallDisplayOffsetY , I_PSP_DISPLAY , displayRepresentationScale_ ) ;
2015-11-13 21:30:32 +00:00
displayRepresentation_ - > SetVisibility ( V_VISIBLE ) ;
2015-12-21 05:32:05 +00:00
} else { // Stretching
2016-09-04 16:46:42 +00:00
label = new HighlightLabel ( gr - > T ( " Stretching " ) , new AnchorLayoutParams ( WRAP_CONTENT , 64.0f , local_dp_xres / 2.0f , local_dp_yres / 2.0f , NONE , NONE , true ) ) ;
2015-12-21 05:32:05 +00:00
displayRepresentation_ = new DragDropDisplay ( g_Config . fSmallDisplayOffsetX , g_Config . fSmallDisplayOffsetY , I_PSP_DISPLAY , displayRepresentationScale_ ) ;
2015-11-13 21:30:32 +00:00
displayRepresentation_ - > SetVisibility ( V_INVISIBLE ) ;
2016-09-04 01:09:44 +00:00
float width = previewWidth ;
float height = previewHeight ;
2015-12-21 05:32:05 +00:00
if ( g_Config . iSmallDisplayZoomType = = 0 ) { // Stretched
2015-11-13 21:30:32 +00:00
Choice * stretched = new Choice ( " " , " " , false , new AnchorLayoutParams ( width , height , width - width / 2.0f , NONE , NONE , height - height / 2.0f ) ) ;
2016-01-17 21:05:32 +00:00
stretched - > SetEnabled ( false ) ;
2015-11-13 21:30:32 +00:00
root_ - > Add ( stretched ) ;
} else { // Partially stretched
float origRatio = ! bRotated ? 480.0f / 272.0f : 272.0f / 480.0f ;
float frameRatio = width / height ;
if ( origRatio > frameRatio ) {
height = width / origRatio ;
2016-09-04 01:09:44 +00:00
if ( ! bRotated & & g_Config . iSmallDisplayZoomType = = 1 ) {
height = ( 272.0f + height ) / 2.0f ;
}
2015-11-13 21:30:32 +00:00
} else {
width = height * origRatio ;
2016-09-04 01:09:44 +00:00
if ( bRotated & & g_Config . iSmallDisplayZoomType = = 1 ) {
width = ( 272.0f + height ) / 2.0f ;
}
2015-11-13 21:30:32 +00:00
}
2016-09-04 01:09:44 +00:00
Choice * stretched = new Choice ( " " , " " , false , new AnchorLayoutParams ( width , height , previewWidth - width / 2.0f , NONE , NONE , previewHeight - height / 2.0f ) ) ;
2016-01-17 21:05:32 +00:00
stretched - > SetEnabled ( false ) ;
2015-11-13 21:30:32 +00:00
root_ - > Add ( stretched ) ;
}
}
if ( bRotated ) {
displayRepresentation_ - > SetAngle ( 90.0f ) ;
2015-10-24 12:40:29 +00:00
}
2016-09-04 16:46:42 +00:00
Choice * back = new Choice ( di - > T ( " Back " ) , " " , false , new AnchorLayoutParams ( leftColumnWidth , WRAP_CONTENT , 10 , NONE , NONE , 10 ) ) ;
2015-10-24 12:40:29 +00:00
back - > OnClick . Handle < UIScreen > ( this , & UIScreen : : OnBack ) ;
2015-11-13 21:30:32 +00:00
root_ - > Add ( displayRepresentation_ ) ;
2016-09-04 16:46:42 +00:00
if ( mode_ ) {
root_ - > Add ( mode_ ) ;
}
if ( label ) {
root_ - > Add ( label ) ;
}
2015-10-24 12:40:29 +00:00
root_ - > Add ( zoom_ ) ;
2015-11-07 00:10:43 +00:00
root_ - > Add ( rotation_ ) ;
2015-10-24 12:40:29 +00:00
root_ - > Add ( back ) ;
}