From 3c4b1afb49ea30aed55d1e57ac5ddefe12a4e871 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Tue, 18 Aug 2009 19:47:00 +0000 Subject: [PATCH] wxgui: All kinds of mess, but still not up to running games yet. * Borrowed wxScopedPtr from wxWidgets 2.9 * Fixed up first-time startup procedures and folder selection * Implemented most of the rest of the missing configuration options, and cleaned up some ambiguities regarding bool types and bitfields. git-svn-id: http://pcsx2.googlecode.com/svn/branches/wxgui@1649 96395faa-99c1-11dd-bbfe-3dabce05a288 --- 3rdparty/wxWidgets/include/wx/setup.h | 2 +- common/build/Utilities/utilities.vcproj | 4 + common/include/Pcsx2Defs.h | 8 +- common/include/Utilities/SafeArray.h | 38 ++-- common/include/Utilities/ScopedPtr.h | 4 + common/include/wx/folderdesc.txt | 13 ++ common/include/wx/scopedarray.h | 63 +++++++ common/include/wx/scopedptr.h | 99 ++++++++++ pcsx2/Config.h | 205 +++++++++------------ pcsx2/Pcsx2Config.cpp | 121 +++++++++--- pcsx2/Plugins.cpp | 14 +- pcsx2/Plugins.h | 2 + pcsx2/gui/AppConfig.cpp | 153 +++++++++++---- pcsx2/gui/AppConfig.h | 39 ++-- pcsx2/gui/Dialogs/ConfigurationDialog.cpp | 5 +- pcsx2/gui/Dialogs/FirstTimeWizard.cpp | 169 +++++++++++++++++ pcsx2/gui/Dialogs/ModalPopups.h | 31 +++- pcsx2/gui/Dialogs/PickUserModeDialog.cpp | 4 +- pcsx2/gui/IniInterface.h | 6 +- pcsx2/gui/Panels/ConfigurationPanels.h | 152 +++++++++------ pcsx2/gui/Panels/MiscPanelStuff.cpp | 55 ++++-- pcsx2/gui/Panels/PathsPanel.cpp | 130 ++++++++----- pcsx2/gui/Panels/PluginSelectorPanel.cpp | 97 +++++++--- pcsx2/gui/main.cpp | 90 ++------- pcsx2/ps2/BiosTools.cpp | 26 ++- pcsx2/ps2/BiosTools.h | 1 + pcsx2/windows/VCprojects/pcsx2_2008.vcproj | 4 + pcsx2_suite_2008.sln | 8 + 28 files changed, 1080 insertions(+), 463 deletions(-) create mode 100644 common/include/Utilities/ScopedPtr.h create mode 100644 common/include/wx/folderdesc.txt create mode 100644 common/include/wx/scopedarray.h create mode 100644 common/include/wx/scopedptr.h create mode 100644 pcsx2/gui/Dialogs/FirstTimeWizard.cpp diff --git a/3rdparty/wxWidgets/include/wx/setup.h b/3rdparty/wxWidgets/include/wx/setup.h index d824878afb..d629f00dba 100644 --- a/3rdparty/wxWidgets/include/wx/setup.h +++ b/3rdparty/wxWidgets/include/wx/setup.h @@ -918,7 +918,7 @@ #define wxUSE_SPLASH 1 // wizards -#define wxUSE_WIZARDDLG 0 +#define wxUSE_WIZARDDLG 1 // Compile in wxAboutBox() function showing the standard "About" dialog. // diff --git a/common/build/Utilities/utilities.vcproj b/common/build/Utilities/utilities.vcproj index 3d50126e04..c0f2589441 100644 --- a/common/build/Utilities/utilities.vcproj +++ b/common/build/Utilities/utilities.vcproj @@ -400,6 +400,10 @@ RelativePath="..\..\include\Utilities\SafeArray.h" > + + diff --git a/common/include/Pcsx2Defs.h b/common/include/Pcsx2Defs.h index 2393544493..851c533254 100644 --- a/common/include/Pcsx2Defs.h +++ b/common/include/Pcsx2Defs.h @@ -173,10 +173,10 @@ // #ifdef _MSC_VER -# define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x -# define PCSX2_ALIGNED_EXTERN(alig,x) extern __declspec(align(alig)) x -# define PCSX2_ALIGNED16(x) __declspec(align(16)) x -# define PCSX2_ALIGNED16_EXTERN(x) extern __declspec(align(16)) x +# define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x +# define PCSX2_ALIGNED_EXTERN(alig,x) extern __declspec(align(alig)) x +# define PCSX2_ALIGNED16(x) __declspec(align(16)) x +# define PCSX2_ALIGNED16_EXTERN(x) extern __declspec(align(16)) x # define __naked __declspec(naked) # define __unused /*unused*/ diff --git a/common/include/Utilities/SafeArray.h b/common/include/Utilities/SafeArray.h index b3b613fb55..1b43cad806 100644 --- a/common/include/Utilities/SafeArray.h +++ b/common/include/Utilities/SafeArray.h @@ -31,39 +31,31 @@ extern void pcsx2_aligned_free(void* pmem); # define _aligned_realloc pcsx2_aligned_realloc #endif -////////////////////////////////////////////////////////////// -// Safe deallocation macros -- always check pointer validity (non-null) -// and set pointer to null on deallocation. +////////////////////////////////////////////////////////////////////////////////////////// +// Safe deallocation macros -- checks pointer validity (non-null) when needed, and sets +// pointer to null after deallocation. #define safe_delete( ptr ) \ - if( ptr != NULL ) { \ - delete ptr; \ - ptr = NULL; \ - } + ((void) (delete ptr), ptr = NULL) #define safe_delete_array( ptr ) \ - if( ptr != NULL ) { \ - delete[] ptr; \ - ptr = NULL; \ - } + ((void) (delete[] ptr), ptr = NULL) +// fixme: I'm pretty sure modern libc implementations under gcc and msvc check null status +// inside free(), meaning we shouldn't have to do it ourselves. But legacy implementations +// didn't always check, so best to be cautious unless absolutely certain it's being covered on +// all ported platforms. #define safe_free( ptr ) \ - if( ptr != NULL ) { \ - free( ptr ); \ - ptr = NULL; \ - } + ((void) (( ( ptr != NULL ) && (free( ptr ), !!0) ), ptr = NULL)) +// Implementation note: all known implementations of _aligned_free check the pointer for +// NULL status (our implementation under GCC, and microsoft's under MSVC), so no need to +// do it here. #define safe_aligned_free( ptr ) \ - if( ptr != NULL ) { \ - _aligned_free( ptr ); \ - ptr = NULL; \ - } + ((void) ( _aligned_free( ptr ), ptr = NULL )) #define SafeSysMunmap( ptr, size ) \ - if( ptr != NULL ) { \ - HostSys::Munmap( (uptr)ptr, size ); \ - ptr = NULL; \ - } + ((void) ( HostSys::Munmap( (uptr)ptr, size ), ptr = NULL )) ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/common/include/Utilities/ScopedPtr.h b/common/include/Utilities/ScopedPtr.h new file mode 100644 index 0000000000..8b0722c478 --- /dev/null +++ b/common/include/Utilities/ScopedPtr.h @@ -0,0 +1,4 @@ +#pragma once + +#include +#include diff --git a/common/include/wx/folderdesc.txt b/common/include/wx/folderdesc.txt new file mode 100644 index 0000000000..9988adbdcd --- /dev/null +++ b/common/include/wx/folderdesc.txt @@ -0,0 +1,13 @@ +------------------------------------------------- + include/wx folder -- PCSX2 Common Includes +------------------------------------------------- + +This folder contains various classes borrowed from wxWidgets 2.9.x / 3.0. + +/Common/include is a PCSX2 project default include search path, and with the /wx +folder prefix, these files can be included the same way as other wxWidgets includes: + +#include + +If/when PCSX2 upgrades to wx2.9/3.0 these files will be removed and the wxWidgets +distribution files will automatically be used instead. diff --git a/common/include/wx/scopedarray.h b/common/include/wx/scopedarray.h new file mode 100644 index 0000000000..2a697fedc6 --- /dev/null +++ b/common/include/wx/scopedarray.h @@ -0,0 +1,63 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/scopedarray.h +// Purpose: scoped smart pointer class +// Author: Vadim Zeitlin +// Created: 2009-02-03 +// RCS-ID: $Id: scopedarray.h 58634 2009-02-03 12:01:46Z VZ $ +// Copyright: (c) Jesse Lovelace and original Boost authors (see below) +// (c) 2009 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#pragma once +#include "wx/defs.h" + +// ---------------------------------------------------------------------------- +// wxScopedArray: A scoped array, same as a wxScopedPtr but uses delete[] +// instead of delete. +// ---------------------------------------------------------------------------- + +template +class wxScopedArray +{ +public: + typedef T element_type; + + wxEXPLICIT wxScopedArray(T * array = NULL) : m_array(array) { } + + ~wxScopedArray() { delete [] m_array; } + + // test for pointer validity: defining conversion to unspecified_bool_type + // and not more obvious bool to avoid implicit conversions to integer types + typedef T *(wxScopedArray::*unspecified_bool_type)() const; + operator unspecified_bool_type() const + { + return m_array ? &wxScopedArray::get : NULL; + } + + void reset(T *array = NULL) + { + if ( array != m_array ) + { + delete [] m_array; + m_array = array; + } + } + + T& operator[](size_t n) const { return m_array[n]; } + + T *get() const { return m_array; } + + void swap(wxScopedArray &other) + { + T * const tmp = other.m_array; + other.m_array = m_array; + m_array = tmp; + } + +private: + T *m_array; + + wxScopedArray(const wxScopedArray&); + wxScopedArray& operator=(const wxScopedArray&); +}; diff --git a/common/include/wx/scopedptr.h b/common/include/wx/scopedptr.h new file mode 100644 index 0000000000..ce88d4e40e --- /dev/null +++ b/common/include/wx/scopedptr.h @@ -0,0 +1,99 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/scopedptr.h +// Purpose: scoped smart pointer class +// Author: Jesse Lovelace +// Created: 06/01/02 +// RCS-ID: $Id: scopedptr.h 60411 2009-04-27 13:59:08Z CE $ +// Copyright: (c) Jesse Lovelace and original Boost authors (see below) +// (c) 2009 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#pragma once +#include "wx/defs.h" + +// This class closely follows the implementation of the boost +// library scoped_ptr and is an adaption for c++ macro's in +// the wxWidgets project. The original authors of the boost +// scoped_ptr are given below with their respective copyrights. + +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation. +// + +// ---------------------------------------------------------------------------- +// wxScopedPtr: A scoped pointer +// ---------------------------------------------------------------------------- + +template +class wxScopedPtr +{ +public: + typedef T element_type; + + wxEXPLICIT wxScopedPtr(T * ptr = NULL) : m_ptr(ptr) { } + + ~wxScopedPtr() { delete m_ptr; } + + // test for pointer validity: defining conversion to unspecified_bool_type + // and not more obvious bool to avoid implicit conversions to integer types + typedef T *(wxScopedPtr::*unspecified_bool_type)() const; + + operator unspecified_bool_type() const + { + return m_ptr ? &wxScopedPtr::get : NULL; + } + + void reset(T * ptr = NULL) + { + if ( ptr != m_ptr ) + { + delete m_ptr; + m_ptr = ptr; + } + } + + T *release() + { + T *ptr = m_ptr; + m_ptr = NULL; + return ptr; + } + + T & operator*() const + { + wxASSERT(m_ptr != NULL); + return *m_ptr; + } + + T * operator->() const + { + wxASSERT(m_ptr != NULL); + return m_ptr; + } + + T * get() const + { + return m_ptr; + } + + void swap(wxScopedPtr& other) + { + T * const tmp = other.m_ptr; + other.m_ptr = m_ptr; + m_ptr = tmp; + } + +private: + T * m_ptr; + + wxScopedPtr(const wxScopedPtr&); + wxScopedPtr& operator=(const wxScopedPtr&); +}; diff --git a/pcsx2/Config.h b/pcsx2/Config.h index ef7e598f0a..23fe962d36 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -36,6 +36,13 @@ enum PluginsEnum_t // equality operators. #define OpEqu( field ) (field == right.field) +// Macro used for removing some of the redtape involved in defining bitfield/union helpers. +// +#define BITFIELD32() \ + union { \ + u32 bitset; \ + struct { + //------------ DEFAULT sseMXCSR VALUES --------------- #define DEFAULT_sseMXCSR 0xffc0 //FPU rounding > DaZ, FtZ, "chop" #define DEFAULT_sseVUMXCSR 0xffc0 //VU rounding > DaZ, FtZ, "chop" @@ -58,72 +65,57 @@ class Pcsx2Config public: struct ProfilerOptions { - union - { - struct - { - bool - Enabled:1, // universal toggle for the profiler. - RecBlocks_EE:1, // Enables per-block profiling for the EE recompiler [unimplemented] - RecBlocks_IOP:1, // Enables per-block profiling for the IOP recompiler [unimplemented] - RecBlocks_VU0:1, // Enables per-block profiling for the VU0 recompiler [unimplemented] - RecBlocks_VU1:1; // Enables per-block profiling for the VU1 recompiler [unimplemented] - }; - u8 bits; - }; - - ProfilerOptions() : bits( 0 ) {} + BITFIELD32() + bool + Enabled:1, // universal toggle for the profiler. + RecBlocks_EE:1, // Enables per-block profiling for the EE recompiler [unimplemented] + RecBlocks_IOP:1, // Enables per-block profiling for the IOP recompiler [unimplemented] + RecBlocks_VU0:1, // Enables per-block profiling for the VU0 recompiler [unimplemented] + RecBlocks_VU1:1; // Enables per-block profiling for the VU1 recompiler [unimplemented] + }; }; + // Default is Disabled, with all recs enabled underneath. + ProfilerOptions() : bitset( 0xfffffffe ) {} void LoadSave( IniInterface& conf ); bool operator ==( const ProfilerOptions& right ) const { - return OpEqu( bits ); + return OpEqu( bitset ); } bool operator !=( const ProfilerOptions& right ) const { - return !this->operator ==( right ); + return !OpEqu( bitset ); } }; - + // ------------------------------------------------------------------------ struct RecompilerOptions { - union - { - struct - { - bool - EnableEE:1, - EnableIOP:1, - EnableVU0:1, - EnableVU1:1; - - bool - UseMicroVU0:1, - UseMicroVU1:1; - }; - u8 bits; - }; + BITFIELD32() + bool + EnableEE:1, + EnableIOP:1, + EnableVU0:1, + EnableVU1:1; + + bool + UseMicroVU0:1, + UseMicroVU1:1; + }; }; - RecompilerOptions() : bits( 0 ) { } - - void Load( const wxString& srcfile ); - void Load( const wxInputStream& srcstream ); - void Save( const wxString& dstfile ); - void Save( const wxOutputStream& deststream ); - + // All recs are enabled by default. + RecompilerOptions() : bitset( 0xffffffff ) { } void LoadSave( IniInterface& conf ); bool operator ==( const RecompilerOptions& right ) const { - return OpEqu( bits ); + return OpEqu( bitset ); } bool operator !=( const RecompilerOptions& right ) const { - return !this->operator ==( right ); + return !OpEqu( bitset ); } } Recompiler; @@ -136,38 +128,27 @@ public: u32 sseMXCSR; u32 sseVUMXCSR; - struct - { - union - { - bool - vuOverflow:1, - vuExtraOverflow:1, - vuSignOverflow:1, - vuUnderflow:1; - - bool - fpuOverflow:1, - fpuExtraOverflow:1, - fpuFullMode:1; - }; - u8 bits; - }; - - CpuOptions() : - sseMXCSR( DEFAULT_sseMXCSR ) - , sseVUMXCSR( DEFAULT_sseVUMXCSR ) - , bits( 0 ) - { - } + BITFIELD32() + bool + vuOverflow:1, + vuExtraOverflow:1, + vuSignOverflow:1, + vuUnderflow:1; + + bool + fpuOverflow:1, + fpuExtraOverflow:1, + fpuFullMode:1; + }; }; + CpuOptions(); void LoadSave( IniInterface& conf ); bool operator ==( const CpuOptions& right ) const { return OpEqu( sseMXCSR ) && OpEqu( sseVUMXCSR ) && - OpEqu( bits ) && OpEqu( Recompiler ); + OpEqu( bitset ) && OpEqu( Recompiler ); } bool operator !=( const CpuOptions& right ) const @@ -193,68 +174,59 @@ public: int ConsecutiveFrames; // number of consecutive frames (fields) to render int ConsecutiveSkip; // number of consecutive frames (fields) to skip + VideoOptions(); void LoadSave( IniInterface& conf ); }; // ------------------------------------------------------------------------ struct GamefixOptions { - union - { - struct - { - bool - VuAddSubHack:1, // Fix for Tri-ace games, they use an encryption algorithm that requires VU ADDI opcode to be bit-accurate. - VuClipFlagHack:1, // Fix for Digimon Rumble Arena 2, fixes spinning/hanging on intro-menu. - FpuCompareHack:1, // Fix for Persona games, maybe others. It's to do with the VU clip flag (again). - FpuMulHack:1, // Fix for Tales of Destiny hangs. - XgKickHack:1; // Fix for Erementar Gerad, adds more delay to VU XGkick instructions. Corrects the color of some graphics, but breaks Tri-ace games and others. - }; - u8 bits; - }; - - GamefixOptions() : bits( 0 ) {} + BITFIELD32() + bool + VuAddSubHack:1, // Fix for Tri-ace games, they use an encryption algorithm that requires VU ADDI opcode to be bit-accurate. + VuClipFlagHack:1, // Fix for Digimon Rumble Arena 2, fixes spinning/hanging on intro-menu. + FpuCompareHack:1, // Fix for Persona games, maybe others. It's to do with the VU clip flag (again). + FpuMulHack:1, // Fix for Tales of Destiny hangs. + XgKickHack:1; // Fix for Erementar Gerad, adds more delay to VU XGkick instructions. Corrects the color of some graphics, but breaks Tri-ace games and others. + }; }; + // all gamefixes are disabled by default. + GamefixOptions() : bitset( 0 ) {} void LoadSave( IniInterface& conf ); bool operator ==( const GamefixOptions& right ) const { - return OpEqu( bits ); + return OpEqu( bitset ); } bool operator !=( const GamefixOptions& right ) const { - return !this->operator ==( right ); + return !OpEqu( bitset ); } }; // ------------------------------------------------------------------------ struct SpeedhackOptions { - union - { - struct - { - int - EECycleRate:2, // EE cyclerate selector (1.0, 1.5, 2.0) - VUCycleSteal:3, // VU Cycle Stealer factor (0, 1, 2, or 3) - IopCycleRate_X2:1, // enables the x2 multiplier of the IOP cyclerate - IntcStat:1, // tells Pcsx2 to fast-forward through intc_stat waits. - BIFC0:1, // enables BIFC0 detection and fast-forwarding - - vuMinMax:1, // microVU specific MinMax hack; Can cause SPS, Black Screens, etc... - vuFlagHack:1; // MicroVU specific flag hack; Can cause Infinite loops, SPS, etc... - }; - u16 bits; - }; + BITFIELD32() + bool + IopCycleRate_X2:1, // enables the x2 multiplier of the IOP cyclerate + IntcStat:1, // tells Pcsx2 to fast-forward through intc_stat waits. + BIFC0:1, // enables BIFC0 detection and fast-forwarding + + vuMinMax:1, // microVU specific MinMax hack; Can cause SPS, Black Screens, etc... + vuFlagHack:1; // MicroVU specific flag hack; Can cause Infinite loops, SPS, etc... + }; }; - SpeedhackOptions() : bits( 0 ) {} + u8 EECycleRate; // EE cyclerate selector (1.0, 1.5, 2.0) + u8 VUCycleSteal; // VU Cycle Stealer factor (0, 1, 2, or 3) + SpeedhackOptions(); void LoadSave( IniInterface& conf ); bool operator ==( const SpeedhackOptions& right ) const { - return OpEqu( bits ); + return OpEqu( bitset ) && OpEqu( EECycleRate ) && OpEqu( VUCycleSteal ); } bool operator !=( const SpeedhackOptions& right ) const @@ -264,18 +236,22 @@ public: }; public: - bool CdvdVerboseReads:1; // enables cdvd read activity verbosely dumped to the console - bool CdvdDumpBlocks:1; // enables cdvd block dumping - bool EnablePatches:1; // enables patch detection and application - // when enabled performs bios stub execution, skipping full sony bios + splash screens - bool SkipBiosSplash:1; + BITFIELD32() + bool + CdvdVerboseReads:1, // enables cdvd read activity verbosely dumped to the console + CdvdDumpBlocks:1, // enables cdvd block dumping + EnablePatches:1, // enables patch detection and application - // Closes the GS/Video port on escape (good for fullscreen activity) - bool closeGSonEsc:1; + // when enabled performs bios stub execution, skipping full sony bios + splash screens + SkipBiosSplash:1, - // enables simulated ejection of memory cards when loading savestates - bool McdEnableEjection:1; + // Closes the GS/Video port on escape (good for fullscreen activity) + closeGSonEsc:1, + + // enables simulated ejection of memory cards when loading savestates + McdEnableEjection:1; + }; }; CpuOptions Cpu; VideoOptions Video; @@ -283,12 +259,13 @@ public: GamefixOptions Gamefixes; ProfilerOptions Profiler; + Pcsx2Config(); + void LoadSave( IniInterface& ini ); + void Load( const wxString& srcfile ); void Load( const wxInputStream& srcstream ); void Save( const wxString& dstfile ); void Save( const wxOutputStream& deststream ); - - void LoadSave( IniInterface& ini ); }; ////////////////////////////////////////////////////////////////////////// diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index d0768a0345..26d3e1679b 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -19,91 +19,152 @@ #include "PrecompiledHeader.h" #include "IniInterface.h" #include "Config.h" +#include "GS.h" + #include +// all speedhacks are disabled by default +Pcsx2Config::SpeedhackOptions::SpeedhackOptions() : + bitset( 0 ) +, EECycleRate( 0 ) +, VUCycleSteal( 0 ) +{ +} + void Pcsx2Config::SpeedhackOptions::LoadSave( IniInterface& ini ) { + SpeedhackOptions defaults; ini.SetPath( L"Speedhacks" ); - IniBitfield( EECycleRate, 0 ); - IniBitfield( VUCycleSteal, 0 ); - IniBitBool( IopCycleRate_X2, false ); - IniBitBool( IntcStat, false ); - IniBitBool( BIFC0, false ); + IniBitfield( EECycleRate ); + IniBitfield( VUCycleSteal ); + IniBitBool( IopCycleRate_X2 ); + IniBitBool( IntcStat ); + IniBitBool( BIFC0 ); ini.SetPath( L".." ); } void Pcsx2Config::ProfilerOptions::LoadSave( IniInterface& ini ) { + ProfilerOptions defaults; ini.SetPath( L"Profiler" ); - IniBitBool( Enabled, false ); - IniBitBool( RecBlocks_EE, true ); - IniBitBool( RecBlocks_IOP, true ); - IniBitBool( RecBlocks_VU0, true ); - IniBitBool( RecBlocks_VU1, true ); + IniBitBool( Enabled ); + IniBitBool( RecBlocks_EE ); + IniBitBool( RecBlocks_IOP ); + IniBitBool( RecBlocks_VU0 ); + IniBitBool( RecBlocks_VU1 ); ini.SetPath( L".." ); } void Pcsx2Config::RecompilerOptions::LoadSave( IniInterface& ini ) { + RecompilerOptions defaults; ini.SetPath( L"Recompiler" ); - IniBitBool( EnableEE, true ); - IniBitBool( EnableIOP, true ); - IniBitBool( EnableVU0, true ); - IniBitBool( EnableVU1, true ); + IniBitBool( EnableEE ); + IniBitBool( EnableIOP ); + IniBitBool( EnableVU0 ); + IniBitBool( EnableVU1 ); ini.SetPath( L".." ); } +Pcsx2Config::CpuOptions::CpuOptions() : + bitset( 0 ) +, sseMXCSR( DEFAULT_sseMXCSR ) +, sseVUMXCSR( DEFAULT_sseVUMXCSR ) +{ + vuOverflow = true; + fpuOverflow = true; +} + void Pcsx2Config::CpuOptions::LoadSave( IniInterface& ini ) { + CpuOptions defaults; ini.SetPath( L"CPU" ); - IniEntry( sseMXCSR, DEFAULT_sseMXCSR ); - IniEntry( sseVUMXCSR, DEFAULT_sseVUMXCSR ); + IniEntry( sseMXCSR ); + IniEntry( sseVUMXCSR ); - IniBitBool( vuOverflow, true ); - IniBitBool( vuExtraOverflow, false ); - IniBitBool( vuSignOverflow, false ); - IniBitBool( vuUnderflow, false ); + IniBitBool( vuOverflow ); + IniBitBool( vuExtraOverflow ); + IniBitBool( vuSignOverflow ); + IniBitBool( vuUnderflow ); - IniBitBool( fpuOverflow, true ); - IniBitBool( fpuExtraOverflow, false ); - IniBitBool( fpuFullMode, false ); + IniBitBool( fpuOverflow ); + IniBitBool( fpuExtraOverflow ); + IniBitBool( fpuFullMode ); Recompiler.LoadSave( ini ); ini.SetPath( L".." ); } +Pcsx2Config::VideoOptions::VideoOptions() : + EnableFrameLimiting( false ) +, EnableFrameSkipping( false ) +, DefaultRegionMode( Region_NTSC ) +, FpsTurbo( 60*4 ) +, FpsLimit( 60 ) +, FpsSkip( 55 ) +, ConsecutiveFrames( 2 ) +, ConsecutiveSkip( 1 ) +{ +} + void Pcsx2Config::VideoOptions::LoadSave( IniInterface& ini ) { + VideoOptions defaults; ini.SetPath( L"Video" ); + IniEntry( EnableFrameLimiting ); + IniEntry( EnableFrameSkipping ); + + static const wxChar * const ntsc_pal_str[2] = { L"ntsc", L"pal" }; + ini.EnumEntry( L"DefaultRegionMode", DefaultRegionMode, ntsc_pal_str, defaults.DefaultRegionMode ); + + IniEntry( FpsTurbo ); + IniEntry( FpsLimit ); + IniEntry( FpsSkip ); + IniEntry( ConsecutiveFrames ); + IniEntry( ConsecutiveSkip ); + ini.SetPath( L".." ); } void Pcsx2Config::GamefixOptions::LoadSave( IniInterface& ini ) { - ini.SetPath( L"Video" ); + GamefixOptions defaults; + ini.SetPath( L"Gamefixes" ); + + IniBitBool( VuAddSubHack ); + IniBitBool( VuClipFlagHack ); + IniBitBool( FpuCompareHack ); + IniBitBool( FpuMulHack ); + IniBitBool( XgKickHack ); ini.SetPath( L".." ); } +Pcsx2Config::Pcsx2Config() : + bitset( 0 ) +{ +} + void Pcsx2Config::LoadSave( IniInterface& ini ) { + Pcsx2Config defaults; ini.SetPath( L"EmuCore" ); - - IniBitBool( CdvdVerboseReads, false ); - IniBitBool( CdvdDumpBlocks, false ); - IniBitBool( EnablePatches, false ); - IniBitBool( closeGSonEsc, false ); - IniBitBool( McdEnableEjection, false ); + IniBitBool( CdvdVerboseReads ); + IniBitBool( CdvdDumpBlocks ); + IniBitBool( EnablePatches ); + + IniBitBool( closeGSonEsc ); + IniBitBool( McdEnableEjection ); // Process various sub-components: diff --git a/pcsx2/Plugins.cpp b/pcsx2/Plugins.cpp index be81deb3ce..23d8a6cddf 100644 --- a/pcsx2/Plugins.cpp +++ b/pcsx2/Plugins.cpp @@ -18,6 +18,7 @@ #include "PrecompiledHeader.h" #include "Utilities/RedtapeWindows.h" +#include "Utilities/ScopedPtr.h" #include #include @@ -46,9 +47,20 @@ const PluginInfo tbl_PluginInfo[] = }; +int EnumeratePluginsFolder( wxArrayString* dest ) +{ + wxScopedPtr placebo; + wxArrayString* realdest = dest; + if( realdest == NULL ) + placebo.reset( realdest = new wxArrayString() ); + + return g_Conf->Folders.Plugins.Exists() ? + wxDir::GetAllFiles( g_Conf->Folders.Plugins.ToString(), realdest, wxsFormat( L"*%s", wxDynamicLibrary::GetDllExt()), wxDIR_FILES ) : 0; +} + + typedef void CALLBACK VoidMethod(); typedef void CALLBACK vMeth(); // shorthand for VoidMethod -; // extra semicolon fixes VA-X intellisense breakage caused by CALLBACK in the above typedef >_< // ---------------------------------------------------------------------------- struct LegacyApi_CommonMethod diff --git a/pcsx2/Plugins.h b/pcsx2/Plugins.h index 54924566b7..0ce6c012f2 100644 --- a/pcsx2/Plugins.h +++ b/pcsx2/Plugins.h @@ -109,6 +109,8 @@ protected: extern const PluginInfo tbl_PluginInfo[]; extern PluginManager* g_plugins; +extern int EnumeratePluginsFolder( wxArrayString* dest ); + void LoadPlugins(); void ReleasePlugins(); diff --git a/pcsx2/gui/AppConfig.cpp b/pcsx2/gui/AppConfig.cpp index 3c4ed21319..9adb2685be 100644 --- a/pcsx2/gui/AppConfig.cpp +++ b/pcsx2/gui/AppConfig.cpp @@ -95,10 +95,7 @@ namespace PathDefs // share with other programs: screenshots, memory cards, and savestates. wxDirName GetDocuments() { - if( g_Conf->UseAdminMode ) - return (wxDirName)wxGetCwd(); - else - return (wxDirName)wxStandardPaths::Get().GetDocumentsDir() + (wxDirName)wxGetApp().GetAppName(); + return (wxDirName)g_Conf->GetDefaultDocumentsFolder(); } wxDirName GetSnapshots() @@ -159,6 +156,13 @@ namespace PathDefs } }; +wxString AppConfig::GetDefaultDocumentsFolder() +{ + if( UseAdminMode ) + return wxGetCwd(); + else + return Path::Combine( wxStandardPaths::Get().GetDocumentsDir(), wxGetApp().GetAppName() ); +} const wxDirName& AppConfig::FolderOptions::operator[]( FoldersEnum_t folderidx ) const { @@ -345,10 +349,32 @@ wxString AppConfig::FullpathTo( PluginsEnum_t pluginidx ) const wxString AppConfig::FullpathToBios() const { return Path::Combine( Folders.Bios, BaseFilenames.Bios ); } wxString AppConfig::FullpathToMcd( uint mcdidx ) const { return Path::Combine( Folders.MemoryCards, Mcd[mcdidx].Filename ); } +AppConfig::AppConfig() : + MainGuiPosition( wxDefaultPosition ) +, LanguageId( wxLANGUAGE_DEFAULT ) +, RecentFileCount( 6 ) +, DeskTheme( L"default" ) +, Listbook_ImageSize( 32 ) +, Toolbar_ImageSize( 24 ) +, Toolbar_ShowLabels( true ) + +, McdEnableNTFS( true ) + +, ProgLogBox() +, Ps2ConBox() +, Folders() +, BaseFilenames() +, EmuOptions() +, m_IsLoaded( false ) +{ +} + // ------------------------------------------------------------------------ void AppConfig::LoadSaveUserMode( IniInterface& ini ) { - IniEntry( UseAdminMode, false ); + AppConfig defaults; + + ini.Entry( L"UseAdminMode", UseAdminMode, false ); ini.Entry( L"SettingsPath", Folders.Settings, PathDefs::GetSettings() ); ini.Flush(); @@ -357,18 +383,20 @@ void AppConfig::LoadSaveUserMode( IniInterface& ini ) // ------------------------------------------------------------------------ void AppConfig::LoadSave( IniInterface& ini ) { - IniEntry( MainGuiPosition, wxDefaultPosition ); - ini.EnumEntry( L"LanguageId", LanguageId ); - IniEntry( RecentFileCount, 6 ); - IniEntry( DeskTheme, L"default" ); - IniEntry( Listbook_ImageSize, 32 ); - IniEntry( Toolbar_ImageSize, 24 ); - IniEntry( Toolbar_ShowLabels, true ); + AppConfig defaults; + + IniEntry( MainGuiPosition ); + ini.EnumEntry( L"LanguageId", LanguageId, NULL, defaults.LanguageId ); + IniEntry( RecentFileCount ); + IniEntry( DeskTheme ); + IniEntry( Listbook_ImageSize ); + IniEntry( Toolbar_ImageSize ); + IniEntry( Toolbar_ShowLabels ); // Process various sub-components: ProgLogBox.LoadSave( ini, L"ProgramLog" ); Ps2ConBox.LoadSave( ini, L"Ps2Console" ); - + Folders.LoadSave( ini ); BaseFilenames.LoadSave( ini ); @@ -391,14 +419,14 @@ void AppConfig::Apply() // Ensure existence of necessary documents folders. Plugins and other parts // of PCSX2 rely on them. - g_Conf->Folders.MemoryCards.Mkdir(); - g_Conf->Folders.Savestates.Mkdir(); - g_Conf->Folders.Snapshots.Mkdir(); + Folders.MemoryCards.Mkdir(); + Folders.Savestates.Mkdir(); + Folders.Snapshots.Mkdir(); // Update the compression attribute on the Memcards folder. // Memcards generally compress very well via NTFS compression. - NTFS_CompressFile( g_Conf->Folders.MemoryCards.ToString(), g_Conf->McdEnableNTFS ); + NTFS_CompressFile( Folders.MemoryCards.ToString(), McdEnableNTFS ); bool prev = wxLog::EnableLogging( false ); // wx generates verbose errors if languages don't exist, so disable them here. if( !i18n_SetLanguage( LanguageId ) ) @@ -445,15 +473,25 @@ void AppConfig::Save() } // ------------------------------------------------------------------------ +AppConfig::ConsoleLogOptions::ConsoleLogOptions() : + Visible( false ) +, AutoDock( true ) +, DisplayPosition( wxDefaultPosition ) +, DisplaySize( wxSize( 540, 540 ) ) +, FontSize( 8 ) +{ +} + void AppConfig::ConsoleLogOptions::LoadSave( IniInterface& ini, const wxChar* logger ) { + ConsoleLogOptions defaults; ini.SetPath( logger ); - IniEntry( Visible, false ); - IniEntry( AutoDock, true ); - IniEntry( DisplayPosition, wxDefaultPosition ); - IniEntry( DisplaySize, wxSize( 540, 540 ) ); - IniEntry( FontSize, 8 ); + IniEntry( Visible ); + IniEntry( AutoDock ); + IniEntry( DisplayPosition ); + IniEntry( DisplaySize ); + IniEntry( FontSize ); ini.SetPath( L".." ); } @@ -470,30 +508,45 @@ void AppConfig::FolderOptions::ApplyDefaults() } // ------------------------------------------------------------------------ +AppConfig::FolderOptions::FolderOptions() : + bitset( 0xffffffff ) +, Plugins( PathDefs::GetPlugins() ) +, Settings( PathDefs::GetSettings() ) +, Bios( PathDefs::GetBios() ) +, Snapshots( PathDefs::GetSnapshots() ) +, Savestates( PathDefs::GetSavestates() ) +, MemoryCards( PathDefs::GetMemoryCards() ) +, Logs( PathDefs::GetLogs() ) + +, RunIso( PathDefs::GetDocuments() ) // raw default is always the Documents folder. +{ +} + void AppConfig::FolderOptions::LoadSave( IniInterface& ini ) { + FolderOptions defaults; ini.SetPath( L"Folders" ); if( ini.IsSaving() ) ApplyDefaults(); - IniEntry( Plugins, PathDefs::GetPlugins() ); - IniEntry( Settings, PathDefs::GetSettings() ); - IniEntry( Bios, PathDefs::GetBios() ); - IniEntry( Snapshots, PathDefs::GetSnapshots() ); - IniEntry( Savestates, PathDefs::GetSavestates() ); - IniEntry( MemoryCards, PathDefs::GetMemoryCards() ); - IniEntry( Logs, PathDefs::GetLogs() ); + IniBitBool( UseDefaultPlugins ); + IniBitBool( UseDefaultSettings ); + IniBitBool( UseDefaultBios ); + IniBitBool( UseDefaultSnapshots ); + IniBitBool( UseDefaultSavestates ); + IniBitBool( UseDefaultMemoryCards ); + IniBitBool( UseDefaultLogs ); - IniEntry( RunIso, PathDefs::GetDocuments() ); // raw default is always the Documents folder. + IniEntry( Plugins ); + IniEntry( Settings ); + IniEntry( Bios ); + IniEntry( Snapshots ); + IniEntry( Savestates ); + IniEntry( MemoryCards ); + IniEntry( Logs ); - IniBitBool( UseDefaultPlugins, true ); - IniBitBool( UseDefaultSettings, true ); - IniBitBool( UseDefaultBios, true ); - IniBitBool( UseDefaultSnapshots, true ); - IniBitBool( UseDefaultSavestates, true ); - IniBitBool( UseDefaultMemoryCards, true ); - IniBitBool( UseDefaultLogs, true ); + IniEntry( RunIso ); if( ini.IsLoading() ) ApplyDefaults(); @@ -535,3 +588,29 @@ void AppConfig::FilenameOptions::LoadSave( IniInterface& ini ) ini.SetPath( L".." ); } +wxFileConfig* OpenFileConfig( const wxString& filename ) +{ + return new wxFileConfig( wxEmptyString, wxEmptyString, filename, wxEmptyString, wxCONFIG_USE_RELATIVE_PATH ); +} + +// Parameters: +// overwrite - this option forces the current settings to overwrite any existing settings that might +// be saved to the configured ini/settings folder. +// +void AppConfig_ReloadGlobalSettings( bool overwrite ) +{ + PathDefs::GetDocuments().Mkdir(); + PathDefs::GetSettings().Mkdir(); + + // Allow wx to use our config, and enforces auto-cleanup as well + wxString confile( g_Conf->Folders.Settings.Combine( FilenameDefs::GetConfig() ).GetFullPath() ); + delete wxConfigBase::Set( OpenFileConfig( confile ) ); + wxConfigBase::Get()->SetRecordDefaults(); + + if( !overwrite ) + g_Conf->Load(); + + g_Conf->Apply(); + g_Conf->Folders.Logs.Mkdir(); +} + diff --git a/pcsx2/gui/AppConfig.h b/pcsx2/gui/AppConfig.h index 98dd52cd6e..5ddbbb4184 100644 --- a/pcsx2/gui/AppConfig.h +++ b/pcsx2/gui/AppConfig.h @@ -20,6 +20,8 @@ class IniInterface; +extern bool UseAdminMode; // dictates if the program uses /home/user or /cwd for the program data + ////////////////////////////////////////////////////////////////////////////////////////// // Pcsx2 Application Configuration. // @@ -40,12 +42,24 @@ public: // Size of the font in points. int FontSize; + ConsoleLogOptions(); void LoadSave( IniInterface& conf, const wxChar* title ); }; // ------------------------------------------------------------------------ struct FolderOptions { + BITFIELD32() + bool + UseDefaultPlugins:1, + UseDefaultSettings:1, + UseDefaultBios:1, + UseDefaultSnapshots:1, + UseDefaultSavestates:1, + UseDefaultMemoryCards:1, + UseDefaultLogs:1; + }; }; + wxDirName Plugins, Settings, @@ -57,15 +71,7 @@ public: wxDirName RunIso; // last used location for Iso loading. - bool - UseDefaultPlugins:1, - UseDefaultSettings:1, - UseDefaultBios:1, - UseDefaultSnapshots:1, - UseDefaultSavestates:1, - UseDefaultMemoryCards:1, - UseDefaultLogs:1; - + FolderOptions(); void LoadSave( IniInterface& conf ); void ApplyDefaults(); @@ -96,7 +102,6 @@ public: }; public: - bool UseAdminMode; // dictates if the program uses /home/user or /cwd for the program data wxPoint MainGuiPosition; // Current language in use (correlates to a wxWidgets wxLANGUAGE specifier) @@ -140,12 +145,7 @@ protected: bool m_IsLoaded; public: - AppConfig() : - Listbook_ImageSize( 32 ) - , Toolbar_ImageSize( 24 ) - , m_IsLoaded( false ) - { - } + AppConfig(); wxString FullpathToBios() const; wxString FullpathToMcd( uint mcdidx ) const; @@ -156,8 +156,15 @@ public: void Apply(); void LoadSaveUserMode( IniInterface& ini ); + wxString GetDefaultDocumentsFolder(); + protected: void LoadSave( IniInterface& ini ); }; +class wxFileConfig; // forward declare. + +extern wxFileConfig* OpenFileConfig( const wxString& filename ); +extern void AppConfig_ReloadGlobalSettings( bool overwrite = false ); + extern AppConfig* g_Conf; diff --git a/pcsx2/gui/Dialogs/ConfigurationDialog.cpp b/pcsx2/gui/Dialogs/ConfigurationDialog.cpp index 610d9b2327..fd9462b94c 100644 --- a/pcsx2/gui/Dialogs/ConfigurationDialog.cpp +++ b/pcsx2/gui/Dialogs/ConfigurationDialog.cpp @@ -67,15 +67,14 @@ Dialogs::ConfigurationDialog::ConfigurationDialog( wxWindow* parent, int id ) : m_listbook.AddPage( new PluginSelectorPanel( m_listbook, IdealWidth ), _("Plugins"), false, cfgid.Plugins ); g_ApplyState.SetCurrentPage( m_listbook.GetPageCount() ); - m_listbook.AddPage( new PathsPanel( m_listbook, IdealWidth ), _("Folders"), false, cfgid.Paths ); - + m_listbook.AddPage( new TabbedPathsPanel( m_listbook, IdealWidth ), _("Folders"), false, cfgid.Paths ); mainSizer.Add( &m_listbook ); AddOkCancel( mainSizer, true ); SetSizerAndFit( &mainSizer ); - Center( wxCENTER_ON_SCREEN | wxBOTH ); + CenterOnScreen(); Connect( wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigurationDialog::OnOk_Click ) ); Connect( wxID_APPLY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigurationDialog::OnApply_Click ) ); diff --git a/pcsx2/gui/Dialogs/FirstTimeWizard.cpp b/pcsx2/gui/Dialogs/FirstTimeWizard.cpp new file mode 100644 index 0000000000..6a3aab240d --- /dev/null +++ b/pcsx2/gui/Dialogs/FirstTimeWizard.cpp @@ -0,0 +1,169 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2009 Pcsx2 Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "PrecompiledHeader.h" +#include "System.h" +#include "Plugins.h" + +#include "ModalPopups.h" +#include "Panels/ConfigurationPanels.h" + +using namespace wxHelpers; +using namespace Panels; + +template< typename T > +static T& MakeWizWidget( int pageid, wxWizardPage& src ) +{ + g_ApplyState.SetCurrentPage( pageid ); + return *new T( src, 620 ); +} + +FirstTimeWizard::FirstTimeWizard( wxWindow* parent ) : + wxWizard( (g_ApplyState.StartWizard(), parent), wxID_ANY, _("PCSX2 First Time Configuration") ) +, m_page_usermode( *new wxWizardPageSimple( this ) ) +//, m_page_paths( *new wxWizardPageSimple( this, &m_page_usermode ) ) +, m_page_plugins( *new wxWizardPageSimple( this, &m_page_usermode ) ) + +, m_panel_LangSel( MakeWizWidget( 0, m_page_usermode ) ) +, m_panel_UsermodeSel( MakeWizWidget( 0, m_page_usermode ) ) +, m_panel_Paths( MakeWizWidget( 0, m_page_usermode ) ) +, m_panel_PluginSel( MakeWizWidget( 1, m_page_plugins ) ) +{ + // Page 1 - User Mode and Language Selectors + wxBoxSizer& usermodeSizer( *new wxBoxSizer( wxVERTICAL ) ); + AddStaticTextTo( &m_page_usermode, usermodeSizer, _("PCSX2 is starting from a new or unknown folder and needs to be configured.") ); + usermodeSizer.Add( &m_panel_LangSel, SizerFlags::StdCenter() ); + usermodeSizer.Add( &m_panel_UsermodeSel, wxSizerFlags().Expand().Border( wxALL, 8 ) ); + + //AddStaticTextTo( this, usermodeSizer, _( "Advanced users can optionally configure these folders." ) ); + usermodeSizer.AddSpacer( 6 ); + usermodeSizer.Add( &m_panel_Paths, wxSizerFlags().Expand().Border( wxALL, 4 ) ); + m_page_usermode.SetSizerAndFit( &usermodeSizer ); + + // Page 2 - Advanced Paths Panel + /*wxBoxSizer& pathsSizer( *new wxBoxSizer( wxVERTICAL ) ); + pathsSizer.Add( &m_panel_Paths, SizerFlags::StdExpand() ); + m_page_paths.SetSizerAndFit( &pathsSizer );*/ + + // Page 3 - Plugins Panel + wxBoxSizer& pluginSizer( *new wxBoxSizer( wxVERTICAL ) ); + pluginSizer.Add( &m_panel_PluginSel, SizerFlags::StdExpand() ); + m_page_plugins.SetSizerAndFit( &pluginSizer ); + + // Assign page indexes as client data + m_page_usermode.SetClientData ( (void*)0 ); + //m_page_paths.SetClientData ( (void*)1 ); + m_page_plugins.SetClientData ( (void*)1 ); + + // Build the forward chain: + // (backward chain is built during initialization above) + m_page_usermode.SetNext ( &m_page_plugins ); + //m_page_paths.SetNext ( &m_page_plugins ); + + GetPageAreaSizer()->Add( &m_page_usermode ); + CenterOnScreen(); + + Connect( wxEVT_WIZARD_PAGE_CHANGED, wxWizardEventHandler( FirstTimeWizard::OnPageChanged ) ); + Connect( wxEVT_WIZARD_PAGE_CHANGING, wxWizardEventHandler( FirstTimeWizard::OnPageChanging ) ); + + Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler(FirstTimeWizard::OnUsermodeChanged) ); +} + +FirstTimeWizard::~FirstTimeWizard() +{ + g_ApplyState.DoCleanup(); +} + +void FirstTimeWizard::OnPageChanging( wxWizardEvent& evt ) +{ + //evt.Skip(); + if( evt.GetDirection() ) + { + // Moving forward: + // Apply settings from the current page... + + int page = (int)evt.GetPage()->GetClientData(); + + if( page >= 0 ) + { + if( !g_ApplyState.ApplyPage( page ) ) + { + evt.Veto(); + return; + } + AppConfig_ReloadGlobalSettings( true ); // ... and overwrite any existing settings + + // [TODO] : The user should be prompted if they want to overwrite existing + // settings or import them instead. + } + + if( page == 0 ) + { + // test plugins folder for validity. If it doesn't exist or is empty then + // the user needs to "try again" :) + + if( !g_Conf->Folders.Plugins.Exists() ) + { + Msgbox::Alert( _( "The selected plugins folder does not exist. You must select a valid PCSX2 plugins folder that exists and contains plugins." ) ); + evt.Veto(); + } + else + { + if( 0 == EnumeratePluginsFolder(NULL) ) + { + Msgbox::Alert( _( "The selected plugins folder is empty. You must select a valid PCSX2 plugins folder that actually contains plugins." ) ); + evt.Veto(); + } + } + } + } +} + +void FirstTimeWizard::OnPageChanged( wxWizardEvent& evt ) +{ + // Plugin Selector needs a special OnShow hack, because Wizard child panels don't + // receive any Show events >_< + if( (sptr)evt.GetPage() == (sptr)&m_page_plugins ) + m_panel_PluginSel.OnShow(); +} + +void FirstTimeWizard::OnUsermodeChanged( wxCommandEvent& evt ) +{ + //wxLogError( L"Awesome" ); + + m_panel_UsermodeSel.Apply( *g_Conf ); // this assigns the current user mode to g_ApplyState.UseAdminMode + if( g_ApplyState.UseAdminMode == UseAdminMode ) return; + + UseAdminMode = g_ApplyState.UseAdminMode; + g_Conf->Folders.ApplyDefaults(); + m_panel_Paths.Reset(); +} + +/* +wxString biosfolder( Path::Combine( conf.GetDefaultDocumentsFolder(), conf.Folders.Bios ) ); + +if( wxDir::Exists( biosfolder ) ) +{ + if( wxDir::GetAllFiles( biosfolder, NULL, L"*.bin", wxDIR_FILES ) ) +} + +if( !wxDir::Exists( biosfolder ) ) +{ + Msgbox::Alert( ("First Time Installation:\n\n") + BIOS_GetMsg_Required() ); +} +*/ \ No newline at end of file diff --git a/pcsx2/gui/Dialogs/ModalPopups.h b/pcsx2/gui/Dialogs/ModalPopups.h index 62aab9bcea..1f339b6e6e 100644 --- a/pcsx2/gui/Dialogs/ModalPopups.h +++ b/pcsx2/gui/Dialogs/ModalPopups.h @@ -18,12 +18,35 @@ #pragma once -#include -#include - -#include "wxHelpers.h" #include "Panels/ConfigurationPanels.h" +#include +#include + +class FirstTimeWizard : public wxWizard +{ +protected: + wxWizardPageSimple& m_page_usermode; + //wxWizardPageSimple& m_page_paths; + wxWizardPageSimple& m_page_plugins; + + Panels::LanguageSelectionPanel& m_panel_LangSel; + Panels::UsermodeSelectionPanel& m_panel_UsermodeSel; + Panels::AdvancedPathsPanel& m_panel_Paths; + Panels::PluginSelectorPanel& m_panel_PluginSel; + +public: + FirstTimeWizard( wxWindow* parent ); + virtual ~FirstTimeWizard(); + + wxWizardPage *GetFirstPage() const { return &m_page_usermode; } + +protected: + virtual void OnPageChanging( wxWizardEvent& evt ); + virtual void OnPageChanged( wxWizardEvent& evt ); + virtual void OnUsermodeChanged( wxCommandEvent& evt ); +}; + namespace Dialogs { class AboutBoxDialog: public wxDialog diff --git a/pcsx2/gui/Dialogs/PickUserModeDialog.cpp b/pcsx2/gui/Dialogs/PickUserModeDialog.cpp index 259cd227f5..c653652df3 100644 --- a/pcsx2/gui/Dialogs/PickUserModeDialog.cpp +++ b/pcsx2/gui/Dialogs/PickUserModeDialog.cpp @@ -26,8 +26,8 @@ using namespace wxHelpers; Dialogs::PickUserModeDialog::PickUserModeDialog( wxWindow* parent, int id ) : wxDialogWithHelpers( parent, id, _("PCSX2 First Time configuration"), false ) -, m_panel_usersel( new Panels::UsermodeSelectionPanel( this, 620 ) ) -, m_panel_langsel( new Panels::LanguageSelectionPanel( this, 620 ) ) +, m_panel_usersel( new Panels::UsermodeSelectionPanel( *this, 620, false ) ) +, m_panel_langsel( new Panels::LanguageSelectionPanel( *this, 620 ) ) { wxBoxSizer& s_main = *new wxBoxSizer( wxVERTICAL ); diff --git a/pcsx2/gui/IniInterface.h b/pcsx2/gui/IniInterface.h index a3a11c1491..7e28e9d46f 100644 --- a/pcsx2/gui/IniInterface.h +++ b/pcsx2/gui/IniInterface.h @@ -151,6 +151,6 @@ protected: // GCC Note: wxT() macro is required when using string token pasting. For some reason L generates // syntax errors. >_< // -#define IniEntry( varname, defval ) ini.Entry( wxT(#varname), varname, defval ) -#define IniBitfield( varname, defval ) varname = ini.EntryBitfield( wxT(#varname), varname, defval ) -#define IniBitBool( varname, defval ) varname = ini.EntryBitBool( wxT(#varname), !!varname, defval ) +#define IniEntry( varname ) ini.Entry( wxT(#varname), varname, defaults.varname ) +#define IniBitfield( varname ) varname = ini.EntryBitfield( wxT(#varname), varname, defaults.varname ) +#define IniBitBool( varname ) varname = ini.EntryBitBool( wxT(#varname), !!varname, defaults.varname ) diff --git a/pcsx2/gui/Panels/ConfigurationPanels.h b/pcsx2/gui/Panels/ConfigurationPanels.h index 2c9093d54b..6cc4980689 100644 --- a/pcsx2/gui/Panels/ConfigurationPanels.h +++ b/pcsx2/gui/Panels/ConfigurationPanels.h @@ -45,7 +45,7 @@ namespace Exception { // -------------------------------------------------------------------------- // Exception used to perform an abort of Apply/Ok action on settings panels. - // When thrown, the user recieves a popup message containing the information + // When thrown, the user receives a popup message containing the information // specified in the exception message, and is returned to the settings dialog // to correct the invalid input fields. // @@ -79,7 +79,6 @@ namespace Exception namespace Panels { - typedef std::list PanelApplyList_t; struct StaticApplyState @@ -91,9 +90,13 @@ namespace Panels // this page as their "go here on error" page. (used to take the user to the // page with the option that failed apply validation). int CurOwnerPage; - + // TODO : Rename me to CurOwnerBook, or rename the one above to ParentPage. wxBookCtrlBase* ParentBook; + + // Crappy hack to handle the UseAdminMode option, which can't be part of AppConfig + // because AppConfig depends on this value to initialize itself. + bool UseAdminMode; StaticApplyState() : PanelList() @@ -106,14 +109,16 @@ namespace Panels { CurOwnerPage = page; } - + void ClearCurrentPage() { CurOwnerPage = wxID_NONE; } void StartBook( wxBookCtrlBase* book ); + void StartWizard(); bool ApplyAll(); + bool ApplyPage( int pageid ); void DoCleanup(); }; @@ -124,8 +129,8 @@ namespace Panels // window (usually the ConfigurationDialog) when either Ok or Apply is clicked. // // Thread Safety: None. This class is only safe when used from the GUI thread, as it uses - // static vars and assumes that only one Applicableconfig system is available to the - // use rate any time (ie, a singular modal dialog). + // static vars and assumes that only one ApplicableConfig system is available to the + // user at any time (ie, a singular modal dialog). // class BaseApplicableConfigPanel : public wxPanelWithHelpers { @@ -156,6 +161,10 @@ namespace Panels m_OwnerBook->SetSelection( m_OwnerPage ); } + // Returns true if this ConfigPanel belongs to the specified page. Useful for doing + // selective application of options for specific pages. + bool IsOnPage( int pageid ) { return m_OwnerPage == pageid; } + // This method attempts to assign the settings for the panel into the given // configuration structure (which is typically a copy of g_Conf). If validation // of form contents fails, the function should throw Exception::CannotApplySettings. @@ -173,7 +182,7 @@ namespace Panels public: virtual ~UsermodeSelectionPanel() { } - UsermodeSelectionPanel( wxWindow* parent, int idealWidth=wxDefaultCoord ); + UsermodeSelectionPanel( wxWindow& parent, int idealWidth=wxDefaultCoord, bool isFirstTime = true ); void Apply( AppConfig& conf ); }; @@ -188,7 +197,7 @@ namespace Panels public: virtual ~LanguageSelectionPanel() { } - LanguageSelectionPanel( wxWindow* parent, int idealWidth=wxDefaultCoord ); + LanguageSelectionPanel( wxWindow& parent, int idealWidth=wxDefaultCoord ); void Apply( AppConfig& conf ); }; @@ -251,53 +260,73 @@ 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 PathsPanel : public BaseApplicableConfigPanel + class DirPickerPanel : public BaseApplicableConfigPanel { protected: - class DirPickerPanel : public BaseApplicableConfigPanel - { - protected: - FoldersEnum_t m_FolderId; - wxDirPickerCtrl* m_pickerCtrl; - wxCheckBox* m_checkCtrl; - - public: - DirPickerPanel( wxWindow* parent, FoldersEnum_t folderid, const wxString& label, const wxString& dialogLabel ); - void Apply( AppConfig& conf ); - - protected: - void UseDefaultPath_Click(wxCommandEvent &event); - void UpdateCheckStatus( bool someNoteworthyBoolean ); - }; - - class MyBasePanel : public wxPanelWithHelpers - { - protected: - wxBoxSizer& s_main; - - public: - MyBasePanel( wxWindow& parent, int idealWidth=wxDefaultCoord ); - - protected: - DirPickerPanel& AddDirPicker( wxBoxSizer& sizer, FoldersEnum_t folderid, - const wxString& label, const wxString& popupLabel ); - }; - - class StandardPanel : public MyBasePanel - { - public: - StandardPanel( wxWindow& parent ); - }; - - class AdvancedPanel : public MyBasePanel - { - public: - AdvancedPanel( wxWindow& parent, int idealWidth ); - }; + FoldersEnum_t m_FolderId; + wxDirPickerCtrl* m_pickerCtrl; + wxCheckBox* m_checkCtrl; public: - PathsPanel( wxWindow& parent, int idealWidth ); + DirPickerPanel( wxWindow* parent, FoldersEnum_t folderid, const wxString& label, const wxString& dialogLabel ); + void Apply( AppConfig& conf ); + void Reset(); + + protected: + void UseDefaultPath_Click(wxCommandEvent &event); + void UpdateCheckStatus( bool someNoteworthyBoolean ); + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // + class BasePathsPanel : public wxPanelWithHelpers + { + protected: + wxBoxSizer& s_main; + + public: + BasePathsPanel( wxWindow& parent, int idealWidth=wxDefaultCoord ); + virtual wxSizer& Sizer() { return s_main; } + + protected: + DirPickerPanel& AddDirPicker( wxBoxSizer& sizer, FoldersEnum_t folderid, + const wxString& label, const wxString& popupLabel ); + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // + class StandardPathsPanel : public BasePathsPanel + { + public: + StandardPathsPanel( wxWindow& parent ); + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // + class AdvancedPathsPanel : public BasePathsPanel + { + protected: + DirPickerPanel& m_dirpick_plugins; + DirPickerPanel& m_dirpick_settings; + + public: + AdvancedPathsPanel( wxWindow& parent, int idealWidth ); + void Reset(); + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // TabbedPathsPanel + // This panel is a Tabbed (paged) panel which contains both Standard Paths and Advanced + // Paths panels. + // + class TabbedPathsPanel : public BaseApplicableConfigPanel + { + public: + TabbedPathsPanel( wxWindow& parent, int idealWidth ); void Apply( AppConfig& conf ); }; @@ -368,7 +397,9 @@ namespace Panels int m_progress; public: - StatusPanel( wxWindow* parent, int pluginCount, int biosCount ); + StatusPanel( wxWindow* parent ); + + void SetGaugeLength( int len ); void AdvanceProgress( const wxString& msg ); void Reset(); }; @@ -378,27 +409,30 @@ namespace Panels // ------------------------------------------------------------------------ protected: - wxArrayString m_FileList; // list of potential plugin files - wxArrayString m_BiosList; + wxArrayString* m_FileList; // list of potential plugin files + wxArrayString* m_BiosList; StatusPanel& m_StatusPanel; ComboBoxPanel& m_ComponentBoxes; - bool m_Uninitialized; EnumThread* m_EnumeratorThread; public: virtual ~PluginSelectorPanel(); PluginSelectorPanel( wxWindow& parent, int idealWidth ); - virtual void OnShow( wxShowEvent& evt ); - virtual void OnRefresh( wxCommandEvent& evt ); virtual void OnProgress( wxCommandEvent& evt ); virtual void OnEnumComplete( wxCommandEvent& evt ); void Apply( AppConfig& conf ); - + void OnShow(); + protected: + virtual void OnShow( wxShowEvent& evt ); + virtual void OnRefresh( wxCommandEvent& evt ); + void DoRefresh(); - int FileCount() const { return m_FileList.Count(); } - const wxString& GetFilename( int i ) const { return m_FileList[i]; } + bool ValidateEnumerationStatus(); + + int FileCount() const { return m_FileList->Count(); } + const wxString& GetFilename( int i ) const { return (*m_FileList)[i]; } friend class EnumThread; }; } diff --git a/pcsx2/gui/Panels/MiscPanelStuff.cpp b/pcsx2/gui/Panels/MiscPanelStuff.cpp index d62bccc198..f552c9b104 100644 --- a/pcsx2/gui/Panels/MiscPanelStuff.cpp +++ b/pcsx2/gui/Panels/MiscPanelStuff.cpp @@ -18,6 +18,7 @@ #include "PrecompiledHeader.h" #include "ConfigurationPanels.h" +#include "ps2/BiosTools.h" #include @@ -43,22 +44,35 @@ void Panels::StaticApplyState::StartBook( wxBookCtrlBase* book ) ParentBook = book; } +void Panels::StaticApplyState::StartWizard() +{ + DevAssert( 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 Panels::StaticApplyState::ApplyAll() +bool Panels::StaticApplyState::ApplyPage( int pageid ) { bool retval = true; try { AppConfig confcopy( *g_Conf ); + g_ApplyState.UseAdminMode = UseAdminMode; + PanelApplyList_t::iterator yay = PanelList.begin(); while( yay != PanelList.end() ) { //DbgCon::Status( L"Writing settings for: " + (*yay)->GetLabel() ); - (*yay)->Apply( confcopy ); + if( (pageid < 0) || (*yay)->IsOnPage( pageid ) ) + (*yay)->Apply( confcopy ); yay++; } @@ -66,6 +80,7 @@ bool Panels::StaticApplyState::ApplyAll() // (conveniently skipping any option application! :D) *g_Conf = confcopy; + UseAdminMode = g_ApplyState.UseAdminMode; g_Conf->Apply(); g_Conf->Save(); } @@ -77,28 +92,43 @@ bool Panels::StaticApplyState::ApplyAll() ex.GetPanel()->SetFocusToMe(); retval = false; - } - return retval; + return retval; +} + +// Returns false if one of the panels fails input validation (in which case dialogs +// should not be closed, etc). +bool Panels::StaticApplyState::ApplyAll() +{ + return ApplyPage( -1 ); } // ----------------------------------------------------------------------- -Panels::UsermodeSelectionPanel::UsermodeSelectionPanel( wxWindow* parent, int idealWidth ) : - BaseApplicableConfigPanel( parent, idealWidth ) +Panels::UsermodeSelectionPanel::UsermodeSelectionPanel( wxWindow& parent, int idealWidth, bool isFirstTime ) : + BaseApplicableConfigPanel( &parent, idealWidth ) , m_radio_user( NULL ) , m_radio_cwd( NULL ) { - wxStaticBoxSizer& s_boxer = *new wxStaticBoxSizer( wxVERTICAL, this, _( "Usermode Selection" ) ); - AddStaticText( s_boxer, pxE( ".Panels:Usermode:Explained", + const wxString usermodeExplained( pxE( ".Panels:Usermode:Explained", L"Please select your preferred default location for PCSX2 user-level documents below " L"(includes memory cards, screenshots, settings, and savestates). " L"These folder locations can be overridden at any time using the Core Settings panel." ) ); + + const wxString usermodeWarning( pxE( ".Panels:Usermode:Warning", + L"You can change the preferred default location for PCSX2 user-level documents here " + L"(includes memory cards, screenshots, settings, and savestates). " + L"This option only affects Standard Paths which are set to use the installation default value." + ) ); + + wxStaticBoxSizer& s_boxer = *new wxStaticBoxSizer( wxVERTICAL, this, _( "Usermode Selection" ) ); + AddStaticText( s_boxer, isFirstTime ? usermodeExplained : usermodeWarning ); m_radio_user = &AddRadioButton( s_boxer, _("User Documents (recommended)"), _("Location: ") + wxStandardPaths::Get().GetDocumentsDir() ); s_boxer.AddSpacer( 4 ); - m_radio_cwd = &AddRadioButton( s_boxer, _("Current working folder (intended for developer use only)"), _("Location: ") + wxGetCwd() ); + m_radio_cwd = &AddRadioButton( s_boxer, _("Current working folder (intended for developer use only)"), _("Location: ") + wxGetCwd(), + _("This setting requires administration privlidges from your operating system.") ); s_boxer.AddSpacer( 4 ); SetSizerAndFit( &s_boxer ); @@ -108,12 +138,13 @@ void Panels::UsermodeSelectionPanel::Apply( AppConfig& conf ) { if( !m_radio_cwd->GetValue() && !m_radio_user->GetValue() ) throw Exception::CannotApplySettings( this, wxLt( "You must select one of the available user modes before proceeding." ) ); - conf.UseAdminMode = m_radio_cwd->GetValue(); + + g_ApplyState.UseAdminMode = m_radio_cwd->GetValue(); } // ----------------------------------------------------------------------- -Panels::LanguageSelectionPanel::LanguageSelectionPanel( wxWindow* parent, int idealWidth ) : - BaseApplicableConfigPanel( parent, idealWidth ) +Panels::LanguageSelectionPanel::LanguageSelectionPanel( wxWindow& parent, int idealWidth ) : + BaseApplicableConfigPanel( &parent, idealWidth ) , m_langs() , m_picker( NULL ) { diff --git a/pcsx2/gui/Panels/PathsPanel.cpp b/pcsx2/gui/Panels/PathsPanel.cpp index d8c27ca7e6..f77e42da11 100644 --- a/pcsx2/gui/Panels/PathsPanel.cpp +++ b/pcsx2/gui/Panels/PathsPanel.cpp @@ -25,15 +25,27 @@ using namespace wxHelpers; static const int BetweenFolderSpace = 5; +static wxString GetNormalizedConfigFolder( FoldersEnum_t folderId ) +{ + const bool isDefault = g_Conf->Folders.IsDefault( folderId ); + wxDirName normalized( isDefault ? g_Conf->Folders[folderId] : PathDefs::Get(folderId) ); + normalized.Normalize( wxPATH_NORM_ALL ); + return normalized.ToString(); +} + // Pass me TRUE if the default path is to be used, and the DirPcikerCtrl disabled from use. -void Panels::PathsPanel::DirPickerPanel::UpdateCheckStatus( bool someNoteworthyBoolean ) +void Panels::DirPickerPanel::UpdateCheckStatus( bool someNoteworthyBoolean ) { m_pickerCtrl->Enable( !someNoteworthyBoolean ); if( someNoteworthyBoolean ) - m_pickerCtrl->SetPath( PathDefs::Get( m_FolderId ).ToString() ); + { + wxDirName normalized( PathDefs::Get( m_FolderId ) ); + normalized.Normalize( wxPATH_NORM_ALL ); + m_pickerCtrl->SetPath( normalized.ToString() ); + } } -void Panels::PathsPanel::DirPickerPanel::UseDefaultPath_Click(wxCommandEvent &event) +void Panels::DirPickerPanel::UseDefaultPath_Click(wxCommandEvent &event) { wxASSERT( m_pickerCtrl != NULL && m_checkCtrl != NULL ); UpdateCheckStatus( m_checkCtrl->IsChecked() ); @@ -43,47 +55,50 @@ void Panels::PathsPanel::DirPickerPanel::UseDefaultPath_Click(wxCommandEvent &ev // If initPath is NULL, then it's assumed the default folder is to be used, which is // obtained from invoking the specified getDefault() function. // -Panels::PathsPanel::DirPickerPanel::DirPickerPanel( wxWindow* parent, FoldersEnum_t folderid, +Panels::DirPickerPanel::DirPickerPanel( wxWindow* parent, FoldersEnum_t folderid, const wxString& label, const wxString& dialogLabel ) : BaseApplicableConfigPanel( parent, wxDefaultCoord ) , m_FolderId( folderid ) { - const bool isDefault = g_Conf->Folders.IsDefault( m_FolderId ); - wxDirName normalized( isDefault ? g_Conf->Folders[m_FolderId] : PathDefs::Get(m_FolderId) ); - normalized.Normalize(); - wxStaticBoxSizer& s_box = *new wxStaticBoxSizer( wxVERTICAL, this, label ); // 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. - m_pickerCtrl = new wxDirPickerCtrl( this, wxID_ANY, normalized.ToString(), dialogLabel, + m_pickerCtrl = new wxDirPickerCtrl( this, wxID_ANY, GetNormalizedConfigFolder( m_FolderId ), dialogLabel, wxDefaultPosition, wxDefaultSize, wxDIRP_USE_TEXTCTRL | wxDIRP_DIR_MUST_EXIST ); s_box.Add( m_pickerCtrl, wxSizerFlags().Border(wxLEFT | wxRIGHT | wxTOP, 5).Expand() ); m_checkCtrl = &AddCheckBox( s_box, _("Use installation default setting") ); + + const bool isDefault = g_Conf->Folders.IsDefault( m_FolderId ); m_checkCtrl->SetValue( isDefault ); UpdateCheckStatus( isDefault ); SetSizerAndFit( &s_box ); - Connect( m_checkCtrl->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( PathsPanel::DirPickerPanel::UseDefaultPath_Click ) ); + Connect( m_checkCtrl->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DirPickerPanel::UseDefaultPath_Click ) ); } -void Panels::PathsPanel::DirPickerPanel::Apply( AppConfig& conf ) +void Panels::DirPickerPanel::Reset() +{ + m_pickerCtrl->SetPath( GetNormalizedConfigFolder( m_FolderId ) ); +} + +void Panels::DirPickerPanel::Apply( AppConfig& conf ) { conf.Folders.Set( m_FolderId, m_pickerCtrl->GetPath(), m_checkCtrl->GetValue() ); } // ------------------------------------------------------------------------ -Panels::PathsPanel::MyBasePanel::MyBasePanel( wxWindow& parent, int idealWidth ) : +Panels::BasePathsPanel::BasePathsPanel( wxWindow& parent, int idealWidth ) : wxPanelWithHelpers( &parent, idealWidth-12 ) , s_main( *new wxBoxSizer( wxVERTICAL ) ) { } -Panels::PathsPanel::DirPickerPanel& Panels::PathsPanel::MyBasePanel::AddDirPicker( wxBoxSizer& sizer, +Panels::DirPickerPanel& Panels::BasePathsPanel::AddDirPicker( wxBoxSizer& sizer, FoldersEnum_t folderid, const wxString& label, const wxString& popupLabel ) { DirPickerPanel* dpan = new DirPickerPanel( this, folderid, label, popupLabel ); @@ -92,8 +107,8 @@ Panels::PathsPanel::DirPickerPanel& Panels::PathsPanel::MyBasePanel::AddDirPicke } // ------------------------------------------------------------------------ -Panels::PathsPanel::StandardPanel::StandardPanel( wxWindow& parent ) : - MyBasePanel( parent ) +Panels::StandardPathsPanel::StandardPathsPanel( wxWindow& parent ) : + BasePathsPanel( parent ) { // TODO : Replace the callback mess here with the new FolderId enumeration setup. :) @@ -146,56 +161,77 @@ Panels::PathsPanel::StandardPanel::StandardPanel( wxWindow& parent ) : } // ------------------------------------------------------------------------ -Panels::PathsPanel::AdvancedPanel::AdvancedPanel( wxWindow& parent, int idealWidth ) : - MyBasePanel( parent, idealWidth-9 ) +Panels::AdvancedPathsPanel::AdvancedPathsPanel( wxWindow& parent, int idealWidth ) : + BasePathsPanel( parent, idealWidth-9 ) + +, m_dirpick_plugins( + AddDirPicker( s_main, FolderId_Plugins, + _("Plugins folder:"), + _("Select a PCSX2 plugins folder") + ) + ) + +, m_dirpick_settings( ( + s_main.AddSpacer( BetweenFolderSpace ), + AddDirPicker( s_main, FolderId_Settings, + _("Settings folder:"), + _("Select location to save PCSX2 settings to") + ) + ) ) { - wxStaticBoxSizer& advanced = *new wxStaticBoxSizer( wxVERTICAL, this, _("Advanced") ); - AddStaticText( advanced, pxE( ".Panels:Folders:Advanced", - L"Warning!! These advanced options are provided for developers and advanced testers only. " - L"Changing these settings can cause program errors, so please be weary." + m_dirpick_plugins.SetToolTip( pxE( ".Tooltips:Folders:Plugins", + L"This is the location where PCSX2 will expect to find its plugins. Plugins found in this folder " + L"will be enumerated and are selectable from the Plugins panel." ) ); - AddDirPicker( advanced, FolderId_Plugins, - _("Plugins:"), - _("Select folder for PCSX2 plugins") ). - SetToolTip( pxE( ".Tooltips:Folders:Plugins", - L"This is the location where PCSX2 will expect to find its plugins. Plugins found in this folder " - L"will be enumerated and are selectable from the Plugins panel." - ) ); - - advanced.AddSpacer( BetweenFolderSpace ); - AddDirPicker( advanced, FolderId_Settings, - _("Settings:"), - _("Select a folder for PCSX2 settings/inis") ). - SetToolTip( pxE( ".Tooltips:Folders:Settings", - L"This is the folder where PCSX2 saves all settings, including settings generated " - L"by most plugins.\n\nWarning: Some older versions of plugins may not respect this value." - ) ); - - advanced.AddSpacer( 4 ); - advanced.Add( new UsermodeSelectionPanel( this, GetIdealWidth()-9 ), SizerFlags::SubGroup() ); - - s_main.Add( &advanced, SizerFlags::SubGroup() ); - s_main.AddSpacer( 5 ); + m_dirpick_settings.SetToolTip( pxE( ".Tooltips:Folders:Settings", + L"This is the folder where PCSX2 saves all settings, including settings generated " + L"by most plugins.\n\nWarning: Some older versions of plugins may not respect this value." + ) ); SetSizerAndFit( &s_main ); } +void Panels::AdvancedPathsPanel::Reset() +{ + m_dirpick_plugins.Reset(); + m_dirpick_settings.Reset(); +} + // ------------------------------------------------------------------------ -Panels::PathsPanel::PathsPanel( wxWindow& parent, int idealWidth ) : +Panels::TabbedPathsPanel::TabbedPathsPanel( wxWindow& parent, int idealWidth ) : BaseApplicableConfigPanel( &parent, idealWidth ) { wxBoxSizer& s_main = *new wxBoxSizer( wxVERTICAL ); wxNotebook& notebook = *new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_BOTTOM | wxNB_FIXEDWIDTH ); - notebook.AddPage( new StandardPanel( notebook ), _("Standard") ); - notebook.AddPage( new AdvancedPanel( notebook, GetIdealWidth() ), _("Advanced") ); + StandardPathsPanel& stah( *new StandardPathsPanel( notebook ) ); + AdvancedPathsPanel& apah( *new AdvancedPathsPanel( notebook, GetIdealWidth() ) ); + notebook.AddPage( &stah, _("Standard") ); + notebook.AddPage( &apah, _("Advanced") ); + + // Advanced Tab uses the Advanced Panel with some extra features. + // This is because the extra features are not present on the Wizard version of the Advanced Panel. + + wxStaticBoxSizer& advanced = *new wxStaticBoxSizer( wxVERTICAL, this, _("Advanced") ); + AddStaticText( advanced, pxE( ".Panels:Folders:Advanced", + L"Warning!! These advanced options are provided for developers and advanced testers only. " + L"Changing these settings can cause program errors and may require administration privlidges, " + L"so please be weary." + ) ); + + advanced.Add( new UsermodeSelectionPanel( *this, GetIdealWidth()-9 ), SizerFlags::SubGroup() ); + advanced.AddSpacer( 4 ); + advanced.Add( &apah.Sizer(), SizerFlags::SubGroup() ); + + apah.SetSizer( &advanced, false ); + apah.Fit(); s_main.Add( ¬ebook, SizerFlags::StdSpace() ); SetSizerAndFit( &s_main ); } -void Panels::PathsPanel::Apply( AppConfig& conf ) +void Panels::TabbedPathsPanel::Apply( AppConfig& conf ) { } diff --git a/pcsx2/gui/Panels/PluginSelectorPanel.cpp b/pcsx2/gui/Panels/PluginSelectorPanel.cpp index 3d67a83da8..316eb202bb 100644 --- a/pcsx2/gui/Panels/PluginSelectorPanel.cpp +++ b/pcsx2/gui/Panels/PluginSelectorPanel.cpp @@ -17,6 +17,7 @@ */ #include "PrecompiledHeader.h" +#include "Utilities/ScopedPtr.h" #include "Plugins.h" #include "ConfigurationPanels.h" #include "ps2/BiosTools.h" @@ -117,9 +118,9 @@ public: static const wxString failed_separator( L"-------- Unsupported Plugins --------" ); // ------------------------------------------------------------------------ -Panels::PluginSelectorPanel::StatusPanel::StatusPanel( wxWindow* parent, int pluginCount, __unused int biosCount ) : +Panels::PluginSelectorPanel::StatusPanel::StatusPanel( wxWindow* parent ) : wxPanelWithHelpers( parent ) -, m_gauge( *new wxGauge( this, wxID_ANY, pluginCount ) ) +, m_gauge( *new wxGauge( this, wxID_ANY, 10 ) ) , m_label( *new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE | wxST_NO_AUTORESIZE ) ) , m_progress( 0 ) { @@ -132,6 +133,11 @@ Panels::PluginSelectorPanel::StatusPanel::StatusPanel( wxWindow* parent, int plu SetSizerAndFit( &s_main ); } +void Panels::PluginSelectorPanel::StatusPanel::SetGaugeLength( int len ) +{ + m_gauge.SetRange( len ); +} + void Panels::PluginSelectorPanel::StatusPanel::AdvanceProgress( const wxString& msg ) { m_label.SetLabel( msg ); @@ -183,15 +189,14 @@ void Panels::PluginSelectorPanel::ComboBoxPanel::Reset() // ------------------------------------------------------------------------ Panels::PluginSelectorPanel::PluginSelectorPanel( wxWindow& parent, int idealWidth ) : BaseApplicableConfigPanel( &parent, idealWidth ) -, m_FileList() -, m_StatusPanel( *new StatusPanel( this, - wxDir::GetAllFiles( g_Conf->Folders.Plugins.ToString(), &m_FileList, wxsFormat( L"*%s", wxDynamicLibrary::GetDllExt()), wxDIR_FILES ), - wxDir::GetAllFiles( g_Conf->Folders.Bios.ToString(), &m_BiosList, L"*.bin", wxDIR_FILES ) - ) ) +, m_FileList( NULL ) +, m_BiosList( NULL ) +, m_StatusPanel( *new StatusPanel( this ) ) , m_ComponentBoxes( *new ComboBoxPanel( this ) ) -, m_Uninitialized( true ) , m_EnumeratorThread( NULL ) { + //ValidateEnumerationStatus(); + wxBoxSizer& s_main = *new wxBoxSizer( wxVERTICAL ); s_main.Add( &m_ComponentBoxes, SizerFlags::StdExpand().ReserveSpaceEvenIfHidden() ); @@ -208,7 +213,7 @@ Panels::PluginSelectorPanel::PluginSelectorPanel( wxWindow& parent, int idealWid SetSizerAndFit( &s_main ); - Connect( GetId(), wxEVT_SHOW, wxShowEventHandler( PluginSelectorPanel::OnShow ) ); + Connect( GetId(), wxEVT_SHOW, wxShowEventHandler( PluginSelectorPanel::OnShow ) ); Connect( wxEVT_EnumeratedNext, wxCommandEventHandler( PluginSelectorPanel::OnProgress ) ); Connect( wxEVT_EnumerationFinished, wxCommandEventHandler( PluginSelectorPanel::OnEnumComplete ) ); @@ -222,6 +227,8 @@ Panels::PluginSelectorPanel::~PluginSelectorPanel() // Kill the thread if it's alive. safe_delete( m_EnumeratorThread ); + safe_delete( m_FileList ); + safe_delete( m_BiosList ); } void Panels::PluginSelectorPanel::Apply( AppConfig& conf ) @@ -247,7 +254,7 @@ void Panels::PluginSelectorPanel::Apply( AppConfig& conf ) ); } - wxFileName relative( m_FileList[(int)m_ComponentBoxes.Get(i).GetClientData(sel)] ); + wxFileName relative( GetFilename((int)m_ComponentBoxes.Get(i).GetClientData(sel)) ); relative.MakeRelativeTo( g_Conf->Folders.Plugins.ToString() ); conf.BaseFilenames.Plugins[tbl_PluginInfo[i].id] = relative.GetFullPath(); } @@ -266,15 +273,13 @@ void Panels::PluginSelectorPanel::Apply( AppConfig& conf ) ) ); } - wxFileName relative( m_BiosList[(int)m_ComponentBoxes.GetBios().GetClientData(sel)] ); + wxFileName relative( (*m_BiosList)[(int)m_ComponentBoxes.GetBios().GetClientData(sel)] ); relative.MakeRelativeTo( g_Conf->Folders.Bios.ToString() ); conf.BaseFilenames.Bios = relative.GetFullPath(); } void Panels::PluginSelectorPanel::DoRefresh() { - m_Uninitialized = false; - // Disable all controls until enumeration is complete. m_ComponentBoxes.Hide(); @@ -284,22 +289,64 @@ void Panels::PluginSelectorPanel::DoRefresh() safe_delete( m_EnumeratorThread ); m_EnumeratorThread = new EnumThread( *this ); m_EnumeratorThread->Start(); + + m_ComponentBoxes.Reset(); +} + +bool Panels::PluginSelectorPanel::ValidateEnumerationStatus() +{ + bool validated = true; + + // re-enumerate plugins and bioses, and if anything changed then we need to wipe + // the contents of the combo boxes and re-enumerate everything. + + // Impl Note: ScopedPtr used so that resources get cleaned up if an exception + // occurs during file enumeration. + wxScopedPtr pluginlist( new wxArrayString() ); + wxScopedPtr bioslist( new wxArrayString() ); + + int pluggers = EnumeratePluginsFolder( pluginlist.get() ); + + if( g_Conf->Folders.Bios.Exists() ) + wxDir::GetAllFiles( g_Conf->Folders.Bios.ToString(), bioslist.get(), L"*.bin", wxDIR_FILES ); + + if( (m_FileList == NULL) || (*pluginlist != *m_FileList) ) + validated = false; + + if( (m_BiosList == NULL) || (*bioslist != *m_BiosList) ) + validated = false; + + delete m_FileList; + delete m_BiosList; + m_FileList = pluginlist.release(); + m_BiosList = bioslist.release(); + + m_StatusPanel.SetGaugeLength( pluggers ); + + return validated; } // ------------------------------------------------------------------------ + +// This overload of OnShow is invoked by wizards, since the wxWizard won't raise +// SHOW events. >_< (only called for show events and not hide events) +void Panels::PluginSelectorPanel::OnShow() +{ + if( !ValidateEnumerationStatus() ) + DoRefresh(); +} + void Panels::PluginSelectorPanel::OnShow( wxShowEvent& evt ) { evt.Skip(); if( !evt.GetShow() ) return; - if( !m_Uninitialized ) return; - - DoRefresh(); + OnShow(); } void Panels::PluginSelectorPanel::OnRefresh( wxCommandEvent& evt ) { - m_ComponentBoxes.Reset(); + ValidateEnumerationStatus(); DoRefresh(); } @@ -314,13 +361,13 @@ void Panels::PluginSelectorPanel::OnEnumComplete( wxCommandEvent& evt ) wxFileName right( g_Conf->FullpathToBios() ); right.MakeRelativeTo( g_Conf->Folders.Plugins.ToString() ); - for( size_t i=0; iGetCount(); ++i ) { wxString description; - if( !IsBIOS(m_BiosList[i], description) ) continue; + if( !IsBIOS((*m_BiosList)[i], description) ) continue; int sel = m_ComponentBoxes.GetBios().Append( description, (void*)i ); - wxFileName left( m_BiosList[i] ); + wxFileName left( (*m_BiosList)[i] ); left.MakeRelativeTo( g_Conf->Folders.Plugins.ToString() ); if( left == right ) @@ -358,15 +405,15 @@ void Panels::PluginSelectorPanel::OnEnumComplete( wxCommandEvent& evt ) void Panels::PluginSelectorPanel::OnProgress( wxCommandEvent& evt ) { size_t evtidx = evt.GetExtraLong(); - m_StatusPanel.AdvanceProgress( (evtidx < m_FileList.Count()-1) ? - m_FileList[evtidx + 1] : wxString(_("Completing tasks...")) + m_StatusPanel.AdvanceProgress( (evtidx < m_FileList->Count()-1) ? + (*m_FileList)[evtidx + 1] : wxString(_("Completing tasks...")) ); EnumeratedPluginInfo& result( m_EnumeratorThread->Results[evtidx] ); if( result.TypeMask == 0 ) { - Console::Error( L"Some kinda plugin failure: " + m_FileList[evtidx] ); + Console::Error( L"Some kinda plugin failure: " + (*m_FileList)[evtidx] ); } for( int i=0; iFullpathTo(tbl_PluginInfo[i].id) ); left.MakeRelativeTo( g_Conf->Folders.Plugins.ToString() ); diff --git a/pcsx2/gui/main.cpp b/pcsx2/gui/main.cpp index 2c863466c2..192c2274c0 100644 --- a/pcsx2/gui/main.cpp +++ b/pcsx2/gui/main.cpp @@ -21,6 +21,8 @@ #include "MainFrame.h" #include "Dialogs/ModalPopups.h" +#include "Utilities/ScopedPtr.h" + #include "Resources/EmbeddedImage.h" #include "Resources/BackgroundLogo.h" @@ -28,6 +30,7 @@ IMPLEMENT_APP(Pcsx2App) +bool UseAdminMode = false; AppConfig* g_Conf = NULL; wxFileHistory* g_RecentIsoList = NULL; CoreEmuThread* g_EmuThread = NULL; @@ -62,64 +65,34 @@ Pcsx2App::Pcsx2App() : wxFrame* Pcsx2App::GetMainWindow() const { return m_MainFrame; } -wxFileConfig* OpenConfig( const wxString& filename ) -{ - return new wxFileConfig( wxEmptyString, wxEmptyString, filename, wxEmptyString, wxCONFIG_USE_RELATIVE_PATH ); -} - void Pcsx2App::ReadUserModeSettings() { wxFileName usermodefile( FilenameDefs::GetUsermodeConfig() ); usermodefile.SetPath( wxGetCwd() ); - - wxFileConfig* conf_usermode = OpenConfig( usermodefile.GetFullPath() ); + wxScopedPtr conf_usermode( OpenFileConfig( usermodefile.GetFullPath() ) ); if( !wxFile::Exists( usermodefile.GetFullPath() ) ) { // first time startup, so give the user the choice of user mode: - if( Dialogs::PickUserModeDialog( NULL ).ShowModal() == wxID_CANCEL ) - throw Exception::StartupAborted( L"Startup aborted: User cancelled Usermode selection." ); - + //if( Dialogs::PickUserModeDialog( NULL ).ShowModal() == wxID_CANCEL ) + FirstTimeWizard wiz( NULL ); + if( !wiz.RunWizard( wiz.GetFirstPage() ) ) + throw Exception::StartupAborted( L"Startup aborted: User canceled FirstTime Wizard." ); + // Save user's new settings - if( conf_usermode != NULL ) - { - IniSaver saver( *conf_usermode ); - g_Conf->LoadSaveUserMode( saver ); - } + IniSaver saver( *conf_usermode ); + g_Conf->LoadSaveUserMode( saver ); + g_Conf->Save(); } else { // usermode.ini exists -- assume Documents mode, unless the ini explicitly // specifies otherwise. - g_Conf->UseAdminMode = false; + UseAdminMode = false; - if( conf_usermode != NULL ) - { - IniLoader loader( *conf_usermode ); - g_Conf->LoadSaveUserMode( loader ); - } + IniLoader loader( *conf_usermode ); + g_Conf->LoadSaveUserMode( loader ); } - - safe_delete( conf_usermode ); -} - -// ------------------------------------------------------------------------ -// returns true if a configuration file is present in the current working dir (cwd). -// returns false if not (in which case the calling code should fall back on using OpenConfigUserLocal()) -// -bool Pcsx2App::TryOpenConfigCwd() -{ - ReadUserModeSettings(); - - wxDirName inipath_cwd( (wxDirName)wxGetCwd() + PathDefs::Base::Settings() ); - if( !inipath_cwd.IsReadable() ) return false; - - wxString inifile_cwd( Path::Combine( inipath_cwd, FilenameDefs::GetConfig() ) ); - if( !Path::IsFile( inifile_cwd ) ) return false; - if( Path::GetFileSize( inifile_cwd ) <= 1 ) return false; - - wxConfigBase::Set( OpenConfig( inifile_cwd ) ); - return true; } void Pcsx2App::OnInitCmdLine( wxCmdLineParser& parser ) @@ -184,20 +157,9 @@ bool Pcsx2App::OnInit() try { - if( !TryOpenConfigCwd() ) - { - PathDefs::GetDocuments().Mkdir(); - PathDefs::GetSettings().Mkdir(); + ReadUserModeSettings(); - // Allow wx to use our config, and enforces auto-cleanup as well - wxString confile( Path::Combine( PathDefs::GetSettings(), FilenameDefs::GetConfig() ) ); - wxConfigBase::Set( OpenConfig( confile ) ); - wxConfigBase::Get()->SetRecordDefaults(); - } - g_Conf->Load(); - g_Conf->Apply(); - - g_Conf->Folders.Logs.Mkdir(); + AppConfig_ReloadGlobalSettings(); m_MainFrame = new MainEmuFrame( NULL, L"PCSX2" ); m_ProgramLogBox = new ConsoleLogFrame( m_MainFrame, L"PCSX2 Program Log", g_Conf->ProgLogBox ); @@ -216,24 +178,6 @@ bool Pcsx2App::OnInit() return false; } - // Check to see if the user needs to perform initial setup: - - /*bool needsConfigured = false; - const wxString pc( L"Please Configure" ); - for( int pidx=0; pidxBaseFilenames[(PluginsEnum_t)pidx] == pc ) - { - needsConfigured = true; - break; - } - } - - if( needsConfigured ) - { - Dialogs::ConfigurationDialog( m_MainFrame ).ShowModal(); - }*/ - Connect( pxEVT_MSGBOX, wxCommandEventHandler( Pcsx2App::OnMessageBox ) ); return true; diff --git a/pcsx2/ps2/BiosTools.cpp b/pcsx2/ps2/BiosTools.cpp index 00b38a280d..5145ecf296 100644 --- a/pcsx2/ps2/BiosTools.cpp +++ b/pcsx2/ps2/BiosTools.cpp @@ -47,6 +47,18 @@ struct romdir u32 BiosVersion; // Used in Memory, Misc, CDVD +// Returns a string message telling the user to consult guides for obtaining a legal BIOS. +// This message is in a function because it's used as part of several dialogs in PCSX2 (there +// are multiple variations on the BIOS and BIOS folder checks). +wxString BIOS_GetMsg_Required() +{ + return pxE( ".Popup:BiosDumpRequired", + L"PCSX2 requires a PS2 BIOS in order to run. For legal reasons, you *must* obtain \n" + L"a BIOS from an actual PS2 unit that you own (borrowing doesn't count).\n" + L"Please consult the FAQs and Guides for further instructions." + ); +} + // Returns the version information of the bios currently loaded into memory. static u32 GetBiosVersion() { @@ -152,11 +164,8 @@ void LoadBIOS() throw Exception::FileNotFound( Bios, L"Configured Bios file does not exist", - pxE( ".Error:BiosNotFound", - L"The configured BIOS file does not exist, or no BIOS has been configured.\n\n" - L"PCSX2 requires a PS2 BIOS to run; and the BIOS *must* be obtained from an actual PS2 unit\n" - L"that you own (borrowing doesn't count). Please consult the FAQs and Guides for further instructions." - ) + _("The configured BIOS file does not exist, or no BIOS has been configured.\n\n") + + BIOS_GetMsg_Required() ); } @@ -189,9 +198,8 @@ bool IsBIOS(const wxString& filename, wxString& description) break; // found romdir } - if ((strcmp(rd.fileName, "RESET") != 0) || (rd.fileSize == 0)) { + if ((strcmp(rd.fileName, "RESET") != 0) || (rd.fileSize == 0)) return FALSE; //Unable to locate ROMDIR structure in file or a ioprpXXX.img - } bool found = false; @@ -242,13 +250,13 @@ bool IsBIOS(const wxString& filename, wxString& description) if (fp.Read( &rd, DIRENTRY_SIZE ) != DIRENTRY_SIZE) break; } - fileOffset-=((rd.fileSize + 0x10) & 0xfffffff0) - rd.fileSize; + fileOffset -= ((rd.fileSize + 0x10) & 0xfffffff0) - rd.fileSize; if (found) { if ( biosFileSize < (int)fileOffset) { - description << ((biosFileSize*100)/(int)fileOffset) << L"%"; + description += wxsFormat( L" %d%%", ((biosFileSize*100) / (int)fileOffset) ); // we force users to have correct bioses, // not that lame scph10000 of 513KB ;-) } diff --git a/pcsx2/ps2/BiosTools.h b/pcsx2/ps2/BiosTools.h index af5b50c9ea..23f25e998e 100644 --- a/pcsx2/ps2/BiosTools.h +++ b/pcsx2/ps2/BiosTools.h @@ -20,5 +20,6 @@ extern u32 BiosVersion; // Used by CDVD +extern wxString BIOS_GetMsg_Required(); extern void LoadBIOS(); extern bool IsBIOS(const wxString& filename, wxString& description); diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index ce37da64b2..075b6d0195 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -1989,6 +1989,10 @@ RelativePath="..\..\gui\Dialogs\ConfigurationDialog.h" > + + diff --git a/pcsx2_suite_2008.sln b/pcsx2_suite_2008.sln index fe6ff5186f..2c8ec5f6e8 100644 --- a/pcsx2_suite_2008.sln +++ b/pcsx2_suite_2008.sln @@ -117,6 +117,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxAdv28", "3rdparty\wxWidge {C34487AF-228A-4D11-8E50-27803DF76873} = {C34487AF-228A-4D11-8E50-27803DF76873} EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "wx", "wx", "{62BF822E-6A12-49A8-BE8C-C55A9BCA24DA}" + ProjectSection(SolutionItems) = preProject + common\include\wx\folderdesc.txt = common\include\wx\folderdesc.txt + common\include\wx\scopedarray.h = common\include\wx\scopedarray.h + common\include\wx\scopedptr.h = common\include\wx\scopedptr.h + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -601,6 +608,7 @@ Global {0FADC26C-0E9D-4DD7-84B1-BF4F7754E90C} = {88F517F9-CE1C-4005-9BDF-4481FEB55053} {A51123F5-9505-4EAE-85E7-D320290A272C} = {88F517F9-CE1C-4005-9BDF-4481FEB55053} {4639972E-424E-4E13-8B07-CA403C481346} = {88F517F9-CE1C-4005-9BDF-4481FEB55053} + {62BF822E-6A12-49A8-BE8C-C55A9BCA24DA} = {0FADC26C-0E9D-4DD7-84B1-BF4F7754E90C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution AMDCaProjectFile = E:\devpcsx2\fail\wx\CodeAnalyst\pcsx2_suite_2008.caw