From f5bea18fd98a16359bbecc3d107042a3f8e0c6a4 Mon Sep 17 00:00:00 2001 From: Zephyron Date: Tue, 22 Jul 2025 16:30:47 +1000 Subject: [PATCH] frontend: Improve High DPI support and scaling This patch enhances High DPI support across the Qt frontend with the following improvements: **Windows DPI Awareness:** - Add shellscalingapi.h include for Windows DPI functions - Implement Per Monitor DPI Awareness (Windows 8.1+) and Per Monitor v2 DPI Awareness (Windows 10+) - Use SetProcessDPIAware() and SetProcessDpiAwareness() for better multi-monitor scaling - Dynamically load shcore.dll to access modern DPI awareness APIs **Configuration Dialog Enhancements:** - Add comprehensive High DPI responsive CSS media queries for different DPI levels (192dpi, 240dpi) - Scale UI elements (buttons, comboboxes, line edits, checkboxes, radio buttons) based on screen DPI - Improve scroll area styling with proper scrollbar theming for high DPI displays - Set proper window attributes for scaling (WA_TranslucentBackground, WA_NoSystemBackground) - Calculate logical window size based on device pixel ratio for accurate scaling **UI Improvements:** - Enhanced scroll area styling with custom scrollbar appearance - Better visual feedback with hover effects on scrollbar handles - Improved spacing and sizing for high DPI displays - Set proper window modality and title for configuration dialog These changes provide better visual quality and usability on high DPI displays, particularly on Windows systems with multiple monitors or high-resolution screens. The scaling is now more accurate and consistent across different display configurations. Signed-off-by: Zephyron --- src/citron/configuration/configure.ui | 79 +++++++++++++++++++ src/citron/configuration/configure_dialog.cpp | 71 ++++++++++++++++- src/citron/main.cpp | 22 ++++++ 3 files changed, 169 insertions(+), 3 deletions(-) diff --git a/src/citron/configuration/configure.ui b/src/citron/configuration/configure.ui index fa192dc2f..b785db8e2 100644 --- a/src/citron/configuration/configure.ui +++ b/src/citron/configuration/configure.ui @@ -25,6 +25,14 @@ 0 + + + Qt::ApplicationModal + + + + citron Configuration + QDialog { background-color: #2b2b2b; @@ -441,6 +449,77 @@ QRadioButton::indicator:checked { QRadioButton::indicator:hover { border-color: #4a9eff; } + +/* High DPI specific styles */ +@media (min-resolution: 192dpi) { + QPushButton.tabButton { + padding: 12px 16px; + min-width: 90px; + max-width: 170px; + font-size: 14px; + } + + QComboBox { + min-width: 140px; + min-height: 32px; + padding: 10px 14px; + } + + QLineEdit { + min-height: 24px; + padding: 10px 14px; + } + + QPushButton { + min-height: 24px; + padding: 12px 24px; + } + + QCheckBox::indicator { + width: 20px; + height: 20px; + } + + QRadioButton::indicator { + width: 18px; + height: 18px; + } +} + +@media (min-resolution: 240dpi) { + QPushButton.tabButton { + padding: 14px 18px; + min-width: 95px; + max-width: 180px; + font-size: 16px; + } + + QComboBox { + min-width: 160px; + min-height: 36px; + padding: 12px 16px; + } + + QLineEdit { + min-height: 28px; + padding: 12px 16px; + } + + QPushButton { + min-height: 28px; + padding: 14px 28px; + } + + QCheckBox::indicator { + width: 22px; + height: 22px; + } + + QRadioButton::indicator { + width: 20px; + height: 20px; + } +} diff --git a/src/citron/configuration/configure_dialog.cpp b/src/citron/configuration/configure_dialog.cpp index 0743da933..63784d0fd 100644 --- a/src/citron/configuration/configure_dialog.cpp +++ b/src/citron/configuration/configure_dialog.cpp @@ -43,7 +43,60 @@ QScrollArea* CreateScrollArea(QWidget* widget) { scroll_area->setFrameShape(QFrame::NoFrame); scroll_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - scroll_area->setStyleSheet(QLatin1String("QScrollArea { border: none; background-color: #2b2b2b; }")); + + // High DPI support: Scroll area will inherit scaling from parent + + // Set style with high DPI aware styling + scroll_area->setStyleSheet(QLatin1String( + "QScrollArea { " + "border: none; " + "background-color: #2b2b2b; " + "}" + "QScrollArea > QWidget > QWidget { " + "background-color: #2b2b2b; " + "}" + "QScrollBar:vertical { " + "background-color: #3d3d3d; " + "width: 14px; " + "border-radius: 7px; " + "margin: 2px; " + "}" + "QScrollBar::handle:vertical { " + "background-color: #5d5d5d; " + "border-radius: 6px; " + "min-height: 30px; " + "margin: 1px; " + "}" + "QScrollBar::handle:vertical:hover { " + "background-color: #4a9eff; " + "}" + "QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { " + "border: none; " + "background: none; " + "height: 0px; " + "}" + "QScrollBar:horizontal { " + "background-color: #3d3d3d; " + "height: 14px; " + "border-radius: 7px; " + "margin: 2px; " + "}" + "QScrollBar::handle:horizontal { " + "background-color: #5d5d5d; " + "border-radius: 6px; " + "min-width: 30px; " + "margin: 1px; " + "}" + "QScrollBar::handle:horizontal:hover { " + "background-color: #4a9eff; " + "}" + "QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { " + "border: none; " + "background: none; " + "width: 0px; " + "}" + )); + return scroll_area; } @@ -81,16 +134,28 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint); + // High DPI support: Set proper attributes for scaling + setAttribute(Qt::WA_TranslucentBackground, false); + setAttribute(Qt::WA_NoSystemBackground, false); + setAttribute(Qt::WA_DontShowOnScreen, false); + ui->setupUi(this); // Set size policy and enable resizing setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - // Get screen geometry and set to fullscreen + // Get screen geometry and set to fullscreen with high DPI awareness QScreen* screen = QApplication::primaryScreen(); if (screen) { QRect screenGeometry = screen->availableGeometry(); - setGeometry(screenGeometry); + + // Calculate logical size based on device pixel ratio for high DPI support + qreal devicePixelRatio = screen->devicePixelRatio(); + int logicalWidth = static_cast(screenGeometry.width() / devicePixelRatio); + int logicalHeight = static_cast(screenGeometry.height() / devicePixelRatio); + + // Set geometry using logical units + setGeometry(0, 0, logicalWidth, logicalHeight); showMaximized(); // Start maximized/fullscreen } diff --git a/src/citron/main.cpp b/src/citron/main.cpp index c417fb96d..7c2f20214 100644 --- a/src/citron/main.cpp +++ b/src/citron/main.cpp @@ -183,6 +183,7 @@ Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); #ifdef _WIN32 #include +#include extern "C" { // tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable // graphics @@ -5252,8 +5253,29 @@ static void SetHighDPIAttributes() { Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); #endif + // Enable high DPI scaling and pixmaps QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + + // Set the DPI awareness for better scaling on Windows +#ifdef _WIN32 + // Enable Per Monitor DPI Awareness for Windows 8.1+ + SetProcessDPIAware(); + + // For Windows 10+, use Per Monitor v2 DPI Awareness + // This provides better scaling for multi-monitor setups + HMODULE shcore = LoadLibrary(L"shcore.dll"); + if (shcore) { + typedef HRESULT(WINAPI* SetProcessDpiAwarenessFunc)(int); + SetProcessDpiAwarenessFunc setProcessDpiAwareness = + (SetProcessDpiAwarenessFunc)GetProcAddress(shcore, "SetProcessDpiAwareness"); + if (setProcessDpiAwareness) { + // PROCESS_PER_MONITOR_DPI_AWARE_V2 = 2 + setProcessDpiAwareness(2); + } + FreeLibrary(shcore); + } +#endif } int main(int argc, char* argv[]) {