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 <zephyron@citron-emu.org>
This commit is contained in:
Zephyron
2025-07-22 16:30:47 +10:00
parent bd6dd7f0ff
commit f5bea18fd9
3 changed files with 169 additions and 3 deletions

View File

@@ -25,6 +25,14 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<!-- High DPI support: Enable automatic scaling and proper window modality -->
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
<!-- High DPI scaling attributes -->
<property name="windowTitle">
<string>citron Configuration</string>
</property>
<property name="styleSheet"> <property name="styleSheet">
<string>QDialog { <string>QDialog {
background-color: #2b2b2b; background-color: #2b2b2b;
@@ -441,6 +449,77 @@ QRadioButton::indicator:checked {
QRadioButton::indicator:hover { QRadioButton::indicator:hover {
border-color: #4a9eff; 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;
}
}
</string> </string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">

View File

@@ -43,7 +43,60 @@ QScrollArea* CreateScrollArea(QWidget* widget) {
scroll_area->setFrameShape(QFrame::NoFrame); scroll_area->setFrameShape(QFrame::NoFrame);
scroll_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); scroll_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
scroll_area->setVerticalScrollBarPolicy(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; return scroll_area;
} }
@@ -81,16 +134,28 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowSystemMenuHint |
Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint); 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); ui->setupUi(this);
// Set size policy and enable resizing // Set size policy and enable resizing
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); 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(); QScreen* screen = QApplication::primaryScreen();
if (screen) { if (screen) {
QRect screenGeometry = screen->availableGeometry(); 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<int>(screenGeometry.width() / devicePixelRatio);
int logicalHeight = static_cast<int>(screenGeometry.height() / devicePixelRatio);
// Set geometry using logical units
setGeometry(0, 0, logicalWidth, logicalHeight);
showMaximized(); // Start maximized/fullscreen showMaximized(); // Start maximized/fullscreen
} }

View File

@@ -183,6 +183,7 @@ Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#include <shellscalingapi.h>
extern "C" { extern "C" {
// tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable // tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable
// graphics // graphics
@@ -5252,8 +5253,29 @@ static void SetHighDPIAttributes() {
Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif #endif
// Enable high DPI scaling and pixmaps
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); 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[]) { int main(int argc, char* argv[]) {