summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAxel Spoerl <axel.spoerl@qt.io>2023-05-15 17:32:28 +0200
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2023-05-21 18:36:37 +0200
commit17c589df94a2245ee92d45839c2cba73566d7310 (patch)
tree9c9c5e9366be2ed065f3e2b3cff09b40cb27fc66
parent0328e4297e339de8a2acd84979c667936f6fadf8 (diff)
Shoehorn AccentColor into QPalette and keep existing 64bit resolve mask
It is necessary to add an AccentColor role to QPalette. QPalette currently has 21 color roles and 3 color groups, which require 63 bits to resolve. The resolve mask is implemented with a qint64, which doesn't provide spare bits for another color role. The color role NoRole is used as a default value, marking that a role has not (yet) been defined. The enum value does not represent a valid brush, even though it can theoretically be stored in QPalette's shared data. This patch adds the enum value AccentColor to QPalette::ColorRole, increasing the available color roles to 22. To keep the resolve mask at 63 bits, AccentColor is mapped to NoRole in static constexpr bitPosition. As the enum range would exceed 64 bits without this tweak, 3 additional bits are substracted in the respective static assertion. With NoRole having no bit in the resolve mask, the following adaptions have been implemented: - QPalette::resolve() is adapted to explicitly ignore NoRole. - QPalette::isBrushSet() always returns false for NoRole. - tst_QPalette::setAllPossibleBrushes() to verify the latter - operator== ignores NoRole (documentation updated) AccentColor is added in tst_QPalette::roleValues and enum documentation is adapted. In QPalette's default constructor, the AccentColor brush is defaulting to the Highlight brush, it this is available. Otherwise it is made 30% darker or lighter than the Base brush, depending on dark/light mode heuristics. QPalette's data stram functions have been extended from QDataStream Version Qt_6_6. If earlier versions are de-serialised, the AccentColor defaults to Highlight. An autotest function dataStream() has been added to tst_QPalette. The QDataStream Version Qt_6_6 has been bumped to 21. tst_QDataStream has been adapted to the new version and the new color Role. Change-Id: I98bbf9de95fb83bda921e9614a0db3a3c0ebdf75 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
-rw-r--r--src/corelib/serialization/qdatastream.h2
-rw-r--r--src/gui/kernel/qpalette.cpp68
-rw-r--r--src/gui/kernel/qpalette.h4
-rw-r--r--src/gui/kernel/qplatformtheme.cpp7
-rw-r--r--tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp5
-rw-r--r--tests/auto/gui/kernel/qpalette/tst_qpalette.cpp51
6 files changed, 126 insertions, 11 deletions
diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h
index 0942c3ed1d..9e35328de4 100644
--- a/src/corelib/serialization/qdatastream.h
+++ b/src/corelib/serialization/qdatastream.h
@@ -68,7 +68,7 @@ public:
Qt_6_3 = Qt_6_0,
Qt_6_4 = Qt_6_0,
Qt_6_5 = Qt_6_0,
- Qt_6_6 = Qt_6_0,
+ Qt_6_6 = 21,
Qt_DefaultCompiledVersion = Qt_6_6
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
#error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion
diff --git a/src/gui/kernel/qpalette.cpp b/src/gui/kernel/qpalette.cpp
index 4abbcd5e65..bc5ebeb4de 100644
--- a/src/gui/kernel/qpalette.cpp
+++ b/src/gui/kernel/qpalette.cpp
@@ -16,12 +16,17 @@ static int qt_palette_count = 1;
static constexpr QPalette::ResolveMask colorRoleOffset(QPalette::ColorGroup colorGroup)
{
- return qToUnderlying(QPalette::NColorRoles) * qToUnderlying(colorGroup);
+ // Exclude NoRole; that bit is used for AccentColor
+ return (qToUnderlying(QPalette::NColorRoles) - 1) * qToUnderlying(colorGroup);
}
static constexpr QPalette::ResolveMask bitPosition(QPalette::ColorGroup colorGroup,
QPalette::ColorRole colorRole)
{
+ // Map AccentColor into NoRole for resolving purposes
+ if (colorRole == QPalette::AccentColor)
+ colorRole = QPalette::NoRole;
+
return colorRole + colorRoleOffset(colorGroup);
}
@@ -100,6 +105,24 @@ static void qt_placeholder_from_text(QPalette &pal, int alpha = 50)
}
}
+static void qt_ensure_default_accent_color(QPalette &pal)
+{
+ // have a lighter/darker factor handy, depending on dark/light heuristics
+ const int lighter = pal.base().color().lightness() > pal.text().color().lightness() ? 130 : 70;
+
+ // Act only for color groups where no accent color is set
+ for (int i = 0; i < QPalette::NColorGroups; ++i) {
+ const QPalette::ColorGroup group = static_cast<QPalette::ColorGroup>(i);
+ if (!pal.isBrushSet(group, QPalette::AccentColor)) {
+ // Default to highlight if available, otherwise use a shade of base
+ const QBrush accentBrush = pal.isBrushSet(group, QPalette::Highlight)
+ ? pal.brush(group, QPalette::Highlight)
+ : pal.brush(group, QPalette::Base).color().lighter(lighter);
+ pal.setBrush(group, QPalette::AccentColor, accentBrush);
+ }
+ }
+}
+
static void qt_palette_from_color(QPalette &pal, const QColor &button)
{
int h, s, v;
@@ -124,6 +147,7 @@ static void qt_palette_from_color(QPalette &pal, const QColor &button)
whiteBrush, buttonBrush, buttonBrush);
qt_placeholder_from_text(pal);
+ qt_ensure_default_accent_color(pal);
}
/*!
@@ -524,6 +548,13 @@ static void qt_palette_from_color(QPalette &pal, const QColor &button)
item. By default, the highlight color is
Qt::darkBlue.
+ \value AccentColor A color that typically contrasts or compliments
+ Base, Window and Button colors. It usually represents
+ the users' choice of desktop personalisation.
+ Styling of interactive components is a typical use case.
+ Unless explicitly set, it defaults to Highlight.
+ This enum value has been introduced in Qt 6.6.
+
\value HighlightedText A text color that contrasts with \c Highlight.
By default, the highlighted text color is Qt::white.
@@ -613,6 +644,7 @@ QPalette::QPalette(const QBrush &windowText, const QBrush &button,
base, window);
qt_placeholder_from_text(*this);
+ qt_ensure_default_accent_color(*this);
}
@@ -670,6 +702,7 @@ QPalette::QPalette(const QColor &button, const QColor &window)
whiteBrush, baseBrush, windowBrush);
qt_placeholder_from_text(*this);
+ qt_ensure_default_accent_color(*this);
}
/*!
@@ -837,6 +870,10 @@ void QPalette::setBrush(ColorGroup cg, ColorRole cr, const QBrush &b)
*/
bool QPalette::isBrushSet(ColorGroup cg, ColorRole cr) const
{
+ // NoRole has no resolve mask and should never be set anyway
+ if (cr == NoRole)
+ return false;
+
if (cg == Current)
cg = currentGroup;
@@ -885,8 +922,11 @@ void QPalette::detach()
Returns \c true (usually quickly) if this palette is equal to \a p;
otherwise returns \c false (slowly).
- \note The current ColorGroup is not taken into account when
- comparing palettes
+ \note The following is not taken into account when comparing palettes:
+ \list
+ \li the \c current ColorGroup
+ \li ColorRole NoRole \since 6.6
+ \endlist
\sa operator!=()
*/
@@ -896,6 +936,9 @@ bool QPalette::operator==(const QPalette &p) const
return true;
for(int grp = 0; grp < (int)NColorGroups; grp++) {
for(int role = 0; role < (int)NColorRoles; role++) {
+ // Dont't verify NoRole, because it has no resolve bit
+ if (role == NoRole)
+ continue;
if (d->data->br[grp][role] != p.d->data->br[grp][role])
return false;
}
@@ -979,6 +1022,10 @@ QPalette QPalette::resolve(const QPalette &other) const
palette.detach();
for (int role = 0; role < int(NColorRoles); ++role) {
+ // Don't resolve NoRole, its bits are needed for AccentColor (see bitPosition)
+ if (role == NoRole)
+ continue;
+
for (int grp = 0; grp < int(NColorGroups); ++grp) {
if (!(d->resolveMask & (ResolveMask(1) << bitPosition(ColorGroup(grp), ColorRole(role))))) {
palette.d->data.detach();
@@ -1054,6 +1101,9 @@ QDataStream &operator<<(QDataStream &s, const QPalette &p)
max = QPalette::AlternateBase + 1;
else if (s.version() <= QDataStream::Qt_5_11)
max = QPalette::ToolTipText + 1;
+ else if (s.version() <= QDataStream::Qt_6_5)
+ max = QPalette::PlaceholderText + 1;
+
for (int r = 0; r < max; r++)
s << p.d->data->br[grp][r];
}
@@ -1097,15 +1147,25 @@ QDataStream &operator>>(QDataStream &s, QPalette &p)
} else if (s.version() <= QDataStream::Qt_5_11) {
p = QPalette();
max = QPalette::ToolTipText + 1;
+ } else if (s.version() <= QDataStream::Qt_6_5) {
+ p = QPalette();
+ max = QPalette::PlaceholderText + 1;
}
+
QBrush tmp;
for(int grp = 0; grp < (int)QPalette::NColorGroups; ++grp) {
+ const QPalette::ColorGroup group = static_cast<QPalette::ColorGroup>(grp);
for(int role = 0; role < max; ++role) {
s >> tmp;
- p.setBrush((QPalette::ColorGroup)grp, (QPalette::ColorRole)role, tmp);
+ p.setBrush(group, (QPalette::ColorRole)role, tmp);
}
+
+ // AccentColor defaults to Highlight for stream versions that don't have it.
+ if (s.version() < QDataStream::Qt_6_6)
+ p.setBrush(group, QPalette::AccentColor, p.brush(group, QPalette::Highlight));
}
+
}
return s;
}
diff --git a/src/gui/kernel/qpalette.h b/src/gui/kernel/qpalette.h
index 0a6dc0b381..92d2502afe 100644
--- a/src/gui/kernel/qpalette.h
+++ b/src/gui/kernel/qpalette.h
@@ -55,7 +55,8 @@ public:
NoRole,
ToolTipBase, ToolTipText,
PlaceholderText,
- NColorRoles = PlaceholderText + 1,
+ AccentColor,
+ NColorRoles = AccentColor + 1,
};
Q_ENUM(ColorRole)
@@ -98,6 +99,7 @@ public:
inline const QBrush &link() const { return brush(Link); }
inline const QBrush &linkVisited() const { return brush(LinkVisited); }
inline const QBrush &placeholderText() const { return brush(PlaceholderText); }
+ inline const QBrush &accentColor() const { return brush(AccentColor); }
bool operator==(const QPalette &p) const;
inline bool operator!=(const QPalette &p) const { return !(operator==(p)); }
diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp
index 6b6eb896ed..938a0dab72 100644
--- a/src/gui/kernel/qplatformtheme.cpp
+++ b/src/gui/kernel/qplatformtheme.cpp
@@ -374,6 +374,7 @@ Q_GUI_EXPORT QPalette qt_fusionPalette()
const QColor button = backGround;
const QColor shadow = dark.darker(135);
const QColor disabledShadow = shadow.lighter(150);
+ const QColor disabledHighlight(145, 145, 145);
QColor placeholder = text;
placeholder.setAlpha(128);
@@ -392,7 +393,11 @@ Q_GUI_EXPORT QPalette qt_fusionPalette()
fusionPalette.setBrush(QPalette::Active, QPalette::Highlight, highlight);
fusionPalette.setBrush(QPalette::Inactive, QPalette::Highlight, highlight);
- fusionPalette.setBrush(QPalette::Disabled, QPalette::Highlight, QColor(145, 145, 145));
+ fusionPalette.setBrush(QPalette::Disabled, QPalette::Highlight, disabledHighlight);
+
+ fusionPalette.setBrush(QPalette::Active, QPalette::AccentColor, highlight);
+ fusionPalette.setBrush(QPalette::Inactive, QPalette::AccentColor, highlight);
+ fusionPalette.setBrush(QPalette::Disabled, QPalette::AccentColor, disabledHighlight);
fusionPalette.setBrush(QPalette::PlaceholderText, placeholder);
diff --git a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp
index a203861e30..3c9a83c5aa 100644
--- a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp
+++ b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp
@@ -295,6 +295,7 @@ static int NColorRoles[] = {
QPalette::PlaceholderText + 1, // Qt_5_12
QPalette::PlaceholderText + 1, // Qt_5_13, Qt_5_14, Qt_5_15
QPalette::PlaceholderText + 1, // Qt_6_0
+ QPalette::AccentColor + 1, // Qt_6_6
0 // add the correct value for Qt_5_14 here later
};
@@ -2392,8 +2393,8 @@ void tst_QDataStream::setVersion()
*/
// revise the test if new color roles or color groups are added
- QVERIFY(QPalette::NColorRoles == QPalette::PlaceholderText + 1);
- QCOMPARE(int(QPalette::NColorGroups), 3);
+ QCOMPARE(QPalette::NColorRoles, QPalette::AccentColor + 1);
+ QCOMPARE(static_cast<int>(QPalette::NColorGroups), 3);
QByteArray ba2;
QPalette pal1, pal2;
diff --git a/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp b/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp
index 81036bee0a..bf9799724e 100644
--- a/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp
+++ b/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp
@@ -23,6 +23,7 @@ private Q_SLOTS:
void cannotCheckIfInvalidBrushSet();
void checkIfBrushForCurrentGroupSet();
void cacheKey();
+ void dataStream();
};
void tst_QPalette::roleValues_data()
@@ -51,9 +52,10 @@ void tst_QPalette::roleValues_data()
QTest::newRow("QPalette::ToolTipBase") << int(QPalette::ToolTipBase) << 18;
QTest::newRow("QPalette::ToolTipText") << int(QPalette::ToolTipText) << 19;
QTest::newRow("QPalette::PlaceholderText") << int(QPalette::PlaceholderText) << 20;
+ QTest::newRow("QPalette::AccentColor") << int(QPalette::AccentColor) << 21;
// Change this value as you add more roles.
- QTest::newRow("QPalette::NColorRoles") << int(QPalette::NColorRoles) << 21;
+ QTest::newRow("QPalette::NColorRoles") << int(QPalette::NColorRoles) << 22;
}
void tst_QPalette::roleValues()
@@ -236,8 +238,14 @@ void tst_QPalette::setAllPossibleBrushes()
}
for (int r = 0; r < QPalette::NColorRoles; ++r) {
+ const QPalette::ColorRole role = static_cast<QPalette::ColorRole>(r);
for (int g = 0; g < QPalette::NColorGroups; ++g) {
- QVERIFY(p.isBrushSet(QPalette::ColorGroup(g), QPalette::ColorRole(r)));
+ const QPalette::ColorGroup group = static_cast<QPalette::ColorGroup>(g);
+ // NoRole has no resolve bit => isBrushSet returns false
+ if (role == QPalette::NoRole)
+ QVERIFY(!p.isBrushSet(group, role));
+ else
+ QVERIFY(p.isBrushSet(group, role));
}
}
}
@@ -341,5 +349,44 @@ void tst_QPalette::cacheKey()
loggerShallowDetach.dismiss();
}
+void tst_QPalette::dataStream()
+{
+ const QColor highlight(42, 42, 42);
+ const QColor accent(13, 13, 13);
+ QPalette palette;
+ palette.setBrush(QPalette::Highlight, highlight);
+ palette.setBrush(QPalette::AccentColor, accent);
+
+ // When saved with Qt_6_5 or earlier, AccentColor defaults to Highlight
+ {
+ QByteArray b;
+ {
+ QDataStream stream(&b, QIODevice::WriteOnly);
+ stream.setVersion(QDataStream::Qt_6_5);
+ stream << palette;
+ }
+ QPalette test;
+ QDataStream stream (&b, QIODevice::ReadOnly);
+ stream.setVersion(QDataStream::Qt_6_5);
+ stream >> test;
+ QCOMPARE(test.accentColor().color(), highlight);
+ }
+
+ // When saved with Qt_6_6 or later, AccentColor is saved explicitly
+ {
+ QByteArray b;
+ {
+ QDataStream stream(&b, QIODevice::WriteOnly);
+ stream.setVersion(QDataStream::Qt_6_6);
+ stream << palette;
+ }
+ QPalette test;
+ QDataStream stream (&b, QIODevice::ReadOnly);
+ stream.setVersion(QDataStream::Qt_6_6);
+ stream >> test;
+ QCOMPARE(test.accentColor().color(), accent);
+ }
+}
+
QTEST_MAIN(tst_QPalette)
#include "tst_qpalette.moc"