mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-12-12 10:37:02 +00:00
Revert use of new, slower wxListCtrl::Set*Images API in game list
The SetImageList gives ListCtrl a pointer to use for the images, which we can then asynchronously load its items from. There's no locking, but before we upgraded it to use the new API it has never really caused any issues. In 40302a706b I upgraded to the recommended API that's mentioned in the wxWidgets docs.
However, the performance, especially with a lot of game titles installed, was quite terrible with this new API due to us needing to call wxListCtrl::Set*Images each time a new icon was loaded, which it'll have to rescale each time for the user's DPI (at least, it seems to spend a long time in a bitmap/icon rescaling method). https://github.com/cemu-project/Cemu/issues/1672 brought this up. So ultimately I think it's just better from a usability standpoint to use the old methods.
Also, I removed some of the hacks that were used for the icon column width size, now that its using the new upstreamed fix. I also added a flag to draw vertical lines between the columns.
This commit is contained in:
parent
474e97454e
commit
c7c7e5c29d
2 changed files with 46 additions and 67 deletions
|
|
@ -144,14 +144,12 @@ wxGameList::wxGameList(wxWindow* parent, wxWindowID id)
|
||||||
memset((void*)transparent_bitmap, wxSystemSettings::GetAppearance().IsDark() ? 0xFF : 0x00, sizeof(transparent_bitmap));
|
memset((void*)transparent_bitmap, wxSystemSettings::GetAppearance().IsDark() ? 0xFF : 0x00, sizeof(transparent_bitmap));
|
||||||
wxBitmap blank(transparent_bitmap, kIconWidth, kIconWidth);
|
wxBitmap blank(transparent_bitmap, kIconWidth, kIconWidth);
|
||||||
|
|
||||||
m_image_list_data = {};
|
m_image_list_data.Replace(0, blank);
|
||||||
m_image_list_data.emplace_back(wxBitmapBundle::FromBitmap(blank));
|
wxListCtrl::SetImageList(&m_image_list_data, wxIMAGE_LIST_NORMAL);
|
||||||
wxListCtrl::SetNormalImages(m_image_list_data);
|
|
||||||
|
|
||||||
m_image_list_small_data = {};
|
|
||||||
wxBitmap::Rescale(blank, {kListIconWidth, kListIconWidth});
|
wxBitmap::Rescale(blank, {kListIconWidth, kListIconWidth});
|
||||||
m_image_list_small_data.emplace_back(wxBitmapBundle::FromBitmap(blank));
|
m_image_list_small_data.Replace(0, blank);
|
||||||
wxListCtrl::SetSmallImages(m_image_list_small_data);
|
wxListCtrl::SetImageList(&m_image_list_small_data, wxIMAGE_LIST_SMALL);
|
||||||
|
|
||||||
InsertColumn(ColumnHiddenName, "", wxLIST_FORMAT_LEFT, 0);
|
InsertColumn(ColumnHiddenName, "", wxLIST_FORMAT_LEFT, 0);
|
||||||
if(config.show_icon_column)
|
if(config.show_icon_column)
|
||||||
|
|
@ -302,12 +300,6 @@ int wxGameList::GetColumnDefaultWidth(int column)
|
||||||
switch (column)
|
switch (column)
|
||||||
{
|
{
|
||||||
case ColumnIcon:
|
case ColumnIcon:
|
||||||
#if __WXMSW__
|
|
||||||
// note: this is another workaround that could be used to fix the icon offset, but instead of this there's a vcpkg patch for wxWidgets that fixes the icon offset
|
|
||||||
// wxWidgets offsets the icon in the REPORT view so it's cut off if the column width is set to 64px, see https://github.com/wxWidgets/wxWidgets/blob/09f433faf39aab3f25b3c564b82448bb845fae56/src/msw/listctrl.cpp#L3091
|
|
||||||
// so add 6px to the column width to compensate, and add another 6px to the right side so that it has equal whitespace on both sides
|
|
||||||
// return kListIconWidth + 6 + 6;
|
|
||||||
#endif
|
|
||||||
return kListIconWidth;
|
return kListIconWidth;
|
||||||
case ColumnName:
|
case ColumnName:
|
||||||
return DefaultColumnSize::name;
|
return DefaultColumnSize::name;
|
||||||
|
|
@ -410,11 +402,13 @@ void wxGameList::SetStyle(Style style, bool save)
|
||||||
switch(style)
|
switch(style)
|
||||||
{
|
{
|
||||||
case Style::kIcons:
|
case Style::kIcons:
|
||||||
wxListCtrl::SetNormalImages(m_image_list_data);
|
wxListCtrl::SetImageList(&m_image_list_data, wxIMAGE_LIST_NORMAL);
|
||||||
break;
|
break;
|
||||||
case Style::kSmallIcons:
|
case Style::kSmallIcons:
|
||||||
|
wxListCtrl::SetImageList(&m_image_list_small_data, wxIMAGE_LIST_NORMAL);
|
||||||
|
break;
|
||||||
case Style::kList:
|
case Style::kList:
|
||||||
wxListCtrl::SetSmallImages(m_image_list_small_data);
|
wxListCtrl::SetImageList(&m_image_list_small_data, wxIMAGE_LIST_SMALL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -443,7 +437,7 @@ long wxGameList::GetStyleFlags(Style style) const
|
||||||
switch (style)
|
switch (style)
|
||||||
{
|
{
|
||||||
case Style::kList:
|
case Style::kList:
|
||||||
return (wxLC_SINGLE_SEL | wxLC_REPORT);
|
return (wxLC_SINGLE_SEL | wxLC_VRULES | wxLC_REPORT);
|
||||||
case Style::kIcons:
|
case Style::kIcons:
|
||||||
return (wxLC_SINGLE_SEL | wxLC_ICON);
|
return (wxLC_SINGLE_SEL | wxLC_ICON);
|
||||||
case Style::kSmallIcons:
|
case Style::kSmallIcons:
|
||||||
|
|
@ -484,7 +478,7 @@ void wxGameList::UpdateItemColors(sint32 startIndex)
|
||||||
|
|
||||||
static inline int order_to_int(const std::weak_ordering &wo)
|
static inline int order_to_int(const std::weak_ordering &wo)
|
||||||
{
|
{
|
||||||
// no easy conversion seems to exists in C++20
|
// no easy conversion seems to exist in C++20
|
||||||
if (wo == std::weak_ordering::less)
|
if (wo == std::weak_ordering::less)
|
||||||
return -1;
|
return -1;
|
||||||
else if (wo == std::weak_ordering::greater)
|
else if (wo == std::weak_ordering::greater)
|
||||||
|
|
@ -514,9 +508,6 @@ std::weak_ordering wxGameList::SortComparator(uint64 titleId1, uint64 titleId2,
|
||||||
return CafeTitleList::GetGameInfo(id).GetRegion();
|
return CafeTitleList::GetGameInfo(id).GetRegion();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!sortData->asc)
|
|
||||||
std::swap(titleId1, titleId2);
|
|
||||||
|
|
||||||
switch(sortData->column)
|
switch(sortData->column)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
|
|
@ -545,7 +536,7 @@ std::weak_ordering wxGameList::SortComparator(uint64 titleId1, uint64 titleId2,
|
||||||
int wxGameList::SortFunction(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
|
int wxGameList::SortFunction(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
|
||||||
{
|
{
|
||||||
const auto sort_data = (SortData*)sortData;
|
const auto sort_data = (SortData*)sortData;
|
||||||
return order_to_int(sort_data->thisptr->SortComparator((uint64)item1, (uint64)item2, sort_data));
|
return sort_data->dir * order_to_int(sort_data->thisptr->SortComparator((uint64)item1, (uint64)item2, sort_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxGameList::SortEntries(int column)
|
void wxGameList::SortEntries(int column)
|
||||||
|
|
@ -569,7 +560,7 @@ void wxGameList::SortEntries(int column)
|
||||||
case ColumnRegion:
|
case ColumnRegion:
|
||||||
case ColumnTitleID:
|
case ColumnTitleID:
|
||||||
{
|
{
|
||||||
SortData data{this, ItemColumns{column}, ascending};
|
SortData data{this, ItemColumns{column}, ascending ? 1 : -1};
|
||||||
SortItems(SortFunction, (wxIntPtr)&data);
|
SortItems(SortFunction, (wxIntPtr)&data);
|
||||||
ShowSortIndicator(column, ascending);
|
ShowSortIndicator(column, ascending);
|
||||||
break;
|
break;
|
||||||
|
|
@ -840,8 +831,8 @@ void wxGameList::OnContextMenuSelected(wxCommandEvent& event)
|
||||||
int icon_small;
|
int icon_small;
|
||||||
if (!QueryIconForTitle(title_id, icon_large, icon_small))
|
if (!QueryIconForTitle(title_id, icon_large, icon_small))
|
||||||
break;
|
break;
|
||||||
auto icon = m_image_list_data[icon_large];
|
auto icon = m_image_list_data.GetIcon(icon_large);
|
||||||
auto newClipboardData = wxBitmapDataObject(icon.GetBitmap(icon.GetDefaultSize()));
|
auto newClipboardData = wxBitmapDataObject(icon);
|
||||||
wxClipboard::Get()->SetData(&newClipboardData);
|
wxClipboard::Get()->SetData(&newClipboardData);
|
||||||
wxClipboard::Get()->Close();
|
wxClipboard::Get()->Close();
|
||||||
}
|
}
|
||||||
|
|
@ -1002,7 +993,7 @@ void wxGameList::ApplyGameListColumnWidths()
|
||||||
const auto& config = GetWxGUIConfig();
|
const auto& config = GetWxGUIConfig();
|
||||||
wxWindowUpdateLocker lock(this);
|
wxWindowUpdateLocker lock(this);
|
||||||
if(config.show_icon_column)
|
if(config.show_icon_column)
|
||||||
SetColumnWidth(ColumnIcon, GetColumnDefaultWidth(ColumnIcon));
|
SetColumnWidth(ColumnIcon, kListIconWidth);
|
||||||
else
|
else
|
||||||
SetColumnWidth(ColumnIcon, 0);
|
SetColumnWidth(ColumnIcon, 0);
|
||||||
SetColumnWidth(ColumnName, config.column_width.name);
|
SetColumnWidth(ColumnName, config.column_width.name);
|
||||||
|
|
@ -1117,19 +1108,6 @@ void wxGameList::OnGameEntryUpdatedByTitleId(wxTitleIdEvent& event)
|
||||||
TitleId baseTitleId = gameInfo.GetBaseTitleId();
|
TitleId baseTitleId = gameInfo.GetBaseTitleId();
|
||||||
bool isNewEntry = false;
|
bool isNewEntry = false;
|
||||||
|
|
||||||
if (m_style == Style::kIcons)
|
|
||||||
{
|
|
||||||
wxListCtrl::SetNormalImages(m_image_list_data);
|
|
||||||
}
|
|
||||||
else if (m_style == Style::kSmallIcons)
|
|
||||||
{
|
|
||||||
wxListCtrl::SetSmallImages(m_image_list_small_data);
|
|
||||||
}
|
|
||||||
else if (m_style == Style::kList)
|
|
||||||
{
|
|
||||||
wxListCtrl::SetSmallImages(m_image_list_small_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
int icon = -1; /* 0 is the default empty icon */
|
int icon = -1; /* 0 is the default empty icon */
|
||||||
int icon_small = -1; /* 0 is the default empty icon */
|
int icon_small = -1; /* 0 is the default empty icon */
|
||||||
QueryIconForTitle(baseTitleId, icon, icon_small);
|
QueryIconForTitle(baseTitleId, icon, icon_small);
|
||||||
|
|
@ -1345,11 +1323,11 @@ void wxGameList::AsyncWorkerThread()
|
||||||
wxMemoryInputStream tmp_stream(tgaData->data(), tgaData->size());
|
wxMemoryInputStream tmp_stream(tgaData->data(), tgaData->size());
|
||||||
const wxImage image(tmp_stream);
|
const wxImage image(tmp_stream);
|
||||||
// todo - is wxImageList thread safe?
|
// todo - is wxImageList thread safe?
|
||||||
m_image_list_data.emplace_back(image.Scale(kIconWidth, kIconWidth, wxIMAGE_QUALITY_BICUBIC));
|
int icon = m_image_list_data.Add(image.Scale(kIconWidth, kIconWidth, wxIMAGE_QUALITY_BICUBIC));
|
||||||
m_image_list_small_data.emplace_back(image.Scale(kListIconWidth, kListIconWidth, wxIMAGE_QUALITY_BICUBIC));
|
int icon_small = m_image_list_small_data.Add(image.Scale(kListIconWidth, kListIconWidth, wxIMAGE_QUALITY_BICUBIC));
|
||||||
// store in cache
|
// store in cache
|
||||||
m_icon_cache_mtx.lock();
|
m_icon_cache_mtx.lock();
|
||||||
m_icon_cache.try_emplace(titleId, m_image_list_data.size() - 1, m_image_list_small_data.size() - 1);
|
m_icon_cache.try_emplace(titleId, icon, icon_small);
|
||||||
m_icon_cache_mtx.unlock();
|
m_icon_cache_mtx.unlock();
|
||||||
iconSuccessfullyLoaded = true;
|
iconSuccessfullyLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
@ -1415,9 +1393,9 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
||||||
// Obtain and convert icon
|
// Obtain and convert icon
|
||||||
[&]()
|
[&]()
|
||||||
{
|
{
|
||||||
int iconIndex, smallIconIndex;
|
int iconIdx, smallIconIdx;
|
||||||
|
|
||||||
if (!QueryIconForTitle(titleId, iconIndex, smallIconIndex))
|
if (!QueryIconForTitle(titleId, iconIdx, smallIconIdx))
|
||||||
{
|
{
|
||||||
cemuLog_log(LogType::Force, "Icon hasn't loaded");
|
cemuLog_log(LogType::Force, "Icon hasn't loaded");
|
||||||
return;
|
return;
|
||||||
|
|
@ -1433,8 +1411,8 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
||||||
iconPath = outIconDir / fmt::format("{:016x}.png", gameInfo.GetBaseTitleId());
|
iconPath = outIconDir / fmt::format("{:016x}.png", gameInfo.GetBaseTitleId());
|
||||||
wxFileOutputStream pngFileStream(_pathToUtf8(iconPath.value()));
|
wxFileOutputStream pngFileStream(_pathToUtf8(iconPath.value()));
|
||||||
|
|
||||||
const auto icon = m_image_list_data[iconIndex];
|
const auto icon = m_image_list_data.GetIcon(iconIdx);
|
||||||
wxBitmap bitmap{icon.GetBitmap(wxDefaultSize)};
|
wxBitmap bitmap{icon};
|
||||||
wxImage image = bitmap.ConvertToImage();
|
wxImage image = bitmap.ConvertToImage();
|
||||||
wxPNGHandler pngHandler;
|
wxPNGHandler pngHandler;
|
||||||
if (!pngHandler.SaveFile(&image, pngFileStream, false))
|
if (!pngHandler.SaveFile(&image, pngFileStream, false))
|
||||||
|
|
@ -1508,9 +1486,9 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
||||||
// Obtain and convert icon
|
// Obtain and convert icon
|
||||||
[&]()
|
[&]()
|
||||||
{
|
{
|
||||||
int iconIndex, smallIconIndex;
|
int iconIdx, smallIconIdx;
|
||||||
|
|
||||||
if (!QueryIconForTitle(titleId, iconIndex, smallIconIndex))
|
if (!QueryIconForTitle(titleId, iconIdx, smallIconIdx))
|
||||||
{
|
{
|
||||||
cemuLog_log(LogType::Force, "Icon hasn't loaded");
|
cemuLog_log(LogType::Force, "Icon hasn't loaded");
|
||||||
return;
|
return;
|
||||||
|
|
@ -1526,8 +1504,8 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
||||||
iconPath = outIconDir / fmt::format("{:016x}.png", gameInfo.GetBaseTitleId());
|
iconPath = outIconDir / fmt::format("{:016x}.png", gameInfo.GetBaseTitleId());
|
||||||
wxFileOutputStream pngFileStream(_pathToUtf8(iconPath.value()));
|
wxFileOutputStream pngFileStream(_pathToUtf8(iconPath.value()));
|
||||||
|
|
||||||
const auto icon = m_image_list_data[iconIndex];
|
const auto icon = m_image_list_data.GetIcon(iconIdx);
|
||||||
wxBitmap bitmap{icon.GetBitmap(wxDefaultSize)};
|
wxBitmap bitmap{icon};
|
||||||
wxImage image = bitmap.ConvertToImage();
|
wxImage image = bitmap.ConvertToImage();
|
||||||
wxPNGHandler pngHandler;
|
wxPNGHandler pngHandler;
|
||||||
if (!pngHandler.SaveFile(&image, pngFileStream, false))
|
if (!pngHandler.SaveFile(&image, pngFileStream, false))
|
||||||
|
|
@ -1635,14 +1613,14 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
||||||
cemuLog_log(LogType::Force, "Icon hasn't loaded");
|
cemuLog_log(LogType::Force, "Icon hasn't loaded");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto icon = m_image_list_data[iconIdx];
|
const auto icon = m_image_list_data.GetIcon(iconIdx);
|
||||||
const auto folder = ActiveSettings::GetUserDataPath("icons");
|
const auto folder = ActiveSettings::GetUserDataPath("icons");
|
||||||
if (!fs::exists(folder) && !fs::create_directories(folder))
|
if (!fs::exists(folder) && !fs::create_directories(folder))
|
||||||
{
|
{
|
||||||
cemuLog_log(LogType::Force, "Failed to create icon directory");
|
cemuLog_log(LogType::Force, "Failed to create icon directory");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wxBitmap bitmap{icon.GetBitmap(wxDefaultSize)};
|
wxBitmap bitmap{icon};
|
||||||
|
|
||||||
icon_path = folder / fmt::format("{:016x}.ico", titleId);
|
icon_path = folder / fmt::format("{:016x}.ico", titleId);
|
||||||
auto stream = wxFileOutputStream(icon_path->wstring());
|
auto stream = wxFileOutputStream(icon_path->wstring());
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ private:
|
||||||
{
|
{
|
||||||
wxGameList* thisptr;
|
wxGameList* thisptr;
|
||||||
ItemColumns column;
|
ItemColumns column;
|
||||||
bool asc;
|
int dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
int FindInsertPosition(TitleId titleId);
|
int FindInsertPosition(TitleId titleId);
|
||||||
|
|
@ -122,7 +122,8 @@ private:
|
||||||
|
|
||||||
inline static constexpr int kListIconWidth = 64;
|
inline static constexpr int kListIconWidth = 64;
|
||||||
inline static constexpr int kIconWidth = 128;
|
inline static constexpr int kIconWidth = 128;
|
||||||
wxWithImages::Images m_image_list_data, m_image_list_small_data;
|
wxImageList m_image_list_data = wxImageList(kIconWidth, kIconWidth, false, 1);
|
||||||
|
wxImageList m_image_list_small_data = wxImageList(kListIconWidth, kListIconWidth, false, 1);
|
||||||
|
|
||||||
std::mutex m_icon_cache_mtx;
|
std::mutex m_icon_cache_mtx;
|
||||||
std::set<TitleId> m_icon_loaded;
|
std::set<TitleId> m_icon_loaded;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue