Major Savestate fix: Added version info, which never got added (oops) after I redid the savestate system for 0.9.7. Breaks all old savestates, but should be the last backward compat breakage for quite a while.

Also
 * Tons of small UI bugfixes and cosmetic improvements, mostly to startup, first-time running, and resetting options.
 * Added a third startup option for specifying a custom "default location" for PCSX2 files, in addition to user docs and CWD.

Devs:
 * Implemented some more += operators for adding wxWidgets objects to sizers (pxStretchSpacer mainly).
 * Preliminary re-implementation of memory cards panels -- still non-functional, so it's disabled.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2671 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2010-03-05 14:24:44 +00:00
parent 0548ed0c5a
commit 08f3e4955b
44 changed files with 1494 additions and 759 deletions

View File

@ -121,7 +121,7 @@ public:
wxRadioButton* GetButton( int idx );
const wxRadioButton* GetButton( int idx ) const;
int GetPaddingHoriz() const { return m_padding.GetHeight(); }
int GetPaddingVert() const { return m_padding.GetHeight(); }
int GetIndentation() const { return m_Indentation; }
pxRadioPanel& SetPaddingHoriz( int newpad )

View File

@ -27,6 +27,7 @@ class pxMessageBoxEvent;
BEGIN_DECLARE_EVENT_TYPES()
DECLARE_EVENT_TYPE( pxEvt_Ping, -1 )
DECLARE_EVENT_TYPE( pxEvt_IdleEventQueue, -1 )
DECLARE_EVENT_TYPE( pxEvt_MessageBox, -1 )
DECLARE_EVENT_TYPE( pxEvt_DeleteObject, -1 )
//DECLARE_EVENT_TYPE( pxEvt_Assertion, -1 )
@ -295,8 +296,10 @@ class wxAppWithHelpers : public wxApp
protected:
std::vector<Semaphore*> m_PingWhenIdle;
std::vector<IDeletableObject*> m_DeleteWhenIdle;
std::vector<wxEvent*> m_IdleEventQueue;
Threading::Mutex m_DeleteIdleLock;
wxTimer m_PingTimer;
wxTimer m_IdleEventTimer;
public:
wxAppWithHelpers();
@ -320,12 +323,15 @@ public:
//int OnExit();
protected:
void IdleEventDispatcher( const char* action );
void PingDispatcher( const char* action );
void DeletionDispatcher();
void OnIdleEvent( wxIdleEvent& evt );
void OnPingEvent( pxPingEvent& evt );
void OnAddEventToIdleQueue( wxEvent& evt );
void OnPingTimeout( wxTimerEvent& evt );
void OnIdleEventTimeout( wxTimerEvent& evt );
void OnMessageBox( BaseMessageBoxEvent& evt );
void OnDeleteObject( wxCommandEvent& evt );
};

View File

@ -110,51 +110,24 @@ struct pxStretchType
}
};
class pxProportion
static __forceinline wxSizerFlags pxProportion( int prop )
{
return wxSizerFlags( prop );
}
static __forceinline wxSizerFlags pxBorder( int dir, int pad )
{
return wxSizerFlags().Border( dir, pad );
}
class pxStretchSpacer
{
public:
int intval;
pxProportion( int prop )
int proportion;
pxStretchSpacer( int prop=0 )
{
intval = prop;
}
wxSizerFlags Apply( wxSizerFlags flags=wxSizerFlags() ) const;
wxSizerFlags operator& ( const wxSizerFlags& _flgs ) const
{
return Apply( _flgs );
}
operator wxSizerFlags() const
{
return Apply();
}
};
class pxBorder
{
public:
int direction;
int padding;
pxBorder( int dir, int pad )
{
direction = dir;
padding = pad;
}
wxSizerFlags Apply( wxSizerFlags flags=wxSizerFlags() ) const;
wxSizerFlags operator& ( const wxSizerFlags& _flgs ) const
{
return Apply( _flgs );
}
operator wxSizerFlags() const
{
return Apply();
proportion = prop;
}
};
@ -235,6 +208,8 @@ extern void operator+=( wxSizer* target, wxSizer& src );
extern void operator+=( wxSizer& target, int spacer );
extern void operator+=( wxWindow& target, int spacer );
extern void operator+=( wxSizer& target, const pxStretchSpacer& spacer );
extern void operator+=( wxWindow& target, const pxStretchSpacer& spacer );
// ----------------------------------------------------------------------------
// Important: This template is needed in order to retain window type information and

View File

