mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
1245 lines
38 KiB
C++
1245 lines
38 KiB
C++
/* PCSX2 - PS2 Emulator for PCs
|
|
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
|
*
|
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "PrecompiledHeader.h"
|
|
#include "AppCoreThread.h"
|
|
#include "System.h"
|
|
#include "MemoryCardFile.h"
|
|
|
|
#include "ConfigurationPanels.h"
|
|
#include "MemoryCardPanels.h"
|
|
|
|
#include "Dialogs/ConfigurationDialog.h"
|
|
#include "Utilities/IniInterface.h"
|
|
#include "../../Sio.h"
|
|
|
|
#include <wx/filepicker.h>
|
|
#include <wx/ffile.h>
|
|
#include <wx/dir.h>
|
|
|
|
|
|
static wxDataFormat drag_drop_format(L"PCSX2McdDragDrop");
|
|
|
|
bool CopyDirectory( const wxString& from, const wxString& to );
|
|
bool RemoveDirectory( const wxString& dirname );
|
|
|
|
using namespace pxSizerFlags;
|
|
using namespace Panels;
|
|
|
|
static bool IsMcdFormatted( wxFFile& fhand )
|
|
{
|
|
static const char formatted_psx[] = "MC";
|
|
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 );
|
|
|
|
bool formatted = memcmp( formatted_string, dest, fmtstrlen ) == 0;
|
|
if(!formatted) formatted = memcmp( formatted_psx, dest, 2 ) == 0;
|
|
|
|
return formatted;
|
|
}
|
|
|
|
//sets IsPresent if the file is valid, and derived properties (filename, formatted, size, etc)
|
|
bool EnumerateMemoryCard( McdSlotItem& dest, const wxFileName& filename, const wxDirName basePath )
|
|
{
|
|
dest.IsFormatted = false;
|
|
dest.IsPresent = false;
|
|
dest.IsPSX = false;
|
|
dest.Type = MemoryCardType::MemoryCard_None;
|
|
|
|
const wxString fullpath( filename.GetFullPath() );
|
|
//DevCon.WriteLn( fullpath );
|
|
if ( filename.FileExists() ) {
|
|
// might be a memory card file
|
|
wxFFile mcdFile( fullpath );
|
|
if ( !mcdFile.IsOpened() ) { return false; } // wx should log the error for us.
|
|
|
|
wxFileOffset length = mcdFile.Length();
|
|
|
|
if( length < (1024*528) && length != 0x20000 )
|
|
{
|
|
Console.Warning( "... MemoryCard appears to be truncated. Ignoring." );
|
|
return false;
|
|
}
|
|
|
|
dest.SizeInMB = (uint)( length / ( 1024 * 528 * 2 ) );
|
|
|
|
if ( length == 0x20000 ) {
|
|
dest.IsPSX = true; // PSX memcard;
|
|
dest.SizeInMB = 1; // MegaBIT
|
|
}
|
|
|
|
dest.Type = MemoryCardType::MemoryCard_File;
|
|
dest.IsFormatted = IsMcdFormatted( mcdFile );
|
|
filename.GetTimes( NULL, &dest.DateModified, &dest.DateCreated );
|
|
} else if ( filename.DirExists() ) {
|
|
// might be a memory card folder
|
|
wxFileName superBlockFileName( fullpath, L"_pcsx2_superblock" );
|
|
if ( !superBlockFileName.FileExists() ) { return false; }
|
|
wxFFile mcdFile( superBlockFileName.GetFullPath() );
|
|
if ( !mcdFile.IsOpened() ) { return false; }
|
|
|
|
dest.SizeInMB = 0;
|
|
|
|
dest.Type = MemoryCardType::MemoryCard_Folder;
|
|
dest.IsFormatted = IsMcdFormatted( mcdFile );
|
|
superBlockFileName.GetTimes( NULL, &dest.DateModified, &dest.DateCreated );
|
|
} else {
|
|
// is neither
|
|
return false;
|
|
}
|
|
|
|
dest.IsPresent = true;
|
|
dest.Filename = filename;
|
|
if( filename.GetFullPath() == (basePath+filename.GetFullName()).GetFullPath() )
|
|
dest.Filename = filename.GetFullName();
|
|
|
|
return true;
|
|
}
|
|
|
|
//avih: unused
|
|
/*
|
|
static int EnumerateMemoryCards( McdList& dest, const wxArrayString& files )
|
|
{
|
|
int pushed = 0;
|
|
Console.WriteLn( Color_StrongBlue, "Enumerating memory cards..." );
|
|
for( size_t i=0; i<files.GetCount(); ++i )
|
|
{
|
|
ConsoleIndentScope con_indent;
|
|
McdSlotItem mcdItem;
|
|
if( EnumerateMemoryCard(mcdItem, files[i]) )
|
|
{
|
|
dest.push_back( mcdItem );
|
|
++pushed;
|
|
}
|
|
}
|
|
if( pushed > 0 )
|
|
Console.WriteLn( Color_StrongBlue, "Memory card Enumeration Complete." );
|
|
else
|
|
Console.WriteLn( Color_StrongBlue, "No valid memory card found." );
|
|
|
|
return pushed;
|
|
}
|
|
*/
|
|
// --------------------------------------------------------------------------------------
|
|
// McdListItem (implementations)
|
|
// --------------------------------------------------------------------------------------
|
|
bool McdSlotItem::IsMultitapSlot() const
|
|
{
|
|
return FileMcd_IsMultitapSlot(Slot);
|
|
}
|
|
|
|
uint McdSlotItem::GetMtapPort() const
|
|
{
|
|
return FileMcd_GetMtapPort(Slot);
|
|
}
|
|
|
|
uint McdSlotItem::GetMtapSlot() const
|
|
{
|
|
return FileMcd_GetMtapSlot(Slot);
|
|
}
|
|
|
|
// Compares two cards -- If this equality comparison is used on items where
|
|
// no filename is specified, then the check will include port and slot.
|
|
bool McdSlotItem::operator==( const McdSlotItem& right ) const
|
|
{
|
|
bool fileEqu;
|
|
|
|
if( Filename.GetFullName().IsEmpty() )
|
|
fileEqu = OpEqu(Slot);
|
|
else
|
|
fileEqu = OpEqu(Filename);
|
|
|
|
return fileEqu &&
|
|
OpEqu(IsPresent) && OpEqu(IsEnabled) &&
|
|
OpEqu(SizeInMB) && OpEqu(IsFormatted) &&
|
|
OpEqu(DateCreated) && OpEqu(DateModified);
|
|
}
|
|
|
|
bool McdSlotItem::operator!=( const McdSlotItem& right ) const
|
|
{
|
|
return operator==( right );
|
|
}
|
|
|
|
|
|
// =====================================================================================================
|
|
// BaseMcdListPanel (implementations)
|
|
// =====================================================================================================
|
|
Panels::BaseMcdListPanel::BaseMcdListPanel( wxWindow* parent )
|
|
: _parent( parent )
|
|
{
|
|
m_FolderPicker = new DirPickerPanel( this, FolderId_MemoryCards,
|
|
//_("memory card Search Path:"), // static box label
|
|
_("Select folder with PS2 memory cards") // dir picker popup label
|
|
);
|
|
|
|
m_listview = NULL;
|
|
s_leftside_buttons = NULL;
|
|
s_rightside_buttons = NULL;
|
|
|
|
m_btn_Refresh = new wxButton( this, wxID_ANY, _("Refresh list") );
|
|
|
|
Bind(wxEVT_BUTTON, &BaseMcdListPanel::OnRefreshSelections, this, m_btn_Refresh->GetId());
|
|
}
|
|
|
|
void Panels::BaseMcdListPanel::RefreshMcds() const
|
|
{
|
|
wxCommandEvent refit( wxEVT_BUTTON );
|
|
refit.SetId( m_btn_Refresh->GetId() );
|
|
GetEventHandler()->AddPendingEvent( refit );
|
|
}
|
|
|
|
void Panels::BaseMcdListPanel::CreateLayout()
|
|
{
|
|
//if( m_listview ) m_listview->SetMinSize( wxSize( 480, 140 ) );
|
|
|
|
wxFlexGridSizer* s_flex=new wxFlexGridSizer(3,1, 0, 0);
|
|
s_flex->AddGrowableCol(0);
|
|
s_flex->AddGrowableRow(1);
|
|
SetSizer(s_flex);
|
|
|
|
wxBoxSizer& s_buttons(*new wxBoxSizer( wxHORIZONTAL ));
|
|
s_leftside_buttons = new wxBoxSizer( wxHORIZONTAL );
|
|
s_rightside_buttons = new wxBoxSizer( wxHORIZONTAL );
|
|
|
|
s_buttons += s_leftside_buttons | pxAlignLeft;
|
|
s_buttons += pxStretchSpacer();
|
|
s_buttons += s_rightside_buttons | pxAlignRight;
|
|
|
|
if( m_FolderPicker ) *this += m_FolderPicker | pxExpand;
|
|
else *this += StdPadding;//we need the 'else' because we need these items to land into the proper rows of s_flex.
|
|
|
|
if( m_listview ) *this += m_listview | pxExpand;
|
|
else *this += StdPadding;
|
|
|
|
*this += s_buttons | pxExpand;
|
|
|
|
*s_leftside_buttons += m_btn_Refresh;
|
|
|
|
if (m_listview)
|
|
{
|
|
IniLoader loader;
|
|
ScopedIniGroup group( loader, L"MemoryCardListPanel" );
|
|
m_listview->LoadSaveColumns( loader );
|
|
}
|
|
}
|
|
|
|
void Panels::BaseMcdListPanel::Apply()
|
|
{
|
|
// Save column widths to the configuration file. Since these are used *only* by this
|
|
// dialog, we use a direct local ini save approach, instead of going through g_conf.
|
|
if (m_listview)
|
|
{
|
|
IniSaver saver;
|
|
ScopedIniGroup group( saver, L"MemoryCardListPanel" );
|
|
m_listview->LoadSaveColumns(saver);
|
|
}
|
|
}
|
|
|
|
void Panels::BaseMcdListPanel::AppStatusEvent_OnSettingsApplied()
|
|
{
|
|
if( (m_MultitapEnabled[0] != g_Conf->EmuOptions.MultitapPort0_Enabled) ||
|
|
(m_MultitapEnabled[1] != g_Conf->EmuOptions.MultitapPort1_Enabled) )
|
|
{
|
|
m_MultitapEnabled[0] = g_Conf->EmuOptions.MultitapPort0_Enabled;
|
|
m_MultitapEnabled[1] = g_Conf->EmuOptions.MultitapPort1_Enabled;
|
|
|
|
RefreshMcds();
|
|
}
|
|
}
|
|
|
|
class McdDropTarget : public wxDropTarget
|
|
{
|
|
protected:
|
|
BaseMcdListView* m_listview;
|
|
|
|
public:
|
|
McdDropTarget( BaseMcdListView* listview=NULL )
|
|
{
|
|
m_listview = listview;
|
|
SetDataObject(new wxCustomDataObject(drag_drop_format));
|
|
}
|
|
|
|
virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def)
|
|
{
|
|
int flags = 0;
|
|
|
|
int destViewIndex = m_listview->HitTest( wxPoint(x,y), flags);
|
|
if( wxNOT_FOUND == destViewIndex )
|
|
destViewIndex=-1;//non list item target is the filesystem placeholder.
|
|
|
|
if ( !GetData() )
|
|
return wxDragNone;
|
|
|
|
wxCustomDataObject *dobj = static_cast<wxCustomDataObject *>(GetDataObject());
|
|
|
|
if (dobj->GetDataSize() != sizeof(int))
|
|
return wxDragNone;
|
|
|
|
int sourceViewIndex;
|
|
dobj->GetDataHere(&sourceViewIndex);
|
|
|
|
wxDragResult result = OnDropMcd(
|
|
m_listview->GetMcdProvider().GetCardForViewIndex( sourceViewIndex ),
|
|
m_listview->GetMcdProvider().GetCardForViewIndex( destViewIndex ),
|
|
def
|
|
);
|
|
|
|
if( wxDragNone == result )
|
|
return wxDragNone;
|
|
|
|
m_listview->GetMcdProvider().RefreshMcds();
|
|
return result;
|
|
}
|
|
|
|
|
|
virtual wxDragResult OnDropMcd( McdSlotItem& src, McdSlotItem& dest, wxDragResult def )
|
|
{
|
|
if( src.Slot == dest.Slot ) return wxDragNone;
|
|
//if( !pxAssert( (src.Slot >= 0) && (dest.Slot >= 0) ) ) return wxDragNone;
|
|
const wxDirName basepath( m_listview->GetMcdProvider().GetMcdPath() );
|
|
|
|
if( wxDragCopy == def )
|
|
{
|
|
if( !m_listview->GetMcdProvider().UiDuplicateCard(src, dest) )
|
|
return wxDragNone;
|
|
}
|
|
else if( wxDragMove == def )
|
|
{ // source can only be an existing card.
|
|
// if dest is a ps2-port (empty or not) -> swap cards between ports.
|
|
// is dest is a non-ps2-port -> remove card from port.
|
|
|
|
// Note: For the sake of usability, automatically enable dest if a ps2-port.
|
|
if (src.IsPresent)
|
|
{
|
|
wxFileName tmpFilename = dest.Filename;
|
|
bool tmpPresent = dest.IsPresent;
|
|
if (src.Slot<0 && m_listview->GetMcdProvider().isFileAssignedToInternalSlot(src.Filename))
|
|
m_listview->GetMcdProvider().RemoveCardFromSlot(src.Filename);
|
|
|
|
dest.Filename = src.Filename;
|
|
dest.IsEnabled = dest.IsPresent? dest.IsEnabled:true;
|
|
dest.IsPresent = src.IsPresent;
|
|
|
|
if (dest.Slot>=0)
|
|
{//2 internal slots: swap
|
|
src.Filename = tmpFilename;
|
|
src.IsPresent = tmpPresent;
|
|
}
|
|
else
|
|
{//dest is at the filesystem (= remove card from slot)
|
|
src.Filename = L"";
|
|
src.IsPresent = false;
|
|
src.IsEnabled = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return def;
|
|
}
|
|
};
|
|
|
|
|
|
enum McdMenuId
|
|
{
|
|
McdMenuId_Create = 0x888,
|
|
//McdMenuId_Mount,
|
|
McdMenuId_Rename,
|
|
McdMenuId_RefreshList,
|
|
McdMenuId_AssignUnassign,
|
|
McdMenuId_Duplicate,
|
|
McdMenuId_Convert,
|
|
};
|
|
|
|
|
|
Panels::MemoryCardListPanel_Simple* g_uglyPanel=NULL;
|
|
void g_uglyFunc(){if (g_uglyPanel) g_uglyPanel->OnChangedListSelection();}
|
|
|
|
Panels::MemoryCardListPanel_Simple::~MemoryCardListPanel_Simple() {g_uglyPanel=NULL;}
|
|
|
|
Panels::MemoryCardListPanel_Simple::MemoryCardListPanel_Simple( wxWindow* parent )
|
|
: _parent( parent )
|
|
{
|
|
m_MultitapEnabled[0] = false;
|
|
m_MultitapEnabled[1] = false;
|
|
|
|
m_listview = new MemoryCardListView_Simple(this);
|
|
|
|
m_listview->SetMinSize(wxSize(620, m_listview->GetCharHeight() * 13)); // 740 is nice for default font sizes
|
|
|
|
m_listview->SetDropTarget( new McdDropTarget(m_listview) );
|
|
|
|
//m_button_Mount = new wxButton(this, wxID_ANY, _("Enable port"));
|
|
|
|
m_button_AssignUnassign = new wxButton(this, wxID_ANY, _("Eject"));
|
|
m_button_Duplicate = new wxButton(this, wxID_ANY, _("Duplicate ..."));
|
|
m_button_Rename = new wxButton(this, wxID_ANY, _("Rename ..."));
|
|
m_button_Create = new wxButton(this, wxID_ANY, _("Create ..."));
|
|
m_button_Convert = new wxButton(this, wxID_ANY, _("Convert ..."));
|
|
|
|
// ------------------------------------
|
|
// Sizer / Layout Section
|
|
// ------------------------------------
|
|
|
|
CreateLayout();
|
|
|
|
*s_leftside_buttons += 20;
|
|
//*s_leftside_buttons += m_button_Mount;
|
|
//*s_leftside_buttons += 20;
|
|
|
|
*s_leftside_buttons += Label(_("Card: ")) | pxMiddle;
|
|
*s_leftside_buttons += m_button_AssignUnassign;
|
|
*s_leftside_buttons += 20;
|
|
*s_leftside_buttons += m_button_Duplicate;
|
|
*s_leftside_buttons += 2;
|
|
*s_leftside_buttons += m_button_Rename;
|
|
*s_leftside_buttons += 2;
|
|
*s_leftside_buttons += m_button_Create;
|
|
*s_leftside_buttons += 2;
|
|
*s_leftside_buttons += m_button_Convert;
|
|
SetSizerAndFit(GetSizer());
|
|
|
|
parent->SetWindowStyle(parent->GetWindowStyle() | wxRESIZE_BORDER);
|
|
|
|
Bind(wxEVT_LIST_BEGIN_DRAG, &MemoryCardListPanel_Simple::OnListDrag, this, m_listview->GetId());
|
|
Bind(wxEVT_LIST_ITEM_SELECTED, &MemoryCardListPanel_Simple::OnListSelectionChanged, this, m_listview->GetId());
|
|
Bind(wxEVT_LIST_ITEM_ACTIVATED, &MemoryCardListPanel_Simple::OnItemActivated, this, m_listview->GetId()); //enter or double click
|
|
|
|
//Deselected is not working for some reason (e.g. when clicking an empty row at the table?) - avih
|
|
// wxMSW bug for virtual listviews. Works fine on Linux: http://trac.wxwidgets.org/ticket/1919 - turtleli
|
|
Bind(wxEVT_LIST_ITEM_DESELECTED, &MemoryCardListPanel_Simple::OnListSelectionChanged, this, m_listview->GetId());
|
|
|
|
Bind(wxEVT_LIST_ITEM_RIGHT_CLICK, &MemoryCardListPanel_Simple::OnOpenItemContextMenu, this, m_listview->GetId());
|
|
|
|
//Bind(wxEVT_BUTTON, &MemoryCardListPanel_Simple::OnMountCard, this, m_button_Mount->GetId());
|
|
Bind(wxEVT_BUTTON, &MemoryCardListPanel_Simple::OnCreateOrDeleteCard, this, m_button_Create->GetId());
|
|
Bind(wxEVT_BUTTON, &MemoryCardListPanel_Simple::OnConvertCard, this, m_button_Convert->GetId());
|
|
Bind(wxEVT_BUTTON, &MemoryCardListPanel_Simple::OnRenameFile, this, m_button_Rename->GetId());
|
|
Bind(wxEVT_BUTTON, &MemoryCardListPanel_Simple::OnDuplicateFile, this, m_button_Duplicate->GetId());
|
|
Bind(wxEVT_BUTTON, &MemoryCardListPanel_Simple::OnAssignUnassignFile, this, m_button_AssignUnassign->GetId());
|
|
|
|
// Popup Menu Connections!
|
|
//Bind(McdMenuId_Mount, &MemoryCardListPanel_Simple::OnMountCard, this, McdMenuId_Mount);
|
|
Bind(wxEVT_MENU, &MemoryCardListPanel_Simple::OnCreateOrDeleteCard, this, McdMenuId_Create);
|
|
Bind(wxEVT_MENU, &MemoryCardListPanel_Simple::OnConvertCard, this, McdMenuId_Convert);
|
|
Bind(wxEVT_MENU, &MemoryCardListPanel_Simple::OnRenameFile, this, McdMenuId_Rename);
|
|
Bind(wxEVT_MENU, &MemoryCardListPanel_Simple::OnDuplicateFile, this, McdMenuId_Duplicate);
|
|
Bind(wxEVT_MENU, &MemoryCardListPanel_Simple::OnAssignUnassignFile, this, McdMenuId_AssignUnassign);
|
|
|
|
Bind(wxEVT_MENU, &MemoryCardListPanel_Simple::OnRefreshSelections, this, McdMenuId_RefreshList);
|
|
|
|
//because the wxEVT_LIST_ITEM_DESELECTED doesn't work (buttons stay enabled when clicking an empty area of the list),
|
|
// m_listview can send us an event that indicates a change at the list. Ugly, but works.
|
|
g_uglyPanel=this;
|
|
m_listview->setExternHandler(g_uglyFunc);
|
|
}
|
|
|
|
void Panels::MemoryCardListPanel_Simple::UpdateUI()
|
|
{
|
|
if( !m_listview ) return;
|
|
|
|
int sel = m_listview->GetFirstSelected();
|
|
|
|
m_button_Create->Enable();
|
|
|
|
if( wxNOT_FOUND == sel )
|
|
{
|
|
m_button_Create->SetLabel( _("Create ...") );
|
|
pxSetToolTip( m_button_Create, _("Create a new memory card." ));
|
|
|
|
// m_button_Mount->Disable();
|
|
m_button_Rename->Disable();
|
|
m_button_Duplicate->Disable();
|
|
m_button_AssignUnassign->Disable();
|
|
m_button_Convert->Disable();
|
|
return;
|
|
}
|
|
|
|
const McdSlotItem& card( GetCardForViewIndex(sel) );
|
|
|
|
|
|
m_button_Rename->Enable( card.IsPresent );
|
|
wxString renameTip = _("Rename this memory card ...");
|
|
pxSetToolTip( m_button_Rename, renameTip );
|
|
|
|
m_button_AssignUnassign->Enable( card.IsPresent );
|
|
m_button_AssignUnassign->SetLabel( card.Slot>=0 ? _("Eject") : _("Insert ...") );
|
|
wxString assignTip = (card.Slot>=0)?_("Eject the card from this port"):_("Insert this card to a port ...");
|
|
pxSetToolTip( m_button_AssignUnassign, assignTip );
|
|
|
|
m_button_Duplicate->Enable( card.IsPresent );
|
|
wxString dupTip = _("Create a duplicate of this memory card ...");
|
|
pxSetToolTip( m_button_Duplicate, dupTip );
|
|
|
|
m_button_Convert->Enable( card.IsPresent && card.IsFormatted && !card.IsPSX );
|
|
|
|
//m_button_Create->Enable( card.Slot>=0 || card.IsPresent);
|
|
m_button_Create->SetLabel( card.IsPresent ? _("Delete") : _("Create ...") );
|
|
|
|
if (card.IsPresent)
|
|
pxSetToolTip( m_button_Create, _("Permanently delete this memory card from disk (all contents are lost)"));
|
|
else if( card.Slot >= 0 )
|
|
pxSetToolTip( m_button_Create, _("Create a new memory card and assign it to this Port." ));
|
|
else
|
|
pxSetToolTip( m_button_Create, _("Create a new memory card." ));
|
|
|
|
/*
|
|
m_button_Mount->Enable( card.IsPresent && card.Slot>=0);
|
|
m_button_Mount->SetLabel( card.IsEnabled ? _("Disable Port") : _("Enable Port") );
|
|
pxSetToolTip( m_button_Mount,
|
|
card.IsEnabled
|
|
? _("Disable the selected PS2-Port (this memory card will be invisible to games/BIOS).")
|
|
: _("Enable the selected PS2-Port (games/BIOS will see this memory card).")
|
|
);
|
|
*/
|
|
}
|
|
|
|
void Panels::MemoryCardListPanel_Simple::Apply()
|
|
{
|
|
_parent::Apply();
|
|
|
|
int used=0;
|
|
Console.WriteLn( L"Apply Memory cards:" );
|
|
for( uint slot=0; slot<8; ++slot )
|
|
{
|
|
g_Conf->Mcd[slot].Type = m_Cards[slot].Type;
|
|
g_Conf->Mcd[slot].Enabled = m_Cards[slot].IsEnabled && m_Cards[slot].IsPresent;
|
|
if (m_Cards[slot].IsPresent)
|
|
g_Conf->Mcd[slot].Filename = m_Cards[slot].Filename;
|
|
else
|
|
g_Conf->Mcd[slot].Filename = L"";
|
|
|
|
if( g_Conf->Mcd[slot].Enabled )
|
|
{
|
|
used++;
|
|
Console.WriteLn( L"slot[%d]='%s'", slot, WX_STR(g_Conf->Mcd[slot].Filename.GetFullName()) );
|
|
}
|
|
}
|
|
if( !used )
|
|
Console.WriteLn( L"No active slots" );
|
|
|
|
SetForceMcdEjectTimeoutNow();
|
|
|
|
}
|
|
|
|
void Panels::MemoryCardListPanel_Simple::AppStatusEvent_OnSettingsApplied()
|
|
{
|
|
for( uint slot=0; slot<8; ++slot )
|
|
{
|
|
m_Cards[slot].IsEnabled = g_Conf->Mcd[slot].Enabled;
|
|
m_Cards[slot].Filename = g_Conf->Mcd[slot].Filename;
|
|
|
|
//automatically create the enabled but non-existing file such that it can be managed (else will get created anyway on boot)
|
|
wxString targetFile = (GetMcdPath() + m_Cards[slot].Filename.GetFullName()).GetFullPath();
|
|
if ( m_Cards[slot].IsEnabled && !( wxFileExists( targetFile ) || wxDirExists( targetFile ) ) )
|
|
{
|
|
wxString errMsg;
|
|
if (isValidNewFilename(m_Cards[slot].Filename.GetFullName(), GetMcdPath(), errMsg, 5))
|
|
{
|
|
if ( !Dialogs::CreateMemoryCardDialog::CreateIt(targetFile, 8) )
|
|
Console.Error( L"Automatic createion of MCD '%s' failed. Hope for the best...", WX_STR(targetFile) );
|
|
else
|
|
Console.WriteLn( L"memcard created: '%s'.", WX_STR(targetFile) );
|
|
}
|
|
else
|
|
{
|
|
Console.Error( L"memcard was enabled but had an invalid file name. Aborting automatic creation. Hope for the best... (%s)", WX_STR(errMsg) );
|
|
}
|
|
}
|
|
|
|
if ( !m_Cards[slot].IsEnabled || !( wxFileExists( targetFile ) || wxDirExists( targetFile ) ) )
|
|
{
|
|
m_Cards[slot].IsEnabled = false;
|
|
m_Cards[slot].IsPresent = false;
|
|
m_Cards[slot].Filename = L"";
|
|
}
|
|
|
|
}
|
|
DoRefresh();
|
|
|
|
_parent::AppStatusEvent_OnSettingsApplied();
|
|
}
|
|
|
|
|
|
//BUG: the next function is never reached because, for some reason, IsoDropTarget::OnDropFiles is called instead.
|
|
// Interestingly, IsoDropTarget::OnDropFiles actually "detects" a memory card file as a valid Audio-CD ISO... - avih
|
|
bool Panels::MemoryCardListPanel_Simple::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 Panels::MemoryCardListPanel_Simple::ValidateEnumerationStatus()
|
|
{
|
|
if( m_listview ) m_listview->SetMcdProvider( NULL );
|
|
return false;
|
|
}
|
|
|
|
void Panels::MemoryCardListPanel_Simple::DoRefresh()
|
|
{
|
|
for( uint slot=0; slot<8; ++slot )
|
|
{
|
|
//if( FileMcd_IsMultitapSlot(slot) && !m_MultitapEnabled[FileMcd_GetMtapPort(slot)] )
|
|
// continue;
|
|
|
|
//wxFileName fullpath( m_FolderPicker->GetPath() + g_Conf->Mcd[slot].Filename.GetFullName() );
|
|
wxFileName fullpath = m_FolderPicker->GetPath() + m_Cards[slot].Filename.GetFullName();
|
|
|
|
EnumerateMemoryCard( m_Cards[slot], fullpath, m_FolderPicker->GetPath());
|
|
m_Cards[slot].Slot = slot;
|
|
}
|
|
|
|
ReadFilesAtMcdFolder();
|
|
|
|
|
|
if( m_listview ) m_listview->SetMcdProvider( this );
|
|
UpdateUI();
|
|
}
|
|
|
|
|
|
// =====================================================================================================
|
|
// MemoryCardListPanel_Simple (implementations)
|
|
// =====================================================================================================
|
|
|
|
void Panels::MemoryCardListPanel_Simple::UiCreateNewCard( McdSlotItem& card )
|
|
{//card can also be the filesystem placeholder. On that case, the changes
|
|
// made to it will be reverted on refresh, and we'll just have a new card at the folder.
|
|
if( card.IsPresent ){
|
|
Console.WriteLn("Error: Aborted: create mcd invoked but but a file is already associated.");
|
|
return;
|
|
}
|
|
|
|
Dialogs::CreateMemoryCardDialog dialog( this, m_FolderPicker->GetPath(), L"my memory card" );
|
|
wxWindowID result = dialog.ShowModal();
|
|
|
|
if (result != wxID_CANCEL)
|
|
{
|
|
card.IsEnabled = true;
|
|
card.Filename = dialog.result_createdMcdFilename;
|
|
card.IsPresent = true;
|
|
if ( card.Slot >= 0)
|
|
Console.WriteLn(L"setting new card to slot %u: '%s'", card.Slot, WX_STR(card.Filename.GetFullName()));
|
|
else
|
|
Console.WriteLn(L"Created a new unassigned card file: '%s'", WX_STR(card.Filename.GetFullName()) );
|
|
}
|
|
else
|
|
card.IsEnabled=false;
|
|
|
|
Apply();
|
|
RefreshSelections();
|
|
}
|
|
|
|
void Panels::MemoryCardListPanel_Simple::UiConvertCard( McdSlotItem& card ) {
|
|
if ( !card.IsPresent ) {
|
|
Console.WriteLn( "Error: Aborted: Convert mcd invoked but but a file is not associated." );
|
|
return;
|
|
}
|
|
|
|
AppConfig::McdOptions config;
|
|
config.Filename = card.Filename.GetFullName();
|
|
config.Enabled = card.IsEnabled;
|
|
config.Type = card.Type;
|
|
Dialogs::ConvertMemoryCardDialog dialog( this, m_FolderPicker->GetPath(), config );
|
|
wxWindowID result = dialog.ShowModal();
|
|
|
|
if ( result != wxID_CANCEL ) {
|
|
Apply();
|
|
RefreshSelections();
|
|
}
|
|
}
|
|
|
|
void Panels::MemoryCardListPanel_Simple::UiDeleteCard( McdSlotItem& card )
|
|
{
|
|
if( !card.IsPresent ){
|
|
Console.WriteLn("Error: Aborted: delete mcd invoked but but a file is not associated.");
|
|
return;
|
|
}
|
|
|
|
|
|
bool result = true;
|
|
if( card.IsFormatted )
|
|
{
|
|
wxString content;
|
|
content.Printf(
|
|
pxE( L"You are about to delete the formatted memory card '%s'. All data on this card will be lost! Are you absolutely and quite positively sure?"
|
|
), WX_STR(card.Filename.GetFullName())
|
|
);
|
|
|
|
result = Msgbox::YesNo( content, _("Delete memory file?") );
|
|
}
|
|
|
|
if( result )
|
|
{
|
|
|
|
wxFileName fullpath( m_FolderPicker->GetPath() + card.Filename.GetFullName());
|
|
|
|
card.IsEnabled=false;
|
|
Apply();
|
|
|
|
if ( fullpath.FileExists() ) {
|
|
wxRemoveFile( fullpath.GetFullPath() );
|
|
} else {
|
|
RemoveDirectory( fullpath.GetFullPath() );
|
|
}
|
|
|
|
RefreshSelections();
|
|
}
|
|
|
|
}
|
|
|
|
bool Panels::MemoryCardListPanel_Simple::UiDuplicateCard(McdSlotItem& src, McdSlotItem& dest)
|
|
{
|
|
wxDirName basepath = GetMcdPath();
|
|
if( !src.IsPresent )
|
|
{
|
|
Msgbox::Alert(_("Failed: Can only duplicate an existing card."), _("Duplicate memory card"));
|
|
return false;
|
|
}
|
|
|
|
if ( dest.IsPresent && dest.Slot!=-1 )
|
|
{
|
|
wxString content;
|
|
content.Printf(
|
|
pxE( L"Failed: Duplicate is only allowed to an empty PS2-Port or to the file system." )
|
|
);
|
|
|
|
Msgbox::Alert( content, _("Duplicate memory card") );
|
|
return false;
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
wxString newFilename=L"";
|
|
newFilename = wxGetTextFromUser(_("Select a name for the duplicate\n( '.ps2' will be added automatically)"), _("Duplicate memory card"));
|
|
if( newFilename==L"" )
|
|
{
|
|
//Msgbox::Alert( _("Duplicate canceled"), _("Duplicate memory card") );
|
|
return false;
|
|
}
|
|
newFilename += L".ps2";
|
|
|
|
//check that the name is valid for a new file
|
|
wxString errMsg;
|
|
if( !isValidNewFilename( newFilename, basepath, errMsg, 5 ) )
|
|
{
|
|
wxString message;
|
|
message.Printf(_("Failed: %s"), WX_STR(errMsg));
|
|
Msgbox::Alert( message, _("Duplicate memory card") );
|
|
continue;
|
|
}
|
|
|
|
dest.Filename = newFilename;
|
|
break;
|
|
}
|
|
|
|
|
|
wxFileName srcfile( basepath + src.Filename);
|
|
wxFileName destfile( basepath + dest.Filename);
|
|
|
|
ScopedBusyCursor doh( Cursor_ReallyBusy );
|
|
|
|
if( !( ( srcfile.FileExists() && wxCopyFile( srcfile.GetFullPath(), destfile.GetFullPath(), true ) )
|
|
|| ( !srcfile.FileExists() && CopyDirectory( srcfile.GetFullPath(), destfile.GetFullPath() ) ) ) )
|
|
{
|
|
wxString heading;
|
|
heading.Printf( pxE( L"Failed: Destination memory card '%s' is in use." ),
|
|
WX_STR(dest.Filename.GetFullName()), dest.Slot
|
|
);
|
|
|
|
wxString content;
|
|
|
|
Msgbox::Alert( heading + L"\n\n" + content, _("Copy failed!") );
|
|
|
|
return false;
|
|
}
|
|
|
|
// Destination memcard isEnabled state is the same now as the source's
|
|
wxString success;
|
|
success.Printf(_("Memory card '%s' duplicated to '%s'."),
|
|
WX_STR(src.Filename.GetFullName()),
|
|
WX_STR(dest.Filename.GetFullName())
|
|
);
|
|
Msgbox::Alert(success, _("Success"));
|
|
dest.IsPresent=true;
|
|
dest.IsEnabled = true;
|
|
|
|
Apply();
|
|
DoRefresh();
|
|
return true;
|
|
}
|
|
|
|
void Panels::MemoryCardListPanel_Simple::UiRenameCard( McdSlotItem& card )
|
|
{
|
|
if( !card.IsPresent ){
|
|
Console.WriteLn("Error: Aborted: Rename mcd invoked but no file is associated.");
|
|
return;
|
|
}
|
|
|
|
const wxDirName basepath( m_listview->GetMcdProvider().GetMcdPath() );
|
|
wxString newFilename;
|
|
while (1){
|
|
wxString title;
|
|
title.Printf(_("Select a new name for the memory card '%s'\n( '.ps2' will be added automatically)"),
|
|
WX_STR(card.Filename.GetFullName())
|
|
);
|
|
newFilename = wxGetTextFromUser(title, _("Rename memory card"));
|
|
if( newFilename==L"" )
|
|
return;
|
|
|
|
newFilename += L".ps2";
|
|
|
|
//check that the name is valid for a new file
|
|
wxString errMsg;
|
|
if( !isValidNewFilename( newFilename, basepath, errMsg, 5 ) )
|
|
{
|
|
wxString message;
|
|
message.Printf(_("Error (%s)"), WX_STR(errMsg));
|
|
Msgbox::Alert( message, _("Rename memory card") );
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
bool origEnabled=card.IsEnabled;
|
|
card.IsEnabled=false;
|
|
Apply();
|
|
if( !wxRenameFile( (basepath + card.Filename).GetFullPath(), (basepath + wxFileName(newFilename)).GetFullPath(), false ) )
|
|
{
|
|
card.IsEnabled=origEnabled;
|
|
Apply();
|
|
Msgbox::Alert( _("Error: Rename could not be completed.\n"), _("Rename memory card") );
|
|
|
|
return;
|
|
}
|
|
|
|
card.Filename = newFilename;
|
|
card.IsEnabled=origEnabled;
|
|
Apply();
|
|
|
|
RefreshSelections();
|
|
}
|
|
|
|
void Panels::MemoryCardListPanel_Simple::OnCreateOrDeleteCard(wxCommandEvent& evt)
|
|
{
|
|
int selectedViewIndex = m_listview->GetFirstSelected();
|
|
if( wxNOT_FOUND == selectedViewIndex )
|
|
selectedViewIndex = -1;//get filesystem placeholder, just create a new card at the filesystem.
|
|
|
|
McdSlotItem& card( GetCardForViewIndex(selectedViewIndex) );
|
|
|
|
if( card.IsPresent )
|
|
UiDeleteCard( card );
|
|
else
|
|
UiCreateNewCard( card );
|
|
}
|
|
|
|
void Panels::MemoryCardListPanel_Simple::OnConvertCard(wxCommandEvent& evt) {
|
|
int selectedViewIndex = m_listview->GetFirstSelected();
|
|
if ( wxNOT_FOUND == selectedViewIndex ) {
|
|
return;
|
|
}
|
|
|
|
McdSlotItem& card( GetCardForViewIndex( selectedViewIndex ) );
|
|
if ( card.IsPresent ) {
|
|
UiConvertCard( card );
|
|
}
|
|
}
|
|
|
|
//enable/disapbe port
|
|
/*
|
|
void Panels::MemoryCardListPanel_Simple::OnMountCard(wxCommandEvent& evt)
|
|
{
|
|
evt.Skip();
|
|
|
|
const int selectedViewIndex = m_listview->GetFirstSelected();
|
|
if( wxNOT_FOUND == selectedViewIndex ) return;
|
|
|
|
McdSlotItem& card( GetCardForViewIndex(selectedViewIndex) );
|
|
|
|
card.IsEnabled = !card.IsEnabled;
|
|
m_listview->RefreshItem(selectedViewIndex);
|
|
UpdateUI();
|
|
}
|
|
*/
|
|
/*
|
|
//text dialog: can be used for rename: wxGetTextFromUser - avih
|
|
void Panels::MemoryCardListPanel_Simple::OnRelocateCard(wxCommandEvent& evt)
|
|
{
|
|
evt.Skip();
|
|
|
|
const int slot = m_listview->GetFirstSelected();
|
|
if( wxNOT_FOUND == slot ) return;
|
|
|
|
// Issue a popup to the user that allows them to pick a new .PS2 file to serve as
|
|
// the new host memorycard file for the slot. The dialog has a number of warnings
|
|
// present to reiterate that this is an advanced operation that PCSX2 may not
|
|
// support very well (ie, might be buggy).
|
|
|
|
m_listview->RefreshItem(slot);
|
|
UpdateUI();
|
|
}
|
|
*/
|
|
|
|
// enter/double-click
|
|
void Panels::MemoryCardListPanel_Simple::OnItemActivated(wxListEvent& evt)
|
|
{
|
|
const int viewIndex = m_listview->GetFirstSelected();
|
|
if( wxNOT_FOUND == viewIndex ) return;
|
|
McdSlotItem& card( GetCardForViewIndex(viewIndex) );
|
|
|
|
if ( card.IsPresent )
|
|
UiRenameCard( card );
|
|
else if (card.Slot>=0)
|
|
UiCreateNewCard( card );// IsPresent==false can only happen for an internal slot (vs filename on the HD), so a card can be created.
|
|
}
|
|
|
|
void Panels::MemoryCardListPanel_Simple::OnDuplicateFile(wxCommandEvent& evt)
|
|
{
|
|
const int viewIndex = m_listview->GetFirstSelected();
|
|
if( wxNOT_FOUND == viewIndex ) return;
|
|
McdSlotItem& card( GetCardForViewIndex(viewIndex) );
|
|
|
|
pxAssert( card.IsPresent );
|
|
McdSlotItem dummy;
|
|
UiDuplicateCard(card, dummy);
|
|
}
|
|
|
|
wxString GetPortName(int slotIndex)
|
|
{
|
|
if (slotIndex==0 || slotIndex==1)
|
|
return pxsFmt(wxString(L" ") + _("Port-%u / Multitap-%u--Port-1"), FileMcd_GetMtapPort(slotIndex)+1, FileMcd_GetMtapPort(slotIndex)+1);
|
|
return pxsFmt(wxString(L" ")+_(" Multitap-%u--Port-%u"), FileMcd_GetMtapPort(slotIndex)+1, FileMcd_GetMtapSlot(slotIndex)+1 );
|
|
}
|
|
|
|
void Panels::MemoryCardListPanel_Simple::UiAssignUnassignFile(McdSlotItem &card)
|
|
{
|
|
pxAssert( card.IsPresent );
|
|
|
|
if( card.Slot >=0 )
|
|
{//eject
|
|
card.IsEnabled = false;
|
|
card.IsPresent = false;
|
|
card.Filename = L"";
|
|
DoRefresh();
|
|
}
|
|
else
|
|
{//insert into a (UI) selected slot
|
|
wxArrayString selections;
|
|
int i;
|
|
for (i=0; i< GetNumVisibleInternalSlots(); i++)
|
|
{
|
|
McdSlotItem& selCard = GetCardForViewIndex(i);
|
|
wxString sel = GetPortName( selCard.Slot ) + L" ( ";
|
|
if (selCard.IsPresent)
|
|
sel += selCard.Filename.GetFullName();
|
|
else
|
|
sel += _("Empty");
|
|
sel += L" )";
|
|
|
|
selections.Add(sel);
|
|
}
|
|
wxString title;
|
|
title.Printf(_("Select a target port for '%s'"), WX_STR(card.Filename.GetFullName()));
|
|
int res=wxGetSingleChoiceIndex(title, _("Insert card"), selections, this);
|
|
if( res<0 )
|
|
return;
|
|
|
|
McdSlotItem& target = GetCardForViewIndex(res);
|
|
bool en = target.IsPresent? target.IsEnabled : true;
|
|
RemoveCardFromSlot( card.Filename );
|
|
target.Filename = card.Filename;
|
|
target.IsPresent = true;
|
|
target.IsEnabled = en;
|
|
DoRefresh();
|
|
}
|
|
}
|
|
void Panels::MemoryCardListPanel_Simple::OnAssignUnassignFile(wxCommandEvent& evt)
|
|
{
|
|
const int viewIndex = m_listview->GetFirstSelected();
|
|
if( wxNOT_FOUND == viewIndex ) return;
|
|
McdSlotItem& card( GetCardForViewIndex(viewIndex) );
|
|
|
|
UiAssignUnassignFile(card);
|
|
}
|
|
|
|
void Panels::MemoryCardListPanel_Simple::OnRenameFile(wxCommandEvent& evt)
|
|
{
|
|
const int viewIndex = m_listview->GetFirstSelected();
|
|
if( wxNOT_FOUND == viewIndex ) return;
|
|
McdSlotItem& card( GetCardForViewIndex(viewIndex) );
|
|
|
|
UiRenameCard( card );
|
|
}
|
|
|
|
|
|
void Panels::MemoryCardListPanel_Simple::OnListDrag(wxListEvent& evt)
|
|
{
|
|
int selectionViewIndex = m_listview->GetFirstSelected();
|
|
|
|
if( selectionViewIndex < 0 ) return;
|
|
wxCustomDataObject my_data(drag_drop_format);
|
|
my_data.SetData(sizeof(int), &selectionViewIndex);
|
|
|
|
wxDropSource dragSource( m_listview );
|
|
dragSource.SetData( my_data );
|
|
/*wxDragResult result = */dragSource.DoDragDrop( wxDrag_DefaultMove );
|
|
}
|
|
|
|
void Panels::MemoryCardListPanel_Simple::OnListSelectionChanged(wxListEvent& evt)
|
|
{
|
|
UpdateUI();
|
|
}
|
|
|
|
void Panels::MemoryCardListPanel_Simple::OnOpenItemContextMenu(wxListEvent& evt)
|
|
{
|
|
int idx = evt.GetIndex();
|
|
|
|
wxMenu* junk = new wxMenu();
|
|
|
|
if( idx != wxNOT_FOUND )
|
|
{
|
|
const McdSlotItem& card( GetCardForViewIndex(idx) );
|
|
|
|
if (card.IsPresent){
|
|
junk->Append( McdMenuId_AssignUnassign, card.Slot>=0?_("Eject card"):_("Insert card ...") );
|
|
junk->Append( McdMenuId_Duplicate, _("Duplicate card ...") );
|
|
junk->Append( McdMenuId_Rename, _("Rename card ...") );
|
|
junk->Append( McdMenuId_Create, _("Delete card") );
|
|
if (card.IsFormatted && !card.IsPSX) {
|
|
junk->Append( McdMenuId_Convert, _("Convert card") );
|
|
}
|
|
}
|
|
else
|
|
junk->Append( McdMenuId_Create, _("Create a new card ...") );
|
|
|
|
}
|
|
else
|
|
junk->Append( McdMenuId_Create, _("Create a new card ...") );
|
|
|
|
junk->AppendSeparator();
|
|
|
|
junk->Append( McdMenuId_RefreshList, _("Refresh List") );
|
|
|
|
PopupMenu( junk );
|
|
m_listview->RefreshItem( idx );
|
|
UpdateUI();
|
|
}
|
|
|
|
void Panels::MemoryCardListPanel_Simple::ReadFilesAtMcdFolder(){
|
|
//Dir enumeration/iteration code courtesy of cotton. - avih.
|
|
while( !m_allFilesystemCards.empty() )
|
|
m_allFilesystemCards.pop_back();
|
|
|
|
m_filesystemPlaceholderCard.Slot=-1;
|
|
m_filesystemPlaceholderCard.IsEnabled=false;
|
|
m_filesystemPlaceholderCard.IsPresent=false;
|
|
m_filesystemPlaceholderCard.Filename=L"";
|
|
|
|
|
|
wxArrayString memcardList;
|
|
wxString filename = m_FolderPicker->GetPath().ToString();
|
|
wxDir memcardDir( filename );
|
|
if ( memcardDir.IsOpened() ) {
|
|
// add memory card files
|
|
wxDir::GetAllFiles( filename, &memcardList, L"*.ps2", wxDIR_FILES );
|
|
wxDir::GetAllFiles( filename, &memcardList, L"*.mcd", wxDIR_FILES );
|
|
wxDir::GetAllFiles( filename, &memcardList, L"*.mcr", wxDIR_FILES );
|
|
|
|
// add memory card folders
|
|
wxString dirname;
|
|
if ( memcardDir.GetFirst( &dirname, wxEmptyString, wxDIR_DIRS | wxDIR_HIDDEN ) ) {
|
|
do {
|
|
wxFileName superBlockFileName( wxFileName( filename, dirname ).GetFullPath(), L"_pcsx2_superblock" );
|
|
if ( superBlockFileName.FileExists() ) {
|
|
memcardList.Add( superBlockFileName.GetPath() );
|
|
}
|
|
} while ( memcardDir.GetNext( &dirname ) );
|
|
}
|
|
}
|
|
|
|
|
|
for(uint i = 0; i < memcardList.size(); i++) {
|
|
McdSlotItem currentCardFile;
|
|
bool isOk=EnumerateMemoryCard( currentCardFile, memcardList[i], m_FolderPicker->GetPath() );
|
|
if( isOk && !isFileAssignedAndVisibleOnList( currentCardFile.Filename ) )
|
|
{
|
|
currentCardFile.Slot = -1;
|
|
currentCardFile.IsEnabled = false;
|
|
m_allFilesystemCards.push_back(currentCardFile);
|
|
//DevCon.WriteLn(L"Enumerated file: '%s'", WX_STR(currentCardFile.Filename.GetFullName()) );
|
|
}
|
|
/*else
|
|
DevCon.WriteLn(L"MCD folder card file skipped: '%s'", WX_STR(memcardList[i]) );*/
|
|
}
|
|
}
|
|
|
|
|
|
bool Panels::MemoryCardListPanel_Simple::IsSlotVisible(int slotIndex) const
|
|
{
|
|
if ( slotIndex<0 || slotIndex>=8 ) return false;
|
|
if ( !m_MultitapEnabled[0] && 2<=slotIndex && slotIndex<=4) return false;
|
|
if ( !m_MultitapEnabled[1] && 5<=slotIndex && slotIndex<=7) return false;
|
|
return true;
|
|
}
|
|
//whether or not this filename appears on the ports at the list (takes into account MT enabled/disabled)
|
|
bool Panels::MemoryCardListPanel_Simple::isFileAssignedAndVisibleOnList(const wxFileName cardFile) const
|
|
{
|
|
int i;
|
|
for( i=0; i<8; i++)
|
|
if ( IsSlotVisible(i) && cardFile.GetFullName()==m_Cards[i].Filename.GetFullName() )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
//whether or not this filename is assigned to a ports (regardless if MT enabled/disabled)
|
|
bool Panels::MemoryCardListPanel_Simple::isFileAssignedToInternalSlot(const wxFileName cardFile) const
|
|
{
|
|
int i;
|
|
for( i=0; i<8; i++)
|
|
if ( cardFile.GetFullName()==m_Cards[i].Filename.GetFullName() )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void Panels::MemoryCardListPanel_Simple::RemoveCardFromSlot(const wxFileName cardFile)
|
|
{
|
|
int i;
|
|
for( i=0; i<8; i++)
|
|
if ( cardFile.GetFullName()==m_Cards[i].Filename.GetFullName() )
|
|
{
|
|
m_Cards[i].Filename = L"";
|
|
m_Cards[i].IsPresent = false;
|
|
m_Cards[i].IsEnabled = false;
|
|
}
|
|
}
|
|
|
|
int Panels::MemoryCardListPanel_Simple::GetNumFilesVisibleAsFilesystem() const
|
|
{
|
|
return m_allFilesystemCards.size();
|
|
}
|
|
|
|
|
|
bool Panels::MemoryCardListPanel_Simple::IsNonEmptyFilesystemCards() const
|
|
{
|
|
return GetNumFilesVisibleAsFilesystem()>0;
|
|
}
|
|
|
|
McdSlotItem& Panels::MemoryCardListPanel_Simple::GetNthVisibleFilesystemCard(int n)
|
|
{
|
|
return m_allFilesystemCards.at(n);
|
|
}
|
|
|
|
int Panels::MemoryCardListPanel_Simple::GetNumVisibleInternalSlots() const
|
|
{
|
|
uint baselen = 2;
|
|
if( m_MultitapEnabled[0] ) baselen += 3;
|
|
if( m_MultitapEnabled[1] ) baselen += 3;
|
|
return baselen;
|
|
}
|
|
|
|
// Interface Implementation for IMcdList
|
|
int Panels::MemoryCardListPanel_Simple::GetLength() const
|
|
{
|
|
uint baselen = GetNumVisibleInternalSlots();
|
|
baselen++;//filesystem placeholder
|
|
baselen+= GetNumFilesVisibleAsFilesystem();
|
|
return baselen;
|
|
}
|
|
|
|
|
|
//Translates a list-view index (idx) to an internal memory card slot.
|
|
//This method effectively defines the arrangement of the card slots at the list view.
|
|
//The internal card slots array is fixed as sollows:
|
|
// slot 0: mcd1 (= MT1 slot 1)
|
|
// slot 1: mcd2 (= MT2 slot 1)
|
|
// slots 2,3,4: MT1 slots 2,3,4
|
|
// slots 5,6,7: MT2 slots 2,3,4
|
|
//
|
|
//however, the list-view doesn't show MT slots when this MT is disabled,
|
|
// so the view-index should "shift" to point at the real card slot.
|
|
//While we're at it, we can alternatively enforce any other arrangment of the view by
|
|
// using any other set of 'view-index-to-card-slot' translating that we'd like.
|
|
int Panels::MemoryCardListPanel_Simple::GetSlotIndexForViewIndex( int listViewIndex )
|
|
{
|
|
pxAssert( 0<=listViewIndex && listViewIndex<GetNumVisibleInternalSlots() );
|
|
int targetSlot=-1;
|
|
|
|
/*
|
|
//this list-view arrangement is mostly kept aligned with the internal slots indexes, and only takes care
|
|
// of the case where MT1 is disabled (hence the MT2 slots 2,3,4 "move backwards" 3 places on the view-index)
|
|
// However, this arrangement it's not very intuitive to use...
|
|
if (!m_MultitapEnabled[0] && listViewIndex>=2)
|
|
{
|
|
//we got an MT2 slot.
|
|
assert(listViewIndex < 5);
|
|
targetSlot = listViewIndex+3;
|
|
}
|
|
else
|
|
{
|
|
targetSlot=listViewIndex;//identical view-index and card slot.
|
|
}
|
|
*/
|
|
|
|
//This arrangement of list-view is as follows:
|
|
//mcd1(=MT1 port 1)
|
|
//[MT1 port 2,3,4 if MT1 is enabled]
|
|
//mcd2(=MT2 slot 1)
|
|
//[MT2 port 2,3,4 if MT2 is enabled]
|
|
|
|
if (m_MultitapEnabled[0]){
|
|
//MT1 enabled:
|
|
if (1<=listViewIndex && listViewIndex<=3){//MT1 ports 2/3/4 move one place backwards
|
|
targetSlot=listViewIndex+1;
|
|
}else if (listViewIndex==4){//mcd2 (=MT2 port 1) moves 3 places forward
|
|
targetSlot=1;
|
|
} else {//mcd1 keeps it's pos as first, MT2 ports keep their pos at the end of the list.
|
|
targetSlot=listViewIndex;
|
|
}
|
|
} else {
|
|
//MT1 disabled: mcd1 and mcd2 stay put, MT2 ports 2,3,4 come next (move backwards 3 places)
|
|
if (2<=listViewIndex && listViewIndex<=4)
|
|
targetSlot=listViewIndex+3;
|
|
else
|
|
targetSlot=listViewIndex;
|
|
}
|
|
|
|
pxAssert( 0<=targetSlot && targetSlot<=7 );
|
|
return targetSlot;
|
|
}
|
|
|
|
|
|
McdSlotItem& Panels::MemoryCardListPanel_Simple::GetCardForViewIndex( int idx )
|
|
{
|
|
pxAssert( -1<=idx && idx< GetNumVisibleInternalSlots()+1+GetNumFilesVisibleAsFilesystem() );
|
|
|
|
if( 0<=idx && idx<GetNumVisibleInternalSlots() )
|
|
return m_Cards[GetSlotIndexForViewIndex( idx )];
|
|
|
|
if( idx==-1 || idx == GetNumVisibleInternalSlots() )
|
|
return this->m_filesystemPlaceholderCard;
|
|
|
|
return this->m_allFilesystemCards.at( idx - GetNumVisibleInternalSlots() - 1 );
|
|
}
|