2014-12-22 09:48:17 +00:00
// Copyright (c) 2014- 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/.
2018-09-22 06:24:36 +00:00
# include <algorithm>
2020-01-26 18:43:18 +00:00
# include <memory>
2020-09-29 10:19:22 +00:00
2020-10-04 21:24:14 +00:00
# include "Common/Render/DrawBuffer.h"
2020-10-04 18:48:47 +00:00
# include "Common/UI/View.h"
# include "Common/UI/ViewGroup.h"
# include "Common/UI/Context.h"
# include "Common/UI/UIScreen.h"
2020-10-04 21:24:14 +00:00
# include "Common/GPU/thin3d.h"
2014-12-22 09:48:17 +00:00
2020-10-01 11:05:04 +00:00
# include "Common/Data/Text/I18n.h"
2020-09-29 10:19:22 +00:00
# include "Common/StringUtils.h"
2023-06-30 15:15:49 +00:00
# include "Common/System/OSD.h"
2023-03-22 21:07:29 +00:00
# include "Common/System/Request.h"
2022-11-17 11:19:17 +00:00
# include "Common/VR/PPSSPPVR.h"
2022-11-21 19:15:22 +00:00
# include "Common/UI/AsyncImageFileView.h"
2020-09-29 10:19:22 +00:00
2023-12-20 15:55:39 +00:00
# include "Core/KeyMap.h"
2014-12-22 09:48:17 +00:00
# include "Core/Reporting.h"
# include "Core/SaveState.h"
# include "Core/System.h"
2024-01-21 11:02:30 +00:00
# include "Core/Core.h"
2014-12-22 09:48:17 +00:00
# include "Core/Config.h"
2023-07-02 10:00:13 +00:00
# include "Core/RetroAchievements.h"
2014-12-22 09:48:17 +00:00
# include "Core/ELF/ParamSFO.h"
2020-10-04 08:30:18 +00:00
# include "Core/HLE/sceDisplay.h"
# include "Core/HLE/sceUmd.h"
2014-12-22 09:48:17 +00:00
# include "GPU/GPUCommon.h"
2015-07-29 09:48:20 +00:00
# include "GPU/GPUState.h"
2014-12-22 09:48:17 +00:00
# include "UI/PauseScreen.h"
# include "UI/GameSettingsScreen.h"
# include "UI/ReportScreen.h"
# include "UI/CwCheatScreen.h"
# include "UI/MainScreen.h"
2024-09-18 11:37:38 +00:00
# include "UI/GameScreen.h"
2016-05-28 04:25:05 +00:00
# include "UI/OnScreenDisplay.h"
2014-12-22 09:48:17 +00:00
# include "UI/GameInfoCache.h"
2022-11-22 13:16:24 +00:00
# include "UI/DisplayLayoutScreen.h"
2023-06-15 11:40:37 +00:00
# include "UI/RetroAchievementScreens.h"
2024-09-24 11:50:21 +00:00
# include "UI/BackgroundAudio.h"
2014-12-22 09:48:17 +00:00
2024-01-19 12:44:49 +00:00
static void AfterSaveStateAction ( SaveState : : Status status , std : : string_view message , void * ) {
2021-08-02 13:40:59 +00:00
if ( ! message . empty ( ) & & ( ! g_Config . bDumpFrames | | ! g_Config . bDumpVideoOutput ) ) {
2023-06-20 12:40:46 +00:00
g_OSD . Show ( status = = SaveState : : Status : : SUCCESS ? OSDType : : MESSAGE_SUCCESS : OSDType : : MESSAGE_ERROR ,
message , status = = SaveState : : Status : : SUCCESS ? 2.0 : 5.0 ) ;
2021-08-02 13:40:59 +00:00
}
}
2014-12-31 19:42:28 +00:00
class ScreenshotViewScreen : public PopupScreen {
public :
2023-04-05 22:34:50 +00:00
ScreenshotViewScreen ( const Path & filename , std : : string title , int slot , Path gamePath )
2021-08-02 13:40:59 +00:00
: PopupScreen ( title ) , filename_ ( filename ) , slot_ ( slot ) , gamePath_ ( gamePath ) { } // PopupScreen will translate Back on its own
2014-12-31 19:42:28 +00:00
int GetSlot ( ) const {
return slot_ ;
}
2022-09-17 20:29:33 +00:00
const char * tag ( ) const override { return " ScreenshotView " ; }
2014-12-31 19:42:28 +00:00
protected :
2018-09-01 21:56:56 +00:00
bool FillVertical ( ) const override { return false ; }
UI : : Size PopupWidth ( ) const override { return 500 ; }
2014-12-31 19:42:28 +00:00
bool ShowButtons ( ) const override { return true ; }
2018-09-01 21:56:56 +00:00
void CreatePopupContents ( UI : : ViewGroup * parent ) override {
2021-08-02 13:40:59 +00:00
using namespace UI ;
2023-04-05 22:34:50 +00:00
auto pa = GetI18NCategory ( I18NCat : : PAUSE ) ;
auto di = GetI18NCategory ( I18NCat : : DIALOG ) ;
2021-08-02 13:40:59 +00:00
2021-09-01 03:18:22 +00:00
ScrollView * scroll = new ScrollView ( ORIENT_VERTICAL , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT , 1.0f ) ) ;
2021-08-02 13:40:59 +00:00
LinearLayout * content = new LinearLayout ( ORIENT_VERTICAL ) ;
Margins contentMargins ( 10 , 0 ) ;
content - > Add ( new AsyncImageFileView ( filename_ , IS_KEEP_ASPECT , new LinearLayoutParams ( 480 , 272 , contentMargins ) ) ) - > SetCanBeFocused ( false ) ;
GridLayoutSettings gridsettings ( 240 , 64 , 5 ) ;
gridsettings . fillCells = true ;
GridLayout * grid = content - > Add ( new GridLayoutList ( gridsettings , new LayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ) ;
Choice * back = new Choice ( di - > T ( " Back " ) ) ;
Choice * undoButton = new Choice ( pa - > T ( " Undo last save " ) ) ;
undoButton - > SetEnabled ( SaveState : : HasUndoSaveInSlot ( gamePath_ , slot_ ) ) ;
grid - > Add ( new Choice ( pa - > T ( " Save State " ) ) ) - > OnClick . Handle ( this , & ScreenshotViewScreen : : OnSaveState ) ;
grid - > Add ( new Choice ( pa - > T ( " Load State " ) ) ) - > OnClick . Handle ( this , & ScreenshotViewScreen : : OnLoadState ) ;
grid - > Add ( back ) - > OnClick . Handle < UIScreen > ( this , & UIScreen : : OnBack ) ;
grid - > Add ( undoButton ) - > OnClick . Handle ( this , & ScreenshotViewScreen : : OnUndoState ) ;
scroll - > Add ( content ) ;
parent - > Add ( scroll ) ;
2014-12-31 19:42:28 +00:00
}
private :
2021-08-02 13:40:59 +00:00
UI : : EventReturn OnSaveState ( UI : : EventParams & e ) ;
UI : : EventReturn OnLoadState ( UI : : EventParams & e ) ;
UI : : EventReturn OnUndoState ( UI : : EventParams & e ) ;
2021-05-05 23:31:38 +00:00
Path filename_ ;
2021-08-02 13:40:59 +00:00
Path gamePath_ ;
2014-12-31 19:42:28 +00:00
int slot_ ;
} ;
2021-08-02 13:40:59 +00:00
UI : : EventReturn ScreenshotViewScreen : : OnSaveState ( UI : : EventParams & e ) {
g_Config . iCurrentStateSlot = slot_ ;
SaveState : : SaveSlot ( gamePath_ , slot_ , & AfterSaveStateAction ) ;
TriggerFinish ( DR_OK ) ; //OK will close the pause screen as well
return UI : : EVENT_DONE ;
}
UI : : EventReturn ScreenshotViewScreen : : OnLoadState ( UI : : EventParams & e ) {
g_Config . iCurrentStateSlot = slot_ ;
SaveState : : LoadSlot ( gamePath_ , slot_ , & AfterSaveStateAction ) ;
TriggerFinish ( DR_OK ) ;
return UI : : EVENT_DONE ;
}
UI : : EventReturn ScreenshotViewScreen : : OnUndoState ( UI : : EventParams & e ) {
SaveState : : UndoSaveSlot ( gamePath_ , slot_ ) ;
TriggerFinish ( DR_CANCEL ) ;
return UI : : EVENT_DONE ;
}
2014-12-31 14:33:43 +00:00
class SaveSlotView : public UI : : LinearLayout {
public :
2022-12-08 15:17:44 +00:00
SaveSlotView ( const Path & gamePath , int slot , bool vertical , UI : : LayoutParams * layoutParams = nullptr ) ;
2014-12-31 14:33:43 +00:00
void GetContentDimensions ( const UIContext & dc , float & w , float & h ) const override {
w = 500 ; h = 90 ;
}
2015-06-11 18:22:16 +00:00
void Draw ( UIContext & dc ) override ;
2014-12-31 14:33:43 +00:00
2014-12-31 19:42:28 +00:00
int GetSlot ( ) const {
return slot_ ;
}
2021-05-05 23:31:38 +00:00
Path GetScreenshotFilename ( ) const {
2014-12-31 19:42:28 +00:00
return screenshotFilename_ ;
}
std : : string GetScreenshotTitle ( ) const {
2021-05-15 06:00:22 +00:00
return SaveState : : GetSlotDateAsString ( gamePath_ , slot_ ) ;
2014-12-31 19:42:28 +00:00
}
2014-12-31 14:33:43 +00:00
UI : : Event OnStateLoaded ;
UI : : Event OnStateSaved ;
2014-12-31 19:42:28 +00:00
UI : : Event OnScreenshotClicked ;
2014-12-31 14:33:43 +00:00
private :
2014-12-31 19:42:28 +00:00
UI : : EventReturn OnScreenshotClick ( UI : : EventParams & e ) ;
2014-12-31 14:33:43 +00:00
UI : : EventReturn OnSaveState ( UI : : EventParams & e ) ;
UI : : EventReturn OnLoadState ( UI : : EventParams & e ) ;
2017-11-23 17:08:39 +00:00
UI : : Button * saveStateButton_ = nullptr ;
UI : : Button * loadStateButton_ = nullptr ;
2014-12-31 14:33:43 +00:00
int slot_ ;
2021-05-05 23:31:38 +00:00
Path gamePath_ ;
Path screenshotFilename_ ;
2014-12-31 14:33:43 +00:00
} ;
2022-12-08 15:17:44 +00:00
SaveSlotView : : SaveSlotView ( const Path & gameFilename , int slot , bool vertical , UI : : LayoutParams * layoutParams ) : UI : : LinearLayout ( UI : : ORIENT_HORIZONTAL , layoutParams ) , slot_ ( slot ) , gamePath_ ( gameFilename ) {
2015-06-11 18:22:16 +00:00
using namespace UI ;
2021-05-15 06:00:22 +00:00
screenshotFilename_ = SaveState : : GenerateSaveSlotFilename ( gamePath_ , slot , SaveState : : SCREENSHOT_EXTENSION ) ;
2015-06-11 18:22:16 +00:00
Add ( new Spacer ( 5 ) ) ;
2020-11-30 12:55:38 +00:00
AsyncImageFileView * fv = Add ( new AsyncImageFileView ( screenshotFilename_ , IS_DEFAULT , new UI : : LayoutParams ( 82 * 2 , 47 * 2 ) ) ) ;
2017-05-30 11:52:29 +00:00
fv - > SetOverlayText ( StringFromFormat ( " %d " , slot_ + 1 ) ) ;
2015-06-11 18:22:16 +00:00
2023-04-05 22:34:50 +00:00
auto pa = GetI18NCategory ( I18NCat : : PAUSE ) ;
2015-06-11 18:22:16 +00:00
2022-11-19 19:54:26 +00:00
LinearLayout * lines = new LinearLayout ( ORIENT_VERTICAL , new LinearLayoutParams ( WRAP_CONTENT , WRAP_CONTENT ) ) ;
lines - > SetSpacing ( 2.0f ) ;
Add ( lines ) ;
2022-12-08 15:17:44 +00:00
LinearLayout * buttons = new LinearLayout ( vertical ? ORIENT_VERTICAL : ORIENT_HORIZONTAL , new LinearLayoutParams ( WRAP_CONTENT , WRAP_CONTENT ) ) ;
2022-11-19 19:54:26 +00:00
buttons - > SetSpacing ( 10.0f ) ;
lines - > Add ( buttons ) ;
2015-06-11 18:22:16 +00:00
2015-07-01 22:13:35 +00:00
saveStateButton_ = buttons - > Add ( new Button ( pa - > T ( " Save State " ) , new LinearLayoutParams ( 0.0 , G_VCENTER ) ) ) ;
2015-06-11 18:22:16 +00:00
saveStateButton_ - > OnClick . Handle ( this , & SaveSlotView : : OnSaveState ) ;
fv - > OnClick . Handle ( this , & SaveSlotView : : OnScreenshotClick ) ;
2021-05-15 06:00:22 +00:00
if ( SaveState : : HasSaveInSlot ( gamePath_ , slot ) ) {
2023-12-03 15:41:29 +00:00
if ( ! Achievements : : HardcoreModeActive ( ) ) {
2023-11-14 21:54:39 +00:00
loadStateButton_ = buttons - > Add ( new Button ( pa - > T ( " Load State " ) , new LinearLayoutParams ( 0.0 , G_VCENTER ) ) ) ;
loadStateButton_ - > OnClick . Handle ( this , & SaveSlotView : : OnLoadState ) ;
}
2015-06-11 18:22:16 +00:00
2021-05-15 06:00:22 +00:00
std : : string dateStr = SaveState : : GetSlotDateAsString ( gamePath_ , slot_ ) ;
2022-11-19 19:54:26 +00:00
if ( ! dateStr . empty ( ) ) {
2022-12-08 15:17:44 +00:00
TextView * dateView = new TextView ( dateStr , new LinearLayoutParams ( 0.0 , G_VCENTER ) ) ;
if ( vertical ) {
dateView - > SetSmall ( true ) ;
}
lines - > Add ( dateView ) - > SetShadow ( true ) ;
2015-06-11 18:22:16 +00:00
}
} else {
2021-05-05 23:31:38 +00:00
fv - > SetFilename ( Path ( ) ) ;
2015-06-11 18:22:16 +00:00
}
}
void SaveSlotView : : Draw ( UIContext & dc ) {
if ( g_Config . iCurrentStateSlot = = slot_ ) {
dc . FillRect ( UI : : Drawable ( 0x70000000 ) , GetBounds ( ) . Expand ( 3 ) ) ;
dc . FillRect ( UI : : Drawable ( 0x70FFFFFF ) , GetBounds ( ) . Expand ( 3 ) ) ;
}
UI : : LinearLayout : : Draw ( dc ) ;
}
2014-12-31 14:33:43 +00:00
UI : : EventReturn SaveSlotView : : OnLoadState ( UI : : EventParams & e ) {
g_Config . iCurrentStateSlot = slot_ ;
2021-05-15 06:00:22 +00:00
SaveState : : LoadSlot ( gamePath_ , slot_ , & AfterSaveStateAction ) ;
2017-03-22 01:34:52 +00:00
UI : : EventParams e2 { } ;
2014-12-31 19:42:28 +00:00
e2 . v = this ;
2014-12-31 14:33:43 +00:00
OnStateLoaded . Trigger ( e2 ) ;
return UI : : EVENT_DONE ;
}
UI : : EventReturn SaveSlotView : : OnSaveState ( UI : : EventParams & e ) {
g_Config . iCurrentStateSlot = slot_ ;
2021-05-15 06:00:22 +00:00
SaveState : : SaveSlot ( gamePath_ , slot_ , & AfterSaveStateAction ) ;
2017-03-22 01:34:52 +00:00
UI : : EventParams e2 { } ;
2014-12-31 19:42:28 +00:00
e2 . v = this ;
2014-12-31 14:33:43 +00:00
OnStateSaved . Trigger ( e2 ) ;
return UI : : EVENT_DONE ;
}
2014-12-31 19:42:28 +00:00
UI : : EventReturn SaveSlotView : : OnScreenshotClick ( UI : : EventParams & e ) {
2017-03-22 01:34:52 +00:00
UI : : EventParams e2 { } ;
2014-12-31 19:42:28 +00:00
e2 . v = this ;
OnScreenshotClicked . Trigger ( e2 ) ;
return UI : : EVENT_DONE ;
}
2017-03-15 05:01:18 +00:00
void GamePauseScreen : : update ( ) {
2014-12-22 09:48:17 +00:00
UpdateUIState ( UISTATE_PAUSEMENU ) ;
2017-03-15 05:01:18 +00:00
UIScreen : : update ( ) ;
2014-12-31 19:42:28 +00:00
if ( finishNextFrame_ ) {
2024-04-05 09:07:57 +00:00
TriggerFinish ( finishNextFrameResult_ ) ;
2014-12-31 19:42:28 +00:00
finishNextFrame_ = false ;
}
2022-11-17 11:19:17 +00:00
SetVRAppMode ( VRAppMode : : VR_MENU_MODE ) ;
2014-12-22 09:48:17 +00:00
}
2023-07-10 08:39:44 +00:00
GamePauseScreen : : GamePauseScreen ( const Path & filename )
: UIDialogScreenWithGameBackground ( filename ) {
2024-01-18 22:00:43 +00:00
// So we can tell if something blew up while on the pause screen.
std : : string assertStr = " PauseScreen: " + filename . GetFilename ( ) ;
SetExtraAssertInfo ( assertStr . c_str ( ) ) ;
2023-07-10 08:39:44 +00:00
}
2014-12-22 09:48:17 +00:00
GamePauseScreen : : ~ GamePauseScreen ( ) {
__DisplaySetWasPaused ( ) ;
}
2023-12-20 15:55:39 +00:00
bool GamePauseScreen : : key ( const KeyInput & key ) {
if ( ! UIScreen : : key ( key ) & & ( key . flags & KEY_DOWN ) ) {
// Special case to be able to unpause with a bound pause key.
// Normally we can't bind keys used in the UI.
InputMapping mapping ( key . deviceId , key . keyCode ) ;
std : : vector < int > pspButtons ;
KeyMap : : InputMappingToPspButton ( mapping , & pspButtons ) ;
for ( auto button : pspButtons ) {
if ( button = = VIRTKEY_PAUSE ) {
TriggerFinish ( DR_CANCEL ) ;
return true ;
}
}
return false ;
}
return false ;
}
2023-06-27 12:58:39 +00:00
void GamePauseScreen : : CreateSavestateControls ( UI : : LinearLayout * leftColumnItems , bool vertical ) {
2023-04-05 22:34:50 +00:00
auto pa = GetI18NCategory ( I18NCat : : PAUSE ) ;
2014-12-22 09:48:17 +00:00
2023-06-27 12:58:39 +00:00
static const int NUM_SAVESLOTS = 5 ;
2014-12-22 09:48:17 +00:00
2023-06-27 12:58:39 +00:00
using namespace UI ;
2014-12-22 09:48:17 +00:00
2015-02-16 21:41:01 +00:00
leftColumnItems - > SetSpacing ( 10.0 ) ;
2014-12-22 09:48:17 +00:00
for ( int i = 0 ; i < NUM_SAVESLOTS ; i + + ) {
2022-12-08 15:17:44 +00:00
SaveSlotView * slot = leftColumnItems - > Add ( new SaveSlotView ( gamePath_ , i , vertical , new LayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ) ;
2014-12-31 14:33:43 +00:00
slot - > OnStateLoaded . Handle ( this , & GamePauseScreen : : OnState ) ;
slot - > OnStateSaved . Handle ( this , & GamePauseScreen : : OnState ) ;
2014-12-31 19:42:28 +00:00
slot - > OnScreenshotClicked . Handle ( this , & GamePauseScreen : : OnScreenshotClicked ) ;
2014-12-22 09:48:17 +00:00
}
2015-02-15 10:21:17 +00:00
leftColumnItems - > Add ( new Spacer ( 0.0 ) ) ;
2014-12-22 09:48:17 +00:00
2021-08-03 19:20:01 +00:00
LinearLayout * buttonRow = leftColumnItems - > Add ( new LinearLayout ( ORIENT_HORIZONTAL ) ) ;
2023-12-03 15:41:29 +00:00
if ( g_Config . bEnableStateUndo & & ! Achievements : : HardcoreModeActive ( ) ) {
2021-08-07 11:28:43 +00:00
UI : : Choice * loadUndoButton = buttonRow - > Add ( new Choice ( pa - > T ( " Undo last load " ) ) ) ;
2021-08-03 08:04:49 +00:00
loadUndoButton - > SetEnabled ( SaveState : : HasUndoLoad ( gamePath_ ) ) ;
loadUndoButton - > OnClick . Handle ( this , & GamePauseScreen : : OnLoadUndo ) ;
2021-08-07 11:28:43 +00:00
UI : : Choice * saveUndoButton = buttonRow - > Add ( new Choice ( pa - > T ( " Undo last save " ) ) ) ;
saveUndoButton - > SetEnabled ( SaveState : : HasUndoLastSave ( gamePath_ ) ) ;
saveUndoButton - > OnClick . Handle ( this , & GamePauseScreen : : OnLastSaveUndo ) ;
2021-08-03 08:04:49 +00:00
}
2023-12-03 15:41:29 +00:00
if ( g_Config . iRewindSnapshotInterval > 0 & & ! Achievements : : HardcoreModeActive ( ) ) {
2021-08-03 19:20:01 +00:00
UI : : Choice * rewindButton = buttonRow - > Add ( new Choice ( pa - > T ( " Rewind " ) ) ) ;
rewindButton - > SetEnabled ( SaveState : : CanRewind ( ) ) ;
rewindButton - > OnClick . Handle ( this , & GamePauseScreen : : OnRewind ) ;
}
2023-06-27 12:58:39 +00:00
}
void GamePauseScreen : : CreateViews ( ) {
using namespace UI ;
bool vertical = UseVerticalLayout ( ) ;
Margins scrollMargins ( 0 , 10 , 0 , 0 ) ;
Margins actionMenuMargins ( 0 , 10 , 15 , 0 ) ;
auto gr = GetI18NCategory ( I18NCat : : GRAPHICS ) ;
auto pa = GetI18NCategory ( I18NCat : : PAUSE ) ;
auto ac = GetI18NCategory ( I18NCat : : ACHIEVEMENTS ) ;
root_ = new LinearLayout ( ORIENT_HORIZONTAL ) ;
ViewGroup * leftColumn = new ScrollView ( ORIENT_VERTICAL , new LinearLayoutParams ( 1.0 , scrollMargins ) ) ;
root_ - > Add ( leftColumn ) ;
LinearLayout * leftColumnItems = new LinearLayoutList ( ORIENT_VERTICAL , new LayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ;
leftColumn - > Add ( leftColumnItems ) ;
2023-12-03 16:21:14 +00:00
leftColumnItems - > SetSpacing ( 5.0f ) ;
2023-06-27 12:58:39 +00:00
if ( Achievements : : IsActive ( ) ) {
leftColumnItems - > Add ( new GameAchievementSummaryView ( ) ) ;
2023-12-03 16:21:14 +00:00
char buf [ 512 ] ;
size_t sz = Achievements : : GetRichPresenceMessage ( buf , sizeof ( buf ) ) ;
if ( sz ! = ( size_t ) - 1 ) {
leftColumnItems - > Add ( new TextView ( std : : string_view ( buf , sz ) , new UI : : LinearLayoutParams ( Margins ( 5 , 5 ) ) ) ) - > SetSmall ( true ) ;
}
2023-06-27 12:58:39 +00:00
}
2023-12-03 15:41:29 +00:00
if ( ! Achievements : : HardcoreModeActive ( ) | | g_Config . bAchievementsSaveStateInHardcoreMode ) {
2023-06-27 12:58:39 +00:00
CreateSavestateControls ( leftColumnItems , vertical ) ;
2023-07-10 08:39:44 +00:00
} else {
// Let's show the active challenges.
std : : set < uint32_t > ids = Achievements : : GetActiveChallengeIDs ( ) ;
if ( ! ids . empty ( ) ) {
leftColumnItems - > Add ( new ItemHeader ( ac - > T ( " Active Challenges " ) ) ) ;
for ( auto id : ids ) {
const rc_client_achievement_t * achievement = rc_client_get_achievement_info ( Achievements : : GetClient ( ) , id ) ;
if ( ! achievement )
continue ;
leftColumnItems - > Add ( new AchievementView ( achievement ) ) ;
}
}
2023-11-30 16:33:14 +00:00
// And tack on an explanation for why savestate options are not available.
2024-01-19 12:44:49 +00:00
std : : string_view notAvailable = ac - > T ( " Save states not available in Hardcore Mode " ) ;
2023-11-30 16:33:14 +00:00
leftColumnItems - > Add ( new NoticeView ( NoticeLevel : : INFO , notAvailable , " " ) ) ;
2023-06-27 12:58:39 +00:00
}
2021-08-03 19:20:01 +00:00
2024-10-02 13:13:39 +00:00
LinearLayout * middleColumn = new LinearLayout ( ORIENT_VERTICAL , new LinearLayoutParams ( 64 , FILL_PARENT , Margins ( 0 , 10 , 0 , 15 ) ) ) ;
2024-01-24 09:01:52 +00:00
root_ - > Add ( middleColumn ) ;
2024-10-02 13:13:39 +00:00
middleColumn - > SetSpacing ( 0.0f ) ;
2023-12-11 12:56:16 +00:00
ViewGroup * rightColumnHolder = new LinearLayout ( ORIENT_VERTICAL , new LinearLayoutParams ( vertical ? 200 : 300 , FILL_PARENT , actionMenuMargins ) ) ;
ViewGroup * rightColumn = new ScrollView ( ORIENT_VERTICAL , new LinearLayoutParams ( 1.0f ) ) ;
rightColumnHolder - > Add ( rightColumn ) ;
root_ - > Add ( rightColumnHolder ) ;
2014-12-22 09:48:17 +00:00
LinearLayout * rightColumnItems = new LinearLayout ( ORIENT_VERTICAL ) ;
rightColumn - > Add ( rightColumnItems ) ;
rightColumnItems - > SetSpacing ( 0.0f ) ;
if ( getUMDReplacePermit ( ) ) {
2023-09-04 19:41:57 +00:00
rightColumnItems - > Add ( new Choice ( pa - > T ( " Switch UMD " ) ) ) - > OnClick . Add ( [ = ] ( UI : : EventParams & ) {
screenManager ( ) - > push ( new UmdReplaceScreen ( ) ) ;
return UI : : EVENT_DONE ;
} ) ;
2014-12-22 09:48:17 +00:00
}
2015-07-01 22:13:35 +00:00
Choice * continueChoice = rightColumnItems - > Add ( new Choice ( pa - > T ( " Continue " ) ) ) ;
2014-12-22 09:48:17 +00:00
root_ - > SetDefaultFocusView ( continueChoice ) ;
continueChoice - > OnClick . Handle < UIScreen > ( this , & UIScreen : : OnBack ) ;
2024-10-02 13:13:39 +00:00
rightColumnItems - > Add ( new Spacer ( 20.0 ) ) ;
2022-11-22 13:16:24 +00:00
2017-06-03 03:54:28 +00:00
std : : string gameId = g_paramSFO . GetDiscID ( ) ;
2014-12-22 09:48:17 +00:00
if ( g_Config . hasGameConfig ( gameId ) ) {
2015-07-01 22:13:35 +00:00
rightColumnItems - > Add ( new Choice ( pa - > T ( " Game Settings " ) ) ) - > OnClick . Handle ( this , & GamePauseScreen : : OnGameSettings ) ;
rightColumnItems - > Add ( new Choice ( pa - > T ( " Delete Game Config " ) ) ) - > OnClick . Handle ( this , & GamePauseScreen : : OnDeleteConfig ) ;
2014-12-22 09:48:17 +00:00
} else {
2015-07-01 22:13:35 +00:00
rightColumnItems - > Add ( new Choice ( pa - > T ( " Settings " ) ) ) - > OnClick . Handle ( this , & GamePauseScreen : : OnGameSettings ) ;
rightColumnItems - > Add ( new Choice ( pa - > T ( " Create Game Config " ) ) ) - > OnClick . Handle ( this , & GamePauseScreen : : OnCreateConfig ) ;
2014-12-22 09:48:17 +00:00
}
2024-05-31 06:55:12 +00:00
UI : : Choice * displayEditor_ = rightColumnItems - > Add ( new Choice ( gr - > T ( " Display layout & effects " ) ) ) ;
2022-11-22 13:16:24 +00:00
displayEditor_ - > OnClick . Add ( [ & ] ( UI : : EventParams & ) - > UI : : EventReturn {
screenManager ( ) - > push ( new DisplayLayoutScreen ( gamePath_ ) ) ;
return UI : : EVENT_DONE ;
} ) ;
2014-12-22 09:48:17 +00:00
if ( g_Config . bEnableCheats ) {
2023-06-15 11:40:37 +00:00
rightColumnItems - > Add ( new Choice ( pa - > T ( " Cheats " ) ) ) - > OnClick . Add ( [ & ] ( UI : : EventParams & e ) {
screenManager ( ) - > push ( new CwCheatScreen ( gamePath_ ) ) ;
return UI : : EVENT_DONE ;
} ) ;
}
2023-06-27 21:31:15 +00:00
if ( g_Config . bAchievementsEnable & & Achievements : : HasAchievementsOrLeaderboards ( ) ) {
2023-08-01 11:03:24 +00:00
rightColumnItems - > Add ( new Choice ( ac - > T ( " Achievements " ) ) ) - > OnClick . Add ( [ & ] ( UI : : EventParams & e ) {
2023-06-15 11:40:37 +00:00
screenManager ( ) - > push ( new RetroAchievementsListScreen ( gamePath_ ) ) ;
return UI : : EVENT_DONE ;
} ) ;
2014-12-22 09:48:17 +00:00
}
// TODO, also might be nice to show overall compat rating here?
// Based on their platform or even cpu/gpu/config. Would add an API for it.
2017-12-01 17:07:29 +00:00
if ( Reporting : : IsSupported ( ) & & g_paramSFO . GetValueString ( " DISC_ID " ) . size ( ) ) {
2023-04-05 22:34:50 +00:00
auto rp = GetI18NCategory ( I18NCat : : REPORTING ) ;
2014-12-22 09:48:17 +00:00
rightColumnItems - > Add ( new Choice ( rp - > T ( " ReportButton " , " Report Feedback " ) ) ) - > OnClick . Handle ( this , & GamePauseScreen : : OnReportFeedback ) ;
}
2024-10-02 13:13:39 +00:00
rightColumnItems - > Add ( new Spacer ( 20.0 ) ) ;
2018-04-02 14:31:26 +00:00
if ( g_Config . bPauseMenuExitsEmulator ) {
2023-04-05 22:34:50 +00:00
auto mm = GetI18NCategory ( I18NCat : : MAINMENU ) ;
2018-04-02 14:31:26 +00:00
rightColumnItems - > Add ( new Choice ( mm - > T ( " Exit " ) ) ) - > OnClick . Handle ( this , & GamePauseScreen : : OnExitToMenu ) ;
} else {
rightColumnItems - > Add ( new Choice ( pa - > T ( " Exit to menu " ) ) ) - > OnClick . Handle ( this , & GamePauseScreen : : OnExitToMenu ) ;
}
2023-12-11 12:56:16 +00:00
2024-01-21 11:02:30 +00:00
if ( ! Core_MustRunBehind ( ) ) {
2024-09-18 11:37:38 +00:00
playButton_ = middleColumn - > Add ( new Button ( " " , g_Config . bRunBehindPauseMenu ? ImageID ( " I_PAUSE " ) : ImageID ( " I_PLAY " ) , new LinearLayoutParams ( 64 , 64 ) ) ) ;
playButton_ - > OnClick . Add ( [ = ] ( UI : : EventParams & e ) {
g_Config . bRunBehindPauseMenu = ! g_Config . bRunBehindPauseMenu ;
playButton_ - > SetImageID ( g_Config . bRunBehindPauseMenu ? ImageID ( " I_PAUSE " ) : ImageID ( " I_PLAY " ) ) ;
return UI : : EVENT_DONE ;
} ) ;
2024-10-02 13:13:39 +00:00
middleColumn - > Add ( new Spacer ( 20.0 ) ) ;
2024-09-18 11:37:38 +00:00
Button * infoButton = middleColumn - > Add ( new Button ( " " , ImageID ( " I_INFO " ) , new LinearLayoutParams ( 64 , 64 ) ) ) ;
infoButton - > OnClick . Add ( [ = ] ( UI : : EventParams & e ) {
screenManager ( ) - > push ( new GameScreen ( gamePath_ , true ) ) ;
return UI : : EVENT_DONE ;
} ) ;
2024-01-21 11:02:30 +00:00
} else {
auto nw = GetI18NCategory ( I18NCat : : NETWORKING ) ;
rightColumnHolder - > Add ( new TextView ( nw - > T ( " Network connected " ) ) ) ;
}
2023-12-11 12:56:16 +00:00
rightColumnHolder - > Add ( new Spacer ( 10.0f ) ) ;
2014-12-22 09:48:17 +00:00
}
UI : : EventReturn GamePauseScreen : : OnGameSettings ( UI : : EventParams & e ) {
screenManager ( ) - > push ( new GameSettingsScreen ( gamePath_ ) ) ;
return UI : : EVENT_DONE ;
}
2014-12-31 14:33:43 +00:00
UI : : EventReturn GamePauseScreen : : OnState ( UI : : EventParams & e ) {
2017-03-20 00:43:03 +00:00
TriggerFinish ( DR_CANCEL ) ;
2014-12-31 14:33:43 +00:00
return UI : : EVENT_DONE ;
}
2014-12-31 19:42:28 +00:00
void GamePauseScreen : : dialogFinished ( const Screen * dialog , DialogResult dr ) {
std : : string tag = dialog - > tag ( ) ;
2022-09-17 20:29:33 +00:00
if ( tag = = " ScreenshotView " & & dr = = DR_OK ) {
2014-12-31 19:42:28 +00:00
finishNextFrame_ = true ;
2016-01-24 07:53:31 +00:00
} else {
2024-09-24 11:50:21 +00:00
if ( tag = = " Game " ) {
g_BackgroundAudio . SetGame ( Path ( ) ) ;
}
2016-01-24 07:53:31 +00:00
// There may have been changes to our savestates, so let's recreate.
RecreateViews ( ) ;
2014-12-31 19:42:28 +00:00
}
}
UI : : EventReturn GamePauseScreen : : OnScreenshotClicked ( UI : : EventParams & e ) {
2015-02-16 21:41:01 +00:00
SaveSlotView * v = static_cast < SaveSlotView * > ( e . v ) ;
int slot = v - > GetSlot ( ) ;
2015-02-15 10:21:17 +00:00
g_Config . iCurrentStateSlot = v - > GetSlot ( ) ;
2021-05-15 06:00:22 +00:00
if ( SaveState : : HasSaveInSlot ( gamePath_ , slot ) ) {
2021-05-05 23:31:38 +00:00
Path fn = v - > GetScreenshotFilename ( ) ;
2015-02-16 21:41:01 +00:00
std : : string title = v - > GetScreenshotTitle ( ) ;
2023-04-05 22:34:50 +00:00
Screen * screen = new ScreenshotViewScreen ( fn , title , v - > GetSlot ( ) , gamePath_ ) ;
2015-02-16 21:41:01 +00:00
screenManager ( ) - > push ( screen ) ;
}
2014-12-31 19:42:28 +00:00
return UI : : EVENT_DONE ;
}
2014-12-22 09:48:17 +00:00
UI : : EventReturn GamePauseScreen : : OnExitToMenu ( UI : : EventParams & e ) {
2024-04-05 09:07:57 +00:00
// If RAIntegration has dirty info, ask for confirmation.
if ( Achievements : : RAIntegrationDirty ( ) ) {
auto ac = GetI18NCategory ( I18NCat : : ACHIEVEMENTS ) ;
auto di = GetI18NCategory ( I18NCat : : DIALOG ) ;
screenManager ( ) - > push ( new PromptScreen ( gamePath_ , ac - > T ( " You have unsaved RAIntegration changes. Exit? " ) , di - > T ( " Yes " ) , di - > T ( " No " ) , [ = ] ( bool result ) {
if ( result ) {
if ( g_Config . bPauseMenuExitsEmulator ) {
System_ExitApp ( ) ;
} else {
finishNextFrameResult_ = DR_OK ; // exit game
finishNextFrame_ = true ;
}
}
} ) ) ;
2018-04-02 14:31:26 +00:00
} else {
2024-04-05 09:07:57 +00:00
if ( g_Config . bPauseMenuExitsEmulator ) {
System_ExitApp ( ) ;
} else {
TriggerFinish ( DR_OK ) ;
}
2018-04-02 14:31:26 +00:00
}
2014-12-22 09:48:17 +00:00
return UI : : EVENT_DONE ;
}
UI : : EventReturn GamePauseScreen : : OnReportFeedback ( UI : : EventParams & e ) {
screenManager ( ) - > push ( new ReportScreen ( gamePath_ ) ) ;
return UI : : EVENT_DONE ;
}
UI : : EventReturn GamePauseScreen : : OnRewind ( UI : : EventParams & e ) {
2016-05-28 04:25:05 +00:00
SaveState : : Rewind ( & AfterSaveStateAction ) ;
2014-12-22 09:48:17 +00:00
2017-03-20 00:43:03 +00:00
TriggerFinish ( DR_CANCEL ) ;
2014-12-22 09:48:17 +00:00
return UI : : EVENT_DONE ;
}
2021-08-03 08:04:49 +00:00
UI : : EventReturn GamePauseScreen : : OnLoadUndo ( UI : : EventParams & e ) {
SaveState : : UndoLoad ( gamePath_ , & AfterSaveStateAction ) ;
TriggerFinish ( DR_CANCEL ) ;
return UI : : EVENT_DONE ;
}
2021-08-07 11:28:43 +00:00
UI : : EventReturn GamePauseScreen : : OnLastSaveUndo ( UI : : EventParams & e ) {
SaveState : : UndoLastSave ( gamePath_ ) ;
RecreateViews ( ) ;
return UI : : EVENT_DONE ;
}
2014-12-22 09:48:17 +00:00
void GamePauseScreen : : CallbackDeleteConfig ( bool yes )
{
if ( yes ) {
2024-01-28 15:23:27 +00:00
std : : shared_ptr < GameInfo > info = g_gameInfoCache - > GetInfo ( NULL , gamePath_ , GameInfoFlags : : PARAM_SFO ) ;
if ( info - > Ready ( GameInfoFlags : : PARAM_SFO ) ) {
g_Config . unloadGameConfig ( ) ;
g_Config . deleteGameConfig ( info - > id ) ;
info - > hasConfig = false ;
screenManager ( ) - > RecreateAllViews ( ) ;
}
2014-12-22 09:48:17 +00:00
}
}
UI : : EventReturn GamePauseScreen : : OnCreateConfig ( UI : : EventParams & e )
{
2024-01-28 15:23:27 +00:00
std : : shared_ptr < GameInfo > info = g_gameInfoCache - > GetInfo ( NULL , gamePath_ , GameInfoFlags : : PARAM_SFO ) ;
if ( info - > Ready ( GameInfoFlags : : PARAM_SFO ) ) {
std : : string gameId = g_paramSFO . GetDiscID ( ) ;
g_Config . createGameConfig ( gameId ) ;
g_Config . changeGameSpecific ( gameId , info - > GetTitle ( ) ) ;
g_Config . saveGameConfig ( gameId , info - > GetTitle ( ) ) ;
if ( info ) {
info - > hasConfig = true ;
}
screenManager ( ) - > topScreen ( ) - > RecreateViews ( ) ;
2015-09-10 15:17:26 +00:00
}
2014-12-22 09:48:17 +00:00
return UI : : EVENT_DONE ;
}
2017-12-02 19:39:33 +00:00
2014-12-22 09:48:17 +00:00
UI : : EventReturn GamePauseScreen : : OnDeleteConfig ( UI : : EventParams & e )
{
2023-04-05 22:34:50 +00:00
auto di = GetI18NCategory ( I18NCat : : DIALOG ) ;
auto ga = GetI18NCategory ( I18NCat : : GAME ) ;
2014-12-22 09:48:17 +00:00
screenManager ( ) - > push (
2022-11-29 15:29:43 +00:00
new PromptScreen ( gamePath_ , di - > T ( " DeleteConfirmGameConfig " , " Do you really want to delete the settings for this game? " ) , ga - > T ( " ConfirmDelete " ) , di - > T ( " Cancel " ) ,
2016-10-12 09:32:24 +00:00
std : : bind ( & GamePauseScreen : : CallbackDeleteConfig , this , std : : placeholders : : _1 ) ) ) ;
2014-12-22 09:48:17 +00:00
return UI : : EVENT_DONE ;
}