@ -489,7 +489,7 @@ void Threading::PersistentThread::_try_virtual_invoke( void (PersistentThread::*
{
m_except = new Exception::RuntimeError(
// Diagnostic message:
wxsFormat( L"(thread: %s) STL Runtime Error: %s\n\t%s",
wxsFormat( L"(thread: %s) STL Runtime Error: %s",
GetName().c_str(), fromUTF8( ex.what() ).c_str()
),
@ -513,13 +513,13 @@ void Threading::PersistentThread::_try_virtual_invoke( void (PersistentThread::*
// the MSVC debugger (or by silent random annoying fail on debug-less linux).
/*catch( std::logic_error& ex )
{
throw Exception::BaseException( wxsFormat( L"(thread: %s) STL Logic Error: %s\n\t%s",
throw Exception::BaseException( wxsFormat( L"(thread: %s) STL Logic Error: %s",
GetName().c_str(), fromUTF8( ex.what() ).c_str() )
);
}
catch( std::exception& ex )
{
throw Exception::BaseException( wxsFormat( L"(thread: %s) STL exception: %s\n\t%s",
throw Exception::BaseException( wxsFormat( L"(thread: %s) STL exception: %s",
GetName().c_str(), fromUTF8( ex.what() ).c_str() )
);
}*/

View File

@ -58,8 +58,6 @@ void pxRadioPanel::Reset()
void pxRadioPanel::Realize()
{
//if( )
const int numbuttons = m_buttonStrings.size();
if( numbuttons == 0 ) return;
if( m_IsRealized ) return;
@ -88,15 +86,15 @@ void pxRadioPanel::Realize()
}
pxAssert( GetSizer() != NULL );
wxSizer& sizer( *GetSizer() );
for( int i=0; i<numbuttons; ++i )
{
sizer.Add( m_objects[i].LabelObj, pxSizerFlags::StdExpand() );
*this += m_objects[i].LabelObj | pxSizerFlags::StdExpand();
if( wxStaticText* subobj = m_objects[i].SubTextObj )
{
sizer.Add( subobj, wxSizerFlags().Border( wxLEFT, m_Indentation ) );
sizer.AddSpacer( 9 + m_padding.GetHeight() );
*this += subobj | pxBorder( wxLEFT, m_Indentation );
*this += 9 + m_padding.GetHeight();
}
if( !m_buttonStrings[i].ToolTip.IsEmpty() )
_setToolTipImmediate( i, m_buttonStrings[i].ToolTip );

View File

@ -17,6 +17,7 @@
#include "wxAppWithHelpers.h"
DEFINE_EVENT_TYPE( pxEvt_Ping );
DEFINE_EVENT_TYPE( pxEvt_IdleEventQueue );
DEFINE_EVENT_TYPE( pxEvt_MessageBox );
DEFINE_EVENT_TYPE( pxEvt_DeleteObject );
//DEFINE_EVENT_TYPE( pxEvt_Assertion );
@ -56,22 +57,48 @@ pxPingEvent::pxPingEvent( const pxPingEvent& src )
// --------------------------------------------------------------------------------------
// wxAppWithHelpers Implementation
// --------------------------------------------------------------------------------------
//
// TODO : Ping dispatch and IdleEvent dispatch can be unified into a single dispatch, which
// would mean checking only one list of events per idle event, instead of two. (ie, ping
// events can be appended to the idle event list, instead of into their own custom list).
//
IMPLEMENT_DYNAMIC_CLASS( wxAppWithHelpers, wxApp )
void wxAppWithHelpers::CleanUp()
{
DeletionDispatcher();
_parent::CleanUp();
}
void wxAppWithHelpers::OnPingEvent( pxPingEvent& evt )
{
// Ping events are dispatched during the idle event handler, which ensures
// the ping is posted only after all other pending messages behind the ping
// are also processed.
if( m_PingWhenIdle.size() == 0 ) m_PingTimer.Start( 200, true );
m_PingWhenIdle.push_back( evt.GetSemaphore() );
m_PingTimer.Start( 200, true );
}
void wxAppWithHelpers::CleanUp()
void wxAppWithHelpers::OnAddEventToIdleQueue( wxEvent& evt )
{
DeletionDispatcher();
_parent::CleanUp();
if( m_IdleEventQueue.size() == 0 ) m_IdleEventTimer.Start( 100, true );
m_IdleEventQueue.push_back( evt.Clone() );
}
void wxAppWithHelpers::IdleEventDispatcher( const char* action )
{
size_t size = m_IdleEventQueue.size();
if( size == 0 ) return;
DbgCon.WriteLn( Color_Gray, "App IdleQueue (%s) -> %u events.", action, size );
for( size_t i=0; i<size; ++i )
{
ProcessEvent( *m_IdleEventQueue[i] );
}
m_IdleEventQueue.clear();
}
void wxAppWithHelpers::PingDispatcher( const char* action )
@ -102,7 +129,9 @@ void wxAppWithHelpers::DeletionDispatcher()
void wxAppWithHelpers::OnIdleEvent( wxIdleEvent& evt )
{
m_PingTimer.Stop();
m_IdleEventTimer.Stop();
PingDispatcher( "Idle" );
IdleEventDispatcher( "Idle" );
}
void wxAppWithHelpers::OnPingTimeout( wxTimerEvent& evt )
@ -110,6 +139,11 @@ void wxAppWithHelpers::OnPingTimeout( wxTimerEvent& evt )
PingDispatcher( "Timeout" );
}
void wxAppWithHelpers::OnIdleEventTimeout( wxTimerEvent& evt )
{
IdleEventDispatcher( "Timeout" );
}
void wxAppWithHelpers::Ping()
{
DbgCon.WriteLn( Color_Gray, L"App Event Ping Requested from %s thread.", pxGetCurrentThreadName().c_str() );
@ -157,10 +191,12 @@ bool wxAppWithHelpers::OnInit()
Connect( pxEvt_MessageBox, pxMessageBoxEventThing (wxAppWithHelpers::OnMessageBox) );
//Connect( pxEvt_Assertion, pxMessageBoxEventThing (wxAppWithHelpers::OnMessageBox) );
Connect( pxEvt_Ping, pxPingEventHandler (wxAppWithHelpers::OnPingEvent) );
Connect( pxEvt_IdleEventQueue, wxEventHandler (wxAppWithHelpers::OnAddEventToIdleQueue) );
Connect( pxEvt_DeleteObject, wxCommandEventHandler (wxAppWithHelpers::OnDeleteObject) );
Connect( wxEVT_IDLE, wxIdleEventHandler (wxAppWithHelpers::OnIdleEvent) );
Connect( m_PingTimer.GetId(), wxEVT_TIMER, wxTimerEventHandler(wxAppWithHelpers::OnPingTimeout) );
Connect( m_PingTimer.GetId(), wxEVT_TIMER, wxTimerEventHandler(wxAppWithHelpers::OnPingTimeout) );
Connect( m_IdleEventTimer.GetId(), wxEVT_TIMER, wxTimerEventHandler(wxAppWithHelpers::OnIdleEventTimeout) );
return _parent::OnInit();
}
@ -178,6 +214,7 @@ void wxAppWithHelpers::OnDeleteObject( wxCommandEvent& evt )
wxAppWithHelpers::wxAppWithHelpers()
: m_PingTimer( this )
, m_IdleEventTimer( this )
{
#ifdef __WXMSW__
// This variable assignment ensures that MSVC links in the TLS setup stubs even in

View File

@ -99,16 +99,6 @@ wxSizerFlags pxStretchType::Apply( wxSizerFlags flags ) const
return flags;
}
wxSizerFlags pxProportion::Apply( wxSizerFlags flags ) const
{
return flags.Proportion( intval );
}
wxSizerFlags pxBorder::Apply( wxSizerFlags flags ) const
{
return flags.Border( direction, padding );
}
wxSizerFlags operator& ( const wxSizerFlags& _flgs, const wxSizerFlags& _flgs2 )
{
//return align.Apply( _flgs );
@ -125,6 +115,9 @@ wxSizerFlags operator& ( const wxSizerFlags& _flgs, const wxSizerFlags& _flgs2 )
// Compounding borders is probably a fair approach:
retval.Border( allflags & wxALL, _flgs.GetBorderInPixels() + _flgs2.GetBorderInPixels() );
// Compounding proportions works as well, I figure.
retval.Proportion( _flgs.GetProportion() + _flgs2.GetProportion() );
return retval;
}
@ -155,6 +148,24 @@ void operator+=( wxSizer& target, int spacer )
{
target.AddSpacer( spacer );
}
void operator+=( wxSizer& target, const pxStretchSpacer& spacer )
{
target.AddStretchSpacer( spacer.proportion );
}
void operator+=( wxWindow& target, int spacer )
{
if( !pxAssert( target.GetSizer() != NULL ) ) return;
target.GetSizer()->AddSpacer( spacer );
}
void operator+=( wxWindow& target, const pxStretchSpacer& spacer )
{
if( !pxAssert( target.GetSizer() != NULL ) ) return;
target.GetSizer()->AddStretchSpacer( spacer.proportion );
}
// ----------------------------------------------------------------------------
// Pointer versions! (note that C++ requires one of the two operator params be a
// "poper" object type (non-pointer), so that's why there's only a couple of these.
@ -173,12 +184,6 @@ void operator+=( wxSizer* target, wxSizer& src )
// ----------------------------------------------------------------------------
void operator+=( wxWindow& target, int spacer )
{
if( !pxAssert( target.GetSizer() != NULL ) ) return;
target.GetSizer()->AddSpacer( spacer );
}
// Returns FALSE if the window position is considered invalid, which means that it's title
// bar is most likely not easily grabble. Such a window should be moved to a valid or
// default position.

View File

@ -24,6 +24,9 @@ enum FoldersEnum_t
FolderId_Savestates,
FolderId_MemoryCards,
FolderId_Logs,
FolderId_Documents,
FolderId_COUNT
};

View File

@ -56,7 +56,7 @@ namespace Exception
class SaveStateLoadError : public virtual BadStream
{
public:
DEFINE_STREAM_EXCEPTION( SaveStateLoadError, wxLt("Savestate data is corrupted or incomplete.") )
DEFINE_STREAM_EXCEPTION( SaveStateLoadError, wxLt("Load failed: The savestate appears to be corrupt or incomplete.") )
};
class PluginError : public virtual RuntimeError

View File

@ -95,9 +95,10 @@ protected:
if( !state_buffer_lock.TryAcquire() )
throw Exception::CancelEvent( m_name + L"request ignored: state copy buffer is already locked!" );
_parent::OnStart();
current_state_thread = this;
m_isStarted = true;
_parent::OnStart();
}
void SendFinishEvent( int type )
@ -131,9 +132,18 @@ public:
protected:
void OnStart()
{
_parent::OnStart();
++sys_resume_lock;
m_resume_when_done = CoreThread.Pause();
try
{
++sys_resume_lock;
m_resume_when_done = CoreThread.Pause();
_parent::OnStart();
}
catch( ... )
{
wxGetApp().DeleteObject( this );
throw;
}
}
void ExecuteTaskInThread()
@ -148,6 +158,10 @@ protected:
}
};
static const char SavestateIdentString[] = "PCSX2 Savestate";
static const uint SavestateIdentLen = sizeof(SavestateIdentString);
// --------------------------------------------------------------------------------------
// StateThread_ZipToDisk
// --------------------------------------------------------------------------------------
@ -178,10 +192,19 @@ public:
protected:
void OnStart()
{
_parent::OnStart();
m_gzfp = gzopen( m_filename.ToUTF8(), "wb" );
if( m_gzfp == NULL )
throw Exception::CreateStream( m_filename, "Cannot create savestate file for writing." );
try
{
m_gzfp = gzopen( m_filename.ToUTF8(), "wb" );
if( m_gzfp == NULL )
throw Exception::CreateStream( m_filename, "Cannot create savestate file for writing." );
_parent::OnStart();
}
catch( ... )
{
wxGetApp().DeleteObject( this );
throw;
}
}
void ExecuteTaskInThread()
@ -190,6 +213,10 @@ protected:
static const int BlockSize = 0x20000;
int curidx = 0;
gzwrite(m_gzfp, SavestateIdentString, sizeof( SavestateIdentString ));
gzwrite(m_gzfp, &g_SaveVersion, sizeof( g_SaveVersion ));
do
{
int thisBlockSize = std::min( BlockSize, state_buffer.GetSizeInBytes() - curidx );
@ -245,13 +272,51 @@ public:
protected:
void OnStart()
{
_parent::OnStart();
try
{
m_gzfp = gzopen( m_filename.ToUTF8(), "rb" );
if( m_gzfp == NULL )
throw Exception::CreateStream( m_filename, "Cannot open savestate file for reading." );
m_gzfp = gzopen( m_filename.ToUTF8(), "rb" );
if( m_gzfp == NULL )
throw Exception::CreateStream( m_filename, "Cannot open savestate file for reading." );
char ident[SavestateIdentLen] = {0};
int result = gzread(m_gzfp, ident, SavestateIdentLen);
if( result == -1 )
throw Exception::SaveStateLoadError( m_filename, "Unable to read any data from the gzip archive." );
if( result < SavestateIdentLen )
throw Exception::SaveStateLoadError( m_filename );
if( strcmp(SavestateIdentString, ident) )
throw Exception::SaveStateLoadError( m_filename,
wxsFormat( L"Unrecognized file signature while loading savestate: %s", ident ),
_("File is not a valid PCSX2 savestate, or is from an older unsupported version of PCSX2.")
);
u32 savever;
gzread(m_gzfp, &savever, sizeof(g_SaveVersion));
if( (savever >> 16) != (g_SaveVersion >> 16) )
throw Exception::SaveStateLoadError( m_filename,
wxsFormat( L"Unrecognized file signature while loading savestate: %s", ident ),
_("File is not a valid PCSX2 savestate, or is from an older unsupported version of PCSX2.")
);
if( savever > g_SaveVersion )
throw Exception::SaveStateLoadError( m_filename,
wxsFormat( L"Unrecognized file signature while loading savestate: %s", ident ),
_("File is not a valid PCSX2 savestate, or is from an older unsupported version of PCSX2.")
);
_parent::OnStart();
}
catch( ... )
{
wxGetApp().DeleteObject( this );
throw;
}
}
void ExecuteTaskInThread()
{
// fixme: should start initially with the file size, and then grow from there.

View File

@ -359,8 +359,8 @@ void SaveStateBase::FreezeAll()
//////////////////////////////////////////////////////////////////////////////////
// uncompressed to/from memory state saves implementation
memSavingState::memSavingState( SafeArray<u8>& save_to ) :
SaveStateBase( save_to )
memSavingState::memSavingState( SafeArray<u8>& save_to )
: SaveStateBase( save_to )
{
}
@ -381,12 +381,12 @@ void memSavingState::FreezeAll()
_parent::FreezeAll();
}
memLoadingState::memLoadingState( const SafeArray<u8>& load_from ) :
SaveStateBase( const_cast<SafeArray<u8>&>(load_from) )
memLoadingState::memLoadingState( const SafeArray<u8>& load_from )
: SaveStateBase( const_cast<SafeArray<u8>&>(load_from) )
{
}
memLoadingState::~memLoadingState() { }
memLoadingState::~memLoadingState() throw() { }
// Loading of state data
void memLoadingState::FreezeMem( void* data, int size )

View File

@ -24,7 +24,7 @@
// the lower 16 bit value. IF the change is breaking of all compatibility with old
// states, increment the upper 16 bit value, and clear the lower 16 bits to 0.
static const u32 g_SaveVersion = 0x8b410004;
static const u32 g_SaveVersion = 0x8b420000;
// this function is meant to be used in the place of GSfreeze, and provides a safe layer
// between the GS saving function and the MTGS's needs. :)
@ -231,9 +231,9 @@ protected:
static const int MemoryBaseAllocSize = 0x02b00000; // 45 meg base alloc
public:
virtual ~memSavingState() { }
virtual ~memSavingState() throw() { }
memSavingState( SafeArray<u8>& save_to );
// Saving of state data to a memory buffer
void FreezeMem( void* data, int size );
void FreezeAll();
@ -244,7 +244,7 @@ public:
class memLoadingState : public SaveStateBase
{
public:
virtual ~memLoadingState();
virtual ~memLoadingState() throw();
memLoadingState( const SafeArray<u8>& load_from );
// Loading of state data from a memory buffer...

View File

@ -323,13 +323,22 @@ struct pxAppResources
ScopedPtr<wxIconBundle> IconBundle;
ScopedPtr<wxBitmap> Bitmap_Logo;
ScopedPtr<wxMenu> RecentIsoMenu;
ScopedPtr<RecentIsoManager> RecentIsoList;
pxAppResources();
virtual ~pxAppResources() throw() { }
};
// --------------------------------------------------------------------------------------
// RecentIsoList
// --------------------------------------------------------------------------------------
struct RecentIsoList
{
ScopedPtr<RecentIsoManager> Manager;
ScopedPtr<wxMenu> Menu;
RecentIsoList();
virtual ~RecentIsoList() throw() { }
};
// --------------------------------------------------------------------------------------
// FramerateManager
// --------------------------------------------------------------------------------------
@ -461,6 +470,8 @@ public:
protected:
ScopedPtr<PipeRedirectionBase> m_StdoutRedirHandle;
ScopedPtr<PipeRedirectionBase> m_StderrRedirHandle;
ScopedPtr<RecentIsoList> m_RecentIsoList;
ScopedPtr<pxAppResources> m_Resources;
public:
@ -482,6 +493,7 @@ public:
void PostMenuAction( MenuIdentifiers menu_id ) const;
int IssueDialogAsModal( const wxString& dlgName );
void PostMethod( FnPtr_AppMethod method );
void PostIdleMethod( FnPtr_AppMethod method );
int DoStuckThread( PersistentThread& stuck_thread );
void SysExecute();
@ -501,7 +513,7 @@ public:
void OpenGsPanel();
void CloseGsPanel();
void OnGsFrameClosed();
void OnMainFrameClosed();
void OnMainFrameClosed( wxWindowID id );
// --------------------------------------------------------------------------
// Startup / Shutdown Helpers
@ -524,7 +536,9 @@ public:
// memory until the program exits.
wxMenu& GetRecentIsoMenu();
RecentIsoManager& GetRecentIsoList();
RecentIsoManager& GetRecentIsoManager();
pxAppResources& GetResourceCache();
const wxIconBundle& GetIconBundle();
const wxBitmap& GetLogoBitmap();
wxImageList& GetImgList_Config();
@ -540,6 +554,7 @@ public:
// --------------------------------------------------------------------------
bool OnInit();
int OnExit();
void CleanUp();
void OnInitCmdLine( wxCmdLineParser& parser );
bool OnCmdLineParsed( wxCmdLineParser& parser );
@ -558,7 +573,7 @@ public:
void EnableAllLogging() const;
void DisableWindowLogging() const;
void DisableDiskLogging() const;
void OnProgramLogClosed();
void OnProgramLogClosed( wxWindowID id );
protected:
bool InvokeMethodOnMainThread( FnPtr_AppMethod method );
@ -587,7 +602,7 @@ protected:
void OnEmuKeyDown( wxKeyEvent& evt );
void OnInvokeMethod( pxInvokeMethodEvent& evt );
void OnInvokeMethod( pxInvokeAppMethodEvent& evt );
// ----------------------------------------------------------------------------
// Override wx default exception handling behavior

View File

@ -95,10 +95,16 @@ namespace PathDefs
// share with other programs: screenshots, memory cards, and savestates.
wxDirName GetDocuments()
{
if( UseAdminMode )
return (wxDirName)wxGetCwd();
else
return (wxDirName)Path::Combine( wxStandardPaths::Get().GetDocumentsDir(), wxGetApp().GetAppName() );
switch( DocsFolderMode )
{
case DocsFolder_User: return (wxDirName)Path::Combine( wxStandardPaths::Get().GetDocumentsDir(), wxGetApp().GetAppName() );
case DocsFolder_CWD: return (wxDirName)wxGetCwd();
case DocsFolder_Custom: return CustomDocumentsFolder;
jNO_DEFAULT
}
return wxDirName();
}
wxDirName GetSnapshots()
@ -152,6 +158,8 @@ namespace PathDefs
case FolderId_Savestates: return GetSavestates();
case FolderId_MemoryCards: return GetMemoryCards();
case FolderId_Logs: return GetLogs();
case FolderId_Documents: return CustomDocumentsFolder;
jNO_DEFAULT
}
@ -170,6 +178,8 @@ wxDirName& AppConfig::FolderOptions::operator[]( FoldersEnum_t folderidx )
case FolderId_Savestates: return Savestates;
case FolderId_MemoryCards: return MemoryCards;
case FolderId_Logs: return Logs;
case FolderId_Documents: return CustomDocumentsFolder;
jNO_DEFAULT
}
@ -193,6 +203,8 @@ bool AppConfig::FolderOptions::IsDefault( FoldersEnum_t folderidx ) const
case FolderId_MemoryCards: return UseDefaultMemoryCards;
case FolderId_Logs: return UseDefaultLogs;
case FolderId_Documents: return false;
jNO_DEFAULT
}
return false;
@ -236,6 +248,10 @@ void AppConfig::FolderOptions::Set( FoldersEnum_t folderidx, const wxString& src
Logs = src;
UseDefaultLogs = useDefault;
break;
case FolderId_Documents:
CustomDocumentsFolder = src;
break;
jNO_DEFAULT
}
@ -303,7 +319,6 @@ bool AppConfig::FullpathMatchTest( PluginsEnum_t pluginId, const wxString& cmpto
return left == right;
}
wxDirName GetSettingsFolder()
{
return UseDefaultSettingsFolder ? PathDefs::GetSettings() : SettingsFolder;
@ -363,9 +378,18 @@ void AppConfig::LoadSaveUserMode( IniInterface& ini, const wxString& cwdhash )
ini.GetConfig().Write( L"Timestamp", timestamp_now );*/
ini.Entry( L"UseAdminMode", UseAdminMode, false );
ini.Entry( L"UseDefaultSettingsFolder", UseDefaultSettingsFolder, true );
ini.Entry( L"SettingsFolder", SettingsFolder, PathDefs::GetSettings() );
static const wxChar* DocsFolderModeNames[] =
{
L"User",
L"CWD",
L"Custom",
};
ini.EnumEntry( L"DocumentsFolderMode", DocsFolderMode, DocsFolderModeNames, DocsFolder_User );
ini.Entry( L"UseDefaultSettingsFolder", UseDefaultSettingsFolder, true );
ini.Entry( L"CustomDocumentsFolder", CustomDocumentsFolder, wxDirName() );
ini.Entry( L"SettingsFolder", SettingsFolder, PathDefs::GetSettings() );
ini.Flush();
}
@ -514,7 +538,7 @@ void AppConfig::FolderOptions::LoadSave( IniInterface& ini )
{
ApplyDefaults();
if( !UseAdminMode )
if( DocsFolderMode != DocsFolder_CWD )
{
for( int i=0; i<FolderId_COUNT; ++i )
operator[]( (FoldersEnum_t)i ).Normalize();
@ -672,7 +696,7 @@ void RelocateLogfile()
//
void AppConfig_OnChangedSettingsFolder( bool overwrite )
{
if( !UseAdminMode )
if( DocsFolderMode != DocsFolder_CWD )
PathDefs::GetDocuments().Mkdir();
GetSettingsFolder().Mkdir();

View File

@ -19,9 +19,22 @@
#include "PathDefs.h"
#include "CDVD/CDVDaccess.h"
extern bool UseAdminMode; // dictates if the program uses /home/user or /cwd for the program data
extern wxDirName SettingsFolder; // dictates where the settings folder comes from, *if* UseDefaultSettingsFolder is FALSE.
extern bool UseDefaultSettingsFolder; // when TRUE, pcsx2 derives the settings folder from the UseAdminMode
enum DocsModeType
{
// uses /home/user or /cwd for the program data
DocsFolder_User,
// uses the current working directory for program data
DocsFolder_CWD,
// uses a custom location for program data
DocsFolder_Custom,
};
extern DocsModeType DocsFolderMode; //
extern wxDirName SettingsFolder; // dictates where the settings folder comes from, *if* UseDefaultSettingsFolder is FALSE.
extern wxDirName CustomDocumentsFolder; // allows the specification of a custom home folder for PCSX2 documents files.
extern bool UseDefaultSettingsFolder; // when TRUE, pcsx2 derives the settings folder from the UseAdminMode
wxDirName GetSettingsFolder();
wxString GetSettingsFilename();
@ -189,9 +202,9 @@ public:
bool EnableSpeedHacks;
bool EnableGameFixes;
wxString CurrentIso;
wxString CurrentELF;
CDVD_SourceType CdvdSource;
wxString CurrentIso;
wxString CurrentELF;
CDVD_SourceType CdvdSource;
McdOptions Mcd[2][4];
ConsoleLogOptions ProgLogBox;

View File

@ -131,7 +131,7 @@ void AppCoreThread::OnResumeReady()
if( !wxFile::Exists( g_Conf->CurrentIso ) )
g_Conf->CurrentIso.Clear();
sApp.GetRecentIsoList().Add( g_Conf->CurrentIso );
sApp.GetRecentIsoManager().Add( g_Conf->CurrentIso );
CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso );
AppSaveSettings();

View File

@ -66,12 +66,12 @@ void IEventListener_Plugins::DispatchEvent( const PluginEventType& pevt )
{
switch( pevt )
{
case CorePlugins_Loaded: CorePlugins_OnLoaded(); break;
case CorePlugins_Loaded: CorePlugins_OnLoaded(); break;
case CorePlugins_Init: CorePlugins_OnInit(); break;
case CorePlugins_Opening: CorePlugins_OnOpening(); break;
case CorePlugins_Opened: CorePlugins_OnOpened(); break;
case CorePlugins_Opened: CorePlugins_OnOpened(); break;
case CorePlugins_Closing: CorePlugins_OnClosing(); break;
case CorePlugins_Closed: CorePlugins_OnClosed(); break;
case CorePlugins_Closed: CorePlugins_OnClosed(); break;
case CorePlugins_Shutdown: CorePlugins_OnShutdown(); break;
case CorePlugins_Unloaded: CorePlugins_OnUnloaded(); break;

View File

@ -30,7 +30,7 @@ class GSFrame;
class ConsoleLogFrame;
class PipeRedirectionBase;
class AppCoreThread;
class pxInvokeMethodEvent;
class pxInvokeAppMethodEvent;
class IniInterface;
// wxWidgets forward declarations
@ -41,5 +41,10 @@ class wxDirPickerCtrl;
class wxFilePickerCtrl;
class wxFileDirPickerEvent;
class wxListBox;
class wxListCtrl;
class wxListView;
class wxListbook;
class wxSpinCtrl;
class wxBookCtrlBase;
class wxListEvent;

View File

@ -152,9 +152,10 @@ void Pcsx2App::ReadUserModeSettings()
}
else
{
// usermode.ini exists -- assume Documents mode, unless the ini explicitly
// usermode.ini exists -- assume User Documents mode, unless the ini explicitly
// specifies otherwise.
UseAdminMode = false;
DocsFolderMode = DocsFolder_User;
IniLoader loader( *conf_usermode );
g_Conf->LoadSaveUserMode( loader, groupname );
@ -208,13 +209,14 @@ void Pcsx2App::OpenMainFrame()
MainEmuFrame* mainFrame = new MainEmuFrame( NULL, L"PCSX2" );
m_id_MainFrame = mainFrame->GetId();
mainFrame->PushEventHandler( &GetRecentIsoList() );
mainFrame->PushEventHandler( &GetRecentIsoManager() );
if( wxWindow* deleteme = GetProgramLog() )
{
deleteme->Destroy();
g_Conf->ProgLogBox.Visible = true;
PostMethod( &Pcsx2App::OpenConsoleLog );
m_id_ProgramLogBox = wxID_ANY;
PostIdleMethod( &Pcsx2App::OpenConsoleLog );
}
SetTopWindow( mainFrame ); // not really needed...
@ -235,85 +237,87 @@ void Pcsx2App::AllocateCoreStuffs()
SysLogMachineCaps();
AppApplySettings();
if( m_CoreAllocs ) return;
m_CoreAllocs = new SysCoreAllocations();
if( m_CoreAllocs->HadSomeFailures( g_Conf->EmuOptions.Cpu.Recompiler ) )
if( !m_CoreAllocs )
{
// HadSomeFailures only returns 'true' if an *enabled* cpu type fails to init. If
// the user already has all interps configured, for example, then no point in
// popping up this dialog.
wxDialogWithHelpers exconf( NULL, _("PCSX2 Recompiler Error(s)"), wxVERTICAL );
m_CoreAllocs = new SysCoreAllocations();
exconf += 12;
exconf += exconf.Heading( pxE( ".Error:RecompilerInit",
L"Warning: Some of the configured PS2 recompilers failed to initialize and will not be available for this session:\n" )
);
wxTextCtrl* scrollableTextArea = new wxTextCtrl(
&exconf, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxTE_READONLY | wxTE_MULTILINE | wxTE_WORDWRAP
);
exconf += scrollableTextArea | pxSizerFlags::StdExpand();
if( !m_CoreAllocs->IsRecAvailable_EE() )
if( m_CoreAllocs->HadSomeFailures( g_Conf->EmuOptions.Cpu.Recompiler ) )
{
scrollableTextArea->AppendText( L"* R5900 (EE)\n\n" );
// HadSomeFailures only returns 'true' if an *enabled* cpu type fails to init. If
// the user already has all interps configured, for example, then no point in
// popping up this dialog.
wxDialogWithHelpers exconf( NULL, _("PCSX2 Recompiler Error(s)"), wxVERTICAL );
g_Conf->EmuOptions.Recompiler.EnableEE = false;
exconf += 12;
exconf += exconf.Heading( pxE( ".Error:RecompilerInit",
L"Warning: Some of the configured PS2 recompilers failed to initialize and will not be available for this session:\n" )
);
wxTextCtrl* scrollableTextArea = new wxTextCtrl(
&exconf, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxTE_READONLY | wxTE_MULTILINE | wxTE_WORDWRAP
);
exconf += scrollableTextArea | pxSizerFlags::StdExpand();
if( !m_CoreAllocs->IsRecAvailable_EE() )
{
scrollableTextArea->AppendText( L"* R5900 (EE)\n\n" );
g_Conf->EmuOptions.Recompiler.EnableEE = false;
}
if( !m_CoreAllocs->IsRecAvailable_IOP() )
{
scrollableTextArea->AppendText( L"* R3000A (IOP)\n\n" );
g_Conf->EmuOptions.Recompiler.EnableIOP = false;
}
if( !m_CoreAllocs->IsRecAvailable_MicroVU0() )
{
scrollableTextArea->AppendText( L"* microVU0\n\n" );
g_Conf->EmuOptions.Recompiler.UseMicroVU0 = false;
g_Conf->EmuOptions.Recompiler.EnableVU0 = g_Conf->EmuOptions.Recompiler.EnableVU0 && m_CoreAllocs->IsRecAvailable_SuperVU0();
}
if( !m_CoreAllocs->IsRecAvailable_MicroVU1() )
{
scrollableTextArea->AppendText( L"* microVU1\n\n" );
g_Conf->EmuOptions.Recompiler.UseMicroVU1 = false;
g_Conf->EmuOptions.Recompiler.EnableVU1 = g_Conf->EmuOptions.Recompiler.EnableVU1 && m_CoreAllocs->IsRecAvailable_SuperVU1();
}
if( !m_CoreAllocs->IsRecAvailable_SuperVU0() )
{
scrollableTextArea->AppendText( L"* SuperVU0\n\n" );
g_Conf->EmuOptions.Recompiler.UseMicroVU0 = m_CoreAllocs->IsRecAvailable_MicroVU0();
g_Conf->EmuOptions.Recompiler.EnableVU0 = g_Conf->EmuOptions.Recompiler.EnableVU0 && g_Conf->EmuOptions.Recompiler.UseMicroVU0;
}
if( !m_CoreAllocs->IsRecAvailable_SuperVU1() )
{
scrollableTextArea->AppendText( L"* SuperVU1\n\n" );
g_Conf->EmuOptions.Recompiler.UseMicroVU1 = m_CoreAllocs->IsRecAvailable_MicroVU1();
g_Conf->EmuOptions.Recompiler.EnableVU1 = g_Conf->EmuOptions.Recompiler.EnableVU1 && g_Conf->EmuOptions.Recompiler.UseMicroVU1;
}
exconf += new ModalButtonPanel( &exconf, MsgButtons().OK() ) | pxSizerFlags::StdCenter();
exconf.ShowModal();
// Failures can be SSE-related OR memory related. Should do per-cpu error reports instead...
/*message += pxE( ".Popup Error:EmuCore:MemoryForRecs",
L"These errors are the result of memory allocation failures (see the program log for details). "
L"Closing out some memory hogging background tasks may resolve this error.\n\n"
L"These recompilers have been disabled and interpreters will be used in their place. "
L"Interpreters can be very slow, so don't get too excited. Press OK to continue or CANCEL to close PCSX2."
);*/
//if( !Msgbox::OkCancel( message, _("PCSX2 Initialization Error"), wxICON_ERROR ) )
// return false;
}
if( !m_CoreAllocs->IsRecAvailable_IOP() )
{
scrollableTextArea->AppendText( L"* R3000A (IOP)\n\n" );
g_Conf->EmuOptions.Recompiler.EnableIOP = false;
}
if( !m_CoreAllocs->IsRecAvailable_MicroVU0() )
{
scrollableTextArea->AppendText( L"* microVU0\n\n" );
g_Conf->EmuOptions.Recompiler.UseMicroVU0 = false;
g_Conf->EmuOptions.Recompiler.EnableVU0 = g_Conf->EmuOptions.Recompiler.EnableVU0 && m_CoreAllocs->IsRecAvailable_SuperVU0();
}
if( !m_CoreAllocs->IsRecAvailable_MicroVU1() )
{
scrollableTextArea->AppendText( L"* microVU1\n\n" );
g_Conf->EmuOptions.Recompiler.UseMicroVU1 = false;
g_Conf->EmuOptions.Recompiler.EnableVU1 = g_Conf->EmuOptions.Recompiler.EnableVU1 && m_CoreAllocs->IsRecAvailable_SuperVU1();
}
if( !m_CoreAllocs->IsRecAvailable_SuperVU0() )
{
scrollableTextArea->AppendText( L"* SuperVU0\n\n" );
g_Conf->EmuOptions.Recompiler.UseMicroVU0 = m_CoreAllocs->IsRecAvailable_MicroVU0();
g_Conf->EmuOptions.Recompiler.EnableVU0 = g_Conf->EmuOptions.Recompiler.EnableVU0 && g_Conf->EmuOptions.Recompiler.UseMicroVU0;
}
if( !m_CoreAllocs->IsRecAvailable_SuperVU1() )
{
scrollableTextArea->AppendText( L"* SuperVU1\n\n" );
g_Conf->EmuOptions.Recompiler.UseMicroVU1 = m_CoreAllocs->IsRecAvailable_MicroVU1();
g_Conf->EmuOptions.Recompiler.EnableVU1 = g_Conf->EmuOptions.Recompiler.EnableVU1 && g_Conf->EmuOptions.Recompiler.UseMicroVU1;
}
exconf += new ModalButtonPanel( &exconf, MsgButtons().OK() ) | pxSizerFlags::StdCenter();
exconf.ShowModal();
// Failures can be SSE-related OR memory related. Should do per-cpu error reports instead...
/*message += pxE( ".Popup Error:EmuCore:MemoryForRecs",
L"These errors are the result of memory allocation failures (see the program log for details). "
L"Closing out some memory hogging background tasks may resolve this error.\n\n"
L"These recompilers have been disabled and interpreters will be used in their place. "
L"Interpreters can be very slow, so don't get too excited. Press OK to continue or CANCEL to close PCSX2."
);*/
//if( !Msgbox::OkCancel( message, _("PCSX2 Initialization Error"), wxICON_ERROR ) )
// return false;
}
LoadPluginsPassive( NULL );
@ -397,7 +401,7 @@ bool Pcsx2App::OnCmdLineParsed( wxCmdLineParser& parser )
return true;
}
typedef void (wxEvtHandler::*pxInvokeMethodEventFunction)(pxInvokeMethodEvent&);
typedef void (wxEvtHandler::*pxInvokeMethodEventFunction)(pxInvokeAppMethodEvent&);
typedef void (wxEvtHandler::*pxStuckThreadEventHandler)(pxMessageBoxEvent&);
bool Pcsx2App::OnInit()
@ -444,7 +448,7 @@ bool Pcsx2App::OnInit()
InitDefaultGlobalAccelerators();
delete wxLog::SetActiveTarget( new pxLogConsole() );
m_Resources = new pxAppResources();
m_RecentIsoList = new RecentIsoList();
#ifdef __WXMSW__
pxDwm_Load();
@ -503,7 +507,7 @@ void Pcsx2App::CleanupRestartable()
if( g_Conf )
AppSaveSettings();
sMainFrame.RemoveEventHandler( &GetRecentIsoList() );
sMainFrame.RemoveEventHandler( &GetRecentIsoManager() );
}
// This cleanup handler can be called from OnExit (it doesn't need a running message pump),
@ -517,6 +521,7 @@ void Pcsx2App::CleanupOnExit()
try
{
CleanupRestartable();
CleanupResources();
}
catch( Exception::ThreadDeadlock& ) { throw; }
catch( Exception::CancelEvent& ) { throw; }
@ -552,13 +557,13 @@ void Pcsx2App::CleanupResources()
while( wxGetLocale() != NULL )
delete wxGetLocale();
m_Resources = NULL;
}
int Pcsx2App::OnExit()
{
CleanupOnExit();
CleanupResources();
m_Resources = NULL;
return wxApp::OnExit();
}
@ -577,9 +582,14 @@ Pcsx2App::Pcsx2App()
Pcsx2App::~Pcsx2App()
{
pxDoAssert = pxAssertImpl_LogIt;
}
void Pcsx2App::CleanUp()
{
CleanupResources();
m_Resources = NULL;
m_Resources = NULL;
m_RecentIsoList = NULL;
DisableDiskLogging();
if( emuLog != NULL )
@ -587,6 +597,8 @@ Pcsx2App::~Pcsx2App()
fclose( emuLog );
emuLog = NULL;
}
_parent::CleanUp();
}

View File

@ -42,8 +42,9 @@ DEFINE_EVENT_TYPE( pxEvt_LogicalVsync );
DEFINE_EVENT_TYPE( pxEvt_OpenModalDialog );
bool UseAdminMode = false;
DocsModeType DocsFolderMode = DocsFolder_User;
wxDirName SettingsFolder;
wxDirName CustomDocumentsFolder;
bool UseDefaultSettingsFolder = true;
ScopedPtr<AppConfig> g_Conf;
@ -83,42 +84,42 @@ void Pcsx2App::PostMenuAction( MenuIdentifiers menu_id ) const
}
// --------------------------------------------------------------------------------------
// pxInvokeMethodEvent
// pxInvokeAppMethodEvent
// --------------------------------------------------------------------------------------
// Unlike pxPingEvent, the Semaphore belonging to this event is typically posted when the
// invoked method is completed. If the method can be executed in non-blocking fashion then
// it should leave the semaphore postback NULL.
//
class pxInvokeMethodEvent : public pxPingEvent
class pxInvokeAppMethodEvent : public pxPingEvent
{
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxInvokeMethodEvent)
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxInvokeAppMethodEvent)
protected:
FnPtr_AppMethod m_Method;
public:
virtual ~pxInvokeMethodEvent() throw() { }
virtual pxInvokeMethodEvent *Clone() const { return new pxInvokeMethodEvent(*this); }
virtual ~pxInvokeAppMethodEvent() throw() { }
virtual pxInvokeAppMethodEvent *Clone() const { return new pxInvokeAppMethodEvent(*this); }
explicit pxInvokeMethodEvent( int msgtype, FnPtr_AppMethod method=NULL, Semaphore* sema=NULL )
explicit pxInvokeAppMethodEvent( int msgtype, FnPtr_AppMethod method=NULL, Semaphore* sema=NULL )
: pxPingEvent( msgtype, sema )
{
m_Method = method;
}
explicit pxInvokeMethodEvent( FnPtr_AppMethod method=NULL, Semaphore* sema=NULL )
explicit pxInvokeAppMethodEvent( FnPtr_AppMethod method=NULL, Semaphore* sema=NULL )
: pxPingEvent( pxEvt_InvokeMethod, sema )
{
m_Method = method;
}
explicit pxInvokeMethodEvent( FnPtr_AppMethod method, Semaphore& sema )
explicit pxInvokeAppMethodEvent( FnPtr_AppMethod method, Semaphore& sema )
: pxPingEvent( pxEvt_InvokeMethod, &sema )
{
m_Method = method;
}
pxInvokeMethodEvent( const pxInvokeMethodEvent& src )
pxInvokeAppMethodEvent( const pxInvokeAppMethodEvent& src )
: pxPingEvent( src )
{
m_Method = src.m_Method;
@ -137,9 +138,9 @@ public:
};
IMPLEMENT_DYNAMIC_CLASS( pxInvokeMethodEvent, pxPingEvent )
IMPLEMENT_DYNAMIC_CLASS( pxInvokeAppMethodEvent, pxPingEvent )
void Pcsx2App::OnInvokeMethod( pxInvokeMethodEvent& evt )
void Pcsx2App::OnInvokeMethod( pxInvokeAppMethodEvent& evt )
{
evt.Invoke(); // wow this is easy!
}
@ -722,7 +723,7 @@ bool Pcsx2App::InvokeMethodOnMainThread( FnPtr_AppMethod method )
if( wxThread::IsMain() ) return false;
Semaphore sem;
pxInvokeMethodEvent evt( method, sem );
pxInvokeAppMethodEvent evt( method, sem );
AddPendingEvent( evt );
sem.Wait();
@ -743,7 +744,7 @@ bool Pcsx2App::InvokeMethodOnMainThread( FnPtr_AppMethod method )
bool Pcsx2App::PostMethodToMainThread( FnPtr_AppMethod method )
{
if( wxThread::IsMain() ) return false;
pxInvokeMethodEvent evt( method );
pxInvokeAppMethodEvent evt( method );
AddPendingEvent( evt );
return true;
}
@ -752,10 +753,18 @@ bool Pcsx2App::PostMethodToMainThread( FnPtr_AppMethod method )
// main thread.
void Pcsx2App::PostMethod( FnPtr_AppMethod method )
{
pxInvokeMethodEvent evt( method );
pxInvokeAppMethodEvent evt( method );
AddPendingEvent( evt );
}
// Posts a method to the main thread; non-blocking. Post occurs even when called from the
// main thread.
void Pcsx2App::PostIdleMethod( FnPtr_AppMethod method )
{
pxInvokeAppMethodEvent evt( method );
OnAddEventToIdleQueue( evt );
}
void Pcsx2App::OpenGsPanel()
{
if( InvokeMethodOnMainThread( &Pcsx2App::OpenGsPanel ) ) return;
@ -813,18 +822,18 @@ void Pcsx2App::OnGsFrameClosed()
m_id_GsFrame = wxID_ANY;
}
void Pcsx2App::OnProgramLogClosed()
void Pcsx2App::OnProgramLogClosed( wxWindowID id )
{
if( m_id_ProgramLogBox == wxID_ANY ) return;
if( (m_id_ProgramLogBox == wxID_ANY) || (m_id_ProgramLogBox != id) ) return;
m_id_ProgramLogBox = wxID_ANY;
DisableWindowLogging();
}
void Pcsx2App::OnMainFrameClosed()
void Pcsx2App::OnMainFrameClosed( wxWindowID id )
{
// Nothing threaded depends on the mainframe (yet) -- it all passes through the main wxApp
// message handler. But that might change in the future.
//if( m_id_MainFrame == wxID_ANY ) return;
if( m_id_MainFrame != id ) return;
m_id_MainFrame = wxID_ANY;
}

