mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-11 08:39:13 +01:00
e1359382be
Minor other alterations that relate to above as well. Also added the PanicAlertT version of alerts for some error messages that use PanicAlert. We want the user to actually understand why the error occurred.
1339 lines
36 KiB
C++
1339 lines
36 KiB
C++
// Copyright 2013 Dolphin Emulator Project
|
|
// Licensed under GPLv2
|
|
// Refer to the license.txt file included.
|
|
|
|
#include <algorithm>
|
|
#include <cinttypes>
|
|
#include <cstddef>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <wx/app.h>
|
|
#include <wx/bitmap.h>
|
|
#include <wx/buffer.h>
|
|
#include <wx/chartype.h>
|
|
#include <wx/colour.h>
|
|
#include <wx/defs.h>
|
|
#include <wx/dirdlg.h>
|
|
#include <wx/event.h>
|
|
#include <wx/filedlg.h>
|
|
#include <wx/filefn.h>
|
|
#include <wx/filename.h>
|
|
#include <wx/gdicmn.h>
|
|
#include <wx/imaglist.h>
|
|
#include <wx/listbase.h>
|
|
#include <wx/listctrl.h>
|
|
#include <wx/menu.h>
|
|
#include <wx/menuitem.h>
|
|
#include <wx/msgdlg.h>
|
|
#include <wx/progdlg.h>
|
|
#include <wx/settings.h>
|
|
#include <wx/string.h>
|
|
#include <wx/tipwin.h>
|
|
#include <wx/translation.h>
|
|
#include <wx/unichar.h>
|
|
#include <wx/utils.h>
|
|
#include <wx/version.h>
|
|
#include <wx/window.h>
|
|
#include <wx/windowid.h>
|
|
|
|
#include "Common/CDUtils.h"
|
|
#include "Common/Common.h"
|
|
#include "Common/FileSearch.h"
|
|
#include "Common/FileUtil.h"
|
|
#include "Common/MathUtil.h"
|
|
#include "Common/StdMakeUnique.h"
|
|
#include "Common/StringUtil.h"
|
|
#include "Common/SysConf.h"
|
|
#include "Core/ConfigManager.h"
|
|
#include "Core/Core.h"
|
|
#include "Core/CoreParameter.h"
|
|
#include "Core/Movie.h"
|
|
#include "Core/Boot/Boot.h"
|
|
#include "Core/HW/DVDInterface.h"
|
|
#include "DiscIO/Blob.h"
|
|
#include "DiscIO/Volume.h"
|
|
#include "DiscIO/VolumeCreator.h"
|
|
#include "DolphinWX/Frame.h"
|
|
#include "DolphinWX/GameListCtrl.h"
|
|
#include "DolphinWX/Globals.h"
|
|
#include "DolphinWX/ISOFile.h"
|
|
#include "DolphinWX/ISOProperties.h"
|
|
#include "DolphinWX/Main.h"
|
|
#include "DolphinWX/WxUtils.h"
|
|
#include "DolphinWX/MemoryCards/WiiSaveCrypted.h"
|
|
#include "DolphinWX/resources/Flag_Europe.xpm"
|
|
#include "DolphinWX/resources/Flag_France.xpm"
|
|
#include "DolphinWX/resources/Flag_Germany.xpm"
|
|
#include "DolphinWX/resources/Flag_Italy.xpm"
|
|
#include "DolphinWX/resources/Flag_Japan.xpm"
|
|
#include "DolphinWX/resources/Flag_Korea.xpm"
|
|
#include "DolphinWX/resources/Flag_SDK.xpm"
|
|
#include "DolphinWX/resources/Flag_Taiwan.xpm"
|
|
#include "DolphinWX/resources/Flag_Unknown.xpm"
|
|
#include "DolphinWX/resources/Flag_USA.xpm"
|
|
#include "DolphinWX/resources/Platform_Gamecube.xpm"
|
|
#include "DolphinWX/resources/Platform_Wad.xpm"
|
|
#include "DolphinWX/resources/Platform_Wii.xpm"
|
|
#include "DolphinWX/resources/rating_gamelist.h"
|
|
|
|
size_t CGameListCtrl::m_currentItem = 0;
|
|
size_t CGameListCtrl::m_numberItem = 0;
|
|
std::string CGameListCtrl::m_currentFilename;
|
|
bool sorted = false;
|
|
|
|
extern CFrame* main_frame;
|
|
|
|
static int CompareGameListItems(const GameListItem* iso1, const GameListItem* iso2,
|
|
long sortData = CGameListCtrl::COLUMN_TITLE)
|
|
{
|
|
int t = 1;
|
|
|
|
if (sortData < 0)
|
|
{
|
|
t = -1;
|
|
sortData = -sortData;
|
|
}
|
|
|
|
int indexOne = 0;
|
|
int indexOther = 0;
|
|
|
|
|
|
// index only matters for WADS and PAL GC games, but invalid indicies for the others
|
|
// will return the (only) language in the list
|
|
if (iso1->GetPlatform() == GameListItem::WII_WAD)
|
|
{
|
|
indexOne = SConfig::GetInstance().m_SYSCONF->GetData<u8>("IPL.LNG");
|
|
}
|
|
else // GC
|
|
{
|
|
indexOne = SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage;
|
|
}
|
|
|
|
if (iso2->GetPlatform() == GameListItem::WII_WAD)
|
|
{
|
|
indexOther = SConfig::GetInstance().m_SYSCONF->GetData<u8>("IPL.LNG");
|
|
}
|
|
else // GC
|
|
{
|
|
indexOther = SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage;
|
|
}
|
|
|
|
switch (sortData)
|
|
{
|
|
case CGameListCtrl::COLUMN_TITLE:
|
|
if (!strcasecmp(iso1->GetName(indexOne).c_str(),iso2->GetName(indexOther).c_str()))
|
|
{
|
|
if (iso1->IsDiscTwo())
|
|
return 1 * t;
|
|
else if (iso2->IsDiscTwo())
|
|
return -1 * t;
|
|
}
|
|
return strcasecmp(iso1->GetName(indexOne).c_str(),
|
|
iso2->GetName(indexOther).c_str()) * t;
|
|
case CGameListCtrl::COLUMN_NOTES:
|
|
{
|
|
std::string cmp1 =
|
|
(iso1->GetPlatform() == GameListItem::GAMECUBE_DISC) ?
|
|
iso1->GetCompany() : iso1->GetDescription(indexOne);
|
|
std::string cmp2 =
|
|
(iso2->GetPlatform() == GameListItem::GAMECUBE_DISC) ?
|
|
iso2->GetCompany() : iso2->GetDescription(indexOther);
|
|
return strcasecmp(cmp1.c_str(), cmp2.c_str()) * t;
|
|
}
|
|
case CGameListCtrl::COLUMN_COUNTRY:
|
|
if (iso1->GetCountry() > iso2->GetCountry())
|
|
return 1 * t;
|
|
if (iso1->GetCountry() < iso2->GetCountry())
|
|
return -1 * t;
|
|
return 0;
|
|
case CGameListCtrl::COLUMN_SIZE:
|
|
if (iso1->GetFileSize() > iso2->GetFileSize())
|
|
return 1 * t;
|
|
if (iso1->GetFileSize() < iso2->GetFileSize())
|
|
return -1 * t;
|
|
return 0;
|
|
case CGameListCtrl::COLUMN_PLATFORM:
|
|
if (iso1->GetPlatform() > iso2->GetPlatform())
|
|
return 1 * t;
|
|
if (iso1->GetPlatform() < iso2->GetPlatform())
|
|
return -1 * t;
|
|
return 0;
|
|
|
|
case CGameListCtrl::COLUMN_EMULATION_STATE:
|
|
{
|
|
const int
|
|
nState1 = iso1->GetEmuState(),
|
|
nState2 = iso2->GetEmuState();
|
|
|
|
if (nState1 > nState2)
|
|
return 1 * t;
|
|
if (nState1 < nState2)
|
|
return -1 * t;
|
|
else
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool operator < (const GameListItem &one, const GameListItem &other)
|
|
{
|
|
return CompareGameListItems(&one, &other) < 0;
|
|
}
|
|
|
|
BEGIN_EVENT_TABLE(wxEmuStateTip, wxTipWindow)
|
|
EVT_KEY_DOWN(wxEmuStateTip::OnKeyDown)
|
|
END_EVENT_TABLE()
|
|
|
|
BEGIN_EVENT_TABLE(CGameListCtrl, wxListCtrl)
|
|
EVT_SIZE(CGameListCtrl::OnSize)
|
|
EVT_RIGHT_DOWN(CGameListCtrl::OnRightClick)
|
|
EVT_LEFT_DOWN(CGameListCtrl::OnLeftClick)
|
|
EVT_LIST_KEY_DOWN(LIST_CTRL, CGameListCtrl::OnKeyPress)
|
|
EVT_MOTION(CGameListCtrl::OnMouseMotion)
|
|
EVT_LIST_COL_BEGIN_DRAG(LIST_CTRL, CGameListCtrl::OnColBeginDrag)
|
|
EVT_LIST_COL_CLICK(LIST_CTRL, CGameListCtrl::OnColumnClick)
|
|
EVT_MENU(IDM_PROPERTIES, CGameListCtrl::OnProperties)
|
|
EVT_MENU(IDM_GAMEWIKI, CGameListCtrl::OnWiki)
|
|
EVT_MENU(IDM_OPENCONTAININGFOLDER, CGameListCtrl::OnOpenContainingFolder)
|
|
EVT_MENU(IDM_OPENSAVEFOLDER, CGameListCtrl::OnOpenSaveFolder)
|
|
EVT_MENU(IDM_EXPORTSAVE, CGameListCtrl::OnExportSave)
|
|
EVT_MENU(IDM_SETDEFAULTGCM, CGameListCtrl::OnSetDefaultGCM)
|
|
EVT_MENU(IDM_COMPRESSGCM, CGameListCtrl::OnCompressGCM)
|
|
EVT_MENU(IDM_MULTICOMPRESSGCM, CGameListCtrl::OnMultiCompressGCM)
|
|
EVT_MENU(IDM_MULTIDECOMPRESSGCM, CGameListCtrl::OnMultiDecompressGCM)
|
|
EVT_MENU(IDM_DELETEGCM, CGameListCtrl::OnDeleteGCM)
|
|
END_EVENT_TABLE()
|
|
|
|
CGameListCtrl::CGameListCtrl(wxWindow* parent, const wxWindowID id, const
|
|
wxPoint& pos, const wxSize& size, long style)
|
|
: wxListCtrl(parent, id, pos, size, style), toolTip(nullptr)
|
|
{
|
|
DragAcceptFiles(true);
|
|
Connect(wxEVT_DROP_FILES, wxDropFilesEventHandler(CGameListCtrl::OnDropFiles), nullptr, this);
|
|
}
|
|
|
|
CGameListCtrl::~CGameListCtrl()
|
|
{
|
|
if (m_imageListSmall)
|
|
delete m_imageListSmall;
|
|
|
|
ClearIsoFiles();
|
|
}
|
|
|
|
void CGameListCtrl::InitBitmaps()
|
|
{
|
|
m_imageListSmall = new wxImageList(96, 32);
|
|
SetImageList(m_imageListSmall, wxIMAGE_LIST_SMALL);
|
|
|
|
m_FlagImageIndex.resize(DiscIO::IVolume::NUMBER_OF_COUNTRIES);
|
|
m_FlagImageIndex[DiscIO::IVolume::COUNTRY_EUROPE] = m_imageListSmall->Add(wxBitmap(Flag_Europe_xpm));
|
|
m_FlagImageIndex[DiscIO::IVolume::COUNTRY_GERMANY] = m_imageListSmall->Add(wxBitmap(Flag_Germany_xpm));
|
|
m_FlagImageIndex[DiscIO::IVolume::COUNTRY_FRANCE] = m_imageListSmall->Add(wxBitmap(Flag_France_xpm));
|
|
m_FlagImageIndex[DiscIO::IVolume::COUNTRY_USA] = m_imageListSmall->Add(wxBitmap(Flag_USA_xpm));
|
|
m_FlagImageIndex[DiscIO::IVolume::COUNTRY_JAPAN] = m_imageListSmall->Add(wxBitmap(Flag_Japan_xpm));
|
|
m_FlagImageIndex[DiscIO::IVolume::COUNTRY_KOREA] = m_imageListSmall->Add(wxBitmap(Flag_Korea_xpm));
|
|
m_FlagImageIndex[DiscIO::IVolume::COUNTRY_ITALY] = m_imageListSmall->Add(wxBitmap(Flag_Italy_xpm));
|
|
m_FlagImageIndex[DiscIO::IVolume::COUNTRY_TAIWAN] = m_imageListSmall->Add(wxBitmap(Flag_Taiwan_xpm));
|
|
m_FlagImageIndex[DiscIO::IVolume::COUNTRY_SDK] = m_imageListSmall->Add(wxBitmap(Flag_SDK_xpm));
|
|
m_FlagImageIndex[DiscIO::IVolume::COUNTRY_UNKNOWN] = m_imageListSmall->Add(wxBitmap(Flag_Unknown_xpm));
|
|
|
|
m_PlatformImageIndex.resize(3);
|
|
m_PlatformImageIndex[0] = m_imageListSmall->Add(wxBitmap(Platform_Gamecube_xpm));
|
|
m_PlatformImageIndex[1] = m_imageListSmall->Add(wxBitmap(Platform_Wii_xpm));
|
|
m_PlatformImageIndex[2] = m_imageListSmall->Add(wxBitmap(Platform_Wad_xpm));
|
|
|
|
m_EmuStateImageIndex.resize(6);
|
|
m_EmuStateImageIndex[0] = m_imageListSmall->Add(wxBitmap(rating_0));
|
|
m_EmuStateImageIndex[1] = m_imageListSmall->Add(wxBitmap(rating_1));
|
|
m_EmuStateImageIndex[2] = m_imageListSmall->Add(wxBitmap(rating_2));
|
|
m_EmuStateImageIndex[3] = m_imageListSmall->Add(wxBitmap(rating_3));
|
|
m_EmuStateImageIndex[4] = m_imageListSmall->Add(wxBitmap(rating_4));
|
|
m_EmuStateImageIndex[5] = m_imageListSmall->Add(wxBitmap(rating_5));
|
|
}
|
|
|
|
void CGameListCtrl::BrowseForDirectory()
|
|
{
|
|
wxString dirHome;
|
|
wxGetHomeDir(&dirHome);
|
|
|
|
// browse
|
|
wxDirDialog dialog(this, _("Browse for a directory to add"), dirHome,
|
|
wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
|
|
|
|
if (dialog.ShowModal() == wxID_OK)
|
|
{
|
|
std::string sPath(WxStrToStr(dialog.GetPath()));
|
|
std::vector<std::string>::iterator itResult = std::find(
|
|
SConfig::GetInstance().m_ISOFolder.begin(),
|
|
SConfig::GetInstance().m_ISOFolder.end(), sPath);
|
|
|
|
if (itResult == SConfig::GetInstance().m_ISOFolder.end())
|
|
{
|
|
SConfig::GetInstance().m_ISOFolder.push_back(sPath);
|
|
SConfig::GetInstance().SaveSettings();
|
|
}
|
|
|
|
Update();
|
|
}
|
|
}
|
|
|
|
void CGameListCtrl::Update()
|
|
{
|
|
int scrollPos = wxWindow::GetScrollPos(wxVERTICAL);
|
|
// Don't let the user refresh it while a game is running
|
|
if (Core::GetState() != Core::CORE_UNINITIALIZED)
|
|
return;
|
|
|
|
if (m_imageListSmall)
|
|
{
|
|
delete m_imageListSmall;
|
|
m_imageListSmall = nullptr;
|
|
}
|
|
|
|
Hide();
|
|
|
|
ScanForISOs();
|
|
|
|
ClearAll();
|
|
|
|
if (m_ISOFiles.size() != 0)
|
|
{
|
|
// Don't load bitmaps unless there are games to list
|
|
InitBitmaps();
|
|
|
|
// add columns
|
|
InsertColumn(COLUMN_DUMMY, "");
|
|
InsertColumn(COLUMN_PLATFORM, "");
|
|
InsertColumn(COLUMN_BANNER, _("Banner"));
|
|
InsertColumn(COLUMN_TITLE, _("Title"));
|
|
|
|
// Instead of showing the notes + the company, which is unknown with
|
|
// wii titles We show in the same column : company for GC games and
|
|
// description for wii/wad games
|
|
InsertColumn(COLUMN_NOTES, _("Notes"));
|
|
InsertColumn(COLUMN_COUNTRY, "");
|
|
InsertColumn(COLUMN_SIZE, _("Size"));
|
|
InsertColumn(COLUMN_EMULATION_STATE, _("State"));
|
|
|
|
#ifdef __WXMSW__
|
|
const int platform_padding = 0;
|
|
#else
|
|
const int platform_padding = 8;
|
|
#endif
|
|
|
|
// set initial sizes for columns
|
|
SetColumnWidth(COLUMN_DUMMY,0);
|
|
SetColumnWidth(COLUMN_PLATFORM, 35 + platform_padding);
|
|
SetColumnWidth(COLUMN_BANNER, 96 + platform_padding);
|
|
SetColumnWidth(COLUMN_TITLE, 200 + platform_padding);
|
|
SetColumnWidth(COLUMN_NOTES, 200 + platform_padding);
|
|
SetColumnWidth(COLUMN_COUNTRY, 32 + platform_padding);
|
|
SetColumnWidth(COLUMN_EMULATION_STATE, 50 + platform_padding);
|
|
|
|
// add all items
|
|
for (int i = 0; i < (int)m_ISOFiles.size(); i++)
|
|
{
|
|
InsertItemInReportView(i);
|
|
if (m_ISOFiles[i]->IsCompressed())
|
|
SetItemTextColour(i, wxColour(0xFF0000));
|
|
}
|
|
|
|
// Sort items by Title
|
|
if (!sorted)
|
|
last_column = 0;
|
|
sorted = false;
|
|
wxListEvent event;
|
|
event.m_col = SConfig::GetInstance().m_ListSort2;
|
|
OnColumnClick(event);
|
|
|
|
event.m_col = SConfig::GetInstance().m_ListSort;
|
|
OnColumnClick(event);
|
|
sorted = true;
|
|
|
|
SetColumnWidth(COLUMN_SIZE, wxLIST_AUTOSIZE);
|
|
}
|
|
else
|
|
{
|
|
wxString errorString;
|
|
// We just check for one hide setting to be enabled, as we may only
|
|
// have GC games for example, and hide them, so we should show the
|
|
// second message instead
|
|
if ((SConfig::GetInstance().m_ListGC &&
|
|
SConfig::GetInstance().m_ListWii &&
|
|
SConfig::GetInstance().m_ListWad) &&
|
|
(SConfig::GetInstance().m_ListJap &&
|
|
SConfig::GetInstance().m_ListUsa &&
|
|
SConfig::GetInstance().m_ListPal))
|
|
{
|
|
errorString = _("Dolphin could not find any GC/Wii ISOs. Doubleclick here to browse for files...");
|
|
}
|
|
else
|
|
{
|
|
errorString = _("Dolphin is currently set to hide all games. Doubleclick here to show all games...");
|
|
}
|
|
InsertColumn(0, _("No ISOs or WADS found"));
|
|
long index = InsertItem(0, errorString);
|
|
SetItemFont(index, *wxITALIC_FONT);
|
|
SetColumnWidth(0, wxLIST_AUTOSIZE);
|
|
}
|
|
if (GetSelectedISO() == nullptr)
|
|
main_frame->UpdateGUI();
|
|
Show();
|
|
|
|
AutomaticColumnWidth();
|
|
ScrollLines(scrollPos);
|
|
SetFocus();
|
|
}
|
|
|
|
wxString NiceSizeFormat(u64 _size)
|
|
{
|
|
const char* const unit_symbols[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"};
|
|
|
|
const u64 unit = Log2(std::max<u64>(_size, 1)) / 10;
|
|
const u64 unit_size = (1 << (unit * 10));
|
|
|
|
// ugly rounding integer math
|
|
const u64 value = (_size + unit_size / 2) / unit_size;
|
|
const u64 frac = (_size % unit_size * 10 + unit_size / 2) / unit_size % 10;
|
|
|
|
return StrToWxStr(StringFromFormat("%" PRIu64 ".%" PRIu64 " %s", value, frac, unit_symbols[unit]));
|
|
}
|
|
|
|
void CGameListCtrl::InsertItemInReportView(long _Index)
|
|
{
|
|
// When using wxListCtrl, there is no hope of per-column text colors.
|
|
// But for reference, here are the old colors that were used: (BGR)
|
|
// title: 0xFF0000
|
|
// company: 0x007030
|
|
int ImageIndex = -1;
|
|
|
|
GameListItem& rISOFile = *m_ISOFiles[_Index];
|
|
|
|
// Insert a first row with nothing in it, that will be used as the Index
|
|
long ItemIndex = InsertItem(_Index, wxEmptyString);
|
|
|
|
// Insert the platform's image in the first (visible) column
|
|
SetItemColumnImage(_Index, COLUMN_PLATFORM, m_PlatformImageIndex[rISOFile.GetPlatform()]);
|
|
|
|
if (rISOFile.GetBitmap().IsOk())
|
|
ImageIndex = m_imageListSmall->Add(rISOFile.GetBitmap());
|
|
|
|
// Set the game's banner in the second column
|
|
SetItemColumnImage(_Index, COLUMN_BANNER, ImageIndex);
|
|
|
|
int SelectedLanguage = SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage;
|
|
|
|
// Is this sane?
|
|
if (rISOFile.GetPlatform() == GameListItem::WII_WAD)
|
|
{
|
|
SelectedLanguage = SConfig::GetInstance().m_SYSCONF->GetData<u8>("IPL.LNG");
|
|
}
|
|
|
|
std::string const name = rISOFile.GetName(SelectedLanguage);
|
|
SetItem(_Index, COLUMN_TITLE, StrToWxStr(name), -1);
|
|
|
|
// We show the company string on Gamecube only
|
|
// On Wii we show the description instead as the company string is empty
|
|
std::string const notes = (rISOFile.GetPlatform() == GameListItem::GAMECUBE_DISC) ?
|
|
rISOFile.GetCompany() : rISOFile.GetDescription(SelectedLanguage);
|
|
SetItem(_Index, COLUMN_NOTES, StrToWxStr(notes), -1);
|
|
|
|
// Emulation state
|
|
SetItemColumnImage(_Index, COLUMN_EMULATION_STATE, m_EmuStateImageIndex[rISOFile.GetEmuState()]);
|
|
|
|
// Country
|
|
SetItemColumnImage(_Index, COLUMN_COUNTRY, m_FlagImageIndex[rISOFile.GetCountry()]);
|
|
|
|
// File size
|
|
SetItem(_Index, COLUMN_SIZE, NiceSizeFormat(rISOFile.GetFileSize()), -1);
|
|
|
|
// Background color
|
|
SetBackgroundColor();
|
|
|
|
// Item data
|
|
SetItemData(_Index, ItemIndex);
|
|
}
|
|
|
|
wxColour blend50(const wxColour& c1, const wxColour& c2)
|
|
{
|
|
unsigned char r,g,b,a;
|
|
r = c1.Red()/2 + c2.Red()/2;
|
|
g = c1.Green()/2 + c2.Green()/2;
|
|
b = c1.Blue()/2 + c2.Blue()/2;
|
|
a = c1.Alpha()/2 + c2.Alpha()/2;
|
|
return a << 24 | b << 16 | g << 8 | r;
|
|
}
|
|
|
|
void CGameListCtrl::SetBackgroundColor()
|
|
{
|
|
for (long i = 0; i < GetItemCount(); i++)
|
|
{
|
|
wxColour color = (i & 1) ?
|
|
blend50(wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT),
|
|
wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)) :
|
|
wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
|
|
CGameListCtrl::SetItemBackgroundColour(i, color);
|
|
}
|
|
}
|
|
|
|
void CGameListCtrl::ScanForISOs()
|
|
{
|
|
ClearIsoFiles();
|
|
|
|
CFileSearch::XStringVector Directories(SConfig::GetInstance().m_ISOFolder);
|
|
|
|
if (SConfig::GetInstance().m_RecursiveISOFolder)
|
|
{
|
|
for (u32 i = 0; i < Directories.size(); i++)
|
|
{
|
|
File::FSTEntry FST_Temp;
|
|
File::ScanDirectoryTree(Directories[i], FST_Temp);
|
|
for (auto& Entry : FST_Temp.children)
|
|
{
|
|
if (Entry.isDirectory)
|
|
{
|
|
bool duplicate = false;
|
|
for (auto& Directory : Directories)
|
|
{
|
|
if (Directory == Entry.physicalName)
|
|
{
|
|
duplicate = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!duplicate)
|
|
Directories.push_back(Entry.physicalName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CFileSearch::XStringVector Extensions;
|
|
|
|
if (SConfig::GetInstance().m_ListGC)
|
|
Extensions.push_back("*.gcm");
|
|
if (SConfig::GetInstance().m_ListWii || SConfig::GetInstance().m_ListGC)
|
|
{
|
|
Extensions.push_back("*.iso");
|
|
Extensions.push_back("*.ciso");
|
|
Extensions.push_back("*.gcz");
|
|
Extensions.push_back("*.wbfs");
|
|
}
|
|
if (SConfig::GetInstance().m_ListWad)
|
|
Extensions.push_back("*.wad");
|
|
|
|
CFileSearch FileSearch(Extensions, Directories);
|
|
const CFileSearch::XStringVector& rFilenames = FileSearch.GetFileNames();
|
|
|
|
if (rFilenames.size() > 0)
|
|
{
|
|
wxProgressDialog dialog(
|
|
_("Scanning for ISOs"),
|
|
_("Scanning..."),
|
|
(int)rFilenames.size() - 1,
|
|
this,
|
|
wxPD_APP_MODAL |
|
|
wxPD_AUTO_HIDE |
|
|
wxPD_CAN_ABORT |
|
|
wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME |
|
|
wxPD_SMOOTH // - makes updates as small as possible (down to 1px)
|
|
);
|
|
|
|
for (u32 i = 0; i < rFilenames.size(); i++)
|
|
{
|
|
std::string FileName;
|
|
SplitPath(rFilenames[i], nullptr, &FileName, nullptr);
|
|
|
|
// Update with the progress (i) and the message
|
|
dialog.Update(i, wxString::Format(_("Scanning %s"),
|
|
StrToWxStr(FileName)));
|
|
if (dialog.WasCancelled())
|
|
break;
|
|
|
|
auto iso_file = std::make_unique<GameListItem>(rFilenames[i]);
|
|
|
|
if (iso_file->IsValid())
|
|
{
|
|
bool list = true;
|
|
|
|
switch(iso_file->GetPlatform())
|
|
{
|
|
case GameListItem::WII_DISC:
|
|
if (!SConfig::GetInstance().m_ListWii)
|
|
list = false;
|
|
break;
|
|
case GameListItem::WII_WAD:
|
|
if (!SConfig::GetInstance().m_ListWad)
|
|
list = false;
|
|
break;
|
|
default:
|
|
if (!SConfig::GetInstance().m_ListGC)
|
|
list = false;
|
|
break;
|
|
}
|
|
|
|
switch(iso_file->GetCountry())
|
|
{
|
|
case DiscIO::IVolume::COUNTRY_TAIWAN:
|
|
if (!SConfig::GetInstance().m_ListTaiwan)
|
|
list = false;
|
|
case DiscIO::IVolume::COUNTRY_KOREA:
|
|
if (!SConfig::GetInstance().m_ListKorea)
|
|
list = false;
|
|
break;
|
|
case DiscIO::IVolume::COUNTRY_JAPAN:
|
|
if (!SConfig::GetInstance().m_ListJap)
|
|
list = false;
|
|
break;
|
|
case DiscIO::IVolume::COUNTRY_USA:
|
|
if (!SConfig::GetInstance().m_ListUsa)
|
|
list = false;
|
|
break;
|
|
case DiscIO::IVolume::COUNTRY_FRANCE:
|
|
if (!SConfig::GetInstance().m_ListFrance)
|
|
list = false;
|
|
break;
|
|
case DiscIO::IVolume::COUNTRY_ITALY:
|
|
if (!SConfig::GetInstance().m_ListItaly)
|
|
list = false;
|
|
break;
|
|
default:
|
|
if (!SConfig::GetInstance().m_ListPal)
|
|
list = false;
|
|
break;
|
|
}
|
|
|
|
if (list)
|
|
m_ISOFiles.push_back(iso_file.release());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SConfig::GetInstance().m_ListDrives)
|
|
{
|
|
const std::vector<std::string> drives = cdio_get_devices();
|
|
|
|
for (const auto& drive : drives)
|
|
{
|
|
auto gli = std::make_unique<GameListItem>(drive);
|
|
|
|
if (gli->IsValid())
|
|
m_ISOFiles.push_back(gli.release());
|
|
}
|
|
}
|
|
|
|
std::sort(m_ISOFiles.begin(), m_ISOFiles.end());
|
|
}
|
|
|
|
void CGameListCtrl::OnColBeginDrag(wxListEvent& event)
|
|
{
|
|
if (event.GetColumn() != COLUMN_TITLE && event.GetColumn() != COLUMN_NOTES)
|
|
event.Veto();
|
|
}
|
|
|
|
const GameListItem *CGameListCtrl::GetISO(size_t index) const
|
|
{
|
|
if (index < m_ISOFiles.size())
|
|
return m_ISOFiles[index];
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
CGameListCtrl *caller;
|
|
#if wxCHECK_VERSION(2, 9, 0)
|
|
int wxCALLBACK wxListCompare(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
|
|
#else // 2.8.x
|
|
int wxCALLBACK wxListCompare(long item1, long item2, long sortData)
|
|
#endif
|
|
{
|
|
// return 1 if item1 > item2
|
|
// return -1 if item1 < item2
|
|
// return 0 for identity
|
|
const GameListItem *iso1 = caller->GetISO(item1);
|
|
const GameListItem *iso2 = caller->GetISO(item2);
|
|
|
|
return CompareGameListItems(iso1, iso2, sortData);
|
|
}
|
|
|
|
void CGameListCtrl::OnColumnClick(wxListEvent& event)
|
|
{
|
|
if (event.GetColumn() != COLUMN_BANNER)
|
|
{
|
|
int current_column = event.GetColumn();
|
|
if (sorted)
|
|
{
|
|
if (last_column == current_column)
|
|
{
|
|
last_sort = -last_sort;
|
|
}
|
|
else
|
|
{
|
|
SConfig::GetInstance().m_ListSort2 = last_sort;
|
|
last_column = current_column;
|
|
last_sort = current_column;
|
|
}
|
|
SConfig::GetInstance().m_ListSort = last_sort;
|
|
}
|
|
else
|
|
{
|
|
last_sort = current_column;
|
|
last_column = current_column;
|
|
}
|
|
caller = this;
|
|
SortItems(wxListCompare, last_sort);
|
|
}
|
|
|
|
SetBackgroundColor();
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
// This is used by keyboard gamelist search
|
|
void CGameListCtrl::OnKeyPress(wxListEvent& event)
|
|
{
|
|
static int lastKey = 0, sLoop = 0;
|
|
int Loop = 0;
|
|
|
|
for (int i = 0; i < (int)m_ISOFiles.size(); i++)
|
|
{
|
|
// Easy way to get game string
|
|
wxListItem bleh;
|
|
bleh.SetId(i);
|
|
bleh.SetColumn(COLUMN_TITLE);
|
|
bleh.SetMask(wxLIST_MASK_TEXT);
|
|
GetItem(bleh);
|
|
|
|
wxString text = bleh.GetText();
|
|
|
|
#ifdef __WXGTK__
|
|
if (text.MakeLower()[0] == event.GetKeyCode())
|
|
#else
|
|
if (text.MakeUpper()[0] == event.GetKeyCode())
|
|
#endif
|
|
{
|
|
if (lastKey == event.GetKeyCode() && Loop < sLoop)
|
|
{
|
|
Loop++;
|
|
if (i+1 == (int)m_ISOFiles.size())
|
|
i = -1;
|
|
continue;
|
|
}
|
|
else if (lastKey != event.GetKeyCode())
|
|
{
|
|
sLoop = 0;
|
|
}
|
|
|
|
lastKey = event.GetKeyCode();
|
|
sLoop++;
|
|
|
|
UnselectAll();
|
|
SetItemState(i, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED,
|
|
wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
|
|
EnsureVisible(i);
|
|
break;
|
|
}
|
|
|
|
// If we get past the last game in the list,
|
|
// we'll have to go back to the first one.
|
|
if (i+1 == (int)m_ISOFiles.size() && sLoop > 0 && Loop > 0)
|
|
i = -1;
|
|
}
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
// This shows a little tooltip with the current Game's emulation state
|
|
void CGameListCtrl::OnMouseMotion(wxMouseEvent& event)
|
|
{
|
|
int flags;
|
|
long subitem = 0;
|
|
const long item = HitTest(event.GetPosition(), flags, &subitem);
|
|
static int lastItem = -1;
|
|
|
|
if (GetColumnCount() <= 1)
|
|
return;
|
|
|
|
if (item != wxNOT_FOUND)
|
|
{
|
|
wxRect Rect;
|
|
#ifdef __WXMSW__
|
|
if (subitem == COLUMN_EMULATION_STATE)
|
|
#else
|
|
// The subitem parameter of HitTest is only implemented for wxMSW. On
|
|
// all other platforms it will always be -1. Check the x position
|
|
// instead.
|
|
GetItemRect(item, Rect);
|
|
if (Rect.GetX() + Rect.GetWidth() - GetColumnWidth(COLUMN_EMULATION_STATE) < event.GetX())
|
|
#endif
|
|
{
|
|
if (toolTip || lastItem == item || this != FindFocus())
|
|
{
|
|
if (lastItem != item) lastItem = -1;
|
|
event.Skip();
|
|
return;
|
|
}
|
|
|
|
// Emulation status
|
|
static const char* const emuState[] = { "Broken", "Intro", "In-Game", "Playable", "Perfect" };
|
|
|
|
const GameListItem& rISO = *m_ISOFiles[GetItemData(item)];
|
|
|
|
const int emu_state = rISO.GetEmuState();
|
|
const std::string& issues = rISO.GetIssues();
|
|
|
|
// Show a tooltip containing the EmuState and the state description
|
|
if (emu_state > 0 && emu_state < 6)
|
|
{
|
|
char temp[2048];
|
|
sprintf(temp, "^ %s%s%s", emuState[emu_state - 1],
|
|
issues.size() > 0 ? " :\n" : "", issues.c_str());
|
|
toolTip = new wxEmuStateTip(this, StrToWxStr(temp), &toolTip);
|
|
}
|
|
else
|
|
{
|
|
toolTip = new wxEmuStateTip(this, _("Not Set"), &toolTip);
|
|
}
|
|
|
|
// Get item Coords
|
|
GetItemRect(item, Rect);
|
|
int mx = Rect.GetWidth();
|
|
int my = Rect.GetY();
|
|
#ifndef __WXMSW__
|
|
// For some reason the y position does not account for the header
|
|
// row, so subtract the y position of the first visible item.
|
|
GetItemRect(GetTopItem(), Rect);
|
|
my -= Rect.GetY();
|
|
#endif
|
|
// Convert to screen coordinates
|
|
ClientToScreen(&mx, &my);
|
|
toolTip->SetBoundingRect(wxRect(mx - GetColumnWidth(COLUMN_EMULATION_STATE),
|
|
my, GetColumnWidth(COLUMN_EMULATION_STATE), Rect.GetHeight()));
|
|
toolTip->SetPosition(wxPoint(mx - GetColumnWidth(COLUMN_EMULATION_STATE),
|
|
my - 5 + Rect.GetHeight()));
|
|
lastItem = item;
|
|
}
|
|
}
|
|
if (!toolTip)
|
|
lastItem = -1;
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
void CGameListCtrl::OnLeftClick(wxMouseEvent& event)
|
|
{
|
|
// Focus the clicked item.
|
|
int flags;
|
|
long item = HitTest(event.GetPosition(), flags);
|
|
if ((item != wxNOT_FOUND) && (GetSelectedItemCount() == 0) &&
|
|
(!event.ControlDown()) && (!event.ShiftDown()))
|
|
{
|
|
SetItemState(item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
|
|
SetItemState(item, wxLIST_STATE_FOCUSED, wxLIST_STATE_FOCUSED);
|
|
wxGetApp().GetCFrame()->UpdateGUI();
|
|
}
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
void CGameListCtrl::OnRightClick(wxMouseEvent& event)
|
|
{
|
|
// Focus the clicked item.
|
|
int flags;
|
|
long item = HitTest(event.GetPosition(), flags);
|
|
if (item != wxNOT_FOUND)
|
|
{
|
|
if (GetItemState(item, wxLIST_STATE_SELECTED) != wxLIST_STATE_SELECTED)
|
|
{
|
|
UnselectAll();
|
|
SetItemState(item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
|
|
}
|
|
SetItemState(item, wxLIST_STATE_FOCUSED, wxLIST_STATE_FOCUSED);
|
|
}
|
|
if (GetSelectedItemCount() == 1)
|
|
{
|
|
const GameListItem *selected_iso = GetSelectedISO();
|
|
if (selected_iso)
|
|
{
|
|
wxMenu* popupMenu = new wxMenu;
|
|
popupMenu->Append(IDM_PROPERTIES, _("&Properties"));
|
|
popupMenu->Append(IDM_GAMEWIKI, _("&Wiki"));
|
|
popupMenu->AppendSeparator();
|
|
|
|
if (selected_iso->GetPlatform() != GameListItem::GAMECUBE_DISC)
|
|
{
|
|
popupMenu->Append(IDM_OPENSAVEFOLDER, _("Open Wii &save folder"));
|
|
popupMenu->Append(IDM_EXPORTSAVE, _("Export Wii save (Experimental)"));
|
|
}
|
|
popupMenu->Append(IDM_OPENCONTAININGFOLDER, _("Open &containing folder"));
|
|
popupMenu->AppendCheckItem(IDM_SETDEFAULTGCM, _("Set as &default ISO"));
|
|
|
|
// First we have to decide a starting value when we append it
|
|
if (selected_iso->GetFileName() == SConfig::GetInstance().
|
|
m_LocalCoreStartupParameter.m_strDefaultGCM)
|
|
popupMenu->FindItem(IDM_SETDEFAULTGCM)->Check();
|
|
|
|
popupMenu->AppendSeparator();
|
|
popupMenu->Append(IDM_DELETEGCM, _("&Delete ISO..."));
|
|
|
|
if (selected_iso->GetPlatform() != GameListItem::WII_WAD)
|
|
{
|
|
if (selected_iso->IsCompressed())
|
|
popupMenu->Append(IDM_COMPRESSGCM, _("Decompress ISO..."));
|
|
else if (selected_iso->GetFileName().substr(selected_iso->GetFileName().find_last_of(".")) != ".ciso" &&
|
|
selected_iso->GetFileName().substr(selected_iso->GetFileName().find_last_of(".")) != ".wbfs")
|
|
popupMenu->Append(IDM_COMPRESSGCM, _("Compress ISO..."));
|
|
}
|
|
else
|
|
{
|
|
popupMenu->Append(IDM_LIST_INSTALLWAD, _("Install to Wii Menu"));
|
|
}
|
|
|
|
PopupMenu(popupMenu);
|
|
}
|
|
}
|
|
else if (GetSelectedItemCount() > 1)
|
|
{
|
|
wxMenu* popupMenu = new wxMenu;
|
|
popupMenu->Append(IDM_DELETEGCM, _("&Delete selected ISOs..."));
|
|
popupMenu->AppendSeparator();
|
|
popupMenu->Append(IDM_MULTICOMPRESSGCM, _("Compress selected ISOs..."));
|
|
popupMenu->Append(IDM_MULTIDECOMPRESSGCM, _("Decompress selected ISOs..."));
|
|
PopupMenu(popupMenu);
|
|
}
|
|
}
|
|
|
|
const GameListItem * CGameListCtrl::GetSelectedISO()
|
|
{
|
|
if (m_ISOFiles.size() == 0)
|
|
{
|
|
return nullptr;
|
|
}
|
|
else if (GetSelectedItemCount() == 0)
|
|
{
|
|
return nullptr;
|
|
}
|
|
else
|
|
{
|
|
long item = GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
|
if (item == wxNOT_FOUND)
|
|
{
|
|
return nullptr;
|
|
}
|
|
else
|
|
{
|
|
// Here is a little workaround for multiselections:
|
|
// when > 1 item is selected, return info on the first one
|
|
// and deselect it so the next time GetSelectedISO() is called,
|
|
// the next item's info is returned
|
|
if (GetSelectedItemCount() > 1)
|
|
SetItemState(item, 0, wxLIST_STATE_SELECTED);
|
|
|
|
return m_ISOFiles[GetItemData(item)];
|
|
}
|
|
}
|
|
}
|
|
|
|
void CGameListCtrl::OnOpenContainingFolder(wxCommandEvent& WXUNUSED (event))
|
|
{
|
|
const GameListItem *iso = GetSelectedISO();
|
|
if (!iso)
|
|
return;
|
|
|
|
wxFileName path = wxFileName::FileName(StrToWxStr(iso->GetFileName()));
|
|
path.MakeAbsolute();
|
|
WxUtils::Explore(WxStrToStr(path.GetPath()));
|
|
}
|
|
|
|
void CGameListCtrl::OnOpenSaveFolder(wxCommandEvent& WXUNUSED (event))
|
|
{
|
|
const GameListItem *iso = GetSelectedISO();
|
|
if (!iso)
|
|
return;
|
|
std::string path = iso->GetWiiFSPath();
|
|
if (!path.empty())
|
|
WxUtils::Explore(path);
|
|
}
|
|
|
|
void CGameListCtrl::OnExportSave(wxCommandEvent& WXUNUSED (event))
|
|
{
|
|
const GameListItem *iso = GetSelectedISO();
|
|
if (!iso)
|
|
return;
|
|
u64 title;
|
|
DiscIO::IVolume *Iso = DiscIO::CreateVolumeFromFilename(iso->GetFileName());
|
|
if (Iso)
|
|
{
|
|
if (Iso->GetTitleID((u8*)&title))
|
|
{
|
|
title = Common::swap64(title);
|
|
CWiiSaveCrypted::ExportWiiSave(title);
|
|
}
|
|
delete Iso;
|
|
}
|
|
}
|
|
|
|
// Save this file as the default file
|
|
void CGameListCtrl::OnSetDefaultGCM(wxCommandEvent& event)
|
|
{
|
|
const GameListItem *iso = GetSelectedISO();
|
|
if (!iso) return;
|
|
|
|
if (event.IsChecked())
|
|
{
|
|
// Write the new default value and save it the ini file
|
|
SConfig::GetInstance().m_LocalCoreStartupParameter.m_strDefaultGCM =
|
|
iso->GetFileName();
|
|
SConfig::GetInstance().SaveSettings();
|
|
}
|
|
else
|
|
{
|
|
// Otherwise blank the value and save it
|
|
SConfig::GetInstance().m_LocalCoreStartupParameter.m_strDefaultGCM = "";
|
|
SConfig::GetInstance().SaveSettings();
|
|
}
|
|
}
|
|
|
|
void CGameListCtrl::OnDeleteGCM(wxCommandEvent& WXUNUSED (event))
|
|
{
|
|
if (GetSelectedItemCount() == 1)
|
|
{
|
|
const GameListItem *iso = GetSelectedISO();
|
|
if (!iso)
|
|
return;
|
|
if (wxMessageBox(_("Are you sure you want to delete this file? It will be gone forever!"),
|
|
wxMessageBoxCaptionStr, wxYES_NO | wxICON_EXCLAMATION) == wxYES)
|
|
{
|
|
File::Delete(iso->GetFileName());
|
|
Update();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (wxMessageBox(_("Are you sure you want to delete these files?\nThey will be gone forever!"),
|
|
wxMessageBoxCaptionStr, wxYES_NO | wxICON_EXCLAMATION) == wxYES)
|
|
{
|
|
int selected = GetSelectedItemCount();
|
|
|
|
for (int i = 0; i < selected; i++)
|
|
{
|
|
const GameListItem *iso = GetSelectedISO();
|
|
File::Delete(iso->GetFileName());
|
|
}
|
|
Update();
|
|
}
|
|
}
|
|
}
|
|
|
|
void CGameListCtrl::OnProperties(wxCommandEvent& WXUNUSED (event))
|
|
{
|
|
const GameListItem *iso = GetSelectedISO();
|
|
if (!iso)
|
|
return;
|
|
|
|
CISOProperties ISOProperties(iso->GetFileName(), this);
|
|
if (ISOProperties.ShowModal() == wxID_OK)
|
|
Update();
|
|
}
|
|
|
|
void CGameListCtrl::OnWiki(wxCommandEvent& WXUNUSED (event))
|
|
{
|
|
const GameListItem *iso = GetSelectedISO();
|
|
if (!iso)
|
|
return;
|
|
|
|
std::string wikiUrl = "http://wiki.dolphin-emu.org/dolphin-redirect.php?gameid=[GAME_ID]";
|
|
wikiUrl = ReplaceAll(wikiUrl, "[GAME_ID]", UriEncode(iso->GetUniqueID()));
|
|
if (UriEncode(iso->GetName(0)).length() < 100)
|
|
wikiUrl = ReplaceAll(wikiUrl, "[GAME_NAME]", UriEncode(iso->GetName(0)));
|
|
else
|
|
wikiUrl = ReplaceAll(wikiUrl, "[GAME_NAME]", "");
|
|
|
|
WxUtils::Launch(wikiUrl);
|
|
}
|
|
|
|
void CGameListCtrl::MultiCompressCB(const char* text, float percent, void* arg)
|
|
{
|
|
percent = (((float)m_currentItem) + percent) / (float)m_numberItem;
|
|
wxString textString(StrToWxStr(StringFromFormat("%s (%i/%i) - %s",
|
|
m_currentFilename.c_str(), (int)m_currentItem+1,
|
|
(int)m_numberItem, text)));
|
|
|
|
((wxProgressDialog*)arg)->Update((int)(percent*1000), textString);
|
|
}
|
|
|
|
void CGameListCtrl::OnMultiCompressGCM(wxCommandEvent& /*event*/)
|
|
{
|
|
CompressSelection(true);
|
|
}
|
|
|
|
void CGameListCtrl::OnMultiDecompressGCM(wxCommandEvent& /*event*/)
|
|
{
|
|
CompressSelection(false);
|
|
}
|
|
|
|
void CGameListCtrl::CompressSelection(bool _compress)
|
|
{
|
|
wxString dirHome;
|
|
wxGetHomeDir(&dirHome);
|
|
|
|
wxDirDialog browseDialog(this, _("Browse for output directory"), dirHome,
|
|
wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
|
|
if (browseDialog.ShowModal() != wxID_OK)
|
|
return;
|
|
|
|
bool all_good = true;
|
|
|
|
{
|
|
wxProgressDialog progressDialog(
|
|
_compress ? _("Compressing ISO") : _("Decompressing ISO"),
|
|
_("Working..."),
|
|
1000,
|
|
this,
|
|
wxPD_APP_MODAL |
|
|
wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME |
|
|
wxPD_SMOOTH
|
|
);
|
|
|
|
m_currentItem = 0;
|
|
m_numberItem = GetSelectedItemCount();
|
|
for (u32 i=0; i < m_numberItem; i++)
|
|
{
|
|
const GameListItem *iso = GetSelectedISO();
|
|
|
|
if (!iso->IsCompressed() && _compress)
|
|
{
|
|
std::string FileName, FileExt;
|
|
SplitPath(iso->GetFileName(), nullptr, &FileName, &FileExt);
|
|
m_currentFilename = FileName;
|
|
FileName.append(".gcz");
|
|
|
|
std::string OutputFileName;
|
|
BuildCompleteFilename(OutputFileName,
|
|
WxStrToStr(browseDialog.GetPath()),
|
|
FileName);
|
|
|
|
if (wxFileExists(StrToWxStr(OutputFileName)) &&
|
|
wxMessageBox(
|
|
wxString::Format(_("The file %s already exists.\nDo you wish to replace it?"),
|
|
StrToWxStr(OutputFileName)),
|
|
_("Confirm File Overwrite"),
|
|
wxYES_NO) == wxNO)
|
|
continue;
|
|
|
|
all_good &= DiscIO::CompressFileToBlob(iso->GetFileName(),
|
|
OutputFileName,
|
|
(iso->GetPlatform() == GameListItem::WII_DISC) ? 1 : 0,
|
|
16384, &MultiCompressCB, &progressDialog);
|
|
}
|
|
else if (iso->IsCompressed() && !_compress)
|
|
{
|
|
std::string FileName, FileExt;
|
|
SplitPath(iso->GetFileName(), nullptr, &FileName, &FileExt);
|
|
m_currentFilename = FileName;
|
|
if (iso->GetPlatform() == GameListItem::WII_DISC)
|
|
FileName.append(".iso");
|
|
else
|
|
FileName.append(".gcm");
|
|
|
|
std::string OutputFileName;
|
|
BuildCompleteFilename(OutputFileName,
|
|
WxStrToStr(browseDialog.GetPath()),
|
|
FileName);
|
|
|
|
if (wxFileExists(StrToWxStr(OutputFileName)) &&
|
|
wxMessageBox(
|
|
wxString::Format(_("The file %s already exists.\nDo you wish to replace it?"),
|
|
StrToWxStr(OutputFileName)),
|
|
_("Confirm File Overwrite"),
|
|
wxYES_NO) == wxNO)
|
|
continue;
|
|
|
|
all_good &= DiscIO::DecompressBlobToFile(iso->GetFileName().c_str(),
|
|
OutputFileName.c_str(), &MultiCompressCB, &progressDialog);
|
|
}
|
|
m_currentItem++;
|
|
}
|
|
}
|
|
|
|
if (!all_good)
|
|
wxMessageBox(_("Dolphin was unable to complete the requested action."));
|
|
|
|
Update();
|
|
}
|
|
|
|
void CGameListCtrl::CompressCB(const char* text, float percent, void* arg)
|
|
{
|
|
((wxProgressDialog*)arg)->
|
|
Update((int)(percent*1000), StrToWxStr(text));
|
|
}
|
|
|
|
void CGameListCtrl::OnCompressGCM(wxCommandEvent& WXUNUSED (event))
|
|
{
|
|
const GameListItem *iso = GetSelectedISO();
|
|
if (!iso)
|
|
return;
|
|
|
|
wxString path;
|
|
|
|
std::string FileName, FilePath, FileExtension;
|
|
SplitPath(iso->GetFileName(), &FilePath, &FileName, &FileExtension);
|
|
|
|
do
|
|
{
|
|
if (iso->IsCompressed())
|
|
{
|
|
wxString FileType;
|
|
if (iso->GetPlatform() == GameListItem::WII_DISC)
|
|
FileType = _("All Wii ISO files (iso)") + "|*.iso";
|
|
else
|
|
FileType = _("All Gamecube GCM files (gcm)") + "|*.gcm";
|
|
|
|
path = wxFileSelector(
|
|
_("Save decompressed GCM/ISO"),
|
|
StrToWxStr(FilePath),
|
|
StrToWxStr(FileName) + FileType.After('*'),
|
|
wxEmptyString,
|
|
FileType + "|" + wxGetTranslation(wxALL_FILES),
|
|
wxFD_SAVE,
|
|
this);
|
|
}
|
|
else
|
|
{
|
|
path = wxFileSelector(
|
|
_("Save compressed GCM/ISO"),
|
|
StrToWxStr(FilePath),
|
|
StrToWxStr(FileName) + ".gcz",
|
|
wxEmptyString,
|
|
_("All compressed GC/Wii ISO files (gcz)") +
|
|
wxString::Format("|*.gcz|%s", wxGetTranslation(wxALL_FILES)),
|
|
wxFD_SAVE,
|
|
this);
|
|
}
|
|
if (!path)
|
|
return;
|
|
} while (wxFileExists(path) &&
|
|
wxMessageBox(
|
|
wxString::Format(_("The file %s already exists.\nDo you wish to replace it?"), path.c_str()),
|
|
_("Confirm File Overwrite"),
|
|
wxYES_NO) == wxNO);
|
|
|
|
bool all_good = false;
|
|
|
|
{
|
|
wxProgressDialog dialog(
|
|
iso->IsCompressed() ? _("Decompressing ISO") : _("Compressing ISO"),
|
|
_("Working..."),
|
|
1000,
|
|
this,
|
|
wxPD_APP_MODAL |
|
|
wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME |
|
|
wxPD_SMOOTH
|
|
);
|
|
|
|
|
|
if (iso->IsCompressed())
|
|
all_good = DiscIO::DecompressBlobToFile(iso->GetFileName(),
|
|
WxStrToStr(path), &CompressCB, &dialog);
|
|
else
|
|
all_good = DiscIO::CompressFileToBlob(iso->GetFileName(),
|
|
WxStrToStr(path),
|
|
(iso->GetPlatform() == GameListItem::WII_DISC) ? 1 : 0,
|
|
16384, &CompressCB, &dialog);
|
|
}
|
|
|
|
if (!all_good)
|
|
wxMessageBox(_("Dolphin was unable to complete the requested action."));
|
|
|
|
Update();
|
|
}
|
|
|
|
void CGameListCtrl::OnSize(wxSizeEvent& event)
|
|
{
|
|
if (lastpos == event.GetSize())
|
|
return;
|
|
|
|
lastpos = event.GetSize();
|
|
AutomaticColumnWidth();
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
void CGameListCtrl::AutomaticColumnWidth()
|
|
{
|
|
wxRect rc(GetClientRect());
|
|
|
|
if (GetColumnCount() == 1)
|
|
{
|
|
SetColumnWidth(0, rc.GetWidth());
|
|
}
|
|
else if (GetColumnCount() > 4)
|
|
{
|
|
int resizable = rc.GetWidth() - (
|
|
GetColumnWidth(COLUMN_BANNER)
|
|
+ GetColumnWidth(COLUMN_COUNTRY)
|
|
+ GetColumnWidth(COLUMN_SIZE)
|
|
+ GetColumnWidth(COLUMN_EMULATION_STATE)
|
|
+ GetColumnWidth(COLUMN_PLATFORM));
|
|
|
|
// We hide the Notes column if the window is too small
|
|
if (resizable > 400)
|
|
{
|
|
SetColumnWidth(COLUMN_TITLE, resizable / 2);
|
|
SetColumnWidth(COLUMN_NOTES, resizable / 2);
|
|
}
|
|
else
|
|
{
|
|
SetColumnWidth(COLUMN_TITLE, resizable);
|
|
SetColumnWidth(COLUMN_NOTES, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CGameListCtrl::UnselectAll()
|
|
{
|
|
for (int i=0; i<GetItemCount(); i++)
|
|
{
|
|
SetItemState(i, 0, wxLIST_STATE_SELECTED);
|
|
}
|
|
}
|
|
|
|
void CGameListCtrl::OnDropFiles(wxDropFilesEvent& event)
|
|
{
|
|
if (event.GetNumberOfFiles() != 1)
|
|
return;
|
|
if (File::IsDirectory(WxStrToStr(event.GetFiles()[0])))
|
|
return;
|
|
|
|
wxFileName file = event.GetFiles()[0];
|
|
|
|
if (file.GetExt() == "dtm")
|
|
{
|
|
if (Core::IsRunning())
|
|
return;
|
|
|
|
if (!Movie::IsReadOnly())
|
|
{
|
|
// let's make the read-only flag consistent at the start of a movie.
|
|
Movie::SetReadOnly(true);
|
|
main_frame->GetMenuBar()->FindItem(IDM_RECORDREADONLY)->Check(true);
|
|
}
|
|
|
|
if (Movie::PlayInput(WxStrToStr(file.GetFullPath())))
|
|
main_frame->BootGame("");
|
|
}
|
|
else if (!Core::IsRunning())
|
|
{
|
|
main_frame->BootGame(WxStrToStr(file.GetFullPath()));
|
|
}
|
|
else
|
|
{
|
|
DVDInterface::ChangeDisc(WxStrToStr(file.GetFullPath()));
|
|
}
|
|
}
|