mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-12-14 16:37:00 +00:00
UI: Improvements and fixes for Windows dark mode (#1728)
This commit is contained in:
parent
1382ee0381
commit
934cc3eb9d
17 changed files with 180 additions and 203 deletions
|
|
@ -141,17 +141,15 @@ wxGameList::wxGameList(wxWindow* parent, wxWindowID id)
|
|||
const auto& config = GetWxGUIConfig();
|
||||
|
||||
char transparent_bitmap[kIconWidth * kIconWidth * 4] = {};
|
||||
memset((void*)transparent_bitmap, wxSystemSettings::GetAppearance().IsDark() ? 0xFF : 0x00, sizeof(transparent_bitmap));
|
||||
memset(transparent_bitmap, wxSystemSettings::GetAppearance().IsDark() ? 0xFF : 0x00, sizeof(transparent_bitmap));
|
||||
wxBitmap blank(transparent_bitmap, kIconWidth, kIconWidth);
|
||||
|
||||
m_image_list_data = {};
|
||||
m_image_list_data.emplace_back(wxBitmapBundle::FromBitmap(blank));
|
||||
wxListCtrl::SetNormalImages(m_image_list_data);
|
||||
m_image_list_data.Add(blank);
|
||||
wxListCtrl::SetImageList(&m_image_list_data, wxIMAGE_LIST_NORMAL);
|
||||
|
||||
m_image_list_small_data = {};
|
||||
wxBitmap::Rescale(blank, {kListIconWidth, kListIconWidth});
|
||||
m_image_list_small_data.emplace_back(wxBitmapBundle::FromBitmap(blank));
|
||||
wxListCtrl::SetSmallImages(m_image_list_small_data);
|
||||
m_image_list_small_data.Add(blank);
|
||||
wxListCtrl::SetImageList(&m_image_list_small_data, wxIMAGE_LIST_SMALL);
|
||||
|
||||
InsertColumn(ColumnHiddenName, "", wxLIST_FORMAT_LEFT, 0);
|
||||
if(config.show_icon_column)
|
||||
|
|
@ -251,13 +249,13 @@ void wxGameList::OnGameListSize(wxSizeEvent &event)
|
|||
for(int i = GetColumnCount() - 1; i > 0; i--)
|
||||
{
|
||||
#ifdef wxHAS_LISTCTRL_COLUMN_ORDER
|
||||
if(GetColumnWidth(GetColumnIndexFromOrder(i)) > 0)
|
||||
if(GetColumnWidth(GetColumnIndexFromOrder(i)) > 0)
|
||||
{
|
||||
last_col_index = GetColumnIndexFromOrder(i);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
if(GetColumnWidth(i) > 0)
|
||||
if(GetColumnWidth(i) > 0)
|
||||
{
|
||||
last_col_index = i;
|
||||
break;
|
||||
|
|
@ -302,12 +300,6 @@ int wxGameList::GetColumnDefaultWidth(int column)
|
|||
switch (column)
|
||||
{
|
||||
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;
|
||||
case ColumnName:
|
||||
return DefaultColumnSize::name;
|
||||
|
|
@ -410,11 +402,13 @@ void wxGameList::SetStyle(Style style, bool save)
|
|||
switch(style)
|
||||
{
|
||||
case Style::kIcons:
|
||||
wxListCtrl::SetNormalImages(m_image_list_data);
|
||||
wxListCtrl::SetImageList(&m_image_list_data, wxIMAGE_LIST_NORMAL);
|
||||
break;
|
||||
case Style::kSmallIcons:
|
||||
wxListCtrl::SetImageList(&m_image_list_small_data, wxIMAGE_LIST_NORMAL);
|
||||
break;
|
||||
case Style::kList:
|
||||
wxListCtrl::SetSmallImages(m_image_list_small_data);
|
||||
wxListCtrl::SetImageList(&m_image_list_small_data, wxIMAGE_LIST_SMALL);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -443,7 +437,7 @@ long wxGameList::GetStyleFlags(Style style) const
|
|||
switch (style)
|
||||
{
|
||||
case Style::kList:
|
||||
return (wxLC_SINGLE_SEL | wxLC_REPORT);
|
||||
return (wxLC_SINGLE_SEL | wxLC_VRULES | wxLC_REPORT);
|
||||
case Style::kIcons:
|
||||
return (wxLC_SINGLE_SEL | wxLC_ICON);
|
||||
case Style::kSmallIcons:
|
||||
|
|
@ -458,25 +452,22 @@ void wxGameList::UpdateItemColors(sint32 startIndex)
|
|||
{
|
||||
wxWindowUpdateLocker lock(this);
|
||||
|
||||
wxColour bgColourPrimary = GetBackgroundColour();
|
||||
wxColour bgColourSecondary = wxHelper::CalculateAccentColour(bgColourPrimary);
|
||||
|
||||
for (int i = startIndex; i < GetItemCount(); ++i)
|
||||
{
|
||||
const auto titleId = (uint64)GetItemData(i);
|
||||
const uint64 titleId = GetItemData(i);
|
||||
if (GetConfig().IsGameListFavorite(titleId))
|
||||
{
|
||||
SetItemBackgroundColour(i, kFavoriteColor);
|
||||
SetItemTextColour(i, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
|
||||
}
|
||||
else if ((i&1) != 0)
|
||||
else if ((i % 2) != 0)
|
||||
{
|
||||
SetItemBackgroundColour(i, bgColourPrimary);
|
||||
SetItemBackgroundColour(i, kPrimaryColor);
|
||||
SetItemTextColour(i, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
|
||||
}
|
||||
else
|
||||
{
|
||||
SetItemBackgroundColour(i, bgColourSecondary);
|
||||
SetItemBackgroundColour(i, kAlternateColor);
|
||||
SetItemTextColour(i, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
|
||||
}
|
||||
}
|
||||
|
|
@ -484,7 +475,7 @@ void wxGameList::UpdateItemColors(sint32 startIndex)
|
|||
|
||||
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)
|
||||
return -1;
|
||||
else if (wo == std::weak_ordering::greater)
|
||||
|
|
@ -496,27 +487,24 @@ std::weak_ordering wxGameList::SortComparator(uint64 titleId1, uint64 titleId2,
|
|||
{
|
||||
auto titleLastPlayed = [](uint64_t id)
|
||||
{
|
||||
iosu::pdm::GameListStat playTimeStat{};
|
||||
iosu::pdm::GetStatForGamelist(id, playTimeStat);
|
||||
return playTimeStat;
|
||||
iosu::pdm::GameListStat playTimeStat{};
|
||||
iosu::pdm::GetStatForGamelist(id, playTimeStat);
|
||||
return playTimeStat;
|
||||
};
|
||||
|
||||
auto titlePlayMinutes = [](uint64_t id)
|
||||
{
|
||||
iosu::pdm::GameListStat playTimeStat;
|
||||
if (!iosu::pdm::GetStatForGamelist(id, playTimeStat))
|
||||
return 0u;
|
||||
return playTimeStat.numMinutesPlayed;
|
||||
iosu::pdm::GameListStat playTimeStat;
|
||||
if (!iosu::pdm::GetStatForGamelist(id, playTimeStat))
|
||||
return 0u;
|
||||
return playTimeStat.numMinutesPlayed;
|
||||
};
|
||||
|
||||
auto titleRegion = [](uint64_t id)
|
||||
{
|
||||
return CafeTitleList::GetGameInfo(id).GetRegion();
|
||||
return CafeTitleList::GetGameInfo(id).GetRegion();
|
||||
};
|
||||
|
||||
if (!sortData->asc)
|
||||
std::swap(titleId1, titleId2);
|
||||
|
||||
switch(sortData->column)
|
||||
{
|
||||
default:
|
||||
|
|
@ -545,7 +533,7 @@ std::weak_ordering wxGameList::SortComparator(uint64 titleId1, uint64 titleId2,
|
|||
int wxGameList::SortFunction(wxIntPtr item1, wxIntPtr item2, wxIntPtr 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)
|
||||
|
|
@ -569,7 +557,7 @@ void wxGameList::SortEntries(int column)
|
|||
case ColumnRegion:
|
||||
case ColumnTitleID:
|
||||
{
|
||||
SortData data{this, ItemColumns{column}, ascending};
|
||||
SortData data{this, ItemColumns{column}, ascending ? 1 : -1};
|
||||
SortItems(SortFunction, (wxIntPtr)&data);
|
||||
ShowSortIndicator(column, ascending);
|
||||
break;
|
||||
|
|
@ -840,8 +828,8 @@ void wxGameList::OnContextMenuSelected(wxCommandEvent& event)
|
|||
int icon_small;
|
||||
if (!QueryIconForTitle(title_id, icon_large, icon_small))
|
||||
break;
|
||||
auto icon = m_image_list_data[icon_large];
|
||||
auto newClipboardData = wxBitmapDataObject(icon.GetBitmap(icon.GetDefaultSize()));
|
||||
auto icon = m_image_list_data.GetIcon(icon_large);
|
||||
auto newClipboardData = wxBitmapDataObject(icon);
|
||||
wxClipboard::Get()->SetData(&newClipboardData);
|
||||
wxClipboard::Get()->Close();
|
||||
}
|
||||
|
|
@ -1002,7 +990,7 @@ void wxGameList::ApplyGameListColumnWidths()
|
|||
const auto& config = GetWxGUIConfig();
|
||||
wxWindowUpdateLocker lock(this);
|
||||
if(config.show_icon_column)
|
||||
SetColumnWidth(ColumnIcon, GetColumnDefaultWidth(ColumnIcon));
|
||||
SetColumnWidth(ColumnIcon, kListIconWidth);
|
||||
else
|
||||
SetColumnWidth(ColumnIcon, 0);
|
||||
SetColumnWidth(ColumnName, config.column_width.name);
|
||||
|
|
@ -1024,13 +1012,13 @@ void wxGameList::OnColumnBeginResize(wxListEvent& event)
|
|||
for(int i = GetColumnCount() - 1; i > 0; i--)
|
||||
{
|
||||
#ifdef wxHAS_LISTCTRL_COLUMN_ORDER
|
||||
if(GetColumnWidth(GetColumnIndexFromOrder(i)) > 0)
|
||||
if(GetColumnWidth(GetColumnIndexFromOrder(i)) > 0)
|
||||
{
|
||||
last_col_index = GetColumnIndexFromOrder(i);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
if(GetColumnWidth(i) > 0)
|
||||
if(GetColumnWidth(i) > 0)
|
||||
{
|
||||
last_col_index = i;
|
||||
break;
|
||||
|
|
@ -1117,19 +1105,6 @@ void wxGameList::OnGameEntryUpdatedByTitleId(wxTitleIdEvent& event)
|
|||
TitleId baseTitleId = gameInfo.GetBaseTitleId();
|
||||
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_small = -1; /* 0 is the default empty icon */
|
||||
QueryIconForTitle(baseTitleId, icon, icon_small);
|
||||
|
|
@ -1175,7 +1150,7 @@ void wxGameList::OnGameEntryUpdatedByTitleId(wxTitleIdEvent& event)
|
|||
wxString minutesText = formatWxString(wxPLURAL("{} minute", "{} minutes", minutes), minutes);
|
||||
SetItem(index, ColumnGameTime, hoursText + " " + minutesText);
|
||||
}
|
||||
|
||||
|
||||
// last played
|
||||
if (playTimeStat.last_played.year != 0)
|
||||
{
|
||||
|
|
@ -1345,11 +1320,11 @@ void wxGameList::AsyncWorkerThread()
|
|||
wxMemoryInputStream tmp_stream(tgaData->data(), tgaData->size());
|
||||
const wxImage image(tmp_stream);
|
||||
// todo - is wxImageList thread safe?
|
||||
m_image_list_data.emplace_back(image.Scale(kIconWidth, kIconWidth, wxIMAGE_QUALITY_BICUBIC));
|
||||
m_image_list_small_data.emplace_back(image.Scale(kListIconWidth, kListIconWidth, wxIMAGE_QUALITY_BICUBIC));
|
||||
int icon = m_image_list_data.Add(image.Scale(kIconWidth, kIconWidth, wxIMAGE_QUALITY_BICUBIC));
|
||||
int icon_small = m_image_list_small_data.Add(image.Scale(kListIconWidth, kListIconWidth, wxIMAGE_QUALITY_BICUBIC));
|
||||
// store in cache
|
||||
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();
|
||||
iconSuccessfullyLoaded = true;
|
||||
}
|
||||
|
|
@ -1390,7 +1365,7 @@ bool wxGameList::QueryIconForTitle(TitleId titleId, int& icon, int& iconSmall)
|
|||
return true;
|
||||
}
|
||||
|
||||
void wxGameList::DeleteCachedStrings()
|
||||
void wxGameList::DeleteCachedStrings()
|
||||
{
|
||||
m_name_cache.clear();
|
||||
}
|
||||
|
|
@ -1415,9 +1390,9 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
|||
// 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");
|
||||
return;
|
||||
|
|
@ -1433,8 +1408,8 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
|||
iconPath = outIconDir / fmt::format("{:016x}.png", gameInfo.GetBaseTitleId());
|
||||
wxFileOutputStream pngFileStream(_pathToUtf8(iconPath.value()));
|
||||
|
||||
const auto icon = m_image_list_data[iconIndex];
|
||||
wxBitmap bitmap{icon.GetBitmap(wxDefaultSize)};
|
||||
const auto icon = m_image_list_data.GetIcon(iconIdx);
|
||||
wxBitmap bitmap{icon};
|
||||
wxImage image = bitmap.ConvertToImage();
|
||||
wxPNGHandler pngHandler;
|
||||
if (!pngHandler.SaveFile(&image, pngFileStream, false))
|
||||
|
|
@ -1508,9 +1483,9 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
|||
// 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");
|
||||
return;
|
||||
|
|
@ -1526,8 +1501,8 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
|||
iconPath = outIconDir / fmt::format("{:016x}.png", gameInfo.GetBaseTitleId());
|
||||
wxFileOutputStream pngFileStream(_pathToUtf8(iconPath.value()));
|
||||
|
||||
const auto icon = m_image_list_data[iconIndex];
|
||||
wxBitmap bitmap{icon.GetBitmap(wxDefaultSize)};
|
||||
const auto icon = m_image_list_data.GetIcon(iconIdx);
|
||||
wxBitmap bitmap{icon};
|
||||
wxImage image = bitmap.ConvertToImage();
|
||||
wxPNGHandler pngHandler;
|
||||
if (!pngHandler.SaveFile(&image, pngFileStream, false))
|
||||
|
|
@ -1635,14 +1610,14 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
|||
cemuLog_log(LogType::Force, "Icon hasn't loaded");
|
||||
return;
|
||||
}
|
||||
const auto icon = m_image_list_data[iconIdx];
|
||||
const auto icon = m_image_list_data.GetIcon(iconIdx);
|
||||
const auto folder = ActiveSettings::GetUserDataPath("icons");
|
||||
if (!fs::exists(folder) && !fs::create_directories(folder))
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Failed to create icon directory");
|
||||
return;
|
||||
}
|
||||
wxBitmap bitmap{icon.GetBitmap(wxDefaultSize)};
|
||||
wxBitmap bitmap{icon};
|
||||
|
||||
icon_path = folder / fmt::format("{:016x}.ico", titleId);
|
||||
auto stream = wxFileOutputStream(icon_path->wstring());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue