diff options
Diffstat (limited to 'src/gui/kernel/qpalette.cpp')
-rw-r--r-- | src/gui/kernel/qpalette.cpp | 282 |
1 files changed, 149 insertions, 133 deletions
diff --git a/src/gui/kernel/qpalette.cpp b/src/gui/kernel/qpalette.cpp index b313d545a5..256ea52f01 100644 --- a/src/gui/kernel/qpalette.cpp +++ b/src/gui/kernel/qpalette.cpp @@ -1,44 +1,7 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qpalette.h" -#include "qguiapplication.h" +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qpalette_p.h" #include "qguiapplication_p.h" #include "qdatastream.h" #include "qvariant.h" @@ -48,39 +11,61 @@ QT_BEGIN_NAMESPACE -static int qt_palette_count = 1; +static_assert(QPalettePrivate::bitPosition(QPalette::ColorGroup(QPalette::NColorGroups - 1), + QPalette::ColorRole(QPalette::NColorRoles - 1)) + < sizeof(QPalette::ResolveMask) * CHAR_BIT, + "The resolve mask type is not wide enough to fit the entire bit mask."); -static constexpr QPalette::ResolveMask colorRoleOffset(QPalette::ColorGroup colorGroup) +static QColor qt_mix_colors(QColor a, QColor b) { - return qToUnderlying(QPalette::NColorRoles) * qToUnderlying(colorGroup); + return QColor((a.red() + b.red()) / 2, (a.green() + b.green()) / 2, + (a.blue() + b.blue()) / 2, (a.alpha() + b.alpha()) / 2); } -static constexpr QPalette::ResolveMask bitPosition(QPalette::ColorGroup colorGroup, - QPalette::ColorRole colorRole) -{ - return colorRole + colorRoleOffset(colorGroup); -} +/*! + \internal -static_assert(bitPosition(QPalette::ColorGroup(QPalette::NColorGroups - 1), - QPalette::ColorRole(QPalette::NColorRoles - 1)) - < sizeof(QPalette::ResolveMask) * CHAR_BIT, - "The resolve mask type is not wide enough to fit the entire bit mask."); + Derive undefined \l PlaceholderText colors from \l Text colors. + Unless already set, PlaceholderText colors will be derived from their Text pendents. + Colors of existing PlaceHolderText brushes will not be replaced. -class QPalettePrivate + \a alpha represents the dim factor as a percentage. By default, a PlaceHolderText color + becomes a 50% more transparent version of the corresponding Text color. +*/ +static void qt_placeholder_from_text(QPalette &pal, int alpha = 50) { -public: - QPalettePrivate() : ref(1), ser_no(qt_palette_count++), detach_no(0) { } - QAtomicInt ref; - QBrush br[QPalette::NColorGroups][QPalette::NColorRoles]; - QPalette::ResolveMask resolveMask = {0}; - int ser_no; - int detach_no; -}; + if (alpha < 0 or alpha > 100) + return; -static QColor qt_mix_colors(QColor a, QColor b) + for (int cg = 0; cg < int(QPalette::NColorGroups); ++cg) { + const QPalette::ColorGroup group = QPalette::ColorGroup(cg); + + // skip if the brush has been set already + if (!pal.isBrushSet(group, QPalette::PlaceholderText)) { + QColor c = pal.color(group, QPalette::Text); + const int a = (c.alpha() * alpha) / 100; + c.setAlpha(a); + pal.setColor(group, QPalette::PlaceholderText, c); + } + } +} + +static void qt_ensure_default_accent_color(QPalette &pal) { - return QColor((a.red() + b.red()) / 2, (a.green() + b.green()) / 2, - (a.blue() + b.blue()) / 2, (a.alpha() + b.alpha()) / 2); + // 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::Accent)) { + // 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::Accent, accentBrush); + } + } } static void qt_palette_from_color(QPalette &pal, const QColor &button) @@ -105,6 +90,9 @@ static void qt_palette_from_color(QPalette &pal, const QColor &button) pal.setColorGroup(QPalette::Disabled, buttonBrushDark, buttonBrush, buttonBrushLight150, buttonBrushDark, buttonBrushDark150, buttonBrushDark, whiteBrush, buttonBrush, buttonBrush); + + qt_placeholder_from_text(pal); + qt_ensure_default_accent_color(pal); } /*! @@ -306,6 +294,15 @@ static void qt_palette_from_color(QPalette &pal, const QColor &button) */ /*! + \fn const QBrush & QPalette::accent() const + \since 6.6 + + Returns the accent brush of the current color group. + + \sa ColorRole, brush() +*/ + +/*! \fn const QBrush & QPalette::link() const Returns the unvisited link text brush of the current color group. @@ -505,6 +502,13 @@ static void qt_palette_from_color(QPalette &pal, const QColor &button) item. By default, the highlight color is Qt::darkBlue. + \value [since 6.6] Accent + A color that typically contrasts or complements + 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. + \value HighlightedText A text color that contrasts with \c Highlight. By default, the highlighted text color is Qt::white. @@ -592,6 +596,9 @@ QPalette::QPalette(const QBrush &windowText, const QBrush &button, init(); setColorGroup(All, windowText, button, light, dark, mid, text, bright_text, base, window); + + qt_placeholder_from_text(*this); + qt_ensure_default_accent_color(*this); } @@ -647,6 +654,9 @@ QPalette::QPalette(const QColor &button, const QColor &window) setColorGroup(Disabled, disabledForeground, buttonBrush, buttonBrushLight150, buttonBrushDark, buttonBrushDark150, disabledForeground, whiteBrush, baseBrush, windowBrush); + + qt_placeholder_from_text(*this); + qt_ensure_default_accent_color(*this); } /*! @@ -746,7 +756,7 @@ const QBrush &QPalette::brush(ColorGroup gr, ColorRole cr) const gr = Active; } } - return d->br[gr][cr]; + return d->data->br[gr][cr]; } /*! @@ -784,12 +794,18 @@ void QPalette::setBrush(ColorGroup cg, ColorRole cr, const QBrush &b) cg = Active; } - if (d->br[cg][cr] != b) { + const auto newResolveMask = d->resolveMask | ResolveMask(1) << QPalettePrivate::bitPosition(cg, cr); + const auto valueChanged = d->data->br[cg][cr] != b; + + if (valueChanged) { + detach(); + d->data.detach(); + d->data->br[cg][cr] = b; + } else if (d->resolveMask != newResolveMask) { detach(); - d->br[cg][cr] = b; } - d->resolveMask |= ResolveMask(1) << bitPosition(cg, cr); + d->resolveMask = newResolveMask; } /*! @@ -808,6 +824,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; @@ -821,7 +841,7 @@ bool QPalette::isBrushSet(ColorGroup cg, ColorRole cr) const return false; } - return d->resolveMask & (ResolveMask(1) << bitPosition(cg, cr)); + return d->resolveMask & (ResolveMask(1) << QPalettePrivate::bitPosition(cg, cr)); } /*! @@ -830,17 +850,14 @@ bool QPalette::isBrushSet(ColorGroup cg, ColorRole cr) const void QPalette::detach() { if (d->ref.loadRelaxed() != 1) { - QPalettePrivate *x = new QPalettePrivate; - for(int grp = 0; grp < (int)NColorGroups; grp++) { - for(int role = 0; role < (int)NColorRoles; role++) - x->br[grp][role] = d->br[grp][role]; - } + QPalettePrivate *x = new QPalettePrivate(d->data); x->resolveMask = d->resolveMask; if (!d->ref.deref()) delete d; d = x; + } else { + d->detach_no = ++QPalettePrivate::qt_palette_private_count; } - ++d->detach_no; } /*! @@ -859,18 +876,24 @@ 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!=() */ bool QPalette::operator==(const QPalette &p) const { - if (isCopyOf(p)) + if (isCopyOf(p) || d->data == p.d->data) return true; for(int grp = 0; grp < (int)NColorGroups; grp++) { for(int role = 0; role < (int)NColorRoles; role++) { - if (d->br[grp][role] != p.d->br[grp][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; } } @@ -904,7 +927,7 @@ bool QPalette::isEqual(QPalette::ColorGroup group1, QPalette::ColorGroup group2) if (group1 == group2) return true; for(int role = 0; role < (int)NColorRoles; role++) { - if (d->br[group1][role] != d->br[group2][role]) + if (d->data->br[group1][role] != d->data->br[group2][role]) return false; } return true; @@ -919,7 +942,18 @@ bool QPalette::isEqual(QPalette::ColorGroup group1, QPalette::ColorGroup group2) */ qint64 QPalette::cacheKey() const { - return (((qint64) d->ser_no) << 32) | ((qint64) (d->detach_no)); + return (((qint64) d->data->ser_no) << 32) | ((qint64) (d->detach_no)); +} + +static constexpr QPalette::ResolveMask allResolveMask() +{ + QPalette::ResolveMask mask = {0}; + for (int role = 0; role < int(QPalette::NColorRoles); ++role) { + for (int grp = 0; grp < int(QPalette::NColorGroups); ++grp) { + mask |= (QPalette::ResolveMask(1) << QPalettePrivate::bitPosition(QPalette::ColorGroup(grp), QPalette::ColorRole(role))); + } + } + return mask; } /*! @@ -931,17 +965,25 @@ QPalette QPalette::resolve(const QPalette &other) const if ((*this == other && d->resolveMask == other.d->resolveMask) || d->resolveMask == 0) { QPalette o = other; - o.d->resolveMask = d->resolveMask; + o.setResolveMask(d->resolveMask); return o; } + if (d->resolveMask == allResolveMask()) + return *this; + QPalette palette(*this); palette.detach(); for (int role = 0; role < int(NColorRoles); ++role) { + // Don't resolve NoRole, its bits are needed for Accent (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->br[grp][role] = other.d->br[grp][role]; + if (!(d->resolveMask & (ResolveMask(1) << QPalettePrivate::bitPosition(ColorGroup(grp), ColorRole(role))))) { + palette.d->data.detach(); + palette.d->data->br[grp][role] = other.d->data->br[grp][role]; } } } @@ -1004,7 +1046,7 @@ QDataStream &operator<<(QDataStream &s, const QPalette &p) if (s.version() == 1) { // Qt 1.x for (int i = 0; i < NumOldRoles; ++i) - s << p.d->br[grp][oldRoles[i]].color(); + s << p.d->data->br[grp][oldRoles[i]].color(); } else { int max = (int)QPalette::NColorRoles; if (s.version() <= QDataStream::Qt_2_1) @@ -1013,8 +1055,11 @@ 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->br[grp][r]; + s << p.d->data->br[grp][r]; } } return s; @@ -1056,15 +1101,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); } + + // Accent defaults to Highlight for stream versions that don't have it. + if (s.version() < QDataStream::Qt_6_6) + p.setBrush(group, QPalette::Accent, p.brush(group, QPalette::Highlight)); } + } return s; } @@ -1111,10 +1166,10 @@ void QPalette::setColorGroup(ColorGroup cg, const QBrush &windowText, const QBru for (int cr = Highlight; cr <= LinkVisited; ++cr) { if (cg == All) { for (int group = Active; group < NColorGroups; ++group) { - d->resolveMask &= ~(ResolveMask(1) << bitPosition(ColorGroup(group), ColorRole(cr))); + d->resolveMask &= ~(ResolveMask(1) << QPalettePrivate::bitPosition(ColorGroup(group), ColorRole(cr))); } } else { - d->resolveMask &= ~(ResolveMask(1) << bitPosition(ColorGroup(cg), ColorRole(cr))); + d->resolveMask &= ~(ResolveMask(1) << QPalettePrivate::bitPosition(ColorGroup(cg), ColorRole(cr))); } } } @@ -1169,47 +1224,6 @@ void QPalette::setColorGroup(ColorGroup cg, const QBrush &foreground, const QBru setBrush(cg, ToolTipText, toolTipText); } -Q_GUI_EXPORT QPalette qt_fusionPalette() -{ - QColor backGround(239, 239, 239); - QColor light = backGround.lighter(150); - QColor mid(backGround.darker(130)); - QColor midLight = mid.lighter(110); - QColor base = Qt::white; - QColor disabledBase(backGround); - QColor dark = backGround.darker(150); - QColor darkDisabled = QColor(209, 209, 209).darker(110); - QColor text = Qt::black; - QColor hightlightedText = Qt::white; - QColor disabledText = QColor(190, 190, 190); - QColor button = backGround; - QColor shadow = dark.darker(135); - QColor disabledShadow = shadow.lighter(150); - QColor placeholder = text; - placeholder.setAlpha(128); - - QPalette fusionPalette(Qt::black,backGround,light,dark,mid,text,base); - fusionPalette.setBrush(QPalette::Midlight, midLight); - fusionPalette.setBrush(QPalette::Button, button); - fusionPalette.setBrush(QPalette::Shadow, shadow); - fusionPalette.setBrush(QPalette::HighlightedText, hightlightedText); - - fusionPalette.setBrush(QPalette::Disabled, QPalette::Text, disabledText); - fusionPalette.setBrush(QPalette::Disabled, QPalette::WindowText, disabledText); - fusionPalette.setBrush(QPalette::Disabled, QPalette::ButtonText, disabledText); - fusionPalette.setBrush(QPalette::Disabled, QPalette::Base, disabledBase); - fusionPalette.setBrush(QPalette::Disabled, QPalette::Dark, darkDisabled); - fusionPalette.setBrush(QPalette::Disabled, QPalette::Shadow, disabledShadow); - - fusionPalette.setBrush(QPalette::Active, QPalette::Highlight, QColor(48, 140, 198)); - fusionPalette.setBrush(QPalette::Inactive, QPalette::Highlight, QColor(48, 140, 198)); - fusionPalette.setBrush(QPalette::Disabled, QPalette::Highlight, QColor(145, 145, 145)); - - fusionPalette.setBrush(QPalette::PlaceholderText, placeholder); - - return fusionPalette; -} - #ifndef QT_NO_DEBUG_STREAM static QString groupsToString(const QPalette &p, QPalette::ColorRole cr) { @@ -1221,8 +1235,8 @@ static QString groupsToString(const QPalette &p, QPalette::ColorRole cr) if (p.isBrushSet(cg, cr)) { const auto &color = p.color(cg, cr); - groupString += QString::fromUtf8(groupEnum.valueToKey(cg)) + QLatin1Char(':') + - color.name(QColor::HexArgb) + QLatin1Char(','); + groupString += QString::fromUtf8(groupEnum.valueToKey(cg)) + u':' + + color.name(QColor::HexArgb) + u','; } } groupString.chop(1); @@ -1266,3 +1280,5 @@ QDebug operator<<(QDebug dbg, const QPalette &p) #endif QT_END_NAMESPACE + +#include "moc_qpalette.cpp" |