2013-06-10 20:06:51 +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/.
2013-11-27 10:15:46 +00:00
# include <algorithm>
2021-01-09 22:45:49 +00:00
# include <cmath>
# include <sstream>
2013-11-26 13:45:36 +00:00
2017-02-27 10:32:40 +00:00
# include "ppsspp_config.h"
2020-10-03 22:25:21 +00:00
2020-10-04 08:10:55 +00:00
# include "Common/System/Display.h"
2020-10-04 08:30:18 +00:00
# include "Common/System/System.h"
2023-03-22 14:21:03 +00:00
# include "Common/System/Request.h"
# include "Common/System/NativeApp.h"
2020-10-04 21:24:14 +00:00
# include "Common/Render/TextureAtlas.h"
# include "Common/Render/DrawBuffer.h"
2020-10-04 18:48:47 +00:00
# include "Common/UI/Root.h"
# include "Common/UI/Context.h"
# include "Common/UI/View.h"
# include "Common/UI/ViewGroup.h"
2013-07-21 11:31:46 +00:00
2020-10-01 11:05:04 +00:00
# include "Common/Data/Color/RGBAUtil.h"
# include "Common/Data/Encoding/Utf8.h"
2020-10-03 22:25:21 +00:00
# include "Common/File/PathBrowser.h"
# include "Common/Math/curves.h"
2021-01-08 19:05:43 +00:00
# include "Common/Net/URL.h"
2020-10-04 18:48:47 +00:00
# include "Common/File/FileUtil.h"
2020-08-15 18:53:08 +00:00
# include "Common/TimeUtil.h"
2020-09-29 10:19:22 +00:00
# include "Common/StringUtils.h"
2013-07-21 11:31:46 +00:00
# include "Core/System.h"
2014-02-09 22:04:16 +00:00
# include "Core/Reporting.h"
2023-03-26 09:35:42 +00:00
# include "Core/HLE/sceCtrl.h"
2020-03-08 04:30:55 +00:00
# include "Core/ELF/PBPReader.h"
# include "Core/ELF/ParamSFO.h"
2017-05-18 12:21:13 +00:00
# include "Core/Util/GameManager.h"
2013-07-21 11:31:46 +00:00
2014-06-22 15:02:04 +00:00
# include "UI/BackgroundAudio.h"
2013-06-10 20:06:51 +00:00
# include "UI/EmuScreen.h"
# include "UI/MainScreen.h"
# include "UI/GameScreen.h"
# include "UI/GameInfoCache.h"
2013-07-17 20:27:05 +00:00
# include "UI/GameSettingsScreen.h"
2013-08-14 21:05:02 +00:00
# include "UI/MiscScreens.h"
2013-09-07 15:29:44 +00:00
# include "UI/ControlMappingScreen.h"
2023-12-28 14:34:40 +00:00
# include "UI/RemoteISOScreen.h"
2015-12-21 05:32:05 +00:00
# include "UI/DisplayLayoutScreen.h"
2015-06-11 18:22:16 +00:00
# include "UI/SavedataScreen.h"
2013-11-20 13:42:48 +00:00
# include "UI/Store.h"
2020-07-27 14:53:02 +00:00
# include "UI/InstallZipScreen.h"
2013-06-10 20:06:51 +00:00
# include "Core/Config.h"
2017-03-02 11:29:03 +00:00
# include "Core/Loaders.h"
2013-07-21 23:33:18 +00:00
# include "GPU/GPUInterface.h"
2020-10-01 11:05:04 +00:00
# include "Common/Data/Text/I18n.h"
2013-06-27 14:28:11 +00:00
2023-01-31 10:36:14 +00:00
# if PPSSPP_PLATFORM(IOS) || PPSSPP_PLATFORM(MAC)
# include "UI/DarwinFileSystemServices.h" // For the browser
# endif
2013-11-24 03:02:36 +00:00
# include "Core/HLE/sceUmd.h"
2013-12-06 11:29:27 +00:00
bool MainScreen : : showHomebrewTab = false ;
2021-05-05 23:31:38 +00:00
bool LaunchFile ( ScreenManager * screenManager , const Path & path ) {
2020-07-27 14:53:02 +00:00
// Depending on the file type, we don't want to launch EmuScreen at all.
2021-05-09 16:38:48 +00:00
auto loader = ConstructFileLoader ( path ) ;
2020-07-27 14:53:02 +00:00
if ( ! loader ) {
return false ;
}
2021-08-07 09:54:45 +00:00
std : : string errorString ;
IdentifiedFileType type = Identify_File ( loader , & errorString ) ;
2020-07-27 14:53:02 +00:00
delete loader ;
switch ( type ) {
case IdentifiedFileType : : ARCHIVE_ZIP :
2021-05-09 16:38:48 +00:00
screenManager - > push ( new InstallZipScreen ( path ) ) ;
2020-07-27 14:53:02 +00:00
break ;
default :
// Let the EmuScreen take care of it.
screenManager - > switchScreen ( new EmuScreen ( path ) ) ;
break ;
}
2020-07-28 08:03:55 +00:00
return true ;
2020-07-27 14:53:02 +00:00
}
2021-05-05 23:31:38 +00:00
static bool IsTempPath ( const Path & str ) {
std : : string item = str . ToString ( ) ;
2021-01-09 22:45:49 +00:00
# ifdef _WIN32
// Normalize slashes.
2021-05-05 23:31:38 +00:00
item = ReplaceAll ( item , " / " , " \\ " ) ;
2021-01-09 22:45:49 +00:00
# endif
2018-06-02 23:32:55 +00:00
2021-01-09 22:45:49 +00:00
std : : vector < std : : string > tempPaths = System_GetPropertyStringVec ( SYSPROP_TEMP_DIRS ) ;
for ( auto temp : tempPaths ) {
2018-06-02 23:32:55 +00:00
# ifdef _WIN32
temp = ReplaceAll ( temp , " / " , " \\ " ) ;
if ( ! temp . empty ( ) & & temp [ temp . size ( ) - 1 ] ! = ' \\ ' )
temp + = " \\ " ;
# else
if ( ! temp . empty ( ) & & temp [ temp . size ( ) - 1 ] ! = ' / ' )
temp + = " / " ;
# endif
2021-01-09 22:45:49 +00:00
if ( startsWith ( item , temp ) )
return true ;
2020-01-04 19:06:12 +00:00
}
2018-06-02 23:32:55 +00:00
return false ;
}
2013-06-10 20:06:51 +00:00
class GameButton : public UI : : Clickable {
public :
2021-05-09 13:25:12 +00:00
GameButton ( const Path & gamePath , bool gridStyle , UI : : LayoutParams * layoutParams = 0 )
2019-02-27 09:05:15 +00:00
: UI : : Clickable ( layoutParams ) , gridStyle_ ( gridStyle ) , gamePath_ ( gamePath ) { }
2013-06-10 20:06:51 +00:00
2015-02-02 23:11:51 +00:00
void Draw ( UIContext & dc ) override ;
2021-02-22 00:38:02 +00:00
std : : string DescribeText ( ) const override ;
2015-02-02 23:11:51 +00:00
void GetContentDimensions ( const UIContext & dc , float & w , float & h ) const override {
2013-08-16 10:52:16 +00:00
if ( gridStyle_ ) {
2020-03-01 14:34:35 +00:00
w = 144 * g_Config . fGameGridScale ;
h = 80 * g_Config . fGameGridScale ;
2013-08-16 10:52:16 +00:00
} else {
w = 500 ;
h = 50 ;
}
2013-06-10 20:06:51 +00:00
}
2013-08-16 10:52:16 +00:00
2021-05-05 23:31:38 +00:00
const Path & GamePath ( ) const { return gamePath_ ; }
2013-12-06 10:44:46 +00:00
2013-12-11 19:37:57 +00:00
void SetHoldEnabled ( bool hold ) {
holdEnabled_ = hold ;
}
2022-11-27 15:15:16 +00:00
bool Touch ( const TouchInput & input ) override {
bool retval = UI : : Clickable : : Touch ( input ) ;
2014-01-25 19:24:06 +00:00
hovering_ = bounds_ . Contains ( input . x , input . y ) ;
2015-03-01 14:59:17 +00:00
if ( hovering_ & & ( input . flags & TOUCH_DOWN ) ) {
holdStart_ = time_now_d ( ) ;
}
2013-07-22 20:36:56 +00:00
if ( input . flags & TOUCH_UP ) {
2015-03-01 14:59:17 +00:00
holdStart_ = 0 ;
2013-07-22 20:36:56 +00:00
}
2022-11-27 15:15:16 +00:00
return retval ;
2013-07-22 20:36:56 +00:00
}
2013-12-06 10:44:46 +00:00
2015-02-02 23:11:51 +00:00
bool Key ( const KeyInput & key ) override {
2014-01-25 19:24:06 +00:00
std : : vector < int > pspKeys ;
bool showInfo = false ;
2023-11-13 11:32:31 +00:00
if ( HasFocus ( ) & & UI : : IsInfoKey ( key ) ) {
// If the button mapped to triangle, then show the info.
if ( key . flags & KEY_UP ) {
showInfo = true ;
2014-01-25 19:24:06 +00:00
}
} else if ( hovering_ & & key . deviceId = = DEVICE_ID_MOUSE & & key . keyCode = = NKCODE_EXT_MOUSEBUTTON_2 ) {
// If it's the right mouse button, and it's not otherwise mapped, show the info also.
2019-03-04 01:50:54 +00:00
if ( key . flags & KEY_DOWN ) {
showInfoPressed_ = true ;
}
if ( ( key . flags & KEY_UP ) & & showInfoPressed_ ) {
2014-01-25 19:24:06 +00:00
showInfo = true ;
2019-03-04 01:50:54 +00:00
showInfoPressed_ = false ;
2014-01-25 19:24:06 +00:00
}
}
if ( showInfo ) {
TriggerOnHoldClick ( ) ;
2015-02-02 23:11:51 +00:00
return true ;
2014-01-25 19:24:06 +00:00
}
2015-02-02 23:11:51 +00:00
return Clickable : : Key ( key ) ;
2014-01-25 19:24:06 +00:00
}
2017-03-15 05:01:18 +00:00
void Update ( ) override {
2014-01-25 19:24:06 +00:00
// Hold button for 1.5 seconds to launch the game options
2015-03-01 14:59:17 +00:00
if ( holdEnabled_ & & holdStart_ ! = 0.0 & & holdStart_ < time_now_d ( ) - 1.5 ) {
2014-01-25 19:24:06 +00:00
TriggerOnHoldClick ( ) ;
2013-07-22 20:36:56 +00:00
}
}
2015-02-02 23:11:51 +00:00
void FocusChanged ( int focusFlags ) override {
2014-06-22 01:04:27 +00:00
UI : : Clickable : : FocusChanged ( focusFlags ) ;
TriggerOnHighlight ( focusFlags ) ;
}
2013-07-22 20:36:56 +00:00
UI : : Event OnHoldClick ;
2014-06-22 01:04:27 +00:00
UI : : Event OnHighlight ;
2013-07-22 20:36:56 +00:00
2013-06-10 20:06:51 +00:00
private :
2014-01-25 19:24:06 +00:00
void TriggerOnHoldClick ( ) {
2015-03-01 14:59:17 +00:00
holdStart_ = 0.0 ;
2017-03-22 01:34:52 +00:00
UI : : EventParams e { } ;
2014-01-25 19:24:06 +00:00
e . v = this ;
2021-05-05 23:31:38 +00:00
e . s = gamePath_ . ToString ( ) ;
2014-01-25 19:24:06 +00:00
down_ = false ;
OnHoldClick . Trigger ( e ) ;
}
2014-06-22 01:04:27 +00:00
void TriggerOnHighlight ( int focusFlags ) {
2017-03-22 01:34:52 +00:00
UI : : EventParams e { } ;
2014-06-22 01:04:27 +00:00
e . v = this ;
2021-05-05 23:31:38 +00:00
e . s = gamePath_ . ToString ( ) ;
2014-06-22 01:04:27 +00:00
e . a = focusFlags ;
OnHighlight . Trigger ( e ) ;
}
2014-01-25 19:24:06 +00:00
2013-08-16 10:52:16 +00:00
bool gridStyle_ ;
2021-05-05 23:31:38 +00:00
Path gamePath_ ;
2013-12-06 10:44:46 +00:00
std : : string title_ ;
2013-10-09 14:26:15 +00:00
2019-02-27 09:05:15 +00:00
double holdStart_ = 0.0 ;
bool holdEnabled_ = true ;
2019-03-04 01:50:54 +00:00
bool showInfoPressed_ = false ;
2019-02-27 09:05:15 +00:00
bool hovering_ = false ;
2013-06-10 20:06:51 +00:00
} ;
void GameButton : : Draw ( UIContext & dc ) {
2024-01-28 15:23:27 +00:00
std : : shared_ptr < GameInfo > ginfo = g_gameInfoCache - > GetInfo ( dc . GetDrawContext ( ) , gamePath_ , GameInfoFlags : : PARAM_SFO | GameInfoFlags : : ICON ) ;
2016-12-25 19:54:37 +00:00
Draw : : Texture * texture = 0 ;
2013-07-15 15:41:24 +00:00
u32 color = 0 , shadowColor = 0 ;
2014-12-22 09:48:17 +00:00
using namespace UI ;
2013-07-15 15:41:24 +00:00
2024-01-28 15:23:27 +00:00
if ( ginfo - > Ready ( GameInfoFlags : : ICON ) & & ginfo - > icon . texture ) {
2023-12-12 21:34:31 +00:00
texture = ginfo - > icon . texture ;
2013-06-10 20:06:51 +00:00
}
int x = bounds_ . x ;
int y = bounds_ . y ;
2020-03-01 14:34:35 +00:00
int w = gridStyle_ ? bounds_ . w : 144 ;
2013-06-10 20:06:51 +00:00
int h = bounds_ . h ;
2013-08-16 10:52:16 +00:00
UI : : Style style = dc . theme - > itemStyle ;
2013-08-20 16:18:30 +00:00
if ( down_ )
style = dc . theme - > itemDownStyle ;
2013-08-16 10:52:16 +00:00
if ( ! gridStyle_ | | ! texture ) {
h = 50 ;
if ( HasFocus ( ) )
style = down_ ? dc . theme - > itemDownStyle : dc . theme - > itemFocusedStyle ;
2013-12-11 19:37:57 +00:00
Drawable bg = style . background ;
2013-08-18 20:30:34 +00:00
dc . Draw ( ) - > Flush ( ) ;
dc . RebindTexture ( ) ;
2013-12-11 19:37:57 +00:00
dc . FillRect ( bg , bounds_ ) ;
2013-08-18 20:30:34 +00:00
dc . Draw ( ) - > Flush ( ) ;
2013-08-16 10:52:16 +00:00
}
2013-06-10 20:06:51 +00:00
if ( texture ) {
2017-03-26 07:00:57 +00:00
color = whiteAlpha ( ease ( ( time_now_d ( ) - ginfo - > icon . timeLoaded ) * 2 ) ) ;
shadowColor = blackAlpha ( ease ( ( time_now_d ( ) - ginfo - > icon . timeLoaded ) * 2 ) ) ;
2013-06-10 20:06:51 +00:00
float tw = texture - > Width ( ) ;
float th = texture - > Height ( ) ;
// Adjust position so we don't stretch the image vertically or horizontally.
2019-10-07 21:58:23 +00:00
// Make sure it's not wider than 144 (like Doom Legacy homebrew), ugly in the grid mode.
2020-03-01 14:34:35 +00:00
float nw = std : : min ( h * tw / th , ( float ) w ) ;
2013-06-10 20:06:51 +00:00
x + = ( w - nw ) / 2.0f ;
w = nw ;
}
int txOffset = down_ ? 4 : 0 ;
2013-08-20 16:18:30 +00:00
if ( ! gridStyle_ ) txOffset = 0 ;
2013-06-10 20:06:51 +00:00
2013-12-11 19:37:57 +00:00
Bounds overlayBounds = bounds_ ;
u32 overlayColor = 0 ;
2015-03-01 14:59:17 +00:00
if ( holdEnabled_ & & holdStart_ ! = 0.0 ) {
double time_held = time_now_d ( ) - holdStart_ ;
overlayColor = whiteAlpha ( time_held / 2.5f ) ;
}
2013-12-11 19:37:57 +00:00
2013-06-10 20:06:51 +00:00
// Render button
int dropsize = 10 ;
if ( texture ) {
2020-02-25 18:29:41 +00:00
if ( ! gridStyle_ ) {
x + = 4 ;
}
2013-08-12 22:06:48 +00:00
if ( txOffset ) {
dropsize = 3 ;
y + = txOffset * 2 ;
2013-12-11 19:37:57 +00:00
overlayBounds . y + = txOffset * 2 ;
2013-08-12 22:06:48 +00:00
}
2013-07-15 15:41:24 +00:00
if ( HasFocus ( ) ) {
2013-08-19 22:49:25 +00:00
dc . Draw ( ) - > Flush ( ) ;
dc . RebindTexture ( ) ;
2020-08-15 22:13:19 +00:00
float pulse = sin ( time_now_d ( ) * 7.0 ) * 0.25 + 0.8 ;
2014-06-22 16:16:10 +00:00
dc . Draw ( ) - > DrawImage4Grid ( dc . theme - > dropShadow4Grid , x - dropsize * 1.5f , y - dropsize * 1.5f , x + w + dropsize * 1.5f , y + h + dropsize * 1.5f , alphaMul ( color , pulse ) , 1.0f ) ;
2013-08-19 22:49:25 +00:00
dc . Draw ( ) - > Flush ( ) ;
2013-07-15 15:41:24 +00:00
} else {
2013-08-10 21:04:23 +00:00
dc . Draw ( ) - > Flush ( ) ;
dc . RebindTexture ( ) ;
2013-08-19 22:49:25 +00:00
dc . Draw ( ) - > DrawImage4Grid ( dc . theme - > dropShadow4Grid , x - dropsize , y - dropsize * 0.5f , x + w + dropsize , y + h + dropsize * 1.5 , alphaMul ( shadowColor , 0.5f ) , 1.0f ) ;
2013-07-15 15:41:24 +00:00
dc . Draw ( ) - > Flush ( ) ;
2013-06-10 20:06:51 +00:00
}
2013-07-15 16:57:42 +00:00
dc . Draw ( ) - > Flush ( ) ;
2017-01-30 13:33:38 +00:00
dc . GetDrawContext ( ) - > BindTexture ( 0 , texture ) ;
2015-03-01 14:59:17 +00:00
if ( holdStart_ ! = 0.0 ) {
double time_held = time_now_d ( ) - holdStart_ ;
int holdFrameCount = ( int ) ( time_held * 60.0f ) ;
if ( holdFrameCount > 60 ) {
// Blink before launching by holding
if ( ( ( holdFrameCount > > 3 ) & 1 ) = = 0 )
color = darkenColor ( color ) ;
}
2013-07-22 20:36:56 +00:00
}
2013-06-10 20:06:51 +00:00
dc . Draw ( ) - > DrawTexRect ( x , y , x + w , y + h , 0 , 0 , 1 , 1 , color ) ;
dc . Draw ( ) - > Flush ( ) ;
2013-08-16 10:52:16 +00:00
}
2013-11-25 17:14:11 +00:00
char discNumInfo [ 8 ] ;
if ( ginfo - > disc_total > 1 )
2023-04-28 19:04:05 +00:00
snprintf ( discNumInfo , sizeof ( discNumInfo ) , " -DISC%d " , ginfo - > disc_number ) ;
2013-11-25 17:14:11 +00:00
else
2023-04-28 19:04:05 +00:00
discNumInfo [ 0 ] = ' \0 ' ;
2013-11-25 17:14:11 +00:00
2013-08-18 20:30:34 +00:00
dc . Draw ( ) - > Flush ( ) ;
dc . RebindTexture ( ) ;
2013-08-30 12:47:28 +00:00
dc . SetFontStyle ( dc . theme - > uiFont ) ;
2022-07-18 09:03:02 +00:00
if ( gridStyle_ & & ginfo - > fileType = = IdentifiedFileType : : PPSSPP_GE_DUMP ) {
// Super simple drawing for ge dumps.
dc . PushScissor ( bounds_ ) ;
const std : : string currentTitle = ginfo - > GetTitle ( ) ;
dc . SetFontScale ( 0.6f , 0.6f ) ;
dc . DrawText ( title_ . c_str ( ) , bounds_ . x + 4.0f , bounds_ . centerY ( ) , style . fgColor , ALIGN_VCENTER | ALIGN_LEFT ) ;
dc . SetFontScale ( 1.0f , 1.0f ) ;
title_ = currentTitle ;
dc . Draw ( ) - > Flush ( ) ;
dc . PopScissor ( ) ;
} else if ( ! gridStyle_ ) {
2013-11-26 13:45:36 +00:00
float tw , th ;
2013-08-18 20:30:34 +00:00
dc . Draw ( ) - > Flush ( ) ;
dc . PushScissor ( bounds_ ) ;
2015-12-24 21:18:46 +00:00
const std : : string currentTitle = ginfo - > GetTitle ( ) ;
if ( ! currentTitle . empty ( ) ) {
title_ = ReplaceAll ( currentTitle + discNumInfo , " & " , " && " ) ;
2013-12-11 09:32:39 +00:00
title_ = ReplaceAll ( title_ , " \n " , " " ) ;
2013-12-06 10:44:46 +00:00
}
2013-11-26 13:45:36 +00:00
2016-08-07 23:49:50 +00:00
dc . MeasureText ( dc . GetFontStyle ( ) , 1.0f , 1.0f , title_ . c_str ( ) , & tw , & th , 0 ) ;
2013-11-26 13:45:36 +00:00
int availableWidth = bounds_ . w - 150 ;
2020-02-25 16:59:24 +00:00
if ( g_Config . bShowIDOnGameIcon ) {
float vw , vh ;
dc . MeasureText ( dc . GetFontStyle ( ) , 0.7f , 0.7f , ginfo - > id_version . c_str ( ) , & vw , & vh , 0 ) ;
availableWidth - = vw + 20 ;
dc . SetFontScale ( 0.7f , 0.7f ) ;
2021-09-28 14:28:59 +00:00
dc . DrawText ( ginfo - > id_version . c_str ( ) , bounds_ . x + availableWidth + 160 , bounds_ . centerY ( ) , style . fgColor , ALIGN_VCENTER ) ;
2020-02-25 16:59:24 +00:00
dc . SetFontScale ( 1.0f , 1.0f ) ;
}
2013-11-26 13:45:36 +00:00
float sineWidth = std : : max ( 0.0f , ( tw - availableWidth ) ) / 2.0f ;
float tx = 150 ;
if ( availableWidth < tw ) {
tx - = ( 1.0f + sin ( time_now_d ( ) * 1.5f ) ) * sineWidth ;
Bounds tb = bounds_ ;
tb . x = bounds_ . x + 150 ;
2020-02-25 16:59:24 +00:00
tb . w = availableWidth ;
2013-11-26 13:45:36 +00:00
dc . PushScissor ( tb ) ;
}
2013-12-06 10:44:46 +00:00
dc . DrawText ( title_ . c_str ( ) , bounds_ . x + tx , bounds_ . centerY ( ) , style . fgColor , ALIGN_VCENTER ) ;
2013-11-26 13:45:36 +00:00
if ( availableWidth < tw ) {
dc . PopScissor ( ) ;
}
2013-08-18 20:30:34 +00:00
dc . Draw ( ) - > Flush ( ) ;
dc . PopScissor ( ) ;
} else if ( ! texture ) {
dc . Draw ( ) - > Flush ( ) ;
2013-08-16 10:52:16 +00:00
dc . PushScissor ( bounds_ ) ;
2013-12-06 10:44:46 +00:00
dc . DrawText ( title_ . c_str ( ) , bounds_ . x + 4 , bounds_ . centerY ( ) , style . fgColor , ALIGN_VCENTER ) ;
2013-08-18 20:30:34 +00:00
dc . Draw ( ) - > Flush ( ) ;
2013-08-16 10:52:16 +00:00
dc . PopScissor ( ) ;
2013-08-18 20:30:34 +00:00
} else {
dc . Draw ( ) - > Flush ( ) ;
2013-06-10 20:06:51 +00:00
}
2015-12-24 21:18:46 +00:00
if ( ginfo - > hasConfig & & ! ginfo - > id . empty ( ) ) {
2020-02-29 20:51:14 +00:00
const AtlasImage * gearImage = dc . Draw ( ) - > GetAtlas ( ) - > getImage ( ImageID ( " I_GEAR " ) ) ;
if ( gearImage ) {
if ( gridStyle_ ) {
2020-03-01 14:34:35 +00:00
dc . Draw ( ) - > DrawImage ( ImageID ( " I_GEAR " ) , x , y + h - gearImage - > h * g_Config . fGameGridScale , g_Config . fGameGridScale ) ;
2020-02-29 20:51:14 +00:00
} else {
dc . Draw ( ) - > DrawImage ( ImageID ( " I_GEAR " ) , x - gearImage - > w , y , 1.0f ) ;
}
2020-02-24 12:53:06 +00:00
}
2014-12-15 22:01:07 +00:00
}
2020-02-23 07:33:44 +00:00
if ( g_Config . bShowRegionOnGameIcon & & ginfo - > region > = 0 & & ginfo - > region < GAMEREGION_MAX & & ginfo - > region ! = GAMEREGION_OTHER ) {
2020-02-29 20:51:14 +00:00
const ImageID regionIcons [ GAMEREGION_MAX ] = {
ImageID ( " I_FLAG_JP " ) ,
ImageID ( " I_FLAG_US " ) ,
ImageID ( " I_FLAG_EU " ) ,
ImageID ( " I_FLAG_HK " ) ,
ImageID ( " I_FLAG_AS " ) ,
ImageID ( " I_FLAG_KO " ) ,
ImageID : : invalid ( ) ,
2020-02-23 07:33:44 +00:00
} ;
2020-02-29 20:51:14 +00:00
const AtlasImage * image = dc . Draw ( ) - > GetAtlas ( ) - > getImage ( regionIcons [ ginfo - > region ] ) ;
if ( image ) {
if ( gridStyle_ ) {
2020-03-01 14:34:35 +00:00
dc . Draw ( ) - > DrawImage ( regionIcons [ ginfo - > region ] , x + w - ( image - > w + 5 ) * g_Config . fGameGridScale ,
y + h - ( image - > h + 5 ) * g_Config . fGameGridScale , g_Config . fGameGridScale ) ;
2020-02-29 20:51:14 +00:00
} else {
dc . Draw ( ) - > DrawImage ( regionIcons [ ginfo - > region ] , x - 2 - image - > w - 3 , y + h - image - > h - 5 , 1.0f ) ;
}
2020-02-24 12:53:06 +00:00
}
2020-02-23 07:33:44 +00:00
}
2020-02-24 12:53:06 +00:00
if ( gridStyle_ & & g_Config . bShowIDOnGameIcon ) {
2020-03-01 14:34:35 +00:00
dc . SetFontScale ( 0.5f * g_Config . fGameGridScale , 0.5f * g_Config . fGameGridScale ) ;
2020-02-25 18:29:41 +00:00
dc . DrawText ( ginfo - > id_version . c_str ( ) , x + 5 , y + 1 , 0xFF000000 , ALIGN_TOPLEFT ) ;
2022-02-14 12:57:22 +00:00
dc . DrawText ( ginfo - > id_version . c_str ( ) , x + 4 , y , dc . theme - > infoStyle . fgColor , ALIGN_TOPLEFT ) ;
2020-02-23 13:01:15 +00:00
dc . SetFontScale ( 1.0f , 1.0f ) ;
}
2013-12-11 19:37:57 +00:00
if ( overlayColor ) {
dc . FillRect ( Drawable ( overlayColor ) , overlayBounds ) ;
}
2013-08-30 12:47:28 +00:00
dc . RebindTexture ( ) ;
2013-06-10 20:06:51 +00:00
}
2021-02-22 00:38:02 +00:00
std : : string GameButton : : DescribeText ( ) const {
2024-01-28 15:23:27 +00:00
std : : shared_ptr < GameInfo > ginfo = g_gameInfoCache - > GetInfo ( nullptr , gamePath_ , GameInfoFlags : : PARAM_SFO ) ;
if ( ! ginfo - > Ready ( GameInfoFlags : : PARAM_SFO ) )
2023-04-29 18:45:30 +00:00
return " ... " ;
2023-04-05 22:34:50 +00:00
auto u = GetI18NCategory ( I18NCat : : UI_ELEMENTS ) ;
2023-07-16 14:16:47 +00:00
return ApplySafeSubstitutions ( u - > T ( " %1 button " ) , ginfo - > GetTitle ( ) ) ;
2021-02-22 00:38:02 +00:00
}
2013-12-11 10:03:43 +00:00
class DirButton : public UI : : Button {
public :
2021-05-09 13:25:12 +00:00
DirButton ( const Path & path , bool gridStyle , UI : : LayoutParams * layoutParams )
: UI : : Button ( path . ToString ( ) , layoutParams ) , path_ ( path ) , gridStyle_ ( gridStyle ) , absolute_ ( false ) { }
DirButton ( const Path & path , const std : : string & text , bool gridStyle , UI : : LayoutParams * layoutParams = 0 )
2020-03-01 14:34:35 +00:00
: UI : : Button ( text , layoutParams ) , path_ ( path ) , gridStyle_ ( gridStyle ) , absolute_ ( true ) { }
2013-12-11 10:03:43 +00:00
2022-12-11 04:32:12 +00:00
void Draw ( UIContext & dc ) override ;
2013-12-08 06:39:35 +00:00
2021-05-09 13:25:12 +00:00
const Path & GetPath ( ) const {
2013-12-08 06:39:35 +00:00
return path_ ;
}
bool PathAbsolute ( ) const {
return absolute_ ;
}
private :
2021-05-09 13:25:12 +00:00
Path path_ ;
2020-03-01 14:34:35 +00:00
bool gridStyle_ ;
2021-02-15 18:29:34 +00:00
bool absolute_ ;
2013-12-11 10:03:43 +00:00
} ;
void DirButton : : Draw ( UIContext & dc ) {
2014-12-22 09:48:17 +00:00
using namespace UI ;
2022-02-14 12:57:22 +00:00
Style style = dc . theme - > itemStyle ;
2013-12-11 10:03:43 +00:00
2022-02-14 12:57:22 +00:00
if ( HasFocus ( ) ) style = dc . theme - > itemFocusedStyle ;
if ( down_ ) style = dc . theme - > itemDownStyle ;
if ( ! IsEnabled ( ) ) style = dc . theme - > itemDisabledStyle ;
2013-12-11 10:03:43 +00:00
dc . FillRect ( style . background , bounds_ ) ;
2024-01-19 12:44:49 +00:00
std : : string text ( GetText ( ) ) ;
2013-12-11 10:03:43 +00:00
2020-02-29 20:51:14 +00:00
ImageID image = ImageID ( " I_FOLDER " ) ;
2013-12-11 10:03:43 +00:00
if ( text = = " .. " ) {
2020-02-29 20:51:14 +00:00
image = ImageID ( " I_UP_DIRECTORY " ) ;
2013-12-11 10:03:43 +00:00
}
2019-02-27 09:05:15 +00:00
2013-12-11 10:03:43 +00:00
float tw , th ;
2020-03-01 14:34:35 +00:00
dc . MeasureText ( dc . GetFontStyle ( ) , gridStyle_ ? g_Config . fGameGridScale : 1.0 , gridStyle_ ? g_Config . fGameGridScale : 1.0 , text . c_str ( ) , & tw , & th , 0 ) ;
2013-12-11 10:03:43 +00:00
2020-03-01 14:34:35 +00:00
bool compact = bounds_ . w < 180 * ( gridStyle_ ? g_Config . fGameGridScale : 1.0 ) ;
2013-12-11 10:03:43 +00:00
2020-03-01 14:34:35 +00:00
if ( gridStyle_ ) {
dc . SetFontScale ( g_Config . fGameGridScale , g_Config . fGameGridScale ) ;
}
2013-12-11 10:03:43 +00:00
if ( compact ) {
// No icon, except "up"
dc . PushScissor ( bounds_ ) ;
2020-02-29 20:51:14 +00:00
if ( image = = ImageID ( " I_FOLDER " ) ) {
2013-12-11 10:03:43 +00:00
dc . DrawText ( text . c_str ( ) , bounds_ . x + 5 , bounds_ . centerY ( ) , style . fgColor , ALIGN_VCENTER ) ;
} else {
2022-02-14 12:57:22 +00:00
dc . Draw ( ) - > DrawImage ( image , bounds_ . centerX ( ) , bounds_ . centerY ( ) , gridStyle_ ? g_Config . fGameGridScale : 1.0 , style . fgColor , ALIGN_CENTER ) ;
2013-12-11 10:03:43 +00:00
}
dc . PopScissor ( ) ;
} else {
bool scissor = false ;
if ( tw + 150 > bounds_ . w ) {
dc . PushScissor ( bounds_ ) ;
scissor = true ;
}
2022-02-14 12:57:22 +00:00
dc . Draw ( ) - > DrawImage ( image , bounds_ . x + 72 , bounds_ . centerY ( ) , 0.88f * ( gridStyle_ ? g_Config . fGameGridScale : 1.0 ) , style . fgColor , ALIGN_CENTER ) ;
2013-12-11 10:03:43 +00:00
dc . DrawText ( text . c_str ( ) , bounds_ . x + 150 , bounds_ . centerY ( ) , style . fgColor , ALIGN_VCENTER ) ;
if ( scissor ) {
dc . PopScissor ( ) ;
}
}
2020-03-01 14:34:35 +00:00
if ( gridStyle_ ) {
dc . SetFontScale ( 1.0 , 1.0 ) ;
}
2013-12-11 10:03:43 +00:00
}
2024-01-19 12:44:49 +00:00
GameBrowser : : GameBrowser ( int token , const Path & path , BrowseFlags browseFlags , bool * gridStyle , ScreenManager * screenManager , std : : string_view lastText , std : : string_view lastLink , UI : : LayoutParams * layoutParams )
2024-05-03 15:54:57 +00:00
: LinearLayout ( UI : : ORIENT_VERTICAL , layoutParams ) , gridStyle_ ( gridStyle ) , browseFlags_ ( browseFlags ) , lastText_ ( lastText ) , lastLink_ ( lastLink ) , screenManager_ ( screenManager ) , token_ ( token ) {
2013-08-16 10:52:16 +00:00
using namespace UI ;
2022-12-27 23:08:57 +00:00
path_ . SetUserAgent ( StringFromFormat ( " PPSSPP/%s " , PPSSPP_GIT_VERSION ) ) ;
2024-05-03 15:54:57 +00:00
path_ . SetRootAlias ( " ms: " , GetSysDirectory ( DIRECTORY_MEMSTICK_ROOT ) ) ;
if ( System_GetPropertyBool ( SYSPROP_LIMITED_FILE_BROWSING ) ) {
path_ . RestrictToRoot ( GetSysDirectory ( DIRECTORY_MEMSTICK_ROOT ) ) ;
}
path_ . SetPath ( path ) ;
2013-06-27 14:28:11 +00:00
Refresh ( ) ;
2013-08-16 10:52:16 +00:00
}
2013-06-27 14:28:11 +00:00
2021-05-05 23:31:38 +00:00
void GameBrowser : : FocusGame ( const Path & gamePath ) {
2016-02-08 01:15:19 +00:00
focusGamePath_ = gamePath ;
Refresh ( ) ;
focusGamePath_ . clear ( ) ;
}
2021-05-05 23:31:38 +00:00
void GameBrowser : : SetPath ( const Path & path ) {
2021-05-09 17:06:02 +00:00
path_ . SetPath ( path ) ;
2021-05-29 22:20:41 +00:00
g_Config . currentDirectory = path_ . GetPath ( ) ;
2019-02-17 15:48:32 +00:00
Refresh ( ) ;
}
2023-04-29 18:45:30 +00:00
void GameBrowser : : ApplySearchFilter ( const std : : string & filter ) {
searchFilter_ = filter ;
std : : transform ( searchFilter_ . begin ( ) , searchFilter_ . end ( ) , searchFilter_ . begin ( ) , tolower ) ;
// We don't refresh because game info loads asynchronously anyway.
ApplySearchFilter ( ) ;
}
void GameBrowser : : ApplySearchFilter ( ) {
if ( searchFilter_ . empty ( ) & & searchStates_ . empty ( ) ) {
// We haven't hidden anything, and we're not searching, so do nothing.
searchPending_ = false ;
return ;
}
searchPending_ = false ;
// By default, everything is matching.
searchStates_ . resize ( gameList_ - > GetNumSubviews ( ) , SearchState : : MATCH ) ;
if ( searchFilter_ . empty ( ) ) {
// Just quickly mark anything we hid as visible again.
for ( int i = 0 ; i < gameList_ - > GetNumSubviews ( ) ; + + i ) {
UI : : View * v = gameList_ - > GetViewByIndex ( i ) ;
if ( searchStates_ [ i ] ! = SearchState : : MATCH )
v - > SetVisibility ( UI : : V_VISIBLE ) ;
}
searchStates_ . clear ( ) ;
return ;
}
for ( int i = 0 ; i < gameList_ - > GetNumSubviews ( ) ; + + i ) {
UI : : View * v = gameList_ - > GetViewByIndex ( i ) ;
std : : string label = v - > DescribeText ( ) ;
// TODO: Maybe we should just save the gameButtons list, though nice to search dirs too?
// This is a bit of a hack to recognize a pending game title.
if ( label = = " ... " ) {
searchPending_ = true ;
// Hide anything pending while, we'll pop-in search results as they match.
// Note: we leave it at MATCH if gone before, so we don't show it again.
if ( v - > GetVisibility ( ) = = UI : : V_VISIBLE ) {
if ( searchStates_ [ i ] = = SearchState : : MATCH )
v - > SetVisibility ( UI : : V_GONE ) ;
searchStates_ [ i ] = SearchState : : PENDING ;
}
continue ;
}
std : : transform ( label . begin ( ) , label . end ( ) , label . begin ( ) , tolower ) ;
bool match = v - > CanBeFocused ( ) & & label . find ( searchFilter_ ) ! = label . npos ;
if ( match & & searchStates_ [ i ] ! = SearchState : : MATCH ) {
// It was previously visible and force hidden, so show it again.
v - > SetVisibility ( UI : : V_VISIBLE ) ;
searchStates_ [ i ] = SearchState : : MATCH ;
} else if ( ! match & & searchStates_ [ i ] = = SearchState : : MATCH & & v - > GetVisibility ( ) = = UI : : V_VISIBLE ) {
v - > SetVisibility ( UI : : V_GONE ) ;
searchStates_ [ i ] = SearchState : : MISMATCH ;
}
}
}
2013-08-16 10:52:16 +00:00
UI : : EventReturn GameBrowser : : LayoutChange ( UI : : EventParams & e ) {
2013-08-18 20:30:34 +00:00
* gridStyle_ = e . a = = 0 ? true : false ;
2013-08-16 10:52:16 +00:00
Refresh ( ) ;
return UI : : EVENT_DONE ;
}
UI : : EventReturn GameBrowser : : LastClick ( UI : : EventParams & e ) {
2023-03-21 09:42:23 +00:00
System_LaunchUrl ( LaunchUrlType : : BROWSER_URL , lastLink_ . c_str ( ) ) ;
2013-08-16 10:52:16 +00:00
return UI : : EVENT_DONE ;
}
2020-03-30 20:45:29 +00:00
UI : : EventReturn GameBrowser : : BrowseClick ( UI : : EventParams & e ) {
2023-04-05 22:34:50 +00:00
auto mm = GetI18NCategory ( I18NCat : : MAINMENU ) ;
2024-01-25 11:47:37 +00:00
System_BrowseForFolder ( token_ , mm - > T ( " Choose folder " ) , path_ . GetPath ( ) , [ this ] ( const std : : string & filename , int ) {
2023-03-22 15:09:33 +00:00
this - > SetPath ( Path ( filename ) ) ;
} ) ;
2020-03-30 20:45:29 +00:00
return UI : : EVENT_DONE ;
}
UI : : EventReturn GameBrowser : : StorageClick ( UI : : EventParams & e ) {
2021-01-06 15:37:04 +00:00
std : : vector < std : : string > storageDirs = System_GetPropertyStringVec ( SYSPROP_ADDITIONAL_STORAGE_DIRS ) ;
if ( storageDirs . empty ( ) ) {
// Shouldn't happen - this button shouldn't be clickable.
return UI : : EVENT_DONE ;
}
if ( storageDirs . size ( ) = = 1 ) {
2021-05-05 23:31:38 +00:00
SetPath ( Path ( storageDirs [ 0 ] ) ) ;
2021-01-06 15:37:04 +00:00
} else {
// TODO: We should popup a dialog letting the user choose one.
2021-05-05 23:31:38 +00:00
SetPath ( Path ( storageDirs [ 0 ] ) ) ;
2021-01-06 15:37:04 +00:00
}
2020-03-30 20:45:29 +00:00
return UI : : EVENT_DONE ;
}
2021-07-25 13:25:22 +00:00
UI : : EventReturn GameBrowser : : OnHomeClick ( UI : : EventParams & e ) {
if ( path_ . GetPath ( ) . Type ( ) = = PathType : : CONTENT_URI ) {
Path rootPath = path_ . GetPath ( ) . GetRootVolume ( ) ;
if ( rootPath ! = path_ . GetPath ( ) ) {
SetPath ( rootPath ) ;
return UI : : EVENT_DONE ;
}
if ( System_GetPropertyBool ( SYSPROP_ANDROID_SCOPED_STORAGE ) ) {
// There'll be no sensible home, ignore.
2021-07-18 20:28:59 +00:00
return UI : : EVENT_DONE ;
}
}
2021-05-17 01:04:03 +00:00
SetPath ( HomePath ( ) ) ;
return UI : : EVENT_DONE ;
}
2021-07-18 20:28:59 +00:00
// TODO: This doesn't make that much sense for Android, especially after scoped storage..
// Maybe we should have no home directory in this case. Or it should just navigate to the root
// of the current folder tree.
2021-05-17 01:04:03 +00:00
Path GameBrowser : : HomePath ( ) {
2023-12-28 14:34:40 +00:00
if ( ! homePath_ . empty ( ) ) {
return homePath_ ;
}
2021-01-07 08:40:01 +00:00
# if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH) || defined(USING_WIN_UI) || PPSSPP_PLATFORM(UWP)
2021-05-17 01:04:03 +00:00
return g_Config . memStickDirectory ;
2013-10-21 10:21:22 +00:00
# else
2021-05-17 01:04:03 +00:00
return Path ( getenv ( " HOME " ) ) ;
2013-10-15 11:28:09 +00:00
# endif
2013-06-27 14:28:11 +00:00
}
2013-12-08 06:39:35 +00:00
UI : : EventReturn GameBrowser : : PinToggleClick ( UI : : EventParams & e ) {
auto & pinnedPaths = g_Config . vPinnedPaths ;
2021-05-09 17:06:02 +00:00
const std : : string path = File : : ResolvePath ( path_ . GetPath ( ) . ToString ( ) ) ;
2013-12-08 06:39:35 +00:00
if ( IsCurrentPathPinned ( ) ) {
2018-09-05 04:53:20 +00:00
pinnedPaths . erase ( std : : remove ( pinnedPaths . begin ( ) , pinnedPaths . end ( ) , path ) , pinnedPaths . end ( ) ) ;
2013-12-08 06:39:35 +00:00
} else {
2018-09-05 04:53:20 +00:00
pinnedPaths . push_back ( path ) ;
2013-12-08 06:39:35 +00:00
}
Refresh ( ) ;
return UI : : EVENT_DONE ;
}
2016-07-04 03:48:27 +00:00
bool GameBrowser : : DisplayTopBar ( ) {
2021-05-09 17:06:02 +00:00
return path_ . GetPath ( ) . ToString ( ) ! = " !RECENT " ;
2016-07-04 03:48:27 +00:00
}
2021-05-09 13:25:12 +00:00
bool GameBrowser : : HasSpecialFiles ( std : : vector < Path > & filenames ) {
2021-05-09 17:06:02 +00:00
if ( path_ . GetPath ( ) . ToString ( ) = = " !RECENT " ) {
2021-05-09 13:25:12 +00:00
filenames . clear ( ) ;
2022-07-12 03:44:13 +00:00
for ( auto & str : g_Config . RecentIsos ( ) ) {
2021-05-09 13:25:12 +00:00
filenames . push_back ( Path ( str ) ) ;
}
2016-07-04 03:48:27 +00:00
return true ;
}
return false ;
}
2019-10-06 18:49:35 +00:00
void GameBrowser : : Update ( ) {
LinearLayout : : Update ( ) ;
if ( listingPending_ & & path_ . IsListingReady ( ) ) {
Refresh ( ) ;
}
2023-04-29 18:45:30 +00:00
if ( searchPending_ ) {
ApplySearchFilter ( ) ;
}
2019-10-06 18:49:35 +00:00
}
2020-03-01 14:34:35 +00:00
void GameBrowser : : Draw ( UIContext & dc ) {
using namespace UI ;
if ( lastScale_ ! = g_Config . fGameGridScale | | lastLayoutWasGrid_ ! = * gridStyle_ ) {
Refresh ( ) ;
}
if ( hasDropShadow_ ) {
// Darken things behind.
dc . FillRect ( UI : : Drawable ( 0x60000000 ) , dc . GetBounds ( ) . Expand ( dropShadowExpand_ ) ) ;
float dropsize = 30.0f ;
dc . Draw ( ) - > DrawImage4Grid ( dc . theme - > dropShadow4Grid ,
bounds_ . x - dropsize , bounds_ . y ,
bounds_ . x2 ( ) + dropsize , bounds_ . y2 ( ) + dropsize * 1.5f , 0xDF000000 , 3.0f ) ;
}
if ( clip_ ) {
dc . PushScissor ( bounds_ ) ;
}
dc . FillRect ( bg_ , bounds_ ) ;
for ( View * view : views_ ) {
if ( view - > GetVisibility ( ) = = V_VISIBLE ) {
// Check if bounds are in current scissor rectangle.
if ( dc . GetScissorBounds ( ) . Intersects ( dc . TransformBounds ( view - > GetBounds ( ) ) ) )
view - > Draw ( dc ) ;
}
}
if ( clip_ ) {
dc . PopScissor ( ) ;
}
}
2021-05-09 13:02:46 +00:00
static bool IsValidPBP ( const Path & path , bool allowHomebrew ) {
2020-03-08 04:30:55 +00:00
if ( ! File : : Exists ( path ) )
return false ;
2021-05-09 16:38:48 +00:00
std : : unique_ptr < FileLoader > loader ( ConstructFileLoader ( path ) ) ;
2020-03-08 04:30:55 +00:00
PBPReader pbp ( loader . get ( ) ) ;
std : : vector < u8 > sfoData ;
if ( ! pbp . GetSubFile ( PBP_PARAM_SFO , & sfoData ) )
return false ;
ParamSFOData sfo ;
sfo . ReadSFO ( sfoData ) ;
2020-05-17 13:12:38 +00:00
if ( ! allowHomebrew & & sfo . GetValueString ( " DISC_ID " ) . empty ( ) )
2020-03-08 04:30:55 +00:00
return false ;
if ( sfo . GetValueString ( " CATEGORY " ) = = " ME " )
return false ;
return true ;
}
2013-06-10 20:06:51 +00:00
void GameBrowser : : Refresh ( ) {
2013-08-16 10:52:16 +00:00
using namespace UI ;
2020-03-01 14:34:35 +00:00
lastScale_ = g_Config . fGameGridScale ;
lastLayoutWasGrid_ = * gridStyle_ ;
2013-08-16 10:52:16 +00:00
// Kill all the contents
Clear ( ) ;
2023-04-29 18:45:30 +00:00
searchStates_ . clear ( ) ;
2013-08-16 10:52:16 +00:00
2013-12-03 16:38:58 +00:00
Add ( new Spacer ( 1.0f ) ) ;
2023-04-05 22:34:50 +00:00
auto mm = GetI18NCategory ( I18NCat : : MAINMENU ) ;
2013-08-20 10:28:17 +00:00
2013-12-03 15:17:24 +00:00
// No topbar on recent screen
2016-07-04 03:48:27 +00:00
if ( DisplayTopBar ( ) ) {
2013-12-03 15:17:24 +00:00
LinearLayout * topBar = new LinearLayout ( ORIENT_HORIZONTAL , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ;
2019-10-06 19:40:00 +00:00
if ( browseFlags_ & BrowseFlags : : NAVIGATE ) {
2013-12-03 16:38:58 +00:00
topBar - > Add ( new Spacer ( 2.0f ) ) ;
2023-09-15 10:54:11 +00:00
topBar - > Add ( new TextView ( path_ . GetFriendlyPath ( ) , ALIGN_VCENTER | FLAG_WRAP_TEXT , true , new LinearLayoutParams ( FILL_PARENT , 64.0f , 1.0f ) ) ) ;
2021-07-25 13:25:22 +00:00
topBar - > Add ( new Choice ( ImageID ( " I_HOME " ) , new LayoutParams ( WRAP_CONTENT , 64.0f ) ) ) - > OnClick . Handle ( this , & GameBrowser : : OnHomeClick ) ;
2021-01-06 15:37:04 +00:00
if ( System_GetPropertyBool ( SYSPROP_HAS_ADDITIONAL_STORAGE ) ) {
2020-03-30 20:45:29 +00:00
topBar - > Add ( new Choice ( ImageID ( " I_SDCARD " ) , new LayoutParams ( WRAP_CONTENT , 64.0f ) ) ) - > OnClick . Handle ( this , & GameBrowser : : StorageClick ) ;
}
2023-01-31 10:36:14 +00:00
# if PPSSPP_PLATFORM(IOS) || PPSSPP_PLATFORM(MAC)
// on Darwin, we don't show the 'Browse' text alongside the image
// we show just the image, because we don't need to emphasize the button on Darwin
topBar - > Add ( new Choice ( ImageID ( " I_FOLDER_OPEN " ) , new LayoutParams ( WRAP_CONTENT , 64.0f ) ) ) - > OnClick . Handle ( this , & GameBrowser : : BrowseClick ) ;
# else
2023-12-28 14:34:40 +00:00
if ( ( browseFlags_ & BrowseFlags : : BROWSE ) & & System_GetPropertyBool ( SYSPROP_HAS_FOLDER_BROWSER ) ) {
2021-10-04 18:28:49 +00:00
topBar - > Add ( new Choice ( mm - > T ( " Browse " ) , ImageID ( " I_FOLDER_OPEN " ) , new LayoutParams ( WRAP_CONTENT , 64.0f ) ) ) - > OnClick . Handle ( this , & GameBrowser : : BrowseClick ) ;
2021-01-07 08:40:01 +00:00
}
2023-08-04 20:32:25 +00:00
if ( System_GetPropertyInt ( SYSPROP_DEVICE_TYPE ) = = DEVICE_TYPE_TV ) {
topBar - > Add ( new Choice ( mm - > T ( " Enter Path " ) , new LayoutParams ( WRAP_CONTENT , 64.0f ) ) ) - > OnClick . Add ( [ = ] ( UI : : EventParams & ) {
auto mm = GetI18NCategory ( I18NCat : : MAINMENU ) ;
2024-01-18 10:55:39 +00:00
System_InputBoxGetString ( token_ , mm - > T ( " Enter Path " ) , path_ . GetPath ( ) . ToString ( ) , [ = ] ( const char * responseString , int responseValue ) {
2023-08-04 20:32:25 +00:00
this - > SetPath ( Path ( responseString ) ) ;
} ) ;
return UI : : EVENT_DONE ;
} ) ;
}
2023-01-31 10:36:14 +00:00
# endif
2013-12-03 15:17:24 +00:00
} else {
2016-08-07 20:34:47 +00:00
topBar - > Add ( new Spacer ( new LinearLayoutParams ( FILL_PARENT , 64.0f , 1.0f ) ) ) ;
2013-12-03 15:17:24 +00:00
}
2021-07-12 09:09:39 +00:00
if ( browseFlags_ & BrowseFlags : : HOMEBREW_STORE ) {
topBar - > Add ( new Choice ( mm - > T ( " PPSSPP Homebrew Store " ) , new UI : : LinearLayoutParams ( WRAP_CONTENT , 64.0f ) ) ) - > OnClick . Handle ( this , & GameBrowser : : OnHomebrewStore ) ;
}
2013-12-03 15:17:24 +00:00
ChoiceStrip * layoutChoice = topBar - > Add ( new ChoiceStrip ( ORIENT_HORIZONTAL ) ) ;
2020-02-29 20:51:14 +00:00
layoutChoice - > AddChoice ( ImageID ( " I_GRID " ) ) ;
layoutChoice - > AddChoice ( ImageID ( " I_LINES " ) ) ;
2021-02-28 20:25:37 +00:00
layoutChoice - > SetSelection ( * gridStyle_ ? 0 : 1 , false ) ;
2013-12-03 15:17:24 +00:00
layoutChoice - > OnChoice . Handle ( this , & GameBrowser : : LayoutChange ) ;
2023-12-28 23:17:35 +00:00
topBar - > Add ( new Choice ( ImageID ( " I_ROTATE_LEFT " ) , new LayoutParams ( 64.0f , 64.0f ) ) ) - > OnClick . Add ( [ = ] ( UI : : EventParams & e ) {
path_ . Refresh ( ) ;
Refresh ( ) ;
return UI : : EVENT_DONE ;
} ) ;
2020-03-01 14:34:35 +00:00
topBar - > Add ( new Choice ( ImageID ( " I_GEAR " ) , new LayoutParams ( 64.0f , 64.0f ) ) ) - > OnClick . Handle ( this , & GameBrowser : : GridSettingsClick ) ;
2013-12-03 15:17:24 +00:00
Add ( topBar ) ;
2013-11-29 15:46:47 +00:00
2020-03-01 14:34:35 +00:00
if ( * gridStyle_ ) {
2021-02-22 02:41:08 +00:00
gameList_ = new UI : : GridLayoutList ( UI : : GridLayoutSettings ( 150 * g_Config . fGameGridScale , 85 * g_Config . fGameGridScale ) , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ;
2020-03-01 14:34:35 +00:00
Add ( gameList_ ) ;
} else {
2021-02-22 02:41:08 +00:00
UI : : LinearLayout * gl = new UI : : LinearLayoutList ( UI : : ORIENT_VERTICAL , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ;
2020-03-01 14:34:35 +00:00
gl - > SetSpacing ( 4.0f ) ;
gameList_ = gl ;
Add ( gameList_ ) ;
}
2013-08-16 10:52:16 +00:00
} else {
2020-03-01 14:34:35 +00:00
if ( * gridStyle_ ) {
2021-02-22 02:41:08 +00:00
gameList_ = new UI : : GridLayoutList ( UI : : GridLayoutSettings ( 150 * g_Config . fGameGridScale , 85 * g_Config . fGameGridScale ) , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ;
2020-03-01 14:34:35 +00:00
} else {
UI : : LinearLayout * gl = new UI : : LinearLayout ( UI : : ORIENT_VERTICAL , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ;
gl - > SetSpacing ( 4.0f ) ;
gameList_ = gl ;
}
2020-03-08 21:21:59 +00:00
// Until we can come up with a better space to put it (next to the tabs?) let's get rid of the icon config
// button on the Recent tab, it's ugly. You can use the button from the other tabs.
// LinearLayout *gridOptionColumn = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(64.0, 64.0f));
// gridOptionColumn->Add(new Spacer(12.0));
// gridOptionColumn->Add(new Choice(ImageID("I_GEAR"), new LayoutParams(64.0f, 64.0f)))->OnClick.Handle(this, &GameBrowser::GridSettingsClick);
// LinearLayout *grid = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
// gameList_->ReplaceLayoutParams(new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 0.75));
// grid->Add(gameList_);
// grid->Add(gridOptionColumn);
// Add(grid);
Add ( gameList_ ) ;
2013-08-16 10:52:16 +00:00
}
2013-06-10 20:06:51 +00:00
// Find games in the current directory and create new ones.
2013-12-08 06:39:35 +00:00
std : : vector < DirButton * > dirButtons ;
2013-06-27 14:28:11 +00:00
std : : vector < GameButton * > gameButtons ;
2019-10-06 18:49:35 +00:00
listingPending_ = ! path_ . IsListingReady ( ) ;
2021-05-09 13:25:12 +00:00
std : : vector < Path > filenames ;
2016-07-04 03:48:27 +00:00
if ( HasSpecialFiles ( filenames ) ) {
for ( size_t i = 0 ; i < filenames . size ( ) ; i + + ) {
gameButtons . push_back ( new GameButton ( filenames [ i ] , * gridStyle_ , new UI : : LinearLayoutParams ( * gridStyle_ = = true ? UI : : WRAP_CONTENT : UI : : FILL_PARENT , UI : : WRAP_CONTENT ) ) ) ;
2013-06-27 14:28:11 +00:00
}
2019-10-06 18:49:35 +00:00
} else if ( ! listingPending_ ) {
2021-04-25 18:38:22 +00:00
std : : vector < File : : FileInfo > fileInfo ;
2023-09-22 16:24:37 +00:00
path_ . GetListing ( fileInfo , " iso:cso:chd:pbp:elf:prx:ppdmp: " ) ;
2013-06-10 20:06:51 +00:00
for ( size_t i = 0 ; i < fileInfo . size ( ) ; i + + ) {
2013-12-08 06:54:23 +00:00
bool isGame = ! fileInfo [ i ] . isDirectory ;
2015-06-11 18:22:16 +00:00
bool isSaveData = false ;
2013-12-08 06:54:23 +00:00
// Check if eboot directory
2021-05-11 07:50:28 +00:00
if ( ! isGame & & path_ . GetPath ( ) . size ( ) > = 4 & & IsValidPBP ( path_ . GetPath ( ) / fileInfo [ i ] . name / " EBOOT.PBP " , true ) )
2013-12-08 06:54:23 +00:00
isGame = true ;
2021-05-09 17:06:02 +00:00
else if ( ! isGame & & File : : Exists ( path_ . GetPath ( ) / fileInfo [ i ] . name / " PSP_GAME/SYSDIR " ) )
2013-12-08 06:54:23 +00:00
isGame = true ;
2021-05-09 17:06:02 +00:00
else if ( ! isGame & & File : : Exists ( path_ . GetPath ( ) / fileInfo [ i ] . name / " PARAM.SFO " ) )
2015-06-11 18:22:16 +00:00
isSaveData = true ;
2013-12-08 06:54:23 +00:00
2015-06-11 18:22:16 +00:00
if ( ! isGame & & ! isSaveData ) {
2019-10-06 19:40:00 +00:00
if ( browseFlags_ & BrowseFlags : : NAVIGATE ) {
2020-03-01 14:34:35 +00:00
dirButtons . push_back ( new DirButton ( fileInfo [ i ] . fullName , fileInfo [ i ] . name , * gridStyle_ , new UI : : LinearLayoutParams ( UI : : FILL_PARENT , UI : : FILL_PARENT ) ) ) ;
2013-12-11 09:11:01 +00:00
}
2013-06-27 14:28:11 +00:00
} else {
2013-08-18 20:30:34 +00:00
gameButtons . push_back ( new GameButton ( fileInfo [ i ] . fullName , * gridStyle_ , new UI : : LinearLayoutParams ( * gridStyle_ = = true ? UI : : WRAP_CONTENT : UI : : FILL_PARENT , UI : : WRAP_CONTENT ) ) ) ;
2013-06-27 14:28:11 +00:00
}
2013-06-10 20:06:51 +00:00
}
2013-08-19 22:49:25 +00:00
// Put RAR/ZIP files at the end to get them out of the way. They're only shown so that people
// can click them and get an explanation that they need to unpack them. This is necessary due
// to a flood of support email...
2019-10-06 19:40:00 +00:00
if ( browseFlags_ & BrowseFlags : : ARCHIVES ) {
2013-08-19 22:49:25 +00:00
fileInfo . clear ( ) ;
2014-10-20 22:09:24 +00:00
path_ . GetListing ( fileInfo , " zip:rar:r01:7z: " ) ;
2013-12-11 17:25:55 +00:00
if ( ! fileInfo . empty ( ) ) {
2021-02-22 02:41:08 +00:00
UI : : LinearLayout * zl = new UI : : LinearLayoutList ( UI : : ORIENT_VERTICAL , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ;
2013-12-11 19:01:17 +00:00
zl - > SetSpacing ( 4.0f ) ;
2013-12-11 17:25:55 +00:00
Add ( zl ) ;
for ( size_t i = 0 ; i < fileInfo . size ( ) ; i + + ) {
if ( ! fileInfo [ i ] . isDirectory ) {
2013-12-11 19:37:57 +00:00
GameButton * b = zl - > Add ( new GameButton ( fileInfo [ i ] . fullName , false , new UI : : LinearLayoutParams ( UI : : FILL_PARENT , UI : : WRAP_CONTENT ) ) ) ;
b - > OnClick . Handle ( this , & GameBrowser : : GameButtonClick ) ;
b - > SetHoldEnabled ( false ) ;
2013-12-11 17:25:55 +00:00
}
2013-08-19 22:49:25 +00:00
}
}
}
2013-06-10 20:06:51 +00:00
}
2019-10-06 19:40:00 +00:00
if ( browseFlags_ & BrowseFlags : : NAVIGATE ) {
2020-12-20 00:38:45 +00:00
if ( path_ . CanNavigateUp ( ) ) {
2021-05-09 13:25:12 +00:00
gameList_ - > Add ( new DirButton ( Path ( std : : string ( " .. " ) ) , * gridStyle_ , new UI : : LinearLayoutParams ( UI : : FILL_PARENT , UI : : FILL_PARENT ) ) ) - >
2020-12-20 00:38:45 +00:00
OnClick . Handle ( this , & GameBrowser : : NavigateClick ) ;
}
2020-03-30 20:45:29 +00:00
2013-12-08 06:39:35 +00:00
// Add any pinned paths before other directories.
auto pinnedPaths = GetPinnedPaths ( ) ;
for ( auto it = pinnedPaths . begin ( ) , end = pinnedPaths . end ( ) ; it ! = end ; + + it ) {
2021-05-09 13:25:12 +00:00
gameList_ - > Add ( new DirButton ( * it , GetBaseName ( ( * it ) . ToString ( ) ) , * gridStyle_ , new UI : : LinearLayoutParams ( UI : : FILL_PARENT , UI : : FILL_PARENT ) ) ) - >
2013-12-08 06:39:35 +00:00
OnClick . Handle ( this , & GameBrowser : : NavigateClick ) ;
}
2013-12-05 11:07:21 +00:00
}
2013-06-27 14:28:11 +00:00
2019-10-06 18:49:35 +00:00
if ( listingPending_ ) {
gameList_ - > Add ( new UI : : TextView ( mm - > T ( " Loading... " ) , ALIGN_CENTER , false , new UI : : LinearLayoutParams ( UI : : FILL_PARENT , UI : : FILL_PARENT ) ) ) ;
}
2013-06-27 14:28:11 +00:00
for ( size_t i = 0 ; i < dirButtons . size ( ) ; i + + ) {
2013-08-16 10:52:16 +00:00
gameList_ - > Add ( dirButtons [ i ] ) - > OnClick . Handle ( this , & GameBrowser : : NavigateClick ) ;
2013-06-27 14:28:11 +00:00
}
for ( size_t i = 0 ; i < gameButtons . size ( ) ; i + + ) {
2013-08-16 10:52:16 +00:00
GameButton * b = gameList_ - > Add ( gameButtons [ i ] ) ;
2013-07-22 20:36:56 +00:00
b - > OnClick . Handle ( this , & GameBrowser : : GameButtonClick ) ;
b - > OnHoldClick . Handle ( this , & GameBrowser : : GameButtonHoldClick ) ;
2014-06-22 01:04:27 +00:00
b - > OnHighlight . Handle ( this , & GameBrowser : : GameButtonHighlight ) ;
2016-02-08 01:15:19 +00:00
if ( ! focusGamePath_ . empty ( ) & & b - > GamePath ( ) = = focusGamePath_ ) {
b - > SetFocus ( ) ;
}
2013-06-10 20:06:51 +00:00
}
2013-08-16 10:52:16 +00:00
2013-12-08 06:39:35 +00:00
// Show a button to toggle pinning at the very end.
2021-07-29 21:15:35 +00:00
if ( ( browseFlags_ & BrowseFlags : : PIN ) & & ! path_ . GetPath ( ) . empty ( ) ) {
2013-12-08 06:39:35 +00:00
std : : string caption = IsCurrentPathPinned ( ) ? " - " : " + " ;
if ( ! * gridStyle_ ) {
2015-07-01 22:02:08 +00:00
caption = IsCurrentPathPinned ( ) ? mm - > T ( " UnpinPath " , " Unpin " ) : mm - > T ( " PinPath " , " Pin " ) ;
2013-12-08 06:39:35 +00:00
}
gameList_ - > Add ( new UI : : Button ( caption , new UI : : LinearLayoutParams ( UI : : FILL_PARENT , UI : : FILL_PARENT ) ) ) - >
OnClick . Handle ( this , & GameBrowser : : PinToggleClick ) ;
}
2021-07-29 21:15:35 +00:00
if ( path_ . GetPath ( ) . empty ( ) ) {
Add ( new TextView ( mm - > T ( " UseBrowseOrLoad " , " Use Browse to choose a folder, or Load to choose a file. " ) ) ) ;
}
2023-12-28 14:34:40 +00:00
if ( ! lastText_ . empty ( ) ) {
2013-08-16 10:52:16 +00:00
Add ( new Spacer ( ) ) ;
2013-08-16 14:48:43 +00:00
Add ( new Choice ( lastText_ , new UI : : LinearLayoutParams ( UI : : WRAP_CONTENT , UI : : WRAP_CONTENT ) ) ) - > OnClick . Handle ( this , & GameBrowser : : LastClick ) ;
2013-08-16 10:52:16 +00:00
}
2013-06-10 20:06:51 +00:00
}
2013-12-08 06:39:35 +00:00
bool GameBrowser : : IsCurrentPathPinned ( ) {
const auto paths = g_Config . vPinnedPaths ;
2021-05-09 17:06:02 +00:00
return std : : find ( paths . begin ( ) , paths . end ( ) , File : : ResolvePath ( path_ . GetPath ( ) . ToString ( ) ) ) ! = paths . end ( ) ;
2013-12-08 06:39:35 +00:00
}
2024-04-02 15:37:00 +00:00
std : : vector < Path > GameBrowser : : GetPinnedPaths ( ) const {
2014-01-02 00:45:37 +00:00
# ifndef _WIN32
2013-12-08 06:39:35 +00:00
static const std : : string sepChars = " / " ;
# else
static const std : : string sepChars = " / \\ " ;
# endif
2021-05-09 17:06:02 +00:00
const std : : string currentPath = File : : ResolvePath ( path_ . GetPath ( ) . ToString ( ) ) ;
2013-12-08 06:39:35 +00:00
const std : : vector < std : : string > paths = g_Config . vPinnedPaths ;
2021-05-09 13:25:12 +00:00
std : : vector < Path > results ;
2013-12-08 06:39:35 +00:00
for ( size_t i = 0 ; i < paths . size ( ) ; + + i ) {
// We want to exclude the current path, and its direct children.
if ( paths [ i ] = = currentPath ) {
continue ;
}
if ( startsWith ( paths [ i ] , currentPath ) ) {
std : : string descendant = paths [ i ] . substr ( currentPath . size ( ) ) ;
// If there's only one separator (or none), its a direct child.
if ( descendant . find_last_of ( sepChars ) = = descendant . find_first_of ( sepChars ) ) {
continue ;
}
}
2021-05-09 13:25:12 +00:00
results . push_back ( Path ( paths [ i ] ) ) ;
2013-12-08 06:39:35 +00:00
}
return results ;
}
2024-04-02 15:37:00 +00:00
std : : string GameBrowser : : GetBaseName ( const std : : string & path ) const {
2014-01-02 00:45:37 +00:00
# ifndef _WIN32
2013-12-08 06:39:35 +00:00
static const std : : string sepChars = " / " ;
# else
static const std : : string sepChars = " / \\ " ;
# endif
auto trailing = path . find_last_not_of ( sepChars ) ;
if ( trailing ! = path . npos ) {
size_t start = path . find_last_of ( sepChars , trailing ) ;
if ( start ! = path . npos ) {
return path . substr ( start + 1 , trailing - start ) ;
}
return path . substr ( 0 , trailing ) ;
}
size_t start = path . find_last_of ( sepChars ) ;
if ( start ! = path . npos ) {
return path . substr ( start + 1 ) ;
}
return path ;
}
2013-06-10 20:06:51 +00:00
UI : : EventReturn GameBrowser : : GameButtonClick ( UI : : EventParams & e ) {
GameButton * button = static_cast < GameButton * > ( e . v ) ;
2017-02-27 20:57:46 +00:00
UI : : EventParams e2 { } ;
2021-05-05 23:31:38 +00:00
e2 . s = button - > GamePath ( ) . ToString ( ) ;
2013-06-10 20:06:51 +00:00
// Insta-update - here we know we are already on the right thread.
OnChoice . Trigger ( e2 ) ;
return UI : : EVENT_DONE ;
}
2013-07-22 20:36:56 +00:00
UI : : EventReturn GameBrowser : : GameButtonHoldClick ( UI : : EventParams & e ) {
GameButton * button = static_cast < GameButton * > ( e . v ) ;
2017-02-27 20:57:46 +00:00
UI : : EventParams e2 { } ;
2021-05-05 23:31:38 +00:00
e2 . s = button - > GamePath ( ) . ToString ( ) ;
2013-07-22 20:36:56 +00:00
// Insta-update - here we know we are already on the right thread.
OnHoldChoice . Trigger ( e2 ) ;
return UI : : EVENT_DONE ;
}
2014-06-22 01:04:27 +00:00
UI : : EventReturn GameBrowser : : GameButtonHighlight ( UI : : EventParams & e ) {
// Insta-update - here we know we are already on the right thread.
OnHighlight . Trigger ( e ) ;
return UI : : EVENT_DONE ;
}
2013-06-27 14:28:11 +00:00
UI : : EventReturn GameBrowser : : NavigateClick ( UI : : EventParams & e ) {
2019-02-17 15:48:32 +00:00
DirButton * button = static_cast < DirButton * > ( e . v ) ;
2021-05-09 17:06:02 +00:00
Path text = button - > GetPath ( ) ;
2013-12-08 06:39:35 +00:00
if ( button - > PathAbsolute ( ) ) {
path_ . SetPath ( text ) ;
} else {
2021-05-09 17:06:02 +00:00
path_ . Navigate ( text . ToString ( ) ) ;
2013-12-08 06:39:35 +00:00
}
2021-05-29 22:20:41 +00:00
g_Config . currentDirectory = path_ . GetPath ( ) ;
2013-06-27 14:28:11 +00:00
Refresh ( ) ;
return UI : : EVENT_DONE ;
}
2020-03-02 07:34:26 +00:00
UI : : EventReturn GameBrowser : : GridSettingsClick ( UI : : EventParams & e ) {
2023-04-05 22:34:50 +00:00
auto sy = GetI18NCategory ( I18NCat : : SYSTEM ) ;
2020-03-02 07:34:26 +00:00
auto gridSettings = new GridSettingsScreen ( sy - > T ( " Games list settings " ) ) ;
gridSettings - > OnRecentChanged . Handle ( this , & GameBrowser : : OnRecentClear ) ;
if ( e . v )
gridSettings - > SetPopupOrigin ( e . v ) ;
screenManager_ - > push ( gridSettings ) ;
return UI : : EVENT_DONE ;
}
UI : : EventReturn GameBrowser : : OnRecentClear ( UI : : EventParams & e ) {
screenManager_ - > RecreateAllViews ( ) ;
2023-03-21 10:21:19 +00:00
System_Notify ( SystemNotification : : UI ) ;
2020-03-02 07:34:26 +00:00
return UI : : EVENT_DONE ;
}
2020-05-17 12:57:12 +00:00
UI : : EventReturn GameBrowser : : OnHomebrewStore ( UI : : EventParams & e ) {
screenManager_ - > push ( new StoreScreen ( ) ) ;
return UI : : EVENT_DONE ;
}
MainScreen : : MainScreen ( ) {
2021-05-05 23:31:38 +00:00
g_BackgroundAudio . SetGame ( Path ( ) ) ;
2013-12-04 16:41:59 +00:00
}
2014-06-22 15:02:04 +00:00
MainScreen : : ~ MainScreen ( ) {
2021-05-05 23:31:38 +00:00
g_BackgroundAudio . SetGame ( Path ( ) ) ;
2014-06-22 15:02:04 +00:00
}
2013-06-10 20:06:51 +00:00
void MainScreen : : CreateViews ( ) {
// Information in the top left.
// Back button to the bottom left.
// Scrolling action menu to the right.
using namespace UI ;
2014-06-29 19:02:32 +00:00
bool vertical = UseVerticalLayout ( ) ;
2013-10-10 09:09:48 +00:00
2023-04-05 22:34:50 +00:00
auto mm = GetI18NCategory ( I18NCat : : MAINMENU ) ;
2013-08-11 15:25:50 +00:00
2017-12-13 05:38:45 +00:00
tabHolder_ = new TabHolder ( ORIENT_HORIZONTAL , 64 , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT , 1.0f ) ) ;
ViewGroup * leftColumn = tabHolder_ ;
2016-01-23 06:38:21 +00:00
tabHolder_ - > SetTag ( " MainScreenGames " ) ;
2016-02-08 01:15:19 +00:00
gameBrowsers_ . clear ( ) ;
2014-03-03 11:56:01 +00:00
2017-12-13 05:35:18 +00:00
tabHolder_ - > SetClip ( true ) ;
2013-06-10 20:06:51 +00:00
2016-03-06 01:18:24 +00:00
bool showRecent = g_Config . iMaxRecent > 0 ;
2021-07-17 17:50:36 +00:00
bool hasStorageAccess = ! System_GetPropertyBool ( SYSPROP_SUPPORTS_PERMISSIONS ) | |
System_GetPermissionStatus ( SYSTEM_PERMISSION_STORAGE ) = = PERMISSION_STATUS_GRANTED ;
2018-06-02 23:32:55 +00:00
bool storageIsTemporary = IsTempPath ( GetSysDirectory ( DIRECTORY_SAVEDATA ) ) & & ! confirmedTemporary_ ;
2016-03-06 01:18:24 +00:00
if ( showRecent & & ! hasStorageAccess ) {
2022-07-12 03:44:13 +00:00
showRecent = g_Config . HasRecentIsos ( ) ;
2016-03-06 01:18:24 +00:00
}
if ( showRecent ) {
2014-06-29 03:44:24 +00:00
ScrollView * scrollRecentGames = new ScrollView ( ORIENT_VERTICAL , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ;
2016-01-23 06:52:13 +00:00
scrollRecentGames - > SetTag ( " MainScreenRecentGames " ) ;
2024-01-18 10:55:39 +00:00
GameBrowser * tabRecentGames = new GameBrowser ( GetRequesterToken ( ) ,
2021-05-09 17:06:02 +00:00
Path ( " !RECENT " ) , BrowseFlags : : NONE , & g_Config . bGridView1 , screenManager ( ) , " " , " " ,
2014-06-29 03:44:24 +00:00
new LinearLayoutParams ( FILL_PARENT , FILL_PARENT ) ) ;
scrollRecentGames - > Add ( tabRecentGames ) ;
2016-02-08 01:15:19 +00:00
gameBrowsers_ . push_back ( tabRecentGames ) ;
2017-12-13 05:35:18 +00:00
tabHolder_ - > AddTab ( mm - > T ( " Recent " ) , scrollRecentGames ) ;
2014-06-29 03:44:24 +00:00
tabRecentGames - > OnChoice . Handle ( this , & MainScreen : : OnGameSelectedInstant ) ;
tabRecentGames - > OnHoldChoice . Handle ( this , & MainScreen : : OnGameSelected ) ;
tabRecentGames - > OnHighlight . Handle ( this , & MainScreen : : OnGameHighlight ) ;
}
2013-06-27 14:28:11 +00:00
2018-06-02 23:32:55 +00:00
Button * focusButton = nullptr ;
2016-03-06 01:18:24 +00:00
if ( hasStorageAccess ) {
2021-09-28 06:25:41 +00:00
scrollAllGames_ = new ScrollView ( ORIENT_VERTICAL , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ;
2020-11-23 09:06:48 +00:00
scrollAllGames_ - > SetTag ( " MainScreenAllGames " ) ;
2015-12-17 21:41:50 +00:00
ScrollView * scrollHomebrew = new ScrollView ( ORIENT_VERTICAL , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ;
2016-01-23 06:52:13 +00:00
scrollHomebrew - > SetTag ( " MainScreenHomebrew " ) ;
2013-06-27 14:28:11 +00:00
2023-12-28 14:34:40 +00:00
2024-01-18 10:55:39 +00:00
GameBrowser * tabAllGames = new GameBrowser ( GetRequesterToken ( ) , Path ( g_Config . currentDirectory ) , BrowseFlags : : STANDARD , & g_Config . bGridView2 , screenManager ( ) ,
2023-01-28 23:25:00 +00:00
mm - > T ( " How to get games " ) , " https://www.ppsspp.org/getgames " ,
2015-12-17 21:41:50 +00:00
new LinearLayoutParams ( FILL_PARENT , FILL_PARENT ) ) ;
2024-01-18 10:55:39 +00:00
GameBrowser * tabHomebrew = new GameBrowser ( GetRequesterToken ( ) , GetSysDirectory ( DIRECTORY_GAME ) , BrowseFlags : : HOMEBREW_STORE , & g_Config . bGridView3 , screenManager ( ) ,
2023-01-28 23:25:00 +00:00
mm - > T ( " How to get homebrew & demos " , " How to get homebrew && demos " ) , " https://www.ppsspp.org/gethomebrew " ,
2015-12-17 21:41:50 +00:00
new LinearLayoutParams ( FILL_PARENT , FILL_PARENT ) ) ;
2013-11-29 12:02:08 +00:00
2020-11-23 09:06:48 +00:00
scrollAllGames_ - > Add ( tabAllGames ) ;
2016-02-08 01:15:19 +00:00
gameBrowsers_ . push_back ( tabAllGames ) ;
2015-12-17 21:41:50 +00:00
scrollHomebrew - > Add ( tabHomebrew ) ;
2016-02-08 01:15:19 +00:00
gameBrowsers_ . push_back ( tabHomebrew ) ;
2013-06-10 20:06:51 +00:00
2020-11-23 09:06:48 +00:00
tabHolder_ - > AddTab ( mm - > T ( " Games " ) , scrollAllGames_ ) ;
2017-12-13 05:35:18 +00:00
tabHolder_ - > AddTab ( mm - > T ( " Homebrew & Demos " ) , scrollHomebrew ) ;
2021-09-28 06:25:41 +00:00
scrollAllGames_ - > RememberPosition ( & g_Config . fGameListScrollPosition ) ;
2014-06-29 03:44:24 +00:00
2015-12-17 21:41:50 +00:00
tabAllGames - > OnChoice . Handle ( this , & MainScreen : : OnGameSelectedInstant ) ;
tabHomebrew - > OnChoice . Handle ( this , & MainScreen : : OnGameSelectedInstant ) ;
2014-06-29 03:44:24 +00:00
2015-12-17 21:41:50 +00:00
tabAllGames - > OnHoldChoice . Handle ( this , & MainScreen : : OnGameSelected ) ;
tabHomebrew - > OnHoldChoice . Handle ( this , & MainScreen : : OnGameSelected ) ;
2013-06-10 20:06:51 +00:00
2015-12-17 21:41:50 +00:00
tabAllGames - > OnHighlight . Handle ( this , & MainScreen : : OnGameHighlight ) ;
tabHomebrew - > OnHighlight . Handle ( this , & MainScreen : : OnGameHighlight ) ;
2023-12-28 14:34:40 +00:00
if ( g_Config . bRemoteTab & & ! g_Config . sLastRemoteISOServer . empty ( ) ) {
auto ri = GetI18NCategory ( I18NCat : : REMOTEISO ) ;
ScrollView * scrollRemote = new ScrollView ( ORIENT_VERTICAL , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ;
scrollRemote - > SetTag ( " MainScreenRemote " ) ;
Path remotePath ( FormatRemoteISOUrl ( g_Config . sLastRemoteISOServer . c_str ( ) , g_Config . iLastRemoteISOPort , RemoteSubdir ( ) . c_str ( ) ) ) ;
2024-01-18 10:55:39 +00:00
GameBrowser * tabRemote = new GameBrowser ( GetRequesterToken ( ) , remotePath , BrowseFlags : : NAVIGATE , & g_Config . bGridView3 , screenManager ( ) ,
2023-12-28 14:34:40 +00:00
ri - > T ( " Remote disc streaming " ) , " https://www.ppsspp.org/docs/reference/disc-streaming " ,
new LinearLayoutParams ( FILL_PARENT , FILL_PARENT ) ) ;
tabRemote - > SetHomePath ( remotePath ) ;
scrollRemote - > Add ( tabRemote ) ;
gameBrowsers_ . push_back ( tabRemote ) ;
tabHolder_ - > AddTab ( ri - > T ( " Remote disc streaming " ) , scrollRemote ) ;
tabRemote - > OnChoice . Handle ( this , & MainScreen : : OnGameSelectedInstant ) ;
tabRemote - > OnHoldChoice . Handle ( this , & MainScreen : : OnGameSelected ) ;
tabRemote - > OnHighlight . Handle ( this , & MainScreen : : OnGameHighlight ) ;
}
2022-07-12 03:44:13 +00:00
if ( g_Config . HasRecentIsos ( ) ) {
2017-12-13 05:34:17 +00:00
tabHolder_ - > SetCurrentTab ( 0 , true ) ;
2015-12-17 21:41:50 +00:00
} else if ( g_Config . iMaxRecent > 0 ) {
2017-12-13 05:34:17 +00:00
tabHolder_ - > SetCurrentTab ( 1 , true ) ;
2015-12-17 21:41:50 +00:00
}
2013-06-10 20:06:51 +00:00
2015-12-17 21:41:50 +00:00
if ( backFromStore_ | | showHomebrewTab ) {
2017-12-13 05:34:17 +00:00
tabHolder_ - > SetCurrentTab ( 2 , true ) ;
2015-12-17 21:41:50 +00:00
backFromStore_ = false ;
showHomebrewTab = false ;
}
2018-06-02 23:32:55 +00:00
if ( storageIsTemporary ) {
LinearLayout * buttonHolder = new LinearLayout ( ORIENT_HORIZONTAL , new LinearLayoutParams ( WRAP_CONTENT , WRAP_CONTENT ) ) ;
buttonHolder - > Add ( new Spacer ( new LinearLayoutParams ( 1.0f ) ) ) ;
focusButton = new Button ( mm - > T ( " SavesAreTemporaryIgnore " , " Ignore warning " ) , new LinearLayoutParams ( WRAP_CONTENT , WRAP_CONTENT ) ) ;
focusButton - > SetPadding ( 32 , 16 ) ;
buttonHolder - > Add ( focusButton ) - > OnClick . Add ( [ this ] ( UI : : EventParams & e ) {
confirmedTemporary_ = true ;
RecreateViews ( ) ;
return UI : : EVENT_DONE ;
} ) ;
buttonHolder - > Add ( new Spacer ( new LinearLayoutParams ( 1.0f ) ) ) ;
leftColumn - > Add ( new Spacer ( new LinearLayoutParams ( 0.1f ) ) ) ;
leftColumn - > Add ( new TextView ( mm - > T ( " SavesAreTemporary " , " PPSSPP saving in temporary storage " ) , ALIGN_HCENTER , false ) ) ;
leftColumn - > Add ( new TextView ( mm - > T ( " SavesAreTemporaryGuidance " , " Extract PPSSPP somewhere to save permanently " ) , ALIGN_HCENTER , false ) ) ;
leftColumn - > Add ( new Spacer ( 10.0f ) ) ;
leftColumn - > Add ( buttonHolder ) ;
leftColumn - > Add ( new Spacer ( new LinearLayoutParams ( 0.1f ) ) ) ;
}
2015-12-17 21:41:50 +00:00
} else {
2020-12-06 17:27:11 +00:00
scrollAllGames_ = nullptr ;
2017-12-13 05:38:45 +00:00
if ( ! showRecent ) {
leftColumn = new LinearLayout ( ORIENT_VERTICAL , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT , 1.0f ) ) ;
// Just so it's destroyed on recreate.
leftColumn - > Add ( tabHolder_ ) ;
tabHolder_ - > SetVisibility ( V_GONE ) ;
}
2016-03-06 01:18:24 +00:00
LinearLayout * buttonHolder = new LinearLayout ( ORIENT_HORIZONTAL , new LinearLayoutParams ( WRAP_CONTENT , WRAP_CONTENT ) ) ;
buttonHolder - > Add ( new Spacer ( new LinearLayoutParams ( 1.0f ) ) ) ;
2018-06-02 23:32:55 +00:00
focusButton = new Button ( mm - > T ( " Give PPSSPP permission to access storage " ) , new LinearLayoutParams ( WRAP_CONTENT , WRAP_CONTENT ) ) ;
focusButton - > SetPadding ( 32 , 16 ) ;
buttonHolder - > Add ( focusButton ) - > OnClick . Handle ( this , & MainScreen : : OnAllowStorage ) ;
2016-03-06 01:18:24 +00:00
buttonHolder - > Add ( new Spacer ( new LinearLayoutParams ( 1.0f ) ) ) ;
2017-12-13 05:35:18 +00:00
leftColumn - > Add ( new Spacer ( new LinearLayoutParams ( 0.1f ) ) ) ;
2016-03-06 01:18:24 +00:00
leftColumn - > Add ( buttonHolder ) ;
leftColumn - > Add ( new Spacer ( 10.0f ) ) ;
leftColumn - > Add ( new TextView ( mm - > T ( " PPSSPP can't load games or save right now " ) , ALIGN_HCENTER , false ) ) ;
2017-12-13 05:35:18 +00:00
leftColumn - > Add ( new Spacer ( new LinearLayoutParams ( 0.1f ) ) ) ;
2013-11-20 15:36:58 +00:00
}
2013-11-29 15:46:47 +00:00
2013-10-09 14:26:15 +00:00
ViewGroup * rightColumn = new ScrollView ( ORIENT_VERTICAL ) ;
LinearLayout * rightColumnItems = new LinearLayout ( ORIENT_VERTICAL , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ;
2013-10-22 14:18:43 +00:00
rightColumnItems - > SetSpacing ( 0.0f ) ;
2013-06-10 20:06:51 +00:00
rightColumn - > Add ( rightColumnItems ) ;
2013-06-27 14:28:11 +00:00
2013-08-19 22:49:25 +00:00
char versionString [ 256 ] ;
2023-04-28 19:04:05 +00:00
snprintf ( versionString , sizeof ( versionString ) , " %s " , PPSSPP_GIT_VERSION ) ;
2013-08-19 22:49:25 +00:00
rightColumnItems - > SetSpacing ( 0.0f ) ;
2021-01-08 19:29:09 +00:00
AnchorLayout * logos = new AnchorLayout ( new AnchorLayoutParams ( FILL_PARENT , 60.0f , false ) ) ;
2017-04-30 00:35:12 +00:00
if ( System_GetPropertyBool ( SYSPROP_APP_GOLD ) ) {
2021-02-22 00:38:02 +00:00
logos - > Add ( new ImageView ( ImageID ( " I_ICONGOLD " ) , " " , IS_DEFAULT , new AnchorLayoutParams ( 64 , 64 , 0 , 0 , NONE , NONE , false ) ) ) ;
2017-04-05 14:21:08 +00:00
} else {
2021-02-22 00:38:02 +00:00
logos - > Add ( new ImageView ( ImageID ( " I_ICON " ) , " " , IS_DEFAULT , new AnchorLayoutParams ( 64 , 64 , 0 , 0 , NONE , NONE , false ) ) ) ;
2017-04-05 14:21:08 +00:00
}
2021-02-22 00:38:02 +00:00
logos - > Add ( new ImageView ( ImageID ( " I_LOGO " ) , " PPSSPP " , IS_DEFAULT , new AnchorLayoutParams ( 180 , 64 , 64 , - 5.0f , NONE , NONE , false ) ) ) ;
2020-03-30 20:45:29 +00:00
2021-01-08 21:25:33 +00:00
# if !defined(MOBILE_DEVICE)
2023-04-05 22:34:50 +00:00
auto gr = GetI18NCategory ( I18NCat : : GRAPHICS ) ;
2023-01-11 22:23:08 +00:00
ImageID icon ( g_Config . UseFullScreen ( ) ? " I_RESTORE " : " I_FULLSCREEN " ) ;
fullscreenButton_ = logos - > Add ( new Button ( gr - > T ( " FullScreen " , " Full Screen " ) , icon , new AnchorLayoutParams ( 48 , 48 , NONE , 0 , 0 , NONE , false ) ) ) ;
fullscreenButton_ - > SetIgnoreText ( true ) ;
fullscreenButton_ - > OnClick . Handle ( this , & MainScreen : : OnFullScreenToggle ) ;
2020-03-30 20:45:29 +00:00
# endif
2013-08-19 22:49:25 +00:00
rightColumnItems - > Add ( logos ) ;
2022-12-03 18:07:38 +00:00
TextView * ver = rightColumnItems - > Add ( new TextView ( versionString , new LinearLayoutParams ( Margins ( 70 , - 10 , 0 , 4 ) ) ) ) ;
2015-09-23 15:34:16 +00:00
ver - > SetSmall ( true ) ;
ver - > SetClip ( false ) ;
2020-07-16 13:49:18 +00:00
2023-01-11 22:23:08 +00:00
LinearLayout * rightColumnChoices = rightColumnItems ;
if ( vertical ) {
ScrollView * rightColumnScroll = new ScrollView ( ORIENT_HORIZONTAL ) ;
rightColumnChoices = new LinearLayout ( ORIENT_HORIZONTAL ) ;
rightColumnScroll - > Add ( rightColumnChoices ) ;
rightColumnItems - > Add ( rightColumnScroll ) ;
}
2020-07-16 13:49:18 +00:00
if ( System_GetPropertyBool ( SYSPROP_HAS_FILE_BROWSER ) ) {
2023-01-11 22:23:08 +00:00
rightColumnChoices - > Add ( new Choice ( mm - > T ( " Load " , " Load... " ) ) ) - > OnClick . Handle ( this , & MainScreen : : OnLoadFile ) ;
2020-07-16 13:49:18 +00:00
}
2023-01-11 22:23:08 +00:00
rightColumnChoices - > Add ( new Choice ( mm - > T ( " Game Settings " , " Settings " ) ) ) - > OnClick . Handle ( this , & MainScreen : : OnGameSettings ) ;
rightColumnChoices - > Add ( new Choice ( mm - > T ( " Credits " ) ) ) - > OnClick . Handle ( this , & MainScreen : : OnCredits ) ;
if ( ! vertical ) {
rightColumnChoices - > Add ( new Choice ( mm - > T ( " www.ppsspp.org " ) ) ) - > OnClick . Handle ( this , & MainScreen : : OnPPSSPPOrg ) ;
2024-05-02 15:15:23 +00:00
# if !PPSSPP_PLATFORM(IOS_APP_STORE)
2023-01-11 22:23:08 +00:00
if ( ! System_GetPropertyBool ( SYSPROP_APP_GOLD ) & & ( System_GetPropertyInt ( SYSPROP_DEVICE_TYPE ) ! = DEVICE_TYPE_VR ) ) {
Choice * gold = rightColumnChoices - > Add ( new Choice ( mm - > T ( " Buy PPSSPP Gold " ) ) ) ;
gold - > OnClick . Handle ( this , & MainScreen : : OnSupport ) ;
gold - > SetIcon ( ImageID ( " I_ICONGOLD " ) , 0.5f ) ;
}
2024-05-02 15:15:23 +00:00
# endif
2017-04-05 14:21:08 +00:00
}
2017-02-27 10:32:40 +00:00
2023-01-11 22:23:08 +00:00
rightColumnChoices - > Add ( new Spacer ( 25.0 ) ) ;
2024-05-03 07:37:35 +00:00
# if !PPSSPP_PLATFORM(IOS_APP_STORE)
// Officially, iOS apps should not have exit buttons. Remove it to maximize app store review chances.
2023-01-11 22:23:08 +00:00
rightColumnChoices - > Add ( new Choice ( mm - > T ( " Exit " ) ) ) - > OnClick . Handle ( this , & MainScreen : : OnExit ) ;
2024-05-03 07:37:35 +00:00
# endif
2013-11-26 13:04:29 +00:00
2013-10-09 14:26:15 +00:00
if ( vertical ) {
root_ = new LinearLayout ( ORIENT_VERTICAL ) ;
2023-01-11 22:23:08 +00:00
rightColumn - > ReplaceLayoutParams ( new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ;
leftColumn - > ReplaceLayoutParams ( new LinearLayoutParams ( 1.0f ) ) ;
2013-11-29 15:46:47 +00:00
root_ - > Add ( rightColumn ) ;
2013-10-09 14:26:15 +00:00
root_ - > Add ( leftColumn ) ;
} else {
2023-12-20 09:35:02 +00:00
Margins actionMenuMargins ( 0 , 10 , 10 , 0 ) ;
2013-10-09 14:26:15 +00:00
root_ = new LinearLayout ( ORIENT_HORIZONTAL ) ;
rightColumn - > ReplaceLayoutParams ( new LinearLayoutParams ( 300 , FILL_PARENT , actionMenuMargins ) ) ;
2013-11-24 08:08:05 +00:00
root_ - > Add ( leftColumn ) ;
2013-10-09 14:26:15 +00:00
root_ - > Add ( rightColumn ) ;
}
2013-11-26 13:04:29 +00:00
2018-06-02 23:32:55 +00:00
if ( focusButton ) {
root_ - > SetDefaultFocusView ( focusButton ) ;
2017-12-30 01:55:37 +00:00
} else if ( tabHolder_ - > GetVisibility ( ) ! = V_GONE ) {
root_ - > SetDefaultFocusView ( tabHolder_ ) ;
}
2014-03-03 11:56:01 +00:00
2023-07-06 14:34:54 +00:00
root_ - > SetTag ( " mainroot " ) ;
2013-11-26 13:04:29 +00:00
upgradeBar_ = 0 ;
if ( ! g_Config . upgradeMessage . empty ( ) ) {
2023-12-20 09:35:02 +00:00
auto u = GetI18NCategory ( I18NCat : : UPGRADE ) ;
2013-11-26 13:04:29 +00:00
upgradeBar_ = new LinearLayout ( ORIENT_HORIZONTAL , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ;
UI : : Margins textMargins ( 10 , 5 ) ;
UI : : Margins buttonMargins ( 0 , 0 ) ;
UI : : Drawable solid ( 0xFFbd9939 ) ;
upgradeBar_ - > SetBG ( solid ) ;
2024-01-19 12:44:49 +00:00
upgradeBar_ - > Add ( new TextView ( std : : string ( u - > T ( " New version of PPSSPP available " ) ) + std : : string ( " : " ) + g_Config . upgradeVersion , new LinearLayoutParams ( 1.0f , textMargins ) ) ) ;
2021-01-03 19:07:59 +00:00
# if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(WINDOWS)
2013-11-26 13:04:29 +00:00
upgradeBar_ - > Add ( new Button ( u - > T ( " Download " ) , new LinearLayoutParams ( buttonMargins ) ) ) - > OnClick . Handle ( this , & MainScreen : : OnDownloadUpgrade ) ;
2021-01-03 19:07:59 +00:00
# else
upgradeBar_ - > Add ( new Button ( u - > T ( " Details " ) , new LinearLayoutParams ( buttonMargins ) ) ) - > OnClick . Handle ( this , & MainScreen : : OnDownloadUpgrade ) ;
# endif
2013-11-26 13:04:29 +00:00
upgradeBar_ - > Add ( new Button ( u - > T ( " Dismiss " ) , new LinearLayoutParams ( buttonMargins ) ) ) - > OnClick . Handle ( this , & MainScreen : : OnDismissUpgrade ) ;
// Slip in under root_
LinearLayout * newRoot = new LinearLayout ( ORIENT_VERTICAL ) ;
newRoot - > Add ( root_ ) ;
newRoot - > Add ( upgradeBar_ ) ;
root_ - > ReplaceLayoutParams ( new LinearLayoutParams ( 1.0 ) ) ;
root_ = newRoot ;
}
}
2023-04-29 18:45:30 +00:00
bool MainScreen : : key ( const KeyInput & touch ) {
if ( touch . flags & KEY_DOWN ) {
if ( touch . keyCode = = NKCODE_CTRL_LEFT | | touch . keyCode = = NKCODE_CTRL_RIGHT )
searchKeyModifier_ = true ;
2023-06-22 07:06:19 +00:00
if ( touch . keyCode = = NKCODE_F & & searchKeyModifier_ & & System_GetPropertyBool ( SYSPROP_HAS_TEXT_INPUT_DIALOG ) ) {
2023-04-29 18:45:30 +00:00
auto se = GetI18NCategory ( I18NCat : : SEARCH ) ;
2024-01-18 10:55:39 +00:00
System_InputBoxGetString ( GetRequesterToken ( ) , se - > T ( " Search term " ) , searchFilter_ , [ & ] ( const std : : string & value , int ) {
2023-04-29 18:45:30 +00:00
searchFilter_ = StripSpaces ( value ) ;
searchChanged_ = true ;
} ) ;
}
} else if ( touch . flags & KEY_UP ) {
if ( touch . keyCode = = NKCODE_CTRL_LEFT | | touch . keyCode = = NKCODE_CTRL_RIGHT )
searchKeyModifier_ = false ;
}
return UIScreenWithBackground : : key ( touch ) ;
}
2015-12-17 21:41:50 +00:00
UI : : EventReturn MainScreen : : OnAllowStorage ( UI : : EventParams & e ) {
System_AskForPermission ( SYSTEM_PERMISSION_STORAGE ) ;
return UI : : EVENT_DONE ;
}
2013-11-26 13:04:29 +00:00
UI : : EventReturn MainScreen : : OnDownloadUpgrade ( UI : : EventParams & e ) {
2017-04-05 14:21:08 +00:00
# if PPSSPP_PLATFORM(ANDROID)
2013-11-26 13:04:29 +00:00
// Go to app store
2017-04-30 00:35:12 +00:00
if ( System_GetPropertyBool ( SYSPROP_APP_GOLD ) ) {
2023-03-21 09:42:23 +00:00
System_LaunchUrl ( LaunchUrlType : : BROWSER_URL , " market://details?id=org.ppsspp.ppssppgold " ) ;
2017-04-05 14:21:08 +00:00
} else {
2023-03-21 09:42:23 +00:00
System_LaunchUrl ( LaunchUrlType : : BROWSER_URL , " market://details?id=org.ppsspp.ppsspp " ) ;
2017-04-05 14:21:08 +00:00
}
2021-01-03 19:07:59 +00:00
# elif PPSSPP_PLATFORM(WINDOWS)
2023-03-21 09:42:23 +00:00
System_LaunchUrl ( LaunchUrlType : : BROWSER_URL , " https://www.ppsspp.org/download " ) ;
2013-11-26 13:04:29 +00:00
# else
// Go directly to ppsspp.org and let the user sort it out
2021-01-03 19:07:59 +00:00
// (for details and in case downloads doesn't have their platform.)
2023-03-21 09:42:23 +00:00
System_LaunchUrl ( LaunchUrlType : : BROWSER_URL , " https://www.ppsspp.org/ " ) ;
2013-11-26 13:04:29 +00:00
# endif
2014-12-22 09:48:17 +00:00
return UI : : EVENT_DONE ;
2013-11-26 13:04:29 +00:00
}
UI : : EventReturn MainScreen : : OnDismissUpgrade ( UI : : EventParams & e ) {
g_Config . DismissUpgrade ( ) ;
2014-12-22 09:48:17 +00:00
upgradeBar_ - > SetVisibility ( UI : : V_GONE ) ;
return UI : : EVENT_DONE ;
2013-06-10 20:06:51 +00:00
}
2023-09-30 09:21:22 +00:00
void MainScreen : : sendMessage ( UIMessage message , const char * value ) {
2013-10-21 20:52:44 +00:00
// Always call the base class method first to handle the most common messages.
UIScreenWithBackground : : sendMessage ( message , value ) ;
2023-09-30 09:21:22 +00:00
if ( message = = UIMessage : : REQUEST_GAME_BOOT ) {
if ( screenManager ( ) - > topScreen ( ) = = this ) {
2021-05-05 23:31:38 +00:00
LaunchFile ( screenManager ( ) , Path ( std : : string ( value ) ) ) ;
2019-02-17 15:48:32 +00:00
}
2023-09-30 09:21:22 +00:00
} else if ( message = = UIMessage : : PERMISSION_GRANTED & & ! strcmp ( value , " storage " ) ) {
2015-12-17 21:41:50 +00:00
RecreateViews ( ) ;
}
2013-07-08 10:35:08 +00:00
}
2017-03-15 05:01:18 +00:00
void MainScreen : : update ( ) {
UIScreen : : update ( ) ;
2013-09-15 16:35:58 +00:00
UpdateUIState ( UISTATE_MENU ) ;
2023-04-29 18:45:30 +00:00
if ( searchChanged_ ) {
for ( auto browser : gameBrowsers_ )
browser - > ApplySearchFilter ( searchFilter_ ) ;
searchChanged_ = false ;
}
2013-06-10 20:06:51 +00:00
}
2013-06-27 14:28:11 +00:00
UI : : EventReturn MainScreen : : OnLoadFile ( UI : : EventParams & e ) {
2017-04-30 00:35:12 +00:00
if ( System_GetPropertyBool ( SYSPROP_HAS_FILE_BROWSER ) ) {
2023-04-05 22:34:50 +00:00
auto mm = GetI18NCategory ( I18NCat : : MAINMENU ) ;
2024-01-18 10:55:39 +00:00
System_BrowseForFile ( GetRequesterToken ( ) , mm - > T ( " Load " ) , BrowseFileType : : BOOTABLE , [ ] ( const std : : string & value , int ) {
2023-09-30 09:21:22 +00:00
System_PostUIMessage ( UIMessage : : REQUEST_GAME_BOOT , value ) ;
2023-03-22 14:21:03 +00:00
} ) ;
2017-04-02 17:50:09 +00:00
}
2013-06-27 14:28:11 +00:00
return UI : : EVENT_DONE ;
}
2021-01-08 19:05:43 +00:00
UI : : EventReturn MainScreen : : OnFullScreenToggle ( UI : : EventParams & e ) {
2022-05-28 22:47:12 +00:00
if ( g_Config . iForceFullScreen ! = - 1 )
g_Config . bFullScreen = g_Config . UseFullScreen ( ) ;
2021-01-08 19:05:43 +00:00
if ( fullscreenButton_ ) {
2022-05-28 22:47:12 +00:00
fullscreenButton_ - > SetImageID ( ImageID ( ! g_Config . UseFullScreen ( ) ? " I_RESTORE " : " I_FULLSCREEN " ) ) ;
2021-01-08 19:05:43 +00:00
}
2021-01-08 21:25:33 +00:00
# if !defined(MOBILE_DEVICE)
g_Config . bFullScreen = ! g_Config . bFullScreen ;
2023-03-22 21:17:53 +00:00
System_ToggleFullscreenState ( " " ) ;
2021-01-08 19:05:43 +00:00
# endif
return UI : : EVENT_DONE ;
}
2014-06-22 01:04:27 +00:00
void MainScreen : : DrawBackground ( UIContext & dc ) {
if ( highlightedGamePath_ . empty ( ) & & prevHighlightedGamePath_ . empty ( ) ) {
return ;
}
if ( DrawBackgroundFor ( dc , prevHighlightedGamePath_ , 1.0f - prevHighlightProgress_ ) ) {
if ( prevHighlightProgress_ < 1.0f ) {
prevHighlightProgress_ + = 1.0f / 20.0f ;
}
}
if ( ! highlightedGamePath_ . empty ( ) ) {
if ( DrawBackgroundFor ( dc , highlightedGamePath_ , highlightProgress_ ) ) {
if ( highlightProgress_ < 1.0f ) {
highlightProgress_ + = 1.0f / 20.0f ;
}
}
}
}
2021-05-05 23:31:38 +00:00
bool MainScreen : : DrawBackgroundFor ( UIContext & dc , const Path & gamePath , float progress ) {
2014-06-22 01:04:27 +00:00
dc . Flush ( ) ;
2017-05-18 10:52:03 +00:00
std : : shared_ptr < GameInfo > ginfo ;
2014-06-22 01:04:27 +00:00
if ( ! gamePath . empty ( ) ) {
2024-01-28 15:23:27 +00:00
ginfo = g_gameInfoCache - > GetInfo ( dc . GetDrawContext ( ) , gamePath , GameInfoFlags : : BG ) ;
2014-06-22 01:04:27 +00:00
// Loading texture data may bind a texture.
dc . RebindTexture ( ) ;
// Let's not bother if there's no picture.
2024-01-28 15:23:27 +00:00
if ( ! ginfo - > Ready ( GameInfoFlags : : BG ) | | ( ! ginfo - > pic1 . texture & & ! ginfo - > pic0 . texture ) ) {
2014-06-22 01:04:27 +00:00
return false ;
}
} else {
return false ;
}
2021-04-04 17:57:40 +00:00
auto pic = ginfo - > GetBGPic ( ) ;
2023-12-12 21:34:31 +00:00
Draw : : Texture * texture = pic ? pic - > texture : nullptr ;
2014-06-22 01:04:27 +00:00
uint32_t color = whiteAlpha ( ease ( progress ) ) & 0xFFc0c0c0 ;
2018-07-21 20:47:29 +00:00
if ( texture ) {
dc . GetDrawContext ( ) - > BindTexture ( 0 , texture ) ;
dc . Draw ( ) - > DrawTexRect ( dc . GetBounds ( ) , 0 , 0 , 1 , 1 , color ) ;
dc . Flush ( ) ;
dc . RebindTexture ( ) ;
}
2014-06-22 01:04:27 +00:00
return true ;
}
2013-06-10 20:06:51 +00:00
UI : : EventReturn MainScreen : : OnGameSelected ( UI : : EventParams & e ) {
2021-01-05 16:01:05 +00:00
g_Config . Save ( " MainScreen::OnGameSelected " ) ;
2021-05-05 23:31:38 +00:00
Path path ( e . s ) ;
2024-01-28 15:23:27 +00:00
std : : shared_ptr < GameInfo > ginfo = g_gameInfoCache - > GetInfo ( nullptr , path , GameInfoFlags : : FILE_TYPE ) ;
if ( ginfo - > fileType = = IdentifiedFileType : : PSP_SAVEDATA_DIRECTORY ) {
2015-06-12 12:46:34 +00:00
return UI : : EVENT_DONE ;
}
2017-05-18 12:21:13 +00:00
if ( g_GameManager . GetState ( ) = = GameManagerState : : INSTALLING )
return UI : : EVENT_DONE ;
2016-02-08 01:15:19 +00:00
// Restore focus if it was highlighted (e.g. by gamepad.)
restoreFocusGamePath_ = highlightedGamePath_ ;
2020-08-02 17:44:48 +00:00
g_BackgroundAudio . SetGame ( path ) ;
2014-06-22 16:32:57 +00:00
lockBackgroundAudio_ = true ;
2013-09-15 04:08:53 +00:00
screenManager ( ) - > push ( new GameScreen ( path ) ) ;
2013-06-10 20:06:51 +00:00
return UI : : EVENT_DONE ;
}
2014-06-22 01:04:27 +00:00
UI : : EventReturn MainScreen : : OnGameHighlight ( UI : : EventParams & e ) {
2014-12-22 09:48:17 +00:00
using namespace UI ;
2021-05-05 23:31:38 +00:00
Path path ( e . s ) ;
2014-06-22 01:04:27 +00:00
2016-02-08 01:15:19 +00:00
// Don't change when re-highlighting what's already highlighted.
if ( path ! = highlightedGamePath_ | | e . a = = FF_LOSTFOCUS ) {
if ( ! highlightedGamePath_ . empty ( ) ) {
if ( prevHighlightedGamePath_ . empty ( ) | | prevHighlightProgress_ > = 0.75f ) {
prevHighlightedGamePath_ = highlightedGamePath_ ;
prevHighlightProgress_ = 1.0 - highlightProgress_ ;
}
highlightedGamePath_ . clear ( ) ;
}
if ( e . a = = FF_GOTFOCUS ) {
highlightedGamePath_ = path ;
highlightProgress_ = 0.0f ;
2014-06-22 01:04:27 +00:00
}
}
2014-06-22 16:16:10 +00:00
2016-02-13 09:48:11 +00:00
if ( ( ! highlightedGamePath_ . empty ( ) | | e . a = = FF_LOSTFOCUS ) & & ! lockBackgroundAudio_ ) {
2020-08-02 17:44:48 +00:00
g_BackgroundAudio . SetGame ( highlightedGamePath_ ) ;
2016-02-13 09:48:11 +00:00
}
2014-06-22 16:32:57 +00:00
lockBackgroundAudio_ = false ;
2014-06-22 01:04:27 +00:00
return UI : : EVENT_DONE ;
}
2013-08-16 10:52:16 +00:00
UI : : EventReturn MainScreen : : OnGameSelectedInstant ( UI : : EventParams & e ) {
2021-01-05 16:01:05 +00:00
g_Config . Save ( " MainScreen::OnGameSelectedInstant " ) ;
2020-07-28 08:03:55 +00:00
ScreenManager * screen = screenManager ( ) ;
2021-05-05 23:31:38 +00:00
LaunchFile ( screen , Path ( e . s ) ) ;
2013-07-22 20:36:56 +00:00
return UI : : EVENT_DONE ;
}
2013-08-16 10:52:16 +00:00
UI : : EventReturn MainScreen : : OnGameSettings ( UI : : EventParams & e ) {
2021-05-05 23:31:38 +00:00
screenManager ( ) - > push ( new GameSettingsScreen ( Path ( ) , " " ) ) ;
2020-03-01 14:34:35 +00:00
return UI : : EVENT_DONE ;
}
2013-06-10 20:06:51 +00:00
UI : : EventReturn MainScreen : : OnCredits ( UI : : EventParams & e ) {
screenManager ( ) - > push ( new CreditsScreen ( ) ) ;
return UI : : EVENT_DONE ;
}
UI : : EventReturn MainScreen : : OnSupport ( UI : : EventParams & e ) {
2016-10-12 09:13:16 +00:00
# ifdef __ANDROID__
2023-03-21 09:42:23 +00:00
System_LaunchUrl ( LaunchUrlType : : BROWSER_URL , " market://details?id=org.ppsspp.ppssppgold " ) ;
2013-07-15 15:41:24 +00:00
# else
2023-03-21 09:42:23 +00:00
System_LaunchUrl ( LaunchUrlType : : BROWSER_URL , " https://www.ppsspp.org/buygold " ) ;
2013-07-15 15:41:24 +00:00
# endif
2013-06-10 20:06:51 +00:00
return UI : : EVENT_DONE ;
2013-06-27 17:40:45 +00:00
}
2013-06-28 12:29:15 +00:00
2013-08-19 22:49:25 +00:00
UI : : EventReturn MainScreen : : OnPPSSPPOrg ( UI : : EventParams & e ) {
2023-03-21 09:42:23 +00:00
System_LaunchUrl ( LaunchUrlType : : BROWSER_URL , " https://www.ppsspp.org " ) ;
2013-08-19 22:49:25 +00:00
return UI : : EVENT_DONE ;
}
UI : : EventReturn MainScreen : : OnForums ( UI : : EventParams & e ) {
2023-03-21 09:42:23 +00:00
System_LaunchUrl ( LaunchUrlType : : BROWSER_URL , " https://forums.ppsspp.org " ) ;
2013-08-19 22:49:25 +00:00
return UI : : EVENT_DONE ;
}
2013-06-28 12:29:15 +00:00
UI : : EventReturn MainScreen : : OnExit ( UI : : EventParams & e ) {
2020-12-13 09:29:12 +00:00
// Let's make sure the config was saved, since it may not have been.
2021-08-07 08:47:11 +00:00
if ( ! g_Config . Save ( " MainScreen::OnExit " ) ) {
2023-03-22 21:55:53 +00:00
System_Toast ( " Failed to save settings! \n Check permissions, or try to restart the device. " ) ;
2021-08-07 08:47:11 +00:00
}
2014-02-11 10:32:54 +00:00
// Request the framework to exit cleanly.
2023-03-22 21:07:29 +00:00
System_ExitApp ( ) ;
2014-02-11 10:32:54 +00:00
2014-06-22 07:38:46 +00:00
UpdateUIState ( UISTATE_EXIT ) ;
2013-06-28 12:29:15 +00:00
return UI : : EVENT_DONE ;
}
2013-07-21 11:31:46 +00:00
2013-11-20 15:36:58 +00:00
void MainScreen : : dialogFinished ( const Screen * dialog , DialogResult result ) {
2022-09-17 20:29:33 +00:00
std : : string tag = dialog - > tag ( ) ;
if ( tag = = " Store " ) {
2013-11-20 15:36:58 +00:00
backFromStore_ = true ;
RecreateViews ( ) ;
}
2022-09-17 20:29:33 +00:00
if ( tag = = " Game " ) {
2016-02-13 09:48:11 +00:00
if ( ! restoreFocusGamePath_ . empty ( ) & & UI : : IsFocusMovementEnabled ( ) ) {
2016-02-08 01:15:19 +00:00
// Prevent the background from fading, since we just were displaying it.
highlightedGamePath_ = restoreFocusGamePath_ ;
highlightProgress_ = 1.0f ;
// Refocus the game button itself.
int tab = tabHolder_ - > GetCurrentTab ( ) ;
2016-02-13 18:57:05 +00:00
if ( tab > = 0 & & tab < ( int ) gameBrowsers_ . size ( ) ) {
2016-02-08 01:15:19 +00:00
gameBrowsers_ [ tab ] - > FocusGame ( restoreFocusGamePath_ ) ;
}
// Don't get confused next time.
restoreFocusGamePath_ . clear ( ) ;
} else {
// Not refocusing, so we need to stop the audio.
2021-05-05 23:31:38 +00:00
g_BackgroundAudio . SetGame ( Path ( ) ) ;
2016-02-08 01:15:19 +00:00
}
}
2013-11-20 15:36:58 +00:00
}
2013-11-24 03:02:36 +00:00
void UmdReplaceScreen : : CreateViews ( ) {
2014-12-22 09:48:17 +00:00
using namespace UI ;
2013-11-24 04:14:44 +00:00
Margins actionMenuMargins ( 0 , 100 , 15 , 0 ) ;
2023-04-05 22:34:50 +00:00
auto mm = GetI18NCategory ( I18NCat : : MAINMENU ) ;
auto di = GetI18NCategory ( I18NCat : : DIALOG ) ;
2013-11-24 03:02:36 +00:00
2015-12-23 04:43:54 +00:00
TabHolder * leftColumn = new TabHolder ( ORIENT_HORIZONTAL , 64 , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT , 1.0 ) ) ;
2016-01-23 06:38:21 +00:00
leftColumn - > SetTag ( " UmdReplace " ) ;
2013-11-24 03:02:36 +00:00
leftColumn - > SetClip ( true ) ;
2013-11-24 04:14:44 +00:00
ViewGroup * rightColumn = new ScrollView ( ORIENT_VERTICAL , new LinearLayoutParams ( 270 , FILL_PARENT , actionMenuMargins ) ) ;
LinearLayout * rightColumnItems = new LinearLayout ( ORIENT_VERTICAL , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ;
rightColumnItems - > SetSpacing ( 0.0f ) ;
rightColumn - > Add ( rightColumnItems ) ;
2014-06-29 03:44:24 +00:00
if ( g_Config . iMaxRecent > 0 ) {
ScrollView * scrollRecentGames = new ScrollView ( ORIENT_VERTICAL , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ;
2016-01-23 06:52:13 +00:00
scrollRecentGames - > SetTag ( " UmdReplaceRecentGames " ) ;
2024-01-18 10:55:39 +00:00
GameBrowser * tabRecentGames = new GameBrowser ( GetRequesterToken ( ) ,
2021-05-09 17:06:02 +00:00
Path ( " !RECENT " ) , BrowseFlags : : NONE , & g_Config . bGridView1 , screenManager ( ) , " " , " " ,
2014-06-29 03:44:24 +00:00
new LinearLayoutParams ( FILL_PARENT , FILL_PARENT ) ) ;
scrollRecentGames - > Add ( tabRecentGames ) ;
2015-07-01 22:02:08 +00:00
leftColumn - > AddTab ( mm - > T ( " Recent " ) , scrollRecentGames ) ;
2023-08-18 08:21:13 +00:00
tabRecentGames - > OnChoice . Handle ( this , & UmdReplaceScreen : : OnGameSelected ) ;
2014-06-29 03:44:24 +00:00
tabRecentGames - > OnHoldChoice . Handle ( this , & UmdReplaceScreen : : OnGameSelected ) ;
}
2013-11-24 03:02:36 +00:00
ScrollView * scrollAllGames = new ScrollView ( ORIENT_VERTICAL , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT ) ) ;
2016-01-23 06:52:13 +00:00
scrollAllGames - > SetTag ( " UmdReplaceAllGames " ) ;
2013-11-24 03:02:36 +00:00
2024-01-18 10:55:39 +00:00
GameBrowser * tabAllGames = new GameBrowser ( GetRequesterToken ( ) , Path ( g_Config . currentDirectory ) , BrowseFlags : : STANDARD , & g_Config . bGridView2 , screenManager ( ) ,
2019-10-06 19:40:00 +00:00
mm - > T ( " How to get games " ) , " https://www.ppsspp.org/getgames.html " ,
2013-11-24 03:02:36 +00:00
new LinearLayoutParams ( FILL_PARENT , FILL_PARENT ) ) ;
scrollAllGames - > Add ( tabAllGames ) ;
2015-07-01 22:02:08 +00:00
leftColumn - > AddTab ( mm - > T ( " Games " ) , scrollAllGames ) ;
2013-11-24 03:02:36 +00:00
2023-08-18 08:21:13 +00:00
tabAllGames - > OnChoice . Handle ( this , & UmdReplaceScreen : : OnGameSelected ) ;
2014-06-29 03:44:24 +00:00
2013-11-24 03:02:36 +00:00
tabAllGames - > OnHoldChoice . Handle ( this , & UmdReplaceScreen : : OnGameSelected ) ;
2023-09-04 19:41:57 +00:00
if ( System_GetPropertyBool ( SYSPROP_HAS_FILE_BROWSER ) ) {
rightColumnItems - > Add ( new Choice ( mm - > T ( " Load " , " Load... " ) ) ) - > OnClick . Add ( [ & ] ( UI : : EventParams & e ) {
auto mm = GetI18NCategory ( I18NCat : : MAINMENU ) ;
2024-01-18 10:55:39 +00:00
System_BrowseForFile ( GetRequesterToken ( ) , mm - > T ( " Load " ) , BrowseFileType : : BOOTABLE , [ & ] ( const std : : string & value , int ) {
2023-09-04 19:41:57 +00:00
__UmdReplace ( Path ( value ) ) ;
TriggerFinish ( DR_OK ) ;
} ) ;
return EVENT_DONE ;
} ) ;
}
2022-12-11 04:32:12 +00:00
rightColumnItems - > Add ( new Choice ( di - > T ( " Cancel " ) ) ) - > OnClick . Handle < UIScreen > ( this , & UIScreen : : OnCancel ) ;
2023-09-04 19:41:57 +00:00
rightColumnItems - > Add ( new Spacer ( ) ) ;
2015-07-01 22:02:08 +00:00
rightColumnItems - > Add ( new Choice ( mm - > T ( " Game Settings " ) ) ) - > OnClick . Handle ( this , & UmdReplaceScreen : : OnGameSettings ) ;
2013-11-24 04:14:44 +00:00
2022-07-12 03:44:13 +00:00
if ( g_Config . HasRecentIsos ( ) ) {
2017-12-13 05:34:17 +00:00
leftColumn - > SetCurrentTab ( 0 , true ) ;
2014-06-29 03:44:24 +00:00
} else if ( g_Config . iMaxRecent > 0 ) {
2017-12-13 05:34:17 +00:00
leftColumn - > SetCurrentTab ( 1 , true ) ;
2013-11-24 03:02:36 +00:00
}
root_ = new LinearLayout ( ORIENT_HORIZONTAL ) ;
2013-11-29 12:02:08 +00:00
root_ - > Add ( leftColumn ) ;
root_ - > Add ( rightColumn ) ;
2013-11-24 03:02:36 +00:00
}
2017-03-15 05:01:18 +00:00
void UmdReplaceScreen : : update ( ) {
2013-11-24 03:02:36 +00:00
UpdateUIState ( UISTATE_PAUSEMENU ) ;
2017-03-15 05:01:18 +00:00
UIScreen : : update ( ) ;
2013-11-24 03:02:36 +00:00
}
UI : : EventReturn UmdReplaceScreen : : OnGameSelected ( UI : : EventParams & e ) {
2021-05-09 16:38:48 +00:00
__UmdReplace ( Path ( e . s ) ) ;
2017-03-20 00:43:03 +00:00
TriggerFinish ( DR_OK ) ;
2013-11-24 03:02:36 +00:00
return UI : : EVENT_DONE ;
}
2014-12-22 09:48:17 +00:00
UI : : EventReturn UmdReplaceScreen : : OnGameSettings ( UI : : EventParams & e ) {
2021-05-05 23:31:38 +00:00
screenManager ( ) - > push ( new GameSettingsScreen ( Path ( ) ) ) ;
2013-11-24 04:14:44 +00:00
return UI : : EVENT_DONE ;
}
2015-06-12 18:37:42 +00:00
2020-03-01 14:34:35 +00:00
void GridSettingsScreen : : CreatePopupContents ( UI : : ViewGroup * parent ) {
using namespace UI ;
2023-04-05 22:34:50 +00:00
auto di = GetI18NCategory ( I18NCat : : DIALOG ) ;
auto sy = GetI18NCategory ( I18NCat : : SYSTEM ) ;
2020-03-01 14:34:35 +00:00
2021-08-29 21:11:32 +00:00
ScrollView * scroll = new ScrollView ( ORIENT_VERTICAL , new LinearLayoutParams ( FILL_PARENT , WRAP_CONTENT , 1.0f ) ) ;
2021-02-22 02:41:08 +00:00
LinearLayout * items = new LinearLayoutList ( ORIENT_VERTICAL ) ;
2020-03-01 14:34:35 +00:00
items - > Add ( new CheckBox ( & g_Config . bGridView1 , sy - > T ( " Display Recent on a grid " ) ) ) ;
items - > Add ( new CheckBox ( & g_Config . bGridView2 , sy - > T ( " Display Games on a grid " ) ) ) ;
items - > Add ( new CheckBox ( & g_Config . bGridView3 , sy - > T ( " Display Homebrew on a grid " ) ) ) ;
items - > Add ( new ItemHeader ( sy - > T ( " Grid icon size " ) ) ) ;
items - > Add ( new Choice ( sy - > T ( " Increase size " ) ) ) - > OnClick . Handle ( this , & GridSettingsScreen : : GridPlusClick ) ;
items - > Add ( new Choice ( sy - > T ( " Decrease size " ) ) ) - > OnClick . Handle ( this , & GridSettingsScreen : : GridMinusClick ) ;
2020-03-02 07:34:26 +00:00
items - > Add ( new ItemHeader ( sy - > T ( " Display Extra Info " ) ) ) ;
items - > Add ( new CheckBox ( & g_Config . bShowIDOnGameIcon , sy - > T ( " Show ID " ) ) ) ;
items - > Add ( new CheckBox ( & g_Config . bShowRegionOnGameIcon , sy - > T ( " Show region flag " ) ) ) ;
if ( g_Config . iMaxRecent > 0 ) {
items - > Add ( new ItemHeader ( sy - > T ( " Clear Recent " ) ) ) ;
items - > Add ( new Choice ( sy - > T ( " Clear Recent Games List " ) ) ) - > OnClick . Handle ( this , & GridSettingsScreen : : OnRecentClearClick ) ;
}
2020-03-01 14:34:35 +00:00
scroll - > Add ( items ) ;
parent - > Add ( scroll ) ;
}
UI : : EventReturn GridSettingsScreen : : GridPlusClick ( UI : : EventParams & e ) {
g_Config . fGameGridScale = std : : min ( g_Config . fGameGridScale * 1.25f , MAX_GAME_GRID_SCALE ) ;
return UI : : EVENT_DONE ;
}
UI : : EventReturn GridSettingsScreen : : GridMinusClick ( UI : : EventParams & e ) {
g_Config . fGameGridScale = std : : max ( g_Config . fGameGridScale / 1.25f , MIN_GAME_GRID_SCALE ) ;
return UI : : EVENT_DONE ;
}
2020-03-02 07:34:26 +00:00
UI : : EventReturn GridSettingsScreen : : OnRecentClearClick ( UI : : EventParams & e ) {
2022-07-12 03:44:13 +00:00
g_Config . ClearRecentIsos ( ) ;
2020-03-02 07:34:26 +00:00
OnRecentChanged . Trigger ( e ) ;
return UI : : EVENT_DONE ;
}