2023-12-22 11:57:49 +00:00
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
2023-05-25 16:24:01 +00:00
# include "MainWindow.h"
# include "QtHost.h"
# include "QtUtils.h"
# include "SettingWidgetBinder.h"
# include "Settings/GameCheatSettingsWidget.h"
2023-10-14 08:45:09 +00:00
# include "Settings/SettingsWindow.h"
2023-05-25 16:24:01 +00:00
# include "pcsx2/GameList.h"
# include "pcsx2/Patch.h"
# include "common/HeterogeneousContainers.h"
2023-10-14 08:45:09 +00:00
GameCheatSettingsWidget : : GameCheatSettingsWidget ( SettingsWindow * dialog , QWidget * parent )
2023-05-25 16:24:01 +00:00
: m_dialog ( dialog )
{
m_ui . setupUi ( this ) ;
reloadList ( ) ;
SettingsInterface * sif = m_dialog - > getSettingsInterface ( ) ;
SettingWidgetBinder : : BindWidgetToBoolSetting ( sif , m_ui . enableCheats , " EmuCore " , " EnableCheats " , false ) ;
2024-01-01 00:23:27 +00:00
SettingWidgetBinder : : BindWidgetToBoolSetting ( sif , m_ui . allCRCsCheckbox , " EmuCore " , " ShowCheatsForAllCRCs " , false ) ;
2023-05-25 16:24:01 +00:00
updateListEnabled ( ) ;
connect ( m_ui . enableCheats , & QCheckBox : : stateChanged , this , & GameCheatSettingsWidget : : updateListEnabled ) ;
connect ( m_ui . cheatList , & QTreeWidget : : itemDoubleClicked , this , & GameCheatSettingsWidget : : onCheatListItemDoubleClicked ) ;
connect ( m_ui . cheatList , & QTreeWidget : : itemChanged , this , & GameCheatSettingsWidget : : onCheatListItemChanged ) ;
2023-11-17 01:33:24 +00:00
connect ( m_ui . reloadCheats , & QPushButton : : clicked , this , & GameCheatSettingsWidget : : onReloadClicked ) ;
2023-05-25 16:24:01 +00:00
connect ( m_ui . enableAll , & QPushButton : : clicked , this , [ this ] ( ) { setStateForAll ( true ) ; } ) ;
connect ( m_ui . disableAll , & QPushButton : : clicked , this , [ this ] ( ) { setStateForAll ( false ) ; } ) ;
2024-01-01 00:23:27 +00:00
connect ( m_ui . allCRCsCheckbox , & QCheckBox : : stateChanged , this , & GameCheatSettingsWidget : : onReloadClicked ) ;
2024-01-09 23:52:24 +00:00
dialog - > registerWidgetHelp ( m_ui . allCRCsCheckbox , tr ( " Show Cheats For All CRCs " ) , tr ( " Checked " ) ,
tr ( " Toggles scanning patch files for all CRCs of the game. With this enabled available patches for the game serial with different CRCs will also be loaded. " ) ) ;
2023-05-25 16:24:01 +00:00
}
GameCheatSettingsWidget : : ~ GameCheatSettingsWidget ( ) = default ;
void GameCheatSettingsWidget : : onCheatListItemDoubleClicked ( QTreeWidgetItem * item , int column )
{
QVariant data = item - > data ( 0 , Qt : : UserRole ) ;
if ( ! data . isValid ( ) )
return ;
std : : string cheat_name = data . toString ( ) . toStdString ( ) ;
const bool new_state = ! ( item - > checkState ( 0 ) = = Qt : : Checked ) ;
item - > setCheckState ( 0 , new_state ? Qt : : Checked : Qt : : Unchecked ) ;
setCheatEnabled ( std : : move ( cheat_name ) , new_state , true ) ;
}
void GameCheatSettingsWidget : : onCheatListItemChanged ( QTreeWidgetItem * item , int column )
{
QVariant data = item - > data ( 0 , Qt : : UserRole ) ;
if ( ! data . isValid ( ) )
return ;
std : : string cheat_name = data . toString ( ) . toStdString ( ) ;
const bool current_enabled =
( std : : find ( m_enabled_patches . begin ( ) , m_enabled_patches . end ( ) , cheat_name ) ! = m_enabled_patches . end ( ) ) ;
const bool current_checked = ( item - > checkState ( 0 ) = = Qt : : Checked ) ;
if ( current_enabled = = current_checked )
return ;
setCheatEnabled ( std : : move ( cheat_name ) , current_checked , true ) ;
}
void GameCheatSettingsWidget : : onReloadClicked ( )
{
reloadList ( ) ;
// reload it on the emu thread too, so it picks up any changes
g_emu_thread - > reloadPatches ( ) ;
}
void GameCheatSettingsWidget : : updateListEnabled ( )
{
const bool cheats_enabled = m_dialog - > getEffectiveBoolValue ( " EmuCore " , " EnableCheats " , false ) ;
m_ui . cheatList - > setEnabled ( cheats_enabled ) ;
m_ui . enableAll - > setEnabled ( cheats_enabled ) ;
m_ui . disableAll - > setEnabled ( cheats_enabled ) ;
m_ui . reloadCheats - > setEnabled ( cheats_enabled ) ;
2024-01-01 00:23:27 +00:00
m_ui . allCRCsCheckbox - > setEnabled ( cheats_enabled ) ;
2023-05-25 16:24:01 +00:00
}
2024-01-01 02:40:14 +00:00
void GameCheatSettingsWidget : : disableAllCheats ( )
{
SettingsInterface * si = m_dialog - > getSettingsInterface ( ) ;
si - > ClearSection ( Patch : : CHEATS_CONFIG_SECTION ) ;
si - > Save ( ) ;
}
2024-01-07 03:05:09 +00:00
void GameCheatSettingsWidget : : resizeEvent ( QResizeEvent * event )
{
QWidget : : resizeEvent ( event ) ;
QtUtils : : ResizeColumnsForTreeView ( m_ui . cheatList , { 320 , 100 , - 1 } ) ;
}
2023-05-25 16:24:01 +00:00
void GameCheatSettingsWidget : : setCheatEnabled ( std : : string name , bool enabled , bool save_and_reload_settings )
{
SettingsInterface * si = m_dialog - > getSettingsInterface ( ) ;
auto it = std : : find ( m_enabled_patches . begin ( ) , m_enabled_patches . end ( ) , name ) ;
if ( enabled )
{
si - > AddToStringList ( Patch : : CHEATS_CONFIG_SECTION , Patch : : PATCH_ENABLE_CONFIG_KEY , name . c_str ( ) ) ;
if ( it = = m_enabled_patches . end ( ) )
m_enabled_patches . push_back ( std : : move ( name ) ) ;
}
else
{
si - > RemoveFromStringList ( Patch : : CHEATS_CONFIG_SECTION , Patch : : PATCH_ENABLE_CONFIG_KEY , name . c_str ( ) ) ;
if ( it ! = m_enabled_patches . end ( ) )
m_enabled_patches . erase ( it ) ;
}
if ( save_and_reload_settings )
{
si - > Save ( ) ;
g_emu_thread - > reloadGameSettings ( ) ;
}
}
void GameCheatSettingsWidget : : setStateForAll ( bool enabled )
{
QSignalBlocker sb ( m_ui . cheatList ) ;
setStateRecursively ( nullptr , enabled ) ;
m_dialog - > getSettingsInterface ( ) - > Save ( ) ;
g_emu_thread - > reloadGameSettings ( ) ;
}
void GameCheatSettingsWidget : : setStateRecursively ( QTreeWidgetItem * parent , bool enabled )
{
const int count = parent ? parent - > childCount ( ) : m_ui . cheatList - > topLevelItemCount ( ) ;
for ( int i = 0 ; i < count ; i + + )
{
QTreeWidgetItem * item = parent ? parent - > child ( i ) : m_ui . cheatList - > topLevelItem ( i ) ;
QVariant data = item - > data ( 0 , Qt : : UserRole ) ;
if ( data . isValid ( ) )
{
if ( ( item - > checkState ( 0 ) = = Qt : : Checked ) ! = enabled )
{
item - > setCheckState ( 0 , enabled ? Qt : : Checked : Qt : : Unchecked ) ;
setCheatEnabled ( data . toString ( ) . toStdString ( ) , enabled , false ) ;
}
}
else
{
setStateRecursively ( item , enabled ) ;
}
}
}
void GameCheatSettingsWidget : : reloadList ( )
{
u32 num_unlabelled_codes = 0 ;
2024-01-01 00:23:27 +00:00
bool showAllCRCS = m_ui . allCRCsCheckbox - > isChecked ( ) ;
m_patches = Patch : : GetPatchInfo ( m_dialog - > getSerial ( ) , m_dialog - > getDiscCRC ( ) , true , showAllCRCS , & num_unlabelled_codes ) ;
2023-05-25 16:24:01 +00:00
m_enabled_patches =
m_dialog - > getSettingsInterface ( ) - > GetStringList ( Patch : : CHEATS_CONFIG_SECTION , Patch : : PATCH_ENABLE_CONFIG_KEY ) ;
m_parent_map . clear ( ) ;
while ( m_ui . cheatList - > topLevelItemCount ( ) > 0 )
delete m_ui . cheatList - > takeTopLevelItem ( 0 ) ;
for ( const Patch : : PatchInfo & pi : m_patches )
{
const bool enabled =
( std : : find ( m_enabled_patches . begin ( ) , m_enabled_patches . end ( ) , pi . name ) ! = m_enabled_patches . end ( ) ) ;
const std : : string_view parent_part = pi . GetNameParentPart ( ) ;
QTreeWidgetItem * parent = getTreeWidgetParent ( parent_part ) ;
QTreeWidgetItem * item = new QTreeWidgetItem ( ) ;
populateTreeWidgetItem ( item , pi , enabled ) ;
if ( parent )
parent - > addChild ( item ) ;
else
m_ui . cheatList - > addTopLevelItem ( item ) ;
}
// Hide root indicator when there's no groups, frees up some whitespace.
m_ui . cheatList - > setRootIsDecorated ( ! m_parent_map . empty ( ) ) ;
if ( num_unlabelled_codes > 0 )
{
QTreeWidgetItem * item = new QTreeWidgetItem ( ) ;
item - > setText ( 0 , tr ( " %1 unlabelled patch codes will automatically activate. " ) . arg ( num_unlabelled_codes ) ) ;
m_ui . cheatList - > addTopLevelItem ( item ) ;
}
}
QTreeWidgetItem * GameCheatSettingsWidget : : getTreeWidgetParent ( const std : : string_view & parent )
{
if ( parent . empty ( ) )
return nullptr ;
2023-07-22 03:15:26 +00:00
auto it = m_parent_map . find ( parent ) ;
2023-05-25 16:24:01 +00:00
if ( it ! = m_parent_map . end ( ) )
return it - > second ;
std : : string_view this_part = parent ;
QTreeWidgetItem * parent_to_this = nullptr ;
const std : : string_view : : size_type pos = parent . rfind ( ' \\ ' ) ;
if ( pos ! = std : : string : : npos & & pos ! = ( parent . size ( ) - 1 ) )
{
// go up the chain until we find the real parent, then back down
parent_to_this = getTreeWidgetParent ( parent . substr ( 0 , pos ) ) ;
this_part = parent . substr ( pos + 1 ) ;
}
QTreeWidgetItem * item = new QTreeWidgetItem ( ) ;
item - > setText ( 0 , QString : : fromUtf8 ( this_part . data ( ) , this_part . length ( ) ) ) ;
if ( parent_to_this )
parent_to_this - > addChild ( item ) ;
else
m_ui . cheatList - > addTopLevelItem ( item ) ;
// Must be called after adding.
item - > setExpanded ( true ) ;
m_parent_map . emplace ( parent , item ) ;
return item ;
}
void GameCheatSettingsWidget : : populateTreeWidgetItem ( QTreeWidgetItem * item , const Patch : : PatchInfo & pi , bool enabled )
{
const std : : string_view name_part = pi . GetNamePart ( ) ;
item - > setFlags ( item - > flags ( ) | Qt : : ItemIsUserCheckable | Qt : : ItemNeverHasChildren ) ;
item - > setCheckState ( 0 , enabled ? Qt : : Checked : Qt : : Unchecked ) ;
item - > setData ( 0 , Qt : : UserRole , QString : : fromStdString ( pi . name ) ) ;
if ( ! name_part . empty ( ) )
item - > setText ( 0 , QString : : fromUtf8 ( name_part . data ( ) , name_part . length ( ) ) ) ;
item - > setText ( 1 , QString : : fromStdString ( pi . author ) ) ;
item - > setText ( 2 , QString : : fromStdString ( pi . description ) ) ;
}