1 // Copyright (C) 2003 Dolphin Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official SVN repository and contact information can be found at
16 // http://code.google.com/p/dolphin-emu/
20 #include <wx/imaglist.h>
21 #include <wx/fontmap.h>
25 #include "FileSearch.h"
26 #include "StringUtil.h"
27 #include "ConfigManager.h"
28 #include "GameListCtrl.h"
31 #include "ISOProperties.h"
39 #include "../resources/Flag_Europe.xpm"
40 #include "../resources/Flag_France.xpm"
41 #include "../resources/Flag_Italy.xpm"
42 #include "../resources/Flag_Japan.xpm"
43 #include "../resources/Flag_USA.xpm"
44 #include "../resources/Flag_Taiwan.xpm"
45 #include "../resources/Flag_Korea.xpm"
46 #include "../resources/Flag_Unknown.xpm"
48 #include "../resources/Platform_Wad.xpm"
49 #include "../resources/Platform_Wii.xpm"
50 #include "../resources/Platform_Gamecube.xpm"
52 #include "../resources/rating_gamelist.h"
53 #endif // USE_XPM_BITMAPS
55 size_t CGameListCtrl::m_currentItem
= 0;
56 size_t CGameListCtrl::m_numberItem
= 0;
57 std::string
CGameListCtrl::m_currentFilename
;
59 static int currentColumn
= 0;
60 bool operator < (const GameListItem
&one
, const GameListItem
&other
)
65 switch (one
.GetCountry())
67 case DiscIO::IVolume::COUNTRY_JAPAN
:;
68 case DiscIO::IVolume::COUNTRY_USA
:indexOne
= 0; break;
69 default: indexOne
= (int)SConfig::GetInstance().m_InterfaceLanguage
;
72 switch (other
.GetCountry())
74 case DiscIO::IVolume::COUNTRY_JAPAN
:;
75 case DiscIO::IVolume::COUNTRY_USA
:indexOther
= 0; break;
76 default: indexOther
= (int)SConfig::GetInstance().m_InterfaceLanguage
;
81 case CGameListCtrl::COLUMN_TITLE
: return strcasecmp(one
.GetName(indexOne
).c_str(), other
.GetName(indexOther
).c_str()) < 0;
82 case CGameListCtrl::COLUMN_NOTES
:
84 // On Gamecube we show the company string, while it's empty on other platforms, so we show the description instead
85 std::string cmp1
= (one
.GetPlatform() == GameListItem::GAMECUBE_DISC
) ? one
.GetCompany() : one
.GetDescription(indexOne
);
86 std::string cmp2
= (other
.GetPlatform() == GameListItem::GAMECUBE_DISC
) ? other
.GetCompany() : other
.GetDescription(indexOther
);
87 return strcasecmp(cmp1
.c_str(), cmp2
.c_str()) < 0;
89 case CGameListCtrl::COLUMN_COUNTRY
: return (one
.GetCountry() < other
.GetCountry());
90 case CGameListCtrl::COLUMN_SIZE
: return (one
.GetFileSize() < other
.GetFileSize());
91 case CGameListCtrl::COLUMN_PLATFORM
: return (one
.GetPlatform() < other
.GetPlatform());
92 default: return strcasecmp(one
.GetName(indexOne
).c_str(), other
.GetName(indexOther
).c_str()) < 0;
97 BEGIN_EVENT_TABLE(wxEmuStateTip
, wxTipWindow
)
98 EVT_KEY_DOWN(wxEmuStateTip::OnKeyDown
)
101 BEGIN_EVENT_TABLE(CGameListCtrl
, wxListCtrl
)
103 EVT_PAINT(CGameListCtrl::OnPaintDrawImages
)
105 EVT_SIZE(CGameListCtrl::OnSize
)
106 EVT_RIGHT_DOWN(CGameListCtrl::OnRightClick
)
107 EVT_LEFT_DOWN(CGameListCtrl::OnLeftClick
)
108 EVT_LIST_KEY_DOWN(LIST_CTRL
, CGameListCtrl::OnKeyPress
)
109 EVT_MOTION(CGameListCtrl::OnMouseMotion
)
110 EVT_LIST_COL_BEGIN_DRAG(LIST_CTRL
, CGameListCtrl::OnColBeginDrag
)
111 EVT_LIST_COL_CLICK(LIST_CTRL
, CGameListCtrl::OnColumnClick
)
112 EVT_MENU(IDM_PROPERTIES
, CGameListCtrl::OnProperties
)
113 EVT_MENU(IDM_OPENCONTAININGFOLDER
, CGameListCtrl::OnOpenContainingFolder
)
114 EVT_MENU(IDM_OPENSAVEFOLDER
, CGameListCtrl::OnOpenSaveFolder
)
115 EVT_MENU(IDM_EXPORTSAVE
, CGameListCtrl::OnExportSave
)
116 EVT_MENU(IDM_SETDEFAULTGCM
, CGameListCtrl::OnSetDefaultGCM
)
117 EVT_MENU(IDM_COMPRESSGCM
, CGameListCtrl::OnCompressGCM
)
118 EVT_MENU(IDM_MULTICOMPRESSGCM
, CGameListCtrl::OnMultiCompressGCM
)
119 EVT_MENU(IDM_MULTIDECOMPRESSGCM
, CGameListCtrl::OnMultiDecompressGCM
)
120 EVT_MENU(IDM_DELETEGCM
, CGameListCtrl::OnDeleteGCM
)
121 EVT_MENU(IDM_INSTALLWAD
, CGameListCtrl::OnInstallWAD
)
125 CGameListCtrl::CGameListCtrl(wxWindow
* parent
, const wxWindowID id
, const wxPoint
& pos
, const wxSize
& size
, long style
)
126 : wxListCtrl(parent
, id
, pos
, size
, style
), toolTip(0)
130 CGameListCtrl::~CGameListCtrl()
132 if (m_imageListSmall
)
133 delete m_imageListSmall
;
136 void CGameListCtrl::InitBitmaps()
138 m_imageListSmall
= new wxImageList(96, 32);
139 SetImageList(m_imageListSmall
, wxIMAGE_LIST_SMALL
);
142 m_FlagImageIndex
.resize(DiscIO::IVolume::NUMBER_OF_COUNTRIES
);
143 iconTemp
.CopyFromBitmap(wxBitmap(Flag_Europe_xpm
));
144 m_FlagImageIndex
[DiscIO::IVolume::COUNTRY_EUROPE
] = m_imageListSmall
->Add(iconTemp
);
145 iconTemp
.CopyFromBitmap(wxBitmap(Flag_France_xpm
));
146 m_FlagImageIndex
[DiscIO::IVolume::COUNTRY_FRANCE
] = m_imageListSmall
->Add(iconTemp
);
147 iconTemp
.CopyFromBitmap(wxBitmap(Flag_USA_xpm
));
148 m_FlagImageIndex
[DiscIO::IVolume::COUNTRY_USA
] = m_imageListSmall
->Add(iconTemp
);
149 iconTemp
.CopyFromBitmap(wxBitmap(Flag_Japan_xpm
));
150 m_FlagImageIndex
[DiscIO::IVolume::COUNTRY_JAPAN
] = m_imageListSmall
->Add(iconTemp
);
151 iconTemp
.CopyFromBitmap(wxBitmap(Flag_Korea_xpm
));
152 m_FlagImageIndex
[DiscIO::IVolume::COUNTRY_KOREA
] = m_imageListSmall
->Add(iconTemp
);
153 iconTemp
.CopyFromBitmap(wxBitmap(Flag_Italy_xpm
));
154 m_FlagImageIndex
[DiscIO::IVolume::COUNTRY_ITALY
] = m_imageListSmall
->Add(iconTemp
);
155 iconTemp
.CopyFromBitmap(wxBitmap(Flag_Taiwan_xpm
));
156 m_FlagImageIndex
[DiscIO::IVolume::COUNTRY_TAIWAN
] = m_imageListSmall
->Add(iconTemp
);
157 iconTemp
.CopyFromBitmap(wxBitmap(Flag_Unknown_xpm
));
158 m_FlagImageIndex
[DiscIO::IVolume::COUNTRY_SDK
] = m_imageListSmall
->Add(iconTemp
);
159 iconTemp
.CopyFromBitmap(wxBitmap(Flag_Unknown_xpm
));
160 m_FlagImageIndex
[DiscIO::IVolume::COUNTRY_UNKNOWN
] = m_imageListSmall
->Add(iconTemp
);
162 m_PlatformImageIndex
.resize(3);
163 iconTemp
.CopyFromBitmap(wxBitmap(Platform_Gamecube_xpm
));
164 m_PlatformImageIndex
[0] = m_imageListSmall
->Add(iconTemp
);
165 iconTemp
.CopyFromBitmap(wxBitmap(Platform_Wii_xpm
));
166 m_PlatformImageIndex
[1] = m_imageListSmall
->Add(iconTemp
);
167 iconTemp
.CopyFromBitmap(wxBitmap(Platform_Wad_xpm
));
168 m_PlatformImageIndex
[2] = m_imageListSmall
->Add(iconTemp
);
170 m_EmuStateImageIndex
.resize(6);
171 iconTemp
.CopyFromBitmap(wxBitmap(rating_0
));
172 m_EmuStateImageIndex
[0] = m_imageListSmall
->Add(iconTemp
);
173 iconTemp
.CopyFromBitmap(wxBitmap(rating_1
));
174 m_EmuStateImageIndex
[1] = m_imageListSmall
->Add(iconTemp
);
175 iconTemp
.CopyFromBitmap(wxBitmap(rating_2
));
176 m_EmuStateImageIndex
[2] = m_imageListSmall
->Add(iconTemp
);
177 iconTemp
.CopyFromBitmap(wxBitmap(rating_3
));
178 m_EmuStateImageIndex
[3] = m_imageListSmall
->Add(iconTemp
);
179 iconTemp
.CopyFromBitmap(wxBitmap(rating_4
));
180 m_EmuStateImageIndex
[4] = m_imageListSmall
->Add(iconTemp
);
181 iconTemp
.CopyFromBitmap(wxBitmap(rating_5
));
182 m_EmuStateImageIndex
[5] = m_imageListSmall
->Add(iconTemp
);
185 void CGameListCtrl::BrowseForDirectory()
188 wxGetHomeDir(&dirHome
);
191 wxDirDialog
dialog(this, _("Browse for a directory to add"), dirHome
, wxDD_DEFAULT_STYLE
| wxDD_DIR_MUST_EXIST
);
193 if (dialog
.ShowModal() == wxID_OK
)
195 std::string
sPath(dialog
.GetPath().mb_str());
196 std::vector
<std::string
>::iterator itResult
= std::find(
197 SConfig::GetInstance().m_ISOFolder
.begin(), SConfig::GetInstance().m_ISOFolder
.end(), sPath
200 if (itResult
== SConfig::GetInstance().m_ISOFolder
.end())
202 SConfig::GetInstance().m_ISOFolder
.push_back(sPath
);
203 SConfig::GetInstance().SaveSettings();
210 void CGameListCtrl::Update()
212 // Don't let the user refresh it while a game is running
213 if (Core::GetState() != Core::CORE_UNINITIALIZED
)
216 if (m_imageListSmall
)
218 delete m_imageListSmall
;
219 m_imageListSmall
= NULL
;
222 // NetPlay : Set/Reset the GameList string
232 if (m_ISOFiles
.size() != 0)
234 // Don't load bitmaps unless there are games to list
238 InsertColumn(COLUMN_PLATFORM
, _(""));
239 InsertColumn(COLUMN_BANNER
, _("Banner"));
240 InsertColumn(COLUMN_TITLE
, _("Title"));
242 // Instead of showing the notes + the company, which is unknown with wii titles
243 // We show in the same column : company for GC games and description for wii/wad games
244 InsertColumn(COLUMN_NOTES
, _("Notes"));
245 InsertColumn(COLUMN_COUNTRY
, _(""));
246 InsertColumn(COLUMN_SIZE
, _("Size"));
247 InsertColumn(COLUMN_EMULATION_STATE
, _("State"));
250 // set initial sizes for columns
251 SetColumnWidth(COLUMN_PLATFORM
, 35);
252 SetColumnWidth(COLUMN_BANNER
, 96);
253 SetColumnWidth(COLUMN_TITLE
, 200);
254 SetColumnWidth(COLUMN_NOTES
, 200);
255 SetColumnWidth(COLUMN_COUNTRY
, 32);
256 SetColumnWidth(COLUMN_EMULATION_STATE
, 50);
259 for (int i
= 0; i
< (int)m_ISOFiles
.size(); i
++)
261 InsertItemInReportView(i
);
262 if (m_ISOFiles
[i
].IsCompressed())
263 SetItemTextColour(i
, wxColour(0xFF0000));
266 // Sort items by Title
268 event
.m_col
= COLUMN_TITLE
; last_column
= 0;
269 OnColumnClick(event
);
271 SetColumnWidth(COLUMN_SIZE
, wxLIST_AUTOSIZE
);
275 wxString errorString
;
276 // We just check for one hide setting to be enabled, as we may only have GC games
277 // for example, and hide them, so we should show the second message instead
278 if ((SConfig::GetInstance().m_ListGC
&&
279 SConfig::GetInstance().m_ListWii
&&
280 SConfig::GetInstance().m_ListWad
) &&
281 (SConfig::GetInstance().m_ListJap
&&
282 SConfig::GetInstance().m_ListUsa
&&
283 SConfig::GetInstance().m_ListPal
))
285 errorString
= _("Dolphin could not find any GC/Wii ISOs. Doubleclick here to browse for files...");
289 errorString
= _("Dolphin is currently set to hide all games. Doubleclick here to show all games...");
291 InsertColumn(0, _("No ISOs or WADS found"));
292 long index
= InsertItem(0, errorString
);
293 SetItemFont(index
, *wxITALIC_FONT
);
294 SetColumnWidth(0, wxLIST_AUTOSIZE
);
299 AutomaticColumnWidth();
302 wxString
NiceSizeFormat(s64 _size
)
304 const char* sizes
[] = {"b", "KB", "MB", "GB", "TB", "PB", "EB"};
308 while (_size
> (s64
)1024)
311 frac
= (int)_size
& 1023;
315 float f
= (float)_size
+ ((float)frac
/ 1024.0f
);
319 sprintf(tempstr
,"%3.1f %s", f
, sizes
[s
]);
320 NiceString
= wxString::FromAscii(tempstr
);
324 std::string
CGameListCtrl::GetGamePaths() const
328 std::string
CGameListCtrl::GetGameNames() const
334 // This draws our icons on top of the gamelist, it's only used on Windows
335 void CGameListCtrl::OnPaintDrawImages(wxPaintEvent
& event
)
337 int i
= 0, nState
= 0;
342 // Calls the default drawing code
343 wxControl::OnPaint(event
);
345 // Draw the flags, platform icons and emustate icons on top if there's games to show
346 if (m_ISOFiles
.size() != 0)
348 // Retrieve the topmost shown item and get drawing offsets
349 long top
= GetTopItem();
350 int flagOffset
= GetColumnWidth(0) + GetColumnWidth(1) + GetColumnWidth(2) + GetColumnWidth(3);
351 int stateOffset
= flagOffset
+ GetColumnWidth(4) + GetColumnWidth(5);
353 // Only redraw shown lines
354 for (i
= top
; i
< top
+ GetCountPerPage() + 2; i
++)
356 if (GetItemRect(i
, itemRect
))
358 int itemY
= itemRect
.GetTop();
359 const GameListItem
& rISOFile
= m_ISOFiles
[GetItemData(i
)];
361 m_imageListSmall
->Draw(m_PlatformImageIndex
[rISOFile
.GetPlatform()], dc
, itemRect
.GetX()+3, itemY
);
362 m_imageListSmall
->Draw(m_FlagImageIndex
[rISOFile
.GetCountry()], dc
, flagOffset
, itemY
);
364 ini
.Load((std::string(File::GetUserPath(D_GAMECONFIG_IDX
)) + (rISOFile
.GetUniqueID()) + ".ini").c_str());
365 ini
.Get("EmuState", "EmulationStateId", &nState
);
366 m_imageListSmall
->Draw(m_EmuStateImageIndex
[nState
], dc
, stateOffset
, itemY
);
373 void CGameListCtrl::InsertItemInReportView(long _Index
)
375 // When using wxListCtrl, there is no hope of per-column text colors.
376 // But for reference, here are the old colors that were used: (BGR)
380 wxCSConv
SJISConv(wxFontMapper::GetEncodingName(wxFONTENCODING_SHIFT_JIS
));
381 GameListItem
& rISOFile
= m_ISOFiles
[_Index
];
382 m_gamePath
.append(rISOFile
.GetFileName() + '\n');
384 // Insert a first row with the platform image, that will be used as the Index
386 long ItemIndex
= InsertItem(_Index
, wxEmptyString
, m_PlatformImageIndex
[rISOFile
.GetPlatform()]);
388 long ItemIndex
= InsertItem(_Index
, wxEmptyString
, -1);
391 if (rISOFile
.GetImage().IsOk())
392 ImageIndex
= m_imageListSmall
->Add(rISOFile
.GetImage());
394 // Set the game's banner in the second column
395 SetItemColumnImage(_Index
, COLUMN_BANNER
, ImageIndex
);
397 if (rISOFile
.GetPlatform() != GameListItem::WII_WAD
)
401 // We show the company string on Gamecube only
402 // On Wii we show the description instead as the company string is empty
403 if (rISOFile
.GetPlatform() == GameListItem::GAMECUBE_DISC
)
404 company
= rISOFile
.GetCompany().c_str();
406 switch (rISOFile
.GetCountry())
408 case DiscIO::IVolume::COUNTRY_TAIWAN
:
409 case DiscIO::IVolume::COUNTRY_JAPAN
:
411 wxString name
= wxString(rISOFile
.GetName(0).c_str(), SJISConv
);
412 m_gameList
.append(StringFromFormat("%s (J)\n", (const char*)name
.c_str()));
413 SetItem(_Index
, COLUMN_TITLE
, name
, -1);
414 SetItem(_Index
, COLUMN_NOTES
, wxString(company
.size() ? company
.c_str() : rISOFile
.GetDescription(0).c_str(), SJISConv
), -1);
417 case DiscIO::IVolume::COUNTRY_USA
:
418 m_gameList
.append(StringFromFormat("%s (U)\n", rISOFile
.GetName(0).c_str()));
419 SetItem(_Index
, COLUMN_TITLE
,
420 wxString::From8BitData(rISOFile
.GetName(0).c_str()), -1);
421 SetItem(_Index
, COLUMN_NOTES
,
422 wxString::From8BitData(company
.size() ? company
.c_str() : rISOFile
.GetDescription(0).c_str()), -1);
425 m_gameList
.append(StringFromFormat("%s (E)\n", rISOFile
.GetName((int)SConfig::GetInstance().m_InterfaceLanguage
).c_str()));
426 SetItem(_Index
, COLUMN_TITLE
,
427 wxString::From8BitData(rISOFile
.GetName((int)SConfig::GetInstance().m_InterfaceLanguage
).c_str()), -1);
428 SetItem(_Index
, COLUMN_NOTES
, wxString::From8BitData(
429 company
.size() ? company
.c_str() : rISOFile
.GetDescription((int)SConfig::GetInstance().m_InterfaceLanguage
).c_str()), -1);
433 else // It's a Wad file
435 m_gameList
.append(StringFromFormat("%s (WAD)\n", rISOFile
.GetName(0).c_str()));
436 SetItem(_Index
, COLUMN_TITLE
, wxString(rISOFile
.GetName(0).c_str(), SJISConv
), -1);
437 SetItem(_Index
, COLUMN_NOTES
, wxString(rISOFile
.GetDescription(0).c_str(), SJISConv
), -1);
441 // Load the INI file for columns that read from it
443 ini
.Load((std::string(File::GetUserPath(D_GAMECONFIG_IDX
)) + (rISOFile
.GetUniqueID()) + ".ini").c_str());
447 ini
.Get("EmuState", "EmulationStateId", &nState
);
450 SetItemColumnImage(_Index
, COLUMN_EMULATION_STATE
, m_EmuStateImageIndex
[nState
]);
453 SetItemColumnImage(_Index
, COLUMN_COUNTRY
, m_FlagImageIndex
[rISOFile
.GetCountry()]);
457 SetItem(_Index
, COLUMN_SIZE
, NiceSizeFormat(rISOFile
.GetFileSize()), -1);
460 SetBackgroundColor();
463 SetItemData(_Index
, ItemIndex
);
466 wxColour
blend50(const wxColour
& c1
, const wxColour
& c2
)
468 unsigned char r
,g
,b
,a
;
469 r
= c1
.Red()/2 + c2
.Red()/2;
470 g
= c1
.Green()/2 + c2
.Green()/2;
471 b
= c1
.Blue()/2 + c2
.Blue()/2;
472 a
= c1
.Alpha()/2 + c2
.Alpha()/2;
473 return a
<< 24 | b
<< 16 | g
<< 8 | r
;
476 void CGameListCtrl::SetBackgroundColor()
478 for(long i
= 0; i
< GetItemCount(); i
++)
480 wxColour color
= (i
& 1) ? blend50(wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)) : wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
);
481 CGameListCtrl::SetItemBackgroundColour(i
, color
);
485 void CGameListCtrl::ScanForISOs()
488 CFileSearch::XStringVector
Directories(SConfig::GetInstance().m_ISOFolder
);
490 if (SConfig::GetInstance().m_RecursiveISOFolder
)
492 for (u32 i
= 0; i
< Directories
.size(); i
++)
494 File::FSTEntry FST_Temp
;
495 File::ScanDirectoryTree(Directories
.at(i
).c_str(), FST_Temp
);
496 for (u32 j
= 0; j
< FST_Temp
.children
.size(); j
++)
498 if (FST_Temp
.children
.at(j
).isDirectory
)
500 bool duplicate
= false;
501 NormalizeDirSep(&(FST_Temp
.children
.at(j
).physicalName
));
502 for (u32 k
= 0; k
< Directories
.size(); k
++)
504 NormalizeDirSep(&Directories
.at(k
));
505 if (strcmp(Directories
.at(k
).c_str(), FST_Temp
.children
.at(j
).physicalName
.c_str()) == 0)
512 Directories
.push_back(FST_Temp
.children
.at(j
).physicalName
.c_str());
518 CFileSearch::XStringVector Extensions
;
520 if (SConfig::GetInstance().m_ListGC
)
521 Extensions
.push_back("*.gcm");
522 if (SConfig::GetInstance().m_ListWii
|| SConfig::GetInstance().m_ListGC
)
524 Extensions
.push_back("*.iso");
525 Extensions
.push_back("*.gcz");
527 if (SConfig::GetInstance().m_ListWad
)
528 Extensions
.push_back("*.wad");
530 CFileSearch
FileSearch(Extensions
, Directories
);
531 const CFileSearch::XStringVector
& rFilenames
= FileSearch
.GetFileNames();
533 if (rFilenames
.size() > 0)
535 wxProgressDialog
dialog(_T("Scanning for ISOs"),
537 (int)rFilenames
.size(), // range
540 // wxPD_AUTO_HIDE | -- try this as well
542 wxPD_ESTIMATED_TIME
|
543 wxPD_REMAINING_TIME
|
544 wxPD_SMOOTH
// - makes indeterminate mode bar on WinXP very small
546 dialog
.CenterOnParent();
548 for (u32 i
= 0; i
< rFilenames
.size(); i
++)
550 std::string FileName
;
551 SplitPath(rFilenames
[i
], NULL
, &FileName
, NULL
);
554 char tempstring
[128];
555 sprintf(tempstring
,"Scanning %s", FileName
.c_str());
556 msg
= wxString(tempstring
, *wxConvCurrent
);
558 // Update with the progress (i) and the message (msg)
559 bool Cont
= dialog
.Update(i
, msg
);
564 GameListItem
ISOFile(rFilenames
[i
]);
565 if (ISOFile
.IsValid())
569 switch(ISOFile
.GetPlatform())
571 case GameListItem::WII_DISC
:
572 if (!SConfig::GetInstance().m_ListWii
)
575 case GameListItem::WII_WAD
:
576 if (!SConfig::GetInstance().m_ListWad
)
580 if (!SConfig::GetInstance().m_ListGC
)
585 switch(ISOFile
.GetCountry())
587 case DiscIO::IVolume::COUNTRY_TAIWAN
:
588 if (!SConfig::GetInstance().m_ListTaiwan
)
590 case DiscIO::IVolume::COUNTRY_KOREA
:
591 if (!SConfig::GetInstance().m_ListKorea
)
594 case DiscIO::IVolume::COUNTRY_JAPAN
:
595 if (!SConfig::GetInstance().m_ListJap
)
598 case DiscIO::IVolume::COUNTRY_USA
:
599 if (!SConfig::GetInstance().m_ListUsa
)
602 case DiscIO::IVolume::COUNTRY_FRANCE
:
603 if (!SConfig::GetInstance().m_ListFrance
)
606 case DiscIO::IVolume::COUNTRY_ITALY
:
607 if (!SConfig::GetInstance().m_ListItaly
)
611 if (!SConfig::GetInstance().m_ListPal
)
616 if (list
) m_ISOFiles
.push_back(ISOFile
);
621 if (SConfig::GetInstance().m_ListDrives
)
623 std::vector
<std::string
> drives
= cdio_get_devices();
624 GameListItem
* Drive
[24];
625 // Another silly Windows limitation of 24 drive letters
626 for (u32 i
= 0; i
< drives
.size() && i
< 24; i
++)
628 Drive
[i
] = new GameListItem(drives
[i
].c_str());
629 if (Drive
[i
]->IsValid()) m_ISOFiles
.push_back(*Drive
[i
]);
633 std::sort(m_ISOFiles
.begin(), m_ISOFiles
.end());
636 void CGameListCtrl::OnColBeginDrag(wxListEvent
& event
)
638 if (event
.GetColumn() != COLUMN_TITLE
&& event
.GetColumn() != COLUMN_NOTES
)
642 const GameListItem
*CGameListCtrl::GetISO(int index
) const
644 return &m_ISOFiles
[index
];
647 CGameListCtrl
*caller
;
648 int wxCALLBACK
wxListCompare(long item1
, long item2
, long sortData
)
650 //return 1 if item1 > item2
651 //return -1 if item1 < item2
653 const GameListItem
*iso1
= caller
->GetISO(item1
);
654 const GameListItem
*iso2
= caller
->GetISO(item2
);
661 sortData
= -sortData
;
667 switch (iso1
->GetCountry())
669 case DiscIO::IVolume::COUNTRY_JAPAN
:;
670 case DiscIO::IVolume::COUNTRY_USA
:indexOne
= 0; break;
671 default: indexOne
= (int)SConfig::GetInstance().m_InterfaceLanguage
;
674 switch (iso2
->GetCountry())
676 case DiscIO::IVolume::COUNTRY_JAPAN
:;
677 case DiscIO::IVolume::COUNTRY_USA
:indexOther
= 0; break;
678 default: indexOther
= (int)SConfig::GetInstance().m_InterfaceLanguage
;
683 case CGameListCtrl::COLUMN_TITLE
:
684 return strcasecmp(iso1
->GetName(indexOne
).c_str(),iso2
->GetName(indexOther
).c_str()) *t
;
685 case CGameListCtrl::COLUMN_NOTES
:
687 std::string cmp1
= (iso1
->GetPlatform() == GameListItem::GAMECUBE_DISC
) ? iso1
->GetCompany() : iso1
->GetDescription(indexOne
);
688 std::string cmp2
= (iso2
->GetPlatform() == GameListItem::GAMECUBE_DISC
) ? iso2
->GetCompany() : iso2
->GetDescription(indexOther
);
689 return strcasecmp(cmp1
.c_str(), cmp2
.c_str()) *t
;
691 case CGameListCtrl::COLUMN_COUNTRY
:
692 if(iso1
->GetCountry() > iso2
->GetCountry()) return 1 *t
;
693 if(iso1
->GetCountry() < iso2
->GetCountry()) return -1 *t
;
695 case CGameListCtrl::COLUMN_SIZE
:
696 if (iso1
->GetFileSize() > iso2
->GetFileSize()) return 1 *t
;
697 if (iso1
->GetFileSize() < iso2
->GetFileSize()) return -1 *t
;
699 case CGameListCtrl::COLUMN_PLATFORM
:
700 if(iso1
->GetPlatform() > iso2
->GetPlatform()) return 1 *t
;
701 if(iso1
->GetPlatform() < iso2
->GetPlatform()) return -1 *t
;
703 case CGameListCtrl::COLUMN_EMULATION_STATE
:
704 IniFile ini
; int nState1
= 0, nState2
= 0;
705 std::string GameIni1
= std::string(File::GetUserPath(D_GAMECONFIG_IDX
)) + iso1
->GetUniqueID() + ".ini";
706 std::string GameIni2
= std::string(File::GetUserPath(D_GAMECONFIG_IDX
)) + iso2
->GetUniqueID() + ".ini";
708 ini
.Load(GameIni1
.c_str());
709 ini
.Get("EmuState", "EmulationStateId", &nState1
);
710 ini
.Load(GameIni2
.c_str());
711 ini
.Get("EmuState", "EmulationStateId", &nState2
);
713 if(nState1
> nState2
) return 1 *t
;
714 if(nState1
< nState2
) return -1 *t
;
721 void CGameListCtrl::OnColumnClick(wxListEvent
& event
)
723 if(event
.GetColumn() != COLUMN_BANNER
)
725 int current_column
= event
.GetColumn();
727 if(last_column
== current_column
)
729 last_sort
= -last_sort
;
733 last_column
= current_column
;
734 last_sort
= current_column
;
738 SortItems(wxListCompare
, last_sort
);
741 SetBackgroundColor();
746 // This is used by keyboard gamelist search
747 void CGameListCtrl::OnKeyPress(wxListEvent
& event
)
749 static int lastKey
= 0, sLoop
= 0;
752 for (int i
= 0; i
< (int)m_ISOFiles
.size(); i
++)
754 // Easy way to get game string
757 bleh
.SetColumn(COLUMN_TITLE
);
758 bleh
.SetMask(wxLIST_MASK_TEXT
);
761 wxString text
= bleh
.GetText();
763 if (text
.MakeUpper().at(0) == event
.GetKeyCode())
765 if (lastKey
== event
.GetKeyCode() && Loop
< sLoop
)
768 if (i
+1 == (int)m_ISOFiles
.size())
772 else if (lastKey
!= event
.GetKeyCode())
775 lastKey
= event
.GetKeyCode();
779 SetItemState(i
, wxLIST_STATE_SELECTED
|wxLIST_STATE_FOCUSED
, wxLIST_STATE_SELECTED
|wxLIST_STATE_FOCUSED
);
784 // If we get past the last game in the list, we'll have to go back to the first one.
785 if (i
+1 == (int)m_ISOFiles
.size() && sLoop
> 0 && Loop
> 0)
792 // This shows a little tooltip with the current Game's emulation state
793 void CGameListCtrl::OnMouseMotion(wxMouseEvent
& event
)
795 int flags
; long subitem
= 0;
796 long item
= HitTest(event
.GetPosition(), flags
, &subitem
);
797 static int lastItem
= -1;
799 if (item
!= wxNOT_FOUND
)
801 if (subitem
== COLUMN_EMULATION_STATE
)
803 if (toolTip
|| lastItem
== item
|| this != FindFocus()) {
808 const GameListItem
& rISO
= m_ISOFiles
[GetItemData(item
)];
811 ini
.Load((std::string(File::GetUserPath(D_GAMECONFIG_IDX
)) + (rISO
.GetUniqueID()) + ".ini").c_str());
814 std::string emuState
[5] = {"Broken", "Intro", "In-Game", "Playable", "Perfect"}, issues
;
817 ini
.Get("EmuState", "EmulationStateId", &nState
);
818 ini
.Get("EmuState", "EmulationIssues", &issues
, "");
820 // Get item Coords then convert from wxWindow coord to Screen coord
822 this->GetItemRect(item
, Rect
);
823 int mx
= Rect
.GetWidth();
824 int my
= Rect
.GetY();
825 this->ClientToScreen(&mx
, &my
);
827 // Show a tooltip containing the EmuState and the state description
828 if (nState
> 0 && nState
< 6)
831 sprintf(temp
, "^ %s%s%s", emuState
[nState
-1].c_str(), issues
.size() > 0 ? " :\n" : "", issues
.c_str());
832 toolTip
= new wxEmuStateTip(this, wxString(temp
, *wxConvCurrent
), &toolTip
);
835 toolTip
= new wxEmuStateTip(this, wxT("Not Set"), &toolTip
);
837 toolTip
->SetBoundingRect(wxRect(mx
- GetColumnWidth(subitem
), my
, GetColumnWidth(subitem
), Rect
.GetHeight()));
838 toolTip
->SetPosition(wxPoint(mx
- GetColumnWidth(subitem
), my
- 5 + Rect
.GetHeight()));
847 void CGameListCtrl::OnLeftClick(wxMouseEvent
& event
)
849 // Focus the clicked item.
851 long item
= HitTest(event
.GetPosition(), flags
);
852 if ((item
!= wxNOT_FOUND
) && (GetSelectedItemCount() == 0) && (!event
.ControlDown()) && (!event
.ShiftDown()))
854 SetItemState(item
, wxLIST_STATE_SELECTED
, wxLIST_STATE_SELECTED
);
855 SetItemState(item
, wxLIST_STATE_FOCUSED
, wxLIST_STATE_FOCUSED
);
856 wxGetApp().GetCFrame()->UpdateGUI();
862 void CGameListCtrl::OnRightClick(wxMouseEvent
& event
)
864 // Focus the clicked item.
866 long item
= HitTest(event
.GetPosition(), flags
);
867 if (item
!= wxNOT_FOUND
)
869 if (GetItemState(item
, wxLIST_STATE_SELECTED
) != wxLIST_STATE_SELECTED
)
872 SetItemState(item
, wxLIST_STATE_SELECTED
, wxLIST_STATE_SELECTED
);
874 SetItemState(item
, wxLIST_STATE_FOCUSED
, wxLIST_STATE_FOCUSED
);
877 if (GetSelectedItemCount() == 1)
879 const GameListItem
*selected_iso
= GetSelectedISO();
882 wxMenu
* popupMenu
= new wxMenu
;
883 popupMenu
->Append(IDM_PROPERTIES
, _("&Properties"));
884 popupMenu
->AppendSeparator();
886 if (selected_iso
->GetPlatform() != GameListItem::GAMECUBE_DISC
)
888 popupMenu
->Append(IDM_OPENSAVEFOLDER
, _("Open Wii &save folder"));
889 popupMenu
->Append(IDM_EXPORTSAVE
, _("Export Wii save (Experimental)"));
891 popupMenu
->Append(IDM_OPENCONTAININGFOLDER
, _("Open &containing folder"));
892 popupMenu
->AppendCheckItem(IDM_SETDEFAULTGCM
, _("Set as &default ISO"));
894 // First we have to decide a starting value when we append it
895 if(selected_iso
->GetFileName() == SConfig::GetInstance().
896 m_LocalCoreStartupParameter
.m_strDefaultGCM
)
897 popupMenu
->FindItem(IDM_SETDEFAULTGCM
)->Check();
899 popupMenu
->AppendSeparator();
900 popupMenu
->Append(IDM_DELETEGCM
, _("&Delete ISO..."));
902 if (selected_iso
->GetPlatform() != GameListItem::WII_WAD
)
904 if (selected_iso
->IsCompressed())
905 popupMenu
->Append(IDM_COMPRESSGCM
, _("Decompress ISO..."));
907 popupMenu
->Append(IDM_COMPRESSGCM
, _("Compress ISO..."));
909 popupMenu
->Append(IDM_INSTALLWAD
, _("Install to Wii Menu"));
911 PopupMenu(popupMenu
);
914 else if (GetSelectedItemCount() > 1)
916 wxMenu
* popupMenu
= new wxMenu
;
917 popupMenu
->Append(IDM_DELETEGCM
, _("&Delete selected ISOs..."));
918 popupMenu
->AppendSeparator();
919 popupMenu
->Append(IDM_MULTICOMPRESSGCM
, _("Compress selected ISOs..."));
920 popupMenu
->Append(IDM_MULTIDECOMPRESSGCM
, _("Decompress selected ISOs..."));
921 PopupMenu(popupMenu
);
925 const GameListItem
* CGameListCtrl::GetSelectedISO()
927 if (m_ISOFiles
.size() == 0)
931 else if (GetSelectedItemCount() == 0)
937 long item
= GetNextItem(-1, wxLIST_NEXT_ALL
, wxLIST_STATE_SELECTED
);
938 if (item
== wxNOT_FOUND
)
939 return new GameListItem("");
942 // Here is a little workaround for multiselections:
943 // when > 1 item is selected, return info on the first one
944 // and deselect it so the next time GetSelectedISO() is called,
945 // the next item's info is returned
946 if (GetSelectedItemCount() > 1)
947 SetItemState(item
, 0, wxLIST_STATE_SELECTED
);
949 return &m_ISOFiles
[GetItemData(item
)];
954 void CGameListCtrl::OnOpenContainingFolder(wxCommandEvent
& WXUNUSED (event
))
956 const GameListItem
*iso
= GetSelectedISO();
960 SplitPath(iso
->GetFileName(), &path
, 0, 0);
961 WxUtils::Explore(path
.c_str());
964 void CGameListCtrl::OnOpenSaveFolder(wxCommandEvent
& WXUNUSED (event
))
966 const GameListItem
*iso
= GetSelectedISO();
969 if (iso
->GetWiiFSPath() != "NULL")
970 WxUtils::Explore(iso
->GetWiiFSPath().c_str());
973 void CGameListCtrl::OnExportSave(wxCommandEvent
& WXUNUSED (event
))
975 const GameListItem
*iso
= GetSelectedISO();
979 DiscIO::IVolume
*Iso
= DiscIO::CreateVolumeFromFilename(iso
->GetFileName());
982 if (Iso
->GetTitleID((u8
*)&title
))
984 title
= Common::swap64(title
);
985 CWiiSaveCrypted
* exportSave
= new CWiiSaveCrypted("", title
);
992 // =======================================================
993 // Save this file as the default file
995 void CGameListCtrl::OnSetDefaultGCM(wxCommandEvent
& event
)
997 const GameListItem
*iso
= GetSelectedISO();
1000 if (event
.IsChecked()) // Write the new default value and save it the ini file
1002 SConfig::GetInstance().m_LocalCoreStartupParameter
.m_strDefaultGCM
= iso
->GetFileName();
1003 SConfig::GetInstance().SaveSettings();
1005 else // Othwerise blank the value and save it
1007 SConfig::GetInstance().m_LocalCoreStartupParameter
.m_strDefaultGCM
= "";
1008 SConfig::GetInstance().SaveSettings();
1014 void CGameListCtrl::OnDeleteGCM(wxCommandEvent
& WXUNUSED (event
))
1016 if (GetSelectedItemCount() == 1)
1018 const GameListItem
*iso
= GetSelectedISO();
1021 if (wxMessageBox(_("Are you sure you want to delete this file?\nIt will be gone forever!"),
1022 wxMessageBoxCaptionStr
, wxYES_NO
| wxICON_EXCLAMATION
) == wxYES
)
1024 File::Delete(iso
->GetFileName().c_str());
1030 if (wxMessageBox(_("Are you sure you want to delete these files?\nThey will be gone forever!"),
1031 wxMessageBoxCaptionStr
, wxYES_NO
| wxICON_EXCLAMATION
) == wxYES
)
1033 int selected
= GetSelectedItemCount();
1035 for (int i
= 0; i
< selected
; i
++)
1037 const GameListItem
*iso
= GetSelectedISO();
1038 File::Delete(iso
->GetFileName().c_str());
1045 void CGameListCtrl::OnProperties(wxCommandEvent
& WXUNUSED (event
))
1047 const GameListItem
*iso
= GetSelectedISO();
1050 CISOProperties
ISOProperties(iso
->GetFileName(), this);
1051 if(ISOProperties
.ShowModal() == wxID_OK
)
1055 void CGameListCtrl::OnInstallWAD(wxCommandEvent
& WXUNUSED (event
))
1057 const GameListItem
*iso
= GetSelectedISO();
1061 wxProgressDialog
dialog(_T("Installing WAD to Wii Menu..."),
1066 // wxPD_AUTO_HIDE | -- try this as well
1068 wxPD_ESTIMATED_TIME
|
1069 wxPD_REMAINING_TIME
|
1070 wxPD_SMOOTH
// - makes indeterminate mode bar on WinXP very small
1073 dialog
.CenterOnParent();
1075 CBoot::Install_WiiWAD(iso
->GetFileName().c_str());
1078 void CGameListCtrl::MultiCompressCB(const char* text
, float percent
, void* arg
)
1080 percent
= (((float)m_currentItem
) + percent
) / (float)m_numberItem
;
1082 wxString
textString(wxString::Format(wxT("%s (%i/%i) - %s"), m_currentFilename
.c_str(), (int)m_currentItem
+1, (int)m_numberItem
, text
));
1084 ((wxProgressDialog
*)arg
)->Update((int)(percent
*1000), textString
);
1087 void CGameListCtrl::OnMultiCompressGCM(wxCommandEvent
& /*event*/)
1089 CompressSelection(true);
1092 void CGameListCtrl::OnMultiDecompressGCM(wxCommandEvent
& /*event*/)
1094 CompressSelection(false);
1097 void CGameListCtrl::CompressSelection(bool _compress
)
1100 wxGetHomeDir(&dirHome
);
1102 wxDirDialog
browseDialog(this, _("Browse for output directory"), dirHome
, wxDD_DEFAULT_STYLE
| wxDD_DIR_MUST_EXIST
);
1103 if (browseDialog
.ShowModal() != wxID_OK
)
1106 wxProgressDialog
progressDialog(_compress
? _("Compressing ISO") : _("Decompressing ISO"),
1111 // wxPD_AUTO_HIDE | -- try this as well
1113 wxPD_ESTIMATED_TIME
|
1114 wxPD_REMAINING_TIME
|
1115 wxPD_SMOOTH
// - makes indeterminate mode bar on WinXP very small
1118 progressDialog
.SetSize(wxSize(600, 180));
1119 progressDialog
.CenterOnParent();
1122 m_numberItem
= GetSelectedItemCount();
1123 for (u32 i
=0; i
<m_numberItem
; i
++)
1125 const GameListItem
*iso
= GetSelectedISO();
1127 if (!iso
->IsCompressed() && _compress
)
1129 std::string FileName
;
1130 SplitPath(iso
->GetFileName(), NULL
, &FileName
, NULL
);
1131 m_currentFilename
= FileName
;
1132 FileName
.append(".gcz");
1134 std::string OutputFileName
;
1135 BuildCompleteFilename(OutputFileName
, (const char *)browseDialog
.GetPath().mb_str(wxConvUTF8
), FileName
);
1137 DiscIO::CompressFileToBlob(iso
->GetFileName().c_str(), OutputFileName
.c_str(), (iso
->GetPlatform() == GameListItem::WII_DISC
) ? 1 : 0, 16384, &MultiCompressCB
, &progressDialog
);
1139 else if (iso
->IsCompressed() && !_compress
)
1141 std::string FileName
;
1142 SplitPath(iso
->GetFileName(), NULL
, &FileName
, NULL
);
1143 m_currentFilename
= FileName
;
1144 FileName
.append(".gcm");
1146 std::string OutputFileName
;
1147 BuildCompleteFilename(OutputFileName
, (const char *)browseDialog
.GetPath().mb_str(wxConvUTF8
), FileName
);
1149 DiscIO::DecompressBlobToFile(iso
->GetFileName().c_str(), OutputFileName
.c_str(), &MultiCompressCB
, &progressDialog
);
1156 void CGameListCtrl::CompressCB(const char* text
, float percent
, void* arg
)
1158 ((wxProgressDialog
*)arg
)->Update((int)(percent
*1000), wxString(text
, *wxConvCurrent
));
1161 void CGameListCtrl::OnCompressGCM(wxCommandEvent
& WXUNUSED (event
))
1163 const GameListItem
*iso
= GetSelectedISO();
1169 std::string FileName
;
1170 SplitPath(iso
->GetFileName(), NULL
, &FileName
, NULL
);
1172 if (iso
->IsCompressed())
1174 path
= wxFileSelector(
1175 _T("Save decompressed ISO"),
1176 wxEmptyString
, wxString(FileName
.c_str(), *wxConvCurrent
), wxEmptyString
,
1179 _T("All GC/Wii ISO files (gcm)|*.gcm|All files (%s)|%s"),
1180 wxFileSelectorDefaultWildcardStr
,
1181 wxFileSelectorDefaultWildcardStr
1193 path
= wxFileSelector(
1194 _T("Save compressed ISO"),
1195 wxEmptyString
, wxString(FileName
.c_str(), *wxConvCurrent
), wxEmptyString
,
1198 _T("All compressed GC/Wii ISO files (gcz)|*.gcz|All files (%s)|%s"),
1199 wxFileSelectorDefaultWildcardStr
,
1200 wxFileSelectorDefaultWildcardStr
1211 wxProgressDialog
dialog(iso
->IsCompressed() ? _T("Decompressing ISO") : _T("Compressing ISO"),
1216 // wxPD_AUTO_HIDE | -- try this as well
1218 wxPD_ESTIMATED_TIME
|
1219 wxPD_REMAINING_TIME
|
1220 wxPD_SMOOTH
// - makes indeterminate mode bar on WinXP very small
1223 dialog
.SetSize(wxSize(280, 180));
1224 dialog
.CenterOnParent();
1226 if (iso
->IsCompressed())
1227 DiscIO::DecompressBlobToFile(iso
->GetFileName().c_str(), path
.char_str(), &CompressCB
, &dialog
);
1229 DiscIO::CompressFileToBlob(iso
->GetFileName().c_str(), path
.char_str(), (iso
->GetPlatform() == GameListItem::WII_DISC
) ? 1 : 0, 16384, &CompressCB
, &dialog
);
1234 void CGameListCtrl::OnSize(wxSizeEvent
& event
)
1236 if (lastpos
== event
.GetSize()) return;
1237 lastpos
= event
.GetSize();
1238 AutomaticColumnWidth();
1243 void CGameListCtrl::AutomaticColumnWidth()
1245 wxRect
rc(GetClientRect());
1247 if (GetColumnCount() == 1)
1249 SetColumnWidth(0, rc
.GetWidth());
1251 else if (GetColumnCount() > 4)
1253 int resizable
= rc
.GetWidth() - (
1254 GetColumnWidth(COLUMN_BANNER
)
1255 + GetColumnWidth(COLUMN_COUNTRY
)
1256 + GetColumnWidth(COLUMN_SIZE
)
1257 + GetColumnWidth(COLUMN_EMULATION_STATE
)
1258 + GetColumnWidth(COLUMN_PLATFORM
)
1259 + 5); // some pad to keep the horizontal scrollbar away :)
1261 // We hide the Company column if the window is too small
1262 if (0.5*resizable
> 200)
1264 SetColumnWidth(COLUMN_TITLE
, 0.5*resizable
);
1265 SetColumnWidth(COLUMN_NOTES
, 0.5*resizable
);
1269 SetColumnWidth(COLUMN_TITLE
, resizable
);
1270 SetColumnWidth(COLUMN_NOTES
, 0);
1275 void CGameListCtrl::UnselectAll()
1277 for (int i
=0; i
<GetItemCount(); i
++)
1279 SetItemState(i
, 0, wxLIST_STATE_SELECTED
);