From 08f3e4955bb4772e4d8d7540fe5a168d9a994a17 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Fri, 5 Mar 2010 14:24:44 +0000 Subject: [PATCH] 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 --- common/include/Utilities/pxRadioPanel.h | 2 +- common/include/Utilities/wxAppWithHelpers.h | 6 + common/include/Utilities/wxGuiTools.h | 59 +--- common/src/Utilities/ThreadTools.cpp | 6 +- common/src/Utilities/pxRadioPanel.cpp | 10 +- common/src/Utilities/wxAppWithHelpers.cpp | 47 ++- common/src/Utilities/wxGuiTools.cpp | 37 ++- pcsx2/PathDefs.h | 3 + pcsx2/Plugins.h | 2 +- pcsx2/RecoverySystem.cpp | 91 +++++- pcsx2/SaveState.cpp | 10 +- pcsx2/SaveState.h | 8 +- pcsx2/gui/App.h | 29 +- pcsx2/gui/AppConfig.cpp | 44 ++- pcsx2/gui/AppConfig.h | 25 +- pcsx2/gui/AppCoreThread.cpp | 2 +- pcsx2/gui/AppEventSources.cpp | 6 +- pcsx2/gui/AppForwardDefs.h | 7 +- pcsx2/gui/AppInit.cpp | 180 +++++----- pcsx2/gui/AppMain.cpp | 47 +-- pcsx2/gui/AppRes.cpp | 39 ++- pcsx2/gui/ApplyState.h | 5 +- pcsx2/gui/ConsoleLogger.cpp | 54 +-- pcsx2/gui/ConsoleLogger.h | 3 +- pcsx2/gui/Dialogs/AboutBoxDialog.cpp | 4 +- pcsx2/gui/Dialogs/AssertionDialog.cpp | 3 +- pcsx2/gui/Dialogs/CreateMemoryCardDialog.cpp | 16 +- pcsx2/gui/Dialogs/FirstTimeWizard.cpp | 11 +- pcsx2/gui/Dialogs/ModalPopups.h | 1 + pcsx2/gui/IsoDropTarget.h | 1 + pcsx2/gui/MainFrame.cpp | 23 +- pcsx2/gui/MainFrame.h | 3 +- pcsx2/gui/MainMenuClicks.cpp | 8 + .../gui/Panels/BaseApplicableConfigPanel.cpp | 206 ++++++++++++ pcsx2/gui/Panels/BiosSelectorPanel.cpp | 64 ++-- pcsx2/gui/Panels/ConfigurationPanels.h | 204 +++++------- pcsx2/gui/Panels/CpuPanel.cpp | 10 +- pcsx2/gui/Panels/DirPickerPanel.cpp | 115 +++++-- pcsx2/gui/Panels/MemoryCardListPanel.cpp | 195 +++++++++++ pcsx2/gui/Panels/MemoryCardListView.h | 135 ++++++++ pcsx2/gui/Panels/MemoryCardsPanel.cpp | 309 ++++++++++-------- pcsx2/gui/Panels/MiscPanelStuff.cpp | 209 +++--------- pcsx2/gui/Panels/PluginSelectorPanel.cpp | 2 +- pcsx2/windows/VCprojects/pcsx2_2008.vcproj | 12 + 44 files changed, 1494 insertions(+), 759 deletions(-) create mode 100644 pcsx2/gui/Panels/BaseApplicableConfigPanel.cpp create mode 100644 pcsx2/gui/Panels/MemoryCardListPanel.cpp create mode 100644 pcsx2/gui/Panels/MemoryCardListView.h diff --git a/common/include/Utilities/pxRadioPanel.h b/common/include/Utilities/pxRadioPanel.h index 1d1a98d029..67e3d99e32 100644 --- a/common/include/Utilities/pxRadioPanel.h +++ b/common/include/Utilities/pxRadioPanel.h @@ -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 ) diff --git a/common/include/Utilities/wxAppWithHelpers.h b/common/include/Utilities/wxAppWithHelpers.h index 1e20e9243b..23a28beb32 100644 --- a/common/include/Utilities/wxAppWithHelpers.h +++ b/common/include/Utilities/wxAppWithHelpers.h @@ -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 m_PingWhenIdle; std::vector m_DeleteWhenIdle; + std::vector 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 ); }; diff --git a/common/include/Utilities/wxGuiTools.h b/common/include/Utilities/wxGuiTools.h index 2a542e0b7f..6fe94d8870 100644 --- a/common/include/Utilities/wxGuiTools.h +++ b/common/include/Utilities/wxGuiTools.h @@ -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 diff --git a/common/src/Utilities/ThreadTools.cpp b/common/src/Utilities/ThreadTools.cpp index 8b8383c1ae..47314549fc 100644 --- a/common/src/Utilities/ThreadTools.cpp +++ b/common/src/Utilities/ThreadTools.cpp @@ -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() ) ); }*/ diff --git a/common/src/Utilities/pxRadioPanel.cpp b/common/src/Utilities/pxRadioPanel.cpp index 66d1cccb02..8a2752526d 100644 --- a/common/src/Utilities/pxRadioPanel.cpp +++ b/common/src/Utilities/pxRadioPanel.cpp @@ -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 %u events.", action, size ); + + for( size_t i=0; iAddSpacer( 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. diff --git a/pcsx2/PathDefs.h b/pcsx2/PathDefs.h index 5393f44bbb..e56151c6f5 100644 --- a/pcsx2/PathDefs.h +++ b/pcsx2/PathDefs.h @@ -24,6 +24,9 @@ enum FoldersEnum_t FolderId_Savestates, FolderId_MemoryCards, FolderId_Logs, + + FolderId_Documents, + FolderId_COUNT }; diff --git a/pcsx2/Plugins.h b/pcsx2/Plugins.h index 7257ae854d..e735e0448b 100644 --- a/pcsx2/Plugins.h +++ b/pcsx2/Plugins.h @@ -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 diff --git a/pcsx2/RecoverySystem.cpp b/pcsx2/RecoverySystem.cpp index a4a9d7e359..bfdfaa3e2f 100644 --- a/pcsx2/RecoverySystem.cpp +++ b/pcsx2/RecoverySystem.cpp @@ -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. diff --git a/pcsx2/SaveState.cpp b/pcsx2/SaveState.cpp index 28525cb5e6..57ca5462bc 100644 --- a/pcsx2/SaveState.cpp +++ b/pcsx2/SaveState.cpp @@ -359,8 +359,8 @@ void SaveStateBase::FreezeAll() ////////////////////////////////////////////////////////////////////////////////// // uncompressed to/from memory state saves implementation -memSavingState::memSavingState( SafeArray& save_to ) : - SaveStateBase( save_to ) +memSavingState::memSavingState( SafeArray& save_to ) + : SaveStateBase( save_to ) { } @@ -381,12 +381,12 @@ void memSavingState::FreezeAll() _parent::FreezeAll(); } -memLoadingState::memLoadingState( const SafeArray& load_from ) : - SaveStateBase( const_cast&>(load_from) ) +memLoadingState::memLoadingState( const SafeArray& load_from ) + : SaveStateBase( const_cast&>(load_from) ) { } -memLoadingState::~memLoadingState() { } +memLoadingState::~memLoadingState() throw() { } // Loading of state data void memLoadingState::FreezeMem( void* data, int size ) diff --git a/pcsx2/SaveState.h b/pcsx2/SaveState.h index e438331c83..76f4621b88 100644 --- a/pcsx2/SaveState.h +++ b/pcsx2/SaveState.h @@ -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& 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& load_from ); // Loading of state data from a memory buffer... diff --git a/pcsx2/gui/App.h b/pcsx2/gui/App.h index b530b7ab35..cfa7ca217c 100644 --- a/pcsx2/gui/App.h +++ b/pcsx2/gui/App.h @@ -323,13 +323,22 @@ struct pxAppResources ScopedPtr IconBundle; ScopedPtr Bitmap_Logo; - ScopedPtr RecentIsoMenu; - ScopedPtr RecentIsoList; - pxAppResources(); virtual ~pxAppResources() throw() { } }; +// -------------------------------------------------------------------------------------- +// RecentIsoList +// -------------------------------------------------------------------------------------- +struct RecentIsoList +{ + ScopedPtr Manager; + ScopedPtr Menu; + + RecentIsoList(); + virtual ~RecentIsoList() throw() { } +}; + // -------------------------------------------------------------------------------------- // FramerateManager // -------------------------------------------------------------------------------------- @@ -461,6 +470,8 @@ public: protected: ScopedPtr m_StdoutRedirHandle; ScopedPtr m_StderrRedirHandle; + + ScopedPtr m_RecentIsoList; ScopedPtr 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 diff --git a/pcsx2/gui/AppConfig.cpp b/pcsx2/gui/AppConfig.cpp index 0b88ef4136..c1594b842c 100644 --- a/pcsx2/gui/AppConfig.cpp +++ b/pcsx2/gui/AppConfig.cpp @@ -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; iCurrentIso ) ) g_Conf->CurrentIso.Clear(); - sApp.GetRecentIsoList().Add( g_Conf->CurrentIso ); + sApp.GetRecentIsoManager().Add( g_Conf->CurrentIso ); CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso ); AppSaveSettings(); diff --git a/pcsx2/gui/AppEventSources.cpp b/pcsx2/gui/AppEventSources.cpp index c807c34737..d53d9a7c8f 100644 --- a/pcsx2/gui/AppEventSources.cpp +++ b/pcsx2/gui/AppEventSources.cpp @@ -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; diff --git a/pcsx2/gui/AppForwardDefs.h b/pcsx2/gui/AppForwardDefs.h index c957941bc6..28b359e958 100644 --- a/pcsx2/gui/AppForwardDefs.h +++ b/pcsx2/gui/AppForwardDefs.h @@ -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; diff --git a/pcsx2/gui/AppInit.cpp b/pcsx2/gui/AppInit.cpp index 1c47ffa994..990abc68c1 100644 --- a/pcsx2/gui/AppInit.cpp +++ b/pcsx2/gui/AppInit.cpp @@ -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(); } diff --git a/pcsx2/gui/AppMain.cpp b/pcsx2/gui/AppMain.cpp index 3335fd6aa8..260c67abbc 100644 --- a/pcsx2/gui/AppMain.cpp +++ b/pcsx2/gui/AppMain.cpp @@ -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 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; } diff --git a/pcsx2/gui/AppRes.cpp b/pcsx2/gui/AppRes.cpp index bc6d061e57..62d80f886d 100644 --- a/pcsx2/gui/AppRes.cpp +++ b/pcsx2/gui/AppRes.cpp @@ -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& bundle( m_Resources->IconBundle ); + ScopedPtr& bundle( GetResourceCache().IconBundle ); if( !bundle ) { bundle = new wxIconBundle(); @@ -102,7 +112,7 @@ const wxIconBundle& Pcsx2App::GetIconBundle() // ------------------------------------------------------------------------ const wxBitmap& Pcsx2App::GetLogoBitmap() { - ScopedPtr& logo( m_Resources->Bitmap_Logo ); + ScopedPtr& logo( GetResourceCache().Bitmap_Logo ); if( logo ) return *logo; wxFileName mess; @@ -138,7 +148,7 @@ const wxBitmap& Pcsx2App::GetLogoBitmap() // ------------------------------------------------------------------------ wxImageList& Pcsx2App::GetImgList_Config() { - ScopedPtr& images( m_Resources->ConfigImages ); + ScopedPtr& 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& images( m_Resources->ToolbarImages ); + ScopedPtr& images( GetResourceCache().ToolbarImages ); if( !images ) { diff --git a/pcsx2/gui/ApplyState.h b/pcsx2/gui/ApplyState.h index f02455b469..f19b4dfdd5 100644 --- a/pcsx2/gui/ApplyState.h +++ b/pcsx2/gui/ApplyState.h @@ -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 diff --git a/pcsx2/gui/ConsoleLogger.cpp b/pcsx2/gui/ConsoleLogger.cpp index 5845821be0..c122dea69b 100644 --- a/pcsx2/gui/ConsoleLogger.cpp +++ b/pcsx2/gui/ConsoleLogger.cpp @@ -25,17 +25,15 @@ #include 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 ); } diff --git a/pcsx2/gui/ConsoleLogger.h b/pcsx2/gui/ConsoleLogger.h index 3cfd4daa9d..345ea23cbb 100644 --- a/pcsx2/gui/ConsoleLogger.h +++ b/pcsx2/gui/ConsoleLogger.h @@ -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 ); diff --git a/pcsx2/gui/Dialogs/AboutBoxDialog.cpp b/pcsx2/gui/Dialogs/AboutBoxDialog.cpp index c050e48e92..228095ffb8 100644 --- a/pcsx2/gui/Dialogs/AboutBoxDialog.cpp +++ b/pcsx2/gui/Dialogs/AboutBoxDialog.cpp @@ -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 diff --git a/pcsx2/gui/Dialogs/AssertionDialog.cpp b/pcsx2/gui/Dialogs/AssertionDialog.cpp index 636307b27e..b597ddfeb3 100644 --- a/pcsx2/gui/Dialogs/AssertionDialog.cpp +++ b/pcsx2/gui/Dialogs/AssertionDialog.cpp @@ -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 ); diff --git a/pcsx2/gui/Dialogs/CreateMemoryCardDialog.cpp b/pcsx2/gui/Dialogs/CreateMemoryCardDialog.cpp index d3b11ffb9a..3f55c3361d 100644 --- a/pcsx2/gui/Dialogs/CreateMemoryCardDialog.cpp +++ b/pcsx2/gui/Dialogs/CreateMemoryCardDialog.cpp @@ -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 ) diff --git a/pcsx2/gui/Dialogs/FirstTimeWizard.cpp b/pcsx2/gui/Dialogs/FirstTimeWizard.cpp index a97411708f..c535077237 100644 --- a/pcsx2/gui/Dialogs/FirstTimeWizard.cpp +++ b/pcsx2/gui/Dialogs/FirstTimeWizard.cpp @@ -20,6 +20,7 @@ #include "ModalPopups.h" #include "Panels/ConfigurationPanels.h" #include +#include 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") ) diff --git a/pcsx2/gui/Dialogs/ModalPopups.h b/pcsx2/gui/Dialogs/ModalPopups.h index 759b854440..0807cffb58 100644 --- a/pcsx2/gui/Dialogs/ModalPopups.h +++ b/pcsx2/gui/Dialogs/ModalPopups.h @@ -39,6 +39,7 @@ protected: protected: void OnUsermodeChanged( wxCommandEvent& evt ); + void OnCustomDirChanged( wxCommandEvent& evt ); }; protected: diff --git a/pcsx2/gui/IsoDropTarget.h b/pcsx2/gui/IsoDropTarget.h index cc5d3bbe91..64d256ef5f 100644 --- a/pcsx2/gui/IsoDropTarget.h +++ b/pcsx2/gui/IsoDropTarget.h @@ -26,6 +26,7 @@ protected: wxWindow* m_WindowBound; public: + virtual ~IsoDropTarget() throw() { } IsoDropTarget( wxWindow* parent ) : wxFileDropTarget() { m_WindowBound = parent; diff --git a/pcsx2/gui/MainFrame.cpp b/pcsx2/gui/MainFrame.cpp index 07f100aa2b..abc4bb8686 100644 --- a/pcsx2/gui/MainFrame.cpp +++ b/pcsx2/gui/MainFrame.cpp @@ -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 ); diff --git a/pcsx2/gui/MainFrame.h b/pcsx2/gui/MainFrame.h index 15b37e5273..a82df371b2 100644 --- a/pcsx2/gui/MainFrame.h +++ b/pcsx2/gui/MainFrame.h @@ -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 ); diff --git a/pcsx2/gui/MainMenuClicks.cpp b/pcsx2/gui/MainMenuClicks.cpp index 68540bcaeb..3c014aa8aa 100644 --- a/pcsx2/gui/MainMenuClicks.cpp +++ b/pcsx2/gui/MainMenuClicks.cpp @@ -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 { diff --git a/pcsx2/gui/Panels/BaseApplicableConfigPanel.cpp b/pcsx2/gui/Panels/BaseApplicableConfigPanel.cpp new file mode 100644 index 0000000000..632da6c97a --- /dev/null +++ b/pcsx2/gui/Panels/BaseApplicableConfigPanel.cpp @@ -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 . + */ + +#include "PrecompiledHeader.h" +#include "App.h" + +#include "ConfigurationPanels.h" +#include "Dialogs/ConfigurationDialog.h" + +#include + +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() {} diff --git a/pcsx2/gui/Panels/BiosSelectorPanel.cpp b/pcsx2/gui/Panels/BiosSelectorPanel.cpp index b7c1c0404d..856cad5a90 100644 --- a/pcsx2/gui/Panels/BiosSelectorPanel.cpp +++ b/pcsx2/gui/Panels/BiosSelectorPanel.cpp @@ -24,17 +24,35 @@ #include #include -// ------------------------------------------------------------------------ +// ===================================================================================================== +// 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 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 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; diff --git a/pcsx2/gui/Panels/ConfigurationPanels.h b/pcsx2/gui/Panels/ConfigurationPanels.h index bdfab67c4f..b33760569d 100644 --- a/pcsx2/gui/Panels/ConfigurationPanels.h +++ b/pcsx2/gui/Panels/ConfigurationPanels.h @@ -23,51 +23,61 @@ #include #include -#include +#include #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 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 // -------------------------------------------------------------------------------------- diff --git a/pcsx2/gui/Panels/CpuPanel.cpp b/pcsx2/gui/Panels/CpuPanel.cpp index d3b072d20c..f56887ea73 100644 --- a/pcsx2/gui/Panels/CpuPanel.cpp +++ b/pcsx2/gui/Panels/CpuPanel.cpp @@ -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 ); diff --git a/pcsx2/gui/Panels/DirPickerPanel.cpp b/pcsx2/gui/Panels/DirPickerPanel.cpp index cec43c9f6b..cc9b57c92e 100644 --- a/pcsx2/gui/Panels/DirPickerPanel.cpp +++ b/pcsx2/gui/Panels/DirPickerPanel.cpp @@ -15,12 +15,15 @@ #include "PrecompiledHeader.h" #include "ConfigurationPanels.h" +#include "Dialogs/ModalPopups.h" #include #include #include #include +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 ); } diff --git a/pcsx2/gui/Panels/MemoryCardListPanel.cpp b/pcsx2/gui/Panels/MemoryCardListPanel.cpp new file mode 100644 index 0000000000..610ccb95d6 --- /dev/null +++ b/pcsx2/gui/Panels/MemoryCardListPanel.cpp @@ -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 . + */ + +#include "PrecompiledHeader.h" +#include "ConfigurationPanels.h" +#include "MemoryCardListView.h" + +#include +#include +#include + + +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 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( 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; isize(); ++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 ); +} diff --git a/pcsx2/gui/Panels/MemoryCardListView.h b/pcsx2/gui/Panels/MemoryCardListView.h new file mode 100644 index 0000000000..78c9659a8d --- /dev/null +++ b/pcsx2/gui/Panels/MemoryCardListView.h @@ -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 . + */ + +#pragma once + +#include "AppCommon.h" + +#include +#include + +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 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 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 ); + + }; + +}; diff --git a/pcsx2/gui/Panels/MemoryCardsPanel.cpp b/pcsx2/gui/Panels/MemoryCardsPanel.cpp index 00a3c8d031..95f791cf7f 100644 --- a/pcsx2/gui/Panels/MemoryCardsPanel.cpp +++ b/pcsx2/gui/Panels/MemoryCardsPanel.cpp @@ -15,143 +15,184 @@ #include "PrecompiledHeader.h" #include "ConfigurationPanels.h" +#include "MemoryCardListView.h" + #include "Dialogs/ConfigurationDialog.h" #include #include +#include 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; iGetId(), 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) ); } - - } + diff --git a/pcsx2/gui/Panels/MiscPanelStuff.cpp b/pcsx2/gui/Panels/MiscPanelStuff.cpp index 5e775e5cff..07c5ea9754 100644 --- a/pcsx2/gui/Panels/MiscPanelStuff.cpp +++ b/pcsx2/gui/Panels/MiscPanelStuff.cpp @@ -22,168 +22,13 @@ #include "ps2/BiosTools.h" #include -#include 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 ); } diff --git a/pcsx2/gui/Panels/PluginSelectorPanel.cpp b/pcsx2/gui/Panels/PluginSelectorPanel.cpp index 9cf8d682a2..20d7f358a5 100644 --- a/pcsx2/gui/Panels/PluginSelectorPanel.cpp +++ b/pcsx2/gui/Panels/PluginSelectorPanel.cpp @@ -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 { diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index 63cb7dec17..96851bdbdf 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -2561,6 +2561,10 @@ RelativePath="..\..\gui\Panels\AudioPanel.cpp" > + + @@ -2593,6 +2597,14 @@ RelativePath="..\..\gui\Panels\LogOptionsPanels.h" > + + + +