View File

@ -64,30 +64,40 @@ const wxImage& LoadImageAny(
return dest = onFail.Get();
}
RecentIsoList::RecentIsoList()
{
Menu = new wxMenu();
Menu->Append( MenuId_IsoBrowse, _("Browse..."), _("Browse for an Iso that is not in your recent history.") );
Manager = new RecentIsoManager( Menu );
}
pxAppResources::pxAppResources()
{
// RecentIsoList and Menu must be created immediately, since they depend on listening for App configuration
// events that can be thrown very early ni program execution.
RecentIsoMenu = new wxMenu();
RecentIsoMenu->Append( MenuId_IsoBrowse, _("Browse..."), _("Browse for an Iso that is not in your recent history.") );
RecentIsoList = new RecentIsoManager( RecentIsoMenu );
}
wxMenu& Pcsx2App::GetRecentIsoMenu()
{
pxAssert( !!m_Resources->RecentIsoMenu );
return *m_Resources->RecentIsoMenu;
pxAssert( !!m_RecentIsoList->Menu );
return *m_RecentIsoList->Menu;
}
RecentIsoManager& Pcsx2App::GetRecentIsoList()
RecentIsoManager& Pcsx2App::GetRecentIsoManager()
{
pxAssert( !!m_Resources->RecentIsoList );
return *m_Resources->RecentIsoList;
pxAssert( !!m_RecentIsoList->Manager );
return *m_RecentIsoList->Manager;
}
pxAppResources& Pcsx2App::GetResourceCache()
{
if( !m_Resources )
m_Resources = new pxAppResources();
return *m_Resources;
}
const wxIconBundle& Pcsx2App::GetIconBundle()
{
ScopedPtr<wxIconBundle>& bundle( m_Resources->IconBundle );
ScopedPtr<wxIconBundle>& bundle( GetResourceCache().IconBundle );
if( !bundle )
{
bundle = new wxIconBundle();
@ -102,7 +112,7 @@ const wxIconBundle& Pcsx2App::GetIconBundle()
// ------------------------------------------------------------------------
const wxBitmap& Pcsx2App::GetLogoBitmap()
{
ScopedPtr<wxBitmap>& logo( m_Resources->Bitmap_Logo );
ScopedPtr<wxBitmap>& logo( GetResourceCache().Bitmap_Logo );
if( logo ) return *logo;
wxFileName mess;
@ -138,7 +148,7 @@ const wxBitmap& Pcsx2App::GetLogoBitmap()
// ------------------------------------------------------------------------
wxImageList& Pcsx2App::GetImgList_Config()
{
ScopedPtr<wxImageList>& images( m_Resources->ConfigImages );
ScopedPtr<wxImageList>& images( GetResourceCache().ConfigImages );
if( !images )
{
images = new wxImageList(32, 32);
@ -176,10 +186,9 @@ wxImageList& Pcsx2App::GetImgList_Config()
return *images;
}
// ------------------------------------------------------------------------
wxImageList& Pcsx2App::GetImgList_Toolbars()
{
ScopedPtr<wxImageList>& images( m_Resources->ToolbarImages );
ScopedPtr<wxImageList>& images( GetResourceCache().ToolbarImages );
if( !images )
{

View File

@ -149,6 +149,8 @@ public:
// If no exceptions are thrown, then the operation is assumed a success. :)
virtual void Apply()=0;
void Init();
// Mandatory override: As a rule for proper interface design, all deriving classes need
// to implement this function. There's no implementation of an options/settings panel
// that does not heed the changes of application status/settings changes. ;)
@ -160,7 +162,8 @@ public:
virtual void AppStatusEvent_OnSettingsLoadSave( const AppSettingsEventInfo& ) {}
virtual void AppStatusEvent_OnExit() {}
void Init();
protected:
virtual void OnSettingsApplied( wxCommandEvent& evt );
};
class ApplicableWizardPage : public wxWizardPageSimple, public IApplyState

View File

@ -25,17 +25,15 @@
#include <wx/textfile.h>
BEGIN_DECLARE_EVENT_TYPES()
DECLARE_EVENT_TYPE(wxEVT_LOG_Write, -1)
DECLARE_EVENT_TYPE(wxEVT_LOG_Newline, -1)
DECLARE_EVENT_TYPE(wxEVT_SetTitleText, -1)
DECLARE_EVENT_TYPE(wxEVT_FlushQueue, -1)
DECLARE_EVENT_TYPE(pxEvt_LogWrite, -1)
DECLARE_EVENT_TYPE(pxEvt_SetTitleText, -1)
DECLARE_EVENT_TYPE(pxEvt_FlushQueue, -1)
END_DECLARE_EVENT_TYPES()
DEFINE_EVENT_TYPE(wxEVT_LOG_Write)
DEFINE_EVENT_TYPE(wxEVT_LOG_Newline)
DEFINE_EVENT_TYPE(wxEVT_SetTitleText)
DEFINE_EVENT_TYPE(wxEVT_DockConsole)
DEFINE_EVENT_TYPE(wxEVT_FlushQueue)
DEFINE_EVENT_TYPE(pxEvt_LogWrite)
DEFINE_EVENT_TYPE(pxEvt_SetTitleText)
DEFINE_EVENT_TYPE(pxEvt_DockConsole)
DEFINE_EVENT_TYPE(pxEvt_FlushQueue)
// C++ requires abstract destructors to exist, even though they're abstract.
PipeRedirectionBase::~PipeRedirectionBase() throw() {}
@ -321,14 +319,15 @@ ConsoleLogFrame::ConsoleLogFrame( MainEmuFrame *parent, const wxString& title, A
Connect( m_item_StdoutEE->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( ConsoleLogFrame::OnLogSourceChanged ) );
Connect( m_item_StdoutIOP->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( ConsoleLogFrame::OnLogSourceChanged ) );
Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler (ConsoleLogFrame::OnCloseWindow) );
Connect( wxEVT_MOVE, wxMoveEventHandler (ConsoleLogFrame::OnMoveAround) );
Connect( wxEVT_SIZE, wxSizeEventHandler (ConsoleLogFrame::OnResize) );
Connect( wxEVT_ACTIVATE, wxActivateEventHandler (ConsoleLogFrame::OnActivate) );
Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler (ConsoleLogFrame::OnCloseWindow) );
Connect( wxEVT_DESTROY, wxWindowDestroyEventHandler (ConsoleLogFrame::OnDestroyWindow) );
Connect( wxEVT_MOVE, wxMoveEventHandler (ConsoleLogFrame::OnMoveAround) );
Connect( wxEVT_SIZE, wxSizeEventHandler (ConsoleLogFrame::OnResize) );
Connect( wxEVT_ACTIVATE, wxActivateEventHandler (ConsoleLogFrame::OnActivate) );
Connect( wxEVT_SetTitleText, wxCommandEventHandler (ConsoleLogFrame::OnSetTitle) );
Connect( wxEVT_DockConsole, wxCommandEventHandler (ConsoleLogFrame::OnDockedMove) );
Connect( wxEVT_FlushQueue, wxCommandEventHandler (ConsoleLogFrame::OnFlushEvent) );
Connect( pxEvt_SetTitleText, wxCommandEventHandler (ConsoleLogFrame::OnSetTitle) );
Connect( pxEvt_DockConsole, wxCommandEventHandler (ConsoleLogFrame::OnDockedMove) );
Connect( pxEvt_FlushQueue, wxCommandEventHandler (ConsoleLogFrame::OnFlushEvent) );
Connect( wxEVT_IDLE, wxIdleEventHandler (ConsoleLogFrame::OnIdleEvent) );
Connect( wxEVT_TIMER, wxTimerEventHandler (ConsoleLogFrame::OnFlushLimiterTimer) );
@ -343,7 +342,7 @@ ConsoleLogFrame::ConsoleLogFrame( MainEmuFrame *parent, const wxString& title, A
ConsoleLogFrame::~ConsoleLogFrame()
{
wxGetApp().OnProgramLogClosed();
wxGetApp().OnProgramLogClosed( GetId() );
}
// Implementation note: Calls SetColor and Write( text ). Override those virtuals
@ -379,7 +378,7 @@ void ConsoleLogFrame::Write( ConsoleColors color, const wxString& text )
if( !m_pendingFlushMsg )
{
wxCommandEvent evt( wxEVT_FlushQueue );
wxCommandEvent evt( pxEvt_FlushQueue );
evt.SetInt( 0 );
GetEventHandler()->AddPendingEvent( evt );
m_pendingFlushMsg = true;
@ -506,11 +505,17 @@ void ConsoleLogFrame::OnCloseWindow(wxCloseEvent& event)
else
{
m_threadlogger = NULL;
wxGetApp().OnProgramLogClosed();
wxGetApp().OnProgramLogClosed( GetId() );
event.Skip();
}
}
void ConsoleLogFrame::OnDestroyWindow(wxWindowDestroyEvent& event)
{
m_threadlogger = NULL;
wxGetApp().OnProgramLogClosed( GetId() );
}
void ConsoleLogFrame::OnOpen(wxCommandEvent& WXUNUSED(event))
{
Show(true);
@ -602,7 +607,7 @@ void ConsoleLogFrame::OnIdleEvent( wxIdleEvent& )
m_flushevent_counter = 0;
m_timer_FlushLimiter.Stop();
wxCommandEvent sendevt( wxEVT_FlushQueue );
wxCommandEvent sendevt( pxEvt_FlushQueue );
GetEventHandler()->AddPendingEvent( sendevt );
}
}
@ -613,7 +618,7 @@ void ConsoleLogFrame::OnFlushLimiterTimer( wxTimerEvent& )
m_flushevent_counter = 0;
wxCommandEvent sendevt( wxEVT_FlushQueue );
wxCommandEvent sendevt( pxEvt_FlushQueue );
GetEventHandler()->AddPendingEvent( sendevt );
}
@ -743,9 +748,8 @@ const ConsoleLogFrame* Pcsx2App::GetProgramLog() const
void Pcsx2App::ProgramLog_PostEvent( wxEvent& evt )
{
// New console log object model makes this check obsolete:
//if( m_ProgramLogBox == NULL ) return;
GetProgramLog()->GetEventHandler()->AddPendingEvent( evt );
if( ConsoleLogFrame* proglog = GetProgramLog() )
proglog->GetEventHandler()->AddPendingEvent( evt );
}
// --------------------------------------------------------------------------------------
@ -811,7 +815,7 @@ template< const IConsoleWriter& secondary >
static void __concall ConsoleToWindow_SetTitle( const wxString& title )
{
secondary.SetTitle(title);
wxCommandEvent evt( wxEVT_SetTitleText );
wxCommandEvent evt( pxEvt_SetTitleText );
evt.SetString( title );
wxGetApp().ProgramLog_PostEvent( evt );
}

View File

@ -18,7 +18,7 @@
#include "App.h"
BEGIN_DECLARE_EVENT_TYPES()
DECLARE_EVENT_TYPE(wxEVT_DockConsole, -1)
DECLARE_EVENT_TYPE(pxEvt_DockConsole, -1)
END_DECLARE_EVENT_TYPES()
static const bool EnableThreadedLoggingTest = false; //true;
@ -267,6 +267,7 @@ protected:
void OnLogSourceChanged(wxCommandEvent& event);
virtual void OnCloseWindow(wxCloseEvent& event);
virtual void OnDestroyWindow(wxWindowDestroyEvent& event);
void OnSetTitle( wxCommandEvent& event );
void OnDockedMove( wxCommandEvent& event );

View File

@ -107,9 +107,9 @@ Dialogs::AboutBoxDialog::AboutBoxDialog( wxWindow* parent )
AuthLogoSizer += 7;
AuthLogoSizer += contribs;
ContribSizer.AddStretchSpacer( 1 );
ContribSizer += pxStretchSpacer( 1 );
ContribSizer += m_bitmap_dualshock | StdSpace();
ContribSizer.AddStretchSpacer( 1 );
ContribSizer += pxStretchSpacer( 1 );
// Main (top-level) layout

View File

@ -47,7 +47,8 @@ Dialogs::AssertionDialog::AssertionDialog( const wxString& text, const wxString&
traceArea->WriteText( stacktrace );
traceArea->SetMinSize( wxSize( GetIdealWidth()-24, (fonty+1)*18 ) );
traceArea->ShowPosition(0);
traceArea->SetInsertionPoint( 0 );
traceArea->ShowPosition( 0 );
}
*this += Heading( text );

View File

@ -21,8 +21,20 @@
using namespace pxSizerFlags;
// defined in MemoryCardsPanel.cpp
extern wxFilePickerCtrl* CreateMemoryCardFilePicker( wxWindow* parent, uint portidx, uint slotidx, const wxString& filename=wxEmptyString );
wxFilePickerCtrl* CreateMemoryCardFilePicker( wxWindow* parent, uint portidx, uint slotidx, const wxString& filename=wxEmptyString )
{
return new wxFilePickerCtrl( parent, wxID_ANY, filename,
wxsFormat(_("Select memorycard for Port %u / Slot %u"), portidx+1, slotidx+1), // picker window title
L"*.ps2", // default wildcard
wxDefaultPosition, wxDefaultSize,
wxFLP_DEFAULT_STYLE & ~wxFLP_FILE_MUST_EXIST
);
}
/*pxSetToolTip( m_button_Recreate, pxE( ".Tooltip:MemoryCard:Recreate",
L"Deletes the existing memory card and creates a new one. All existing card contents will be lost."
) );*/
Dialogs::CreateMemoryCardDialog::CreateMemoryCardDialog( wxWindow* parent, uint port, uint slot, const wxString& filepath )
: BaseApplicableDialog( parent, _("Create a new MemoryCard..."), wxVERTICAL )

View File

@ -20,6 +20,7 @@
#include "ModalPopups.h"
#include "Panels/ConfigurationPanels.h"
#include <wx/file.h>
#include <wx/filepicker.h>
using namespace Panels;
using namespace pxSizerFlags;
@ -74,16 +75,24 @@ FirstTimeWizard::UsermodePage::UsermodePage( wxWizard* parent ) :
*this += panel | pxExpand;
Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler(FirstTimeWizard::UsermodePage::OnUsermodeChanged) );
Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler(UsermodePage::OnUsermodeChanged) );
Connect( m_panel_UserSel->GetDirPickerId(), wxEVT_COMMAND_DIRPICKER_CHANGED, wxCommandEventHandler(UsermodePage::OnCustomDirChanged) );
}
void FirstTimeWizard::UsermodePage::OnUsermodeChanged( wxCommandEvent& evt )
{
evt.Skip();
m_panel_UserSel->Apply();
g_Conf->Folders.ApplyDefaults();
m_dirpick_settings->Reset();
}
void FirstTimeWizard::UsermodePage::OnCustomDirChanged( wxCommandEvent& evt )
{
OnUsermodeChanged( evt );
}
// ----------------------------------------------------------------------------
FirstTimeWizard::FirstTimeWizard( wxWindow* parent )
: wxWizard( parent, wxID_ANY, _("PCSX2 First Time Configuration") )

View File

@ -39,6 +39,7 @@ protected:
protected:
void OnUsermodeChanged( wxCommandEvent& evt );
void OnCustomDirChanged( wxCommandEvent& evt );
};
protected:

View File

@ -26,6 +26,7 @@ protected:
wxWindow* m_WindowBound;
public:
virtual ~IsoDropTarget() throw() { }
IsoDropTarget( wxWindow* parent ) : wxFileDropTarget()
{
m_WindowBound = parent;

View File

@ -95,9 +95,17 @@ void MainEmuFrame::OnCloseWindow(wxCloseEvent& evt)
if( StateCopy_InvokeOnSaveComplete( new InvokeAction_MenuCommand( MenuId_Exit ) ) ) return;
}
wxGetApp().PrepForExit();
sApp.OnMainFrameClosed();
m_menuCDVD.Remove( MenuId_IsoSelector );
//m_menuCDVD.Delete( MenuId_IsoSelector );
wxGetApp().PrepForExit();
sApp.OnMainFrameClosed( GetId() );
evt.Skip();
}
void MainEmuFrame::OnDestroyWindow( wxWindowDestroyEvent& evt )
{
evt.Skip();
}
@ -462,20 +470,19 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title)
m_MenuItem_Console.Check( g_Conf->ProgLogBox.Visible );
ConnectMenus();
Connect( wxEVT_MOVE, wxMoveEventHandler (MainEmuFrame::OnMoveAround) );
Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler(MainEmuFrame::OnCloseWindow) );
Connect( wxEVT_MOVE, wxMoveEventHandler (MainEmuFrame::OnMoveAround) );
Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler (MainEmuFrame::OnCloseWindow) );
Connect( wxEVT_DESTROY, wxWindowDestroyEventHandler (MainEmuFrame::OnDestroyWindow) );
Connect( wxEVT_SET_FOCUS, wxFocusEventHandler(MainEmuFrame::OnFocus) );
Connect( wxEVT_SET_FOCUS, wxFocusEventHandler (MainEmuFrame::OnFocus) );
Connect( wxEVT_ACTIVATE, wxActivateEventHandler(MainEmuFrame::OnActivate) );
Connect( wxEVT_ACTIVATE, wxActivateEventHandler (MainEmuFrame::OnActivate) );
SetDropTarget( new IsoDropTarget( this ) );
}
MainEmuFrame::~MainEmuFrame() throw()
{
m_menuCDVD.Remove( MenuId_IsoSelector );
if( m_RestartEmuOnDelete )
{
sApp.SetExitOnFrameDelete( false );

View File

@ -227,16 +227,17 @@ public:
bool IsPaused() const { return GetMenuBar()->IsChecked( MenuId_Sys_SuspendResume ); }
void UpdateIsoSrcSelection();
void RemoveCdvdMenu();
protected:
void ApplySettings();
void ApplyCoreStatus();
void SaveEmuOptions();
void InitLogBoxPosition( AppConfig::ConsoleLogOptions& conf );
void OnCloseWindow( wxCloseEvent& evt );
void OnDestroyWindow( wxWindowDestroyEvent& evt );
void OnMoveAround( wxMoveEvent& evt );
void OnFocus( wxFocusEvent& evt );
void OnActivate( wxActivateEvent& evt );

View File

@ -70,8 +70,16 @@ static void WipeSettings()
//wxRmdir( GetSettingsFolder().ToString() );
g_Conf = new AppConfig();
sMainFrame.RemoveCdvdMenu();
}
void MainEmuFrame::RemoveCdvdMenu()
{
if( wxMenuItem* item = m_menuCDVD.FindItem(MenuId_IsoSelector) )
m_menuCDVD.Remove( item );
}
class RestartEverything_WhenCoreThreadStops : public EventListener_CoreThread,
public virtual IDeletableObject
{

View File

@ -0,0 +1,206 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2009 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 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 for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "App.h"
#include "ConfigurationPanels.h"
#include "Dialogs/ConfigurationDialog.h"
#include <wx/bookctrl.h>
using namespace Dialogs;
// -----------------------------------------------------------------------
// This method should be called by the parent dalog box of a configuration
// on dialog destruction. It asserts if the ApplyList hasn't been cleaned up
// and then cleans it up forcefully.
//
void ApplyStateStruct::DoCleanup() throw()
{
pxAssertMsg( PanelList.size() != 0, L"PanelList list hasn't been cleaned up." );
PanelList.clear();
ParentBook = NULL;
}
void ApplyStateStruct::StartBook( wxBookCtrlBase* book )
{
pxAssertDev( ParentBook == NULL, "An ApplicableConfig session is already in progress." );
ParentBook = book;
}
void ApplyStateStruct::StartWizard()
{
pxAssertDev( ParentBook == NULL, "An ApplicableConfig session is already in progress." );
}
// -----------------------------------------------------------------------
//
// Parameters:
// pageid - identifier of the page to apply settings for. All other pages will be
// skipped. If pageid is negative (-1) then all pages are applied.
//
// Returns false if one of the panels fails input validation (in which case dialogs
// should not be closed, etc).
//
bool ApplyStateStruct::ApplyPage( int pageid )
{
bool retval = true;
// Save these settings so we can restore them if the Apply fails.
DocsModeType oldDocsMode = DocsFolderMode;
wxDirName oldSettingsFolder = SettingsFolder;
bool oldUseDefSet = UseDefaultSettingsFolder;
AppConfig confcopy( *g_Conf );
try
{
PanelApplyList_t::iterator yay = PanelList.begin();
while( yay != PanelList.end() )
{
//DbgCon.Status( L"Writing settings for: " + (*yay)->GetLabel() );
if( (pageid < 0) || (*yay)->IsOnPage( pageid ) )
(*yay)->Apply();
yay++;
}
// If an exception is thrown above, this code below won't get run.
// (conveniently skipping any option application! :D)
// Note: apply first, then save -- in case the apply fails.
AppApplySettings( &confcopy );
}
catch( Exception::CannotApplySettings& ex )
{
DocsFolderMode = oldDocsMode;
SettingsFolder = oldSettingsFolder;
UseDefaultSettingsFolder = oldUseDefSet;
*g_Conf = confcopy;
if( ex.IsVerbose )
{
wxMessageBox( ex.FormatDisplayMessage(), _("Cannot apply settings...") );
if( ex.GetPanel() != NULL )
ex.GetPanel()->SetFocusToMe();
}
retval = false;
}
catch( ... )
{
DocsFolderMode = oldDocsMode;
SettingsFolder = oldSettingsFolder;
UseDefaultSettingsFolder = oldUseDefSet;
*g_Conf = confcopy;
throw;
}
return retval;
}
// Returns false if one of the panels fails input validation (in which case dialogs
// should not be closed, etc).
bool ApplyStateStruct::ApplyAll()
{
return ApplyPage( -1 );
}
// --------------------------------------------------------------------------------------
// BaseApplicableConfigPanel Implementations
// --------------------------------------------------------------------------------------
IApplyState* BaseApplicableConfigPanel::FindApplyStateManager() const
{
wxWindow* millrun = this->GetParent();
while( millrun != NULL )
{
if( BaseApplicableDialog* dialog = wxDynamicCast( millrun, BaseApplicableDialog ) )
return (IApplyState*)dialog;
if( ApplicableWizardPage* wizpage = wxDynamicCast( millrun, ApplicableWizardPage ) )
return (IApplyState*)wizpage;
millrun = millrun->GetParent();
}
return NULL;
}
BaseApplicableConfigPanel::~BaseApplicableConfigPanel() throw()
{
if( IApplyState* iapp = FindApplyStateManager() )
iapp->GetApplyState().PanelList.remove( this );
}
BaseApplicableConfigPanel::BaseApplicableConfigPanel( wxWindow* parent, wxOrientation orient )
: wxPanelWithHelpers( parent, orient )
, m_AppStatusHelper( this )
{
Init();
}
BaseApplicableConfigPanel::BaseApplicableConfigPanel( wxWindow* parent, wxOrientation orient, const wxString& staticLabel )
: wxPanelWithHelpers( parent, orient, staticLabel )
, m_AppStatusHelper( this )
{
Init();
}
void BaseApplicableConfigPanel::SetFocusToMe()
{
if( (m_OwnerBook == NULL) || (m_OwnerPage == wxID_NONE) ) return;
m_OwnerBook->SetSelection( m_OwnerPage );
}
BEGIN_DECLARE_EVENT_TYPES()
DECLARE_EVENT_TYPE( pxEvt_ApplySettings, -1 )
END_DECLARE_EVENT_TYPES()
DEFINE_EVENT_TYPE( pxEvt_ApplySettings )
void BaseApplicableConfigPanel::Init()
{
// We need to bind to an event that occurs *after* all window and child
// window mess has been created. Unfortunately the WindowCreate event handler
// is immediate, and depends on the platform for how it "works", and thus
// useless. Solution: Create our own! :)
//Connect( wxEVT_CREATE, wxWindowCreateEventHandler (BaseApplicableConfigPanel::OnCreateWindow) );
Connect( pxEvt_ApplySettings, wxCommandEventHandler (BaseApplicableConfigPanel::OnSettingsApplied) );
if( IApplyState* iapp = FindApplyStateManager() )
{
ApplyStateStruct& applyState( iapp->GetApplyState() );
m_OwnerPage = applyState.CurOwnerPage;
m_OwnerBook = applyState.ParentBook;
applyState.PanelList.push_back( this );
}
wxCommandEvent applyEvent( pxEvt_ApplySettings );
applyEvent.SetId( GetId() );
AddPendingEvent( applyEvent );
}
//void BaseApplicableConfigPanel::OnCreateWindow( wxWindowCreateEvent& evt )
void BaseApplicableConfigPanel::OnSettingsApplied( wxCommandEvent& evt )
{
evt.Skip();
if( evt.GetId() == GetId() ) AppStatusEvent_OnSettingsApplied();
}
void BaseApplicableConfigPanel::AppStatusEvent_OnSettingsApplied() {}

View File

@ -24,17 +24,35 @@
#include <wx/filepicker.h>
#include <wx/listbox.h>
// ------------------------------------------------------------------------
// =====================================================================================================
// BaseSelectorPanel
// =====================================================================================================
Panels::BaseSelectorPanel::BaseSelectorPanel( wxWindow* parent )
: BaseApplicableConfigPanel( parent, wxVERTICAL )
{
Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler(PluginSelectorPanel::OnFolderChanged), NULL, this );
Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler (BaseSelectorPanel::OnFolderChanged) );
//Connect( wxEVT_ACTIVATE, wxActivateEventHandler (BaseSelectorPanel::OnActivate) );
Connect( wxEVT_SHOW, wxShowEventHandler (BaseSelectorPanel::OnShow) );
}
Panels::BaseSelectorPanel::~BaseSelectorPanel() throw()
{
}
void Panels::BaseSelectorPanel::OnActivate(wxActivateEvent& evt)
{
evt.Skip();
if( !evt.GetActive() ) return;
OnShown();
}
void Panels::BaseSelectorPanel::OnShow(wxShowEvent& evt)
{
evt.Skip();
if( !evt.GetShow() ) return;
OnShown();
}
void Panels::BaseSelectorPanel::OnShown()
{
if( !ValidateEnumerationStatus() )
@ -61,7 +79,9 @@ void Panels::BaseSelectorPanel::OnFolderChanged( wxFileDirPickerEvent& evt )
OnShown();
}
// ----------------------------------------------------------------------------
// =====================================================================================================
// BiosSelectorPanel
// =====================================================================================================
Panels::BiosSelectorPanel::BiosSelectorPanel( wxWindow* parent, int idealWidth )
: BaseSelectorPanel( parent )
, m_ComboBox( *new wxListBox( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_SINGLE | wxLB_SORT | wxLB_NEEDED_SB ) )
@ -87,25 +107,6 @@ Panels::BiosSelectorPanel::~BiosSelectorPanel() throw ()
{
}
bool Panels::BiosSelectorPanel::ValidateEnumerationStatus()
{
bool validated = true;
// Impl Note: ScopedPtr used so that resources get cleaned up if an exception
// occurs during file enumeration.
ScopedPtr<wxArrayString> bioslist( new wxArrayString() );
if( m_FolderPicker.GetPath().Exists() )
wxDir::GetAllFiles( m_FolderPicker.GetPath().ToString(), bioslist, L"*.*", wxDIR_FILES );
if( !m_BiosList || (*bioslist != *m_BiosList) )
validated = false;
m_BiosList.SwapPtr( bioslist );
return validated;
}
void Panels::BiosSelectorPanel::Apply()
{
int sel = m_ComboBox.GetSelection();
@ -130,6 +131,25 @@ void Panels::BiosSelectorPanel::AppStatusEvent_OnSettingsApplied()
{
}
bool Panels::BiosSelectorPanel::ValidateEnumerationStatus()
{
bool validated = true;
// Impl Note: ScopedPtr used so that resources get cleaned up if an exception
// occurs during file enumeration.
ScopedPtr<wxArrayString> bioslist( new wxArrayString() );
if( m_FolderPicker.GetPath().Exists() )
wxDir::GetAllFiles( m_FolderPicker.GetPath().ToString(), bioslist, L"*.*", wxDIR_FILES );
if( !m_BiosList || (*bioslist != *m_BiosList) )
validated = false;
m_BiosList.SwapPtr( bioslist );
return validated;
}
void Panels::BiosSelectorPanel::DoRefresh()
{
if( !m_BiosList ) return;

View File

@ -23,51 +23,61 @@
#include <wx/image.h>
#include <wx/statline.h>
#include <wx/spinctrl.h>
#include <wx/dnd.h>
#include "AppCommon.h"
#include "ApplyState.h"
// --------------------------------------------------------------------------------------
// pxUniformTable
// --------------------------------------------------------------------------------------
// TODO : Move this class to the common Utilities lib, if it proves useful. :)
/*
class pxUniformTable : public wxFlexGridSizer
{
protected:
int m_curcell;
SafeArray<wxPanelWithHelpers*> m_panels;
public:
pxUniformTable( wxWindow* parent, int numcols, int numrows, const wxString* staticBoxLabels=NULL );
virtual ~pxUniformTable() throw() {}
int GetCellCount() const
{
return m_panels.GetLength();
}
wxPanelWithHelpers* operator()( int col, int row )
{
return m_panels[(col*GetCols()) + row];
}
wxPanelWithHelpers* operator[]( int cellidx )
{
return m_panels[cellidx];
}
};
*/
namespace Panels
{
//////////////////////////////////////////////////////////////////////////////////////////
// --------------------------------------------------------------------------------------
// DirPickerPanel
// --------------------------------------------------------------------------------------
// A simple panel which provides a specialized configurable directory picker with a
// "[x] Use Default setting" option, which enables or disables the panel.
//
class DirPickerPanel : public BaseApplicableConfigPanel
{
protected:
FoldersEnum_t m_FolderId;
wxDirPickerCtrl* m_pickerCtrl;
pxCheckBox* m_checkCtrl;
public:
DirPickerPanel( wxWindow* parent, FoldersEnum_t folderid, const wxString& label, const wxString& dialogLabel );
DirPickerPanel( wxWindow* parent, FoldersEnum_t folderid, const wxString& dialogLabel );
virtual ~DirPickerPanel() throw() { }
void Apply();
void AppStatusEvent_OnSettingsApplied();
void Reset();
wxDirName GetPath() const;
void SetPath( const wxString& src );
DirPickerPanel& SetStaticDesc( const wxString& msg );
DirPickerPanel& SetToolTip( const wxString& tip );
wxWindowID GetId() const;
wxWindowID GetPanelId() const { return m_windowId; }
protected:
void Init( FoldersEnum_t folderid, const wxString& dialogLabel, bool isCompact );
void UseDefaultPath_Click( wxCommandEvent &event );
void Explore_Click( wxCommandEvent &event );
void UpdateCheckStatus( bool someNoteworthyBoolean );
};
// --------------------------------------------------------------------------------------
// UsermodeSelectionPanel / LanguageSelectionPanel
// --------------------------------------------------------------------------------------
class UsermodeSelectionPanel : public BaseApplicableConfigPanel
{
protected:
pxRadioPanel* m_radio_UserMode;
DirPickerPanel* m_dirpicker_custom;
public:
virtual ~UsermodeSelectionPanel() throw() { }
@ -75,10 +85,12 @@ namespace Panels
void Apply();
void AppStatusEvent_OnSettingsApplied();
wxWindowID GetDirPickerId() const { return m_dirpicker_custom ? m_dirpicker_custom->GetId() : 0; }
protected:
void OnRadioChanged( wxCommandEvent& evt );
};
//////////////////////////////////////////////////////////////////////////////////////////
//
class LanguageSelectionPanel : public BaseApplicableConfigPanel
{
protected:
@ -104,6 +116,8 @@ namespace Panels
public:
CpuPanelEE( wxWindow* parent );
virtual ~CpuPanelEE() throw() {}
void Apply();
void AppStatusEvent_OnSettingsApplied();
@ -119,6 +133,8 @@ namespace Panels
public:
CpuPanelVU( wxWindow* parent );
virtual ~CpuPanelVU() throw() {}
void Apply();
void AppStatusEvent_OnSettingsApplied();
@ -283,6 +299,7 @@ namespace Panels
pxCheckBox* m_check_vuMinMax;
public:
virtual ~SpeedHacksPanel() throw() {}
SpeedHacksPanel( wxWindow* parent );
void Apply();
void EnableStuff();
@ -320,94 +337,15 @@ namespace Panels
void AppStatusEvent_OnSettingsApplied();
};
// --------------------------------------------------------------------------------------
// MemoryCardsPanel
// --------------------------------------------------------------------------------------
class MemoryCardsPanel : public BaseApplicableConfigPanel
{
class SingleCardPanel : public BaseApplicableConfigPanel
{
protected:
uint m_port, m_slot;
wxFilePickerCtrl* m_filepicker;
wxCheckBox* m_check_Disable;
wxButton* m_button_Recreate;
// Displays card status: Size, Formatted, etc.
wxStaticText* m_label_Status;
public:
SingleCardPanel( wxWindow* parent, uint portidx, uint slotidx );
virtual ~SingleCardPanel() throw() { }
void Apply();
bool UpdateStatusLine( const wxFileName& mcdfilename );
protected:
void AppStatusEvent_OnSettingsApplied();
void OnFileChanged( wxCommandEvent& evt );
void OnRecreate_Clicked( wxCommandEvent& evt );
};
protected:
pxCheckBox* m_check_Ejection;
pxCheckBox* m_check_Multitap[2];
SingleCardPanel* m_CardPanel[2][4];
public:
MemoryCardsPanel( wxWindow* parent );
virtual ~MemoryCardsPanel() throw() { }
void Apply();
protected:
void OnMultitapChecked( wxCommandEvent& evt );
void AppStatusEvent_OnSettingsApplied();
};
// --------------------------------------------------------------------------------------
// DirPickerPanel
// --------------------------------------------------------------------------------------
// A simple panel which provides a specialized configurable directory picker with a
// "[x] Use Default setting" option, which enables or disables the panel.
//
class DirPickerPanel : public BaseApplicableConfigPanel
{
protected:
FoldersEnum_t m_FolderId;
wxDirPickerCtrl* m_pickerCtrl;
pxCheckBox* m_checkCtrl;
public:
DirPickerPanel( wxWindow* parent, FoldersEnum_t folderid, const wxString& label, const wxString& dialogLabel );
virtual ~DirPickerPanel() throw() { }
void Apply();
void AppStatusEvent_OnSettingsApplied();
void Reset();
wxDirName GetPath() const;
DirPickerPanel& SetStaticDesc( const wxString& msg );
DirPickerPanel& SetToolTip( const wxString& tip );
protected:
void UseDefaultPath_Click( wxCommandEvent &event );
void Explore_Click( wxCommandEvent &event );
void UpdateCheckStatus( bool someNoteworthyBoolean );
};
//////////////////////////////////////////////////////////////////////////////////////////
//
class SettingsDirPickerPanel : public DirPickerPanel
{
public:
SettingsDirPickerPanel( wxWindow* parent );
};
//////////////////////////////////////////////////////////////////////////////////////////
//
// --------------------------------------------------------------------------------------
// BasePathsPanel / StandardPathsPanel
// --------------------------------------------------------------------------------------
class BasePathsPanel : public wxPanelWithHelpers
{
public:
@ -416,8 +354,6 @@ namespace Panels
protected:
};
//////////////////////////////////////////////////////////////////////////////////////////
//
class StandardPathsPanel : public BasePathsPanel
{
public:
@ -429,6 +365,8 @@ namespace Panels
// --------------------------------------------------------------------------------------
class BaseSelectorPanel: public BaseApplicableConfigPanel
{
typedef BaseApplicableConfigPanel _parent;
public:
virtual ~BaseSelectorPanel() throw();
BaseSelectorPanel( wxWindow* parent );
@ -441,6 +379,8 @@ namespace Panels
protected:
virtual void DoRefresh()=0;
virtual bool ValidateEnumerationStatus()=0;
void OnActivate(wxActivateEvent& evt);
void OnShow(wxShowEvent& evt);
};
// --------------------------------------------------------------------------------------
@ -464,6 +404,32 @@ namespace Panels
virtual bool ValidateEnumerationStatus();
};
class MemoryCardListPanel;
class MemoryCardInfoPanel;
// --------------------------------------------------------------------------------------
// MemoryCardsPanel
// --------------------------------------------------------------------------------------
class MemoryCardsPanel : public BaseApplicableConfigPanel
{
protected:
MemoryCardListPanel* m_panel_AllKnownCards;
MemoryCardInfoPanel* m_panel_cardinfo[2][4];
pxCheckBox* m_check_Ejection;
pxCheckBox* m_check_Multitap[2];
uint m_Bindings[2][4];
public:
MemoryCardsPanel( wxWindow* parent );
virtual ~MemoryCardsPanel() throw() { }
void Apply();
protected:
void OnMultitapChecked( wxCommandEvent& evt );
void AppStatusEvent_OnSettingsApplied();
};
// --------------------------------------------------------------------------------------
// PluginSelectorPanel
// --------------------------------------------------------------------------------------

View File

@ -106,8 +106,6 @@ Panels::AdvancedOptionsFPU::AdvancedOptionsFPU( wxWindow* parent )
m_RoundModePanel->Realize();
m_ClampModePanel->Realize();
AppStatusEvent_OnSettingsApplied();
}
@ -122,8 +120,6 @@ Panels::AdvancedOptionsVU::AdvancedOptionsVU( wxWindow* parent )
m_RoundModePanel->Realize();
m_ClampModePanel->Realize();
AppStatusEvent_OnSettingsApplied();
}
Panels::CpuPanelEE::CpuPanelEE( wxWindow* parent )
@ -181,8 +177,6 @@ Panels::CpuPanelEE::CpuPanelEE( wxWindow* parent )
*this += new wxButton( this, wxID_DEFAULT, _("Restore Defaults") ) | StdButton();
Connect( wxID_DEFAULT, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CpuPanelEE::OnRestoreDefaults ) );
AppStatusEvent_OnSettingsApplied();
}
Panels::CpuPanelVU::CpuPanelVU( wxWindow* parent )
@ -232,8 +226,6 @@ Panels::CpuPanelVU::CpuPanelVU( wxWindow* parent )
*this += new wxButton( this, wxID_DEFAULT, _("Restore Defaults") ) | StdButton();
Connect( wxID_DEFAULT, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CpuPanelVU::OnRestoreDefaults ) );
AppStatusEvent_OnSettingsApplied();
}
void Panels::CpuPanelEE::Apply()
@ -246,7 +238,7 @@ void Panels::CpuPanelEE::Apply()
void Panels::CpuPanelEE::AppStatusEvent_OnSettingsApplied()
{
m_panel_RecEE->Enable( x86caps.hasStreamingSIMD2Extensions );
// IOP rec should work fine on any CPU. :D
//m_panel_RecIOP->Enable( x86caps.hasStreamingSIMD2Extensions );

View File

@ -15,12 +15,15 @@
#include "PrecompiledHeader.h"
#include "ConfigurationPanels.h"
#include "Dialogs/ModalPopups.h"
#include <wx/stdpaths.h>
#include <wx/file.h>
#include <wx/dir.h>
#include <wx/filepicker.h>
using namespace pxSizerFlags;
static wxString GetNormalizedConfigFolder( FoldersEnum_t folderId )
{
return Path::Normalize( g_Conf->Folders.IsDefault( folderId ) ? PathDefs::Get(folderId) : g_Conf->Folders[folderId] );
@ -44,12 +47,33 @@ void Panels::DirPickerPanel::UseDefaultPath_Click( wxCommandEvent &evt )
{
evt.Skip();
pxAssert( (m_pickerCtrl != NULL) && (m_checkCtrl != NULL) );
UpdateCheckStatus( m_checkCtrl->IsChecked() );
UpdateCheckStatus( m_checkCtrl ? m_checkCtrl->IsChecked() : false );
}
void Panels::DirPickerPanel::Explore_Click( wxCommandEvent &evt )
{
pxExplore( m_pickerCtrl->GetPath() );
wxString path( m_pickerCtrl->GetPath() );
if( !wxDirExists(path) )
{
wxDialogWithHelpers createPathDlg( NULL, _("Path does not exist"), wxVERTICAL );
createPathDlg.SetIdealWidth( 600 );
createPathDlg += createPathDlg.Text( path ) | StdCenter();
createPathDlg += createPathDlg.Heading( pxE( ".Error:Explore:CreatePath",
L"The specified path/directory does not exist. Would you like to create it?" )
);
wxWindowID result = pxIssueConfirmation( createPathDlg,
MsgButtons().Custom(_("Create")).Cancel(),
L"DirPicker:CreateOnExplore"
);
if( result == wxID_CANCEL ) return;
wxMkdir( path );
}
pxExplore( path );
}
// ------------------------------------------------------------------------
@ -58,17 +82,22 @@ void Panels::DirPickerPanel::Explore_Click( wxCommandEvent &evt )
//
Panels::DirPickerPanel::DirPickerPanel( wxWindow* parent, FoldersEnum_t folderid, const wxString& label, const wxString& dialogLabel )
: BaseApplicableConfigPanel( parent, wxVERTICAL, label )
{
Init( folderid, dialogLabel, false );
}
Panels::DirPickerPanel::DirPickerPanel( wxWindow* parent, FoldersEnum_t folderid, const wxString& dialogLabel )
: BaseApplicableConfigPanel( parent, wxVERTICAL )
{
Init( folderid, dialogLabel, true );
}
void Panels::DirPickerPanel::Init( FoldersEnum_t folderid, const wxString& dialogLabel, bool isCompact )
{
m_FolderId = folderid;
m_pickerCtrl = NULL;
m_checkCtrl = NULL;
m_checkCtrl = new pxCheckBox( this, _("Use default setting") );
wxFlexGridSizer& s_lower( *new wxFlexGridSizer( 2, 0, 4 ) );
s_lower.AddGrowableCol( 1 );
// Force the Dir Picker to use a text control. This isn't standard on Linux/GTK but it's much
// more usable, so to hell with standards.
@ -82,30 +111,53 @@ Panels::DirPickerPanel::DirPickerPanel( wxWindow* parent, FoldersEnum_t folderid
if( !wxDir::Exists( normalized ) )
wxMkdir( normalized );
if( !isCompact )
{
m_checkCtrl = new pxCheckBox( this, _("Use default setting") );
pxSetToolTip( m_checkCtrl, pxE( ".Tooltip:DirPicker:UseDefault",
L"When checked this folder will automatically reflect the default associated with PCSX2's current usermode setting. " )
);
Connect( m_checkCtrl->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DirPickerPanel::UseDefaultPath_Click ) );
}
m_pickerCtrl = new wxDirPickerCtrl( this, wxID_ANY, wxEmptyString, dialogLabel,
wxDefaultPosition, wxDefaultSize, wxDIRP_USE_TEXTCTRL | wxDIRP_DIR_MUST_EXIST
);
GetSizer()->Add( m_pickerCtrl, wxSizerFlags().Border(wxLEFT | wxRIGHT | wxTOP, 5).Expand() );
s_lower.Add( m_checkCtrl );
pxSetToolTip( m_checkCtrl, pxE( ".Tooltip:DirPicker:UseDefault",
L"When checked this folder will automatically reflect the default associated with PCSX2's current usermode setting. " )
);
#ifndef __WXGTK__
// GTK+ : The wx implementation of Explore isn't reliable, so let's not even put the
// button on the dialogs for now.
wxButton* b_explore( new wxButton( this, wxID_ANY, _("Open in Explorer") ) );
pxSetToolTip( b_explore, _("Open an explorer window to this folder.") );
s_lower.Add( b_explore, pxSizerFlags::StdButton().Align( wxALIGN_RIGHT ) );
Connect( b_explore->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DirPickerPanel::Explore_Click ) );
#endif
GetSizer()->Add( &s_lower, wxSizerFlags().Expand() );
if( isCompact )
{
wxFlexGridSizer& s_compact( *new wxFlexGridSizer( 2, 0, 4 ) );
s_compact.AddGrowableCol( 0 );
s_compact += m_pickerCtrl | pxExpand;
#ifndef __WXGTK__
s_compact += b_explore;
#endif
*this += s_compact | pxExpand; //.Border(wxLEFT | wxRIGHT | wxTOP, 5);
}
else
{
wxBoxSizer& s_lower( *new wxBoxSizer( wxHORIZONTAL ) );
Connect( m_checkCtrl->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DirPickerPanel::UseDefaultPath_Click ) );
s_lower += m_checkCtrl | pxMiddle;
#ifndef __WXGTK__
s_lower += pxStretchSpacer(1);
s_lower += b_explore;
#endif
*this += m_pickerCtrl | pxExpand.Border(wxLEFT | wxRIGHT | wxTOP, StdPadding);
*this += s_lower | pxExpand.Border(wxLEFT | wxRIGHT, StdPadding);
}
// wx warns when paths don't exist, but this is typically normal when the wizard
// creates its child controls. So let's ignore them.
@ -125,12 +177,23 @@ Panels::DirPickerPanel& Panels::DirPickerPanel::SetToolTip( const wxString& tip
return *this;
}
wxWindowID Panels::DirPickerPanel::GetId() const
{
return m_pickerCtrl->GetId();
}
void Panels::DirPickerPanel::Reset()
{
const bool isDefault = g_Conf->Folders.IsDefault( m_FolderId );
m_checkCtrl->SetValue( isDefault );
m_pickerCtrl->Enable( !isDefault );
m_pickerCtrl->SetPath( GetNormalizedConfigFolder( m_FolderId ) );
if( m_checkCtrl )
m_checkCtrl->SetValue( isDefault );
if( m_pickerCtrl )
{
m_pickerCtrl->Enable( m_checkCtrl ? !isDefault : true );
m_pickerCtrl->SetPath( GetNormalizedConfigFolder( m_FolderId ) );
}
}
void Panels::DirPickerPanel::AppStatusEvent_OnSettingsApplied()
@ -140,10 +203,16 @@ void Panels::DirPickerPanel::AppStatusEvent_OnSettingsApplied()
void Panels::DirPickerPanel::Apply()
{
g_Conf->Folders.Set( m_FolderId, m_pickerCtrl->GetPath(), m_checkCtrl->GetValue() );
if( !m_pickerCtrl ) return;
g_Conf->Folders.Set( m_FolderId, m_pickerCtrl->GetPath(), m_checkCtrl ? m_checkCtrl->GetValue() : false );
}
wxDirName Panels::DirPickerPanel::GetPath() const
{
return wxDirName( m_pickerCtrl->GetPath() );
return wxDirName( m_pickerCtrl ? m_pickerCtrl->GetPath() : wxEmptyString );
}
void Panels::DirPickerPanel::SetPath( const wxString& newPath )
{
m_pickerCtrl->SetPath( newPath );
}

View File

@ -0,0 +1,195 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2009 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 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 for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "ConfigurationPanels.h"
#include "MemoryCardListView.h"
#include <wx/filepicker.h>
#include <wx/ffile.h>
#include <wx/dir.h>
using namespace pxSizerFlags;
using namespace Panels;
static bool IsMcdFormatted( wxFFile& fhand )
{
static const char formatted_string[] = "Sony PS2 Memory Card Format";
static const int fmtstrlen = sizeof( formatted_string )-1;
char dest[fmtstrlen];
fhand.Read( dest, fmtstrlen );
return memcmp( formatted_string, dest, fmtstrlen ) == 0;
}
static bool EnumerateMemoryCard( McdListItem& dest, const wxString& filename )
{
Console.WriteLn( filename.c_str() );
wxFFile mcdFile( filename );
if( !mcdFile.IsOpened() ) return false; // wx should log the error for us.
if( mcdFile.Length() < (1024*528) )
{
Console.Warning( "... MemoryCard appears to be truncated. Ignoring." );
return false;
}
dest.Filename = filename;
dest.SizeInMB = (uint)(mcdFile.Length() / (1024 * 528 * 2));
dest.IsFormatted = IsMcdFormatted( mcdFile );
wxFileName(filename).GetTimes( NULL, &dest.DateModified, &dest.DateCreated );
return true;
}
static int EnumerateMemoryCards( McdList& dest, const wxArrayString& files )
{
int pushed = 0;
Console.WriteLn( Color_StrongBlue, "Enumerating MemoryCards..." );
for( size_t i=0; i<files.GetCount(); ++i )
{
ConsoleIndentScope con_indent;
McdListItem mcdItem;
if( EnumerateMemoryCard(mcdItem, files[i]) )
{
dest.push_back( mcdItem );
++pushed;
}
}
if( pushed > 0 )
Console.WriteLn( Color_StrongBlue, "MemoryCard Enumeration Complete." );
else
Console.WriteLn( Color_StrongBlue, "No valid MemoryCards found." );
return pushed;
}
// =====================================================================================================
// MemoryCardListPanel
// =====================================================================================================
MemoryCardListPanel::MemoryCardListPanel( wxWindow* parent )
: BaseSelectorPanel( parent )
{
m_FolderPicker = new DirPickerPanel( this, FolderId_MemoryCards,
//_("MemoryCard Search Path:"), // static box label
_("Select folder with PS2 MemoryCards") // dir picker popup label
);
m_listview = new MemoryCardListView(this);
wxButton* button_Create = new wxButton(this, wxID_ANY, _("Create new card..."));
//Connect( m_list_AllKnownCards->GetId(), wxEVT_COMMAND_LEFT_CLICK, MemoryCardsPanel::OnListDrag);
// ------------------------------------
// Sizer / Layout Section
// ------------------------------------
wxBoxSizer& s_buttons (*new wxBoxSizer( wxHORIZONTAL ));
wxBoxSizer& s_leftside (*new wxBoxSizer( wxHORIZONTAL ));
wxBoxSizer& s_rightside (*new wxBoxSizer( wxHORIZONTAL ));
s_leftside += button_Create | StdSpace();
s_buttons += s_leftside | pxAlignLeft;
s_buttons += pxStretchSpacer();
s_buttons += s_rightside | pxAlignRight;
*this += m_FolderPicker | pxExpand;
*this += m_listview | pxExpand;
*this += s_buttons | pxExpand;
m_listview->SetMinSize( wxSize( wxDefaultCoord, 120 ) );
AppStatusEvent_OnSettingsApplied();
Disable();
}
void MemoryCardListPanel::Apply()
{
}
void MemoryCardListPanel::AppStatusEvent_OnSettingsApplied()
{
}
bool Panels::MemoryCardListPanel::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames)
{
if( filenames.GetCount() == 1 && wxFileName(filenames[0]).IsDir() )
{
m_FolderPicker->SetPath( filenames[0] );
return true;
}
return false;
}
bool MemoryCardListPanel::ValidateEnumerationStatus()
{
bool validated = true;
// Impl Note: ScopedPtr used so that resources get cleaned up if an exception
// occurs during file enumeration.
ScopedPtr<McdList> mcdlist( new McdList() );
if( m_FolderPicker->GetPath().Exists() )
{
wxArrayString files;
wxDir::GetAllFiles( m_FolderPicker->GetPath().ToString(), &files, L"*.ps2", wxDIR_FILES );
EnumerateMemoryCards( *mcdlist, files );
}
if( !m_KnownCards || (*mcdlist != *m_KnownCards) )
validated = false;
m_listview->AssignCardsList( NULL );
m_KnownCards.SwapPtr( mcdlist );
return validated;
}
void MemoryCardListPanel::DoRefresh()
{
if( !m_KnownCards ) return;
//m_listview->ClearAll();
//m_listview->CreateColumns();
for( size_t i=0; i<m_KnownCards->size(); ++i )
{
McdListItem& mcditem( (*m_KnownCards)[i] );
for( int port=0; port<2; ++port )
for( int slot=0; slot<4; ++slot )
{
wxFileName right( g_Conf->FullpathToMcd(port, slot) );
right.MakeAbsolute();
wxFileName left( mcditem.Filename );
left.MakeAbsolute();
if( left == right )
{
mcditem.Port = port;
mcditem.Slot = slot;
}
}
}
m_listview->AssignCardsList( m_KnownCards );
}

View File

@ -0,0 +1,135 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2009 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 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 for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "AppCommon.h"
#include <wx/dnd.h>
#include <wx/listctrl.h>
namespace Panels
{
// --------------------------------------------------------------------------------------
// McdListItem
// --------------------------------------------------------------------------------------
struct McdListItem
{
uint SizeInMB; // size, in megabytes!
bool IsFormatted;
wxDateTime DateCreated;
wxDateTime DateModified;
wxFileName Filename; // full pathname
int Port;
int Slot;
McdListItem()
{
Port = -1;
Slot = -1;
}
bool operator==( const McdListItem& right ) const
{
return
OpEqu(SizeInMB) && OpEqu(IsFormatted) &&
OpEqu(DateCreated) && OpEqu(DateModified) &&
OpEqu(Filename);
}
bool operator!=( const McdListItem& right ) const
{
return operator==( right );
}
};
typedef std::vector<McdListItem> McdList;
// --------------------------------------------------------------------------------------
// MemoryCardListView
// --------------------------------------------------------------------------------------
class MemoryCardListView : public wxListView
{
typedef wxListView _parent;
protected:
McdList* m_KnownCards;
public:
virtual ~MemoryCardListView() throw() { }
MemoryCardListView( wxWindow* parent );
virtual void OnListDrag(wxListEvent& evt);
virtual void CreateColumns();
virtual void AssignCardsList( McdList* knownCards, int length=0 );
protected:
// Overrides for wxLC_VIRTUAL
virtual wxString OnGetItemText(long item, long column) const;
virtual int OnGetItemImage(long item) const;
virtual int OnGetItemColumnImage(long item, long column) const;
virtual wxListItemAttr *OnGetItemAttr(long item) const;
};
// --------------------------------------------------------------------------------------
// MemoryCardListPanel
// --------------------------------------------------------------------------------------
class MemoryCardListPanel
: public BaseSelectorPanel
, public wxFileDropTarget
{
protected:
DirPickerPanel* m_FolderPicker;
MemoryCardListView* m_listview;
ScopedPtr<McdList> m_KnownCards;
public:
virtual ~MemoryCardListPanel() throw() {}
MemoryCardListPanel( wxWindow* parent );
protected:
virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames);
virtual void Apply();
virtual void AppStatusEvent_OnSettingsApplied();
virtual void DoRefresh();
virtual bool ValidateEnumerationStatus();
};
// --------------------------------------------------------------------------------------
// MemoryCardInfoPanel
// --------------------------------------------------------------------------------------
class MemoryCardInfoPanel : public BaseApplicableConfigPanel
{
protected:
uint m_port;
uint m_slot;
//wxStaticText* m_label;
wxTextCtrl* m_label;
public:
virtual ~MemoryCardInfoPanel() throw() {}
MemoryCardInfoPanel( wxWindow* parent, uint port, uint slot );
void Apply();
protected:
void AppStatusEvent_OnSettingsApplied();
void paintEvent( wxPaintEvent& evt );
};
};

