project64/Source/Project64/UserInterface/RomBrowser.cpp

1438 lines
48 KiB
C++

#include "stdafx.h"
#include <Project64/Settings/UISettings.h>
#include <commctrl.h>
#include <shlobj.h>
std::string CRomBrowser::m_UnknownGoodName;
CRomBrowser::CRomBrowser(HWND & MainWindow, HWND & StatusWindow) :
m_MainWindow(MainWindow),
m_StatusWindow(StatusWindow),
m_ShowingRomBrowser(false),
m_AllowSelectionLastRom(true),
m_WatchThreadID(0),
m_WatchThread(nullptr),
m_WatchStopEvent(nullptr)
{
m_hRomList = 0;
m_Visible = false;
GetFieldInfo(m_Fields);
m_FieldType.resize(m_Fields.size());
}
CRomBrowser::~CRomBrowser(void)
{
WatchThreadStop();
DeallocateBrushs();
}
void CRomBrowser::AddField(ROMBROWSER_FIELDS_LIST & Fields, LPCSTR Name, int32_t Pos, int32_t ID, int32_t Width, LanguageStringID LangID, bool UseDefault)
{
Fields.push_back(ROMBROWSER_FIELDS(Name, Pos, ID, (int)(Width * DPIScale()), LangID, UseDefault));
}
void CRomBrowser::GetFieldInfo(ROMBROWSER_FIELDS_LIST & Fields, bool UseDefault /* = false */)
{
Fields.clear();
AddField(Fields, "File Name", -1, RB_FileName, 218, RB_FILENAME, UseDefault);
AddField(Fields, "Internal Name", -1, RB_InternalName, 200, RB_INTERNALNAME, UseDefault);
AddField(Fields, "Good Name", -1, RB_GoodName, 218, RB_GOODNAME, UseDefault);
AddField(Fields, "Name", 0, RB_Name, 417, RB_NAME, UseDefault);
AddField(Fields, "Status", 1, RB_Status, 206, RB_STATUS, UseDefault);
AddField(Fields, "Rom Size", -1, RB_RomSize, 100, RB_ROMSIZE, UseDefault);
AddField(Fields, "Notes (Core)", -1, RB_CoreNotes, 120, RB_NOTES_CORE, UseDefault);
AddField(Fields, "Notes (default plugins)", -1, RB_PluginNotes, 188, RB_NOTES_PLUGIN, UseDefault);
AddField(Fields, "Notes (User)", -1, RB_UserNotes, 100, RB_NOTES_USER, UseDefault);
AddField(Fields, "Cartridge ID", -1, RB_CartridgeID, 100, RB_CART_ID, UseDefault);
AddField(Fields, "Media", -1, RB_Media, 100, RB_MEDIA, UseDefault);
AddField(Fields, "Country", -1, RB_Country, 100, RB_COUNTRY, UseDefault);
AddField(Fields, "Developer", -1, RB_Developer, 100, RB_DEVELOPER, UseDefault);
AddField(Fields, "CRC1", -1, RB_Crc1, 100, RB_CRC1, UseDefault);
AddField(Fields, "CRC2", -1, RB_Crc2, 100, RB_CRC2, UseDefault);
AddField(Fields, "CIC Chip", -1, RB_CICChip, 100, RB_CICCHIP, UseDefault);
AddField(Fields, "Release Date", -1, RB_ReleaseDate, 100, RB_RELEASE_DATE, UseDefault);
AddField(Fields, "Genre", -1, RB_Genre, 100, RB_GENRE, UseDefault);
AddField(Fields, "Players", -1, RB_Players, 100, RB_PLAYERS, UseDefault);
AddField(Fields, "Force Feedback", -1, RB_ForceFeedback, 100, RB_FORCE_FEEDBACK, UseDefault);
AddField(Fields, "File Format", -1, RB_FileFormat, 100, RB_FILE_FORMAT, UseDefault);
}
int32_t CRomBrowser::CalcSortPosition(uint32_t lParam)
{
int32_t Start = 0;
int32_t End = ListView_GetItemCount(m_hRomList) - 1;
if (End < 0)
{
return 0;
}
for (int32_t SortIndex = NoOfSortKeys; SortIndex >= 0; SortIndex--)
{
std::string SortFieldName = UISettingsLoadStringIndex(RomBrowser_SortFieldIndex, SortIndex);
if (SortFieldName.length() == 0)
{
continue;
}
if (End == Start)
{
break;
}
size_t index;
for (index = 0; index < m_Fields.size(); index++)
{
if (_stricmp(m_Fields[index].Name(), SortFieldName.c_str()) == 0)
{
break;
}
}
if (index >= m_Fields.size())
{
continue;
}
SORT_FIELD SortFieldInfo;
SortFieldInfo._this = this;
SortFieldInfo.Key = index;
SortFieldInfo.KeyAscend = UISettingsLoadBoolIndex(RomBrowser_SortAscendingIndex, SortIndex);
// Calculate new start and end
int32_t LastTestPos = -1;
while (Start < End)
{
int32_t TestPos = (int32_t)floor((float)((Start + End) / 2));
if (LastTestPos == TestPos)
{
TestPos += 1;
}
LastTestPos = TestPos;
LVITEM lvItem;
memset(&lvItem, 0, sizeof(lvItem));
lvItem.mask = LVIF_PARAM;
lvItem.iItem = TestPos;
if (!SendMessage(m_hRomList, LVM_GETITEM, 0, (LPARAM)&lvItem))
{
return End;
}
int32_t Result = RomList_CompareItems(lParam, lvItem.lParam, (uint32_t)&SortFieldInfo);
if (Result < 0)
{
if (End == TestPos)
{
break;
}
End = TestPos;
}
else if (Result > 0)
{
if (Start == TestPos)
{
break;
}
Start = TestPos;
}
else
{
// Find new start
float Left = (float)Start;
float Right = (float)TestPos;
while (Left < Right)
{
int32_t NewTestPos = (int32_t)floor((Left + Right) / 2);
if (LastTestPos == NewTestPos)
{
NewTestPos += 1;
}
LastTestPos = NewTestPos;
memset(&lvItem, 0, sizeof(lvItem));
lvItem.mask = LVIF_PARAM;
lvItem.iItem = NewTestPos;
if (!SendMessage(m_hRomList, LVM_GETITEM, 0, (LPARAM)&lvItem))
{
return End;
}
Result = RomList_CompareItems(lParam, lvItem.lParam, (uint32_t)&SortFieldInfo);
if (Result <= 0)
{
if (Right == NewTestPos)
{
break;
}
Right = (float)NewTestPos;
}
else if (Result > 0)
{
Left = Left != (float)NewTestPos ? (float)NewTestPos : Left + 1;
}
}
Start = (int32_t)((float)Right);
// Find new end
Left = (float)TestPos;
Right = (float)End;
while (Left < Right)
{
int32_t NewTestPos = (int32_t)ceil((Left + Right) / 2);
if (LastTestPos == NewTestPos)
{
NewTestPos -= 1;
}
LastTestPos = NewTestPos;
memset(&lvItem, 0, sizeof(lvItem));
lvItem.mask = LVIF_PARAM;
lvItem.iItem = NewTestPos;
if (!SendMessage(m_hRomList, LVM_GETITEM, 0, (LPARAM)&lvItem))
{
return End;
}
Result = RomList_CompareItems(lParam, lvItem.lParam, (uint32_t)&SortFieldInfo);
if (Result >= 0)
{
if (Left == NewTestPos)
{
break;
}
Left = (float)NewTestPos;
}
if (Result < 0)
{
Right = (float)NewTestPos;
}
}
End = (int32_t)Left;
break;
}
}
}
// Compare end with item to see if we should do it after or before it
for (int32_t SortIndex = 0; SortIndex < NoOfSortKeys; SortIndex++)
{
std::string SortFieldName = UISettingsLoadStringIndex(RomBrowser_SortFieldIndex, SortIndex);
if (SortFieldName.length() == 0)
{
continue;
}
size_t index;
for (index = 0; index < m_Fields.size(); index++)
{
if (_stricmp(m_Fields[index].Name(), SortFieldName.c_str()) == 0)
{
break;
}
}
if (index >= m_Fields.size())
{
continue;
}
SORT_FIELD SortFieldInfo;
SortFieldInfo._this = this;
SortFieldInfo.Key = index;
SortFieldInfo.KeyAscend = UISettingsLoadBoolIndex(RomBrowser_SortAscendingIndex, SortIndex) != 0;
LVITEM lvItem;
memset(&lvItem, 0, sizeof(LVITEM));
lvItem.mask = LVIF_PARAM;
lvItem.iItem = End;
if (!SendMessage(m_hRomList, LVM_GETITEM, 0, (LPARAM)&lvItem))
{
return End;
}
int32_t Result = RomList_CompareItems(lParam, lvItem.lParam, (uint32_t)&SortFieldInfo);
if (Result < 0)
{
return End;
}
if (Result > 0)
{
return End + 1;
}
}
return End + 1;
}
void CRomBrowser::RomAddedToList(int32_t ListPos)
{
LVITEM lvItem;
memset(&lvItem, 0, sizeof(lvItem));
lvItem.mask = LVIF_TEXT | LVIF_PARAM;
lvItem.iItem = CalcSortPosition(ListPos);
lvItem.lParam = (LPARAM)ListPos;
lvItem.pszText = LPSTR_TEXTCALLBACK;
int32_t index = SendMessage(m_hRomList, LVM_INSERTITEM, 0, (LPARAM)&lvItem);
int32_t iItem = ListView_GetNextItem(m_hRomList, -1, LVNI_SELECTED);
// If the last ROM then highlight the item
if (iItem < 0 && _stricmp(m_RomInfo[ListPos].szFullFileName, m_LastRom.c_str()) == 0)
{
ListView_SetItemState(m_hRomList, index, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
}
if (iItem >= 0)
{
ListView_EnsureVisible(m_hRomList, iItem, FALSE);
}
}
void CRomBrowser::RomListReset(void)
{
WriteTrace(TraceUserInterface, TraceDebug, "1");
ListView_DeleteAllItems(m_hRomList);
WriteTrace(TraceUserInterface, TraceDebug, "2");
InvalidateRect(m_hRomList, nullptr, TRUE);
Sleep(100);
WriteTrace(TraceUserInterface, TraceDebug, "3");
m_LastRom = UISettingsLoadStringIndex(File_RecentGameFileIndex, 0);
if (m_WatchRomDir != g_Settings->LoadStringVal(RomList_GameDir))
{
WriteTrace(TraceUserInterface, TraceDebug, "4");
WatchThreadStop();
WriteTrace(TraceUserInterface, TraceDebug, "5");
WatchThreadStart();
WriteTrace(TraceUserInterface, TraceDebug, "6");
}
}
void CRomBrowser::CreateRomListControl(void)
{
m_hRomList = CreateWindow(WC_LISTVIEW, nullptr, WS_TABSTOP | WS_VISIBLE | WS_CHILD | LVS_OWNERDRAWFIXED | LVS_SINGLESEL | LVS_REPORT, 0, 0, 0, 0, m_MainWindow, (HMENU)IDC_ROMLIST, GetModuleHandle(nullptr), nullptr);
ResetRomBrowserColomuns();
LoadRomList();
}
void CRomBrowser::DeallocateBrushs(void)
{
for (HBRUSH_MAP::iterator itr = m_Brushes.begin(); itr != m_Brushes.end(); itr++)
{
DeleteObject(itr->second);
}
m_Brushes.clear();
}
void CRomBrowser::RomListLoaded(void)
{
RomList_SortList();
}
void CRomBrowser::RomDirChanged(void)
{
PostMessage(m_MainWindow, WM_COMMAND, ID_FILE_REFRESHROMLIST, 0);
}
void CRomBrowser::HighLightLastRom(void)
{
if (!m_AllowSelectionLastRom)
{
return;
}
m_LastRom = UISettingsLoadStringIndex(File_RecentGameFileIndex, 0);
// Make sure ROM browser is visible
if (!RomBrowserVisible())
{
return;
}
LVITEM lvItem;
lvItem.mask = LVIF_PARAM;
int32_t ItemCount = ListView_GetItemCount(m_hRomList);
for (int32_t index = 0; index < ItemCount; index++)
{
// Get The next item
lvItem.iItem = index;
if (!SendMessage(m_hRomList, LVM_GETITEM, 0, (LPARAM)&lvItem))
{
return;
}
// Get the ROM info for that item
if (lvItem.lParam < 0 || lvItem.lParam >= (LPARAM)m_RomInfo.size())
{
return;
}
ROM_INFO * pRomInfo = &m_RomInfo[lvItem.lParam];
if (!m_AllowSelectionLastRom)
{
return;
}
// If the last ROM then highlight the item
if (_stricmp(pRomInfo->szFullFileName, m_LastRom.c_str()) == 0)
{
ListView_SetItemState(m_hRomList, index, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
ListView_EnsureVisible(m_hRomList, index, FALSE);
return;
}
}
}
void CRomBrowser::MenuSetText(HMENU hMenu, int32_t MenuPos, const wchar_t * Title, char * ShortCut)
{
MENUITEMINFO MenuInfo;
wchar_t String[256];
if (Title == nullptr || wcslen(Title) == 0)
{
return;
}
memset(&MenuInfo, 0, sizeof(MENUITEMINFO));
MenuInfo.cbSize = sizeof(MENUITEMINFO);
MenuInfo.fMask = MIIM_TYPE;
MenuInfo.fType = MFT_STRING;
MenuInfo.fState = MFS_ENABLED;
MenuInfo.dwTypeData = String;
MenuInfo.cch = 256;
GetMenuItemInfo(hMenu, MenuPos, TRUE, &MenuInfo);
wcscpy(String, Title);
if (wcschr(String, '\t') != nullptr)
{
*(wcschr(String, '\t')) = '\0';
}
if (ShortCut)
{
swprintf(String, sizeof(String) / sizeof(String[0]), L"%s\t%s", String, stdstr(ShortCut).ToUTF16().c_str());
}
SetMenuItemInfo(hMenu, MenuPos, TRUE, &MenuInfo);
}
void CRomBrowser::ResetRomBrowserColomuns(void)
{
size_t Coloumn, index;
LV_COLUMN lvColumn;
wchar_t szString[300];
GetFieldInfo(m_Fields);
// Remove all current columns
memset(&lvColumn, 0, sizeof(lvColumn));
lvColumn.mask = LVCF_FMT;
while (ListView_GetColumn(m_hRomList, 0, &lvColumn))
{
ListView_DeleteColumn(m_hRomList, 0);
}
// Add columns
lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.pszText = szString;
for (Coloumn = 0; Coloumn < m_Fields.size(); Coloumn++)
{
for (index = 0; index < m_Fields.size(); index++)
{
if (m_Fields[index].Pos() == Coloumn)
{
break;
}
}
if (index == m_Fields.size() || m_Fields[index].Pos() != Coloumn)
{
m_FieldType[Coloumn] = -1;
break;
}
m_FieldType[Coloumn] = m_Fields[index].ID();
lvColumn.cx = m_Fields[index].ColWidth();
wcsncpy(szString, wGS(m_Fields[index].LangID()).c_str(), sizeof(szString) / sizeof(szString[0]));
SendMessage(m_hRomList, LVM_INSERTCOLUMN, (WPARAM)(int32_t)(Coloumn), (LPARAM)(const LV_COLUMN *)(&lvColumn));
}
}
void CRomBrowser::ResizeRomList(WORD nWidth, WORD nHeight)
{
if (RomBrowserVisible())
{
if (UISettingsLoadBool(RomBrowser_Maximized) == 0 && nHeight != 0)
{
if (UISettingsLoadDword(RomBrowser_Width) != nWidth)
{
UISettingsSaveDword(RomBrowser_Width, nWidth);
}
if (UISettingsLoadDword(RomBrowser_Height) != nHeight)
{
UISettingsSaveDword(RomBrowser_Height, nHeight);
}
}
if (IsWindow(m_StatusWindow) && IsWindowVisible(m_StatusWindow))
{
RECT rc;
GetWindowRect(m_StatusWindow, &rc);
nHeight -= (WORD)(rc.bottom - rc.top);
}
MoveWindow(m_hRomList, 0, 0, nWidth, nHeight, TRUE);
}
}
bool CRomBrowser::RomBrowserVisible(void)
{
if (!IsWindow(m_hRomList))
{
return false;
}
if (!IsWindowVisible(m_hRomList))
{
return false;
}
if (!m_Visible)
{
return false;
}
return true;
}
void CRomBrowser::RomBrowserToTop(void)
{
BringWindowToTop(m_hRomList);
SetFocus(m_hRomList);
}
void CRomBrowser::RomBrowserMaximize(bool Mazimize)
{
UISettingsSaveBool(RomBrowser_Maximized, Mazimize);
}
bool CRomBrowser::RomListDrawItem(int32_t idCtrl, uint32_t lParam)
{
if (idCtrl != IDC_ROMLIST)
{
return false;
}
LPDRAWITEMSTRUCT ditem = (LPDRAWITEMSTRUCT)lParam;
RECT rcItem, rcDraw;
wchar_t String[300];
LVITEM lvItem;
HBRUSH hBrush = (HBRUSH)(COLOR_WINDOW + 1);
LV_COLUMN lvc;
int32_t nColumn;
lvItem.mask = LVIF_PARAM;
lvItem.iItem = ditem->itemID;
if (!SendMessage(m_hRomList, LVM_GETITEM, 0, (LPARAM)&lvItem))
{
return false;
}
lvItem.state = ListView_GetItemState(m_hRomList, ditem->itemID, -1);
bool bSelected = (lvItem.state & LVIS_SELECTED) != 0;
if (lvItem.lParam < 0 || lvItem.lParam >= (LPARAM)m_RomInfo.size())
{
return true;
}
ROM_INFO * pRomInfo = &m_RomInfo[lvItem.lParam];
if (pRomInfo == nullptr)
{
return true;
}
if (bSelected)
{
HBRUSH_MAP::iterator itr = m_Brushes.find(pRomInfo->SelColor);
if (itr != m_Brushes.end())
{
hBrush = itr->second;
}
else
{
std::pair<HBRUSH_MAP::iterator, bool> res = m_Brushes.insert(HBRUSH_MAP::value_type(pRomInfo->SelColor, CreateSolidBrush(pRomInfo->SelColor)));
hBrush = res.first->second;
}
SetTextColor(ditem->hDC, pRomInfo->SelTextColor);
}
else
{
SetTextColor(ditem->hDC, pRomInfo->TextColor);
}
FillRect(ditem->hDC, &ditem->rcItem, hBrush);
SetBkMode(ditem->hDC, TRANSPARENT);
// Draw
ListView_GetItemRect(m_hRomList, ditem->itemID, &rcItem, LVIR_LABEL);
lvItem.iSubItem = 0;
lvItem.cchTextMax = sizeof(String) / sizeof(String[0]);
lvItem.pszText = String;
SendMessage(m_hRomList, LVM_GETITEMTEXT, (WPARAM)ditem->itemID, (LPARAM)&lvItem);
memcpy(&rcDraw, &rcItem, sizeof(RECT));
rcDraw.right -= 3;
std::wstring text = String;
if (wcscmp(L"#340#", text.c_str()) == 0)
{
text = wGS(RB_NOT_GOOD_FILE);
}
if (wcscmp(L"#321#", text.c_str()) == 0)
{
text = stdstr(pRomInfo->FileName).ToUTF16();
}
DrawText(ditem->hDC, text.c_str(), text.length(), &rcDraw, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER | DT_WORD_ELLIPSIS);
memset(&lvc, 0, sizeof(lvc));
lvc.mask = LVCF_FMT | LVCF_WIDTH;
for (nColumn = 1; ListView_GetColumn(m_hRomList, nColumn, &lvc); nColumn += 1)
{
rcItem.left = rcItem.right;
rcItem.right += lvc.cx;
lvItem.iSubItem = nColumn;
lvItem.cchTextMax = sizeof(String) / sizeof(String[0]);
lvItem.pszText = String;
SendMessage(m_hRomList, LVM_GETITEMTEXT, ditem->itemID, (LPARAM)&lvItem);
memcpy(&rcDraw, &rcItem, sizeof(RECT));
rcDraw.right -= 3;
text = String;
if (wcscmp(L"#340#", text.c_str()) == 0)
{
text = wGS(RB_NOT_GOOD_FILE);
}
if (wcscmp(L"#321#", text.c_str()) == 0)
{
text = stdstr(pRomInfo->FileName).ToUTF16();
}
DrawText(ditem->hDC, text.c_str(), text.length(), &rcDraw, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER | DT_WORD_ELLIPSIS);
}
return true;
}
bool CRomBrowser::RomListNotify(int32_t idCtrl, uint32_t pnmh)
{
if (idCtrl != IDC_ROMLIST)
{
return false;
}
if (!RomBrowserVisible())
{
return false;
}
switch (((LPNMHDR)pnmh)->code)
{
case LVN_COLUMNCLICK: RomList_ColoumnSortList(pnmh); break;
case NM_RETURN: RomList_OpenRom(pnmh); break;
case NM_DBLCLK: RomList_OpenRom(pnmh); break;
case LVN_GETDISPINFO: RomList_GetDispInfo(pnmh); break;
case NM_RCLICK: RomList_PopupMenu(pnmh); break;
case NM_CLICK:
{
LONG iItem = ListView_GetNextItem(m_hRomList, -1, LVNI_SELECTED);
if (iItem != -1)
{
m_AllowSelectionLastRom = false;
}
}
break;
default:
return false;
}
return true;
}
void CRomBrowser::RomList_ColoumnSortList(uint32_t pnmh)
{
LPNMLISTVIEW pnmv = (LPNMLISTVIEW)pnmh;
size_t index;
for (index = 0; index < m_Fields.size(); index++)
{
if (m_Fields[index].Pos() == (size_t)pnmv->iSubItem)
{
break;
}
}
if (m_Fields.size() == index)
{
return;
}
if (_stricmp(UISettingsLoadStringIndex(RomBrowser_SortFieldIndex, 0).c_str(), m_Fields[index].Name()) == 0)
{
UISettingsSaveBoolIndex(RomBrowser_SortAscendingIndex, 0, !UISettingsLoadBoolIndex(RomBrowser_SortAscendingIndex, 0));
}
else
{
int32_t count;
for (count = NoOfSortKeys; count > 0; count--)
{
UISettingsSaveStringIndex(RomBrowser_SortFieldIndex, count, UISettingsLoadStringIndex(RomBrowser_SortFieldIndex, count - 1).c_str());
UISettingsSaveBoolIndex(RomBrowser_SortAscendingIndex, count, UISettingsLoadBoolIndex(RomBrowser_SortAscendingIndex, count - 1));
}
UISettingsSaveStringIndex(RomBrowser_SortFieldIndex, 0, m_Fields[index].Name());
UISettingsSaveBoolIndex(RomBrowser_SortAscendingIndex, 0, true);
}
RomList_SortList();
}
int32_t CALLBACK CRomBrowser::RomList_CompareItems(uint32_t lParam1, uint32_t lParam2, uint32_t lParamSort)
{
SORT_FIELD * SortFieldInfo = (SORT_FIELD *)lParamSort;
CRomBrowser * _this = SortFieldInfo->_this;
if (lParam1 < 0 || lParam1 >= _this->m_RomInfo.size())
{
return 0;
}
if (lParam2 < 0 || lParam2 >= _this->m_RomInfo.size())
{
return 0;
}
ROM_INFO * pRomInfo1 = &_this->m_RomInfo[SortFieldInfo->KeyAscend ? lParam1 : lParam2];
ROM_INFO * pRomInfo2 = &_this->m_RomInfo[SortFieldInfo->KeyAscend ? lParam2 : lParam1];
int32_t result;
const char *GoodName1 = nullptr, *GoodName2 = nullptr;
if (SortFieldInfo->Key == RB_GoodName)
{
GoodName1 = strcmp("#340#", pRomInfo1->GoodName) != 0 ? pRomInfo1->GoodName : m_UnknownGoodName.c_str();
GoodName2 = strcmp("#340#", pRomInfo2->GoodName) != 0 ? pRomInfo2->GoodName : m_UnknownGoodName.c_str();
}
const char *Name1 = nullptr, *Name2 = nullptr;
if (SortFieldInfo->Key == RB_Name)
{
Name1 = strcmp("#321#", pRomInfo1->Name) != 0 ? pRomInfo1->GoodName : pRomInfo1->FileName;
Name2 = strcmp("#321#", pRomInfo2->Name) != 0 ? pRomInfo2->GoodName : pRomInfo2->FileName;
}
switch (SortFieldInfo->Key)
{
case RB_FileName: result = (int32_t)lstrcmpiA(pRomInfo1->FileName, pRomInfo2->FileName); break;
case RB_InternalName: result = (int32_t)lstrcmpiA(pRomInfo1->InternalName, pRomInfo2->InternalName); break;
case RB_GoodName: result = (int32_t)lstrcmpiA(GoodName1, GoodName2); break;
case RB_Name: result = (int32_t)lstrcmpiA(Name1, Name2); break;
case RB_Status: result = (int32_t)lstrcmpiA(pRomInfo1->Status, pRomInfo2->Status); break;
case RB_RomSize: result = (int32_t)pRomInfo1->RomSize - (int32_t)pRomInfo2->RomSize; break;
case RB_CoreNotes: result = (int32_t)lstrcmpiA(pRomInfo1->CoreNotes, pRomInfo2->CoreNotes); break;
case RB_PluginNotes: result = (int32_t)lstrcmpiA(pRomInfo1->PluginNotes, pRomInfo2->PluginNotes); break;
case RB_UserNotes: result = (int32_t)lstrcmpiA(pRomInfo1->UserNotes, pRomInfo2->UserNotes); break;
case RB_CartridgeID: result = (int32_t)lstrcmpiA(pRomInfo1->CartID, pRomInfo2->CartID); break;
case RB_Media: result = (int32_t)pRomInfo1->Media - (int32_t)pRomInfo2->Media; break;
case RB_Country: result = (int32_t)pRomInfo1->Country - (int32_t)pRomInfo2->Country; break;
case RB_Developer: result = (int32_t)lstrcmpiA(pRomInfo1->Developer, pRomInfo2->Developer); break;
case RB_Crc1: result = (int32_t)pRomInfo1->CRC1 - (int32_t)pRomInfo2->CRC1; break;
case RB_Crc2: result = (int32_t)pRomInfo1->CRC2 - (int32_t)pRomInfo2->CRC2; break;
case RB_CICChip: result = (int32_t)pRomInfo1->CicChip - (int32_t)pRomInfo2->CicChip; break;
case RB_ReleaseDate: result = (int32_t)lstrcmpiA(pRomInfo1->ReleaseDate, pRomInfo2->ReleaseDate); break;
case RB_Players: result = (int32_t)pRomInfo1->Players - (int32_t)pRomInfo2->Players; break;
case RB_ForceFeedback: result = (int32_t)lstrcmpiA(pRomInfo1->ForceFeedback, pRomInfo2->ForceFeedback); break;
case RB_Genre: result = (int32_t)lstrcmpiA(pRomInfo1->Genre, pRomInfo2->Genre); break;
case RB_FileFormat: result = (int32_t)pRomInfo1->FileFormat - (int32_t)pRomInfo2->FileFormat; break;
default: result = 0; break;
}
return result;
}
void CRomBrowser::RomList_GetDispInfo(uint32_t pnmh)
{
LV_DISPINFO * lpdi = (LV_DISPINFO *)pnmh;
if (lpdi->item.lParam < 0 || lpdi->item.lParam >= (LPARAM)m_RomInfo.size())
{
return;
}
ROM_INFO * pRomInfo = &m_RomInfo[lpdi->item.lParam];
if (pRomInfo == nullptr)
{
wcscpy(lpdi->item.pszText, L" ");
return;
}
switch (m_FieldType[lpdi->item.iSubItem])
{
case RB_FileName: wcsncpy(lpdi->item.pszText, stdstr(pRomInfo->FileName).ToUTF16(CP_ACP).c_str(), lpdi->item.cchTextMax); break;
case RB_InternalName: wcsncpy(lpdi->item.pszText, stdstr(pRomInfo->InternalName).ToUTF16(stdstr::CODEPAGE_932).c_str(), lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case RB_GoodName: wcsncpy(lpdi->item.pszText, stdstr(pRomInfo->GoodName).ToUTF16().c_str(), lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case RB_Name: wcsncpy(lpdi->item.pszText, stdstr(pRomInfo->Name).ToUTF16().c_str(), lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case RB_CoreNotes: wcsncpy(lpdi->item.pszText, stdstr(pRomInfo->CoreNotes).ToUTF16().c_str(), lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case RB_PluginNotes: wcsncpy(lpdi->item.pszText, stdstr(pRomInfo->PluginNotes).ToUTF16().c_str(), lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case RB_Status: wcsncpy(lpdi->item.pszText, stdstr(pRomInfo->Status).ToUTF16().c_str(), lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case RB_RomSize: swprintf(lpdi->item.pszText, lpdi->item.cchTextMax / sizeof(wchar_t), L"%.1f MBit", (float)pRomInfo->RomSize / 0x20000); break;
case RB_CartridgeID: wcsncpy(lpdi->item.pszText, stdstr(pRomInfo->CartID).ToUTF16().c_str(), lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case RB_Media:
switch (pRomInfo->Media)
{
case 'C': wcsncpy(lpdi->item.pszText, L"N64 Cartridge (Disk Compatible)", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case 'D': wcsncpy(lpdi->item.pszText, L"64DD Disk", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case 'E': wcsncpy(lpdi->item.pszText, L"64DD Disk (Expansion)", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case 'M': wcsncpy(lpdi->item.pszText, L"N64 Development Cartridge", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case 'N': wcsncpy(lpdi->item.pszText, L"N64 Cartridge", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case 'Z': wcsncpy(lpdi->item.pszText, L"Aleck64", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case 0: wcsncpy(lpdi->item.pszText, L"None", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
default: swprintf(lpdi->item.pszText, lpdi->item.cchTextMax / sizeof(wchar_t), L"(Unknown %c (%X))", pRomInfo->Media, pRomInfo->Media); break;
}
break;
case RB_Country:
switch (pRomInfo->Country)
{
case '7': wcsncpy(lpdi->item.pszText, L"Beta", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case 'A': wcsncpy(lpdi->item.pszText, L"NTSC", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case 'D': wcsncpy(lpdi->item.pszText, L"Germany", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case 'E': wcsncpy(lpdi->item.pszText, L"America", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case 'F': wcsncpy(lpdi->item.pszText, L"France", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case 'J': wcsncpy(lpdi->item.pszText, L"Japan", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case 'I': wcsncpy(lpdi->item.pszText, L"Italy", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case 'P': wcsncpy(lpdi->item.pszText, L"Europe", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case 'S': wcsncpy(lpdi->item.pszText, L"Spain", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case 'U': wcsncpy(lpdi->item.pszText, L"Australia", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case 'X': wcsncpy(lpdi->item.pszText, L"PAL", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case 'Y': wcsncpy(lpdi->item.pszText, L"PAL", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case 0: wcsncpy(lpdi->item.pszText, L"None", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
default: swprintf(lpdi->item.pszText, lpdi->item.cchTextMax / sizeof(wchar_t), L"Unknown %c (%02X)", pRomInfo->Country, pRomInfo->Country); break;
}
break;
case RB_Crc1: swprintf(lpdi->item.pszText, lpdi->item.cchTextMax / sizeof(wchar_t), L"0x%08X", pRomInfo->CRC1); break;
case RB_Crc2: swprintf(lpdi->item.pszText, lpdi->item.cchTextMax / sizeof(wchar_t), L"0x%08X", pRomInfo->CRC2); break;
case RB_CICChip:
if (pRomInfo->CicChip < 0)
{
swprintf(lpdi->item.pszText, lpdi->item.cchTextMax / sizeof(wchar_t), L"Unknown CIC Chip");
}
else if (pRomInfo->CicChip == CIC_NUS_8303)
{
swprintf(lpdi->item.pszText, lpdi->item.cchTextMax / sizeof(wchar_t), L"CIC-NUS-8303");
}
else if (pRomInfo->CicChip == CIC_NUS_5167)
{
swprintf(lpdi->item.pszText, lpdi->item.cchTextMax / sizeof(wchar_t), L"CIC-NUS-5167");
}
else if (pRomInfo->CicChip == CIC_NUS_DDUS)
{
swprintf(lpdi->item.pszText, lpdi->item.cchTextMax / sizeof(wchar_t), L"CIC-NUS-????");
}
else if (pRomInfo->CicChip == CIC_NUS_8401)
{
swprintf(lpdi->item.pszText, lpdi->item.cchTextMax / sizeof(wchar_t), L"CIC-NUS-8401");
}
else if (pRomInfo->CicChip == CIC_NUS_5101)
{
swprintf(lpdi->item.pszText, lpdi->item.cchTextMax / sizeof(wchar_t), L"CIC-NUS-5101");
}
else
{
swprintf(lpdi->item.pszText, lpdi->item.cchTextMax / sizeof(wchar_t), L"CIC-NUS-610%d", pRomInfo->CicChip);
}
break;
case RB_UserNotes: wcsncpy(lpdi->item.pszText, stdstr(pRomInfo->UserNotes).ToUTF16().c_str(), lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case RB_Developer: wcsncpy(lpdi->item.pszText, stdstr(pRomInfo->Developer).ToUTF16().c_str(), lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case RB_ReleaseDate: wcsncpy(lpdi->item.pszText, stdstr(pRomInfo->ReleaseDate).ToUTF16().c_str(), lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case RB_Genre: wcsncpy(lpdi->item.pszText, stdstr(pRomInfo->Genre).ToUTF16().c_str(), lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case RB_Players: swprintf(lpdi->item.pszText, lpdi->item.cchTextMax / sizeof(wchar_t), L"%d", pRomInfo->Players); break;
case RB_ForceFeedback: wcsncpy(lpdi->item.pszText, stdstr(pRomInfo->ForceFeedback).ToUTF16().c_str(), lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case RB_FileFormat:
switch (pRomInfo->FileFormat)
{
case Format_Uncompressed: wcsncpy(lpdi->item.pszText, L"Uncompressed", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case Format_Zip: wcsncpy(lpdi->item.pszText, L"Zip", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
case Format_7zip: wcsncpy(lpdi->item.pszText, L"7zip", lpdi->item.cchTextMax / sizeof(wchar_t)); break;
default: swprintf(lpdi->item.pszText, lpdi->item.cchTextMax / sizeof(wchar_t), L"Unknown (%X)", pRomInfo->FileFormat); break;
}
break;
default: wcsncpy(lpdi->item.pszText, L" ", lpdi->item.cchTextMax);
}
if (lpdi->item.pszText == nullptr || wcslen(lpdi->item.pszText) == 0)
{
lpdi->item.pszText = L" ";
}
}
void CRomBrowser::RomList_OpenRom(uint32_t /*pnmh*/)
{
ROM_INFO * pRomInfo;
LV_ITEM lvItem;
LONG iItem;
iItem = ListView_GetNextItem(m_hRomList, -1, LVNI_SELECTED);
if (iItem == -1)
{
return;
}
memset(&lvItem, 0, sizeof(LV_ITEM));
lvItem.mask = LVIF_PARAM;
lvItem.iItem = iItem;
if (!SendMessage(m_hRomList, LVM_GETITEM, 0, (LPARAM)&lvItem))
{
return;
}
if (lvItem.lParam < 0 || lvItem.lParam >= (LPARAM)m_RomInfo.size())
{
return;
}
pRomInfo = &m_RomInfo[lvItem.lParam];
if (!pRomInfo)
{
return;
}
m_StopRefresh = true;
if (UISettingsLoadBool(UserInterface_ShowingNagWindow))
{
return;
}
if ((CPath(pRomInfo->szFullFileName).GetExtension() != "ndd") && (CPath(pRomInfo->szFullFileName).GetExtension() != "d64"))
{
CN64System::RunFileImage(pRomInfo->szFullFileName);
}
else
{
CN64System::RunDiskImage(pRomInfo->szFullFileName);
}
}
void CRomBrowser::RomList_PopupMenu(uint32_t /*pnmh*/)
{
LONG iItem = ListView_GetNextItem(m_hRomList, -1, LVNI_SELECTED);
m_SelectedRom = "";
if (iItem != -1)
{
LV_ITEM lvItem;
memset(&lvItem, 0, sizeof(LV_ITEM));
lvItem.mask = LVIF_PARAM;
lvItem.iItem = iItem;
if (!SendMessage(m_hRomList, LVM_GETITEM, 0, (LPARAM)&lvItem))
{
return;
}
if (lvItem.lParam < 0 || lvItem.lParam >= (LPARAM)m_RomInfo.size())
{
return;
}
ROM_INFO * pRomInfo = &m_RomInfo[lvItem.lParam];
if (!pRomInfo)
{
return;
}
m_SelectedRom = pRomInfo->szFullFileName;
}
// Load the menu
HMENU hMenu = LoadMenu(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDR_POPUP));
HMENU hPopupMenu = (HMENU)GetSubMenu(hMenu, 0);
// Fix up menu
MenuSetText(hPopupMenu, 0, wGS(POPUP_PLAY).c_str(), nullptr);
MenuSetText(hPopupMenu, 1, wGS(POPUP_PLAYDISK).c_str(), nullptr);
MenuSetText(hPopupMenu, 3, wGS(MENU_REFRESH).c_str(), nullptr);
MenuSetText(hPopupMenu, 4, wGS(MENU_CHOOSE_ROM).c_str(), nullptr);
MenuSetText(hPopupMenu, 6, wGS(POPUP_INFO).c_str(), nullptr);
MenuSetText(hPopupMenu, 7, wGS(POPUP_GFX_PLUGIN).c_str(), nullptr);
MenuSetText(hPopupMenu, 9, wGS(POPUP_SETTINGS).c_str(), nullptr);
MenuSetText(hPopupMenu, 10, wGS(POPUP_CHEATS).c_str(), nullptr);
MenuSetText(hPopupMenu, 11, wGS(POPUP_ENHANCEMENTS).c_str(), nullptr);
if (m_SelectedRom.size() == 0)
{
DeleteMenu(hPopupMenu, 11, MF_BYPOSITION);
DeleteMenu(hPopupMenu, 10, MF_BYPOSITION);
DeleteMenu(hPopupMenu, 9, MF_BYPOSITION);
DeleteMenu(hPopupMenu, 8, MF_BYPOSITION);
DeleteMenu(hPopupMenu, 7, MF_BYPOSITION);
DeleteMenu(hPopupMenu, 6, MF_BYPOSITION);
DeleteMenu(hPopupMenu, 5, MF_BYPOSITION);
DeleteMenu(hPopupMenu, 2, MF_BYPOSITION);
DeleteMenu(hPopupMenu, 1, MF_BYPOSITION);
DeleteMenu(hPopupMenu, 0, MF_BYPOSITION);
}
else
{
bool inBasicMode = g_Settings->LoadBool(UserInterface_BasicMode);
bool CheatsRemembered = !inBasicMode && g_Settings->LoadBool(Setting_RememberCheats);
bool Enhancement = !inBasicMode && g_Settings->LoadBool(Setting_Enhancement);
if (!Enhancement)
{
DeleteMenu(hPopupMenu, 11, MF_BYPOSITION);
}
if (!CheatsRemembered)
{
DeleteMenu(hPopupMenu, 10, MF_BYPOSITION);
}
if (inBasicMode)
{
DeleteMenu(hPopupMenu, 9, MF_BYPOSITION);
}
if (inBasicMode && !CheatsRemembered)
{
DeleteMenu(hPopupMenu, 8, MF_BYPOSITION);
}
DeleteMenu(hPopupMenu, 7, MF_BYPOSITION);
if ((CPath(m_SelectedRom).GetExtension() == "ndd") || (CPath(m_SelectedRom).GetExtension() == "d64"))
{
DeleteMenu(hPopupMenu, 1, MF_BYPOSITION);
}
if (!inBasicMode && g_Plugins && g_Plugins->Gfx() && g_Plugins->Gfx()->GetRomBrowserMenu != nullptr)
{
HMENU GfxMenu = (HMENU)g_Plugins->Gfx()->GetRomBrowserMenu();
if (GfxMenu)
{
MENUITEMINFO lpmii;
InsertMenu(hPopupMenu, 7, MF_POPUP | MF_BYPOSITION, (uint32_t)GfxMenu, wGS(POPUP_GFX_PLUGIN).c_str());
lpmii.cbSize = sizeof(MENUITEMINFO);
lpmii.fMask = MIIM_STATE;
lpmii.fState = 0;
SetMenuItemInfo(hPopupMenu, (uint32_t)GfxMenu, MF_BYCOMMAND, &lpmii);
}
}
}
// Get the current mouse location
POINT Mouse;
GetCursorPos(&Mouse);
// Show the menu
TrackPopupMenu(hPopupMenu, 0, Mouse.x, Mouse.y, 0, m_MainWindow, nullptr);
DestroyMenu(hMenu);
}
void CRomBrowser::RomList_SortList(void)
{
SORT_FIELD SortFieldInfo;
m_UnknownGoodName = stdstr().FromUTF16(wGS(RB_NOT_GOOD_FILE).c_str());
for (int32_t count = NoOfSortKeys; count >= 0; count--)
{
stdstr SortFieldName = UISettingsLoadStringIndex(RomBrowser_SortFieldIndex, count);
size_t index;
for (index = 0; index < m_Fields.size(); index++)
{
if (_stricmp(m_Fields[index].Name(), SortFieldName.c_str()) == 0)
{
break;
}
}
if (index >= m_Fields.size())
{
continue;
}
SortFieldInfo._this = this;
SortFieldInfo.Key = index;
SortFieldInfo.KeyAscend = UISettingsLoadBoolIndex(RomBrowser_SortAscendingIndex, count) != 0;
ListView_SortItems(m_hRomList, RomList_CompareItems, &SortFieldInfo);
}
}
void CRomBrowser::SaveRomListColoumnInfo(void)
{
WriteTrace(TraceUserInterface, TraceDebug, "Start");
// if (!RomBrowserVisible()) { return; }
if (g_Settings == nullptr)
{
return;
}
LV_COLUMN lvColumn;
memset(&lvColumn, 0, sizeof(lvColumn));
lvColumn.mask = LVCF_WIDTH;
for (size_t Coloumn = 0; ListView_GetColumn(m_hRomList, Coloumn, &lvColumn); Coloumn++)
{
size_t index;
bool bFound = false;
for (index = 0; index < m_Fields.size(); index++)
{
if (m_Fields[index].Pos() == Coloumn)
{
bFound = true;
break;
}
}
if (bFound)
{
if (m_Fields[index].ColWidth() != lvColumn.cx)
{
m_Fields[index].SetColWidth(lvColumn.cx);
}
}
}
WriteTrace(TraceUserInterface, TraceDebug, "Done");
}
int32_t CALLBACK CRomBrowser::SelectRomDirCallBack(HWND hwnd, uint32_t uMsg, uint32_t /*lp*/, uint32_t lpData)
{
switch (uMsg)
{
case BFFM_INITIALIZED:
// WParam is TRUE since you are passing a path
// It would be FALSE if you were passing a PIDL
if (lpData)
{
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
SetWindowText(hwnd, wGS(DIR_SELECT_ROM).c_str());
}
break;
}
return 0;
}
void CRomBrowser::SelectRomDir(void)
{
wchar_t SelectedDir[MAX_PATH];
LPITEMIDLIST pidl;
BROWSEINFO bi;
std::wstring title = wGS(SELECT_ROM_DIR);
WriteTrace(TraceUserInterface, TraceDebug, "1");
stdstr RomDir = g_Settings->LoadStringVal(RomList_GameDir).c_str();
bi.hwndOwner = m_MainWindow;
bi.pidlRoot = nullptr;
bi.pszDisplayName = SelectedDir;
bi.lpszTitle = title.c_str();
bi.ulFlags = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS | BIF_USENEWUI;
bi.lpfn = (BFFCALLBACK)SelectRomDirCallBack;
bi.lParam = (uint32_t)RomDir.c_str();
WriteTrace(TraceUserInterface, TraceDebug, "2");
if ((pidl = SHBrowseForFolder(&bi)) != nullptr)
{
WriteTrace(TraceUserInterface, TraceDebug, "3");
char Directory[_MAX_PATH];
if (SHGetPathFromIDListA(pidl, Directory))
{
int32_t len = strlen(Directory);
WriteTrace(TraceUserInterface, TraceDebug, "4");
if (Directory[len - 1] != '\\')
{
strcat(Directory, "\\");
}
WriteTrace(TraceUserInterface, TraceDebug, "5");
WriteTrace(TraceUserInterface, TraceDebug, "6");
g_Settings->SaveString(RomList_GameDir, Directory);
WriteTrace(TraceUserInterface, TraceDebug, "7");
Notify().AddRecentDir(Directory);
WriteTrace(TraceUserInterface, TraceDebug, "8");
RefreshRomList();
WriteTrace(TraceUserInterface, TraceDebug, "9");
}
}
}
void CRomBrowser::FixRomListWindow(void)
{
// Change the window style
long Style = GetWindowLong(m_MainWindow, GWL_STYLE) | WS_SIZEBOX | WS_MAXIMIZEBOX;
SetWindowLong(m_MainWindow, GWL_STYLE, Style);
// Get the current window size
RECT rect;
GetWindowRect(m_MainWindow, &rect);
// We find the middle position of the screen, we use this if there is no setting
int32_t X = (GetSystemMetrics(SM_CXSCREEN) - (rect.right - rect.left)) / 2;
int32_t Y = (GetSystemMetrics(SM_CYSCREEN) - (rect.bottom - rect.top)) / 2;
// Load the value from settings, if none is available, default to above
UISettingsLoadDword(RomBrowser_Top, (uint32_t &)Y);
UISettingsLoadDword(RomBrowser_Left, (uint32_t &)X);
SetWindowPos(m_MainWindow, nullptr, X, Y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
// Fix height and width
int32_t Width = UISettingsLoadDword(RomBrowser_Width);
int32_t Height = UISettingsLoadDword(RomBrowser_Height);
if (Width < 200)
{
Width = 200;
}
if (Height < 200)
{
Height = 200;
}
RECT rcClient;
rcClient.top = 0;
rcClient.bottom = Height;
rcClient.left = 0;
rcClient.right = Width;
AdjustWindowRect(&rcClient, GetWindowLong(m_MainWindow, GWL_STYLE), true);
int32_t WindowHeight = rcClient.bottom - rcClient.top;
int32_t WindowWidth = rcClient.right - rcClient.left;
SetWindowPos(m_MainWindow, nullptr, 0, 0, WindowWidth, WindowHeight, SWP_NOMOVE | SWP_NOZORDER);
}
void CRomBrowser::ShowRomList(void)
{
if (m_Visible || g_Settings->LoadBool(GameRunning_CPU_Running))
{
return;
}
m_ShowingRomBrowser = true;
WatchThreadStop();
if (m_hRomList == nullptr)
{
CreateRomListControl();
}
EnableWindow(m_hRomList, TRUE);
ShowWindow(m_hRomList, SW_SHOW);
FixRomListWindow();
m_AllowSelectionLastRom = true;
// Make sure selected item is visible
int32_t iItem = ListView_GetNextItem(m_hRomList, -1, LVNI_SELECTED);
ListView_EnsureVisible(m_hRomList, iItem, FALSE);
// Mark the window as visible
m_Visible = true;
RECT rcWindow;
if (GetClientRect(m_MainWindow, &rcWindow))
{
ResizeRomList((WORD)rcWindow.right, (WORD)rcWindow.bottom);
}
InvalidateRect(m_hRomList, nullptr, TRUE);
// Start thread to watch for directory change
WatchThreadStart();
m_ShowingRomBrowser = false;
}
void CRomBrowser::HideRomList(void)
{
if (!RomBrowserVisible())
{
return;
}
ShowWindow(m_MainWindow, SW_HIDE);
SaveRomListColoumnInfo();
WatchThreadStop();
// Make sure the window does disappear
Sleep(100);
// Disable the ROM list
EnableWindow(m_hRomList, FALSE);
ShowWindow(m_hRomList, SW_HIDE);
if (UISettingsLoadBool(RomBrowser_Maximized))
{
ShowWindow(m_MainWindow, SW_RESTORE);
}
// Change the window style
long Style = GetWindowLong(m_MainWindow, GWL_STYLE) & ~(WS_SIZEBOX | WS_MAXIMIZEBOX);
SetWindowLong(m_MainWindow, GWL_STYLE, Style);
// Move window to correct location
RECT rect;
GetWindowRect(m_MainWindow, &rect);
int32_t X = (GetSystemMetrics(SM_CXSCREEN) - (rect.right - rect.left)) / 2;
int32_t Y = (GetSystemMetrics(SM_CYSCREEN) - (rect.bottom - rect.top)) / 2;
UISettingsLoadDword(UserInterface_MainWindowTop, (uint32_t &)Y);
UISettingsLoadDword(UserInterface_MainWindowLeft, (uint32_t &)X);
SetWindowPos(m_MainWindow, nullptr, X, Y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
// Mark the window as not visible
m_Visible = false;
// Make the main window visible again
ShowWindow(m_MainWindow, SW_SHOW);
BringWindowToTop(m_MainWindow);
PostMessage(m_MainWindow, WM_MAKE_FOCUS, 0, 0);
}
bool CRomBrowser::RomDirNeedsRefresh(void)
{
bool InWatchThread = (m_WatchThreadID == GetCurrentThreadId());
// Get old MD5 of file names
stdstr FileName = g_Settings->LoadStringVal(RomList_RomListCache);
if (!CPath(FileName).Exists())
{
// If file does not exist then refresh the data
return true;
}
CFile hFile(FileName.c_str(), CFileBase::modeRead);
if (!hFile.IsOpen())
{
// Could not validate, assume it is fine
return false;
}
unsigned char CurrentFileMD5[16];
hFile.Read(&CurrentFileMD5, sizeof(CurrentFileMD5));
hFile.Close();
// Get current MD5 of file names
strlist FileNames;
if (!GetRomFileNames(FileNames, CPath(g_Settings->LoadStringVal(RomList_GameDir)), stdstr(""), InWatchThread))
{
return false;
}
FileNames.sort();
MD5 NewMd5 = RomListHash(FileNames);
if (memcmp(NewMd5.raw_digest(), CurrentFileMD5, sizeof(CurrentFileMD5)) != 0)
{
return true;
}
return false;
}
void CRomBrowser::WatchRomDirChanged(CRomBrowser * _this)
{
try
{
WriteTrace(TraceUserInterface, TraceDebug, "1");
_this->m_WatchRomDir = g_Settings->LoadStringVal(RomList_GameDir);
WriteTrace(TraceUserInterface, TraceDebug, "2");
if (_this->RomDirNeedsRefresh())
{
WriteTrace(TraceUserInterface, TraceDebug, "2a");
_this->RomDirChanged();
}
WriteTrace(TraceUserInterface, TraceDebug, "3");
HANDLE hChange[] = {
_this->m_WatchStopEvent,
FindFirstChangeNotificationA(_this->m_WatchRomDir.c_str(), g_Settings->LoadBool(RomList_GameDirRecursive), FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE),
};
WriteTrace(TraceUserInterface, TraceDebug, "4");
for (;;)
{
WriteTrace(TraceUserInterface, TraceDebug, "5");
if (WaitForMultipleObjects(sizeof(hChange) / sizeof(hChange[0]), hChange, false, INFINITE) == WAIT_OBJECT_0)
{
WriteTrace(TraceUserInterface, TraceDebug, "5a");
FindCloseChangeNotification(hChange[1]);
return;
}
WriteTrace(TraceUserInterface, TraceDebug, "5b");
if (_this->RomDirNeedsRefresh())
{
_this->RomDirChanged();
}
WriteTrace(TraceUserInterface, TraceDebug, "5c");
if (!FindNextChangeNotification(hChange[1]))
{
FindCloseChangeNotification(hChange[1]);
return;
}
WriteTrace(TraceUserInterface, TraceDebug, "5d");
}
}
catch (...)
{
WriteTrace(TraceUserInterface, TraceError, __FUNCTION__ ": Unhandled Exception");
}
}
void CRomBrowser::WatchThreadStart(void)
{
if (m_WatchThread != nullptr)
{
// Thread already running
return;
}
WriteTrace(TraceUserInterface, TraceDebug, "1");
WatchThreadStop();
WriteTrace(TraceUserInterface, TraceDebug, "2");
if (m_WatchStopEvent == nullptr)
{
m_WatchStopEvent = CreateEvent(nullptr, true, false, nullptr);
}
WriteTrace(TraceUserInterface, TraceDebug, "3");
m_WatchThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)WatchRomDirChanged, this, 0, &m_WatchThreadID);
WriteTrace(TraceUserInterface, TraceDebug, "4");
}
void CRomBrowser::WatchThreadStop(void)
{
if (m_WatchThread == nullptr)
{
return;
}
WriteTrace(TraceUserInterface, TraceDebug, "1");
SetEvent(m_WatchStopEvent);
DWORD ExitCode = 0;
for (int32_t count = 0; count < 20; count++)
{
WriteTrace(TraceUserInterface, TraceDebug, "2");
GetExitCodeThread(m_WatchThread, &ExitCode);
if (ExitCode != STILL_ACTIVE)
{
break;
}
Sleep(200);
}
WriteTrace(TraceUserInterface, TraceDebug, "3");
if (ExitCode == STILL_ACTIVE)
{
WriteTrace(TraceUserInterface, TraceDebug, "3a");
TerminateThread(m_WatchThread, 0);
}
WriteTrace(TraceUserInterface, TraceDebug, "4");
CloseHandle(m_WatchThread);
CloseHandle(m_WatchStopEvent);
m_WatchStopEvent = nullptr;
m_WatchThread = nullptr;
m_WatchThreadID = 0;
WriteTrace(TraceUserInterface, TraceDebug, "5");
}
bool CRomBrowser::GetRomFileNames(strlist & FileList, const CPath & BaseDirectory, const std::string & Directory, bool InWatchThread)
{
if (!BaseDirectory.DirectoryExists())
{
return false;
}
CPath SearchPath(BaseDirectory, "*.*");
SearchPath.AppendDirectory(Directory.c_str());
if (!SearchPath.FindFirst(CPath::FIND_ATTRIBUTE_ALLFILES))
{
return false;
}
do
{
if (InWatchThread && WaitForSingleObject(m_WatchStopEvent, 0) != WAIT_TIMEOUT)
{
return false;
}
if (SearchPath.IsDirectory())
{
if (g_Settings->LoadBool(RomList_GameDirRecursive))
{
CPath CurrentDir(Directory);
CurrentDir.AppendDirectory(SearchPath.GetLastDirectory().c_str());
GetRomFileNames(FileList, BaseDirectory, CurrentDir, InWatchThread);
}
}
else
{
AddFileNameToList(FileList, Directory, SearchPath);
}
} while (SearchPath.FindNext());
return true;
}