mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-12-15 01:36:59 +00:00
UI: Upgrade to wxWidgets 3.3.1 and add dark mode support for Windows (#1647)
This commit is contained in:
parent
4efa40c51c
commit
08609591ae
77 changed files with 1224 additions and 1645 deletions
|
|
@ -140,32 +140,33 @@ wxGameList::wxGameList(wxWindow* parent, wxWindowID id)
|
|||
{
|
||||
const auto& config = GetWxGUIConfig();
|
||||
|
||||
char transparent_bitmap[kIconWidth * kIconWidth * 4] = {wxIMAGE_ALPHA_TRANSPARENT};
|
||||
memset((void*)transparent_bitmap, wxIMAGE_ALPHA_TRANSPARENT, sizeof(transparent_bitmap));
|
||||
wxBitmap blank(transparent_bitmap, kIconWidth, kIconWidth);
|
||||
blank.UseAlpha(true);
|
||||
|
||||
m_image_list_data = {};
|
||||
m_image_list_data.emplace_back(wxBitmapBundle::FromBitmap(blank));
|
||||
wxListCtrl::SetNormalImages(m_image_list_data);
|
||||
|
||||
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);
|
||||
|
||||
InsertColumn(ColumnHiddenName, "", wxLIST_FORMAT_LEFT, 0);
|
||||
if(config.show_icon_column)
|
||||
InsertColumn(ColumnIcon, _("Icon"), wxLIST_FORMAT_LEFT, kListIconWidth);
|
||||
InsertColumn(ColumnIcon, _("Icon"), wxLIST_FORMAT_LEFT, GetColumnDefaultWidth(ColumnIcon));
|
||||
else
|
||||
InsertColumn(ColumnIcon, _("Icon"), wxLIST_FORMAT_LEFT, 0);
|
||||
InsertColumn(ColumnName, _("Game"), wxLIST_FORMAT_LEFT, config.column_width.name);
|
||||
InsertColumn(ColumnVersion, _("Version"), wxLIST_FORMAT_RIGHT, config.column_width.version);
|
||||
InsertColumn(ColumnDLC, _("DLC"), wxLIST_FORMAT_RIGHT, config.column_width.dlc);
|
||||
InsertColumn(ColumnVersion, _("Version"), wxLIST_FORMAT_LEFT, config.column_width.version);
|
||||
InsertColumn(ColumnDLC, _("DLC"), wxLIST_FORMAT_LEFT, config.column_width.dlc);
|
||||
InsertColumn(ColumnGameTime, _("You've played"), wxLIST_FORMAT_LEFT, config.column_width.game_time);
|
||||
InsertColumn(ColumnGameStarted, _("Last played"), wxLIST_FORMAT_LEFT, config.column_width.game_started);
|
||||
InsertColumn(ColumnRegion, _("Region"), wxLIST_FORMAT_LEFT, config.column_width.region);
|
||||
InsertColumn(ColumnTitleID, _("Title ID"), wxLIST_FORMAT_LEFT, config.column_width.title_id);
|
||||
|
||||
const char transparent_bitmap[kIconWidth * kIconWidth * 4] = {0};
|
||||
wxBitmap blank(transparent_bitmap, kIconWidth, kIconWidth);
|
||||
blank.UseAlpha(true);
|
||||
|
||||
m_image_list = new wxImageList(kIconWidth, kIconWidth);
|
||||
m_image_list->Add(blank);
|
||||
wxListCtrl::SetImageList(m_image_list, wxIMAGE_LIST_NORMAL);
|
||||
|
||||
m_image_list_small = new wxImageList(kListIconWidth, kListIconWidth);
|
||||
wxBitmap::Rescale(blank, {kListIconWidth, kListIconWidth});
|
||||
m_image_list_small->Add(blank);
|
||||
wxListCtrl::SetImageList(m_image_list_small, wxIMAGE_LIST_SMALL);
|
||||
|
||||
m_tooltip_window = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER);
|
||||
auto* tooltip_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
tooltip_sizer->Add(new wxStaticText(m_tooltip_window, wxID_ANY, _("This game entry seems to be either an update or the base game was merged with update data\nBroken game dumps cause various problems during emulation and may even stop working at all in future Cemu versions\nPlease make sure the base game is intact and install updates only with the File->Install Update/DLC option")), 0, wxALL, 5);
|
||||
|
|
@ -210,10 +211,6 @@ wxGameList::~wxGameList()
|
|||
m_async_task_count.increment();
|
||||
m_async_worker_thread.join();
|
||||
|
||||
// destroy image lists
|
||||
delete m_image_list;
|
||||
delete m_image_list_small;
|
||||
|
||||
// clear image cache
|
||||
m_icon_cache_mtx.lock();
|
||||
m_icon_cache.clear();
|
||||
|
|
@ -306,6 +303,12 @@ 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;
|
||||
|
|
@ -408,10 +411,11 @@ void wxGameList::SetStyle(Style style, bool save)
|
|||
switch(style)
|
||||
{
|
||||
case Style::kIcons:
|
||||
wxListCtrl::SetImageList(m_image_list, wxIMAGE_LIST_NORMAL);
|
||||
wxListCtrl::SetNormalImages(m_image_list_data);
|
||||
break;
|
||||
case Style::kSmallIcons:
|
||||
wxListCtrl::SetImageList(m_image_list_small, wxIMAGE_LIST_NORMAL);
|
||||
case Style::kList:
|
||||
wxListCtrl::SetSmallImages(m_image_list_small_data);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -464,7 +468,7 @@ void wxGameList::UpdateItemColors(sint32 startIndex)
|
|||
if (GetConfig().IsGameListFavorite(titleId))
|
||||
{
|
||||
SetItemBackgroundColour(i, kFavoriteColor);
|
||||
SetItemTextColour(i, 0x000000UL);
|
||||
SetItemTextColour(i, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
|
||||
}
|
||||
else if ((i&1) != 0)
|
||||
{
|
||||
|
|
@ -638,6 +642,7 @@ enum ContextMenuEntries
|
|||
kContextMenuCopyTitleId,
|
||||
kContextMenuCopyTitleImage
|
||||
};
|
||||
|
||||
void wxGameList::OnContextMenu(wxContextMenuEvent& event)
|
||||
{
|
||||
auto& config = GetConfig();
|
||||
|
|
@ -809,33 +814,34 @@ void wxGameList::OnContextMenuSelected(wxCommandEvent& event)
|
|||
}
|
||||
case kContextMenuCopyTitleName:
|
||||
{
|
||||
if (wxTheClipboard->Open())
|
||||
if (wxClipboard::Get()->Open())
|
||||
{
|
||||
wxTheClipboard->SetData(new wxTextDataObject(wxString::FromUTF8(gameInfo.GetTitleName())));
|
||||
wxTheClipboard->Close();
|
||||
wxClipboard::Get()->SetData(new wxTextDataObject(wxString::FromUTF8(gameInfo.GetTitleName())));
|
||||
wxClipboard::Get()->Close();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kContextMenuCopyTitleId:
|
||||
{
|
||||
if (wxTheClipboard->Open())
|
||||
if (wxClipboard::Get()->Open())
|
||||
{
|
||||
wxTheClipboard->SetData(new wxTextDataObject(fmt::format("{:016x}", gameInfo.GetBaseTitleId())));
|
||||
wxTheClipboard->Close();
|
||||
wxClipboard::Get()->SetData(new wxTextDataObject(fmt::format("{:016x}", gameInfo.GetBaseTitleId())));
|
||||
wxClipboard::Get()->Close();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kContextMenuCopyTitleImage:
|
||||
{
|
||||
if (wxTheClipboard->Open())
|
||||
if (wxClipboard::Get()->Open())
|
||||
{
|
||||
int icon_large;
|
||||
int icon_small;
|
||||
if (!QueryIconForTitle(title_id, icon_large, icon_small))
|
||||
break;
|
||||
auto icon = m_image_list->GetBitmap(icon_large);
|
||||
wxTheClipboard->SetData(new wxBitmapDataObject(icon));
|
||||
wxTheClipboard->Close();
|
||||
auto icon = m_image_list_data[icon_large];
|
||||
auto newClipboardData = wxBitmapDataObject(icon.GetBitmap(icon.GetDefaultSize()));
|
||||
wxClipboard::Get()->SetData(&newClipboardData);
|
||||
wxClipboard::Get()->Close();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -994,7 +1000,7 @@ void wxGameList::ApplyGameListColumnWidths()
|
|||
const auto& config = GetWxGUIConfig();
|
||||
wxWindowUpdateLocker lock(this);
|
||||
if(config.show_icon_column)
|
||||
SetColumnWidth(ColumnIcon, kListIconWidth);
|
||||
SetColumnWidth(ColumnIcon, GetColumnDefaultWidth(ColumnIcon));
|
||||
else
|
||||
SetColumnWidth(ColumnIcon, 0);
|
||||
SetColumnWidth(ColumnName, config.column_width.name);
|
||||
|
|
@ -1109,6 +1115,23 @@ 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);
|
||||
|
||||
auto index = FindListItemByTitleId(baseTitleId);
|
||||
if(index == wxNOT_FOUND)
|
||||
{
|
||||
|
|
@ -1118,10 +1141,6 @@ void wxGameList::OnGameEntryUpdatedByTitleId(wxTitleIdEvent& event)
|
|||
isNewEntry = true;
|
||||
}
|
||||
|
||||
int icon = 0; /* 0 is the default empty icon */
|
||||
int icon_small = 0; /* 0 is the default empty icon */
|
||||
QueryIconForTitle(baseTitleId, icon, icon_small);
|
||||
|
||||
if (m_style == Style::kList)
|
||||
{
|
||||
SetItemColumnImage(index, ColumnIcon, icon_small);
|
||||
|
|
@ -1324,17 +1343,18 @@ void wxGameList::AsyncWorkerThread()
|
|||
wxMemoryInputStream tmp_stream(tgaData->data(), tgaData->size());
|
||||
const wxImage image(tmp_stream);
|
||||
// todo - is wxImageList thread safe?
|
||||
int icon = m_image_list->Add(image.Scale(kIconWidth, kIconWidth, wxIMAGE_QUALITY_BICUBIC));
|
||||
int icon_small = m_image_list_small->Add(image.Scale(kListIconWidth, kListIconWidth, wxIMAGE_QUALITY_BICUBIC));
|
||||
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));
|
||||
// store in cache
|
||||
m_icon_cache_mtx.lock();
|
||||
m_icon_cache.try_emplace(titleId, icon, icon_small);
|
||||
m_icon_cache.try_emplace(titleId, m_image_list_data.size() - 1, m_image_list_small_data.size() - 1);
|
||||
m_icon_cache_mtx.unlock();
|
||||
iconSuccessfullyLoaded = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Failed to load icon for title {:016x}", titleId);
|
||||
cemu_assert_debug(false);
|
||||
}
|
||||
titleInfo.Unmount(tempMountPath);
|
||||
// notify UI about loaded icon
|
||||
|
|
@ -1411,7 +1431,9 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
|||
iconPath = outIconDir / fmt::format("{:016x}.png", gameInfo.GetBaseTitleId());
|
||||
wxFileOutputStream pngFileStream(_pathToUtf8(iconPath.value()));
|
||||
|
||||
auto image = m_image_list->GetIcon(iconIndex).ConvertToImage();
|
||||
const auto icon = m_image_list_data[iconIndex];
|
||||
wxBitmap bitmap{icon.GetBitmap(wxDefaultSize)};
|
||||
wxImage image = bitmap.ConvertToImage();
|
||||
wxPNGHandler pngHandler;
|
||||
if (!pngHandler.SaveFile(&image, pngFileStream, false))
|
||||
{
|
||||
|
|
@ -1502,7 +1524,9 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
|||
iconPath = outIconDir / fmt::format("{:016x}.png", gameInfo.GetBaseTitleId());
|
||||
wxFileOutputStream pngFileStream(_pathToUtf8(iconPath.value()));
|
||||
|
||||
auto image = m_image_list->GetIcon(iconIndex).ConvertToImage();
|
||||
const auto icon = m_image_list_data[iconIndex];
|
||||
wxBitmap bitmap{icon.GetBitmap(wxDefaultSize)};
|
||||
wxImage image = bitmap.ConvertToImage();
|
||||
wxPNGHandler pngHandler;
|
||||
if (!pngHandler.SaveFile(&image, pngFileStream, false))
|
||||
{
|
||||
|
|
@ -1609,19 +1633,14 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
|||
cemuLog_log(LogType::Force, "Icon hasn't loaded");
|
||||
return;
|
||||
}
|
||||
const auto icon = m_image_list->GetIcon(iconIdx);
|
||||
const auto icon = m_image_list_data[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{};
|
||||
if (!bitmap.CopyFromIcon(icon))
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Failed to copy icon");
|
||||
return;
|
||||
}
|
||||
wxBitmap bitmap{icon.GetBitmap(wxDefaultSize)};
|
||||
|
||||
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