View File

@ -15,143 +15,184 @@
#include "PrecompiledHeader.h"
#include "ConfigurationPanels.h"
#include "MemoryCardListView.h"
#include "Dialogs/ConfigurationDialog.h"
#include <wx/filepicker.h>
#include <wx/ffile.h>
#include <wx/dir.h>
using namespace pxSizerFlags;
using namespace Panels;
wxFilePickerCtrl* CreateMemoryCardFilePicker( wxWindow* parent, uint portidx, uint slotidx, const wxString& filename=wxEmptyString )
enum McdColumnType
{
return new wxFilePickerCtrl( parent, wxID_ANY, filename,
wxsFormat(_("Select memorycard for Port %u / Slot %u"), portidx+1, slotidx+1), // picker window title
L"*.ps2", // default wildcard
wxDefaultPosition, wxDefaultSize,
wxFLP_DEFAULT_STYLE & ~wxFLP_FILE_MUST_EXIST
);
McdCol_Filename,
McdCol_Mounted,
McdCol_Size,
McdCol_Formatted,
McdCol_DateModified,
McdCol_DateCreated,
McdCol_Path,
McdCol_Count
};
void MemoryCardListView::CreateColumns()
{
struct ColumnInfo
{
wxString name;
wxListColumnFormat align;
};
const ColumnInfo columns[] =
{
{ _("Filename"), wxLIST_FORMAT_LEFT },
{ _("Mounted"), wxLIST_FORMAT_CENTER },
{ _("Size"), wxLIST_FORMAT_LEFT },
{ _("Formatted"), wxLIST_FORMAT_CENTER },
{ _("Last Modified"), wxLIST_FORMAT_LEFT },
{ _("Created On"), wxLIST_FORMAT_LEFT },
{ _("Path"), wxLIST_FORMAT_LEFT }
};
for( int i=0; i<McdCol_Count; ++i )
InsertColumn( i, columns[i].name, columns[i].align, -1 );
}
// --------------------------------------------------------------------------------------
// SingleCardPanel Implementations
// --------------------------------------------------------------------------------------
Panels::MemoryCardsPanel::SingleCardPanel::SingleCardPanel( wxWindow* parent, uint portidx, uint slotidx )
: BaseApplicableConfigPanel( parent, wxVERTICAL /*, wxsFormat(_("Port %u / Slot %u"), portidx+1, slotidx+1)*/ )
void MemoryCardListView::AssignCardsList( McdList* knownCards, int length )
{
m_port = portidx;
m_slot = slotidx;
if( knownCards == NULL ) length = 0;
m_KnownCards = knownCards;
m_filepicker = CreateMemoryCardFilePicker( this, portidx, slotidx );
SetItemCount( length );
RefreshItems( 0, length );
}
m_check_Disable = new wxCheckBox ( this, wxID_ANY, _("Disable this card") );
m_button_Recreate = new wxButton ( this, wxID_ANY, _("Re-create") );
m_label_Status = new wxStaticText ( this, wxID_ANY, _("Status: ") );
MemoryCardListView::MemoryCardListView( wxWindow* parent )
: wxListView( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL )
{
m_KnownCards = NULL;
CreateColumns();
//m_KnownCards;
Connect( wxEVT_COMMAND_LIST_BEGIN_DRAG, wxListEventHandler(MemoryCardListView::OnListDrag));
}
void Panels::MemoryCardListView::OnListDrag(wxListEvent& evt)
{
evt.Skip();
wxFileDataObject my_data;
my_data.AddFile( (*m_KnownCards)[ GetItemData(GetFirstSelected()) ].Filename.GetFullPath() );
wxDropSource dragSource( this );
dragSource.SetData( my_data );
wxDragResult result = dragSource.DoDragDrop();
}
// return the text for the given column of the given item
wxString Panels::MemoryCardListView::OnGetItemText(long item, long column) const
{
if( m_KnownCards == NULL ) return _parent::OnGetItemText(item, column);
const McdListItem& it( (*m_KnownCards)[item] );
switch( column )
{
case McdCol_Mounted:
{
if( (it.Port == -1) && (it.Slot == -1) ) return L"No";
return wxsFormat( L"%u / %u", it.Port+1, it.Slot+1);
}
case McdCol_Filename: return it.Filename.GetName();
case McdCol_Size: return wxsFormat( L"%u MB", it.SizeInMB );
case McdCol_Formatted: return it.IsFormatted ? L"Yes" : L"No";
case McdCol_DateModified: return it.DateModified.FormatDate();
case McdCol_DateCreated: return it.DateModified.FormatDate();
case McdCol_Path: return it.Filename.GetPath();
}
pxFail( "Unknown column index in MemoryCardListView -- returning an empty string." );
return wxEmptyString;
}
// return the icon for the given item. In report view, OnGetItemImage will
// only be called for the first column. See OnGetItemColumnImage for
// details.
int Panels::MemoryCardListView::OnGetItemImage(long item) const
{
return _parent::OnGetItemImage( item );
}
// return the icon for the given item and column.
int Panels::MemoryCardListView::OnGetItemColumnImage(long item, long column) const
{
return _parent::OnGetItemColumnImage( item, column );
}
// return the attribute for the item (may return NULL if none)
wxListItemAttr* Panels::MemoryCardListView::OnGetItemAttr(long item) const
{
wxListItemAttr* retval = _parent::OnGetItemAttr(item);
//const McdListItem& it( (*m_KnownCards)[item] );
return retval;
}
// =====================================================================================================
// MemoryCardInfoPanel
// =====================================================================================================
MemoryCardInfoPanel::MemoryCardInfoPanel( wxWindow* parent, uint port, uint slot )
: BaseApplicableConfigPanel( parent, wxVERTICAL ) //, wxEmptyString )
{
m_port = port;
m_slot = slot;
SetMinSize( wxSize(128, 48) );
Connect( wxEVT_PAINT, wxPaintEventHandler(MemoryCardInfoPanel::paintEvent) );
pxSetToolTip( m_check_Disable, pxE( ".Tooltip:MemoryCard:Enable",
L"When disabled, the card slot is reported as being empty to the emulator."
) );
pxSetToolTip( m_button_Recreate, pxE( ".Tooltip:MemoryCard:Recreate",
L"Deletes the existing memory card and creates a new one. All existing card contents will be lost."
) );
wxFlexGridSizer& s_status( *new wxFlexGridSizer( 4 ) );
s_status.AddGrowableCol( 1 );
s_status += StdPadding;
s_status += m_label_Status | pxMiddle;
s_status += m_button_Recreate;
s_status += StdPadding;
*this += m_check_Disable | pxBorder( wxLEFT, StdPadding );
*this += m_filepicker | StdExpand();
*this += s_status | pxExpand;
Connect( m_filepicker->GetId(), wxEVT_COMMAND_FILEPICKER_CHANGED, wxCommandEventHandler(SingleCardPanel::OnFileChanged) );
Connect( m_button_Recreate->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(SingleCardPanel::OnRecreate_Clicked) );
AppStatusEvent_OnSettingsApplied();
}
void Panels::MemoryCardsPanel::SingleCardPanel::OnFileChanged( wxCommandEvent& evt )
void MemoryCardInfoPanel::paintEvent(wxPaintEvent & evt)
{
if( UpdateStatusLine(m_filepicker->GetPath()) ) evt.Skip();
}
wxPaintDC dc( this );
void Panels::MemoryCardsPanel::SingleCardPanel::OnRecreate_Clicked( wxCommandEvent& evt )
{
if( !wxFileName( m_filepicker->GetPath() ).IsOk() ) return;
Dialogs::CreateMemoryCardDialog( this, m_port, m_slot, m_filepicker->GetPath() ).ShowModal();
}
void Panels::MemoryCardsPanel::SingleCardPanel::Apply()
{
AppConfig::McdOptions& mcd( g_Conf->Mcd[m_port][m_slot] );
//mcd.Enabled = m_check_Disable->GetValue();
//mcd.Filename = m_filepicker->GetPath();
}
void Panels::MemoryCardsPanel::SingleCardPanel::AppStatusEvent_OnSettingsApplied()
{
const AppConfig::McdOptions& mcd( g_Conf->Mcd[m_port][m_slot] );
const wxString mcdFilename( g_Conf->FullpathToMcd( m_port, m_slot ) );
m_filepicker->SetPath( mcdFilename );
UpdateStatusLine( mcdFilename );
m_check_Disable->SetValue( !mcd.Enabled );
}
bool Panels::MemoryCardsPanel::SingleCardPanel::UpdateStatusLine( const wxFileName& mcdfilename )
{
if( !mcdfilename.IsOk() )
{
m_label_Status->SetLabel(_("Invalid filename or path."));
m_button_Recreate->SetLabel(_("Create"));
m_button_Recreate->Disable();
return false;
}
wxFont woot( dc.GetFont() );
woot.SetWeight( wxBOLD );
dc.SetFont( woot );
m_button_Recreate->Enable();
if( !mcdfilename.FileExists() )
{
m_label_Status->SetLabel(_("Status: File does not exist."));
m_button_Recreate->SetLabel(_("Create"));
return false;
}
else
{
m_button_Recreate->SetLabel(_("Re-create"));
wxString msg;
msg = _("No Card (empty)");
// TODO: Add formatted/unformatted check here.
wxFFile mcdFile( mcdfilename.GetFullPath() );
if( !mcdFile.IsOpened() )
{
m_label_Status->SetLabel(_("Status: Permission denied."));
}
else
{
const uint size = (uint)(mcdFile.Length() / (1024 * 528 * 2));
m_label_Status->SetLabel( wxsFormat(_("Status: %u MB"), size) );
}
int tWidth, tHeight;
dc.GetTextExtent( msg, &tWidth, &tHeight );
return true;
}
dc.DrawText( msg, (dc.GetSize().GetWidth() - tWidth) / 2, 0 );
//dc.DrawCircle( dc.GetSize().GetWidth()/2, 24, dc.GetSize().GetWidth()/4 );
}
void MemoryCardInfoPanel::Apply()
{
}
void MemoryCardInfoPanel::AppStatusEvent_OnSettingsApplied()
{
}
// --------------------------------------------------------------------------------------
// MemoryCardsPanel Implementations
// --------------------------------------------------------------------------------------
Panels::MemoryCardsPanel::MemoryCardsPanel( wxWindow* parent )
: BaseApplicableConfigPanel( parent )
{
wxPanelWithHelpers* columns[2];
m_panel_AllKnownCards = new MemoryCardListPanel( this );
m_idealWidth -= 48;
m_check_Ejection = new pxCheckBox( this,
@ -161,23 +202,25 @@ Panels::MemoryCardsPanel::MemoryCardsPanel( wxWindow* parent )
L"loading from savestates. May not be compatible with all games (Guitar Hero)."
)
);
m_idealWidth += 48;
wxPanelWithHelpers* columns[2];
for( uint port=0; port<2; ++port )
{
columns[port] = new wxPanelWithHelpers( this, wxVERTICAL );
columns[port]->SetIdealWidth( (columns[port]->GetIdealWidth()-12) / 2 );
m_check_Multitap[port] = new pxCheckBox( columns[port], wxsFormat(_("Enable Multitap on Port %u"), port+1) );
/*m_check_Multitap[port] = new pxCheckBox( columns[port], wxsFormat(_("Enable Multitap on Port %u"), port+1) );
m_check_Multitap[port]->SetClientData( (void*) port );
m_check_Multitap[port]->SetFont( wxFont( m_check_Multitap[port]->GetFont().GetPointSize()+1, wxFONTFAMILY_MODERN, wxNORMAL, wxNORMAL, false, L"Lucida Console" ) );*/
for( uint slot=0; slot<4; ++slot )
for( uint slot=0; slot<1; ++slot )
{
m_CardPanel[port][slot] = new SingleCardPanel( columns[port], port, slot );
m_panel_cardinfo[port][slot] = new MemoryCardInfoPanel( columns[port], port, slot );
}
Connect( m_check_Multitap[port]->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(MemoryCardsPanel::OnMultitapChecked));
//Connect( m_check_Multitap[port]->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(MemoryCardsPanel::OnMultitapChecked));
}
// ------------------------------------
@ -194,29 +237,30 @@ Panels::MemoryCardsPanel::MemoryCardsPanel( wxWindow* parent )
*columns[port] += portSizer | SubGroup();
for( uint slot=0; slot<4; ++slot )
{
portSizer += m_CardPanel[port][slot] | pxExpand;
if( slot == 0 )
{
portSizer += new wxStaticLine( columns[port] ) | pxExpand.Border( wxTOP, StdPadding );
portSizer += m_check_Multitap[port] | pxCenter.Border( wxBOTTOM, StdPadding );
}
}
portSizer += m_panel_cardinfo[port][0] | SubGroup();
//portSizer += new wxStaticLine( columns[port] ) | pxExpand.Border( wxTOP, StdPadding );
//portSizer += m_check_Multitap[port] | pxCenter.Border( wxBOTTOM, StdPadding );
*s_table += columns[port] | StdExpand();
/*for( uint slot=1; slot<4; ++slot )
{
//portSizer += new wxStaticText( columns[port], wxID_ANY, wxsFormat(_("Slot #%u"), slot+1) ); // | pxCenter;
wxStaticBoxSizer& staticbox( *new wxStaticBoxSizer( wxVERTICAL, columns[port] ) );
staticbox += m_panel_cardinfo[port][slot] | pxExpand;
portSizer += staticbox | SubGroup();
}*/
*s_table += columns[port] | StdExpand();
}
wxBoxSizer& s_checks( *new wxBoxSizer( wxVERTICAL ) );
s_checks += m_check_Ejection;
wxBoxSizer* s_checks = new wxBoxSizer( wxVERTICAL );
*s_checks += m_check_Ejection;
*this += s_table | pxExpand;
*this += s_checks | StdExpand();
*this += s_table | pxExpand;
*this += m_panel_AllKnownCards | StdExpand();
*this += s_checks | StdExpand();
AppStatusEvent_OnSettingsApplied();
Disable(); // it's all broken right now, so disable it
}
void Panels::MemoryCardsPanel::OnMultitapChecked( wxCommandEvent& evt )
@ -227,7 +271,7 @@ void Panels::MemoryCardsPanel::OnMultitapChecked( wxCommandEvent& evt )
for( uint slot=1; slot<4; ++slot )
{
m_CardPanel[port][slot]->Enable( m_check_Multitap[port]->IsChecked() && g_Conf->Mcd[port][slot].Enabled );
//m_panel_cardinfo[port][slot]->Enable( m_check_Multitap[port]->IsChecked() );
}
}
}
@ -241,10 +285,9 @@ void Panels::MemoryCardsPanel::AppStatusEvent_OnSettingsApplied()
const Pcsx2Config& emuconf( g_Conf->EmuOptions );
for( uint port=0; port<2; ++port )
for( uint slot=0; slot<4; ++slot )
for( uint slot=1; slot<4; ++slot )
{
m_CardPanel[port][slot]->Enable( g_Conf->Mcd[port][slot].Enabled && ((slot == 0) || emuconf.MultitapEnabled(port)) );
//m_panel_cardinfo[port][slot]->Enable( emuconf.MultitapEnabled(port) );
}
}

