Windows QPA: Provide an experimental palette for dark mode

Provide a simple palette for dark mode, implementing
dark mode support level 2.

Task-number: QTBUG-72028
Change-Id: I6f71870b251ccb7da30c01abb22c224e600f2b27
Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
This commit is contained in:
Friedemann Kleint 2019-09-25 15:04:36 +02:00
parent eb26563dd5
commit 859307d7a5
6 changed files with 118 additions and 27 deletions

View File

@ -1226,6 +1226,11 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
for (QWindowsWindow *w : d->m_windows)
w->setDarkBorder(QWindowsContextPrivate::m_darkMode);
}
if ((options & QWindowsIntegration::DarkModeStyle) != 0) {
QWindowsTheme::instance()->refresh();
for (QWindowsWindow *w : d->m_windows)
QWindowSystemInterface::handleThemeChange(w->window());
}
}
return d->m_screenManager.handleScreenChanges();
}

View File

@ -243,6 +243,15 @@ static bool shGetFileInfoBackground(const QString &fileName, DWORD attributes,
return result;
}
// Dark Mode constants
enum DarkModeColors : QRgb {
darkModeBtnHighlightRgb = 0xc0c0c0,
darkModeBtnShadowRgb = 0x808080,
darkModeHighlightRgb = 0x0055ff, // deviating from 0x800080
darkModeMenuHighlightRgb = darkModeHighlightRgb,
darkModeGrayTextRgb = 0x00ff00
};
// from QStyle::standardPalette
static inline QPalette standardPalette()
{
@ -260,23 +269,55 @@ static inline QPalette standardPalette()
return palette;
}
static inline QPalette systemPalette()
static void populateLightSystemBasePalette(QPalette &result)
{
QPalette result = standardPalette();
result.setColor(QPalette::WindowText, getSysColor(COLOR_WINDOWTEXT));
result.setColor(QPalette::Button, getSysColor(COLOR_BTNFACE));
result.setColor(QPalette::Light, getSysColor(COLOR_BTNHIGHLIGHT));
const QColor btnFace = getSysColor(COLOR_BTNFACE);
result.setColor(QPalette::Button, btnFace);
const QColor btnHighlight = getSysColor(COLOR_BTNHIGHLIGHT);
result.setColor(QPalette::Light, btnHighlight);
result.setColor(QPalette::Dark, getSysColor(COLOR_BTNSHADOW));
result.setColor(QPalette::Mid, result.button().color().darker(150));
result.setColor(QPalette::Text, getSysColor(COLOR_WINDOWTEXT));
result.setColor(QPalette::BrightText, getSysColor(COLOR_BTNHIGHLIGHT));
result.setColor(QPalette::BrightText, btnHighlight);
result.setColor(QPalette::Base, getSysColor(COLOR_WINDOW));
result.setColor(QPalette::Window, getSysColor(COLOR_BTNFACE));
result.setColor(QPalette::Window, btnFace);
result.setColor(QPalette::ButtonText, getSysColor(COLOR_BTNTEXT));
result.setColor(QPalette::Midlight, getSysColor(COLOR_3DLIGHT));
result.setColor(QPalette::Shadow, getSysColor(COLOR_3DDKSHADOW));
result.setColor(QPalette::Highlight, getSysColor(COLOR_HIGHLIGHT));
result.setColor(QPalette::HighlightedText, getSysColor(COLOR_HIGHLIGHTTEXT));
}
static void populateDarkSystemBasePalette(QPalette &result)
{
const QColor darkModeWindowText = Qt::white;
result.setColor(QPalette::WindowText, darkModeWindowText);
const QColor darkModebtnFace = Qt::black;
result.setColor(QPalette::Button, darkModebtnFace);
const QColor btnHighlight = QColor(darkModeBtnHighlightRgb);
result.setColor(QPalette::Light, btnHighlight);
result.setColor(QPalette::Dark, QColor(darkModeBtnShadowRgb));
result.setColor(QPalette::Mid, result.button().color().darker(150));
result.setColor(QPalette::Text, darkModeWindowText);
result.setColor(QPalette::BrightText, btnHighlight);
result.setColor(QPalette::Base, darkModebtnFace);
result.setColor(QPalette::Window, darkModebtnFace);
result.setColor(QPalette::ButtonText, darkModeWindowText);
result.setColor(QPalette::Midlight, darkModeWindowText);
result.setColor(QPalette::Shadow, darkModeWindowText);
result.setColor(QPalette::Highlight, QColor(darkModeHighlightRgb));
result.setColor(QPalette::HighlightedText, darkModeWindowText);
}
static QPalette systemPalette(bool light)
{
QPalette result = standardPalette();
if (light)
populateLightSystemBasePalette(result);
else
populateDarkSystemBasePalette(result);
result.setColor(QPalette::Link, Qt::blue);
result.setColor(QPalette::LinkVisited, Qt::magenta);
result.setColor(QPalette::Inactive, QPalette::Button, result.button().color());
@ -302,19 +343,19 @@ static inline QPalette systemPalette()
result.setColor(QPalette::Disabled, QPalette::Text, disabled);
result.setColor(QPalette::Disabled, QPalette::ButtonText, disabled);
result.setColor(QPalette::Disabled, QPalette::Highlight,
getSysColor(COLOR_HIGHLIGHT));
light ? getSysColor(COLOR_HIGHLIGHT) : QColor(darkModeHighlightRgb));
result.setColor(QPalette::Disabled, QPalette::HighlightedText,
getSysColor(COLOR_HIGHLIGHTTEXT));
light ? getSysColor(COLOR_HIGHLIGHTTEXT) : QColor(Qt::white));
result.setColor(QPalette::Disabled, QPalette::Base,
result.window().color());
return result;
}
static inline QPalette toolTipPalette(const QPalette &systemPalette)
static inline QPalette toolTipPalette(const QPalette &systemPalette, bool light)
{
QPalette result(systemPalette);
const QColor tipBgColor(getSysColor(COLOR_INFOBK));
const QColor tipTextColor(getSysColor(COLOR_INFOTEXT));
const QColor tipBgColor = light ? getSysColor(COLOR_INFOBK) : QColor(Qt::black);
const QColor tipTextColor = light ? getSysColor(COLOR_INFOTEXT) : QColor(Qt::white);
result.setColor(QPalette::All, QPalette::Button, tipBgColor);
result.setColor(QPalette::All, QPalette::Window, tipBgColor);
@ -339,12 +380,13 @@ static inline QPalette toolTipPalette(const QPalette &systemPalette)
return result;
}
static inline QPalette menuPalette(const QPalette &systemPalette)
static inline QPalette menuPalette(const QPalette &systemPalette, bool light)
{
QPalette result(systemPalette);
const QColor menuColor(getSysColor(COLOR_MENU));
const QColor menuTextColor(getSysColor(COLOR_MENUTEXT));
const QColor disabled(getSysColor(COLOR_GRAYTEXT));
const QColor menuColor = light ? getSysColor(COLOR_MENU) : QColor(Qt::black);
const QColor menuTextColor = light ? getSysColor(COLOR_MENUTEXT) : QColor(Qt::white);
const QColor disabled = light
? getSysColor(COLOR_GRAYTEXT) : QColor(darkModeGrayTextRgb);
// we might need a special color group for the result.
result.setColor(QPalette::Active, QPalette::Button, menuColor);
result.setColor(QPalette::Active, QPalette::Text, menuTextColor);
@ -353,8 +395,10 @@ static inline QPalette menuPalette(const QPalette &systemPalette)
result.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
result.setColor(QPalette::Disabled, QPalette::Text, disabled);
const bool isFlat = booleanSystemParametersInfo(SPI_GETFLATMENU, false);
result.setColor(QPalette::Disabled, QPalette::Highlight,
getSysColor(isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT));
const QColor highlightColor = light
? (getSysColor(isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT))
: QColor(darkModeMenuHighlightRgb);
result.setColor(QPalette::Disabled, QPalette::Highlight, highlightColor);
result.setColor(QPalette::Disabled, QPalette::HighlightedText, disabled);
result.setColor(QPalette::Disabled, QPalette::Button,
result.color(QPalette::Active, QPalette::Button));
@ -375,12 +419,12 @@ static inline QPalette menuPalette(const QPalette &systemPalette)
return result;
}
static inline QPalette *menuBarPalette(const QPalette &menuPalette)
static inline QPalette *menuBarPalette(const QPalette &menuPalette, bool light)
{
QPalette *result = nullptr;
if (booleanSystemParametersInfo(SPI_GETFLATMENU, false)) {
result = new QPalette(menuPalette);
const QColor menubar(getSysColor(COLOR_MENUBAR));
const QColor menubar(light ? getSysColor(COLOR_MENUBAR) : QColor(Qt::black));
result->setColor(QPalette::Active, QPalette::Button, menubar);
result->setColor(QPalette::Disabled, QPalette::Button, menubar);
result->setColor(QPalette::Inactive, QPalette::Button, menubar);
@ -487,10 +531,26 @@ void QWindowsTheme::refreshPalettes()
if (!QGuiApplication::desktopSettingsAware())
return;
m_palettes[SystemPalette] = new QPalette(systemPalette());
m_palettes[ToolTipPalette] = new QPalette(toolTipPalette(*m_palettes[SystemPalette]));
m_palettes[MenuPalette] = new QPalette(menuPalette(*m_palettes[SystemPalette]));
m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette]);
const bool light =
!QWindowsContext::isDarkMode()
|| (QWindowsIntegration::instance()->options() & QWindowsIntegration::DarkModeStyle) == 0;
m_palettes[SystemPalette] = new QPalette(systemPalette(light));
m_palettes[ToolTipPalette] = new QPalette(toolTipPalette(*m_palettes[SystemPalette], light));
m_palettes[MenuPalette] = new QPalette(menuPalette(*m_palettes[SystemPalette], light));
m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette], light);
if (!light) {
m_palettes[ButtonPalette] = new QPalette(*m_palettes[SystemPalette]);
m_palettes[ButtonPalette]->setColor(QPalette::Button, QColor(0x666666u));
const QColor checkBoxBlue(0x0078d7u);
const QColor white(Qt::white);
m_palettes[CheckBoxPalette] = new QPalette(*m_palettes[SystemPalette]);
m_palettes[CheckBoxPalette]->setColor(QPalette::Window, checkBoxBlue);
m_palettes[CheckBoxPalette]->setColor(QPalette::Base, checkBoxBlue);
m_palettes[CheckBoxPalette]->setColor(QPalette::Button, checkBoxBlue);
m_palettes[CheckBoxPalette]->setColor(QPalette::ButtonText, white);
m_palettes[RadioButtonPalette] = new QPalette(*m_palettes[CheckBoxPalette]);
}
}
void QWindowsTheme::clearFonts()
@ -499,6 +559,12 @@ void QWindowsTheme::clearFonts()
std::fill(m_fonts, m_fonts + NFonts, nullptr);
}
void QWindowsTheme::refresh()
{
refreshPalettes();
refreshFonts();
}
void QWindowsTheme::refreshFonts()
{
clearFonts();

View File

@ -88,11 +88,11 @@ public:
static bool queryHighContrast();
void refreshFonts();
void refresh();
static const char *name;
private:
void refresh() { refreshPalettes(); refreshFonts(); }
void clearPalettes();
void refreshPalettes();
void clearFonts();

View File

@ -225,9 +225,11 @@ static HRGN qt_hrgn_from_qregion(const QRegion &region)
*/
bool QWindowsXPStylePrivate::useXP(bool update)
{
if (!update)
return use_xp;
return use_xp = IsThemeActive() && (IsAppThemed() || !QCoreApplication::instance());
if (update) {
use_xp = IsThemeActive() && (IsAppThemed() || !QCoreApplication::instance())
&& !QWindowsStylePrivate::isDarkMode();
}
return use_xp;
}
/* \internal

View File

@ -84,6 +84,7 @@
#include <qpa/qplatformscreen.h>
#include <private/qguiapplication_p.h>
#include <private/qhighdpiscaling_p.h>
#include <qpa/qplatformnativeinterface.h>
#include <private/qwidget_p.h>
#include <private/qstylehelper_p.h>
@ -127,6 +128,22 @@ qreal QWindowsStylePrivate::appDevicePixelRatio()
return qApp->devicePixelRatio();
}
bool QWindowsStylePrivate::isDarkMode()
{
bool result = false;
#ifdef Q_OS_WIN
// Windows only: Return whether dark mode style support is desired and
// dark mode is in effect.
if (auto ni = QGuiApplication::platformNativeInterface()) {
const QVariant darkModeStyleP = ni->property("darkModeStyle");
result = darkModeStyleP.type() == QVariant::Bool
&& darkModeStyleP.value<bool>()
&& ni->property("darkMode").value<bool>();
}
#endif
return result;
}
// Returns \c true if the toplevel parent of \a widget has seen the Alt-key
bool QWindowsStylePrivate::hasSeenAlt(const QWidget *widget) const
{

View File

@ -74,6 +74,7 @@ public:
static qreal devicePixelRatio(const QWidget *widget = nullptr)
{ return widget ? widget->devicePixelRatioF() : QWindowsStylePrivate::appDevicePixelRatio(); }
static qreal nativeMetricScaleFactor(const QWidget *widget = nullptr);
static bool isDarkMode();
bool hasSeenAlt(const QWidget *widget) const;
bool altDown() const { return alt_down; }