From 43d804991edc6eacf8a4d372954d3b5d10a6d51f Mon Sep 17 00:00:00 2001 From: uncor3 Date: Sun, 22 Feb 2026 11:59:57 +0300 Subject: [PATCH] refactor(ui): add WinUI stylesheet for Windows - Introduced WinToolWidget for custom window management on Windows. - Implemented backdrop type settings for Windows in SettingsManager. - Enhanced SettingsWidget to allow selection of backdrop type. - Improved status balloon and toolbox widget styles for Windows. - Refined tab widget animations and styles for better visual feedback. - Fixed issues with loading and error widgets in ZLoadingWidget. - Updated welcome widget to support custom hyperlink colors. - General code cleanup and style adjustments across multiple files. --- CMakeLists.txt | 122 +- resources.win.qrc | 82 ++ resources/win.dark.qcss | 1126 +++++++++++++++++ resources/win.light.qcss | 1124 ++++++++++++++++ resources/win/dark/CheckBox.png | Bin 0 -> 208 bytes resources/win/dark/CheckBoxPressed.png | Bin 0 -> 273 bytes resources/win/dark/ComboBox.png | Bin 0 -> 226 bytes resources/win/dark/ComboBoxDisabled.png | Bin 0 -> 252 bytes resources/win/dark/NextMonth.png | Bin 0 -> 245 bytes resources/win/dark/NextMonthDisabled.png | Bin 0 -> 266 bytes resources/win/dark/PrevMonth.png | Bin 0 -> 234 bytes resources/win/dark/PrevMonthDisabled.png | Bin 0 -> 263 bytes resources/win/dark/RadioButton.png | Bin 0 -> 254 bytes resources/win/dark/RadioButtonHover.png | Bin 0 -> 259 bytes resources/win/dark/RadioButtonPressed.png | Bin 0 -> 233 bytes resources/win/dark/ScrollBottom.png | Bin 0 -> 247 bytes resources/win/dark/ScrollBottomHover.png | Bin 0 -> 245 bytes resources/win/dark/ScrollBottomPressed.png | Bin 0 -> 232 bytes resources/win/dark/ScrollLeft.png | Bin 0 -> 226 bytes resources/win/dark/ScrollLeftHover.png | Bin 0 -> 225 bytes resources/win/dark/ScrollLeftPressed.png | Bin 0 -> 233 bytes resources/win/dark/ScrollRight.png | Bin 0 -> 241 bytes resources/win/dark/ScrollRightHover.png | Bin 0 -> 235 bytes resources/win/dark/ScrollRightPressed.png | Bin 0 -> 227 bytes resources/win/dark/ScrollTop.png | Bin 0 -> 238 bytes resources/win/dark/ScrollTopHover.png | Bin 0 -> 236 bytes resources/win/dark/ScrollTopPressed.png | Bin 0 -> 224 bytes resources/win/dark/SpinBoxDown.png | Bin 0 -> 404 bytes resources/win/dark/SpinBoxDownDisabled.png | Bin 0 -> 642 bytes resources/win/dark/SpinBoxUp.png | Bin 0 -> 368 bytes resources/win/dark/SpinBoxUpDisabled.png | Bin 0 -> 625 bytes resources/win/dark/ToggleSwitchDisabled.png | Bin 0 -> 329 bytes resources/win/dark/ToggleSwitchOff.png | Bin 0 -> 336 bytes resources/win/dark/ToggleSwitchOffHover.png | Bin 0 -> 354 bytes resources/win/dark/ToggleSwitchOffPressed.png | Bin 0 -> 356 bytes resources/win/dark/ToggleSwitchOn.png | Bin 0 -> 259 bytes resources/win/dark/ToggleSwitchOnHover.png | Bin 0 -> 283 bytes resources/win/dark/ToggleSwitchOnPressed.png | Bin 0 -> 278 bytes resources/win/dark/TreeViewClose.png | Bin 0 -> 263 bytes resources/win/dark/TreeViewOpen.png | Bin 0 -> 275 bytes resources/win/light/CheckBox.png | Bin 0 -> 215 bytes resources/win/light/CheckBoxPressed.png | Bin 0 -> 267 bytes resources/win/light/ComboBox.png | Bin 0 -> 220 bytes resources/win/light/ComboBoxDisabled.png | Bin 0 -> 252 bytes resources/win/light/NextMonth.png | Bin 0 -> 250 bytes resources/win/light/NextMonthDisabled.png | Bin 0 -> 245 bytes resources/win/light/PrevMonth.png | Bin 0 -> 248 bytes resources/win/light/PrevMonthDisabled.png | Bin 0 -> 234 bytes resources/win/light/RadioButton.png | Bin 0 -> 267 bytes resources/win/light/RadioButtonHover.png | Bin 0 -> 272 bytes resources/win/light/RadioButtonPressed.png | Bin 0 -> 239 bytes resources/win/light/ScrollBottom.png | Bin 0 -> 253 bytes resources/win/light/ScrollBottomHover.png | Bin 0 -> 261 bytes resources/win/light/ScrollBottomPressed.png | Bin 0 -> 235 bytes resources/win/light/ScrollLeft.png | Bin 0 -> 244 bytes resources/win/light/ScrollLeftHover.png | Bin 0 -> 240 bytes resources/win/light/ScrollLeftPressed.png | Bin 0 -> 222 bytes resources/win/light/ScrollRight.png | Bin 0 -> 252 bytes resources/win/light/ScrollRightHover.png | Bin 0 -> 254 bytes resources/win/light/ScrollRightPressed.png | Bin 0 -> 221 bytes resources/win/light/ScrollTop.png | Bin 0 -> 244 bytes resources/win/light/ScrollTopHover.png | Bin 0 -> 252 bytes resources/win/light/ScrollTopPressed.png | Bin 0 -> 225 bytes resources/win/light/SpinBoxDown.png | Bin 0 -> 436 bytes resources/win/light/SpinBoxDownDisabled.png | Bin 0 -> 577 bytes resources/win/light/SpinBoxUp.png | Bin 0 -> 403 bytes resources/win/light/SpinBoxUpDisabled.png | Bin 0 -> 567 bytes resources/win/light/ToggleSwitchDisabled.png | Bin 0 -> 334 bytes resources/win/light/ToggleSwitchOff.png | Bin 0 -> 329 bytes resources/win/light/ToggleSwitchOffHover.png | Bin 0 -> 344 bytes .../win/light/ToggleSwitchOffPressed.png | Bin 0 -> 367 bytes resources/win/light/ToggleSwitchOn.png | Bin 0 -> 272 bytes resources/win/light/ToggleSwitchOnHover.png | Bin 0 -> 287 bytes resources/win/light/ToggleSwitchOnPressed.png | Bin 0 -> 318 bytes resources/win/light/TreeViewClose.png | Bin 0 -> 291 bytes resources/win/light/TreeViewOpen.png | Bin 0 -> 304 bytes src/airplaywidget.cpp | 2 +- src/appswidget.cpp | 20 +- src/base/tool.cpp | 8 + src/base/tool.h | 9 + src/cableinfowidget.cpp | 8 +- src/core/services/get-device-info.cpp | 3 +- src/core/services/init_device.cpp | 12 +- src/deviceinfowidget.cpp | 28 +- src/devicesidebarwidget.cpp | 128 +- src/devicesidebarwidget.h | 4 +- src/diagnosewidget.cpp | 31 +- src/diskusagewidget.cpp | 15 +- src/httpserver.cpp | 8 +- src/iDescriptor-ui.h | 22 + src/iDescriptor.h | 8 +- src/ifusewidget.cpp | 2 +- src/infolabel.cpp | 33 +- src/infolabel.h | 15 +- src/installedappswidget.cpp | 6 +- src/logindialog.cpp | 31 +- src/main.cpp | 14 +- src/mainwindow.cpp | 139 +- src/mainwindow.h | 22 +- src/platform/windows/blur_imp.cpp | 101 ++ src/platform/windows/check_deps.cpp | 2 +- src/platform/windows/check_deps.h | 28 - src/platform/windows/setuptitlebar.cpp | 33 + .../windows/widgets/wintoolwidget.cpp | 361 ++++++ src/platform/windows/widgets/wintoolwidget.h | 76 ++ src/platform/windows/win_common.h | 107 ++ src/servicemanager.cpp | 6 +- src/servicemanager.h | 2 +- src/settingsmanager.cpp | 14 + src/settingsmanager.h | 8 + src/settingswidget.cpp | 66 +- src/settingswidget.h | 4 + src/statusballoon.cpp | 17 +- src/toolboxwidget.cpp | 31 +- src/welcomewidget.cpp | 24 +- src/welcomewidget.h | 2 +- src/zlineedit.cpp | 30 +- src/zloadingwidget.cpp | 29 +- src/zloadingwidget.h | 2 + src/ztabwidget.cpp | 254 +++- src/ztabwidget.h | 5 +- 121 files changed, 3745 insertions(+), 479 deletions(-) create mode 100644 resources.win.qrc create mode 100644 resources/win.dark.qcss create mode 100644 resources/win.light.qcss create mode 100644 resources/win/dark/CheckBox.png create mode 100644 resources/win/dark/CheckBoxPressed.png create mode 100644 resources/win/dark/ComboBox.png create mode 100644 resources/win/dark/ComboBoxDisabled.png create mode 100644 resources/win/dark/NextMonth.png create mode 100644 resources/win/dark/NextMonthDisabled.png create mode 100644 resources/win/dark/PrevMonth.png create mode 100644 resources/win/dark/PrevMonthDisabled.png create mode 100644 resources/win/dark/RadioButton.png create mode 100644 resources/win/dark/RadioButtonHover.png create mode 100644 resources/win/dark/RadioButtonPressed.png create mode 100644 resources/win/dark/ScrollBottom.png create mode 100644 resources/win/dark/ScrollBottomHover.png create mode 100644 resources/win/dark/ScrollBottomPressed.png create mode 100644 resources/win/dark/ScrollLeft.png create mode 100644 resources/win/dark/ScrollLeftHover.png create mode 100644 resources/win/dark/ScrollLeftPressed.png create mode 100644 resources/win/dark/ScrollRight.png create mode 100644 resources/win/dark/ScrollRightHover.png create mode 100644 resources/win/dark/ScrollRightPressed.png create mode 100644 resources/win/dark/ScrollTop.png create mode 100644 resources/win/dark/ScrollTopHover.png create mode 100644 resources/win/dark/ScrollTopPressed.png create mode 100644 resources/win/dark/SpinBoxDown.png create mode 100644 resources/win/dark/SpinBoxDownDisabled.png create mode 100644 resources/win/dark/SpinBoxUp.png create mode 100644 resources/win/dark/SpinBoxUpDisabled.png create mode 100644 resources/win/dark/ToggleSwitchDisabled.png create mode 100644 resources/win/dark/ToggleSwitchOff.png create mode 100644 resources/win/dark/ToggleSwitchOffHover.png create mode 100644 resources/win/dark/ToggleSwitchOffPressed.png create mode 100644 resources/win/dark/ToggleSwitchOn.png create mode 100644 resources/win/dark/ToggleSwitchOnHover.png create mode 100644 resources/win/dark/ToggleSwitchOnPressed.png create mode 100644 resources/win/dark/TreeViewClose.png create mode 100644 resources/win/dark/TreeViewOpen.png create mode 100644 resources/win/light/CheckBox.png create mode 100644 resources/win/light/CheckBoxPressed.png create mode 100644 resources/win/light/ComboBox.png create mode 100644 resources/win/light/ComboBoxDisabled.png create mode 100644 resources/win/light/NextMonth.png create mode 100644 resources/win/light/NextMonthDisabled.png create mode 100644 resources/win/light/PrevMonth.png create mode 100644 resources/win/light/PrevMonthDisabled.png create mode 100644 resources/win/light/RadioButton.png create mode 100644 resources/win/light/RadioButtonHover.png create mode 100644 resources/win/light/RadioButtonPressed.png create mode 100644 resources/win/light/ScrollBottom.png create mode 100644 resources/win/light/ScrollBottomHover.png create mode 100644 resources/win/light/ScrollBottomPressed.png create mode 100644 resources/win/light/ScrollLeft.png create mode 100644 resources/win/light/ScrollLeftHover.png create mode 100644 resources/win/light/ScrollLeftPressed.png create mode 100644 resources/win/light/ScrollRight.png create mode 100644 resources/win/light/ScrollRightHover.png create mode 100644 resources/win/light/ScrollRightPressed.png create mode 100644 resources/win/light/ScrollTop.png create mode 100644 resources/win/light/ScrollTopHover.png create mode 100644 resources/win/light/ScrollTopPressed.png create mode 100644 resources/win/light/SpinBoxDown.png create mode 100644 resources/win/light/SpinBoxDownDisabled.png create mode 100644 resources/win/light/SpinBoxUp.png create mode 100644 resources/win/light/SpinBoxUpDisabled.png create mode 100644 resources/win/light/ToggleSwitchDisabled.png create mode 100644 resources/win/light/ToggleSwitchOff.png create mode 100644 resources/win/light/ToggleSwitchOffHover.png create mode 100644 resources/win/light/ToggleSwitchOffPressed.png create mode 100644 resources/win/light/ToggleSwitchOn.png create mode 100644 resources/win/light/ToggleSwitchOnHover.png create mode 100644 resources/win/light/ToggleSwitchOnPressed.png create mode 100644 resources/win/light/TreeViewClose.png create mode 100644 resources/win/light/TreeViewOpen.png create mode 100644 src/platform/windows/blur_imp.cpp delete mode 100644 src/platform/windows/check_deps.h create mode 100644 src/platform/windows/setuptitlebar.cpp create mode 100644 src/platform/windows/widgets/wintoolwidget.cpp create mode 100644 src/platform/windows/widgets/wintoolwidget.h create mode 100644 src/platform/windows/win_common.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e39dc30..11fda9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,6 @@ if(WIN32) endif() # Feature options -option(ENABLE_RECOVERY_DEVICE_SUPPORT "Enable recovery device support (requires libirecovery)" ON) set(PACKAGE_MANAGER_HINT "" CACHE STRING "Name of package manager(s) used to manage this build (e.g. paru, yay, pamac)") option(PACKAGE_MANAGER_MANAGED "Build as package manager managed version (auto updates will be handled by the package manager)" OFF) option(DEPLOY "Deploy the application (WIN32 only)" ON) @@ -26,39 +25,27 @@ if (APPLE) endif() # Platform-specific paths for libraries built from source -# if(WIN32) -# include_directories("C:/msys64/mingw64/include") -# link_directories("C:/msys64/mingw64/lib") -# set(PKG_CONFIG_EXECUTABLE "C:/msys64/mingw64/bin/pkg-config.exe") -# list(APPEND CMAKE_PREFIX_PATH "C:/lxqt") -# set(CUSTOM_LIB_PATH "C:/msys64/mingw64/lib") -# set(CUSTOM_INCLUDE_PATH "C:/msys64/mingw64/include") -# set(CUSTOM_PKGCONFIG_PATH "C:/msys64/mingw64/lib/pkgconfig") -# set(ENV{PKG_CONFIG_PATH} "${CUSTOM_PKGCONFIG_PATH};$ENV{PKG_CONFIG_PATH}") -# elseif(APPLE) -# set(CUSTOM_LIB_PATH "/usr/local/lib") -# # Remove the problematic include path that's causing conflicts -# # set(CUSTOM_INCLUDE_PATH "/usr/local/include") -# set(CUSTOM_PKGCONFIG_PATH "/usr/local/lib/pkgconfig") -# set(ENV{PKG_CONFIG_PATH} "${CUSTOM_PKGCONFIG_PATH}:$ENV{PKG_CONFIG_PATH}") -# else () -# set(CUSTOM_LIB_PATH "/usr/local/lib") -# set(CUSTOM_PKGCONFIG_PATH "/usr/local/lib/pkgconfig") -# set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${CUSTOM_PKGCONFIG_PATH}") -# endif() +if(WIN32) + include_directories("C:/msys64/mingw64/include") + link_directories("C:/msys64/mingw64/lib") + set(PKG_CONFIG_EXECUTABLE "C:/msys64/mingw64/bin/pkg-config.exe") + list(APPEND CMAKE_PREFIX_PATH "C:/lxqt") + set(CUSTOM_LIB_PATH "C:/msys64/mingw64/lib") + set(CUSTOM_INCLUDE_PATH "C:/msys64/mingw64/include") + set(CUSTOM_PKGCONFIG_PATH "C:/msys64/mingw64/lib/pkgconfig") + set(ENV{PKG_CONFIG_PATH} "${CUSTOM_PKGCONFIG_PATH};$ENV{PKG_CONFIG_PATH}") +elseif(APPLE) + set(CUSTOM_LIB_PATH "/usr/local/lib") + # Remove the problematic include path that's causing conflicts + # set(CUSTOM_INCLUDE_PATH "/usr/local/include") + set(CUSTOM_PKGCONFIG_PATH "/usr/local/lib/pkgconfig") + set(ENV{PKG_CONFIG_PATH} "${CUSTOM_PKGCONFIG_PATH}:$ENV{PKG_CONFIG_PATH}") +else () + set(CUSTOM_LIB_PATH "/usr/local/lib") + set(CUSTOM_PKGCONFIG_PATH "/usr/local/lib/pkgconfig") + set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${CUSTOM_PKGCONFIG_PATH}") +endif() -# foreach(_ IN LISTS CMAKE_PREFIX_PATH) -# list(APPEND _qt_pkg_dirs -# "${_}/lib/pkgconfig" -# "${_}/lib64/pkgconfig" -# "${_}/lib64/qt/pkgconfig" -# "${_}/lib/qt/pkgconfig" -# ) -# endforeach() - - -# list(APPEND _qt_pkg_dirs ${CUSTOM_PKGCONFIG_PATH}) - find_package(PkgConfig REQUIRED) find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia MultimediaWidgets Network QuickControls2 SerialPort Positioning Location QuickWidgets) find_package(SQLite3 REQUIRED) @@ -110,6 +97,14 @@ add_custom_command( COMMENT "Building idevice-rs FFI libraryy" VERBATIM ) +elseif(WIN32) +add_custom_command( + OUTPUT ${IDEVICE_RS_LIB_PATH} + COMMAND ${CARGO_EXECUTABLE} +stable-x86_64-pc-windows-gnu build --manifest-path ${IDEVICE_RS_SOURCE_DIR}/Cargo.toml + WORKING_DIRECTORY ${IDEVICE_RS_SOURCE_DIR} + COMMENT "Building idevice-rs FFI libraryy" + VERBATIM +) else() add_custom_command( OUTPUT ${IDEVICE_RS_LIB_PATH} @@ -150,6 +145,11 @@ file(GLOB PLIST_CPP_SOURCES add_library(idevice_cpp STATIC ${IDEVICE_CPP_SOURCES} ${PLIST_CPP_SOURCES}) add_dependencies(idevice_cpp idevice_rs_build) +if(WIN32) +# Define LIBPLIST_STATIC to prevent functions from being marked as DLL imports +target_compile_definitions(idevice_cpp PUBLIC LIBPLIST_STATIC) +endif() + target_include_directories(idevice_cpp PUBLIC ${IDEVICE_CPP_INCLUDE_DIR} ${PLIST_CPP_INCLUDE_DIR} @@ -201,21 +201,6 @@ pkg_check_modules(AVCODEC REQUIRED IMPORTED_TARGET libavcodec) pkg_check_modules(AVUTIL REQUIRED IMPORTED_TARGET libavutil) pkg_check_modules(SWSCALE REQUIRED IMPORTED_TARGET libswscale) -# if(ENABLE_RECOVERY_DEVICE_SUPPORT) -# find_library(IRECOVERY_LIBRARY -# NAMES irecovery-1.0 -# PATHS ${CUSTOM_LIB_PATH} -# NO_DEFAULT_PATH -# ) -# if(IRECOVERY_LIBRARY) -# message(STATUS "Building with recovery device support enabled") -# else() -# message(WARNING "libirecovery not found. Recovery device support will be disabled. This is to be expected if you are installing from Arch AUR.") -# set(ENABLE_RECOVERY_DEVICE_SUPPORT OFF) -# endif() -# else() -# message(STATUS "Recovery device support disabled") -# endif() # Add libssh for SSH connections pkg_check_modules(SSH REQUIRED IMPORTED_TARGET libssh) @@ -252,8 +237,10 @@ elseif (WIN32) src/core/services/dnssd/dnssd_service.h ) - file(GLOB WINDOWS_PLATFORM_SOURCES src/platform/windows/*.cpp src/platform/windows/*.h) + file(GLOB WINDOWS_PLATFORM_SOURCES src/platform/windows/*.cpp src/platform/windows/*.h src/platform/windows/widgets/*.cpp src/platform/windows/widgets/*.h) list(APPEND PROJECT_SOURCES ${WINDOWS_PLATFORM_SOURCES}) + list(APPEND PROJECT_SOURCES + resources.win.qrc) else() list(APPEND PROJECT_SOURCES src/core/services/avahi/avahi_service.cpp @@ -261,17 +248,6 @@ else() ) endif() -if (NOT ENABLE_RECOVERY_DEVICE_SUPPORT) - list(REMOVE_ITEM PROJECT_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/src/recoverydeviceinfowidget.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/recoverydeviceinfowidget.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/core/helpers/parse_recovery_mode.cpp - src/recoverydeviceinfowidget.cpp - src/recoverydeviceinfowidget.h - src/core/helpers/parse_recovery_mode.cpp - ) -endif() - add_subdirectory(lib/uxplay) add_subdirectory(lib/ipatool-go) add_subdirectory(lib/zupdater) @@ -323,14 +299,8 @@ target_link_libraries(iDescriptor PRIVATE Qt6::Positioning Qt6::QuickWidgets Qt6::QuickControls2 - # ${IMOBILEDEVICE_LIBRARY} - # ${IMOBILEDEVICE_GLUE_LIBRARY} - # ${TATSU_LIBRARY} - # ${SSL_LIBRARY} - # ${CRYPTO_LIBRARY} PkgConfig::SSH ${SSH_LIBRARY} - # ${USBMUXD_LIBRARY} PkgConfig::PUGIXML # PkgConfig::USB # PkgConfig::PLIST @@ -350,11 +320,6 @@ target_link_libraries(iDescriptor PRIVATE SQLite::SQLite3 ) -# # Conditionally link libirecovery -# if(ENABLE_RECOVERY_DEVICE_SUPPORT) -# target_link_libraries(iDescriptor PRIVATE ${IRECOVERY_LIBRARY}) -# endif() - target_include_directories(iDescriptor PRIVATE # Put idevice-rs includes FIRST ${IDEVICE_CPP_INCLUDE_DIR} @@ -376,7 +341,7 @@ if(APPLE) ${CORE_SERVICES_FRAMEWORK}) message(STATUS "Using macOS Bonjour framework for network service discovery") elseif (WIN32) - target_link_libraries(iDescriptor PRIVATE PkgConfig::LIBARCHIVE) + target_link_libraries(iDescriptor PRIVATE PkgConfig::LIBARCHIVE dwmapi ntdll) find_path(DNSSD_INCLUDE_DIR dns_sd.h HINTS ${BONJOUR_SDK}/Include ) # $<$ fixes winres compiler errors target_include_directories(iDescriptor PRIVATE @@ -406,11 +371,6 @@ target_compile_definitions(iDescriptor PRIVATE SOURCE_DIR="${CMAKE_SOURCE_DIR}" ) -# Add compile definition for recovery device support -if(ENABLE_RECOVERY_DEVICE_SUPPORT) - target_compile_definitions(iDescriptor PRIVATE ENABLE_RECOVERY_DEVICE_SUPPORT) -endif() - if(PACKAGE_MANAGER_MANAGED) target_compile_definitions(iDescriptor PRIVATE PACKAGE_MANAGER_MANAGED) message(STATUS "Building as package manager managed version, updates will be handled by the package manager") @@ -435,14 +395,8 @@ set_target_properties(iDescriptor PROPERTIES WIN32_EXECUTABLE TRUE BUILD_WITH_INSTALL_RPATH TRUE ) + if (UNIX AND NOT APPLE) - # Required on Linux to find libirecovery-1.0.so.5 at runtime - if (ENABLE_RECOVERY_DEVICE_SUPPORT) - set_target_properties(iDescriptor PROPERTIES - # Control library search order - system libs first, then /usr/local/lib - INSTALL_RPATH "/usr/lib/x86_64-linux-gnu:/usr/lib:/usr/local/lib:$ORIGIN" - ) - endif() # Add install rules for the project # include(GNUInstallDirs) diff --git a/resources.win.qrc b/resources.win.qrc new file mode 100644 index 0000000..72e0b5b --- /dev/null +++ b/resources.win.qrc @@ -0,0 +1,82 @@ + + + resources/win.dark.qcss + resources/win.light.qcss + + + resources/win/dark/CheckBox.png + resources/win/dark/CheckBoxPressed.png + resources/win/dark/ComboBox.png + resources/win/dark/ComboBoxDisabled.png + resources/win/dark/NextMonth.png + resources/win/dark/NextMonthDisabled.png + resources/win/dark/PrevMonth.png + resources/win/dark/PrevMonthDisabled.png + resources/win/dark/RadioButton.png + resources/win/dark/RadioButtonHover.png + resources/win/dark/RadioButtonPressed.png + resources/win/dark/ScrollBottom.png + resources/win/dark/ScrollBottomHover.png + resources/win/dark/ScrollBottomPressed.png + resources/win/dark/ScrollLeft.png + resources/win/dark/ScrollLeftHover.png + resources/win/dark/ScrollLeftPressed.png + resources/win/dark/ScrollRight.png + resources/win/dark/ScrollRightHover.png + resources/win/dark/ScrollRightPressed.png + resources/win/dark/ScrollTop.png + resources/win/dark/ScrollTopHover.png + resources/win/dark/ScrollTopPressed.png + resources/win/dark/SpinBoxDown.png + resources/win/dark/SpinBoxDownDisabled.png + resources/win/dark/SpinBoxUp.png + resources/win/dark/SpinBoxUpDisabled.png + resources/win/dark/ToggleSwitchDisabled.png + resources/win/dark/ToggleSwitchOff.png + resources/win/dark/ToggleSwitchOffHover.png + resources/win/dark/ToggleSwitchOffPressed.png + resources/win/dark/ToggleSwitchOn.png + resources/win/dark/ToggleSwitchOnHover.png + resources/win/dark/ToggleSwitchOnPressed.png + resources/win/dark/TreeViewClose.png + resources/win/dark/TreeViewOpen.png + + + resources/win/light/CheckBox.png + resources/win/light/CheckBoxPressed.png + resources/win/light/ComboBox.png + resources/win/light/ComboBoxDisabled.png + resources/win/light/NextMonth.png + resources/win/light/NextMonthDisabled.png + resources/win/light/PrevMonth.png + resources/win/light/PrevMonthDisabled.png + resources/win/light/RadioButton.png + resources/win/light/RadioButtonHover.png + resources/win/light/RadioButtonPressed.png + resources/win/light/ScrollBottom.png + resources/win/light/ScrollBottomHover.png + resources/win/light/ScrollBottomPressed.png + resources/win/light/ScrollLeft.png + resources/win/light/ScrollLeftHover.png + resources/win/light/ScrollLeftPressed.png + resources/win/light/ScrollRight.png + resources/win/light/ScrollRightHover.png + resources/win/light/ScrollRightPressed.png + resources/win/light/ScrollTop.png + resources/win/light/ScrollTopHover.png + resources/win/light/ScrollTopPressed.png + resources/win/light/SpinBoxDown.png + resources/win/light/SpinBoxDownDisabled.png + resources/win/light/SpinBoxUp.png + resources/win/light/SpinBoxUpDisabled.png + resources/win/light/ToggleSwitchDisabled.png + resources/win/light/ToggleSwitchOff.png + resources/win/light/ToggleSwitchOffHover.png + resources/win/light/ToggleSwitchOffPressed.png + resources/win/light/ToggleSwitchOn.png + resources/win/light/ToggleSwitchOnHover.png + resources/win/light/ToggleSwitchOnPressed.png + resources/win/light/TreeViewClose.png + resources/win/light/TreeViewOpen.png + + \ No newline at end of file diff --git a/resources/win.dark.qcss b/resources/win.dark.qcss new file mode 100644 index 0000000..28acc57 --- /dev/null +++ b/resources/win.dark.qcss @@ -0,0 +1,1126 @@ +QWidget { + background: transparent; + color: rgb(255, 255, 255); + font-size: 17px; + font-family: "Segoe UI Variable Small", serif; + font-weight: 400; +} + +/*MENU*/ +QMenuBar { + background-color: transparent; + color: white; + padding: 10px; + font-size: 17px; + font-family: "Segoe UI Variable Small", serif; + font-weight: 400; +} + +QMenuBar::item { + background-color: transparent; + padding: 10px 13px; + margin-left: 5px; + border-radius: 5px; +} + +QMenuBar::item:selected { + background-color: rgba(255, 255, 255, 20); +} + +QMenuBar::item:pressed { + background-color: rgba(255, 255, 255, 13); + color: rgba(255, 255, 255, 200); +} + +QMenu { + background-color: transparent; + padding-left: 1px; + padding-top: 1px; + border-radius: 5px; + border: 1px solid rgba(255, 255, 255, 13); +} + +QMenu::item { + background-color: transparent; + padding: 5px 15px; + border-radius: 5px; + min-width: 60px; + margin: 3px; +} + +QMenu::item:selected { + background-color: rgba(255, 255, 255, 16); +} + +QMenu::item:pressed { + background-color: rgba(255, 255, 255, 10); +} + +QMenu::right-arrow { + image: url(:/resources/win/dark/TreeViewClose.png); + min-width: 40px; + min-height: 18px; +} + +QMenuBar:disabled { + color: rgb(150, 150, 150); +} + +QMenu::item:disabled { + color: rgb(150, 150, 150); + background-color: transparent; +} + +/*PUSHBUTTON*/ +QPushButton { + background-color: rgba(255, 255, 255, 18); + border: 1px solid rgba(255, 255, 255, 13); + border-radius: 7px; + min-height: 38px; + max-height: 38px; + padding-left: 7px; + padding-right: 7px; +} + +QPushButton:hover { + background-color: rgba(255, 255, 255, 25); + border: 1px solid rgba(255, 255, 255, 10); +} + +QPushButton::pressed { + background-color: rgba(255, 255, 255, 7); + border: 1px solid rgba(255, 255, 255, 13); + color: rgba(255, 255, 255, 200); +} + +QPushButton::disabled { + color: rgb(150, 150, 150); + background-color: rgba(255, 255, 255, 13); +} + +/*RADIOBUTTON*/ +QRadioButton { + min-height: 30px; + max-height: 30px; +} + +QRadioButton::indicator { + width: 22px; + height: 22px; + border-radius: 13px; + border: 2px solid #848484; + background-color: rgba(255, 255, 255, 0); + margin-right: 5px; +} + +QRadioButton::indicator:hover { + background-color: rgba(255, 255, 255, 16); +} + +QRadioButton::indicator:pressed { + background-color: rgba(255, 255, 255, 20); + border: 2px solid #434343; + image: url(:/resources/win/dark/RadioButton.png); +} + +QRadioButton::indicator:checked { + background-color: %1; + border: 2px solid %1; + image: url(:/resources/win/dark/RadioButton.png); +} + +QRadioButton::indicator:checked:hover { + image: url(:/resources/win/dark/RadioButtonHover.png); +} + +QRadioButton::indicator:checked:pressed { + image: url(:/resources/win/dark/RadioButtonPressed.png); +} + +QRadioButton:disabled { + color: rgb(150, 150, 150); +} + +QRadioButton::indicator:disabled { + border: 2px solid #646464; + background-color: rgba(255, 255, 255, 0); +} + +/*CHECKBOX*/ +QCheckBox { + min-height: 30px; + max-height: 30px; +} + +QCheckBox::indicator { + width: 22px; + height: 22px; + border-radius: 5px; + border: 2px solid #848484; + background-color: rgba(255, 255, 255, 0); + margin-right: 5px; +} + +QCheckBox::indicator:hover { + background-color: rgba(255, 255, 255, 16); +} + +QCheckBox::indicator:pressed { + background-color: rgba(255, 255, 255, 20); + border: 2px solid #434343; +} + +QCheckBox::indicator:checked { + background-color: %1; + border: 2px solid %1; + image: url(:/CheckBox/img dark/CheckBox.png); +} + +QCheckBox::indicator:checked:pressed { + image: url(:/resources/win/dark/CheckBoxPressed.png); +} + +QCheckBox:disabled { + color: rgb(150, 150, 150); +} + +QCheckBox::indicator:disabled { + border: 2px solid #646464; + background-color: rgba(255, 255, 255, 0); +} + +/*GROUPBOX*/ +QGroupBox { + border-radius: 5px; + border: 1px solid rgba(255, 255, 255, 13); + margin-top: 30px; + background-color: rgba(255, 255, 255, 16); +} + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + /* padding: 7px 15px; */ + /* margin-left: 5px; */ + /* border-top-left-radius: 5px; */ + /* border-top-right-radius: 5px; */ +} + +QGroupBox::title::disabled { + color: rgb(150, 150, 150) +} + +/*TABWIDGET*/ +QTabWidget { +} + +QWidget { + border-radius: 5px; +} + +QTabWidget::pane { + border: 1px solid rgb(43, 43, 43); + border-radius: 5px; +} + +QTabWidget::tab-bar { + left: 5px; +} + +QTabBar::tab { + background-color: rgba(255, 255, 255, 0); + padding: 7px 15px; + margin-right: 2px; +} + +QTabBar::tab:hover { + background-color: rgba(255, 255, 255, 13); + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} + +QTabBar::tab:selected { + background-color: rgba(255, 255, 255, 16); + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} + +QTabBar::tab:disabled { + color: rgb(150, 150, 150) +} + +/*SPINBOX*/ +QSpinBox { + background-color: rgba(255, 255, 255, 10); + border: 1px solid rgba(255, 255, 255, 13); + border-radius: 5px; + padding-left: 10px; + min-height: 38px; + max-height: 38px; + min-width: 100px; + border-bottom: 1px solid rgba(255, 255, 255, 150); +} + +QSpinBox:hover { + background-color: rgba(255, 255, 255, 16); + border: 1px solid rgba(255, 255, 255, 13); + border-bottom: 1px solid rgba(255, 255, 255, 150); +} + +QSpinBox::focus { + background-color: rgba(255, 255, 255, 5); + border: 1px solid rgba(255, 255, 255, 13); + color: rgba(255, 255, 255, 200); + border-bottom: 2px solid %1; +} + +QSpinBox::up-button { + image: url(:/resources/win/dark/SpinBoxUp.png); + background-color: rgba(0, 0, 0, 0); + border: 1px solid rgba(0, 0, 0, 0); + border-radius: 4px; + margin-top: 1px; + margin-bottom: 1px; + margin-right: 2px; + min-width: 30px; + max-width: 30px; + min-height: 20px; +} + +QSpinBox::up-button:hover { + background-color: rgba(255, 255, 255, 13); +} + +QSpinBox::up-button:pressed { + background-color: rgba(255, 255, 255, 5); +} + +QSpinBox::down-button { + image: url(:/resources/win/dark/SpinBoxDown.png); + background-color: rgba(0, 0, 0, 0); + border: 1px solid rgba(0, 0, 0, 0); + border-radius: 4px; + margin-top: 1px; + margin-bottom: 1px; + margin-right: 2px; + min-width: 30px; + max-width: 30px; + min-height: 20px; +} + +QSpinBox::down-button:hover { + background-color: rgba(255, 255, 255, 13); +} + +QSpinBox::down-button:pressed { + background-color: rgba(255, 255, 255, 5); +} + +QSpinBox::drop-down { + background-color: transparent; + width: 50px; +} + +QSpinBox:disabled { + color: rgb(150, 150, 150); + background-color: rgba(255, 255, 255, 13); + border: 1px solid rgba(255, 255, 255, 5); +} + +QSpinBox::up-button:disabled { + image: url(:/resources/win/dark/SpinBoxUpDisabled.png); +} + +QSpinBox::down-button:disabled { + image: url(:/resources/win/dark/SpinBoxDownDisabled.png); +} + +/*DOUBLESPINBOX*/ +QDoubleSpinBox { + background-color: rgba(255, 255, 255, 10); + border: 1px solid rgba(255, 255, 255, 13); + border-radius: 5px; + padding-left: 10px; + min-height: 38px; + max-height: 38px; + min-width: 100px; + border-bottom: 1px solid rgba(255, 255, 255, 150); +} + +QDoubleSpinBox:hover { + background-color: rgba(255, 255, 255, 16); + border: 1px solid rgba(255, 255, 255, 13); + border-bottom: 1px solid rgba(255, 255, 255, 150); +} + +QDoubleSpinBox::focus { + background-color: rgba(255, 255, 255, 5); + border: 1px solid rgba(255, 255, 255, 13); + color: rgba(255, 255, 255, 200); + border-bottom: 2px solid %1; +} + +QDoubleSpinBox::up-button { + image: url(:/resources/win/dark/SpinBoxUp.png); + background-color: rgba(0, 0, 0, 0); + border: 1px solid rgba(0, 0, 0, 0); + border-radius: 4px; + margin-top: 1px; + margin-bottom: 1px; + margin-right: 2px; + min-width: 30px; + max-width: 30px; + min-height: 20px; +} + +QDoubleSpinBox::up-button:hover { + background-color: rgba(255, 255, 255, 13); +} + +QDoubleSpinBox::up-button:pressed { + background-color: rgba(255, 255, 255, 5); +} + +QDoubleSpinBox::down-button { + image: url(:/resources/win/dark/SpinBoxDown.png); + background-color: rgba(0, 0, 0, 0); + border: 1px solid rgba(0, 0, 0, 0); + border-radius: 4px; + margin-top: 1px; + margin-bottom: 1px; + margin-right: 2px; + min-width: 30px; + max-width: 30px; + min-height: 20px; +} + +QDoubleSpinBox::down-button:hover { + background-color: rgba(255, 255, 255, 13); +} + +QDoubleSpinBox::down-button:pressed { + background-color: rgba(255, 255, 255, 5); +} + +QDoubleSpinBox::drop-down { + background-color: transparent; + width: 50px; +} + +QDoubleSpinBox:disabled { + color: rgb(150, 150, 150); + background-color: rgba(255, 255, 255, 13); + border: 1px solid rgba(255, 255, 255, 5); +} + +QDoubleSpinBox::up-button:disabled { + image: url(:/resources/win/dark/SpinBoxUpDisabled.png); +} + +QDoubleSpinBox::down-button:disabled { + image: url(:/resources/win/dark/SpinBoxDownDisabled.png); +} + +/*DATETIMEEDIT*/ +QDateTimeEdit { + background-color: rgba(255, 255, 255, 10); + border: 1px solid rgba(255, 255, 255, 13); + border-radius: 5px; + padding-left: 10px; + min-height: 38px; + max-height: 38px; + min-width: 100px; + border-bottom: 1px solid rgba(255, 255, 255, 150); +} + +QDateTimeEdit:hover { + background-color: rgba(255, 255, 255, 16); + border: 1px solid rgba(255, 255, 255, 13); + border-bottom: 1px solid rgba(255, 255, 255, 150); +} + +QDateTimeEdit::focus { + background-color: rgba(255, 255, 255, 5); + border: 1px solid rgba(255, 255, 255, 13); + color: rgba(255, 255, 255, 200); + border-bottom: 2px solid %1; +} + +QDateTimeEdit::up-button { + image: url(:/resources/win/dark/SpinBoxUp.png); + background-color: rgba(0, 0, 0, 0); + border: 1px solid rgba(0, 0, 0, 0); + border-radius: 4px; + margin-top: 1px; + margin-bottom: 1px; + margin-right: 2px; + min-width: 30px; + max-width: 30px; + min-height: 20px; +} + +QDateTimeEdit::up-button:hover { + background-color: rgba(255, 255, 255, 13); +} + +QDateTimeEdit::up-button:pressed { + background-color: rgba(255, 255, 255, 5); +} + +QDateTimeEdit::down-button { + image: url(:/resources/win/dark/SpinBoxDown.png); + background-color: rgba(0, 0, 0, 0); + border: 1px solid rgba(0, 0, 0, 0); + border-radius: 4px; + margin-top: 1px; + margin-bottom: 1px; + margin-right: 2px; + min-width: 30px; + max-width: 30px; + min-height: 20px; +} + +QDateTimeEdit::down-button:hover { + background-color: rgba(255, 255, 255, 13); +} + +QDateTimeEdit::down-button:pressed { + background-color: rgba(255, 255, 255, 5); +} + +QDateTimeEdit::drop-down { + background-color: transparent; + width: 50px; +} + +QDateTimeEdit:disabled { + color: rgb(150, 150, 150); + background-color: rgba(255, 255, 255, 13); + border: 1px solid rgba(255, 255, 255, 5); +} + +QDateTimeEdit::up-button:disabled { + image: url(:/resources/win/dark/SpinBoxUpDisabled.png); +} + +QDateTimeEdit::down-button:disabled { + image: url(:/resources/win/dark/SpinBoxDownDisabled.png); +} + +/*SLIDERVERTICAL*/ +QSlider:vertical { + min-width: 30px; + min-height: 100px; +} + +QSlider::groove:vertical { + width: 5px; + background-color: rgba(255, 255, 255, 150); + border-radius: 2px; +} + +QSlider::handle:vertical { + background-color: %1; + border: 6px solid #454545; + height: 13px; + min-width: 15px; + margin: 0px -10px; + border-radius: 12px +} + +QSlider::handle:vertical:hover { + background-color: %1; + border: 4px solid #454545; + height: 17px; + min-width: 15px; + margin: 0px -10px; + border-radius: 12px +} + +QSlider::handle:vertical:pressed { + background-color: %1; + border: 7px solid #454545; + height: 11px; + min-width: 15px; + margin: 0px -10px; + border-radius: 12px +} + +QSlider::groove:vertical:disabled { + background-color: rgba(255, 255, 255, 75); +} + +QSlider::handle:vertical:disabled { + background-color: #555555; + border: 6px solid #353535; +} + +/*SLIDERHORIZONTAL*/ +QSlider:horizontal { + min-width: 100px; + min-height: 30px; +} + +QSlider::groove:horizontal { + height: 5px; + background-color: rgba(255, 255, 255, 150); + border-radius: 2px; +} + +QSlider::handle:horizontal { + background-color: %1; + border: 6px solid #454545; + width: 13px; + min-height: 15px; + margin: -10px 0; + border-radius: 12px +} + +QSlider::handle:horizontal:hover { + background-color: %1; + border: 4px solid #454545; + width: 17px; + min-height: 15px; + margin: -10px 0; + border-radius: 12px +} + +QSlider::handle:horizontal:pressed { + background-color: %1; + border: 7px solid #454545; + width: 11px; + min-height: 15px; + margin: -10px 0; + border-radius: 12px +} + +QSlider::groove:horizontal:disabled { + background-color: rgba(255, 255, 255, 75); +} + +QSlider::handle:horizontal:disabled { + background-color: #555555; + border: 6px solid #353535; +} + +/*PROGRESSBAR*/ +QProgressBar { + background-color: qlineargradient(spread:reflect, x1:0.5, y1:0.5, x2:0.5, y2:1, stop:0.119403 rgba(255, 255, 255, 250), stop:0.273632 rgba(0, 0, 0, 0)); + border-radius: 2px; + min-height: 4px; + max-height: 4px; +} + +QProgressBar::chunk { + background-color: %1; + border-radius: 2px; +} + +/*COMBOBOX*/ +QComboBox { + background-color: rgba(255, 255, 255, 16); + border: 1px solid rgba(255, 255, 255, 13); + border-radius: 5px; + padding-left: 10px; + min-height: 38px; + max-height: 38px; +} + +QComboBox:hover { + background-color: rgba(255, 255, 255, 20); + border: 1px solid rgba(255, 255, 255, 10); +} + +QComboBox::pressed { + background-color: rgba(255, 255, 255, 20); + border: 1px solid rgba(255, 255, 255, 13); + color: rgba(255, 255, 255, 200); +} + +QComboBox::down-arrow { + image: url(:/resources/win/dark/ComboBox.png); +} + +QComboBox::drop-down { + background-color: transparent; + min-width: 50px; +} + +QComboBox:disabled { + color: rgb(150, 150, 150); + background-color: rgba(255, 255, 255, 13); + border: 1px solid rgba(255, 255, 255, 5); +} + +QComboBox::down-arrow:disabled { + image: url(:/resources/win/dark/ComboBoxDisabled.png); +} + +/*LINEEDIT*/ +QLineEdit { + background-color: rgba(255, 255, 255, 16); + border: 1px solid rgba(255, 255, 255, 13); + font-size: 16px; + font-family: "Segoe UI", serif; + font-weight: 500; + border-radius: 7px; + border-bottom: 1px solid rgba(255, 255, 255, 150); + padding: 5px; +} + +QLineEdit:hover { + background-color: rgba(255, 255, 255, 20); + border: 1px solid rgba(255, 255, 255, 10); + border-bottom: 1px solid rgba(255, 255, 255, 150); +} + +QLineEdit:focus { + border-bottom: 2px solid %1; + background-color: rgba(255, 255, 255, 5); + border-top: 1px solid rgba(255, 255, 255, 13); + border-left: 1px solid rgba(255, 255, 255, 13); + border-right: 1px solid rgba(255, 255, 255, 13); +} + +QLineEdit:disabled { + color: rgb(150, 150, 150); + background-color: rgba(255, 255, 255, 13); + border: 1px solid rgba(255, 255, 255, 5); +} + +/*SCROLLVERTICAL*/ +QScrollBar:vertical { + border: 6px solid rgba(255, 255, 255, 0); + margin: 14px 0px 14px 0px; + width: 16px; +} + +QScrollBar:vertical:hover { + border: 5px solid rgba(255, 255, 255, 0); +} + +QScrollBar::handle:vertical { + background-color: rgba(255, 255, 255, 130); + border-radius: 2px; + min-height: 25px; +} + +QScrollBar::sub-line:vertical { + image: url(:/resources/win/dark/ScrollTop.png); + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical:hover { + image: url(:/resources/win/dark/ScrollTopHover.png); +} + +QScrollBar::sub-line:vertical:pressed { + image: url(:/resources/win/dark/ScrollTopPressed.png); +} + +QScrollBar::add-line:vertical { + image: url(:/resources/win/dark/ScrollBottom.png); + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::add-line:vertical:hover { + image: url(:/resources/win/dark/ScrollBottomHover.png); +} + +QScrollBar::add-line:vertical:pressed { + image: url(:/resources/win/dark/ScrollBottomPressed.png); +} + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background: none; +} + +/*SCROLLHORIZONTAL*/ +QScrollBar:horizontal { + border: 6px solid rgba(255, 255, 255, 0); + margin: 0px 14px 0px 14px; + height: 16px; +} + +QScrollBar:horizontal:hover { + border: 5px solid rgba(255, 255, 255, 0); +} + +QScrollBar::handle:horizontal { + background-color: rgba(255, 255, 255, 130); + border-radius: 2px; + min-width: 25px; +} + +QScrollBar::sub-line:horizontal { + image: url(:/resources/win/dark/ScrollLeft.png); + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:horizontal:hover { + image: url(:/resources/win/dark/ScrollLeftHover.png); +} + +QScrollBar::sub-line:horizontal:pressed { + image: url(:/resources/win/dark/ScrollLeftPressed.png); +} + +QScrollBar::add-line:horizontal { + image: url(:/resources/win/dark/ScrollRight.png); + subcontrol-position: right; + subcontrol-origin: margin; +} + +QScrollBar::add-line:horizontal:hover { + image: url(:/resources/win/dark/ScrollRightHover.png); +} + +QScrollBar::add-line:horizontal:pressed { + image: url(:/resources/win/dark/ScrollRightPressed.png); +} + +QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { + background: none; +} + +/*TEXTEDIT*/ +QTextEdit { + background-color: rgba(255, 255, 255, 16); + border: 1px solid rgba(255, 255, 255, 13); + font-size: 16px; + font-family: "Segoe UI", serif; + font-weight: 500; + border-radius: 7px; + border-bottom: 1px solid rgba(255, 255, 255, 150); + padding: 5px; +} + +QTextEdit:hover { + background-color: rgba(255, 255, 255, 20); + border: 1px solid rgba(255, 255, 255, 10); + border-bottom: 1px solid rgba(255, 255, 255, 150); +} + +QTextEdit:focus { + border-bottom: 2px solid %1; + background-color: rgba(255, 255, 255, 5); + border-top: 1px solid rgba(255, 255, 255, 13); + border-left: 1px solid rgba(255, 255, 255, 13); + border-right: 1px solid rgba(255, 255, 255, 13); +} + +QTextEdit:disabled { + color: rgb(150, 150, 150); + background-color: rgba(255, 255, 255, 13); + border: 1px solid rgba(255, 255, 255, 5); +} + +/*CALENDAR*/ +QCalendarWidget { +} + +QCalendarWidget QToolButton { + height: 36px; + font-size: 18px; + background-color: rgba(255, 255, 255, 0); + margin: 5px; +} + +QCalendarWidget QWidget#qt_calendar_navigationbar { + background-color: rgba(255, 255, 255, 0); + border: 1px solid rgba(255, 255, 255, 13); + border-top-left-radius: 5px; + border-top-right-radius: 5px; + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; + border-bottom: none; +} + +#qt_calendar_prevmonth { + qproperty-icon: url(:/resources/win/dark/PrevMonth.png); + width: 32px; +} + +#qt_calendar_nextmonth { + qproperty-icon: url(:/resources/win/dark/NextMonth.png); + width: 32px; +} + +#qt_calendar_prevmonth:hover, #qt_calendar_nextmonth:hover { + background-color: rgba(255, 255, 255, 16); + border-radius: 5px; +} + +#qt_calendar_prevmonth:pressed, #qt_calendar_nextmonth:pressed { + background-color: rgba(255, 255, 255, 10); + border-radius: 5px; +} + +#qt_calendar_yearbutton, #qt_calendar_monthbutton { + color: white; + margin: 5px 0px; + padding: 0px 10px; +} + +#qt_calendar_yearbutton:hover, #qt_calendar_monthbutton:hover { + background-color: rgba(255, 255, 255, 16); + border-radius: 5px; +} + +#qt_calendar_yearbutton:pressed, #qt_calendar_monthbutton:pressed { + background-color: rgba(255, 255, 255, 10); + border-radius: 5px; +} + +QCalendarWidget QToolButton::menu-indicator#qt_calendar_monthbutton { + background-color: transparent; +} + +QCalendarWidget QMenu { + background-color : #202020; +} + +QCalendarWidget QSpinBox { + margin: 5px 0px; +} + +QCalendarWidget QSpinBox::focus { + background-color: rgba(255, 255, 255, 5); + border: 1px solid rgba(255, 255, 255, 13); + color: rgba(0, 0, 0, 200); + border-bottom: 2px solid %1; +} + +QCalendarWidget QSpinBox::up-button { + image: url(:/resources/win/dark/SpinBoxUp.png); + background-color: rgba(0, 0, 0, 0); + border: 1px solid rgba(0, 0, 0, 0); + border-radius: 4px; + margin-top: 1px; + margin-bottom: 1px; + margin-right: 2px; + min-width: 30px; + max-width: 30px; + min-height: 20px; +} + +QCalendarWidget QSpinBox::up-button:hover { + background-color: rgba(255, 255, 255, 13); +} + +QCalendarWidget QSpinBox::up-button:pressed { + background-color: rgba(255, 255, 255, 5); +} + +QCalendarWidget QSpinBox::down-button { + image: url(:/resources/win/dark/SpinBoxDown.png); + background-color: rgba(0, 0, 0, 0); + border: 1px solid rgba(0, 0, 0, 0); + border-radius: 4px; + margin-top: 1px; + margin-bottom: 1px; + margin-right: 2px; + min-width: 30px; + max-width: 30px; + min-height: 20px; +} + +QCalendarWidget QSpinBox::down-button:hover { + background-color: rgba(255, 255, 255, 13); +} + +QCalendarWidget QSpinBox::down-button:pressed { + background-color: rgba(255, 255, 255, 5); +} + +QCalendarWidget QWidget { + alternate-background-color: rgba(255, 255, 255, 0); +} + +QCalendarWidget QAbstractItemView:enabled { + color: rgb(255, 255, 255); + selection-background-color: %1; + selection-color: black; + border: 1px solid rgba(255, 255, 255, 13); + border-top-left-radius: 0px; + border-top-right-radius: 0px; + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; + outline: 0; +} + +QCalendarWidget QAbstractItemView:disabled { + color: rgb(150, 150, 150); + selection-background-color: rgb(150, 150, 150); + selection-color: black; + border: 1px solid rgba(255, 255, 255, 13); + border-top-left-radius: 0px; + border-top-right-radius: 0px; + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; +} + +#qt_calendar_yearbutton:disabled, #qt_calendar_monthbutton:disabled { + color: rgb(150, 150, 150); +} + +#qt_calendar_prevmonth:disabled { + qproperty-icon: url(:/resources/win/dark/PrevMonthDisabled.png); +} + +#qt_calendar_nextmonth:disabled { + qproperty-icon: url(:/resources/win/dark/NextMonthDisabled.png); +} + +/*TREEWIDGET*/ +QTreeView { + background-color: transparent; + border: 1px solid rgba(255, 255, 255, 13); + border-radius: 5px; + outline: 0; + padding-right: 5px; +} + +QTreeView::item { + padding: 7px; + margin-top: 3px; +} + +QTreeView::item:selected { + color: white; + background-color: rgba(255, 255, 255, 13); + border-radius: 5px; + margin-bottom: 3px; + padding-left: 0px; +} + +QTreeView::item:!selected:hover { + background-color: rgba(255, 255, 255, 16); + border-radius: 5px; + margin-bottom: 3px; + padding-left: 0px; +} + +QTreeView::branch:has-children:!has-siblings:closed, +QTreeView::branch:closed:has-children:has-siblings { + image: url(:/resources/win/dark/TreeViewClose.png); +} + +QTreeView::branch:open:has-children:!has-siblings, +QTreeView::branch:open:has-children:has-siblings { + image: url(:/resources/win/dark/TreeViewOpen.png); +} + +QTreeView:disabled { + color: rgb(150, 150, 150); +} + +/*TOGGLESWITCH*/ +#toggleSwitch { + color: rgb(255, 255, 255); + font-size: 17px; + font-family: "Segoe UI Variable Small", serif; + font-weight: 400; +} + +#toggleSwitch::indicator { + width: 22px; + height: 22px; + border-radius: 13px; + border: 2px solid #848484; + background-color: rgba(255, 255, 255, 0); + image: url(:/resources/win/dark/ToggleSwitchOff.png); + margin-right: 5px; + padding-right: 25px; + padding-left: 0px; +} + +#toggleSwitch::indicator:hover { + background-color: rgba(255, 255, 255, 13); + image: url(:/resources/win/dark/ToggleSwitchOffHover.png); +} + +#toggleSwitch::indicator:pressed { + background-color: rgba(255, 255, 255, 20); + width: 26px; + padding-right: 21px; + image: url(:/resources/win/dark/ToggleSwitchOffPressed.png); +} + +#toggleSwitch::indicator:checked { + background-color: %1; + border: 2px solid %1; + image: url(:/resources/win/dark/ToggleSwitchOn.png); + padding-left: 25px; + padding-right: 0px; +} + +#toggleSwitch::indicator:checked:hover { + background-color: %1; + image: url(:/resources/win/dark/ToggleSwitchOnHover.png); +} + +#toggleSwitch::indicator:checked:pressed { + background-color: %1; + width: 26px; + padding-left: 21px; + image: url(:/resources/win/dark/ToggleSwitchOnPressed.png); +} + +#toggleSwitch:disabled { + color: rgb(150, 150, 150); +} + +#toggleSwitch::indicator:disabled { + border: 2px solid #646464; + background-color: rgba(255, 255, 255, 0); + image: url(:/resources/win/dark/ToggleSwitchDisabled.png); +} + +/*HYPERLINKBUTTON*/ +#hyperlinkButton { + color: %1; + font-size: 17px; + font-family: "Segoe UI Variable Small", serif; + border-radius: 5px; + background-color: rgba(255, 255, 255, 0); + border: none; +} + +#hyperlinkButton:hover { + background-color: rgba(255, 255, 255, 20); +} + +#hyperlinkButton::pressed { + background-color: rgba(255, 255, 255, 15); + color: %1; +} + +#hyperlinkButton:disabled { + color: rgb(150, 150, 150) +} + +/*LISTVIEW*/ +QListView { + background-color: transparent; + font-size: 17px; + font-family: "Segoe UI Variable Small", serif; + font-weight: 400; + padding: 7px; + border-radius: 10px; + outline: 0; +} + +QListView::item { + height: 35px; +} + +QListView::item:selected { + background-color: rgba(255, 255, 255, 13); + color: white; + border-radius: 5px; + padding-left: 0px; +} \ No newline at end of file diff --git a/resources/win.light.qcss b/resources/win.light.qcss new file mode 100644 index 0000000..3f34631 --- /dev/null +++ b/resources/win.light.qcss @@ -0,0 +1,1124 @@ +QWidget { + background: transparent; + color: rgb(0, 0, 0); + font-size: 17px; + font-family: "Segoe UI Variable Small", serif; + font-weight: 400; +} + +/*MENU*/ +QMenuBar { + background-color: transparent; + color: rgba(0, 0, 0); + padding: 10px; + font-size: 17px; + font-family: "Segoe UI Variable Small", serif; + font-weight: 400; +} + +QMenuBar::item { + background-color: transparent; + padding: 10px 13px; + margin-left: 5px; + border-radius: 5px; +} + +QMenuBar::item:selected { + background-color: rgb(0, 0, 0, 10); +} + +QMenuBar::item:pressed { + background-color: rgb(0, 0, 0, 7); + color: rgb(0, 0, 0, 150); +} + +QMenu { + background-color: transparent; + padding-left: 1px; + padding-top: 1px; + border-radius: 5px; + border: 1px solid rgb(0, 0, 0, 13); +} + +QMenu::item { + background-color: transparent; + padding: 5px 15px; + border-radius: 5px; + min-width: 60px; + margin: 3px; +} + +QMenu::item:selected { + background-color: rgb(0, 0, 0, 10); +} + +QMenu::item:pressed { + background-color: rgb(0, 0, 0, 7); +} + +QMenu::right-arrow { + image: url(:/resources/win/light/TreeViewClose.png); + min-width: 40px; + min-height: 18px; +} + +QMenuBar:disabled { + color: rgb(0, 0, 0, 150); +} + +QMenu::item:disabled { + color: rgb(0, 0, 0, 150); + background-color: transparent; +} + +/*PUSHBUTTON*/ +QPushButton { + background-color: rgb(0, 0, 0, 7); + border: 1px solid rgb(0, 0, 0, 13); + border-radius: 7px; + min-height: 38px; + max-height: 38px; +} + +QPushButton:hover { + background-color: rgb(0, 0, 0, 10); + border: 1px solid rgb(0, 0, 0, 13); +} + +QPushButton::pressed { + color: rgb(0, 0, 0, 150); +} + +QPushButton::disabled { + color: rgb(0, 0, 0, 110); + background-color: rgb(0, 0, 0, 13); + border: 1px solid rgb(0, 0, 0, 5); +} + +/*RADIOBUTTON*/ +QRadioButton { + min-height: 30px; + max-height: 30px; +} + +QRadioButton::indicator { + width: 22px; + height: 22px; + border-radius: 13px; + border: 2px solid #999999; + background-color: rgb(0, 0, 0, 5); + margin-right: 5px; +} + +QRadioButton::indicator:hover { + background-color: rgb(0, 0, 0, 0); +} + +QRadioButton::indicator:pressed { + background-color: rgb(0, 0, 0, 5); + border: 2px solid #bbbbbb; + image: url(:/resources/win/light/RadioButton.png); +} + +QRadioButton::indicator:checked { + background-color: %1; + border: 2px solid %1; + image: url(:/resources/win/light/RadioButton.png); + color: rgb(255, 255, 255); +} + +QRadioButton::indicator:checked:hover { + image: url(:/resources/win/light/RadioButtonHover.png); +} + +QRadioButton::indicator:checked:pressed { + image: url(:/resources/win/light/RadioButtonPressed.png); +} + +QRadioButton:disabled { + color: rgb(0, 0, 0, 110); +} + +QRadioButton::indicator:disabled { + border: 2px solid #bbbbbb; + background-color: rgb(0, 0, 0, 0); +} + +/*CHECKBOX*/ +QCheckBox { + min-height: 30px; + max-height: 30px; +} + +QCheckBox::indicator { + width: 22px; + height: 22px; + border-radius: 5px; + border: 2px solid #999999; + background-color: rgb(0, 0, 0, 0); + margin-right: 5px; +} + +QCheckBox::indicator:hover { + background-color: rgb(0, 0, 0, 15); +} + +QCheckBox::indicator:pressed { + background-color: rgb(0, 0, 0, 24); + border: 2px solid #bbbbbb; +} + +QCheckBox::indicator:checked { + background-color: %1; + border: 2px solid %1; + image: url(:/resources/win/light/CheckBox.png); + color: rgb(255, 255, 255); +} + +QCheckBox::indicator:checked:pressed { + image: url(:/resources/win/light/CheckBoxPressed.png); +} + +QCheckBox:disabled { + color: rgb(0, 0, 0, 110); +} + +QCheckBox::indicator:disabled { + border: 2px solid #bbbbbb; + background-color: rgb(0, 0, 0, 0); +} + +/*GROUPBOX*/ +QGroupBox { + border-radius: 5px; + border: 1px solid rgb(0, 0, 0, 13); + margin-top: 36px; +} + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + background-color: rgb(0, 0, 0, 10); + padding: 7px 15px; + margin-left: 5px; + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} + +QGroupBox::title::disabled { + color: rgb(0, 0, 0, 150); +} + +/*TABWIDGET*/ +QTabWidget { +} + +QWidget { + border-radius: 5px; +} + +QTabWidget::pane { + border: 1px solid rgb(0, 0, 0, 13); + border-radius: 5px; +} + +QTabWidget::tab-bar { + left: 5px; +} + +QTabBar::tab { + background-color: rgb(0, 0, 0, 0); + padding: 7px 15px; + margin-right: 2px; +} + +QTabBar::tab:hover { + background-color: rgb(0, 0, 0, 13); + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} + +QTabBar::tab:selected { + background-color: rgb(0, 0, 0, 10); + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} + +QTabBar::tab:disabled { + color: rgb(0, 0, 0, 150) +} + +/*SPINBOX*/ +QSpinBox { + background-color: rgb(0, 0, 0, 7); + border: 1px solid rgb(0, 0, 0, 13); + border-radius: 5px; + padding-left: 10px; + min-height: 38px; + max-height: 38px; + min-width: 100px; + border-bottom: 1px solid rgb(0, 0, 0, 100); +} + +QSpinBox:hover { + background-color: rgb(0, 0, 0, 13); + border: 1px solid rgb(0, 0, 0, 13); + border-bottom: 1px solid rgb(0, 0, 0, 100); +} + +QSpinBox::focus { + background-color: rgb(0, 0, 0, 5); + border: 1px solid rgb(0, 0, 0, 10); + color: rgb(0, 0, 0, 200); + border-bottom: 2px solid %1; +} + +QSpinBox::up-button { + image: url(:/resources/win/light/SpinBoxUp.png); + background-color: rgb(0, 0, 0, 0); + border: 1px solid rgb(0, 0, 0, 0); + border-radius: 4px; + margin-top: 1px; + margin-bottom: 1px; + margin-right: 2px; + min-width: 30px; + max-width: 30px; + min-height: 20px; +} + +QSpinBox::up-button:hover { + background-color: rgb(0, 0, 0, 10); +} + +QSpinBox::up-button:pressed { + background-color: rgb(0, 0, 0, 5); +} + +QSpinBox::down-button { + image: url(:/resources/win/light/SpinBoxDown.png); + background-color: rgb(0, 0, 0, 0); + border: 1px solid rgb(0, 0, 0, 0); + border-radius: 4px; + margin-top: 1px; + margin-bottom: 1px; + margin-right: 2px; + min-width: 30px; + max-width: 30px; + min-height: 20px; +} + +QSpinBox::down-button:hover { + background-color: rgb(0, 0, 0, 10); +} + +QSpinBox::down-button:pressed { + background-color: rgb(0, 0, 0, 5); +} + +QSpinBox::drop-down { + background-color: transparent; + width: 50px; +} + +QSpinBox:disabled { + color: rgb(0, 0, 0, 110); + background-color: rgb(0, 0, 0, 13); + border: 1px solid rgb(0, 0, 0, 5); +} + +QSpinBox::up-button:disabled { + image: url(:/resources/win/light/SpinBoxUpDisabled.png); +} + +QSpinBox::down-button:disabled { + image: url(:/resources/win/light/SpinBoxDownDisabled.png); +} + +/*DOUBLESPINBOX*/ +QDoubleSpinBox { + background-color: rgb(0, 0, 0, 7); + border: 1px solid rgb(0, 0, 0, 13); + border-radius: 5px; + padding-left: 10px; + min-height: 38px; + max-height: 38px; + min-width: 100px; + border-bottom: 1px solid rgb(0, 0, 0, 100); +} + +QDoubleSpinBox:hover { + background-color: rgb(0, 0, 0, 13); + border: 1px solid rgb(0, 0, 0, 13); + border-bottom: 1px solid rgb(0, 0, 0, 100); +} + +QDoubleSpinBox::focus { + background-color: rgb(0, 0, 0, 5); + border: 1px solid rgb(0, 0, 0, 10); + color: rgb(0, 0, 0, 200); + border-bottom: 2px solid %1; +} + +QDoubleSpinBox::up-button { + image: url(:/resources/win/light/SpinBoxUp.png); + background-color: rgb(0, 0, 0, 0); + border: 1px solid rgb(0, 0, 0, 0); + border-radius: 4px; + margin-top: 1px; + margin-bottom: 1px; + margin-right: 2px; + min-width: 30px; + max-width: 30px; + min-height: 20px; +} + +QDoubleSpinBox::up-button:hover { + background-color: rgb(0, 0, 0, 10); +} + +QDoubleSpinBox::up-button:pressed { + background-color: rgb(0, 0, 0, 5); +} + +QDoubleSpinBox::down-button { + image: url(:/resources/win/light/SpinBoxDown.png); + background-color: rgb(0, 0, 0, 0); + border: 1px solid rgb(0, 0, 0, 0); + border-radius: 4px; + margin-top: 1px; + margin-bottom: 1px; + margin-right: 2px; + min-width: 30px; + max-width: 30px; + min-height: 20px; +} + +QDoubleSpinBox::down-button:hover { + background-color: rgb(0, 0, 0, 10); +} + +QDoubleSpinBox::down-button:pressed { + background-color: rgb(0, 0, 0, 5); +} + +QDoubleSpinBox::drop-down { + background-color: transparent; + width: 50px; +} + +QDoubleSpinBox:disabled { + color: rgb(0, 0, 0, 110); + background-color: rgb(0, 0, 0, 13); + border: 1px solid rgb(0, 0, 0, 5); +} + +QDoubleSpinBox::up-button:disabled { + image: url(:/resources/win/light/SpinBoxUpDisabled.png); +} + +QDoubleSpinBox::down-button:disabled { + image: url(:/resources/win/light/SpinBoxDownDisabled.png); +} + +/*DATETIMEEDIT*/ +QDateTimeEdit { + background-color: rgb(0, 0, 0, 7); + border: 1px solid rgb(0, 0, 0, 13); + border-radius: 5px; + padding-left: 10px; + min-height: 38px; + max-height: 38px; + min-width: 100px; + border-bottom: 1px solid rgb(0, 0, 0, 100); +} + +QDateTimeEdit:hover { + background-color: rgb(0, 0, 0, 13); + border: 1px solid rgb(0, 0, 0, 13); + border-bottom: 1px solid rgb(0, 0, 0, 100); +} + +QDateTimeEdit::focus { + background-color: rgb(0, 0, 0, 5); + border: 1px solid rgb(0, 0, 0, 10); + color: rgb(0, 0, 0, 200); + border-bottom: 2px solid %1; +} + +QDateTimeEdit::up-button { + image: url(:/resources/win/light/SpinBoxUp.png); + background-color: rgb(0, 0, 0, 0); + border: 1px solid rgb(0, 0, 0, 0); + border-radius: 4px; + margin-top: 1px; + margin-bottom: 1px; + margin-right: 2px; + min-width: 30px; + max-width: 30px; + min-height: 20px; +} + +QDateTimeEdit::up-button:hover { + background-color: rgb(0, 0, 0, 10); +} + +QDateTimeEdit::up-button:pressed { + background-color: rgb(0, 0, 0, 5); +} + +QDateTimeEdit::down-button { + image: url(:/resources/win/light/SpinBoxDown.png); + background-color: rgb(0, 0, 0, 0); + border: 1px solid rgb(0, 0, 0, 0); + border-radius: 4px; + margin-top: 1px; + margin-bottom: 1px; + margin-right: 2px; + min-width: 30px; + max-width: 30px; + min-height: 20px; +} + +QDateTimeEdit::down-button:hover { + background-color: rgb(0, 0, 0, 10); +} + +QDateTimeEdit::down-button:pressed { + background-color: rgb(0, 0, 0, 5); +} + +QDateTimeEdit::drop-down { + background-color: transparent; + width: 50px; +} + +QDateTimeEdit:disabled { + color: rgb(0, 0, 0, 110); + background-color: rgb(0, 0, 0, 13); + border: 1px solid rgb(0, 0, 0, 5); +} + +QDateTimeEdit::up-button:disabled { + image: url(:/resources/win/light/SpinBoxUpDisabled.png); +} + +QDateTimeEdit::down-button:disabled { + image: url(:/resources/win/light/SpinBoxDownDisabled.png); +} + +/*SLIDERVERTICAL*/ +QSlider:vertical { + min-width: 30px; + min-height: 100px; +} + +QSlider::groove:vertical { + width: 5px; + background-color: rgb(0, 0, 0, 100); + border-radius: 2px; +} + +QSlider::handle:vertical { + background-color: %1; + border: 6px solid #dbdbdb; + height: 13px; + min-width: 15px; + margin: 0px -10px; + border-radius: 12px; +} + +QSlider::handle:vertical:hover { + background-color: %1; + border: 4px solid #dbdbdb; + height: 17px; + min-width: 15px; + margin: 0px -10px; + border-radius: 12px +} + +QSlider::handle:vertical:pressed { + background-color: %1; + border: 7px solid #dbdbdb; + height: 11px; + min-width: 15px; + margin: 0px -10px; + border-radius: 12px +} + +QSlider::groove:vertical:disabled { + background-color: rgb(0, 0, 0, 75); +} + +QSlider::handle:vertical:disabled { + background-color: #808080; + border: 6px solid #cccccc; +} + +/*SLIDERHORIZONTAL*/ +QSlider:horizontal { + min-width: 100px; + min-height: 30px; +} + +QSlider::groove:horizontal { + height: 5px; + background-color: rgb(0, 0, 0, 100); + border-radius: 2px; +} + +QSlider::handle:horizontal { + background-color: %1; + border: 6px solid #dbdbdb; + width: 13px; + min-height: 15px; + margin: -10px 0; + border-radius: 12px +} + +QSlider::handle:horizontal:hover { + background-color: %1; + border: 4px solid #dbdbdb; + width: 17px; + min-height: 15px; + margin: -10px 0; + border-radius: 12px +} + +QSlider::handle:horizontal:pressed { + background-color: %1; + border: 7px solid #dbdbdb; + width: 11px; + min-height: 15px; + margin: -10px 0; + border-radius: 12px +} + +QSlider::groove:horizontal:disabled { + background-color: rgb(0, 0, 0, 75); +} + +QSlider::handle:horizontal:disabled { + background-color: #808080; + border: 6px solid #cccccc; +} + +/*PROGRESSBAR*/ +QProgressBar { + background-color: qlineargradient(spread:reflect, x1:0.5, y1:0.5, x2:0.5, y2:1, stop:0.233831 rgba(0, 0, 0, 255), stop:0.343284 rgba(0, 0, 0, 0)); + border-radius: 2px; + min-height: 4px; + max-height: 4px; +} + +QProgressBar::chunk { + background-color: %1; + border-radius: 2px; +} + +/*COMBOBOX*/ +QComboBox { + background-color: rgb(0, 0, 0, 7); + border: 1px solid rgb(0, 0, 0, 13); + border-radius: 5px; + padding-left: 10px; + min-height: 38px; + max-height: 38px; +} + +QComboBox:hover { + background-color: rgb(0, 0, 0, 13); + border: 1px solid rgb(0, 0, 0, 13); +} + +QComboBox::pressed { + border: 1px solid rgb(0, 0, 0, 10); +} + +QComboBox::down-arrow { + image: url(:/resources/win/light/ComboBox.png); +} + +QComboBox::drop-down { + background-color: transparent; + min-width: 50px; +} + +QComboBox:disabled { + color: rgb(0, 0, 0, 110); + background-color: rgb(0, 0, 0, 13); + border: 1px solid rgb(0, 0, 0, 5); +} + +QComboBox::down-arrow:disabled { + image: url(:/resources/win/light/ComboBoxDisabled.png); +} + +/*LINEEDIT*/ +QLineEdit { + background-color: rgb(0, 0, 0, 7); + border: 1px solid rgb(0, 0, 0, 13); + font-size: 16px; + font-family: "Segoe UI", serif; + font-weight: 500; + border-radius: 7px; + border-bottom: 1px solid rgb(0, 0, 0, 100); + padding-top: 0px; + padding-left: 5px; +} + +QLineEdit:hover { + background-color: rgb(0, 0, 0, 13); + border: 1px solid rgb(0, 0, 0, 13); + border-bottom: 1px solid rgb(0, 0, 0, 100); +} + +QLineEdit:focus { + border-bottom: 2px solid %1; + background-color: rgb(0, 0, 0, 5); + border-top: 1px solid rgb(0, 0, 0, 13); + border-left: 1px solid rgb(0, 0, 0, 13); + border-right: 1px solid rgb(0, 0, 0, 13); +} + +QLineEdit:disabled { + color: rgb(0, 0, 0, 150); + background-color: rgb(0, 0, 0, 13); + border: 1px solid rgb(0, 0, 0, 5); +} + +/*SCROLLVERTICAL*/ +QScrollBar:vertical { + border: 6px solid rgb(0, 0, 0, 0); + margin: 14px 0px 14px 0px; + width: 16px; +} + +QScrollBar:vertical:hover { + border: 5px solid rgb(0, 0, 0, 0); +} + +QScrollBar::handle:vertical { + background-color: rgb(0, 0, 0, 110); + border-radius: 2px; + min-height: 25px; +} + +QScrollBar::sub-line:vertical { + image: url(:/resources/win/light/ScrollTop.png); + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical:hover { + image: url(:/resources/win/light/ScrollTopHover.png); +} + +QScrollBar::sub-line:vertical:pressed { + image: url(:/resources/win/light/ScrollTopPressed.png); +} + +QScrollBar::add-line:vertical { + image: url(:/resources/win/light/ScrollBottom.png); + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::add-line:vertical:hover { + image: url(:/resources/win/light/ScrollBottomHover.png); +} + +QScrollBar::add-line:vertical:pressed { + image: url(:/resources/win/light/ScrollBottomPressed.png); +} + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background: none; +} + +/*SCROLLHORIZONTAL*/ +QScrollBar:horizontal { + border: 6px solid rgb(0, 0, 0, 0); + margin: 0px 14px 0px 14px; + height: 16px; +} + +QScrollBar:horizontal:hover { + border: 5px solid rgb(0, 0, 0, 0); +} + +QScrollBar::handle:horizontal { + background-color: rgb(0, 0, 0, 110); + border-radius: 2px; + min-width: 25px; +} + +QScrollBar::sub-line:horizontal { + image: url(:/resources/win/light/ScrollLeft.png); + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:horizontal:hover { + image: url(:/resources/win/light/ScrollLeftHover.png); +} + +QScrollBar::sub-line:horizontal:pressed { + image: url(:/resources/win/light/ScrollLeftPressed.png); +} + +QScrollBar::add-line:horizontal { + image: url(:/resources/win/light/ScrollRight.png); + subcontrol-position: right; + subcontrol-origin: margin; +} + +QScrollBar::add-line:horizontal:hover { + image: url(:/resources/win/light/ScrollRightHover.png); +} + +QScrollBar::add-line:horizontal:pressed { + image: url(:/resources/win/light/ScrollRightPressed.png); +} + +QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { + background: none; +} + +/*TEXTEDIT*/ +QTextEdit { + background-color: rgb(0, 0, 0, 7); + border: 1px solid rgb(0, 0, 0, 13); + font-size: 16px; + font-family: "Segoe UI", serif; + font-weight: 500; + border-radius: 7px; + border-bottom: 1px solid rgb(0, 0, 0, 100); + padding: 5px; +} + +QTextEdit:hover { + background-color: rgb(0, 0, 0, 13); + border: 1px solid rgb(0, 0, 0, 13); + border-bottom: 1px solid rgb(0, 0, 0, 100); +} + +QTextEdit:focus { + background-color: rgb(0, 0, 0, 5); + border-top: 1px solid rgb(0, 0, 0, 13); + border-left: 1px solid rgb(0, 0, 0, 13); + border-right: 1px solid rgb(0, 0, 0, 13); + border-bottom: 2px solid %1; +} + +QTextEdit:disabled { + color: rgb(0, 0, 0, 110); + background-color: rgb(0, 0, 0, 13); + border: 1px solid rgb(0, 0, 0, 5); +} + +/*CALENDAR*/ +QCalendarWidget { +} + +QCalendarWidget QToolButton { + height: 36px; + font-size: 18px; + background-color: rgb(0, 0, 0, 0); + margin: 5px; +} + +QCalendarWidget QWidget#qt_calendar_navigationbar { + background-color: rgb(0, 0, 0, 0); + border: 1px solid rgb(0, 0, 0, 13); + border-top-left-radius: 5px; + border-top-right-radius: 5px; + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; + border-bottom: none; +} + +QCalendarWidget QMenu { + background-color : #f3f3f3; +} + +#qt_calendar_prevmonth { + qproperty-icon: url(:/resources/win/light/PrevMonth.png); + width: 32px; +} + +#qt_calendar_nextmonth { + qproperty-icon: url(:/resources/win/light/NextMonth.png); + width: 32px; +} + +#qt_calendar_prevmonth:hover, #qt_calendar_nextmonth:hover { + background-color: rgb(0, 0, 0, 10); + border-radius: 5px; +} + +#qt_calendar_prevmonth:pressed, #qt_calendar_nextmonth:pressed { + background-color: rgb(0, 0, 0, 7); + border-radius: 5px; +} + +#qt_calendar_yearbutton, #qt_calendar_monthbutton { + color: rgb(0, 0, 0); + margin: 5px 0px; + padding: 0px 10px; +} + +#qt_calendar_yearbutton:hover, #qt_calendar_monthbutton:hover { + background-color: rgb(0, 0, 0, 10); + border-radius: 5px; +} + +#qt_calendar_yearbutton:pressed, #qt_calendar_monthbutton:pressed { + background-color: rgb(0, 0, 0, 7); + border-radius: 5px; +} + +QCalendarWidget QToolButton::menu-indicator#qt_calendar_monthbutton { + background-color: transparent; +} + +QCalendarWidget QSpinBox { + margin: 5px 0px; +} + +QCalendarWidget QSpinBox::focus { + background-color: rgb(0, 0, 0, 5); + border: 1px solid rgb(0, 0, 0, 10); + color: rgb(0, 0, 0, 200); + border-bottom: 2px solid %1; +} + +QCalendarWidget QSpinBox::up-button { + image: url(:/resources/win/light/SpinBoxUp.png); + background-color: rgb(0, 0, 0, 0); + border: 1px solid rgb(0, 0, 0, 0); + border-radius: 4px; + margin-top: 1px; + margin-bottom: 1px; + margin-right: 2px; + min-width: 30px; + max-width: 30px; + min-height: 20px; +} + +QCalendarWidget QSpinBox::up-button:hover { + background-color: rgb(0, 0, 0, 10); +} + +QCalendarWidget QSpinBox::up-button:pressed { + background-color: rgb(0, 0, 0, 5); +} + +QCalendarWidget QSpinBox::down-button { + image: url(:/resources/win/light/SpinBoxDown.png); + background-color: rgb(0, 0, 0, 0); + border: 1px solid rgb(0, 0, 0, 0); + border-radius: 4px; + margin-top: 1px; + margin-bottom: 1px; + margin-right: 2px; + min-width: 30px; + max-width: 30px; + min-height: 20px; +} + +QCalendarWidget QSpinBox::down-button:hover { + background-color: rgb(0, 0, 0, 10); +} + +QCalendarWidget QSpinBox::down-button:pressed { + background-color: rgb(0, 0, 0, 5); +} + +QCalendarWidget QWidget { + alternate-background-color: rgb(0, 0, 0, 0); +} + +QCalendarWidget QAbstractItemView:enabled { + color: rgb(0, 0, 0); + selection-background-color: %1; + selection-color: black; + border: 1px solid rgb(0, 0, 0, 10); + border-top-left-radius: 0px; + border-top-right-radius: 0px; + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; + outline: 0; +} + +QCalendarWidget QAbstractItemView:disabled { + color: rgb(30, 30, 30); + selection-background-color: rgb(30, 30, 30); + selection-color: black; + border: 1px solid rgb(0, 0, 0, 13); + border-top-left-radius: 0px; + border-top-right-radius: 0px; + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; +} + +#qt_calendar_yearbutton:disabled, #qt_calendar_monthbutton:disabled { + color: rgb(0, 0, 0, 110); +} + +#qt_calendar_prevmonth:disabled { + qproperty-icon: url(:/resources/win/light/PrevMonthDisabled.png); +} + +#qt_calendar_nextmonth:disabled { + qproperty-icon: url(:/resources/win/light/NextMonthDisabled.png); +} + +/*TREEWIDGET*/ +QTreeView { + background-color: transparent; + border: 1px solid rgb(0, 0, 0, 13); + border-radius: 5px; + outline: 0; + padding-right: 5px; +} + +QTreeView::item { + padding: 7px; + margin-top: 3px; +} + +QTreeView::item:selected { + color: rgb(0, 0, 0); + background-color: rgb(0, 0, 0, 7); + border-radius: 5px; + margin-bottom: 3px; + padding-left: 0px; +} + +QTreeView::item:!selected:hover { + background-color: rgb(0, 0, 0, 13); + border-radius: 5px; + margin-bottom: 3px; + padding-left: 0px; +} + +QTreeView::branch:has-children:!has-siblings:closed, +QTreeView::branch:closed:has-children:has-siblings { + image: url(:/resources/win/light/TreeViewClose.png); +} + +QTreeView::branch:open:has-children:!has-siblings, +QTreeView::branch:open:has-children:has-siblings { + image: url(:/resources/win/light/TreeViewOpen.png); +} + +QTreeView:disabled { + color: rgb(0, 0, 0, 110); +} + +/*TOGGLESWITCH*/ +#toggleSwitch { + color: rgb(0, 0, 0); + font-size: 17px; + font-family: "Segoe UI Variable Small", serif; + font-weight: 400; +} + +#toggleSwitch::indicator { + width: 22px; + height: 22px; + border-radius: 13px; + border: 2px solid #999999; + background-color: rgb(0, 0, 0, 0); + image: url(:/resources/win/light/ToggleSwitchOff.png); + margin-right: 5px; + padding-right: 25px; + padding-left: 0px; +} + +#toggleSwitch::indicator:hover { + background-color: rgb(0, 0, 0, 15); + image: url(:/resources/win/light/ToggleSwitchOffHover.png); +} + +#toggleSwitch::indicator:pressed { + background-color: rgb(0, 0, 0, 24); + width: 26px; + padding-right: 21px; + image: url(:/resources/win/light/ToggleSwitchOffPressed.png); +} + +#toggleSwitch::indicator:checked { + background-color: %1; + border: 2px solid %1; + image: url(:/resources/win/light/ToggleSwitchOn.png); + color: rgb(255, 255, 255); + padding-left: 25px; + padding-right: 0px; +} + +#toggleSwitch::indicator:checked:hover { + background-color: %1; + image: url(:/resources/win/light/ToggleSwitchOnHover.png); +} + +#toggleSwitch::indicator:checked:pressed { + background-color: %1; + width: 26px; + padding-left: 21px; + image: url(:/resources/win/light/ToggleSwitchOnPressed.png); +} + +#toggleSwitch:disabled { + color: rgb(0, 0, 0, 110); +} + +#toggleSwitch::indicator:disabled { + border: 2px solid #bbbbbb; + image: url(:/resources/win/light/ToggleSwitchDisabled.png); +} + +/*HYPERLINKBUTTON*/ +#hyperlinkButton { + color: %1; + font-size: 17px; + font-family: "Segoe UI Variable Small", serif; + border-radius: 5px; + background-color: rgb(0, 0, 0, 0); + border: none; +} + +#hyperlinkButton:hover { + background-color: rgb(0, 0, 0, 10); +} + +#hyperlinkButton::pressed { + background-color: rgb(0, 0, 0, 7); + color: %1; +} + +#hyperlinkButton:disabled { + color: rgb(0, 0, 0, 110) +} + +/*LISTVIEW*/ +QListView { + background-color: transparent; + font-size: 17px; + font-family: "Segoe UI Variable Small", serif; + font-weight: 400; + padding: 7px; + border-radius: 10px; + outline: 0; +} + +QListView::item { + height: 35px; +} + +QListView::item:selected { + background-color: rgb(0, 0, 0, 13); + color: black; + border-radius: 5px; + padding-left: 0px; +} \ No newline at end of file diff --git a/resources/win/dark/CheckBox.png b/resources/win/dark/CheckBox.png new file mode 100644 index 0000000000000000000000000000000000000000..a6dc41b07ca782ba535e24c00da5befdf022679a GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4foCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBeyXR7V@L(#+l!984F&=(7xfuAJsg;X3L02d zLV#2g%Mt~~Z6_xcJa9?R|2=8vza_CAnui=3ZkFA2Ynhkf_#%AEzsU7{VY}Zx`K{r5 y{(VmSarMwIxt}jM9atE~e```W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{xVM&$B+ufw-a~s9##-&<8L`4C8@|O)S;%V zB3#j;A#EY7qFga~$&$}pHx;BC{%8N4v{Cb?l)#I9)quhTO{Ido)w=K}m>}Bx~9?A*V0J-jZAI2lYi{*EauX zXORynyQ`df84+y87h Q26Qolr>mdKI;Vst0EhHrIsgCw literal 0 HcmV?d00001 diff --git a/resources/win/dark/ComboBox.png b/resources/win/dark/ComboBox.png new file mode 100644 index 0000000000000000000000000000000000000000..e16366b63dcc9b052f3b242c1280c7c8544cd41a GIT binary patch literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^MnJ5_!3HGTDo)q{Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAu+S