View File

@ -22,168 +22,13 @@
#include "ps2/BiosTools.h"
#include <wx/stdpaths.h>
#include <wx/bookctrl.h>
using namespace Dialogs;
// -----------------------------------------------------------------------
// This method should be called by the parent dalog box of a configuration
// on dialog destruction. It asserts if the ApplyList hasn't been cleaned up
// and then cleans it up forcefully.
//
void ApplyStateStruct::DoCleanup() throw()
{
pxAssertMsg( PanelList.size() != 0, L"PanelList list hasn't been cleaned up." );
PanelList.clear();
ParentBook = NULL;
}
void ApplyStateStruct::StartBook( wxBookCtrlBase* book )
{
pxAssertDev( ParentBook == NULL, "An ApplicableConfig session is already in progress." );
ParentBook = book;
}
void ApplyStateStruct::StartWizard()
{
pxAssertDev( ParentBook == NULL, "An ApplicableConfig session is already in progress." );
}
// -----------------------------------------------------------------------
//
// Parameters:
// pageid - identifier of the page to apply settings for. All other pages will be
// skipped. If pageid is negative (-1) then all pages are applied.
//
// Returns false if one of the panels fails input validation (in which case dialogs
// should not be closed, etc).
//
bool ApplyStateStruct::ApplyPage( int pageid )
{
bool retval = true;
// Save these settings so we can restore them if the Apply fails.
bool oldAdminMode = UseAdminMode;
wxDirName oldSettingsFolder = SettingsFolder;
bool oldUseDefSet = UseDefaultSettingsFolder;
AppConfig confcopy( *g_Conf );
try
{
PanelApplyList_t::iterator yay = PanelList.begin();
while( yay != PanelList.end() )
{
//DbgCon.Status( L"Writing settings for: " + (*yay)->GetLabel() );
if( (pageid < 0) || (*yay)->IsOnPage( pageid ) )
(*yay)->Apply();
yay++;
}
// If an exception is thrown above, this code below won't get run.
// (conveniently skipping any option application! :D)
// Note: apply first, then save -- in case the apply fails.
AppApplySettings( &confcopy );
}
catch( Exception::CannotApplySettings& ex )
{
UseAdminMode = oldAdminMode;
SettingsFolder = oldSettingsFolder;
UseDefaultSettingsFolder = oldUseDefSet;
*g_Conf = confcopy;
if( ex.IsVerbose )
{
wxMessageBox( ex.FormatDisplayMessage(), _("Cannot apply settings...") );
if( ex.GetPanel() != NULL )
ex.GetPanel()->SetFocusToMe();
}
retval = false;
}
catch( ... )
{
UseAdminMode = oldAdminMode;
SettingsFolder = oldSettingsFolder;
UseDefaultSettingsFolder = oldUseDefSet;
*g_Conf = confcopy;
throw;
}
return retval;
}
// Returns false if one of the panels fails input validation (in which case dialogs
// should not be closed, etc).
bool ApplyStateStruct::ApplyAll()
{
return ApplyPage( -1 );
}
using namespace pxSizerFlags;
// --------------------------------------------------------------------------------------
// BaseApplicableConfigPanel Implementations
// UsermodeSelectionPanel
// --------------------------------------------------------------------------------------
IApplyState* BaseApplicableConfigPanel::FindApplyStateManager() const
{
wxWindow* millrun = this->GetParent();
while( millrun != NULL )
{
if( BaseApplicableDialog* dialog = wxDynamicCast( millrun, BaseApplicableDialog ) )
return (IApplyState*)dialog;
if( ApplicableWizardPage* wizpage = wxDynamicCast( millrun, ApplicableWizardPage ) )
return (IApplyState*)wizpage;
millrun = millrun->GetParent();
}
return NULL;
}
BaseApplicableConfigPanel::~BaseApplicableConfigPanel() throw()
{
if( IApplyState* iapp = FindApplyStateManager() )
iapp->GetApplyState().PanelList.remove( this );
}
BaseApplicableConfigPanel::BaseApplicableConfigPanel( wxWindow* parent, wxOrientation orient )
: wxPanelWithHelpers( parent, orient )
, m_AppStatusHelper( this )
{
Init();
}
BaseApplicableConfigPanel::BaseApplicableConfigPanel( wxWindow* parent, wxOrientation orient, const wxString& staticLabel )
: wxPanelWithHelpers( parent, orient, staticLabel )
, m_AppStatusHelper( this )
{
Init();
}
void BaseApplicableConfigPanel::SetFocusToMe()
{
if( (m_OwnerBook == NULL) || (m_OwnerPage == wxID_NONE) ) return;
m_OwnerBook->SetSelection( m_OwnerPage );
}
void BaseApplicableConfigPanel::Init()
{
if( IApplyState* iapp = FindApplyStateManager() )
{
ApplyStateStruct& applyState( iapp->GetApplyState() );
m_OwnerPage = applyState.CurOwnerPage;
m_OwnerBook = applyState.ParentBook;
applyState.PanelList.push_back( this );
}
}
void BaseApplicableConfigPanel::AppStatusEvent_OnSettingsApplied() {}
// -----------------------------------------------------------------------
Panels::UsermodeSelectionPanel::UsermodeSelectionPanel( wxWindow* parent, bool isFirstTime )
: BaseApplicableConfigPanel( parent, wxVERTICAL, _("Usermode Selection") )
{
@ -211,30 +56,56 @@ Panels::UsermodeSelectionPanel::UsermodeSelectionPanel( wxWindow* parent, bool i
_("Location: ") + wxGetCwd(),
_("This setting requires administration privileges from your operating system.")
),
};
m_radio_UserMode = new pxRadioPanel( this, UsermodeOptions );
m_radio_UserMode->SetPaddingHoriz( m_radio_UserMode->GetPaddingHoriz() + 4 );
m_radio_UserMode->Realize();
*this += Text( (isFirstTime ? usermodeExplained : usermodeWarning) );
*this += m_radio_UserMode | pxSizerFlags::StdExpand();
RadioPanelItem(
_("Custom folder:"),
wxEmptyString,
_("This setting may require administration privileges from your operating system, depending on how your system is configured.")
)
};
m_radio_UserMode = new pxRadioPanel( this, UsermodeOptions );
m_radio_UserMode->SetPaddingHoriz( m_radio_UserMode->GetPaddingVert() + 4 );
m_radio_UserMode->Realize();
m_dirpicker_custom = new DirPickerPanel( this, FolderId_Documents, _("Select a document root for PCSX2") );
*this += Text( isFirstTime ? usermodeExplained : usermodeWarning );
*this += m_radio_UserMode | StdExpand();
*this += m_dirpicker_custom | pxExpand.Border( wxLEFT, StdPadding + m_radio_UserMode->GetIndentation() );
*this += 4;
AppStatusEvent_OnSettingsApplied();
Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler(UsermodeSelectionPanel::OnRadioChanged) );
}
void Panels::UsermodeSelectionPanel::Apply()
{
UseAdminMode = (m_radio_UserMode->GetSelection() == 1);
DocsFolderMode = (DocsModeType) m_radio_UserMode->GetSelection();
CustomDocumentsFolder = m_dirpicker_custom->GetPath();
}
void Panels::UsermodeSelectionPanel::AppStatusEvent_OnSettingsApplied()
{
m_radio_UserMode->SetSelection( (int)UseAdminMode );
if( m_radio_UserMode ) m_radio_UserMode->SetSelection( DocsFolderMode );
if( m_dirpicker_custom ) m_dirpicker_custom->Enable( DocsFolderMode == DocsFolder_Custom );
}
// -----------------------------------------------------------------------
void Panels::UsermodeSelectionPanel::OnRadioChanged( wxCommandEvent& evt )
{
evt.Skip();
if( !m_radio_UserMode ) return;
if( m_dirpicker_custom )
m_dirpicker_custom->Enable( m_radio_UserMode->GetSelection() == (int)DocsFolder_Custom );
}
// --------------------------------------------------------------------------------------
// LanguageSelectionPanel
// --------------------------------------------------------------------------------------
Panels::LanguageSelectionPanel::LanguageSelectionPanel( wxWindow* parent )
: BaseApplicableConfigPanel( parent, wxHORIZONTAL )
{
@ -266,6 +137,8 @@ Panels::LanguageSelectionPanel::LanguageSelectionPanel( wxWindow* parent )
void Panels::LanguageSelectionPanel::Apply()
{
if( !m_picker ) return;
// The combo box's order is sorted and may not match our m_langs order, so
// we have to do a string comparison to find a match:
@ -285,5 +158,5 @@ void Panels::LanguageSelectionPanel::Apply()
void Panels::LanguageSelectionPanel::AppStatusEvent_OnSettingsApplied()
{
m_picker->SetSelection( g_Conf->LanguageId );
if( m_picker ) m_picker->SetSelection( g_Conf->LanguageId );
}

View File

@ -629,7 +629,7 @@ Panels::PluginSelectorPanel::EnumThread::EnumThread( PluginSelectorPanel& master
void Panels::PluginSelectorPanel::EnumThread::DoNextPlugin( int curidx )
{
DbgCon.Indent().WriteLn( L"Enumerating Plugin: " + m_master.GetFilename( curidx ) );
DbgCon.Indent().WriteLn( L"Plugin: " + m_master.GetFilename( curidx ) );
try
{

View File

@ -2561,6 +2561,10 @@
RelativePath="..\..\gui\Panels\AudioPanel.cpp"
>
</File>
<File
RelativePath="..\..\gui\Panels\BaseApplicableConfigPanel.cpp"
>
</File>
<File
RelativePath="..\..\gui\Panels\BiosSelectorPanel.cpp"
>
@ -2593,6 +2597,14 @@
RelativePath="..\..\gui\Panels\LogOptionsPanels.h"
>
</File>
<File
RelativePath="..\..\gui\Panels\MemoryCardListPanel.cpp"
>
</File>
<File
RelativePath="..\..\gui\Panels\MemoryCardListView.h"
>
</File>
<File
RelativePath="..\..\gui\Panels\MemoryCardsPanel.cpp"
>