diff --git a/CMakeLists.txt b/CMakeLists.txt index f348769939..4b65dbc96d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1151,6 +1151,7 @@ set(NativeAppSource UI/MiscScreens.cpp UI/GameScreen.cpp UI/GameSettingsScreen.cpp + UI/TouchControlLayoutScreen.cpp UI/GamepadEmu.cpp UI/UIShader.cpp UI/OnScreenDisplay.cpp diff --git a/Core/Config.cpp b/Core/Config.cpp index 75c99ea9a1..5af102df7c 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -210,7 +210,28 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) #endif control->Get("TouchButtonOpacity", &iTouchButtonOpacity, 65); control->Get("ButtonScale", &fButtonScale, 1.15); - + //set these to -1 if not initialized. initializing these + //requires pixel coordinates which is not known right now. + //will be initialized in GamepadEmu::CreatePadLayout + control->Get("ActionButtonSpacing", &iActionButtonSpacing, -1); + control->Get("ActionButtonCenterX", &iActionButtonCenterX, -1); + control->Get("ActionButtonCenterY", &iActionButtonCenterY, -1); + control->Get("DPadRadius", &iDpadRadius, -1); + control->Get("DPadX", &iDpadX, -1); + control->Get("DPadY", &iDpadY, -1); + control->Get("StartKeyX", &iStartKeyX, -1); + control->Get("StartKeyY", &iStartKeyY, -1); + control->Get("SelectKeyX", &iSelectKeyX, -1); + control->Get("SelectKeyY", &iSelectKeyY, -1); + control->Get("UnthrottleKeyX", &iUnthrottleKeyX, -1); + control->Get("UnthrottleKeyY", &iUnthrottleKeyY, -1); + control->Get("LKeyX", &iLKeyX, -1); + control->Get("LKeyY", &iLKeyY, -1); + control->Get("RKeyX", &iRKeyX, -1); + control->Get("RKeyY", &iRKeyY, -1); + control->Get("AnalogStickX", &iAnalogStickX, -1); + control->Get("AnalogStickY", &iAnalogStickY, -1); + IniFile::Section *pspConfig = iniFile.GetOrCreateSection("SystemParam"); pspConfig->Get("NickName", &sNickName, "PPSSPP"); pspConfig->Get("Language", &iLanguage, PSP_SYSTEMPARAM_LANGUAGE_ENGLISH); @@ -370,6 +391,25 @@ void Config::Save() { #endif control->Set("TouchButtonOpacity", iTouchButtonOpacity); control->Set("ButtonScale", fButtonScale); + control->Set("ActionButtonSpacing", iActionButtonSpacing); + control->Set("ActionButtonCenterX", iActionButtonCenterX); + control->Set("ActionButtonCenterY", iActionButtonCenterY); + control->Set("DPadRadius", iDpadRadius); + control->Set("DPadX", iDpadX); + control->Set("DPadY", iDpadY); + control->Set("StartKeyX", iStartKeyX); + control->Set("StartKeyY", iStartKeyY); + control->Set("SelectKeyX", iSelectKeyX); + control->Set("SelectKeyY", iSelectKeyY); + control->Set("UnthrottleKeyX", iUnthrottleKeyX); + control->Set("UnthrottleKeyY", iUnthrottleKeyY); + control->Set("LKeyX", iLKeyX); + control->Set("LKeyY", iLKeyY); + control->Set("RKeyX", iRKeyX); + control->Set("RKeyY", iRKeyY); + control->Set("AnalogStickX", iAnalogStickX); + control->Set("AnalogStickY", iAnalogStickY); + IniFile::Section *pspConfig = iniFile.GetOrCreateSection("SystemParam"); pspConfig->Set("NickName", sNickName.c_str()); diff --git a/Core/Config.h b/Core/Config.h index c38fb8c230..5c85a55aaf 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -108,8 +108,6 @@ public: bool bShowTouchControls; bool bShowAnalogStick; bool bHapticFeedback; - int iTouchButtonOpacity; - float fButtonScale; // UI bool bShowDebuggerOnLoad; @@ -123,7 +121,26 @@ public: bool bGridView2; bool bGridView3; - + // Control + int iTouchButtonOpacity; + float fButtonScale; + //space between PSP buttons + int iActionButtonSpacing; + //the PSP button's center (triangle, circle, square, cross) + int iActionButtonCenterX, iActionButtonCenterY; + //radius of the D-pad (PSP cross) + int iDpadRadius; + //the D-pad (PSP cross) position + int iDpadX, iDpadY; + //the start key position + int iStartKeyX, iStartKeyY; + //the select key position; + int iSelectKeyX, iSelectKeyY; + int iUnthrottleKeyX, iUnthrottleKeyY; + int iLKeyX, iLKeyY; + int iRKeyX, iRKeyY; + //position of the analog stick + int iAnalogStickX, iAnalogStickY; // GLES backend-specific hacks. Not saved to the ini file, do not add checkboxes. Will be made into // proper options when good enough. diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 38bfa40e71..6acb55cf97 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -415,6 +415,7 @@ static const struct { int from, to; } legacy_touch_mapping[12] = { }; void EmuScreen::CreateViews() { + InitPadLayout(); root_ = CreatePadLayout(&pauseTrigger_); if (g_Config.bShowDeveloperMenu) { root_->Add(new UI::Button("DevMenu"))->OnClick.Handle(this, &EmuScreen::OnDevTools); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 8b433693db..a9bdbb1183 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -29,6 +29,8 @@ #include "UI/MiscScreens.h" #include "UI/ControlMappingScreen.h" #include "UI/DevScreens.h" +//yuck. need a better name +#include "UI/TouchControlLayoutScreen.h" #include "Core/Config.h" #include "Core/Host.h" @@ -204,6 +206,7 @@ void GameSettingsScreen::CreateViews() { tabHolder->AddTab(ms->T("Controls"), controlsSettingsScroll); controlsSettings->Add(new ItemHeader(ms->T("Controls"))); controlsSettings->Add(new Choice(c->T("Control Mapping")))->OnClick.Handle(this, &GameSettingsScreen::OnControlMapping); + #ifdef USING_GLES2 controlsSettings->Add(new CheckBox(&g_Config.bHapticFeedback, c->T("HapticFeedback", "Haptic Feedback (vibration)"))); controlsSettings->Add(new CheckBox(&g_Config.bAccelerometerToAnalogHoriz, c->T("Tilt", "Tilt to Analog (horizontal)"))); @@ -211,6 +214,7 @@ void GameSettingsScreen::CreateViews() { #endif controlsSettings->Add(new ItemHeader(c->T("OnScreen", "On-Screen Touch Controls"))); controlsSettings->Add(new CheckBox(&g_Config.bShowTouchControls, c->T("OnScreen", "On-Screen Touch Controls"))); + controlsSettings->Add(new Choice(c->T("Reposition on-screen Controls")))->OnClick.Handle(this, &GameSettingsScreen::OnTouchControlLayout); controlsSettings->Add(new PopupSliderChoice(&g_Config.iTouchButtonOpacity, 0, 100, c->T("Button Opacity"), screenManager())); controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fButtonScale, 0.80, 2.0, c->T("Button Scaling"), screenManager())); controlsSettings->Add(new CheckBox(&g_Config.bShowAnalogStick, c->T("Show Left Analog Stick"))); @@ -453,6 +457,11 @@ UI::EventReturn GameSettingsScreen::OnControlMapping(UI::EventParams &e) { return UI::EVENT_DONE; } +UI::EventReturn GameSettingsScreen::OnTouchControlLayout(UI::EventParams &e){ + screenManager()->push(new TouchControlLayoutScreen()); + return UI::EVENT_DONE; +}; + void DeveloperToolsScreen::CreateViews() { using namespace UI; root_ = new ScrollView(ORIENT_VERTICAL); diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 5e457b8c95..77aa17931e 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -48,6 +48,7 @@ private: // Event handlers UI::EventReturn OnControlMapping(UI::EventParams &e); + UI::EventReturn OnTouchControlLayout(UI::EventParams &e); UI::EventReturn OnDumpNextFrameToLog(UI::EventParams &e); UI::EventReturn OnBack(UI::EventParams &e); UI::EventReturn OnReloadCheats(UI::EventParams &e); diff --git a/UI/GamepadEmu.cpp b/UI/GamepadEmu.cpp index 1c7cb933f6..adc0447a3f 100644 --- a/UI/GamepadEmu.cpp +++ b/UI/GamepadEmu.cpp @@ -269,32 +269,167 @@ void PSPStick::ProcessTouch(float x, float y, bool down) { } } - - -UI::ViewGroup *CreatePadLayout(bool *pause) { - using namespace UI; - - AnchorLayout *root = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); +void InitPadLayout(){ // TODO: See if we can make some kind of global scaling for views instead of this hackery. float scale = g_Config.fButtonScale; - // const int button_spacing = 50 * controlScale; - const int button_spacing = 50 * scale; - const int arrow_spacing = 40 * scale; + //PSP buttons (triangle, circle, square, cross)--------------------- + //space between the PSP buttons (traingle, circle, square and cross) + const int Action_button_spacing = 50 * scale; - const int circleX = 40 * scale; - const int circleY = 120 * scale; + if(g_Config.iActionButtonSpacing == -1){ + g_Config.iActionButtonSpacing = Action_button_spacing; + } - const int startX = 170 * scale; - const int leftX = 40 * scale; - const int leftY = (g_Config.bShowAnalogStick ? 250 : 120) * scale; - const int stickX = leftX + arrow_spacing; - const int stickY = 80 * scale; - const int bottomStride = 100 * scale; + //position of the circle button (the PSP circle button). It is the farthest to the left + int Action_button_center_X = dp_xres - Action_button_spacing * 2; + int Action_button_center_Y = dp_yres - Action_button_spacing * 2; - const int crosspadRadius = 40 * scale; + if(g_Config.iActionButtonCenterX == -1 || g_Config.iActionButtonCenterY == -1 ){ + //setup defaults + g_Config.iActionButtonCenterX = Action_button_center_X; + g_Config.iActionButtonCenterY = Action_button_center_Y; + } + + //D-PAD (up down left right) (aka PSP cross)-------------------------------------------------------------- + //radius to the D-pad + const int D_pad_Radius = 40 * scale; + + if(g_Config.iDpadRadius == -1){ + g_Config.iDpadRadius = D_pad_Radius; + } + + int D_pad_X = 2.5 * D_pad_Radius; + int D_pad_Y = dp_yres - D_pad_Radius; + if(g_Config.bShowAnalogStick){ + D_pad_Y -= 200 * scale; + } + + if(g_Config.iDpadX == -1 || g_Config.iDpadY == -1 ){ + //setup defaults + g_Config.iDpadX = D_pad_X; + g_Config.iDpadY = D_pad_Y; + } + + //analog stick------------------------------------------------------- + //keep the analog stick right below the D pad + int analog_stick_X = D_pad_X; + int analog_stick_Y = dp_yres - 80 * scale; + + if(g_Config.iAnalogStickX == -1 || g_Config.iAnalogStickY == -1 ){ + g_Config.iAnalogStickX = analog_stick_X; + g_Config.iAnalogStickY = analog_stick_Y; + } + + //select, start, throttle-------------------------------------------- + //space between the bottom keys (space between select, start and un-throttle) + const int bottom_key_spacing = 100 * scale; + + int start_key_X = dp_xres / 2 - (bottom_key_spacing) * scale; + int start_key_Y = dp_yres - 60 * scale; + + if(g_Config.iStartKeyX == -1 || g_Config.iStartKeyY == -1 ){ + g_Config.iStartKeyX = start_key_X; + g_Config.iStartKeyY = start_key_Y; + } + + + int select_key_X = dp_xres / 2; + int select_key_Y = dp_yres - 60 * scale; + + if(g_Config.iSelectKeyX == -1 || g_Config.iSelectKeyY == -1 ){ + g_Config.iSelectKeyX = select_key_X; + g_Config.iSelectKeyY = select_key_Y; + } + + int unthrottle_key_X = dp_xres / 2 + (bottom_key_spacing); + int unthrottle_key_Y = dp_yres - 60 * scale; + + if(g_Config.iUnthrottleKeyX == -1 || g_Config.iUnthrottleKeyY == -1 ){ + g_Config.iUnthrottleKeyX = unthrottle_key_X; + g_Config.iUnthrottleKeyY = unthrottle_key_Y; + } + + //L and R------------------------------------------------------------ + int l_key_X = 70 * scale; + int l_key_Y = 40 * scale; + + if(g_Config.iLKeyX == -1 || g_Config.iLKeyY == -1 ){ + g_Config.iLKeyX = l_key_X; + g_Config.iLKeyY = l_key_Y; + } + + int r_key_X = dp_xres - 60 * scale; + int r_key_Y = 40 * scale; + + if(g_Config.iRKeyX == -1 || g_Config.iRKeyY == -1 ){ + g_Config.iRKeyX = r_key_X; + g_Config.iRKeyY = r_key_Y; + } + +}; + + + +UI::ViewGroup *CreatePadLayout(bool *pause) { + //standard coord system + + using namespace UI; + + AnchorLayout *root = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); + + //PSP buttons (triangle, circle, square, cross)--------------------- + //space between the PSP buttons (traingle, circle, square and cross) + const int Action_button_spacing = g_Config.iActionButtonSpacing; + //position of the circle button (the PSP circle button). It is the farthest to the left + int Action_button_center_X = g_Config.iActionButtonCenterX; + int Action_button_center_Y = g_Config.iActionButtonCenterY; + + const int Action_circle_button_X = Action_button_center_X - Action_button_spacing; + const int Action_circle_button_Y = Action_button_center_Y; + + const int Action_cross_button_X = Action_button_center_X; + const int Action_cross_button_Y = Action_button_center_Y + Action_button_spacing; + + const int Action_triangle_button_X = Action_button_center_X; + const int Action_triangle_button_Y = Action_button_center_Y - Action_button_spacing; + + const int Action_square_button_X = Action_button_center_X + Action_button_spacing; + const int Action_square_button_Y = Action_button_center_Y; + + //D-PAD (up down left right) (aka PSP cross)-------------------------------------------------------------- + //radius to the D-pad + const int D_pad_Radius = g_Config.iDpadRadius; + + int D_pad_X = g_Config.iDpadX; + int D_pad_Y = g_Config.iDpadY; + + //select, start, throttle-------------------------------------------- + //space between the bottom keys (space between select, start and un-throttle) + int start_key_X = g_Config.iStartKeyX; + int start_key_Y = g_Config.iStartKeyY; + + + int select_key_X = g_Config.iSelectKeyX; + int select_key_Y = g_Config.iSelectKeyY; + + int unthrottle_key_X = g_Config.iUnthrottleKeyX; + int unthrottle_key_Y = g_Config.iUnthrottleKeyY; + + //L and R------------------------------------------------------------ + int l_key_X = g_Config.iLKeyX; + int l_key_Y = g_Config.iLKeyY; + + int r_key_X = g_Config.iRKeyX; + int r_key_Y = g_Config.iRKeyY; + + + //analog stick------------------------------------------------------- + int analog_stick_X = g_Config.iAnalogStickX; + int analog_stick_Y = g_Config.iAnalogStickY; + const int halfW = dp_xres / 2; #if USE_PAUSE_BUTTON @@ -302,23 +437,24 @@ UI::ViewGroup *CreatePadLayout(bool *pause) { #endif if (g_Config.bShowTouchControls) { - root->Add(new BoolButton(&PSP_CoreParameter().unthrottle, I_RECT, I_ARROW, scale, new AnchorLayoutParams(NONE, NONE, startX + 2 * bottomStride, 30, true)))->SetAngle(180); + + float scale = g_Config.fButtonScale; + root->Add(new PSPButton(CTRL_CIRCLE, I_ROUND, I_CIRCLE, scale, new AnchorLayoutParams(Action_circle_button_X, Action_circle_button_Y, NONE, NONE, true))); + root->Add(new PSPButton(CTRL_CROSS, I_ROUND, I_CROSS, scale, new AnchorLayoutParams(Action_cross_button_X, Action_cross_button_Y, NONE, NONE, true))); + root->Add(new PSPButton(CTRL_TRIANGLE, I_ROUND, I_TRIANGLE, scale, new AnchorLayoutParams(Action_triangle_button_X, Action_triangle_button_Y, NONE, NONE, true))); + root->Add(new PSPButton(CTRL_SQUARE, I_ROUND, I_SQUARE, scale, new AnchorLayoutParams(Action_square_button_X, Action_square_button_Y, NONE, NONE, true))); - root->Add(new PSPButton(CTRL_CIRCLE, I_ROUND, I_CIRCLE, scale, new AnchorLayoutParams(NONE, NONE, circleX, circleY, true))); - root->Add(new PSPButton(CTRL_CROSS, I_ROUND, I_CROSS, scale, new AnchorLayoutParams(NONE, NONE, circleX + button_spacing, circleY - button_spacing, true))); - root->Add(new PSPButton(CTRL_TRIANGLE, I_ROUND, I_TRIANGLE, scale, new AnchorLayoutParams(NONE, NONE, circleX + button_spacing, circleY + button_spacing, true))); - root->Add(new PSPButton(CTRL_SQUARE, I_ROUND, I_SQUARE, scale, new AnchorLayoutParams(NONE, NONE, circleX + button_spacing * 2, circleY, true))); + root->Add(new PSPButton(CTRL_START, I_RECT, I_START, scale, new AnchorLayoutParams(start_key_X, start_key_Y, NONE, NONE, true))); + root->Add(new PSPButton(CTRL_SELECT, I_RECT, I_SELECT, scale, new AnchorLayoutParams(select_key_X, select_key_Y, NONE, NONE, true))); + root->Add(new BoolButton(&PSP_CoreParameter().unthrottle, I_RECT, I_ARROW, scale, new AnchorLayoutParams(unthrottle_key_X, unthrottle_key_Y, NONE, NONE, true)))->SetAngle(180); - root->Add(new PSPButton(CTRL_START, I_RECT, I_START, scale, new AnchorLayoutParams(NONE, NONE, startX, 30, true))); - root->Add(new PSPButton(CTRL_SELECT, I_RECT, I_SELECT, scale, new AnchorLayoutParams(NONE, NONE, startX + bottomStride, 30, true))); + root->Add(new PSPButton(CTRL_LTRIGGER, I_SHOULDER, I_L, scale, new AnchorLayoutParams(l_key_X, l_key_Y, NONE, NONE, true))); + root->Add(new PSPButton(CTRL_RTRIGGER, I_SHOULDER, I_R, scale, new AnchorLayoutParams(r_key_X,r_key_Y, NONE, NONE, true)))->FlipImageH(true); - root->Add(new PSPButton(CTRL_LTRIGGER, I_SHOULDER, I_L, scale, new AnchorLayoutParams(10, 10, NONE, NONE, false))); - root->Add(new PSPButton(CTRL_RTRIGGER, I_SHOULDER, I_R, scale, new AnchorLayoutParams(NONE, 10, 10, NONE, false)))->FlipImageH(true); - - root->Add(new PSPCross(I_DIR, I_ARROW, scale, crosspadRadius, new AnchorLayoutParams(leftX + arrow_spacing, NONE, NONE, leftY, true))); + root->Add(new PSPCross(I_DIR, I_ARROW, scale, D_pad_Radius, new AnchorLayoutParams(D_pad_X, D_pad_Y, NONE, NONE, true))); if (g_Config.bShowAnalogStick) { - root->Add(new PSPStick(I_STICKBG, I_STICK, 0, scale, new AnchorLayoutParams(stickX, NONE, NONE, stickY, true))); + root->Add(new PSPStick(I_STICKBG, I_STICK, 0, scale, new AnchorLayoutParams(analog_stick_X, analog_stick_Y, NONE, NONE, true))); } } diff --git a/UI/GamepadEmu.h b/UI/GamepadEmu.h index c29783db4f..7f70338c23 100644 --- a/UI/GamepadEmu.h +++ b/UI/GamepadEmu.h @@ -41,11 +41,11 @@ public: protected: uint32_t pointerDownMask_; + float scale_; private: int bgImg_; int img_; - float scale_; float angle_; bool flipImageH_; }; @@ -120,4 +120,7 @@ private: bool lastPointerDown_[MAX_POINTERS]; }; +//initializes the layout from Config. if a default layout does not exist, +//it sets up default values +void InitPadLayout(); UI::ViewGroup *CreatePadLayout(bool *pause); diff --git a/UI/TouchControlLayoutScreen.cpp b/UI/TouchControlLayoutScreen.cpp new file mode 100644 index 0000000000..56c5191a24 --- /dev/null +++ b/UI/TouchControlLayoutScreen.cpp @@ -0,0 +1,271 @@ +#include "TouchControlLayoutScreen.h" +#include "Core/Config.h" +#include "Core/System.h" +#include "base/colorutil.h" +#include "ui/ui_context.h" +#include "ui_atlas.h" +#include "gfx_es2/draw_buffer.h" +#include "GamepadEmu.h" +#include "i18n/i18n.h" + +static const int leftMargin = 140; + + +//convert from screen coordinates (leftMargin to dp_xres) to actual fullscreen coordinates (0 to dp_xres) +int toFullscreenCoord(int screenx){ + return ((float)dp_xres / (dp_xres - leftMargin)) * (screenx - leftMargin); +} + +//convert from external fullscreen coordinates(0 to dp_xres) to the current partial coordinates (leftMargin to dp_xres) +int fromFullscreenCoord(int controllerX){ + return leftMargin + ((dp_xres - leftMargin) / (float)dp_xres) * controllerX; +}; + +class DragDropButton : public MultiTouchButton{ +public: + DragDropButton(int &x, int &y, int bgImg, int img, float scale) + : MultiTouchButton(bgImg, img, scale, new UI::AnchorLayoutParams(fromFullscreenCoord(x), y, UI::NONE, UI::NONE, true)), x_(x), y_(y){ + scale_ = scale; + } + + virtual bool IsDown(){ + //don't want the button to enlarge and throw the user's perspective + //of button size off whack. + return false; + }; + + void SavePosition(){ + x_ = toFullscreenCoord(bounds_.centerX()); + y_ = bounds_.centerY(); + } + +private: + int &x_, &y_; +}; + + +class PSPActionButtons : public DragDropButton{ +public: + PSPActionButtons(int &x, int &y, int actionButtonSpacing, float scale) + : DragDropButton(x, y, -1, -1, scale), actionButtonSpacing_(actionButtonSpacing){ + using namespace UI; + roundId_ = I_ROUND; + + circleId_ = I_CIRCLE; + crossId_ = I_CROSS; + triangleId_ = I_TRIANGLE; + squareId_ = I_SQUARE; + }; + + void Draw(UIContext &dc){ + float opacity = g_Config.iTouchButtonOpacity / 100.0f; + + + uint32_t colorBg = colorAlpha(0xc0b080, opacity); + uint32_t color = colorAlpha(0xFFFFFF, opacity); + + int centerX = bounds_.centerX(); + int centerY = bounds_.centerY(); + + dc.Draw()->DrawImageRotated(roundId_, centerX + actionButtonSpacing_, centerY, scale_, 0, colorBg, false); + dc.Draw()->DrawImageRotated(circleId_, centerX + actionButtonSpacing_, centerY, scale_, 0, color, false); + + dc.Draw()->DrawImageRotated(roundId_, centerX, centerY + actionButtonSpacing_, scale_, 0, colorBg, false); + dc.Draw()->DrawImageRotated(crossId_, centerX, centerY + actionButtonSpacing_, scale_, 0, color, false); + + dc.Draw()->DrawImageRotated(roundId_, centerX, centerY - actionButtonSpacing_, scale_, 0, colorBg, false); + dc.Draw()->DrawImageRotated(triangleId_, centerX, centerY - actionButtonSpacing_, scale_, 0, color, false); + + dc.Draw()->DrawImageRotated(roundId_, centerX - actionButtonSpacing_, centerY, scale_, 0, colorBg, false); + dc.Draw()->DrawImageRotated(squareId_, centerX - actionButtonSpacing_, centerY, scale_, 0, color, false); + }; + + void GetContentDimensions(const UIContext &dc, float &w, float &h) const{ + const AtlasImage &image = dc.Draw()->GetAtlas()->images[roundId_]; + w = 2 * actionButtonSpacing_ + image.w * scale_; + h = 2 * actionButtonSpacing_ + image.h * scale_; + + //w += 2 * actionButtonSpacing_; + //h += 2 * actionButtonSpacing_; + }; +private: + int roundId_; + int circleId_, crossId_, triangleId_, squareId_; + + int actionButtonSpacing_; +}; + +class PSPDPadButtons : public DragDropButton{ +public: + PSPDPadButtons(int &x, int &y, int DpadRadius, float scale) + : DragDropButton(x, y, -1, -1, scale), DpadRadius_(DpadRadius){ + } + + void Draw(UIContext &dc){ + float opacity = g_Config.iTouchButtonOpacity / 100.0f; + + uint32_t colorBg = colorAlpha(0xc0b080, opacity); + uint32_t color = colorAlpha(0xFFFFFF, opacity); + + static const float xoff[4] = {1, 0, -1, 0}; + static const float yoff[4] = {0, 1, 0, -1}; + + for (int i = 0; i < 4; i++) { + float x = bounds_.centerX() + xoff[i] * DpadRadius_; + float y = bounds_.centerY() + yoff[i] * DpadRadius_; + float angle = i * M_PI / 2; + + dc.Draw()->DrawImageRotated(I_DIR, x, y, scale_, angle + PI, colorBg, false); + dc.Draw()->DrawImageRotated(I_ARROW, x, y, scale_, angle + PI, color); + } + } + + void GetContentDimensions(const UIContext &dc, float &w, float &h) const{ + const AtlasImage &image = dc.Draw()->GetAtlas()->images[I_DIR]; + w = 2 * DpadRadius_ + image.w * scale_; + h = 2 * DpadRadius_ + image.h * scale_; + + //w += 2 * DpadRadius_; + //h += 2 * DpadRadius_; + }; + +private: + int DpadRadius_; +}; + + + +TouchControlLayoutScreen::TouchControlLayoutScreen(){ + pickedControl_ = 0; +}; + +void TouchControlLayoutScreen::touch(const TouchInput &touch){ + UIScreen::touch(touch); + + using namespace UI; + +//this is if - not else if as up and move can occur simultaneously + if ((touch.flags & TOUCH_MOVE) && pickedControl_ != 0){ + const Bounds &bounds = pickedControl_->GetBounds(); + + int mintouchX = leftMargin + bounds.w * 0.5; + int maxTouchX = dp_xres - bounds.w * 0.5; + + int minTouchY = bounds.h * 0.5; + int maxTouchY = dp_yres - bounds.h * 0.5; + + 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; + } + + ILOG("position: x = %d; y = %d", newX, newY); + pickedControl_->ReplaceLayoutParams(new UI::AnchorLayoutParams(newX, newY, NONE, NONE,true)); + } + + else if ((touch.flags & TOUCH_DOWN) && pickedControl_ == 0){ + ILOG("->->->picked up") + pickedControl_ = getPickedControl(touch.x, touch.y); + } + + else if ((touch.flags & TOUCH_UP) && pickedControl_ != 0){ + pickedControl_->SavePosition(); + ILOG("->->->dropped down") + pickedControl_ = 0; + } + + +}; + +UI::EventReturn TouchControlLayoutScreen::OnBack(UI::EventParams &e){ + g_Config.Save(); + + if(PSP_IsInited()) { + screenManager()->finishDialog(this, DR_CANCEL); + } else { + screenManager()->finishDialog(this, DR_OK); + } + + return UI::EVENT_DONE; +}; + + + + +void TouchControlLayoutScreen::CreateViews(){ +//setup g_Config for button layout + InitPadLayout(); + + + using namespace UI; + + I18NCategory *d = GetI18NCategory("Dialog"); + + root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); + + Choice *back = new Choice(d->T("Back"), "", false, new AnchorLayoutParams(leftMargin, WRAP_CONTENT, 10, NONE, NONE, 10)); + back->OnClick.Handle(this, &TouchControlLayoutScreen::OnBack); + root_->Add(back); + + + TabHolder *tabHolder = new TabHolder(ORIENT_VERTICAL, leftMargin, new AnchorLayoutParams(10, 0, 10, 0, false)); + root_->Add(tabHolder); + + //this is more for show than anything else. It's used to provide a boundary + //so that buttons like back can be placed within the boundary. + //serves no other purpose. + AnchorLayout *controlsHolder = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); + + float scale = g_Config.fButtonScale; + controls_.push_back(new PSPActionButtons(g_Config.iActionButtonCenterX, g_Config.iActionButtonCenterY, g_Config.iActionButtonSpacing, scale)); + controls_.push_back(new PSPDPadButtons(g_Config.iDpadX, g_Config.iDpadY, g_Config.iDpadRadius, scale)); + + controls_.push_back(new DragDropButton(g_Config.iSelectKeyX, g_Config.iSelectKeyY, I_RECT, I_SELECT, scale)); + controls_.push_back(new DragDropButton(g_Config.iStartKeyX, g_Config.iStartKeyY, I_RECT, I_START, scale)); + controls_.push_back(new DragDropButton(g_Config.iUnthrottleKeyX, g_Config.iUnthrottleKeyY, I_RECT, I_ARROW, scale)); + + controls_.push_back(new DragDropButton(g_Config.iLKeyX, g_Config.iLKeyY, I_SHOULDER, I_L, scale)); + controls_.push_back(new DragDropButton(g_Config.iRKeyX, g_Config.iRKeyY, I_SHOULDER, I_R, scale)); + + if (g_Config.bShowAnalogStick) { + controls_.push_back(new DragDropButton(g_Config.iAnalogStickX, g_Config.iAnalogStickY, I_STICKBG, I_STICK, scale)); + }; + + I18NCategory *c = GetI18NCategory("Controls"); + tabHolder->AddTab(c->T("Controls"), controlsHolder); + + + for(UI::View *control : controls_){ + root_->Add(control); + } +}; + + + +//return the control which was picked up bu the touchEvent. If a control +//was already picked up, then it's being dragged around, so just return that instead +DragDropButton *TouchControlLayoutScreen::getPickedControl(const int x, const int y){ + + if(pickedControl_ != 0){ + return pickedControl_; + } + + for(DragDropButton *control : controls_){ + const Bounds &bounds = control->GetBounds(); + static const int thresholdFactor = 1.5; + + Bounds tolerantBounds(bounds.x, bounds.y, bounds.w * thresholdFactor, bounds.h * thresholdFactor); + if(tolerantBounds.Contains(x, y)){ + return control; + } + } + + return 0; +} diff --git a/UI/TouchControlLayoutScreen.h b/UI/TouchControlLayoutScreen.h new file mode 100644 index 0000000000..514e152784 --- /dev/null +++ b/UI/TouchControlLayoutScreen.h @@ -0,0 +1,42 @@ +// 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 "base/functional.h" +#include "ui/view.h" +#include "MiscScreens.h" +#include + +class DragDropButton; + +class TouchControlLayoutScreen : public UIDialogScreenWithBackground{ +public: + + TouchControlLayoutScreen(); + + virtual void CreateViews(); + virtual void touch(const TouchInput &touch); + +protected: + virtual UI::EventReturn OnBack(UI::EventParams &e); + +private: + DragDropButton *pickedControl_; + std::vector controls_; + DragDropButton *getPickedControl(const int x, const int y); +}; diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 5f805afa33..3498f2cf68 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -112,6 +112,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/UI/GameScreen.cpp \ $(SRC)/UI/ControlMappingScreen.cpp \ $(SRC)/UI/GameSettingsScreen.cpp \ + $(SRC)/UI/TouchControlLayoutScreen.cpp \ $(SRC)/UI/CwCheatScreen.cpp \ $(SRC)/ext/disarm.cpp \ $(SRC)/ext/libkirk/AES.c \