p4Hgw_OmqXbgaaCUAxb< z+dkxMjXnIsf62Wy_B-1um0bcH_x*Tr-L_@JstIANOONXM)XxLi$slUQkoCaz$*IYP PX&|nrtDnm{r-UW|=2A;V literal 0 HcmV?d00001 diff --git a/resources/win/dark/ComboBoxDisabled.png b/resources/win/dark/ComboBoxDisabled.png new file mode 100644 index 0000000000000000000000000000000000000000..997a3901f59003428dc983198105c963b96ef5f7 GIT binary patch literal 252 zcmeAS@N?(olHy`uVBq!ia0vp^MnJ5_!3HGTDo)q{Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAuZjfWZ5fj*DQm5UtRWo1aUoG{an^LB{Ts5f}L3% literal 0 HcmV?d00001 diff --git a/resources/win/dark/NextMonth.png b/resources/win/dark/NextMonth.png new file mode 100644 index 0000000000000000000000000000000000000000..395f4ff23c5af05491ed6a28f838a4f847d4661e GIT binary patch literal 245 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBewU|7ZtTXSgB%^k82~S7H$FPYnKAGL#6zrHB_R;lv ni$9yY=#v+F9=ZMBd4oaqvQ}ig=WTDGs~9|8{an^LB{Ts5MKM?0 literal 0 HcmV?d00001 diff --git a/resources/win/dark/NextMonthDisabled.png b/resources/win/dark/NextMonthDisabled.png new file mode 100644 index 0000000000000000000000000000000000000000..29832ff783634333576638d4108a02cdf266350c GIT binary patch literal 266 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{(Mgt$B+ufxBYv04;cuw&Y#N>w$O)h%|VWi zYrH)IW(K{Fr`6gpq`G;?ipWc79xBv3$@Ftq`K7(`39d(+G?%s>DSg*yBX?{@^!ld< zd>{2ZJrS(K&bDtc_cVn&$uo~0vixo(^S!mFCu5Inv)}N*+uD!HmcD8C=eQ$Ddlfly3?ML``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBe!ZuQV@L(#+x|e_1_K_K_p2B3WKMspUXO@geCyJy-(2q literal 0 HcmV?d00001 diff --git a/resources/win/dark/PrevMonthDisabled.png b/resources/win/dark/PrevMonthDisabled.png new file mode 100644 index 0000000000000000000000000000000000000000..4f4d708279cd22e397c60eae634f5f4c1cf727e5 GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{v1yi$B+ufxBYv0n+*h7Ys)?73wlg9>zY&v z)bxq%B*#64Bo?&=?j|KYj=W~}dJdn?A7rvQIjQvDyPvj-e2m`}minBzApXs-VxRWX zTN3Sa8n68_|E>N_;__e1zNEt@fA=sx+|9?3xBmHJz0<2cMm|`4`@ZbfmgTGCS%1E0 z)Z3`FMbh?!beJRmgX!WdCp{lZ^e{iM{%x#mRCwYd%e)!JUxgOzr~|r_!PC{xWt~$( F69A<^VHyAc literal 0 HcmV?d00001 diff --git a/resources/win/dark/RadioButton.png b/resources/win/dark/RadioButton.png new file mode 100644 index 0000000000000000000000000000000000000000..18fc29271c4ff75af0691f9c8b6a7fd473b2860f GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4foCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{$x)V$B+ufx05gOIv9w!>I+LOoV}4zdIP6g z60?~B(|X4s-^K4urR;4_{>&=6)L-6sR07KPX4ABxyL#E86O_)OX>U2XCSv$W@15W_=%a84+Z60VqaXIIBz!7WG?}+ w_3In!FNrb*TCgYI+qUl}-``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{tQnS$B+ufx04U@wkim)-rwF7&$Kk4N%dx9 z$pYPo&a#HNFXS$)kv>{_b@t>loJNrf4Dwz!k|#X;PR`5mU}vu1l(td%^_Fnix1xb{ zOrbHxFYi5xoTIqwMdb>Chg@Z+?mU{hd#an**5X%9W>4;e1Fln!(wgQu&X%Q~loCIEGK BTxtLS literal 0 HcmV?d00001 diff --git a/resources/win/dark/RadioButtonPressed.png b/resources/win/dark/RadioButtonPressed.png new file mode 100644 index 0000000000000000000000000000000000000000..c17a061fe713383d4fedbc18355a498fa6dc1406 GIT binary patch literal 233 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4foCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBex0X_V@L(#+sUVS8x#aw+_g8bSYP(r!eSky zeSlAcHJq8V&cKI(M4LY z^qWF}OT`{;k;V;-$Cm~x2`>E5QX!^hqdc#1$6a+1Yx7xBopMJmKC;-K8)tjs_=%bh Z(W498w&tiRYz4Z6!PC{xWt~$(69DyQN=X0! literal 0 HcmV?d00001 diff --git a/resources/win/dark/ScrollBottom.png b/resources/win/dark/ScrollBottom.png new file mode 100644 index 0000000000000000000000000000000000000000..c0fdf27bbb8a7f3f2134b51c311a8100736754ba GIT binary patch literal 247 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~i!3HGN^yhQ|Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAuifv-~RKpL|A7^mbQS=9EB#UrzYm5k9;`oV;oxgV|Ozd z8Lt!2ygOfRRW{q*f5-AKX8-=5%zis;)2i#^p9zk^JT?+koz3@O1TaS?83{1OP+oQi}ip literal 0 HcmV?d00001 diff --git a/resources/win/dark/ScrollBottomHover.png b/resources/win/dark/ScrollBottomHover.png new file mode 100644 index 0000000000000000000000000000000000000000..27b1ac5ed9b2497b9d2b035e40381f372992c75f GIT binary patch literal 245 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~i!3HGN^yhQ|Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAuI>a_v#38 z403v*P{JU4fnyP?*8-+#`&$kk3+LN&`(IjmhiGW%KgPNOhuc|MYyawPEj(VM*ko8^ z_0{cvuZB+(lTts^1*MWzT`?}3796-E6=O2*_pB%R+xO;vk(a6$QTw~5kIP3XPh|er mR_P|5z%O?HzD4Y}5SE=4r+D3gh50JbRScf4elF{r5}E*fx>Lvi literal 0 HcmV?d00001 diff --git a/resources/win/dark/ScrollBottomPressed.png b/resources/win/dark/ScrollBottomPressed.png new file mode 100644 index 0000000000000000000000000000000000000000..4d2d4967710c9bbb339f6da7e9890288774f810a GIT binary patch literal 232 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~i!3HGN^yhQ|Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAu|^T;+sH+FnGH9xvXgW literal 0 HcmV?d00001 diff --git a/resources/win/dark/ScrollLeft.png b/resources/win/dark/ScrollLeft.png new file mode 100644 index 0000000000000000000000000000000000000000..de8e5cb119f8bb779052b7dc6fadbf80d7074d66 GIT binary patch literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^d_XL~!3HGNrubO_Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAuvv z{X)U3fJMDfIoUx#kb7nQ-u@sDIepFm--t^(M(P^`HNwO-lo)M}*qqGWqwCO+entPZ zaV{TA>2~#Jr+Dks__eIJzJ7YD@39W^iHrL-a_mXygqFgC^2Ww RYX-TU!PC{xWt~$(69E1EMAQHP literal 0 HcmV?d00001 diff --git a/resources/win/dark/ScrollLeftHover.png b/resources/win/dark/ScrollLeftHover.png new file mode 100644 index 0000000000000000000000000000000000000000..b04ff99bc3b7e03a50786ec45f9e0d906c4e9473 GIT binary patch literal 225 zcmeAS@N?(olHy`uVBq!ia0vp^d_XL~!3HGNrubO_Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAu_5ybTIGuJ%V5B^pH~4)RJI z^p$ayJZS5)OK>YEyKRG5{+{5;-=1&vY)mw;J?xUs@`kM-h_&+sVs^0Cae6vEc zr>P6iGVnaHeV3ShCFiV}k}Gc>WiNWIl)XNvYUxG+ryJSd&arEJoAdL4MNGbu+T?q$ S%nkxwz~JfX=d#Wzp$P!hM@Dr3 literal 0 HcmV?d00001 diff --git a/resources/win/dark/ScrollLeftPressed.png b/resources/win/dark/ScrollLeftPressed.png new file mode 100644 index 0000000000000000000000000000000000000000..22d516cb504e8225279fc4ab0c76cdbfb7d05c6b GIT binary patch literal 233 zcmeAS@N?(olHy`uVBq!ia0vp^d_XL~!3HGNrubO_Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAud0xXN0h zbkkwxkwBRP0wv7u1_=5&cztB^#pz}b6^VByX*1G abMCqZ>F*(2H&y{%!r z9OUlAu z9OUlAunrC}Gd$`vT$Z|x+c;cNMoZ1FZD cFVdQ&MBb@0MU9(MF0Q* literal 0 HcmV?d00001 diff --git a/resources/win/dark/ScrollRightPressed.png b/resources/win/dark/ScrollRightPressed.png new file mode 100644 index 0000000000000000000000000000000000000000..2743f7054bd8758f4b96ab2854a814db096ffec3 GIT binary patch literal 227 zcmeAS@N?(olHy`uVBq!ia0vp^d_XL~!3HGNrubO_Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAud&ISV>*W^M5_l+e@ehPh$ zSV~#udWc`x(b)HZY1^_J!3#~|zB)Vo_)x+4qmFC8!1Q_N+LlcXl9LHwxp!d||jvX(` z9OUlAuW^y4Gs z)xXwE+JA4F%D?FL)~w(sds_PCCSBa&@^e|>6DHfM>f)~JF8Uu>uHnwK>Cjw_S9%7{ f{nnDZYAu-`^{a z9OUlAuO>c25xc)1Ra+d^zm+|3{`-QkgfwP_>M6X9o0ll(HgxDbH2VJ0 z@AAY=wN5P`e>$G7xiLwM`>a}&xu>Sf0lQu&(bt->np{`crnha@=wzO`kkhiX;rk{> d;mG^zx%*aWPx!$i0dy1tgQu&X%Q~loCIB?gPIv$S literal 0 HcmV?d00001 diff --git a/resources/win/dark/ScrollTopPressed.png b/resources/win/dark/ScrollTopPressed.png new file mode 100644 index 0000000000000000000000000000000000000000..2043f777887ef976d4e3ca438105922a2281ba60 GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~i!3HGN^yhQ|Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAu*ZsR1luKBuKdh79 z>F8d_QphZ>agcM4OIDV?Qs&YJ2b=lpq@DixH_Y#McG()9wajOR=z|m5S7tKi%=r=M zn0JQjL2ujsXO~{B+1hLp&5?Fg+Pve<-fM3^6&$RrYB_bsI_N-;M&8leGC%*SXglTH R{SR~igQu&X%Q~loCIAPVPT&9l literal 0 HcmV?d00001 diff --git a/resources/win/dark/SpinBoxDown.png b/resources/win/dark/SpinBoxDown.png new file mode 100644 index 0000000000000000000000000000000000000000..dca27e0fc1c2e5382b68fb120e6075eeea754645 GIT binary patch literal 404 zcmeAS@N?(olHy`uVBq!ia0vp^MnJ5_!3HGTDo)q{Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAuJ=i?@+)ml1O`ENAF{(m#D>>B?uNHL8DDW^3M?xzR_Y z*YqO;t6%)gLLZ-%ybCVOj5RUY`0u<2!^ZcLB6|)b`7Pm(U1(f#pyXEY?S`4EB}uv- v6ZANn-n~yq=$Jn}Y+lPEjV=%}nIxV4FDbP0l+XkK@j#wb literal 0 HcmV?d00001 diff --git a/resources/win/dark/SpinBoxDownDisabled.png b/resources/win/dark/SpinBoxDownDisabled.png new file mode 100644 index 0000000000000000000000000000000000000000..863987b741cabfd580daefe9e9c704cebefd73de GIT binary patch literal 642 zcmV-|0)737P)xfP;&jSaio-2R;@SS!8E&!lhwg z;?w^lC8>rGu3Sw_?w4HJBX{@SkJt8&NTE;OJF+3uJbzQ%j&*!yL zsT3rafJD&i_0~9+$UGqtkH@3&b+K6JZd8WXgoJL7wRLVHgEN`Tlcs5P-1(Ox)~$b2CY1_2DnymG+FWFkd|*Wk4v!fU-{v)M-yM5ugrip63LmjI*& zKA$g@PNxUtfL{`QNL-Txge$UQI-RCCFefk`k9EAHeiFnm48L8%TGJ7G0?FcXD3HmMmeVh3#F&qwA;s|Xpo6T};BYJtB$m=dvW2okbXyiO1tTBzA`G zaU>Fb zEE7nc4}SY-Gqe#To<)xy+amSRvV$+z2i_SkWG>J>fW*C95`O}YGC8yxQYaJ(g+ifF cC=`(^b07*qoM6N<$f~JNEng9R* literal 0 HcmV?d00001 diff --git a/resources/win/dark/SpinBoxUp.png b/resources/win/dark/SpinBoxUp.png new file mode 100644 index 0000000000000000000000000000000000000000..76e445055c656a82be0374ff76161ecc10daf9b7 GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^MnJ5_!3HGTDo)q{Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAuSV&FTVSC!7t z5x%G55clMQi<6lR8oDi-#MM{WpUl2wG9e&$qsn{le-aDV@8Rdrov6Uk1V)V)qUKMW zc8!O{>&a2eAQutWqzMQ7TT@PmRVs%sz0!M)NrmglLCbEvc>t`od=o6ezYCuGqv_&bbs_HaC%>l@jhb}f{dVQc7la--mG*p}m3rp+?qxGRs2SXn zda%ZIssG!yKL)eUh|S)w&f4}oXKwaUNBs>_uS2%$gB*XFU1wGO>21l?MO- literal 0 HcmV?d00001 diff --git a/resources/win/dark/SpinBoxUpDisabled.png b/resources/win/dark/SpinBoxUpDisabled.png new file mode 100644 index 0000000000000000000000000000000000000000..3fa452a3c84ca93fbf4b68d294d85792a2fa3a55 GIT binary patch literal 625 zcmV-%0*?KOP)@U9$5-3HeN$^=8{_>UB?(9o!J~AB#IJZ93WfB=Vqs!_ zgci?cvv#l7dn3UJ7r{GmjP9DpNc^r+sobLqqg*bhVN)C}fy#XFHWG+Xkyfh}TP~L! z9=j5^-ab^}#gpOcS;91=DpN|1ObL9h(3E4;p78u$BO z=Ib579n;*t1_`0R7)-fb9^ppSR<9)uUcpH+xJlBlp-?Ck3L*Rgnd=tBJYE0G00000 LNkvXXu0mjfgr^6! literal 0 HcmV?d00001 diff --git a/resources/win/dark/ToggleSwitchDisabled.png b/resources/win/dark/ToggleSwitchDisabled.png new file mode 100644 index 0000000000000000000000000000000000000000..2045cd201f6144699c87d8676a3b93b2f0f7cfa2 GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4foCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{yk3@$B+ufw^J?(HW~1=)t55fT_F8paepe4 z#8F-i=@(*lk66lB%r+=nG`*C3mvzLc`qQ!U>Drm6=Q~Vh;y$CbEu-h6Nl1$7%ttT# z)-EiauHvJgleyxgUq|sXhVy}mVtXgc8t~4qRXlo~S^70g;D>uresw86fug+pPabaG zwpZEM?8I^|S``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{!>pE$B+ufw^QEpHW>&Ujkj)8-q5(I(PzQp z9gG_qa~27|VB65x^MK_+Y>`UApKR%$$MiF2$xT1ryjy#N@{FbJsgd($FWVWFtzXik z5_9s@V~cfrTRcBFM0>q%OMUmL>HVq=9s4roK49DJzh%c<4#hokp_+%#E?%2kE zDB=41cLoJ_w&k`t>^SlFv%?LEVi$!=mX{BG_`Q8rhUbs`jE7PWLpC1@X;9xLu#Cw@ zz|T(mOs&T{?jOM~s*^)(ism}jUgMfGySJpoA``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{&!Co$B+ufyHoD+HW>&s^lxfVe!y~x_Y~XR z1`EkujeZLICQlKxYLb2s%BK@j=T&=Ae`k!wm>)@;$iT@hnbjDa$gM!%teKWp`;m z|MN)IEwO2(!b2G;<-_tXTn)W~eaw4g*F1LoR2Af-9x4|UeeUh#%@^72)VCT|b5$=C z4-Zv+7`s51L+e|>8HvdPe(yRKYgjp091>L4Y?)jmR4*F6Msdz9L37{Y_JSBgvG**E zM+)zp?<;&hlTB~~Z|~gg@8ymiwRXBaZ{MD0t$Pgwg4d@%P=DVxVV=n3J0cB-cSQ$n xi*B2Ic7w?a)q7%|u{TX8s6CWyRsF;3Z@t8oarWb{mw`dR;OXk;vd$@?2>?HQh%5jA literal 0 HcmV?d00001 diff --git a/resources/win/dark/ToggleSwitchOffPressed.png b/resources/win/dark/ToggleSwitchOffPressed.png new file mode 100644 index 0000000000000000000000000000000000000000..8fcb8b664907a8e427c85733e02f3f765dbf7900 GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^l0YoR!3HEv_nU76Qk(@Ik;M!Q+`=Ht$S`Y;1W=H% zILO_JVcj{Imp~3nx}&cn1H;CC?mvmFK>klp7srqa#=BGR3N{%Cw1{gjXt}{yq9AG! z#t^bBWPz*$`-Mi$Mxi?i1s)xr#N&UY<@Na-(w*+jm!QwGU+wiSyNgRrp0*}?I#1r> zE_0l9T8BY}OZigQ8U0ICMJ9hca!_%>zCAG-3k0?-ue-0Xfn`_g4L;$n*>wr&L5KLi zKYXBkNXKYL_ii@BJKGY~H2+N6=`u~Ms_TS6VwPeo$Nm;q220+$~!}k*CmMmW3pE{+^D$dw{PFq6;98~)c;+3#d@#S zC&8{)OhR_S%K2e#<=2wd^(kbEu1)yBwfi}%WQ!Y{u75BGFc26#UHx3vIVCg!0NOc- Ah5!Hn literal 0 HcmV?d00001 diff --git a/resources/win/dark/ToggleSwitchOn.png b/resources/win/dark/ToggleSwitchOn.png new file mode 100644 index 0000000000000000000000000000000000000000..c10c8407920aa706a79d7eb2d2f591bdccdf8664 GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4foCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{tQnS$B+ufx04U@wkim)-rwF7&$Kk4N%dx9 z$pYPo&a#HNFXS$)kv>{_b@t>loJNrf4Dwz!k|#X;PR`5mU}vu1l(td%^_Fnix1xb{ zOrbHxFYi5xoTIqwMdb>Chg@Z+?mU{hd#an**5X%9W>4;e1Fln!(wgQu&X%Q~loCIEGK BTxtLS literal 0 HcmV?d00001 diff --git a/resources/win/dark/ToggleSwitchOnHover.png b/resources/win/dark/ToggleSwitchOnHover.png new file mode 100644 index 0000000000000000000000000000000000000000..ed9094fa53d137df0051e9ec14051cfeb76213d5 GIT binary patch literal 283 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4foCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{svDM$B+ufyHgJGHXHD`*3VQ?E@{aLFnf_v zGI@pY0k(H+Jq~lVrrpufWSq?H|4W=ZPDjoBu+kfMfZMaP0`x!1}fsa^^e<&==Xc60= zkbbIj{s!ZxU2@+}?-u1-bBlkqzEZpM;)#7GkxsjcS508ciI_dh;u(L9f2vJE!!7RT a4|q4uS^31W!%qw7b_P#ZKbLh*2~7Zbz-A5r literal 0 HcmV?d00001 diff --git a/resources/win/dark/ToggleSwitchOnPressed.png b/resources/win/dark/ToggleSwitchOnPressed.png new file mode 100644 index 0000000000000000000000000000000000000000..e46f72fd8e2dd8d94f74ffd460e16c808de45b00 GIT binary patch literal 278 zcmeAS@N?(olHy`uVBq!ia0vp^l0YoR!3HEv_nU76Qk(@Ik;M!Q+`=Ht$S`Y;1W=H% zILO_JVcj{Imp~3nx}&cn1H;CC?mvmFK>lh^7srqa#-~$bd0P#5TK(5GX(tM)F{(e{ z320zZX=wJE!SaGhh5IIda;v!CCtJZ^TVppd#(N&!!eiLo-YGdl%6!pxCU3TFf~BDe zyNzZtO@9)yYQc`~K2Hx1Cq+kPm5z0}BGY>8JWnS6Hb_4hA5oC-`ceDz&o_46@k~3B z_RX{E#4_$$g%fMK1UkhgX{cNh5i$S$fBK>c`*(46b{m>qZTN6INjh_*ZJzuIu6gXg VPq%L=F9155!PC{xWt~$(69AR?VR!%l literal 0 HcmV?d00001 diff --git a/resources/win/dark/TreeViewClose.png b/resources/win/dark/TreeViewClose.png new file mode 100644 index 0000000000000000000000000000000000000000..70699fc7fa6e3565664c14783a9dce9bd783a515 GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^MnJ5_!3HGTDo)q{Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAux_R22(k(W3J4yJQEC&LVE!nZ$3vcxAz}%?eW0MpfqNW4A2Bd^y85}Sb4q9e E0LyGw6aWAK literal 0 HcmV?d00001 diff --git a/resources/win/dark/TreeViewOpen.png b/resources/win/dark/TreeViewOpen.png new file mode 100644 index 0000000000000000000000000000000000000000..f780dce8eb61cbc00756768f2e36b8a416417b4d GIT binary patch literal 275 zcmeAS@N?(olHy`uVBq!ia0vp^MnJ5_!3HGTDo)q{Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAub|O!5dPe8;bQhKtNqK}zm#e(Jj=7KYSt%n-p*qtq7V1=W*Qx; zmAYKgQY}7N>CoOTPtk|-l7rlKIGzbD_LO}1<-^`*Va`Qv7OXj!-GQ!5kb9T0RG>Y! SgU1@kWAJqKb6Mw<&;$Sk-DQdZ literal 0 HcmV?d00001 diff --git a/resources/win/light/CheckBox.png b/resources/win/light/CheckBox.png new file mode 100644 index 0000000000000000000000000000000000000000..2bf3cb70f64d9565e8e87cbeb42bd32dad192fe5 GIT binary patch literal 215 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4foCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBevYS$V@L(#+l!984F&=(7biBbs3X3Xk2S0=siQ``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{sK=I$B+ufx0BBD9#-ISi%po&cY*tR-vz%3 zf~)c-_+99m;9JG6vVH=u5u?)l^FISUcC?lo9(t5`Q*Bj9*W)?6&)(IxVlX!M()@Ps z{z?%gUPTp;Xsx4qE5GpYuXkTMS#ELqeF^3Bysk@5lxi;R-@0w7%*JcKIxjqKw%4kD zGm&fhQWmXu3i%3E(#dTyFIPo49JOzmKBsue>%m+D}$%2 KpUXO@geCym6ktsN literal 0 HcmV?d00001 diff --git a/resources/win/light/ComboBox.png b/resources/win/light/ComboBox.png new file mode 100644 index 0000000000000000000000000000000000000000..9cb5618940e7f57faa0158fe1f6d6dbd31ab0ac5 GIT binary patch literal 220 zcmeAS@N?(olHy`uVBq!ia0vp^MnJ5_!3HGTDo)q{Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAumdK II;Vst0QTTVwEzGB literal 0 HcmV?d00001 diff --git a/resources/win/light/ComboBoxDisabled.png b/resources/win/light/ComboBoxDisabled.png new file mode 100644 index 0000000000000000000000000000000000000000..997a3901f59003428dc983198105c963b96ef5f7 GIT binary patch literal 252 zcmeAS@N?(olHy`uVBq!ia0vp^MnJ5_!3HGTDo)q{Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAuZjfWZ5fj*DQm5UtRWo1aUoG{an^LB{Ts5f}L3% literal 0 HcmV?d00001 diff --git a/resources/win/light/NextMonth.png b/resources/win/light/NextMonth.png new file mode 100644 index 0000000000000000000000000000000000000000..2eb226aef656ce7c45f528359b18da17bb8ce508 GIT binary patch literal 250 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBe!r)SV@L(#+y33WEd~NE?B3kdlRP``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBewU|7ZtTXSgB%^k82~S7H$FPYnKAGL#6zrHB_R;lv ni$9yY=#v+F9=ZMBd4oaqvQ}ig=WTDGs~9|8{an^LB{Ts5MKM?0 literal 0 HcmV?d00001 diff --git a/resources/win/light/PrevMonth.png b/resources/win/light/PrevMonth.png new file mode 100644 index 0000000000000000000000000000000000000000..ef060d0a8c15a45b0c489c2de576067e2ce096e7 GIT binary patch literal 248 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBey^vCV@L(#+kS7}1_J??^yv=kJv4+0nwU2P zuof(06lUSnI3VQC#JOL1|2BySs=2f7o-ASep?KRVTlePTe--TeI;I9SdmcAyt_^;( z-R7K0e{XEsf_0_GTwYo(T(auaktM3`C6#m6A5f?fv|YVH`Pb*=7eZR^UW_+euT|6U pX=xYHDZTq(6JNYe#>e7hW=3OG^Rk45J3xmqc)I$ztaD0e0svJ0RO$c# literal 0 HcmV?d00001 diff --git a/resources/win/light/PrevMonthDisabled.png b/resources/win/light/PrevMonthDisabled.png new file mode 100644 index 0000000000000000000000000000000000000000..a995b1f4aa086171aace92159b8841c0ccd6ff98 GIT binary patch literal 234 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBe!ZuQV@L(#+x|e_1_K_K_p2B3WKMspUXO@geCyJy-(2q literal 0 HcmV?d00001 diff --git a/resources/win/light/RadioButton.png b/resources/win/light/RadioButton.png new file mode 100644 index 0000000000000000000000000000000000000000..6350856596f44a90a0fb04aaa1c236fde093d111 GIT binary patch literal 267 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4foCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{sK=I$B+ufx0B!U9#W8KSwFWy@Wz_E2l5ik z1Jy6_7BIV8tY6s~Ww=NG<75B%PwE67a5C~m{M1%y-V`eIUS{fCp}=OdvQw?^XFg+F zU*c>%H&lvS{p?&D9oyVvwpxs3%eFq%-f7!6eajaUNy9)#Wx3``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{!&jD$B+ufw^JVS9#Rl!jkk7mPhbvDV3s|} zo5CD>(6gX<*U8Twra`j~INq-RJ88NDlYF^7-vb9`Pwm1<6YKXp(KB4(s>eG?`gDu2 zbMKYl{_vA4SC<40|>y52_v~ST|Z@(HR>*p1hkIufpA9jIre`)_*kE8ipKA-BG zf5XG3`7+1$qzTQJ?+0`{bG|dZG%+T4XR!BV_Cp=^7Vi`OaOv`y)G%aC{A9=}Tl@#; OU``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBev7AzV@L(#+sUVS8x#aw+_g8bSYP(r!eZ^D zeSuFSHRiFSlghhU1s6U{+WDbU<_06z|CSVGNtHhF)k_XXKPl4w=u`Y=>xNGXyia>w zZv~&v5M0l;ad&YDr(xm(p+{S#W_om{zqqOMh_y=XtLMC_^PS7QJG literal 0 HcmV?d00001 diff --git a/resources/win/light/ScrollBottom.png b/resources/win/light/ScrollBottom.png new file mode 100644 index 0000000000000000000000000000000000000000..523a9a94fa02b18e64b121a5f6c503272a2d8067 GIT binary patch literal 253 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~i!3HGN^yhQ|Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAuuIv%NZu*s32WVf= z=2VdoIv3R>dSjAm#WRLO2U!HaygFE(l=j2^zj8-_7q7%)F})4f`kXrQ<`>p{dBm0X zp}wx&vM~R_JUh97s;g1w&+V-Dd-+}X`5rwr4vA!^F4M*F9EwJ<^LUm_$zJGnULyLE vY7gTe~DWM4fIa64% literal 0 HcmV?d00001 diff --git a/resources/win/light/ScrollBottomHover.png b/resources/win/light/ScrollBottomHover.png new file mode 100644 index 0000000000000000000000000000000000000000..686c3505d1d4524268fabeba01c57d62afa21f6d GIT binary patch literal 261 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~i!3HGN^yhQ|Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAu16hOuEFp!P%|D z$nnyJ+p0nyDJ?vQ`7~{tvbj1sQ#v0g=f(ao{lNe3T|FDCm!`RV`48uwkC|(0b!LUX z55Lh+T=(~-U-GlQxmlYcF1_Tf<6J)`5Fpy2OaJER`W znJpE_w)Sg;_{1MOx||~8EgYL=Tsbb*ZWp-5|Lq97ww`X7i^!=Wpeq?XUHx3vIVCg! E0KMH@tpET3 literal 0 HcmV?d00001 diff --git a/resources/win/light/ScrollBottomPressed.png b/resources/win/light/ScrollBottomPressed.png new file mode 100644 index 0000000000000000000000000000000000000000..7612529602dbd52d0c49c1394f98637cca49ff9b GIT binary patch literal 235 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~i!3HGN^yhQ|Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAu6^-?BjH=^8MSZ8paFT zQrPmINLfs}cxS~9L8lI{mAuF2*+%x*fBuupu72Za)1{@ayUyq8g-<%eaa6_E|A5F> d#a}-ytS^d4bckrJUk`K(gQu&X%Q~loCIE04QL+F4 literal 0 HcmV?d00001 diff --git a/resources/win/light/ScrollLeft.png b/resources/win/light/ScrollLeft.png new file mode 100644 index 0000000000000000000000000000000000000000..24df56af7d0939653719e74c9684d2366f639b0b GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^d_XL~!3HGNrubO_Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAu;x+IUKvudLd|4@Q;~F9p7(V$ngI9>T$+e{x^O(-d6Tk9Nz!cZ7KLs mZmgJ+YxeBTj?U(~PYkbEbyR|6Cw~Pxiow&>&t;ucLK6U!SX7z- literal 0 HcmV?d00001 diff --git a/resources/win/light/ScrollLeftHover.png b/resources/win/light/ScrollLeftHover.png new file mode 100644 index 0000000000000000000000000000000000000000..24af3ae3a3f10149386ec0bc5e862d199e0a9b1e GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^d_XL~!3HGNrubO_Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAuP&+jOy?CzbJ z+Bh%Fdzwu#Z%WTyj@+$Qt@BqlO}WI}yDluB&po^LQQ5;=pMI}oZ4;1FZ0R>#*D_)6 i?TAf})#Z+z z9OUlAu-Ub667w(x1DmELwbmhDCV5{6~pBt>Va94P`? O&*16m=d#Wzp$Py{R6+;< literal 0 HcmV?d00001 diff --git a/resources/win/light/ScrollRight.png b/resources/win/light/ScrollRight.png new file mode 100644 index 0000000000000000000000000000000000000000..f8e070b70c409ba36e1220f15c0ae62080b64fa3 GIT binary patch literal 252 zcmeAS@N?(olHy`uVBq!ia0vp^d_XL~!3HGNrubO_Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAu z9OUlAuZIuxnx;d)RP1(E- zJKo7Paz`KBC3~ZBZA4SL#{t8O&2FxJbthFmpD?#~+RkWvOh@qv=ilQJmt(|Q1qvmT zdg{GiMr&SO?y~7uQ=zESiw8Hgz2|5ytef-M%`5U*$LcRRhDRflUhl1!x!XPWE<@1T wt$7zYkD48|43ExcpOPT7Kj7-rDYK23mQ2^<{J~@S59mAwPgg&ebxsLQ0MSrc*Z=?k literal 0 HcmV?d00001 diff --git a/resources/win/light/ScrollRightPressed.png b/resources/win/light/ScrollRightPressed.png new file mode 100644 index 0000000000000000000000000000000000000000..a63fad0abf20721565915904cb7fad0274d70c3e GIT binary patch literal 221 zcmeAS@N?(olHy`uVBq!ia0vp^d_XL~!3HGNrubO_Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAuGJ{ld^t5Oy4c=c?RXZ*YQm?lrs=v% z9OUlAuS5c z%Uu1?z9~g(f8Jooe#^sf*>?F9x8yS?Di;REPP{rZu&S%6_f?2&d(+xiAu?RK8#=@l mA4Tz=c=P-8|3^3HeP-3lFjv2^FwX<%C z9OUlAuMSVjOgZ1$Z>J1r7)e|xwPZxOb?(S1tC%b#>LA;u(#pir~-x^K7sE%#t`(+8F~K$KdJe=d#Wzp$PyCkyuUu literal 0 HcmV?d00001 diff --git a/resources/win/light/ScrollTopPressed.png b/resources/win/light/ScrollTopPressed.png new file mode 100644 index 0000000000000000000000000000000000000000..72d3ab7033f6ee1da85a33077e10b85b64c0e7f9 GIT binary patch literal 225 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~i!3HGN^yhQ|Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAu&ISV>*ZsR1lv8@*?jADS z z9OUlAupBD(ayq{w$@~nCO?Z)#BBQ;Jg3SeuPCsZ z9oV){@XMyEV7D2(nLfW7PoLR+C!YDdU3!V)Th@0B_QqGW@A+%b58D{f`kg`VM!o7XM zO&;mrhYGhpE4tloq#C(68vaZQTg1Z1`7!&akLUU&iYr+U1N{p^ aA{Go2*V?nEGtC5rID@CFpUXO@geCx;J+dPJ literal 0 HcmV?d00001 diff --git a/resources/win/light/SpinBoxDownDisabled.png b/resources/win/light/SpinBoxDownDisabled.png new file mode 100644 index 0000000000000000000000000000000000000000..1c481178b4b32987f8cd9ec269273cf2a0ec744b GIT binary patch literal 577 zcmV-H0>1r;P)K3Z_Sh>-=9f(N54St}Zf5onF$}{n{sXmIZC_F*iI33b;d;G(f~EyWSxE`q zyQRLC#z{yNMS*r3X+%c%Y{Yym#hS~*?RNXUSS)U$%ePi46bdhx`w|a8#4eg9YzHD9 z5s_P$^-e+v4&H+RI?cdx=yz8Yqav z9OUlAut6=Wct6;h12_9n*UuAZRLJ4 zgXQN!U(0uw6=N^3*qsoMJ-IVu<)zLUu{-8HT^BB>nU|~_!(XT{*;Ls@;#n`>1M`Ue ziM8I>_?DP)eNw!|SQ^-Rvi-$HFNa*$EIGMnHOh*LdUut-I8Jek^#A-PUf1QK-J^T? z*ZHS?*nCCkXd!PA*L{Qg51V}p*|RQGuD`pNZ~l9!DV_^&Gk@Bv!K+#0DAD<6*T$IS tBM}cQKB)&hle=qi>*G-ap2HT2{5E2?MUl&9r~|{0!PC{xWt~$(698mQoSFat literal 0 HcmV?d00001 diff --git a/resources/win/light/SpinBoxUpDisabled.png b/resources/win/light/SpinBoxUpDisabled.png new file mode 100644 index 0000000000000000000000000000000000000000..14437d4b76dc31aff88a2567ee076260b7016c49 GIT binary patch literal 567 zcmV-70?7S|P)3n}|s4p!tFN9ra4P-KODi_&^@;A_9p`EPhwI`#})gqHdzpAv1-{ zBPpXU0*N(9>`C_$`EiAXKebw|0R1{j1ML?cBSln2u;^t}N77}9i}W`v{5~VoM0

zH&Q}PL?lj77APl?l9LJ19&5>{h+xr6s18vUv8}GLz0QBSR%H148YSC|BQvFvlok;Q zjs({?kU0MB9xQw$GTCibN@k8qkdxr#J$1PKOz!!fL*^<>;fUbD6-u^K6=j0b!PuYQ zDkAWSNW^G1WR5!bd7KJRCL$aOPH>j!x=5tRJ(0|j{#g{FP(-kR9wl!wm6%XLI5#*) zDEVMkId?dR$Ps4|By$JV1}R9SWMtM+YWVtBFgA9X!%0NWPg`j6mgqs^nUoM2UVKQ& zQO4<9=9D9l2&5T7LiLEj$edB`S$>c&_`iRKVHk#?!WU7K({LcVA*}!a002ovPDHLk FV1mvU>!kny literal 0 HcmV?d00001 diff --git a/resources/win/light/ToggleSwitchDisabled.png b/resources/win/light/ToggleSwitchDisabled.png new file mode 100644 index 0000000000000000000000000000000000000000..f6209cac5c85586fe611c1832c3bce39525c1028 GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4foCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{$o!U$B+ufw^QEoHW>)C-M4B~E@75*RG$!- z!c@qVB0R^zJ%L&BAnyk~InF7U)}OGS*RrMc)0YM1tY$1vt0F?LPMj5^S-LFj^xJ9c z_r1?|4J-*v5_;!Zw)7oq-n&f)j%$m(oV-i&(1REL%WBM{Uy5h0m~!&T+?DAz3o=Z7 ztCSf#f0_22?eJbQxu0Fw(6!n@X_94`;iG?RJIgx%w`snc;I~_2+1%O$Uc-wDg6j^r z8a`L_T_LEy_H6OtZI!A$=RaLIH0i&w;dPtvK#wOj$IJW-_9X`wn*>=n_myutd3HyO cx!6ypW%r^NJZSlS9q3&KPgg&ebxsLQ00V%7XaE2J literal 0 HcmV?d00001 diff --git a/resources/win/light/ToggleSwitchOff.png b/resources/win/light/ToggleSwitchOff.png new file mode 100644 index 0000000000000000000000000000000000000000..2045cd201f6144699c87d8676a3b93b2f0f7cfa2 GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4foCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{yk3@$B+ufw^J?(HW~1=)t55fT_F8paepe4 z#8F-i=@(*lk66lB%r+=nG`*C3mvzLc`qQ!U>Drm6=Q~Vh;y$CbEu-h6Nl1$7%ttT# z)-EiauHvJgleyxgUq|sXhVy}mVtXgc8t~4qRXlo~S^70g;D>uresw86fug+pPabaG zwpZEM?8I^|S``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{##EM$B+ufyHnosHW>)C-M4B~e!y~wEtT0! zA@7jd3pT4pi$>Xn$`(!GmK#i-F1}*_NoD%6xZgLP>|p-KYdCeyDz8gHK{HGr<{m9v z{KwS8M_ec>OU!SfW|7tU^rIyjOP~5}JZ==H6TUd9?xnFq)@kG4PpzLjobb*)GxyfL z7e~M3v+iS!YJQT$f7GS1!fXDIj*2DzbCl*CQU9m8EkarDsj$63e|U|Xic?2j*^asC zQZ7ldv);+?lF$3-mvP&8%K1GT%-NFOeU(Z4l*jQh(D1Y`qmj;UFR3ku-FJ5Gbj-hX nr{(3Tb&V$6`cv{ZNZ$K!(BbN_4+fio9%t}$^>bP0l+XkK^q`1` literal 0 HcmV?d00001 diff --git a/resources/win/light/ToggleSwitchOffPressed.png b/resources/win/light/ToggleSwitchOffPressed.png new file mode 100644 index 0000000000000000000000000000000000000000..38d76e07ef6ac70c6e1111514a210a7b337adde8 GIT binary patch literal 367 zcmV-#0g(QQP)P000&U1^@s6HNQ8u00009a7bBm000XU z000XU0RWnu7ytkO0drDELIAGL9O(c600d`2O+f$vv5yPz+!E}NOj9sy~ZCiRI7-RLe7ON2`m)5Qo& ztmA$j;eXI(Qq$E4OReKtnN$di_nwpp2d)J7lNO8l+V3%u%>Kz}MN@Ns~;ep)HrR*U&6f~4JOCCA<{dmi;MM>Ueu<{JP2 N002ovPDHLkV1hf`ko5on literal 0 HcmV?d00001 diff --git a/resources/win/light/ToggleSwitchOn.png b/resources/win/light/ToggleSwitchOn.png new file mode 100644 index 0000000000000000000000000000000000000000..22e66bfa7a17d810f8015fbea469ad69994d323f GIT binary patch literal 272 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4foCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{!&jD$B+ufw^JVS9#Rl!jkk7mPhbvDV3s|} zo5CD>(6gX<*U8Twra`j~INq-RJ88NDlYF^7-vb9`Pwm1<6YKXp(KB4(s>eG?`gDu2 zbMKYl{_vA4SC<40|>y52_v~ST|Z@(HR>*p1hkIufpA9jIre`)_*kE8ipKA-BG zf5XG3`7+1$qzTQJ?+0`{bG|dZG%+T4XR!BV_Cp=^7Vi`OaOv`y)G%aC{A9=}Tl@#; OU``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{uWOc$B+ufyHg(W9#Rl!T|ak;^bJ9Yh0+$Y zWDoLo2)|%^&er$A=8}*nt8LZW`E@5*ogOedRk*Y>HB8>+VQ6>f`NqbqiLP^}9Iv-H zbJeSQrTCYYoqL}xF})OW@2`;Ywa4C<7|UY5Z0+3rZ|Z)_=SS2xJx*HQIk$lSR)ZTy zuDA8XuK6j?Cko#`;TL8zX>N9z$gUcVgGb+PxITT})7$MA9z9tzp(-P}c%$Qqe!<`! g?h?TltgS@yzZ~#+rk$1-2XsG!r>mdKI;Vst02mf=WdHyG literal 0 HcmV?d00001 diff --git a/resources/win/light/ToggleSwitchOnPressed.png b/resources/win/light/ToggleSwitchOnPressed.png new file mode 100644 index 0000000000000000000000000000000000000000..4119adb30626d8a9daddb3c6496ee48490b78c37 GIT binary patch literal 318 zcmeAS@N?(olHy`uVBq!ia0vp^l0YoR!3HEv_nU76Qk(@Ik;M!Q+`=Ht$S`Y;1W=H% zILO_JVcj{Imp~3nx}&cn1H;CC?mvmFK>lS<7srqa#-~#s@-`U=w66DQkiNnz!RTJV zbi-$ELtsJkF2=hLYNk#TS>*8X3xE8lOUk_8i>80`+QL0!XN%s1hu^mZFo#azs?(}z z65&~LT`DBt`0bU`cuYUx z=UD4lo=m*BshQg-e*(9(MbZ57E9>TeG;)j->sF0ibKZK@6TeM7Ka(a)pDf}%Sg*hM zxsTDDwDP-WpT8}sE7CdqcY(zopr03;E6xc~qF literal 0 HcmV?d00001 diff --git a/resources/win/light/TreeViewClose.png b/resources/win/light/TreeViewClose.png new file mode 100644 index 0000000000000000000000000000000000000000..1bf84c82c2873d4f3de3c90924b956d8a7450d66 GIT binary patch literal 291 zcmeAS@N?(olHy`uVBq!ia0vp^MnJ5_!3HGTDo)q{Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAuSc@G(gv^<>b5W+KoaYiHK ziq^g>G2WS6D(IltjqP7_uX53L!Q&Ceo z@+CR!j;!eI0{?eM-#$F?`Lx{;#=9?T0zP)m*{OYf(eJq{Cn^UgLYo` kDdm4sJ_=4QF3+B`8}=FWTWn>D1Nwo%)78&qol`;+00f$B(*OVf literal 0 HcmV?d00001 diff --git a/resources/win/light/TreeViewOpen.png b/resources/win/light/TreeViewOpen.png new file mode 100644 index 0000000000000000000000000000000000000000..36a00b8896c6fc917ba0703fa36f7a2f2d58eba3 GIT binary patch literal 304 zcmeAS@N?(olHy`uVBq!ia0vp^MnJ5_!3HGTDo)q{Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAuwER5I2X>D zv4P_hucE(C28(M;z~mVpIJ&qN`X_a{1f+26?bZ}?yr}p^E3K tQ~MCAeOpv>$yULwtX2YwAp2zt*p*KkpV*I@j literal 0 HcmV?d00001 diff --git a/src/airplaywidget.cpp b/src/airplaywidget.cpp index 08cb4df..6f8f1ad 100644 --- a/src/airplaywidget.cpp +++ b/src/airplaywidget.cpp @@ -57,7 +57,7 @@ #include "diagnosedialog.h" #ifdef WIN32 -#include "platform/windows/check_deps.h" +#include "platform/windows/win_common.h" #endif #include "toolboxwidget.h" diff --git a/src/appswidget.cpp b/src/appswidget.cpp index 9b74183..c0d7388 100644 --- a/src/appswidget.cpp +++ b/src/appswidget.cpp @@ -87,18 +87,23 @@ void AppsWidget::setupUI() QWidget *headerWidget = new QWidget(); headerWidget->setFixedHeight(60); - headerWidget->setStyleSheet("border-bottom: 1px solid #363d32;"); + headerWidget->setStyleSheet( + "border-bottom: 1px solid #363d32; border-radius: 0px;"); QHBoxLayout *headerLayout = new QHBoxLayout(headerWidget); headerLayout->setContentsMargins(20, 10, 20, 10); // Create status label first m_statusLabel = new QLabel("Not signed in"); - m_statusLabel->setStyleSheet("margin-right: 20px;"); + m_statusLabel->setStyleSheet("margin-right: 20px; border: none;"); m_loginButton = new QPushButton(); - m_searchEdit = new ZLineEdit(); + m_searchEdit = new QLineEdit(); +#ifndef WIN32 m_searchEdit->setMaximumWidth(350); +#else + m_searchEdit->setMaximumWidth(200); +#endif // --- Status and Login Button --- m_manager = AppStoreManager::sharedInstance(); @@ -214,7 +219,7 @@ void AppsWidget::handleInit() } /* FIXME: ipatoolinitialze still uses the secure backends - when if the user rejects it, the moment he/she tries to sign in + even if the user rejects it, the moment he/she tries to sign in prompt(keychain or secret-service whatever the backend is) will be seen again */ @@ -262,10 +267,12 @@ void AppsWidget::onAppStoreInitialized(const QJsonObject &accountInfo) } m_loginButton->setText(m_isLoggedIn ? "Sign Out" : "Sign In"); +#ifndef WIN32 m_loginButton->setStyleSheet( "background-color: #007AFF; color: white; border: none; " "border-radius: " "4px; padding: 8px 16px; font-size: 14px;"); +#endif m_searchEdit->setPlaceholderText(m_isLoggedIn ? "Search for apps..." : "Sign in to search"); } @@ -638,8 +645,9 @@ void AppsWidget::createAppCard( ZLabel *installLabel = new ZLabel("Install"); installLabel->setAlignment(Qt::AlignCenter); installLabel->setStyleSheet( - "font-size: 12px; color: #007AFF; font-weight: " - "bold; background-color: transparent;"); + QString("font-size: 12px; color: %1; font-weight: " + "bold; background-color: transparent;") + .arg(COLOR_ACCENT_BLUE.name())); installLabel->setCursor(Qt::PointingHandCursor); installLabel->setFixedHeight(30); diff --git a/src/base/tool.cpp b/src/base/tool.cpp index 05ec12c..1978828 100644 --- a/src/base/tool.cpp +++ b/src/base/tool.cpp @@ -18,8 +18,16 @@ */ #include "tool.h" +#ifdef WIN32 +#include "../platform/windows/widgets/wintoolwidget.h" +#include "../platform/windows/win_common.h" +#endif +#ifdef WIN32 +Tool::Tool(QWidget *parent) : WinToolWidget(parent) +#else Tool::Tool(QWidget *parent) : QWidget(parent) +#endif { #ifdef __APPLE__ setupToolFrame(this); diff --git a/src/base/tool.h b/src/base/tool.h index c92236a..fe0f280 100644 --- a/src/base/tool.h +++ b/src/base/tool.h @@ -26,7 +26,16 @@ #include "../platform/macos/macos.h" #endif +#ifdef WIN32 +#include "../platform/windows/widgets/wintoolwidget.h" +#endif + +#ifdef WIN32 +class Tool : public WinToolWidget +#else class Tool : public QWidget +#endif + { public: explicit Tool(QWidget *parent = nullptr); diff --git a/src/cableinfowidget.cpp b/src/cableinfowidget.cpp index 60db9ef..073c175 100644 --- a/src/cableinfowidget.cpp +++ b/src/cableinfowidget.cpp @@ -81,7 +81,7 @@ void CableInfoWidget::setupUI() m_loadingWidget = new ZLoadingWidget(true, this); m_loadingWidget->setupContentWidget(m_mainLayout); - QVBoxLayout *layout = new QVBoxLayout(this); + QVBoxLayout *layout = new QVBoxLayout(contentWidget()); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(m_loadingWidget); @@ -230,7 +230,7 @@ void CableInfoWidget::updateUI() if (!m_cableInfo.isConnected) { m_errorLabel->setText( QString("%1 does not seem to be connected to any cable.") - .arg(m_device->deviceInfo.productType)); + .arg(QString::fromStdString(m_device->deviceInfo.productType))); m_loadingWidget->showError(); return; } @@ -243,13 +243,13 @@ void CableInfoWidget::updateUI() "absolute guarantee of authenticity."); if (m_cableInfo.isGenuine) { // todo: type-c to type-c - statusText = QString("✅ Genuine %1") + statusText = QString("Genuine %1") .arg(m_cableInfo.isTypeC ? "USB-C to Lightning Cable" : "Lightning Cable"); statusStyle = "QLabel { color: #28a745; font-size: 18px; font-weight: bold; }"; } else { - statusText = "⚠️ Third-party Cable"; + statusText = "Third-party Cable"; statusStyle = "QLabel { color: #dc3545; font-size: 18px; font-weight: bold; }"; diff --git a/src/core/services/get-device-info.cpp b/src/core/services/get-device-info.cpp index 7c0a029..93368a7 100644 --- a/src/core/services/get-device-info.cpp +++ b/src/core/services/get-device-info.cpp @@ -126,6 +126,7 @@ void get_device_info_xml(const char *udid, LockdowndClientHandle *client, if (xml_string) { infoXml.load_string(xml_string); - free(xml_string); + // FIXME: crashes on Windows + // free(xml_string); } } \ No newline at end of file diff --git a/src/core/services/init_device.cpp b/src/core/services/init_device.cpp index f9c56b8..84c7f4f 100644 --- a/src/core/services/init_device.cpp +++ b/src/core/services/init_device.cpp @@ -26,12 +26,18 @@ #endif #include "../../heartbeat.h" #include + +#ifdef _WIN32 +#include "../../platform/windows/win_common.h" +#else #include #include -#include -#include #include #include +#endif + +#include +#include std::string safeGetXML(const char *key, pugi::xml_node dict) { @@ -453,7 +459,7 @@ void init_idescriptor_device(const iDescriptor::Uniq &uniq, heartbeatThread->start(); while (!heartbeatThread->initialCompleted()) { - sleep(1); + // sleep(1); } } else { diff --git a/src/deviceinfowidget.cpp b/src/deviceinfowidget.cpp index dd0b30f..bb58bf8 100644 --- a/src/deviceinfowidget.cpp +++ b/src/deviceinfowidget.cpp @@ -25,7 +25,6 @@ #include "iDescriptor.h" #include "infolabel.h" #include "privateinfolabel.h" -// #include "toolboxwidget.h" #include #include #include @@ -146,13 +145,14 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent) m_chargingStatusLabel = new QLabel(device->deviceInfo.batteryInfo.isCharging ? "Charging" : "Not Charging"); - - m_chargingStatusLabel->setStyleSheet( - device->deviceInfo.batteryInfo.isCharging - ? QString("color: %1;").arg(COLOR_GREEN.name()) - : QString("color: %1;") - .arg(qApp->palette().color(QPalette::WindowText).name())); - + m_chargingStatusLabel->setObjectName("ChargingStatusLabel"); + m_chargingStatusLabel->setStyleSheet(mergeStyles( + m_chargingStatusLabel, + (device->deviceInfo.batteryInfo.isCharging + ? QString("QLabel#ChargingStatusLabel { color: %1; }") + .arg(COLOR_GREEN.name()) + : QString("QLabel#ChargingStatusLabel { color: %1; }") + .arg(qApp->palette().color(QPalette::WindowText).name())))); // Create the layout without a parent widget QHBoxLayout *chargingLayout = new QHBoxLayout(); chargingLayout->setContentsMargins(0, 0, 0, 0); @@ -314,7 +314,11 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent) for (int i = 0; i < numRows; ++i) { // Left column item QLabel *keyLabelLeft = new QLabel(infoItems[i].first); +#ifndef WIN32 keyLabelLeft->setStyleSheet("font-weight: bold;"); +#else + keyLabelLeft->setStyleSheet("font-size: 15px; font-weight: 500;"); +#endif gridLayout->addWidget(keyLabelLeft, i, 0); gridLayout->addWidget(infoItems[i].second, i, 1); @@ -322,7 +326,11 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent) int rightIndex = i + numRows; if (rightIndex < infoItems.size()) { QLabel *keyLabelRight = new QLabel(infoItems[rightIndex].first); +#ifndef WIN32 keyLabelRight->setStyleSheet("font-weight: bold;"); +#else + keyLabelRight->setStyleSheet("font-size: 15px; font-weight: 500;"); +#endif gridLayout->addWidget(keyLabelRight, i, 2); gridLayout->addWidget(infoItems[rightIndex].second, i, 3); } @@ -348,8 +356,6 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent) rightSideLayout->addWidget(new DiskUsageWidget(device, this)); rightSideLayout->addStretch(); - // // TODO: layout shift cause ? - // // rightSideLayout->setAlignment(Qt::AlignCenter); mainLayout->addLayout(rightSideLayout); mainLayout->addStretch(); @@ -420,4 +426,4 @@ void DeviceInfoWidget::updateChargingStatusIcon() // m_chargingStatusLabel->setStyleSheet(""); // m_lightningIconLabel->hide(); // } -} \ No newline at end of file +} diff --git a/src/devicesidebarwidget.cpp b/src/devicesidebarwidget.cpp index 6aa7c87..e47c4c7 100644 --- a/src/devicesidebarwidget.cpp +++ b/src/devicesidebarwidget.cpp @@ -39,6 +39,7 @@ DeviceSidebarItem::DeviceSidebarItem(const QString &deviceName, setFrameStyle(QFrame::StyledPanel); setLineWidth(1); updateToggleButton(); + setObjectName("DeviceSidebarItem"); } void DeviceSidebarItem::setupUI() @@ -59,7 +60,9 @@ void DeviceSidebarItem::setupUI() QHBoxLayout *nameLayout = new QHBoxLayout(); nameLayout->setContentsMargins(0, 0, 0, 0); m_deviceLabel = new QLabel(m_deviceName); +#ifndef WIN32 m_deviceLabel->setStyleSheet("QLabel { font-weight: bold; }"); +#endif m_deviceLabel->setWordWrap(true); nameLayout->addWidget(m_deviceLabel); if (m_wireless) { @@ -78,6 +81,9 @@ void DeviceSidebarItem::setupUI() m_toggleButton->setStyleSheet("QPushButton { " " text-align: left; " " padding: 2px 5px; " +#ifdef WIN32 + " min-height: 0; " +#endif " border: none; " " color: #666; " " font-size: 11px; " @@ -121,6 +127,9 @@ void DeviceSidebarItem::setupUI() QString("QPushButton { " " background-color: rgba(255, 255, 255, 120); " " border: 1px solid rgba(255, 255, 255, 200); " +#ifdef WIN32 + " min-height: 0; " +#endif " padding: 4px 8px; " " text-align: center; " " border-radius: 6px; " @@ -159,7 +168,20 @@ void DeviceSidebarItem::setupUI() setSelected(false); } -void DeviceSidebarItem::setSelected(bool selected) { m_selected = selected; } +void DeviceSidebarItem::setSelected(bool selected) +{ + m_selected = selected; + + if (selected) { + setStyleSheet( + "QFrame#DeviceSidebarItem { background-color: rgba(255, " + "255, 255, 45); }"); + } else { + setStyleSheet( + "QFrame#DeviceSidebarItem { background-color: rgba(255, " + "255, 255, 16); }"); + } +} void DeviceSidebarItem::setCollapsed(bool collapsed) { @@ -452,68 +474,70 @@ void DevicePendingSidebarItem::mousePressEvent(QMouseEvent *event) } // FIXME: better move this to a separate file -void DeviceSidebarItem::paintEvent(QPaintEvent *event) -{ - Q_UNUSED(event); +// void DeviceSidebarItem::paintEvent(QPaintEvent *event) +// { +// Q_UNUSED(event); - QPainter p(this); - p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); +// QPainter p(this); +// p.setRenderHints(QPainter::Antialiasing | +// QPainter::SmoothPixmapTransform); - const qreal dpr = devicePixelRatioF(); - const int w = width(); - const int h = height(); - const int sw = int(w * dpr); - const int sh = int(h * dpr); +// const qreal dpr = devicePixelRatioF(); +// const int w = width(); +// const int h = height(); +// const int sw = int(w * dpr); +// const int sh = int(h * dpr); - constexpr int kCornerRadius = 10; - constexpr int kBlurRadius = 2; +// constexpr int kCornerRadius = 10; +// constexpr int kBlurRadius = 2; - // Cache the blurred background per size - static QPixmap cachedBg; - static QSize cachedSize; +// // Cache the blurred background per size +// static QPixmap cachedBg; +// static QSize cachedSize; - const QSize cacheSize(sw, sh); - if (cachedSize != cacheSize) { - cachedSize = cacheSize; +// const QSize cacheSize(sw, sh); +// if (cachedSize != cacheSize) { +// cachedSize = cacheSize; - QPixmap gradPm(sw, sh); - gradPm.fill(Qt::transparent); - { - QPainter gp(&gradPm); - gp.setRenderHints(QPainter::Antialiasing | - QPainter::SmoothPixmapTransform); +// QPixmap gradPm(sw, sh); +// gradPm.fill(Qt::transparent); +// { +// QPainter gp(&gradPm); +// gp.setRenderHints(QPainter::Antialiasing | +// QPainter::SmoothPixmapTransform); - QLinearGradient grad(0, 0, 1, 1); - grad.setCoordinateMode(QGradient::ObjectMode); - grad.setStops({{0.0, QColor(255, 255, 255, 255)}, - {0.35, QColor(255, 255, 255, 125)}, - {0.65, QColor(255, 255, 255, 125)}, - {1.0, QColor(255, 255, 255, 255)}}); +// QLinearGradient grad(0, 0, 1, 1); +// grad.setCoordinateMode(QGradient::ObjectMode); +// grad.setStops({{0.0, QColor(255, 255, 255, 255)}, +// {0.35, QColor(255, 255, 255, 125)}, +// {0.65, QColor(255, 255, 255, 125)}, +// {1.0, QColor(255, 255, 255, 255)}}); - gp.fillRect(QRectF(0, 0, sw, sh), grad); - } +// gp.fillRect(QRectF(0, 0, sw, sh), grad); +// } - QPixmap blurred = BackDrop::blurPixmap(gradPm, kBlurRadius); +// QPixmap blurred = BackDrop::blurPixmap(gradPm, kBlurRadius); - QPixmap mask = BackDrop::getColoredPixmap( - QBrush(Qt::white), Qt::white, 1, sw, sh, int(kCornerRadius * dpr)); +// QPixmap mask = BackDrop::getColoredPixmap( +// QBrush(Qt::white), Qt::white, 1, sw, sh, int(kCornerRadius * +// dpr)); - BackDrop::cutPixmap(blurred, mask, sw, sh); +// BackDrop::cutPixmap(blurred, mask, sw, sh); - blurred.setDevicePixelRatio(dpr); - cachedBg = blurred; - } +// blurred.setDevicePixelRatio(dpr); +// cachedBg = blurred; +// } - QPainterPath clipPath; - QRectF r = rect().adjusted(0.5, 0.5, -0.5, -0.5); - clipPath.addRoundedRect(r, kCornerRadius, kCornerRadius); - p.setClipPath(clipPath); - p.drawPixmap(r.toRect(), cachedBg); +// QPainterPath clipPath; +// QRectF r = rect().adjusted(0.5, 0.5, -0.5, -0.5); +// clipPath.addRoundedRect(r, kCornerRadius, kCornerRadius); +// p.setClipPath(clipPath); +// p.drawPixmap(r.toRect(), cachedBg); - p.setClipping(false); - QColor borderColor = m_selected ? COLOR_BLUE : QColor("#FFFFFF"); - QPen pen(borderColor, m_selected ? 2.0 : 1.0); - p.setPen(pen); - p.setBrush(Qt::NoBrush); - p.drawRoundedRect(r, kCornerRadius, kCornerRadius); -} \ No newline at end of file +// p.setClipping(false); +// QColor borderColor = m_selected ? COLOR_BLUE : QColor("#FFFFFF"); +// QPen pen(borderColor, m_selected ? 2.0 : 1.0); +// p.setPen(pen); +// p.setBrush(Qt::NoBrush); +// p.drawRoundedRect(r, kCornerRadius, kCornerRadius); +// } \ No newline at end of file diff --git a/src/devicesidebarwidget.h b/src/devicesidebarwidget.h index 80c62ad..9baa8e8 100644 --- a/src/devicesidebarwidget.h +++ b/src/devicesidebarwidget.h @@ -45,8 +45,8 @@ public: void setCollapsed(bool collapsed); bool isCollapsed() const { return m_collapsed; } -protected: - void paintEvent(QPaintEvent *event) override; + // protected: + // void paintEvent(QPaintEvent *event) override; signals: void deviceSelected(const std::string &uuid); void navigationRequested(const std::string &uuid, const QString §ion); diff --git a/src/diagnosewidget.cpp b/src/diagnosewidget.cpp index 77f9c2f..d2ebd06 100644 --- a/src/diagnosewidget.cpp +++ b/src/diagnosewidget.cpp @@ -19,10 +19,11 @@ #include "diagnosewidget.h" #ifdef WIN32 -#include "platform/windows/check_deps.h" +#include "platform/windows/win_common.h" #include #include #endif +#include "iDescriptor-ui.h" #include #include #include @@ -97,21 +98,37 @@ void DependencyItem::setInstalled(bool installed) if (installed) { if (m_name == "Avahi Daemon") { - m_statusLabel->setText("✓ Activated"); + m_statusLabel->setText("Activated"); } else { - m_statusLabel->setText("✓ Installed"); + m_statusLabel->setText("Installed"); } - m_statusLabel->setStyleSheet("color: green; font-weight: bold;"); +#ifndef WIN32 + m_statusLabel->setStyleSheet("color: green;"); +#else + // FIXME: if we call this multiple times, the styles will keep stacking + // and become a mess, need a better way to handle this + m_statusLabel->setStyleSheet(mergeStyles( + m_statusLabel, + QString("QLabel { color: %1; }").arg(COLOR_GREEN.name()))); +#endif m_installButton->setVisible(false); } else { if (m_name == "Avahi Daemon") { - m_statusLabel->setText("✗ Not activated"); + m_statusLabel->setText("Not activated"); m_installButton->setText("Enable"); } else { - m_statusLabel->setText("✗ Not Installed"); + m_statusLabel->setText("Not Installed"); m_installButton->setText("Install"); } - m_statusLabel->setStyleSheet("color: red; font-weight: bold;"); +#ifndef WIN32 + m_statusLabel->setStyleSheet("color: red;"); +#else + // FIXME: if we call this multiple times, the styles will keep stacking + // and become a mess, need a better way to handle this + m_statusLabel->setStyleSheet(mergeStyles( + m_statusLabel, + QString("QLabel { color: %1; }").arg(COLOR_RED.name()))); +#endif m_installButton->setVisible(true); } } diff --git a/src/diskusagewidget.cpp b/src/diskusagewidget.cpp index a0b631d..bf4face 100644 --- a/src/diskusagewidget.cpp +++ b/src/diskusagewidget.cpp @@ -143,22 +143,25 @@ void DiskUsageWidget::setupUI() // Set colors m_systemBar->setStyleSheet( "QWidget#systemBar { background-color: #a1384d; border: 1px solid" - "#e64a5b; padding: 0; margin: 0; border-top-left-radius: 3px; " + "#e64a5b; padding: 0; margin: 0; border-radius:0px; " + "border-top-left-radius: 3px; " "border-bottom-left-radius: 3px; }"); m_appsBar->setStyleSheet( "QWidget#appsBar { background-color: #4f869f; border: 1px solid " - "#63b4da; padding: 0; margin: 0; }"); + "#63b4da; border-radius:0px; padding: 0; margin: 0; }"); m_mediaBar->setStyleSheet("QWidget#mediaBar { background-color: #2ECC71; " "border: none; padding: 0; margin: 0; }"); m_galleryBar->setStyleSheet( "QWidget#galleryBar { background-color: #9b59b6; border: 1px solid " - "#8e44ad; padding: 0; margin: 0; }"); + "#8e44ad; border-radius:0px; padding: 0; margin: 0; }"); m_othersBar->setStyleSheet( "QWidget#othersBar { background-color: #a28729; border: 1px solid " - "#c4a32d; padding: 0; margin: 0; }"); + "#c4a32d; border-radius:0px; padding: 0; margin: 0; }"); m_freeBar->setStyleSheet( - "QWidget#freeBar { background-color: #474747; border: 1px solid " - "#4f4f4f; padding: 0; margin: 0; border-top-right-radius: 3px; " + "QWidget#freeBar { background-color: rgba(255, 255, 255, 10); border: " + "1px solid " + "#4f4f4f4f; padding: 0; margin: 0; border-radius:0px; " + "border-top-right-radius: 3px; " "border-bottom-right-radius: 3px; }"); // remove padding margin from layout diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 2af451c..852ac2c 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -239,12 +239,12 @@ QString HttpServer::generateJsonManifest() const QString HttpServer::getLocalIP() const { - foreach (const QNetworkInterface &interface, + foreach (const QNetworkInterface &netIf, QNetworkInterface::allInterfaces()) { - if (interface.flags().testFlag(QNetworkInterface::IsUp) && - !interface.flags().testFlag(QNetworkInterface::IsLoopBack)) { + if (netIf.flags().testFlag(QNetworkInterface::IsUp) && + !netIf.flags().testFlag(QNetworkInterface::IsLoopBack)) { foreach (const QNetworkAddressEntry &entry, - interface.addressEntries()) { + netIf.addressEntries()) { if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) { return entry.ip().toString(); } diff --git a/src/iDescriptor-ui.h b/src/iDescriptor-ui.h index d5a3708..eb30f9a 100644 --- a/src/iDescriptor-ui.h +++ b/src/iDescriptor-ui.h @@ -40,13 +40,35 @@ #ifdef __APPLE__ #include "./platform/macos/macos.h" +#elif defined(WIN32) +#include "./platform/windows/win_common.h" #endif #define COLOR_GREEN QColor(0, 180, 0) // Green #define COLOR_ORANGE QColor(255, 140, 0) // Orange #define COLOR_RED QColor(255, 0, 0) // Red #define COLOR_BLUE QColor("#2b5693") + +#ifndef WIN32 #define COLOR_ACCENT_BLUE QColor("#0b5ed7") +#define COLOR_HYPERLINK QColor(0, 122, 255) +#else +#define COLOR_ACCENT_BLUE QColor(getWindowsAccentColor()) +#define COLOR_HYPERLINK QColor("#FF7FFFD4") +#endif + +inline QString mergeStyles(QWidget *widget, const QString &newStyles) +{ + if (!widget) { + return newStyles; + } + QString existing = widget->styleSheet(); + if (existing.isEmpty()) + return newStyles; + + return existing + "\n" + newStyles; +} + #define MIN_MAIN_WINDOW_SIZE QSize(900, 600) class ResponsiveGraphicsView : public QGraphicsView diff --git a/src/iDescriptor.h b/src/iDescriptor.h index 341df16..c8dd97b 100644 --- a/src/iDescriptor.h +++ b/src/iDescriptor.h @@ -355,7 +355,7 @@ public: plist_get_string_val(current_node, &value); std::string result = value ? value : ""; if (value) - free(value); + plist_mem_free(value); return result; } plist_t getNode() const { return current_node; } @@ -605,10 +605,12 @@ inline void free_directory_listing(char **entries, size_t count) return; for (size_t i = 0; i < count; i++) { if (entries[i]) { - free(entries[i]); + // FIXME: crashes on Windows + // free(entries[i]); } } - free(entries); + // FIXME: crashes on Windows + // free(entries); } inline int read_file(const char *filename, uint8_t **data, size_t *length) diff --git a/src/ifusewidget.cpp b/src/ifusewidget.cpp index 10f0928..28067c3 100644 --- a/src/ifusewidget.cpp +++ b/src/ifusewidget.cpp @@ -30,7 +30,7 @@ #include #include #ifdef WIN32 -#include "platform/windows/check_deps.h" +#include "platform/windows/win_common.h" #endif iFuseWidget::iFuseWidget(iDescriptorDevice *device, QWidget *parent) diff --git a/src/infolabel.cpp b/src/infolabel.cpp index ef5f411..95af921 100644 --- a/src/infolabel.cpp +++ b/src/infolabel.cpp @@ -29,9 +29,7 @@ InfoLabel::InfoLabel(const QString &text, const QString &textToCopy, m_textToCopy(!textToCopy.isEmpty() ? textToCopy : text) { setCursor(Qt::PointingHandCursor); - setStyleSheet("QLabel:hover { background-color: rgba(255, 255, 255, 0.1); " - "border-radius: 2px; }"); - + setStyleSheet(m_style); m_restoreTimer = new QTimer(this); m_restoreTimer->setSingleShot(true); connect(m_restoreTimer, &QTimer::timeout, this, @@ -49,39 +47,26 @@ void InfoLabel::mousePressEvent(QMouseEvent *event) // prevent layout shifts setMinimumWidth(originalWidth); setText("Copied!"); +#ifdef WIN32 + setStyleSheet(QStringLiteral( + "QLabel { color: #4CAF50; font-weight: bold; font-size: 14px; }" + "QLabel:hover { background-color: rgba(255, 255, 255, 0.1); " + "border-radius: 2px; }")); +#else setStyleSheet("QLabel { color: #4CAF50; font-weight: bold; } " "QLabel:hover { background-color: rgba(255, 255, 255, " "0.1); border-radius: 2px; }"); - +#endif m_restoreTimer->start(1000); // Show "Copied!" for 1 second } QLabel::mousePressEvent(event); } -void InfoLabel::enterEvent(QEnterEvent *event) -{ - if (!m_restoreTimer->isActive()) { - setStyleSheet("QLabel:hover { background-color: rgba(255, 255, 255, " - "0.1); border-radius: 2px; }"); - } - QLabel::enterEvent(event); -} - -void InfoLabel::leaveEvent(QEvent *event) -{ - if (!m_restoreTimer->isActive()) { - setStyleSheet("QLabel:hover { background-color: rgba(255, 255, 255, " - "0.1); border-radius: 2px; }"); - } - QLabel::leaveEvent(event); -} - void InfoLabel::restoreOriginalText() { setText(m_originalText); setMinimumWidth(0); - setStyleSheet("QLabel:hover { background-color: rgba(255, 255, 255, 0.1); " - "border-radius: 2px; }"); + setStyleSheet(m_style); } void InfoLabel::setOriginalText(const QString &text) { m_originalText = text; } diff --git a/src/infolabel.h b/src/infolabel.h index 58f505b..01aa217 100644 --- a/src/infolabel.h +++ b/src/infolabel.h @@ -21,6 +21,7 @@ #define INFOLABEL_H #include +#include #include class InfoLabel : public QLabel @@ -37,8 +38,6 @@ public: protected: void mousePressEvent(QMouseEvent *event) override; - void enterEvent(QEnterEvent *event) override; - void leaveEvent(QEvent *event) override; private slots: void restoreOriginalText(); @@ -47,6 +46,18 @@ private: QString m_originalText; QString m_textToCopy; QTimer *m_restoreTimer; + QString m_style = +#ifdef WIN32 + QStringLiteral( + "QLabel:hover { background-color: rgba(255, 255, 255, 0.1); " + "border-radius: 2px; }" + "QLabel { " + "font-size: 14px;}"); +#else + QStringLiteral( + "QLabel:hover { background-color: rgba(255, 255, 255, 0.1); " + "border-radius: 2px; }"); +#endif }; #endif // INFOLABEL_H \ No newline at end of file diff --git a/src/installedappswidget.cpp b/src/installedappswidget.cpp index 4c4265e..24ccbbb 100644 --- a/src/installedappswidget.cpp +++ b/src/installedappswidget.cpp @@ -322,7 +322,7 @@ void InstalledAppsWidget::fetchInstalledApps() plist_get_string_val(bundle_id, &bundle_id_str); if (bundle_id_str) { appData["bundleId"] = QString(bundle_id_str); - free(bundle_id_str); + plist_mem_free(bundle_id_str); } } @@ -337,7 +337,7 @@ void InstalledAppsWidget::fetchInstalledApps() if (display_name_str) { appData["displayName"] = QString(display_name_str); - free(display_name_str); + plist_mem_free(display_name_str); } } @@ -350,7 +350,7 @@ void InstalledAppsWidget::fetchInstalledApps() plist_get_string_val(version, &version_str); if (version_str) { appData["version"] = QString(version_str); - free(version_str); + plist_mem_free(version_str); } } diff --git a/src/logindialog.cpp b/src/logindialog.cpp index 5ff6980..f886dad 100644 --- a/src/logindialog.cpp +++ b/src/logindialog.cpp @@ -30,12 +30,20 @@ #include #include +#ifdef WIN32 +#include "platform/windows/win_common.h" +#endif + LoginDialog::LoginDialog(QWidget *parent) : QDialog(parent) { setWindowTitle("Login to App Store - iDescriptor"); setModal(true); setFixedWidth(400); +#ifdef WIN32 + setupWinWindow(this); +#endif + QVBoxLayout *layout = new QVBoxLayout(this); layout->setSpacing(15); layout->setContentsMargins(20, 20, 20, 20); @@ -47,8 +55,11 @@ LoginDialog::LoginDialog(QWidget *parent) : QDialog(parent) m_emailEdit = new QLineEdit(); m_emailEdit->setPlaceholderText("Enter your email"); +#ifndef WIN32 m_emailEdit->setStyleSheet("padding: 8px; border: 1px solid #ddd; " "border-radius: 4px; font-size: 14px;"); +#endif + layout->addWidget(m_emailEdit); // Password @@ -59,33 +70,35 @@ LoginDialog::LoginDialog(QWidget *parent) : QDialog(parent) m_passwordEdit = new QLineEdit(); m_passwordEdit->setPlaceholderText("Enter your password"); m_passwordEdit->setEchoMode(QLineEdit::Password); +#ifndef WIN32 m_passwordEdit->setStyleSheet("padding: 8px; border: 1px solid #ddd; " "border-radius: 4px; font-size: 14px;"); +#endif layout->addWidget(m_passwordEdit); // Description - QLabel *descriptionLabel = - new QLabel("Don't worry, your credentials won't be " - "stored or shared anywhere. This App is open-source."); + QLabel *descriptionLabel = new QLabel( + "You shouldn't be using your main account here and don't worry, " + "your credentials won't be " + "stored or shared anywhere. This App is open-source."); descriptionLabel->setStyleSheet("font-size: 10px; font-weight: thin;"); descriptionLabel->setAlignment(Qt::AlignLeft); - descriptionLabel->setWordWrap(true); // Add this line + descriptionLabel->setWordWrap(true); layout->addWidget(descriptionLabel); - // --- Buttons and Indicator --- - // Create a container widget for the sign-in button and the indicator QWidget *signInContainer = new QWidget(this); m_signInStackedLayout = new QStackedLayout(signInContainer); m_signInStackedLayout->setContentsMargins(0, 0, 0, 0); // Create the actual "Sign In" button m_signInButton = new QPushButton("Sign In"); +#ifndef WIN32 m_signInButton->setStyleSheet( "QPushButton { padding: 8px 16px; font-size: 14px; border-radius: 4px; " "background-color: #007AFF; color: white; border: none; min-width: " "80px; }" "QPushButton:hover { background-color: #0056CC; }"); - +#endif // Create the indicator QWidget *indicatorWidget = new QWidget(); QVBoxLayout *indicatorLayout = new QVBoxLayout(indicatorWidget); @@ -103,15 +116,15 @@ LoginDialog::LoginDialog(QWidget *parent) : QDialog(parent) // Ensure the container has the same size as the button signInContainer->setFixedSize(m_signInButton->sizeHint()); - // Create the "Cancel" button m_cancelButton = new QPushButton("Cancel"); - // add disabled style to cancel button +#ifndef WIN32 m_cancelButton->setStyleSheet( "QPushButton { padding: 8px 16px; font-size: 14px; border-radius: 4px; " "background-color: #f0f0f0; color: #333; border: 1px solid #ddd; " "min-width: 80px; }" "QPushButton:disabled { background-color: #eee; color: #aaa; border: " "1px solid #ddd; }"); +#endif // Layout for the buttons QHBoxLayout *buttonLayout = new QHBoxLayout(); diff --git a/src/main.cpp b/src/main.cpp index 133ae06..4f0cf43 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,14 +23,15 @@ #include #include #include +#include #include #include #include #include - #ifdef WIN32 -#include "platform/windows/check_deps.h" +#include "platform/windows/win_common.h" #endif + int main(int argc, char *argv[]) { QApplication a(argc, argv); @@ -45,6 +46,15 @@ int main(int argc, char *argv[]) // " "their default values."); // } #ifdef WIN32 + QFile styleFile(detectDarkModeWindows() ? ":/resources/win.dark.qcss" + : ":/resources/win.light.qcss"); + if (styleFile.open(QFile::ReadOnly | QFile::Text)) { + const QString style = QString::fromUtf8(styleFile.readAll()) + .arg(COLOR_ACCENT_BLUE.name()); + qDebug() << "Loaded Windows style sheet successfully."; + a.setStyleSheet(style); + } + QString appPath = QCoreApplication::applicationDirPath(); QString gstPluginPath = QDir::toNativeSeparators(appPath + "/gstreamer-1.0"); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 7687516..80c1fa9 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -18,7 +18,6 @@ */ #include "mainwindow.h" -#include "./ui_mainwindow.h" #include "appswidget.h" #include "devicemanagerwidget.h" #include "iDescriptor-ui.h" @@ -26,9 +25,6 @@ #include "ifusediskunmountbutton.h" #include "ifusemanager.h" #include "jailbrokenwidget.h" -// #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT -// #include "libirecovery.h" -// #endif #include "toolboxwidget.h" #include "welcomewidget.h" #include @@ -51,112 +47,38 @@ #include #include #include - #ifdef WIN32 -#include "platform/windows/check_deps.h" +#include "platform/windows/win_common.h" #endif using namespace IdeviceFFI; -// void handleCallback(const idevice_event_t *event, void *userData) -// { -// printf("Device event received: "); - -// switch (event->event) { -// case IDEVICE_DEVICE_ADD: { -// /* this should never happen iDescriptor does not support network -// devices but for some reason even though we are only listening for USB -// devices, we still get network devices on macOS*/ if (event->conn_type -// == CONNECTION_NETWORK) { -// return; -// } -// qDebug() << "Device added: " << QString::fromUtf8(event->udid); - -// QMetaObject::invokeMethod( -// AppContext::sharedInstance(), "addDevice", Qt::QueuedConnection, -// Q_ARG(QString, QString::fromUtf8(event->udid)), -// Q_ARG(idevice_connection_type, event->conn_type), -// Q_ARG(AddType, AddType::Regular)); -// break; -// } - -// case IDEVICE_DEVICE_REMOVE: { -// QMetaObject::invokeMethod(AppContext::sharedInstance(), -// "removeDevice", -// Qt::QueuedConnection, -// Q_ARG(QString, QString(event->udid))); -// break; -// } - -// case IDEVICE_DEVICE_PAIRED: { -// if (event->conn_type == CONNECTION_NETWORK) { -// qDebug() -// << "Network devices are not supported but a network device -// was " -// "received in event listener. Please report this issue."; -// return; -// } -// qDebug() << "Device paired: " << QString::fromUtf8(event->udid); - -// QMetaObject::invokeMethod( -// AppContext::sharedInstance(), "addDevice", Qt::QueuedConnection, -// Q_ARG(QString, QString::fromUtf8(event->udid)), -// Q_ARG(idevice_connection_type, event->conn_type), -// Q_ARG(AddType, AddType::Pairing)); -// break; -// } -// default: -// qDebug() << "Unhandled event: " << event->event; -// } -// } - -// #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT -// void handleCallbackRecovery(const irecv_device_event_t *event, void -// *userData) -// { - -// switch (event->type) { -// case IRECV_DEVICE_ADD: -// qDebug() << "Recovery device added: "; -// QMetaObject::invokeMethod(AppContext::sharedInstance(), -// "addRecoveryDevice", Qt::QueuedConnection, -// Q_ARG(uint64_t, event->device_info->ecid)); -// break; -// case IRECV_DEVICE_REMOVE: -// qDebug() << "Recovery device removed: "; -// QMetaObject::invokeMethod(AppContext::sharedInstance(), -// "removeRecoveryDevice", -// Qt::QueuedConnection, Q_ARG(uint64_t, -// event->device_info->ecid)); -// break; -// default: -// printf("Unhandled recovery event: %d\n", event->type); -// } -// } -// irecv_device_event_context_t context; -// #endif - MainWindow *MainWindow::sharedInstance() { static MainWindow instance; return &instance; } -MainWindow::MainWindow(QWidget *parent) - : QMainWindow(parent), ui(new Ui::MainWindow) +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { - ui->setupUi(this); setMinimumSize(MIN_MAIN_WINDOW_SIZE); resize(MIN_MAIN_WINDOW_SIZE); - m_ZTabWidget = new ZTabWidget(this); - m_ZTabWidget->setAttribute(Qt::WA_ContentsMarginsRespectsSafeArea, false); - setContentsMargins(0, 0, 0, 0); + + QWidget *centralWidget = new QWidget(this); + setCentralWidget(centralWidget); + auto mainLayout = new QVBoxLayout(centralWidget); + mainLayout->setContentsMargins(0, 0, 0, 0); + + m_ZTabWidget = new ZTabWidget(this); #ifdef __APPLE__ setupMacOSWindow(this); setAttribute(Qt::WA_ContentsMarginsRespectsSafeArea, false); #endif - setCentralWidget(m_ZTabWidget); + mainLayout->addWidget(m_ZTabWidget); +#ifdef WIN32 + setupWinWindow(this); +#endif m_mainStackedWidget = new QStackedWidget(); WelcomeWidget *welcomePage = new WelcomeWidget(this); @@ -200,25 +122,35 @@ MainWindow::MainWindow(QWidget *parent) m_connectedDeviceCountLabel->setStyleSheet( "QLabel:hover { background-color : #13131319; }"); - ui->statusbar->addWidget(m_connectedDeviceCountLabel); + QWidget *statusbar = new QWidget(); + QHBoxLayout *statusLayout = new QHBoxLayout(statusbar); + statusLayout->setContentsMargins(0, 0, 0, 0); + statusbar->setObjectName("StatusBar"); + statusbar->setStyleSheet( + "QWidget#StatusBar { background-color: transparent; }"); + statusLayout->addWidget(m_connectedDeviceCountLabel); // TODO: implement downloads/uploads progress stuff StatusBalloon *statusBalloon = StatusBalloon::sharedInstance(); - ui->statusbar->addWidget(statusBalloon->getButton()); + statusLayout->addWidget(statusBalloon->getButton()); + statusLayout->addStretch(1); - ui->statusbar->setContentsMargins(0, 0, 0, 0); + statusLayout->setContentsMargins(0, 0, 0, 0); QLabel *appVersionLabel = new QLabel(QString("v%1").arg(APP_VERSION)); appVersionLabel->setContentsMargins(5, 0, 5, 0); appVersionLabel->setStyleSheet( "QLabel:hover { background-color : #13131319; }"); - ui->statusbar->addPermanentWidget(appVersionLabel); - ui->statusbar->addPermanentWidget(githubButton); - ui->statusbar->addPermanentWidget(settingsButton); -#ifdef WIN32 - ui->statusbar->setStyleSheet( - "QStatusBar { border-top: 1px solid #dcdcdc; }"); -#endif + statusLayout->addWidget(appVersionLabel); + statusLayout->addWidget(githubButton); + statusLayout->addWidget(settingsButton); + // #ifdef WIN32 + // statusLayout->setStyleSheet("QStatusBar { border-top: 1px solid + // #dcdcdc; + // }"); + // #endif + + mainLayout->addWidget(statusbar); #ifdef __linux__ QList mounted_iFusePaths = iFuseManager::getMountPoints(); @@ -226,7 +158,7 @@ MainWindow::MainWindow(QWidget *parent) for (const QString &path : mounted_iFusePaths) { auto *p = new iFuseDiskUnmountButton(path); - ui->statusbar->addPermanentWidget(p); + statusbar->addWidget(p); connect(p, &iFuseDiskUnmountButton::clicked, this, [this, p, path]() { bool ok = iFuseManager::linuxUnmount(path); if (!ok) { @@ -235,7 +167,7 @@ MainWindow::MainWindow(QWidget *parent) ". Please try again."); return; } - ui->statusbar->removeWidget(p); + statusbar->removeWidget(p); p->deleteLater(); }); } @@ -521,7 +453,6 @@ MainWindow::~MainWindow() // #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT // irecv_device_event_unsubscribe(context); // #endif - delete ui; m_deviceMonitor->requestInterruption(); // FIXME:QThread: Destroyed while thread '' is still running // m_deviceMonitor->wait(); diff --git a/src/mainwindow.h b/src/mainwindow.h index 85d1bbb..8f23da0 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -22,23 +22,13 @@ #include "ZDownloader.h" #include "ZUpdater.h" #include "devicemanagerwidget.h" -#include "iDescriptor.h" -#include -// #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT -// #include "libirecovery.h" -// #endif #include "devicemonitor.h" +#include "iDescriptor.h" #include "ztabwidget.h" #include +#include #include -QT_BEGIN_NAMESPACE -namespace Ui -{ -class MainWindow; -} -QT_END_NAMESPACE - class MainWindow : public QMainWindow { Q_OBJECT @@ -54,11 +44,17 @@ public slots: private: void createMenus(); - Ui::MainWindow *ui; ZTabWidget *m_ZTabWidget; DeviceManagerWidget *m_deviceManager; QStackedWidget *m_mainStackedWidget; QLabel *m_connectedDeviceCountLabel; DeviceMonitorThread *m_deviceMonitor; + QLabel *m_titleLabel; + QPushButton *m_minBtn; + QPushButton *m_maxBtn; + QPushButton *m_closeBtn; + QWidget *m_titleBar; + QWidget *m_contentArea; + QHBoxLayout *m_titleBarLayout; }; #endif // MAINWINDOW_H diff --git a/src/platform/windows/blur_imp.cpp b/src/platform/windows/blur_imp.cpp new file mode 100644 index 0000000..aa3698e --- /dev/null +++ b/src/platform/windows/blur_imp.cpp @@ -0,0 +1,101 @@ +/* + * iDescriptor: A free and open-source idevice management tool. + * + * Copyright (C) 2025 Uncore + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include "../../settingsmanager.h" +#include "win_common.h" + +void enableAcrylic(HWND hwnd) +{ + const HINSTANCE hModule = LoadLibraryA("user32.dll"); + if (hModule) { + struct ACCENTPOLICY { + int nAccentState; + int nFlags; + DWORD nColor; + int nAnimationId; + }; + struct WINCOMPATTRDATA { + int nAttribute; + PVOID pData; + ULONG ulDataSize; + }; + + typedef BOOL(WINAPI * + pSetWindowCompositionAttribute)(HWND, WINCOMPATTRDATA *); + const auto SetWindowCompositionAttribute = + (pSetWindowCompositionAttribute)GetProcAddress( + hModule, "SetWindowCompositionAttribute"); + + if (SetWindowCompositionAttribute) { + ACCENTPOLICY policy{}; + policy.nAccentState = 4; // ACCENT_ENABLE_ACRYLICBLURBEHIND + policy.nFlags = 2; + + policy.nColor = 0xD0202020; + + WINCOMPATTRDATA data{}; + data.nAttribute = 19; + data.pData = &policy; + data.ulDataSize = sizeof(policy); + + SetWindowCompositionAttribute(hwnd, &data); + } + FreeLibrary(hModule); + } +} + +#ifndef DWMWA_SYSTEMBACKDROP_TYPE +#define DWMWA_SYSTEMBACKDROP_TYPE 38 +#endif + +#ifndef DWMWA_MICA_EFFECT +#define DWMWA_MICA_EFFECT 1029 +#endif +void enableMica(HWND hwnd) +{ + if (!hwnd) + return; + SettingsManager *sm = SettingsManager::sharedInstance(); + WIN_BACKDROP type = sm->winBackdropType(); + MARGINS margins = {-1}; + DwmExtendFrameIntoClientArea(hwnd, &margins); + + DWORD build = 0; + RTL_OSVERSIONINFOW rovi = {0}; + rovi.dwOSVersionInfoSize = sizeof(rovi); + + using RtlGetVersionPtr = LONG(WINAPI *)(PRTL_OSVERSIONINFOW); + HMODULE ntdll = GetModuleHandleW(L"ntdll.dll"); + if (ntdll) { + auto pRtlGetVersion = reinterpret_cast( + GetProcAddress(ntdll, "RtlGetVersion")); + if (pRtlGetVersion && pRtlGetVersion(&rovi) == 0) { + build = rovi.dwBuildNumber; + } + } + + if (build >= 22523) { + DwmSetWindowAttribute(hwnd, DWMWA_SYSTEMBACKDROP_TYPE, &type, + sizeof(type)); + } else if (build >= 22000) { + // Undocumented old method + BOOL mica = TRUE; + DwmSetWindowAttribute(hwnd, DWMWA_MICA_EFFECT, &mica, sizeof(mica)); + } +} diff --git a/src/platform/windows/check_deps.cpp b/src/platform/windows/check_deps.cpp index b2a1062..7d8b082 100644 --- a/src/platform/windows/check_deps.cpp +++ b/src/platform/windows/check_deps.cpp @@ -17,8 +17,8 @@ * along with this program. If not, see . */ +#include "win_common.h" #include -#include bool CheckRegistry(HKEY hKeyRoot, LPCSTR subKey, LPCSTR displayNameToFind) { diff --git a/src/platform/windows/check_deps.h b/src/platform/windows/check_deps.h deleted file mode 100644 index df85ea2..0000000 --- a/src/platform/windows/check_deps.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * iDescriptor: A free and open-source idevice management tool. - * - * Copyright (C) 2025 Uncore - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#ifndef CHECK_DEPS_H -#define CHECK_DEPS_H - -bool IsAppleMobileDeviceSupportInstalled(); -bool IsWinFspInstalled(); -bool is_iDescriptorInstalled(); -bool IsBonjourServiceInstalled(); - -#endif // CHECK_DEPS_H \ No newline at end of file diff --git a/src/platform/windows/setuptitlebar.cpp b/src/platform/windows/setuptitlebar.cpp new file mode 100644 index 0000000..d344c87 --- /dev/null +++ b/src/platform/windows/setuptitlebar.cpp @@ -0,0 +1,33 @@ +#include "win_common.h" + +// TODO: remove +void setupTitleBar(HWND hwnd) +{ + if (!hwnd) + return; + + LONG_PTR style = GetWindowLongPtr(hwnd, GWL_STYLE); + if (style) { + style &= ~WS_THICKFRAME; // disable resizing + // Keep WS_CAPTION, WS_SYSMENU, WS_MINIMIZEBOX, WS_MAXIMIZEBOX + SetWindowLongPtr(hwnd, GWL_STYLE, style); + } + + SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + + // Clear title text and icon + SetWindowTextW(hwnd, L""); + SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM) nullptr); + SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) nullptr); + + // Make the title bar transparent (extend frame into client area) + MARGINS margins = {0, 0, 0, 0}; + DwmExtendFrameIntoClientArea(hwnd, &margins); + + // Disable the DWM caption drawing so the title bar has no background + BOOL value = TRUE; + const DWORD DWMWA_USE_IMMERSIVE_DARK_MODE_ATTR = 20; + DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE_ATTR, &value, + sizeof(value)); +} \ No newline at end of file diff --git a/src/platform/windows/widgets/wintoolwidget.cpp b/src/platform/windows/widgets/wintoolwidget.cpp new file mode 100644 index 0000000..9b8567d --- /dev/null +++ b/src/platform/windows/widgets/wintoolwidget.cpp @@ -0,0 +1,361 @@ +/* + * iDescriptor: A free and open-source idevice management tool. + * + * Copyright (C) 2025 Uncore + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include "wintoolwidget.h" +#include "../win_common.h" +#include +#include +#include +#include +#include +#include +#include // GET_X_LPARAM, GET_Y_LPARAM + +static const int TITLE_BAR_HEIGHT = 32; +// FIXME: custom title bar functionality +// doesnt work properly with Mica effetcs applied, need to investigate further +WinToolWidget::WinToolWidget(QWidget *parent) + : QWidget(parent), m_min_btn{nullptr}, m_max_btn{nullptr}, + m_close_btn{nullptr}, m_resize_border_width{6} +{ + + m_hwnd = (HWND)winId(); + setupWinWindow(this); + + QObject::connect(windowHandle(), &QWindow::screenChanged, this, + &WinToolWidget::onScreenChanged); + + // Add widget. (Initialize central widget) + QWidget *entire_widget = this; + setContentsMargins(0, 0, 0, 0); + + // Layout for entire widgets. + QVBoxLayout *entire_layout = new QVBoxLayout(this); + entire_widget->setLayout(entire_layout); + entire_layout->setContentsMargins(0, 0, 0, 0); + entire_layout->setSpacing(0); + + // Initialize title bar widget + m_titlebar_widget = new QWidget(this); + entire_layout->addWidget(m_titlebar_widget); + m_titlebar_widget->setFixedHeight(35); // Default title bar height is 35 + m_titlebar_widget->setContentsMargins(0, 0, 0, 0); + m_titlebar_widget->setSizePolicy(QSizePolicy::Expanding, + QSizePolicy::Fixed); + + // Layout for title bar + QHBoxLayout *titlebar_layout = new QHBoxLayout(this); + m_titlebar_widget->setLayout(titlebar_layout); + titlebar_layout->setContentsMargins(0, 0, 0, 0); + titlebar_layout->setSpacing(0); + + QWidget *custom_titlebar_widget = new QWidget(this); + titlebar_layout->addWidget(custom_titlebar_widget); + custom_titlebar_widget->setContentsMargins(0, 0, 0, 0); + custom_titlebar_widget->setSizePolicy(QSizePolicy::Expanding, + QSizePolicy::Expanding); + + // Caption buttons – sized like Windows (46×32 for min/max, 46×32 for close) + auto makeBtn = [&](const QString &icon, const QString &normalBg, + const QString &hoverBg, + const QString &pressBg) -> QPushButton * { + auto *btn = new QPushButton(icon, this); + btn->setFixedSize(46, TITLE_BAR_HEIGHT); + btn->setFlat(true); + btn->setFocusPolicy(Qt::NoFocus); + btn->setCursor(Qt::ArrowCursor); + btn->setStyleSheet( + QString("QPushButton { background:%1; color:white; border:none;" + " font-size:10px; font-family:'Segoe MDL2 " + "Assets','Segoe UI Symbol'; }" + "QPushButton:hover { background:%2; }" + "QPushButton:pressed{ background:%3; }") + .arg(normalBg, hoverBg, pressBg)); + return btn; + }; + + // U+E921 minimize, U+E922 restore/maximize, U+E8BB close (Segoe MDL2 + // Assets) + m_min_btn = makeBtn("\uE921", "transparent", "rgba(255,255,255,30)", + "rgba(255,255,255,20)"); + m_max_btn = makeBtn("\uE922", "transparent", "rgba(255,255,255,30)", + "rgba(255,255,255,20)"); + m_close_btn = makeBtn("\uE8BB", "transparent", "#C42B1C", "#9B1B0F"); + titlebar_layout->addWidget(m_min_btn); + titlebar_layout->addWidget(m_max_btn); + titlebar_layout->addWidget(m_close_btn); + + // Layout for title bar customization. + m_custom_titlebar_layout = new QHBoxLayout(custom_titlebar_widget); + custom_titlebar_widget->setLayout(m_custom_titlebar_layout); + m_custom_titlebar_layout->setContentsMargins(0, 0, 0, 0); + m_custom_titlebar_layout->setSpacing(0); + m_custom_titlebar_layout->setAlignment(Qt::AlignLeft); + + QObject::connect(m_min_btn, &QPushButton::clicked, this, + &WinToolWidget::onMinimizeButtonClicked); + QObject::connect(m_max_btn, &QPushButton::clicked, this, + &WinToolWidget::onMaximizeButtonClicked); + QObject::connect(m_close_btn, &QPushButton::clicked, this, + &WinToolWidget::onCloseButtonClicked); + entire_layout->setAlignment(titlebar_layout, Qt::AlignTop); + + m_content_widget = new QWidget(this); + entire_layout->addWidget(m_content_widget); + // m_content_layout = new QVBoxLayout(m_content_widget); + m_content_widget->setContentsMargins(0, 0, 0, 0); + m_content_widget->setSizePolicy(QSizePolicy::Expanding, + QSizePolicy::Expanding); + + // Set default title bar palette. + auto pal = m_titlebar_widget->palette(); + pal.setColor(QPalette::Window, QColor(30, 34, 39)); + m_titlebar_widget->setAutoFillBackground(true); + m_titlebar_widget->setPalette(pal); + + // Set default content widget palette. + pal = m_content_widget->palette(); + pal.setColor(QPalette::Window, QColor(35, 39, 46)); + m_content_widget->setAutoFillBackground(true); + m_content_widget->setPalette(pal); +} + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +bool WinToolWidget::nativeEvent(const QByteArray &event_type, void *message, + long *result) +#else +bool WinToolWidget::nativeEvent(const QByteArray &event_type, void *message, + qintptr *result) +#endif +{ + MSG *msg = (MSG *)message; + + switch (msg->message) { + // Remove the default window frame by hooking the WM_NCCALCSIZE message. + case WM_NCCALCSIZE: { + if (msg->lParam) { + WINDOWPLACEMENT wp; + GetWindowPlacement(m_hwnd, &wp); + + if (wp.showCmd == SW_MAXIMIZE) { + NCCALCSIZE_PARAMS *sz = (NCCALCSIZE_PARAMS *)msg->lParam; + sz->rgrc[0].left += 8; + sz->rgrc[0].top += 8; + sz->rgrc[0].right -= 8; + sz->rgrc[0].bottom -= 8; + } + } + return true; + } + + // Process the mouse when it is on the window border. + case WM_NCHITTEST: { + RECT winrect; + GetWindowRect(msg->hwnd, &winrect); + long x = GET_X_LPARAM(msg->lParam); + long y = GET_Y_LPARAM(msg->lParam); + long local_x = x - winrect.left; + long local_y = y - winrect.top; + + if (x >= winrect.left && x < winrect.left + m_resize_border_width && + y < winrect.bottom && y >= winrect.bottom - m_resize_border_width) { + *result = HTBOTTOMLEFT; + return true; + } + + if (x < winrect.right && x >= winrect.right - m_resize_border_width && + y < winrect.bottom && y >= winrect.bottom - m_resize_border_width) { + *result = HTBOTTOMRIGHT; + return true; + } + + if (x >= winrect.left && x < winrect.left + m_resize_border_width && + y >= winrect.top && y < winrect.top + m_resize_border_width) { + *result = HTTOPLEFT; + return true; + } + + if (x < winrect.right && x >= winrect.right - m_resize_border_width && + y >= winrect.top && y < winrect.top + m_resize_border_width) { + *result = HTTOPRIGHT; + return true; + } + + if (x >= winrect.left && x < winrect.left + m_resize_border_width) { + *result = HTLEFT; + return true; + } + + if (x < winrect.right && x >= winrect.right - m_resize_border_width) { + *result = HTRIGHT; + return true; + } + + if (y < winrect.bottom && y >= winrect.bottom - m_resize_border_width) { + *result = HTBOTTOM; + return true; + } + + if (y >= winrect.top && y < winrect.top + m_resize_border_width) { + *result = HTTOP; + return true; + } + + // Check the area where the user can click to move the window. + if (determineNonClickableWidgetUnderMouse(m_custom_titlebar_layout, + local_x, local_y)) { + *result = HTCAPTION; + return true; + } + + *result = HTTRANSPARENT; + break; + } + case WM_SIZE: { + if (m_max_btn) { + WINDOWPLACEMENT wp; + GetWindowPlacement(m_hwnd, &wp); + m_max_btn->setChecked(wp.showCmd == SW_MAXIMIZE ? true : false); + } + break; + } + default: + break; + } + + return false; +} + +// This is used to change the `active` state of widgets in custom title bar. +bool WinToolWidget::event(QEvent *evt) +{ + switch (evt->type()) { + case QEvent::WindowActivate: { +#if QT_VERSION > QT_VERSION_CHECK(5, 0, 0) + m_close_btn->setStyleSheet(m_close_btn->styleSheet()); + m_min_btn->setStyleSheet(m_min_btn->styleSheet()); + m_max_btn->setStyleSheet(m_max_btn->styleSheet()); +#endif + propagateActiveStateInCustomTitlebar(m_custom_titlebar_layout, true); + break; + } + + case QEvent::WindowDeactivate: { +#if QT_VERSION > QT_VERSION_CHECK(5, 0, 0) + m_close_btn->setStyleSheet(m_close_btn->styleSheet()); + m_min_btn->setStyleSheet(m_min_btn->styleSheet()); + m_max_btn->setStyleSheet(m_max_btn->styleSheet()); +#endif + propagateActiveStateInCustomTitlebar(m_custom_titlebar_layout, false); + break; + } + + default: + break; + } + + return QWidget::event(evt); +} + +// Determine whether the current mouse coordinate is on the non-clickable widget +// or not using a recursive method. +bool WinToolWidget::determineNonClickableWidgetUnderMouse(QLayout *layout, + int x, int y) +{ + if (!layout->count() && layout->geometry().contains(x, y)) + return true; + + for (size_t i = 0; i < layout->count(); i++) { + auto item = layout->itemAt(i)->widget(); + if (item) { + if (item->geometry().contains(x, y)) + return !item->property("clickable widget").toBool(); + } else { + auto child_layout = layout->itemAt(i)->layout(); + if (child_layout && child_layout->geometry().contains(x, y)) + return determineNonClickableWidgetUnderMouse(child_layout, x, + y); + } + } + return false; +} + +// Set `active' state using recursive method. +void WinToolWidget::propagateActiveStateInCustomTitlebar(QLayout *layout, + bool active_state) +{ + for (size_t i = 0; i < layout->count(); i++) { + auto item = layout->itemAt(i)->widget(); + if (item) { + item->setProperty("active", active_state); + item->setStyleSheet(item->styleSheet()); + } else { + auto child_layout = layout->itemAt(i)->layout(); + if (child_layout) + propagateActiveStateInCustomTitlebar(child_layout, + active_state); + } + } +} + +QWidget &WinToolWidget::getTitlebarWidget() { return *m_titlebar_widget; } + +QHBoxLayout &WinToolWidget::getCustomTitlebarLayout() +{ + return *m_custom_titlebar_layout; +} + +void WinToolWidget::setResizeBorderWidth(const int &resize_border_width) +{ + m_resize_border_width = resize_border_width; +} + +void WinToolWidget::setTitlebarHeight(const int &titlebar_height) +{ + m_titlebar_widget->setFixedHeight(titlebar_height); +} + +// Render again when frame is moved to another monitor. +void WinToolWidget::onScreenChanged(QScreen *screen) +{ + SetWindowPos(m_hwnd, NULL, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | + SWP_FRAMECHANGED | SWP_NOACTIVATE); +} + +void WinToolWidget::onMinimizeButtonClicked() +{ + SendMessage(m_hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0); +} + +void WinToolWidget::onMaximizeButtonClicked() +{ + SendMessage(m_hwnd, WM_SYSCOMMAND, + m_max_btn->isChecked() ? SC_MAXIMIZE : SC_RESTORE, 0); + + // Remove the hover state from the maximize button. + m_max_btn->setAttribute(Qt::WA_UnderMouse, false); +} + +void WinToolWidget::onCloseButtonClicked() +{ + SendMessage(m_hwnd, WM_CLOSE, 0, 0); +} + +QWidget *WinToolWidget::contentWidget() { return m_content_widget; } diff --git a/src/platform/windows/widgets/wintoolwidget.h b/src/platform/windows/widgets/wintoolwidget.h new file mode 100644 index 0000000..57d4815 --- /dev/null +++ b/src/platform/windows/widgets/wintoolwidget.h @@ -0,0 +1,76 @@ +/* + * iDescriptor: A free and open-source idevice management tool. + * + * Copyright (C) 2025 Uncore + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef WINTOOLWIDGET_H +#define WINTOOLWIDGET_H + +#include "../win_common.h" +#include +#include +#include +#include +#include +#include +#include + +class WinToolWidget : public QWidget +{ + Q_OBJECT + + HWND m_hwnd; + int m_resize_border_width; + + QPushButton *m_min_btn; + QPushButton *m_max_btn; + QPushButton *m_close_btn; + + QWidget *m_content_widget; + QVBoxLayout *m_content_layout; + QWidget *m_titlebar_widget; + QHBoxLayout *m_custom_titlebar_layout; + QColor m_titleBarColor; + +public: + explicit WinToolWidget(QWidget *parent = nullptr); + void setResizeBorderWidth(const int &resize_border_width); + void setTitlebarHeight(const int &titlebar_height); + QWidget &getTitlebarWidget(); + QHBoxLayout &getCustomTitlebarLayout(); + +private: +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + bool nativeEvent(const QByteArray &event_type, void *message, long *result); +#else + bool nativeEvent(const QByteArray &event_type, void *message, + qintptr *result); +#endif + bool event(QEvent *evt); + bool determineNonClickableWidgetUnderMouse(QLayout *layout, int x, int y); + void propagateActiveStateInCustomTitlebar(QLayout *layout, + bool active_state); + void onScreenChanged(QScreen *screen); + void onMinimizeButtonClicked(); + void onMaximizeButtonClicked(); + void onCloseButtonClicked(); + +protected: + QWidget *contentWidget(); +}; + +#endif // WINTOOLWIDGET_H diff --git a/src/platform/windows/win_common.h b/src/platform/windows/win_common.h new file mode 100644 index 0000000..1403175 --- /dev/null +++ b/src/platform/windows/win_common.h @@ -0,0 +1,107 @@ +/* + * iDescriptor: A free and open-source idevice management tool. + * + * Copyright (C) 2025 Uncore + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum WIN_BACKDROP { MICA = 2, ACRYLIC = 3, MICA_ALT = 4 }; + +bool IsAppleMobileDeviceSupportInstalled(); +bool IsWinFspInstalled(); +bool is_iDescriptorInstalled(); +bool IsBonjourServiceInstalled(); + +void enableAcrylic(HWND hwnd); +void setupTitleBar(HWND hwnd); +void enableMica(HWND hwnd); + +inline QString getWindowsAccentColor() +{ + HKEY hKey = nullptr; + DWORD value = 0; + DWORD size = sizeof(value); + + if (RegOpenKeyExW( + HKEY_CURRENT_USER, + L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Accent", + 0, KEY_READ, &hKey) == ERROR_SUCCESS) { + const LONG res = + RegQueryValueExW(hKey, L"AccentColorMenu", nullptr, nullptr, + reinterpret_cast(&value), &size); + RegCloseKey(hKey); + + if (res == ERROR_SUCCESS) { + // Value is stored as 0xAABBGGRR, convert to #RRGGBB + const BYTE b = (value & 0x00FF0000) >> 16; + const BYTE g = (value & 0x0000FF00) >> 8; + const BYTE r = (value & 0x000000FF); + + return QString("#%1%2%3") + .arg(r, 2, 16, QChar('0')) + .arg(g, 2, 16, QChar('0')) + .arg(b, 2, 16, QChar('0')) + .toUpper(); + } + } + + // Fallback default accent color + return "#0078D4"; +} + +inline bool detectDarkModeWindows() +{ + HKEY hKey; + DWORD value; + DWORD size = sizeof(value); + if (RegOpenKeyExW(HKEY_CURRENT_USER, + L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\P" + L"ersonalize", + 0, KEY_READ, &hKey) == ERROR_SUCCESS) { + if (RegQueryValueExW(hKey, L"AppsUseLightTheme", nullptr, nullptr, + reinterpret_cast(&value), + &size) == ERROR_SUCCESS) { + RegCloseKey(hKey); + return value == 0; // 0 means dark mode, 1 means light mode + } + RegCloseKey(hKey); + } + return true; // Default to dark mode if detection fails +} + +inline void setupWinWindow(QWidget *window) +{ + window->setAttribute(Qt::WA_TranslucentBackground); + HWND hwnd = reinterpret_cast(window->winId()); + + // use mica on Windows 11 + QOperatingSystemVersion osVersion = QOperatingSystemVersion::current(); + if (osVersion >= QOperatingSystemVersion::Windows11) { + enableMica(hwnd); + } else { + enableAcrylic(hwnd); + } +} \ No newline at end of file diff --git a/src/servicemanager.cpp b/src/servicemanager.cpp index c2c089e..8d07428 100644 --- a/src/servicemanager.cpp +++ b/src/servicemanager.cpp @@ -98,10 +98,10 @@ ServiceManager::safeAfcFileSeek(const iDescriptorDevice *device, AfcFileHandle *handle, int64_t offset, int whence) { - off_t newPos; return executeAfcOperation( device, - [offset, whence, &newPos](AfcFileHandle *handle) { + [offset, whence](AfcFileHandle *handle) { + int64_t newPos; return afc_file_seek(handle, offset, whence, &newPos); }, handle); @@ -109,7 +109,7 @@ ServiceManager::safeAfcFileSeek(const iDescriptorDevice *device, IdeviceFfiError * ServiceManager::safeAfcFileTell(const iDescriptorDevice *device, - AfcFileHandle *handle, off_t *position) + AfcFileHandle *handle, int64_t *position) { return executeAfcOperation( device, diff --git a/src/servicemanager.h b/src/servicemanager.h index 541f9ca..3c2f65f 100644 --- a/src/servicemanager.h +++ b/src/servicemanager.h @@ -268,7 +268,7 @@ public: int64_t offset, int whence); static IdeviceFfiError *safeAfcFileTell(const iDescriptorDevice *device, AfcFileHandle *handle, - off_t *position); + int64_t *position); // Utility functions static QByteArray safeReadAfcFileToByteArray( const iDescriptorDevice *device, const char *path, diff --git a/src/settingsmanager.cpp b/src/settingsmanager.cpp index cbfee40..3abdaba 100644 --- a/src/settingsmanager.cpp +++ b/src/settingsmanager.cpp @@ -475,4 +475,18 @@ QMap SettingsManager::getAllIdeviceDefaultPairingFiles() const } return macAddresses; } +#endif + +#ifdef WIN32 +void SettingsManager::setWinBackdropType(WIN_BACKDROP type) +{ + m_settings->setValue("winBackdropType", static_cast(type)); + m_settings->sync(); +} + +WIN_BACKDROP SettingsManager::winBackdropType() const +{ + return static_cast( + m_settings->value("winBackdropType", static_cast(MICA)).toInt()); +} #endif \ No newline at end of file diff --git a/src/settingsmanager.h b/src/settingsmanager.h index 153282a..8ed2104 100644 --- a/src/settingsmanager.h +++ b/src/settingsmanager.h @@ -28,6 +28,10 @@ #include #include +#ifdef WIN32 +#include "platform/windows/win_common.h" +#endif + class SettingsManager : public QObject { Q_OBJECT @@ -127,6 +131,10 @@ public: QMap getAllIdeviceDefaultPairingFiles() const; #endif +#ifdef WIN32 + void setWinBackdropType(WIN_BACKDROP type); + WIN_BACKDROP winBackdropType() const; +#endif signals: void favoritePlacesChanged(); void recentLocationsChanged(); diff --git a/src/settingswidget.cpp b/src/settingswidget.cpp index b1c2159..326e65d 100644 --- a/src/settingswidget.cpp +++ b/src/settingswidget.cpp @@ -37,14 +37,23 @@ #include #include +#ifdef WIN32 +#include "platform/windows/win_common.h" +#include +#endif + SettingsWidget::SettingsWidget(QWidget *parent) : QDialog{parent} { +#ifdef WIN32 + m_backDropTypeCombo = nullptr; +#endif setupUI(); loadSettings(); connectSignals(); // due to scrollbar add 10px on windows #ifdef WIN32 resize(sizeHint().width() + 10, sizeHint().height()); + setupWinWindow(this); #endif } @@ -113,7 +122,26 @@ void SettingsWidget::setupUI() themeLayout->addWidget(m_themeCombo); themeLayout->addStretch(); - generalLayout->addLayout(themeLayout); + +#ifdef WIN32 + QOperatingSystemVersion osVersion = QOperatingSystemVersion::current(); + if (osVersion >= QOperatingSystemVersion::Windows11) { + auto *backDropTypeLayout = new QHBoxLayout(); + backDropTypeLayout->addWidget(new QLabel("Backdrop Type:")); + m_backDropTypeCombo = new QComboBox(); + + // "Auto" => no userData => means "no override" + m_backDropTypeCombo->addItem("Auto"); + m_backDropTypeCombo->addItem("Mica", static_cast(MICA)); + m_backDropTypeCombo->addItem("Mica Alt", static_cast(MICA_ALT)); + m_backDropTypeCombo->addItem("Acrylic", static_cast(ACRYLIC)); + + backDropTypeLayout->addWidget(m_backDropTypeCombo); + backDropTypeLayout->addStretch(); + + generalLayout->addLayout(backDropTypeLayout); + } +#endif scrollLayout->addWidget(generalGroup); @@ -191,7 +219,6 @@ void SettingsWidget::setupUI() m_noHoldCheckbox = new QCheckBox("Allow New Connections to Take Over"); airplayLayout->addWidget(m_noHoldCheckbox); - #ifdef __linux__ m_showV4L2CheckBox = new QCheckBox("Show V4L2 Button on AirPlay Widget"); airplayLayout->addWidget(m_showV4L2CheckBox); @@ -302,6 +329,18 @@ void SettingsWidget::loadSettings() #ifdef __linux__ m_showV4L2CheckBox->setChecked(sm->showV4L2()); #endif + +#ifdef WIN32 + if (m_backDropTypeCombo) { + const int typeValue = static_cast(sm->winBackdropType()); + const int index = m_backDropTypeCombo->findData(typeValue); + if (index != -1) { + m_backDropTypeCombo->setCurrentIndex(index); + } else { + m_backDropTypeCombo->setCurrentIndex(0); + } + } +#endif } void SettingsWidget::connectSignals() @@ -356,14 +395,21 @@ void SettingsWidget::connectSignals() connect(m_defaultJailbrokenRootPassword, &QLineEdit::textChanged, this, &SettingsWidget::onSettingChanged); - connect(m_fpsComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, - &SettingsWidget::onSettingChanged); + connect(m_fpsComboBox, QOverload::of(&QComboBox::currentIndexChanged), + this, &SettingsWidget::onSettingChanged); connect(m_noHoldCheckbox, &QCheckBox::toggled, this, &SettingsWidget::onSettingChanged); #ifdef __linux__ connect(m_showV4L2CheckBox, &QCheckBox::toggled, this, &SettingsWidget::onSettingChanged); #endif +#ifdef WIN32 + if (m_backDropTypeCombo) { + connect(m_backDropTypeCombo, + QOverload::of(&QComboBox::currentIndexChanged), this, + &SettingsWidget::onSettingChanged); + } +#endif } void SettingsWidget::onBrowseButtonClicked() @@ -457,6 +503,18 @@ void SettingsWidget::saveSettings() sm->setShowV4L2(m_showV4L2CheckBox->isChecked()); #endif m_applyButton->setEnabled(false); + +#ifdef WIN32 + if (m_backDropTypeCombo) { + const QVariant data = m_backDropTypeCombo->currentData(); + if (!data.isValid()) { + // Mica + sm->setWinBackdropType(static_cast(2)); + } else { + sm->setWinBackdropType(static_cast(data.toInt())); + } + } +#endif } void SettingsWidget::resetToDefaults() diff --git a/src/settingswidget.h b/src/settingswidget.h index 1ecccd6..c385ff0 100644 --- a/src/settingswidget.h +++ b/src/settingswidget.h @@ -77,6 +77,10 @@ private: QCheckBox *m_showV4L2CheckBox; #endif +#ifdef WIN32 + QComboBox *m_backDropTypeCombo; +#endif + // Buttons QPushButton *m_checkUpdatesButton; QPushButton *m_resetButton; diff --git a/src/statusballoon.cpp b/src/statusballoon.cpp index 2245a6c..bb1f0b1 100644 --- a/src/statusballoon.cpp +++ b/src/statusballoon.cpp @@ -26,6 +26,10 @@ #include #include +#ifdef WIN32 +#include "platform/windows/win_common.h" +#endif + Process::Process(QWidget *parent) : QWidget(parent) {} StatusBalloon *StatusBalloon::sharedInstance() @@ -39,6 +43,10 @@ StatusBalloon::StatusBalloon(QWidget *parent) { setMinimumHeight(300); setMinimumWidth(300); +#ifdef WIN32 + // FIXME: doesnt work the second time we call it + enableAcrylic((HWND)winId()); +#endif // Create main layout m_mainLayout = new QVBoxLayout(); m_mainLayout->setSpacing(8); @@ -77,10 +85,11 @@ void StatusBalloon::connectExportThreadSignals() connect(exportManager->m_exportThread, &ExportManagerThread::fileTransferProgress, this, &StatusBalloon::onFileTransferProgress); - QTimer::singleShot(0, this, [this]() { - // test - startExportProcess("Test Export Process", 10, "/path/to/destination"); - }); + // QTimer::singleShot(0, this, [this]() { + // // test + // startExportProcess("Test Export Process", 10, + // "/path/to/destination"); + // }); } void StatusBalloon::onFileTransferProgress(const QUuid &processId, diff --git a/src/toolboxwidget.cpp b/src/toolboxwidget.cpp index 4f9248e..bc06876 100644 --- a/src/toolboxwidget.cpp +++ b/src/toolboxwidget.cpp @@ -37,6 +37,10 @@ #include #include +#ifdef WIN32 +#include +#endif + struct iDescriptorToolWidget { iDescriptorTool tool; QString description; @@ -335,14 +339,35 @@ void ToolboxWidget::updateToolboxStates() bool enabled = !requiresDevice || hasDevice; toolbox->setEnabled(enabled); +// Opacity does not work because of the stylesheet on Windows +#ifndef WIN32 if (enabled) { - toolbox->setStyleSheet("#toolboxFrame { " - "border-radius: 5px; padding: 5px; }"); + toolbox->setStyleSheet("QWidget#toolboxFrame { " + "padding: 5px; }"); } else { - toolbox->setStyleSheet("#toolboxFrame { border-radius: 5px; " + toolbox->setStyleSheet("QWidget#toolboxFrame { " "padding: 5px;" "opacity: 0.45; }"); } +#else + // base style + // toolbox->setStyleSheet("QWidget#toolboxFrame{ padding: 5px; border: " + // "none; outline: none; }"); + + if (enabled) { + // normal look + toolbox->setStyleSheet("QWidget#toolboxFrame { padding: 5px; " + "border: none; outline: none; }"); + toolbox->setCursor(Qt::PointingHandCursor); + } else { + // disabled look: dull bg + border + muted text, no hand cursor + toolbox->setStyleSheet("padding: 5px;" + "border-radius: 8px;" + "background-color: rgba(255,255,255,1);" + "color: #666;"); + toolbox->setCursor(Qt::ArrowCursor); + } +#endif } } diff --git a/src/welcomewidget.cpp b/src/welcomewidget.cpp index cc6f7d8..2d41a27 100644 --- a/src/welcomewidget.cpp +++ b/src/welcomewidget.cpp @@ -78,8 +78,8 @@ void WelcomeWidget::setupUI() m_mainLayout->addSpacing(10); // GitHub link - m_githubLabel = - createStyledLabel("Found an issue? Report it on GitHub", 12, false); + m_githubLabel = createStyledLabel("Found an issue? Report it on GitHub", 12, + false, COLOR_HYPERLINK); m_githubLabel->setWordWrap(false); m_githubLabel->setMaximumWidth(m_imageLabel->sizeHint().width()); m_githubLabel->setCursor(Qt::PointingHandCursor); @@ -88,7 +88,7 @@ void WelcomeWidget::setupUI() QPalette githubPalette = m_githubLabel->palette(); githubPalette.setColor(QPalette::WindowText, - QColor(0, 122, 255)); // Apple blue + COLOR_HYPERLINK); // Apple blue m_githubLabel->setPalette(githubPalette); m_mainLayout->addWidget(m_githubLabel, 0, Qt::AlignCenter); @@ -102,11 +102,13 @@ void WelcomeWidget::setupUI() m_mainLayout->addStretch(1); } +// FIXME: color param is only respected in Windows build ZLabel *WelcomeWidget::createStyledLabel(const QString &text, int fontSize, - bool isBold) + bool isBold, QColor color) { ZLabel *label = new ZLabel(text); +#ifndef WIN32 QFont font = label->font(); if (fontSize > 0) { font.setPointSize(fontSize); @@ -117,6 +119,20 @@ ZLabel *WelcomeWidget::createStyledLabel(const QString &text, int fontSize, label->setFont(font); label->setWordWrap(true); +#else + label->setStyleSheet(mergeStyles( + label, + QString("QLabel {" + " font-size: %1px;" + " font-weight: %2;" + "%3" + "}") + .arg(fontSize > 0 ? QString::number(fontSize) : "inherit") + .arg(isBold ? "bold" : "normal") + // FIXME: handle this better + .arg(color != Qt::black ? QString("color: %1;").arg(color.name()) + : ""))); +#endif return label; } diff --git a/src/welcomewidget.h b/src/welcomewidget.h index 5c9b11e..6d58370 100644 --- a/src/welcomewidget.h +++ b/src/welcomewidget.h @@ -37,7 +37,7 @@ public: private: void setupUI(); ZLabel *createStyledLabel(const QString &text, int fontSize = 0, - bool isBold = false); + bool isBold = false, QColor color = Qt::black); QVBoxLayout *m_mainLayout; ZLabel *m_titleLabel; diff --git a/src/zlineedit.cpp b/src/zlineedit.cpp index d90a47a..f5e9fed 100644 --- a/src/zlineedit.cpp +++ b/src/zlineedit.cpp @@ -32,18 +32,20 @@ void ZLineEdit::setupStyles() { updateStyles(); } void ZLineEdit::updateStyles() { - setStyleSheet("QLineEdit { " - " border: 2px solid " + - qApp->palette().color(QPalette::Midlight).name() + - "; " - " border-radius: 6px; " - " padding: 8px 12px; " - " font-size: 14px; " - "} " - "QLineEdit:focus { " - " border: 2px solid " + - COLOR_ACCENT_BLUE.name() + - "; " - " outline: none; " - "}"); + // FIMXE: seg faults if Qt decides to change pallets due to applied + // stylesheets + // setStyleSheet("QLineEdit { " + // " border: 2px solid " + + // qApp->palette().color(QPalette::Midlight).name() + + // "; " + // " border-radius: 6px; " + // " padding: 8px 12px; " + // " font-size: 14px; " + // "} " + // "QLineEdit:focus { " + // " border: 2px solid " + + // COLOR_ACCENT_BLUE.name() + + // "; " + // " outline: none; " + // "}"); } \ No newline at end of file diff --git a/src/zloadingwidget.cpp b/src/zloadingwidget.cpp index fdbfd04..3925032 100644 --- a/src/zloadingwidget.cpp +++ b/src/zloadingwidget.cpp @@ -27,34 +27,36 @@ ZLoadingWidget::ZLoadingWidget(bool start, QWidget *parent) void ZLoadingWidget::setupContentWidget(QWidget *contentWidget) { - addWidget(contentWidget); // Content widget at index 1 + m_contentWidget = contentWidget; + addWidget(m_contentWidget); } void ZLoadingWidget::setupContentWidget(QLayout *contentLayout) { - QWidget *contentWidget = new QWidget(); - contentWidget->setLayout(contentLayout); + m_contentWidget = new QWidget(); + m_contentWidget->setLayout(contentLayout); - addWidget(contentWidget); // Content widget at index 1 + addWidget(m_contentWidget); } void ZLoadingWidget::setupErrorWidget(QWidget *errorWidget) { - addWidget(errorWidget); // Error widget at index 2 + m_errorWidget = errorWidget; + addWidget(m_errorWidget); } void ZLoadingWidget::setupErrorWidget(QLayout *errorLayout) { - QWidget *errorWidget = new QWidget(); - errorWidget->setLayout(errorLayout); + m_errorWidget = new QWidget(); + m_errorWidget->setLayout(errorLayout); - addWidget(errorWidget); // Error widget at index 2 + addWidget(m_errorWidget); } void ZLoadingWidget::setupErrorWidget(const QString &errorMessage) { - QWidget *errorWidget = new QWidget(); - QVBoxLayout *errorLayout = new QVBoxLayout(errorWidget); + m_errorWidget = new QWidget(); + QVBoxLayout *errorLayout = new QVBoxLayout(m_errorWidget); errorLayout->setAlignment(Qt::AlignCenter); QLabel *errorLabel = new QLabel(errorMessage); @@ -62,7 +64,7 @@ void ZLoadingWidget::setupErrorWidget(const QString &errorMessage) errorLabel->setStyleSheet("QLabel { color: red; }"); errorLayout->addWidget(errorLabel); - addWidget(errorWidget); // Error widget at index 2 + addWidget(m_errorWidget); } void ZLoadingWidget::setupAditionalWidget(QWidget *customWidget) @@ -92,8 +94,9 @@ void ZLoadingWidget::stop(bool showContent) void ZLoadingWidget::showError() { m_loadingIndicator->stop(); - // FIXME: dont use hardcoded index - setCurrentIndex(2); + if (m_errorWidget) { + setCurrentWidget(m_errorWidget); + } } void ZLoadingWidget::showLoading() diff --git a/src/zloadingwidget.h b/src/zloadingwidget.h index 9ddabf4..f046715 100644 --- a/src/zloadingwidget.h +++ b/src/zloadingwidget.h @@ -23,6 +23,8 @@ public: private: class QProcessIndicator *m_loadingIndicator = nullptr; + QWidget *m_contentWidget = nullptr; + QWidget *m_errorWidget = nullptr; signals: }; diff --git a/src/ztabwidget.cpp b/src/ztabwidget.cpp index dddacc5..66ca6a2 100644 --- a/src/ztabwidget.cpp +++ b/src/ztabwidget.cpp @@ -18,18 +18,51 @@ */ #include "ztabwidget.h" +#include "iDescriptor-ui.h" #include #include #include #include +#include +#include #include #include +QRect gliderEndRectForTab(const ZTab *tab) +{ + if (!tab) + return {}; + + // Approximate "title center" using the push-button contents rect center. + QStyleOptionButton opt; + opt.initFrom(tab); + opt.text = tab->text(); + opt.icon = tab->icon(); + opt.iconSize = tab->iconSize(); + + QRect contents = + tab->style()->subElementRect(QStyle::SE_PushButtonContents, &opt, tab); + if (!contents.isValid()) + contents = tab->rect(); + + const int centerX = tab->mapToParent(contents.center()).x(); + + // Half-width glider, clamped so it never exceeds contents width and never + // gets too tiny. + const int rawW = tab->width() / 1.5; + const int maxW = qMax(1, contents.width()); + const int w = qBound(12, qMin(rawW, maxW), tab->width()); + + const int x = centerX - (w / 2); + const int y = tab->pos().y() + tab->height() - 2; + return QRect(x, y, w, 2); +} + ZTab::ZTab(const QString &text, QWidget *parent) : QPushButton(text, parent) { setCheckable(true); #ifndef WIN32 - setFixedHeight(50); + setFixedHeight(40); #else setFixedHeight(40); #endif @@ -40,13 +73,13 @@ ZTab::ZTab(const QString &text, QWidget *parent) : QPushButton(text, parent) ZTabWidget::ZTabWidget(QWidget *parent) : QWidget(parent), m_currentIndex(0) { m_mainLayout = new QVBoxLayout(this); - m_mainLayout->setContentsMargins(0, 0, 0, 0); + m_mainLayout->setContentsMargins(10, 0, 10, 0); m_mainLayout->setSpacing(0); // Create tab bar container m_tabBar = new QWidget(); #ifndef WIN32 - m_tabBar->setFixedHeight(50); + m_tabBar->setFixedHeight(40); #else m_tabBar->setFixedHeight(40); #endif @@ -80,10 +113,17 @@ ZTabWidget::ZTabWidget(QWidget *parent) : QWidget(parent), m_currentIndex(0) void ZTabWidget::setupGlider() { m_glider = new QWidget(m_tabBar); - m_glider->setStyleSheet("QWidget {" - " background-color: #2b5693;" - " border-radius: 1px;" - "}"); + m_glider->setStyleSheet(QString("QWidget {" + " background-color: %1;" + " border-radius: %2px;" + "}") + .arg(COLOR_ACCENT_BLUE.name()) +#ifndef WIN32 + .arg(6) +#else + .arg(2) +#endif + ); m_glider->hide(); // Hide initially until tabs are added } @@ -111,6 +151,9 @@ void ZTabWidget::setCurrentIndex(int index) m_currentIndex = index; m_tabs[index]->setChecked(true); m_stackedWidget->setCurrentIndex(index); +#ifdef WIN32 + animateWidget(m_stackedWidget->currentWidget()); +#endif updateTabStyles(); animateGlider(index); @@ -119,22 +162,30 @@ void ZTabWidget::setCurrentIndex(int index) void ZTabWidget::finalizeStyles() { + if (m_tabs.isEmpty()) + return; + ZTab *tab = m_tabs[0]; if (tab) { tab->setChecked(true); + QTimer::singleShot(0, [this, tab]() { - if (tab) { - m_glider->setFixedSize(tab->size().width(), 2); - int targetX = tab->pos().x(); - int targetY = tab->pos().y() + tab->size().height() - 2; - m_glider->move(targetX, targetY); - m_gliderAnimation = new QPropertyAnimation(m_glider, "pos"); - m_gliderAnimation->setDuration(250); - m_gliderAnimation->setEasingCurve(QEasingCurve::OutCubic); - m_glider->show(); + if (!tab) + return; + + const QRect endRect = gliderEndRectForTab(tab); + + if (m_gliderAnimation) { + m_gliderAnimation->stop(); + delete m_gliderAnimation; + m_gliderAnimation = nullptr; } + + m_glider->setGeometry(endRect); + m_glider->show(); }); } + updateTabStyles(); } @@ -160,7 +211,7 @@ void ZTabWidget::onTabClicked() } } -void ZTabWidget::animateGlider(int index) +void ZTabWidget::animateGlider(int index, bool onResize) { if (index < 0 || index >= m_tabs.count()) return; @@ -169,59 +220,144 @@ void ZTabWidget::animateGlider(int index) if (!targetTab) return; - // Get the actual position and size of the target tab - QPoint targetTabPos = targetTab->pos(); - QSize targetTabSize = targetTab->size(); + const QRect endRect = gliderEndRectForTab(targetTab); - // Set glider width to match tab width and height to 2px for bottom border - m_glider->setFixedSize(targetTabSize.width(), 2); +#ifdef WIN32 + if (onResize || !m_glider->isVisible()) { + if (m_gliderAnimation) { + m_gliderAnimation->stop(); + delete m_gliderAnimation; + m_gliderAnimation = nullptr; + } + m_glider->setGeometry(endRect); + m_glider->show(); + return; + } - // Position glider at the bottom of the target tab - int targetX = targetTabPos.x(); - int targetY = - // targetTabPos.y() + targetTabSize.height() + 6; // Position at bottom - targetTabPos.y() + targetTabSize.height() - 2; // Position at bottom + const QRect startRect = m_glider->geometry(); - if (m_gliderAnimation == nullptr) + const int left = qMin(startRect.left(), endRect.left()); + const int right = qMax(startRect.right(), endRect.right()); + const QRect stretchRect(left, endRect.y(), (right - left + 1), 2); + + if (m_gliderAnimation) { + m_gliderAnimation->stop(); + delete m_gliderAnimation; + m_gliderAnimation = nullptr; + } + + auto *group = new QSequentialAnimationGroup(this); + + auto *expandAnim = new QPropertyAnimation(m_glider, "geometry"); + expandAnim->setDuration(130); + expandAnim->setStartValue(startRect); + expandAnim->setEndValue(stretchRect); + expandAnim->setEasingCurve(QEasingCurve::OutCubic); + + auto *settleAnim = new QPropertyAnimation(m_glider, "geometry"); + settleAnim->setDuration(190); + settleAnim->setStartValue(stretchRect); + settleAnim->setEndValue(endRect); + settleAnim->setEasingCurve(QEasingCurve::OutCubic); + + group->addAnimation(expandAnim); + group->addAnimation(settleAnim); + + m_gliderAnimation = group; + group->start(); +#else + if (m_gliderAnimation == nullptr) { + m_gliderAnimation = new QPropertyAnimation(m_glider, "pos", this); + static_cast(m_gliderAnimation)->setDuration(250); + static_cast(m_gliderAnimation) + ->setEasingCurve(QEasingCurve::OutCubic); + } + + m_glider->setFixedSize(endRect.width(), 2); + m_gliderAnimation->stop(); + static_cast(m_gliderAnimation) + ->setStartValue(m_glider->pos()); + static_cast(m_gliderAnimation) + ->setEndValue(endRect.topLeft()); + m_gliderAnimation->start(); +#endif +} + +void ZTabWidget::animateWidget(QWidget *widget) +{ +#ifdef WIN32 + if (!widget) return; - m_gliderAnimation->stop(); - m_gliderAnimation->setStartValue(m_glider->pos()); - m_gliderAnimation->setEndValue(QPoint(targetX, targetY)); - m_gliderAnimation->start(); + // FIXME: doesn't work on Tool tab because we are using opacity in + // stylesheet + QGraphicsOpacityEffect *opacityEffect = + qobject_cast(widget->graphicsEffect()); + if (!opacityEffect) { + opacityEffect = new QGraphicsOpacityEffect(widget); + widget->setGraphicsEffect(opacityEffect); + } + + QPropertyAnimation *opacityAnim = + new QPropertyAnimation(opacityEffect, "opacity", this); + opacityAnim->setDuration(350); + opacityAnim->setStartValue(0.0); + opacityAnim->setEndValue(1.0); + opacityAnim->setEasingCurve(QEasingCurve::OutCubic); + opacityAnim->start(QAbstractAnimation::DeleteWhenStopped); + + QPropertyAnimation *posAnim = new QPropertyAnimation(widget, "pos", this); + posAnim->setDuration(350); + posAnim->setStartValue(QPoint(widget->pos().x(), widget->pos().y() + 20)); + posAnim->setEndValue(widget->pos()); + posAnim->setEasingCurve(QEasingCurve::OutCubic); + posAnim->start(QAbstractAnimation::DeleteWhenStopped); +#else + Q_UNUSED(widget); +#endif } void ZTabWidget::updateTabStyles() { + const QString accentColor = + +#ifdef WIN32 + COLOR_ACCENT_BLUE.name(); +#else + "#185ee0"; +#endif + for (int i = 0; i < m_tabs.count(); ++i) { ZTab *tab = m_tabs[i]; if (tab->isChecked()) { - tab->setStyleSheet("ZTab {" - " color: #185ee0;" - // " color: #d7e1f4ff;" - " font-weight: 500;" - " font-size: 20px;" - " border: none;" - " outline: none;" - " background-color: transparent;" - "}" - "ZTab:hover {" - " background-color: transparent;" - "}"); + tab->setStyleSheet(QString("ZTab {" + " color: %1;" + // " color: #d7e1f4ff;" + " font-weight: 700;" + " font-size: 20px;" + " border: none;" + " outline: none;" + " background-color: transparent;" + "}" + "ZTab:hover {" + " background-color: transparent;" + "}") + .arg(accentColor)); } else { - tab->setStyleSheet("ZTab {" - " color: #666;" - // " color: #2b5693;" - " font-weight: 500;" - " font-size: 20px;" - " border: none;" - " outline: none;" - " background-color: transparent;" - "}" - "ZTab:hover {" - " color: #185ee0;" - " background-color: transparent;" - "}"); + tab->setStyleSheet(QString("ZTab {" + " color: #666;" + // " color: #2b5693;" + " font-weight: 700;" + " font-size: 20px;" + " border: none;" + " outline: none;" + " background-color: transparent;" + "}" + "ZTab:hover {" + " color: %1;" + " background-color: transparent;" + "}") + .arg(accentColor)); } } } @@ -231,6 +367,6 @@ void ZTabWidget::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); if (m_currentIndex >= 0 && m_currentIndex < m_tabs.count()) { - animateGlider(m_currentIndex); + animateGlider(m_currentIndex, true); } -} \ No newline at end of file +} diff --git a/src/ztabwidget.h b/src/ztabwidget.h index 0ecab38..081aa5a 100644 --- a/src/ztabwidget.h +++ b/src/ztabwidget.h @@ -67,13 +67,14 @@ private: QStackedWidget *m_stackedWidget; QButtonGroup *m_buttonGroup; QWidget *m_glider; - QPropertyAnimation *m_gliderAnimation = nullptr; + QAbstractAnimation *m_gliderAnimation = nullptr; QList m_tabs; QList m_widgets; int m_currentIndex; void setupGlider(); - void animateGlider(int index); + void animateGlider(int index, bool onResize = false); + void animateWidget(QWidget *widget); void updateTabStyles(); };