UI: Improvements and fixes for Windows dark mode (#1728)

This commit is contained in:
Crementif 2025-11-22 23:26:27 +01:00 committed by GitHub
parent 1382ee0381
commit 934cc3eb9d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 180 additions and 203 deletions

View file

@ -5,6 +5,7 @@ project(wxwidgets-example)
add_executable(main WIN32 popup.cpp)
find_package(wxWidgets REQUIRED)
target_compile_features(main PRIVATE cxx_std_11)
target_compile_definitions(main PRIVATE ${wxWidgets_DEFINITIONS} "$<$<CONFIG:DEBUG>:${wxWidgets_DEFINITIONS_DEBUG}>")
target_include_directories(main PRIVATE ${wxWidgets_INCLUDE_DIRS})
target_link_libraries(main PRIVATE ${wxWidgets_LIBRARIES})
@ -13,6 +14,7 @@ add_executable(main2 WIN32 popup.cpp)
find_package(wxWidgets CONFIG REQUIRED)
target_link_libraries(main2 PRIVATE wx::core wx::base)
target_compile_features(main2 PRIVATE cxx_std_11)
option(USE_WXRC "Use the wxrc resource compiler" ON)
if(USE_WXRC)

View file

@ -1,25 +0,0 @@
diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp
index 2b9e0d7f7e..7eab8b37df 100644
--- a/src/msw/listctrl.cpp
+++ b/src/msw/listctrl.cpp
@@ -3110,6 +3110,11 @@ bool HandleSubItemPrepaint(wxListCtrl* listctrl, LPNMLVCUSTOMDRAW pLVCD, HFONT h
if ( it.iImage != -1 )
{
+ if ( !listctrl->HasCheckBoxes() )
+ {
+ rc.left -= 6;
+ }
+
const int yImage = rc.top + ((rc.bottom - rc.top) / 2 - hImage / 2);
ImageList_Draw(himl, it.iImage, hdc, rc.left, yImage,
nmcd.uItemState & CDIS_SELECTED ? ILD_SELECTED
@@ -3235,7 +3240,7 @@ void HandleItemPaint(wxListCtrl* listctrl, LPNMLVCUSTOMDRAW pLVCD, HFONT hfont)
// do not draw item background colour under the checkbox/image
RECT rcIcon;
wxGetListCtrlItemRect(nmcd.hdr.hwndFrom, nmcd.dwItemSpec, LVIR_ICON, rcIcon);
- if ( !::IsRectEmpty(&rcIcon) )
+ if ( !::IsRectEmpty(&rcIcon) && listctrl->HasCheckBoxes() )
rc.left = rcIcon.right + listctrl->FromDIP(GAP_BETWEEN_CHECKBOX_AND_TEXT);
}

View file

@ -1,39 +1,45 @@
diff --git a/build/cmake/init.cmake b/build/cmake/init.cmake
index f044d22d4d..48fc5ad072 100644
index 4ed7b264ef..195d776aeb 100644
--- a/build/cmake/init.cmake
+++ b/build/cmake/init.cmake
@@ -198,7 +198,7 @@ if(WIN32)
endif()
endif()
-if(WIN32_MSVC_NAMING)
+if(0)
@@ -201,11 +201,11 @@ endif()
wx_get_install_dir(include)
if(WIN32_MSVC_NAMING)
if(wxBUILD_SHARED)
set(lib_suffix "_dll")
- set(lib_suffix "_dll")
+ # set(lib_suffix "_dll")
else()
- set(lib_suffix "_lib")
+ # set(lib_suffix "_lib")
endif()
- set(wxPLATFORM_LIB_DIR "${wxCOMPILER_PREFIX}${wxARCH_SUFFIX}${lib_suffix}")
+ # set(wxPLATFORM_LIB_DIR "${wxCOMPILER_PREFIX}${wxARCH_SUFFIX}${lib_suffix}")
set(wxINSTALL_INCLUDE_DIR "${include_dir}")
else()
wx_get_flavour(lib_flavour "-")
diff --git a/build/cmake/install.cmake b/build/cmake/install.cmake
index a373983043..2e1ace7bf9 100644
index cbbefdebe9..8f2759d5ad 100644
--- a/build/cmake/install.cmake
+++ b/build/cmake/install.cmake
@@ -63,7 +63,7 @@ else()
install(DIRECTORY DESTINATION "bin")
@@ -66,7 +66,7 @@ else()
wx_get_install_platform_dir(runtime)
install(DIRECTORY DESTINATION "${runtime_dir}")
install(CODE "execute_process( \
- COMMAND ${CMAKE_COMMAND} -E create_symlink \
+ COMMAND ${CMAKE_COMMAND} -E copy \
\"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/wx/config/${wxBUILD_FILE_ID}\" \
\"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/wx-config\" \
\"${CMAKE_INSTALL_PREFIX}/${library_dir}/wx/config/${wxBUILD_FILE_ID}\" \
\"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${runtime_dir}/wx-config\" \
)"
diff --git a/build/cmake/utils/CMakeLists.txt b/build/cmake/utils/CMakeLists.txt
index 15f4339ef9..f93849e025 100644
index 608351ac42..d8110f9148 100644
--- a/build/cmake/utils/CMakeLists.txt
+++ b/build/cmake/utils/CMakeLists.txt
@@ -39,7 +39,7 @@ if(wxUSE_XRC)
@@ -40,7 +40,7 @@ if(wxUSE_XRC)
# Don't use wx_install() here to preserve escaping.
install(CODE "execute_process( \
- COMMAND ${CMAKE_COMMAND} -E create_symlink \
+ COMMAND ${CMAKE_COMMAND} -E copy \
\"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/${wxrc_output_name}${EXE_SUFFIX}\" \
\"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/wxrc${EXE_SUFFIX}\" \
\"${CMAKE_INSTALL_PREFIX}/${runtime_dir}/${wxrc_output_name}${EXE_SUFFIX}\" \
\"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${runtime_dir}/wxrc${EXE_SUFFIX}\" \
)"

View file

@ -1,13 +1,12 @@
diff --git a/build/cmake/wxWidgetsConfig.cmake.in b/build/cmake/wxWidgetsConfig.cmake.in
index b251109..60cf762 100644
index 2f3a735d92..c134900764 100644
--- a/build/cmake/wxWidgetsConfig.cmake.in
+++ b/build/cmake/wxWidgetsConfig.cmake.in
@@ -1,5 +1,8 @@
@PACKAGE_INIT@
@@ -155,6 +155,7 @@ foreach(libname @wxLIB_TARGETS@)
endforeach()
+include(CMakeFindDependencyMacro)
include(CMakeFindDependencyMacro)
+find_dependency(NanoSVG CONFIG)
+
cmake_policy(PUSH)
# Set policies to prevent warnings
if(POLICY CMP0057)
if(TARGET wx::wxnet AND @wxUSE_WEBREQUEST_CURL@)
# make sure CURL targets are available:

View file

@ -1,8 +1,8 @@
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
REPO wxWidgets/wxWidgets
REF "v${VERSION}"
SHA512 8ad17582c4ba721ffe76ada4bb8bd7bc4b050491220aca335fd0506a51354fb789d5bc3d965f0f459dc81784d6427c88272e2acc2099cddf73730231b5a16f62
REF "bfd436b"
SHA512 bd3fd6d0d0db3b6fa34eceae1119e21ffd2f62221dcd249f8b8b82a6e65d83a05101e4e1e4ca9b9c4d7937add73b113bb029b03b05d2c3d87d17c1922d800a24
HEAD_REF master
PATCHES
install-layout.patch
@ -12,9 +12,26 @@ vcpkg_from_github(
fix-pcre2.patch
gtk3-link-libraries.patch
sdl2.patch
fix-dark-mode-offset.patch
)
# Submodule dependencies
vcpkg_from_github(
OUT_SOURCE_PATH lexilla_SOURCE_PATH
REPO wxWidgets/lexilla
REF "27c20a6ae5eebf418debeac0166052ed6fb653bc"
SHA512 7e5de7f664509473b691af8261fca34c2687772faca7260eeba5f2984516e6f8edf88c27192e056c9dda996e2ad2c20f6d1dff1c4bd2f3c0d74852cb50ca424a
HEAD_REF wx
)
file(COPY "${lexilla_SOURCE_PATH}/" DESTINATION "${SOURCE_PATH}/src/stc/lexilla")
vcpkg_from_github(
OUT_SOURCE_PATH scintilla_SOURCE_PATH
REPO wxWidgets/scintilla
REF "0b90f31ced23241054e8088abb50babe9a44ae67"
SHA512 db1f3007f4bd8860fad0817b6cf87980a4b713777025128cf5caea8d6d17b6fafe23fd22ff6886d7d5a420f241d85b7502b85d7e52b4ddb0774edc4b0a0203e7
HEAD_REF wx
)
file(COPY "${scintilla_SOURCE_PATH}/" DESTINATION "${SOURCE_PATH}/src/stc/scintilla")
vcpkg_check_features(
OUT_FEATURE_OPTIONS FEATURE_OPTIONS
FEATURES
@ -52,14 +69,20 @@ if(VCPKG_TARGET_IS_WINDOWS)
endif()
endif()
if("webview" IN_LIST FEATURES AND VCPKG_LIBRARY_LINKAGE STREQUAL "static")
list(APPEND OPTIONS -DwxUSE_WEBVIEW_EDGE_STATIC=ON)
endif()
vcpkg_find_acquire_program(PKGCONFIG)
# This may be set to ON by users in a custom triplet.
# The use of 'wxUSE_STL' and 'WXWIDGETS_USE_STD_CONTAINERS' (ON or OFF) are not API compatible
# which is why they must be set in a custom triplet rather than a port feature.
# The use of 'WXWIDGETS_USE_STD_CONTAINERS' (ON or OFF) is not API compatible
# which is why it must be set in a custom triplet rather than a port feature.
# For backwards compatibility, we also replace 'wxUSE_STL' (which no longer
# exists) with 'wxUSE_STD_STRING_CONV_IN_WXSTRING' which still exists and was
# set by `wxUSE_STL` previously.
if(NOT DEFINED WXWIDGETS_USE_STL)
set(WXWIDGETS_USE_STL OFF)
set(WXWIDGETS_USE_STD_STRING_CONV_IN_WXSTRING OFF)
endif()
if(NOT DEFINED WXWIDGETS_USE_STD_CONTAINERS)
@ -70,19 +93,18 @@ vcpkg_cmake_configure(
SOURCE_PATH "${SOURCE_PATH}"
OPTIONS
${FEATURE_OPTIONS}
-DwxUSE_STC=OFF
-DwxUSE_REGEX=sys
-DwxUSE_ZLIB=sys
-DwxUSE_EXPAT=sys
-DwxUSE_LIBJPEG=sys
-DwxUSE_LIBPNG=sys
-DwxUSE_LIBTIFF=sys
-DwxUSE_LIBWEBP=sys
-DwxUSE_NANOSVG=sys
-DwxUSE_LIBWEBP=sys
-DwxUSE_GLCANVAS=ON
-DwxUSE_LIBGNOMEVFS=OFF
-DwxUSE_LIBNOTIFY=OFF
-DwxUSE_STD_STRING_CONV_IN_WXSTRING=${WXWIDGETS_USE_STD_STRING_CONV_IN_WXSTRING}
-DwxUSE_STD_STRING_CONV_IN_WXSTRING=${WXWIDGETS_USE_STL}
-DwxUSE_STD_CONTAINERS=${WXWIDGETS_USE_STD_CONTAINERS}
-DwxUSE_UIACTIONSIMULATOR=OFF
-DCMAKE_DISABLE_FIND_PACKAGE_GSPELL=ON
@ -101,7 +123,7 @@ vcpkg_cmake_configure(
)
vcpkg_cmake_install()
vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/wxWidgets)
vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/wxWidgets-3.3)
# The CMake export is not ready for use: It lacks a config file.
file(REMOVE_RECURSE
@ -126,6 +148,11 @@ vcpkg_copy_pdbs()
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/include/msvc")
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include")
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/lib/mswu")
if(VCPKG_BUILD_TYPE STREQUAL "release")
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/lib/mswud")
endif()
file(GLOB_RECURSE INCLUDES "${CURRENT_PACKAGES_DIR}/include/*.h")
if(EXISTS "${CURRENT_PACKAGES_DIR}/lib/mswu/wx/setup.h")
list(APPEND INCLUDES "${CURRENT_PACKAGES_DIR}/lib/mswu/wx/setup.h")
@ -191,12 +218,30 @@ endif()
if("example" IN_LIST FEATURES)
file(INSTALL
"${CMAKE_CURRENT_LIST_DIR}/example/CMakeLists.txt"
"${SOURCE_PATH}/samples/popup/popup.cpp"
"${SOURCE_PATH}/samples/sample.xpm"
DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/example"
"${CMAKE_CURRENT_LIST_DIR}/minimal_example/CMakeLists.txt"
"${SOURCE_PATH}/samples/minimal/minimal.cpp"
"${SOURCE_PATH}/samples/sample.xpm"
"${SOURCE_PATH}/samples/sample.rc"
DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/minimal_example"
)
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/share/${PORT}/example/popup.cpp" "../sample.xpm" "sample.xpm")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/share/${PORT}/minimal_example/minimal.cpp" "../sample.xpm" "sample.xpm")
endif()
if("example" IN_LIST FEATURES)
file(INSTALL
"${CMAKE_CURRENT_LIST_DIR}/listctrl_example/CMakeLists.txt"
"${SOURCE_PATH}/samples/listctrl/listtest.cpp"
"${SOURCE_PATH}/samples/listctrl/listtest.h"
"${SOURCE_PATH}/samples/listctrl/listtest.rc"
"${SOURCE_PATH}/samples/sample.xpm"
"${SOURCE_PATH}/samples/sample.rc"
"${SOURCE_PATH}/samples/listctrl/bitmaps"
DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/listctrl_example"
)
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/share/${PORT}/listctrl_example/listtest.cpp" "../sample.xpm" "sample.xpm")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/share/${PORT}/listctrl_example/listtest.rc" "../sample.rc" "sample.rc")
endif()
configure_file("${CMAKE_CURRENT_LIST_DIR}/vcpkg-cmake-wrapper.cmake" "${CURRENT_PACKAGES_DIR}/share/${PORT}/vcpkg-cmake-wrapper.cmake" @ONLY)

View file

@ -1,8 +1,8 @@
diff --git a/build/cmake/init.cmake b/build/cmake/init.cmake
index 5447d33..f5440b4 100644
index 4ed7b264ef..9abf7c9d5d 100644
--- a/build/cmake/init.cmake
+++ b/build/cmake/init.cmake
@@ -530,7 +530,9 @@ if(wxUSE_GUI)
@@ -667,7 +667,9 @@ if(wxUSE_GUI)
endif()
if(wxUSE_SOUND AND wxUSE_LIBSDL AND UNIX AND NOT APPLE)
@ -12,12 +12,12 @@ index 5447d33..f5440b4 100644
+ set(SDL2_LIBRARY SDL2::SDL2 CACHE INTERNAL "")
if(NOT SDL2_FOUND)
find_package(SDL)
endif()
mark_as_advanced(SDL_INCLUDE_DIR SDLMAIN_LIBRARY)
diff --git a/build/cmake/wxWidgetsConfig.cmake.in b/build/cmake/wxWidgetsConfig.cmake.in
index 60cf762..202a8c3 100644
index c134900764..7bcb691074 100644
--- a/build/cmake/wxWidgetsConfig.cmake.in
+++ b/build/cmake/wxWidgetsConfig.cmake.in
@@ -2,6 +2,9 @@
@@ -156,6 +156,9 @@ endforeach()
include(CMakeFindDependencyMacro)
find_dependency(NanoSVG CONFIG)
@ -25,5 +25,5 @@ index 60cf762..202a8c3 100644
+ find_dependency(SDL2 CONFIG)
+endif()
cmake_policy(PUSH)
# Set policies to prevent warnings
if(TARGET wx::wxnet AND @wxUSE_WEBREQUEST_CURL@)
# make sure CURL targets are available:

View file

@ -9,7 +9,7 @@ set(WX_ROOT_DIR "${_vcpkg_wx_root}" CACHE INTERNAL "")
unset(_vcpkg_wx_root)
if(WIN32)
# Find all libs with "32" infix which is unknown to FindwxWidgets.cmake
# Find all libs with "33" infix which is unknown to FindwxWidgets.cmake
function(z_vcpkg_wxwidgets_find_base_library BASENAME)
find_library(WX_${BASENAME}d wx${BASENAME}33ud NAMES wx${BASENAME}d PATHS "${wxWidgets_ROOT_DIR}/debug/lib" NO_DEFAULT_PATH)
find_library(WX_${BASENAME} wx${BASENAME}33u NAMES wx${BASENAME} PATHS "${wxWidgets_ROOT_DIR}/lib" NO_DEFAULT_PATH REQUIRED)

View file

@ -590,16 +590,16 @@ void CemuUpdateWindow::OnClose(wxCloseEvent& event)
if (m_restartRequired && !m_restartFile.empty() && fs::exists(m_restartFile))
{
PROCESS_INFORMATION pi{};
STARTUPINFO si{};
STARTUPINFOW si{};
si.cb = sizeof(si);
std::wstring cmdline = GetCommandLineW();
const auto index = cmdline.find('"', 1);
cemu_assert_debug(index != std::wstring::npos);
cmdline = L"\"" + m_restartFile.wstring() + L"\"" + cmdline.substr(index + 1);
cmdline = L"\"" + boost::nowide::widen(_pathToUtf8(m_restartFile)) + L"\"" + cmdline.substr(index + 1);
HANDLE lock = CreateMutex(nullptr, TRUE, L"Global\\cemu_update_lock");
CreateProcess(nullptr, (wchar_t*)cmdline.c_str(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi);
HANDLE lock = CreateMutexW(nullptr, TRUE, L"Global\\cemu_update_lock");
CreateProcessW(nullptr, (wchar_t*)cmdline.c_str(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi);
exit(0);
}

View file

@ -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());

View file

@ -3,15 +3,15 @@
#include "config/CemuConfig.h"
#include "Cafe/TitleList/TitleId.h"
#include <future>
#include <mutex>
#include <optional>
#include <wx/listctrl.h>
#include <wx/timer.h>
#include <wx/panel.h>
#include <wx/settings.h>
#include <Cafe/TitleList/GameInfo.h>
#include "wxHelper.h"
#include "util/helpers/Semaphore.h"
class wxTitleIdEvent : public wxCommandEvent
@ -66,7 +66,8 @@ private:
const wxColour kUpdateColor{ wxSystemSettings::SelectLightDark(wxColour(195, 57, 57), wxColour(84, 29, 29)) };
const wxColour kFavoriteColor{ wxSystemSettings::SelectLightDark(wxColour(253, 246, 211), wxColour(82, 84, 48)) };
const wxColour kSecondColor{ wxSystemSettings::SelectLightDark(wxColour(242, 249, 253), wxColour(34, 34, 34)) };
const wxColour kPrimaryColor = GetBackgroundColour();
const wxColour kAlternateColor = wxHelper::CalculateAccentColour(kPrimaryColor);
void UpdateItemColors(sint32 startIndex = 0);
enum ItemColumns : int
@ -89,7 +90,7 @@ private:
{
wxGameList* thisptr;
ItemColumns column;
bool asc;
int dir;
};
int FindInsertPosition(TitleId titleId);
@ -109,7 +110,7 @@ private:
std::vector<TitleId> m_icon_load_queue;
uint64 m_callbackIdTitleList;
std::string GetNameByTitleId(uint64 titleId);
void HandleTitleListCallback(struct CafeTitleListCallbackEvent* evt);
@ -122,7 +123,8 @@ private:
inline static constexpr int kListIconWidth = 64;
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::set<TitleId> m_icon_loaded;

View file

@ -25,10 +25,9 @@ namespace wxHelper
inline wxColour CalculateAccentColour(const wxColour& bgColour)
{
wxColour bgColourSecondary;
const uint32 bgLightness = (bgColour.GetRed() + bgColour.GetGreen() + bgColour.GetBlue()) / 3;
const bool isDarkTheme = bgLightness < 128;
bgColourSecondary = bgColour.ChangeLightness(isDarkTheme ? 110 : 90); // color for even rows
wxColour bgColourSecondary = bgColour.ChangeLightness(isDarkTheme ? 110 : 90); // color for even rows
// for very light themes we'll use a blue tint to match the older Windows Cemu look
if (bgLightness > 250)
bgColourSecondary = wxColour(bgColour.Red() - 13, bgColour.Green() - 6, bgColour.Blue() - 2);

View file

@ -22,9 +22,10 @@ DirectInputController::~DirectInputController()
// TODO: test if really needed
// workaround for gamecube controllers crash on release?
bool should_release_device = true;
if (m_product_guid == GUID{}) {
DIDEVICEINSTANCE info{};
info.dwSize = sizeof(DIDEVICEINSTANCE);
if (m_product_guid == GUID{})
{
DIDEVICEINSTANCEW info{};
info.dwSize = sizeof(DIDEVICEINSTANCEW);
if (SUCCEEDED(m_device->GetDeviceInfo(&info)))
{
m_product_guid = info.guidProduct;
@ -90,8 +91,8 @@ bool DirectInputController::connect()
if (FAILED(hr) || m_device == nullptr)
return false;
DIDEVICEINSTANCE idi{};
idi.dwSize = sizeof(DIDEVICEINSTANCE);
DIDEVICEINSTANCEW idi{};
idi.dwSize = sizeof(DIDEVICEINSTANCEW);
if (SUCCEEDED(m_device->GetDeviceInfo(&idi)))
{
// overwrite guid name with "real" display name
@ -147,8 +148,8 @@ bool DirectInputController::connect()
}
}
DIDEVICEINSTANCE info{};
info.dwSize = sizeof(DIDEVICEINSTANCE);
DIDEVICEINSTANCEW info{};
info.dwSize = sizeof(DIDEVICEINSTANCEW);
if (SUCCEEDED(m_device->GetDeviceInfo(&info)))
{
m_product_guid = info.guidProduct;
@ -157,7 +158,7 @@ bool DirectInputController::connect()
std::fill(m_min_axis.begin(), m_min_axis.end(), 0);
std::fill(m_max_axis.begin(), m_max_axis.end(), std::numeric_limits<uint16>::max());
m_device->EnumObjects(
[](LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef) -> BOOL
[](LPCDIDEVICEOBJECTINSTANCEW lpddoi, LPVOID pvRef) -> BOOL
{
auto* thisptr = (DirectInputController*)pvRef;

View file

@ -42,7 +42,7 @@ private:
GUID m_product_guid{};
std::shared_mutex m_mutex;
Microsoft::WRL::ComPtr<IDirectInputDevice8> m_device;
Microsoft::WRL::ComPtr<IDirectInputDevice8W> m_device;
Microsoft::WRL::ComPtr<IDirectInputEffect> m_effect;
std::array<LONG, 6> m_min_axis{};

View file

@ -4,34 +4,16 @@
DirectInputControllerProvider::DirectInputControllerProvider()
{
/*m_module = LoadLibraryA("dinput8.dll");
if (!m_module)
throw std::runtime_error("can't load any xinput dll");
m_DirectInput8Create = (decltype(&DirectInput8Create))GetProcAddress(m_module, "DirectInput8Create");
m_GetdfDIJoystick = (decltype(&GetdfDIJoystick))GetProcAddress(m_module, "GetdfDIJoystick");
if (!m_DirectInput8Create)
{
FreeLibrary(m_module);
throw std::runtime_error("can't find the DirectInput8Create export");
}*/
const auto r = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&m_dinput8, nullptr);
const auto r = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8W, (void**)&m_dinput8, nullptr);
if (FAILED(r))
{
const auto error = GetLastError();
//FreeLibrary(m_module);
throw std::runtime_error(fmt::format("can't create direct input object (error: {:#x})", error));
}
}
DirectInputControllerProvider::~DirectInputControllerProvider()
{
/*if (m_module)
FreeLibrary(m_module);
*/
}
std::vector<std::shared_ptr<ControllerBase>> DirectInputControllerProvider::get_controllers()
@ -39,7 +21,7 @@ std::vector<std::shared_ptr<ControllerBase>> DirectInputControllerProvider::get_
std::vector<std::shared_ptr<ControllerBase>> result;
m_dinput8->EnumDevices(DI8DEVCLASS_GAMECTRL,
[](LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef) -> BOOL
[](LPCDIDEVICEINSTANCEW lpddi, LPVOID pvRef) -> BOOL
{
auto* controllers = (decltype(&result))pvRef;
@ -55,8 +37,5 @@ std::vector<std::shared_ptr<ControllerBase>> DirectInputControllerProvider::get_
LPCDIDATAFORMAT DirectInputControllerProvider::get_data_format() const
{
/*if (m_GetdfDIJoystick)
return m_GetdfDIJoystick();*/
return GetdfDIJoystick();
}

View file

@ -23,7 +23,7 @@ public:
std::vector<std::shared_ptr<ControllerBase>> get_controllers() override;
IDirectInput8* get_dinput() const { return m_dinput8.Get(); }
IDirectInput8W* get_dinput() const { return m_dinput8.Get(); }
LPCDIDATAFORMAT get_data_format() const;
private:
@ -32,7 +32,7 @@ private:
decltype(&DirectInput8Create) m_DirectInput8Create;
decltype(&GetdfDIJoystick) m_GetdfDIJoystick = nullptr;
Microsoft::WRL::ComPtr<IDirectInput8> m_dinput8;
Microsoft::WRL::ComPtr<IDirectInput8W> m_dinput8;
};
#endif

View file

@ -96,12 +96,12 @@ void WindowsInitCwd()
{
#if BOOST_OS_WINDOWS
executablePath.resize(4096);
int i = GetModuleFileName(NULL, executablePath.data(), executablePath.size());
int i = GetModuleFileNameW(NULL, executablePath.data(), executablePath.size());
if(i >= 0)
executablePath.resize(i);
else
executablePath.clear();
SetCurrentDirectory(executablePath.c_str());
SetCurrentDirectoryW(executablePath.c_str());
// set high priority
SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
#endif
@ -192,7 +192,7 @@ void HandlePostUpdate()
HANDLE lock;
do
{
lock = CreateMutex(nullptr, TRUE, L"Global\\cemu_update_lock");
lock = CreateMutexW(nullptr, TRUE, L"Global\\cemu_update_lock");
std::this_thread::sleep_for(std::chrono::milliseconds(1));
} while (lock == nullptr);
const DWORD wait_result = WaitForSingleObject(lock, 2000);
@ -220,7 +220,7 @@ void ToolShaderCacheMerger();
#if BOOST_OS_WINDOWS
// entrypoint for release builds
int wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nShowCmd)
int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
{
if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE)))
cemuLog_log(LogType::Force, "CoInitializeEx() failed");

View file

@ -34,13 +34,7 @@
"default-features": false
},
"zstd",
{
"name": "wxwidgets",
"features": [
"debug-support"
],
"default-features": false
},
"wxwidgets",
"openssl",
{
"name": "curl",