8#include "platformtheme.h"
9#include "basictheme_p.h"
10#include "platformpluginfactory.h"
13#include <QGuiApplication>
14#include <QPluginLoader>
19#include <QQuickWindow>
25#include <unordered_map>
47struct TypeInitializer {
57static TypeInitializer initializer;
62class PlatformThemeData :
public QObject
82 AlternateBackgroundColor,
84 ActiveBackgroundColor,
86 VisitedLinkBackgroundColor,
87 NegativeBackgroundColor,
88 NeutralBackgroundColor,
89 PositiveBackgroundColor,
98 using ColorMap = std::unordered_map<std::underlying_type<ColorRole>::type,
QColor>;
105 PlatformTheme::ColorGroup colorGroup = PlatformTheme::Active;
107 std::array<QColor, ColorRoleCount> colors;
118 using Watcher = PlatformTheme *;
123 if (
sender != owner || colorSet == set) {
127 auto oldValue = colorSet;
131 notifyWatchers<PlatformTheme::ColorSet>(
sender, oldValue, set);
134 inline void setColorGroup(PlatformTheme *
sender, PlatformTheme::ColorGroup group)
136 if (
sender != owner || colorGroup == group) {
140 auto oldValue = colorGroup;
145 notifyWatchers<PlatformTheme::ColorGroup>(
sender, oldValue, group);
148 inline void setColor(PlatformTheme *
sender, ColorRole role,
const QColor &color)
150 if (
sender != owner || colors[role] == color) {
154 auto oldValue = colors[role];
156 colors[role] = color;
157 updatePalette(palette, colors);
159 notifyWatchers<QColor>(
sender, oldValue, colors[role]);
162 inline void setDefaultFont(PlatformTheme *
sender,
const QFont &font)
164 if (
sender != owner || font == defaultFont) {
168 auto oldValue = defaultFont;
172 notifyWatchers<QFont>(
sender, oldValue, font);
175 inline void setSmallFont(PlatformTheme *
sender,
const QFont &font)
177 if (
sender != owner || font == smallFont) {
181 auto oldValue = smallFont;
185 notifyWatchers<QFont>(
sender, oldValue, smallFont);
188 inline void addChangeWatcher(PlatformTheme *
object)
193 inline void removeChangeWatcher(PlatformTheme *
object)
199 inline void notifyWatchers(PlatformTheme *
sender,
const T &oldValue,
const T &newValue)
201 for (
auto object : std::as_const(watchers)) {
202 PlatformThemeEvents::PropertyChangedEvent<T>
event(
sender, oldValue, newValue);
208 inline static void updatePalette(
QPalette &palette,
const std::array<QColor, ColorRoleCount> &colors)
210 for (std::size_t i = 0; i < colors.size(); ++i) {
211 setPaletteColor(palette, ColorRole(i), colors.at(i));
216 inline static void updatePalette(
QPalette &palette,
const ColorMap &colors)
218 for (
auto entry : colors) {
219 setPaletteColor(palette, ColorRole(entry.first), entry.second);
223 inline static void setPaletteColor(
QPalette &palette, ColorRole role,
const QColor &color)
231 case BackgroundColor:
236 case AlternateBackgroundColor:
242 case HighlightedTextColor:
248 case VisitedLinkColor:
258class PlatformThemePrivate
261 PlatformThemePrivate()
263 , supportsIconColoring(false)
264 , pendingColorChange(false)
265 , pendingChildUpdate(false)
266 , useAlternateBackgroundColor(false)
267 , colorSet(PlatformTheme::
Window)
268 , colorGroup(PlatformTheme::Active)
272 inline QColor color(
const PlatformTheme *theme, PlatformThemeData::ColorRole color)
const
278 QColor value = data->colors.at(color);
280 if (data->owner != theme && localOverrides) {
281 auto itr = localOverrides->find(color);
282 if (itr != localOverrides->end()) {
290 inline void setColor(PlatformTheme *theme, PlatformThemeData::ColorRole color,
const QColor &value)
292 if (!localOverrides) {
293 localOverrides = std::make_unique<PlatformThemeData::ColorMap>();
298 auto itr = localOverrides->find(color);
299 if (itr != localOverrides->end()) {
300 PlatformThemeChangeTracker tracker(theme, PlatformThemeChangeTracker::PropertyChange::Color);
301 localOverrides->erase(itr);
315 auto itr = localOverrides->find(color);
316 if (itr != localOverrides->end() && itr->second == value && (data && data->owner != theme)) {
320 PlatformThemeChangeTracker tracker(theme, PlatformThemeChangeTracker::PropertyChange::Color);
322 (*localOverrides)[color] = value;
325 data->setColor(theme, color, value);
329 inline void setDataColor(PlatformTheme *theme, PlatformThemeData::ColorRole color,
const QColor &value)
335 if (localOverrides) {
336 auto itr = localOverrides->find(color);
337 if (itr != localOverrides->end()) {
342 PlatformThemeChangeTracker tracker(theme, PlatformThemeChangeTracker::PropertyChange::Color);
345 data->setColor(theme, color, value);
359 std::shared_ptr<PlatformThemeData> data;
362 std::unique_ptr<PlatformThemeData::ColorMap> localOverrides;
365 bool supportsIconColoring : 1;
366 bool pendingColorChange : 1;
367 bool pendingChildUpdate : 1;
368 bool useAlternateBackgroundColor : 1;
374 uint8_t colorSet : 4;
375 uint8_t colorGroup : 4;
379 static_assert(PlatformTheme::ColorGroupCount <= 16,
"PlatformTheme::ColorGroup contains more elements than can be stored in PlatformThemePrivate");
380 static_assert(PlatformTheme::ColorSetCount <= 16,
"PlatformTheme::ColorSet contains more elements than can be stored in PlatformThemePrivate");
382 inline static PlatformPluginFactory *s_pluginFactory =
nullptr;
385PlatformTheme::PlatformTheme(
QObject *parent)
387 , d(new PlatformThemePrivate)
389 if (
QQuickItem *item = qobject_cast<QQuickItem *>(parent)) {
406PlatformTheme::~PlatformTheme()
409 d->data->removeChangeWatcher(
this);
415void PlatformTheme::setColorSet(PlatformTheme::ColorSet colorSet)
417 PlatformThemeChangeTracker tracker(
this, PlatformThemeChangeTracker::PropertyChange::ColorSet);
418 d->colorSet = colorSet;
421 d->data->setColorSet(
this, colorSet);
425PlatformTheme::ColorSet PlatformTheme::colorSet()
const
427 return d->data ? d->data->colorSet :
Window;
430void PlatformTheme::setColorGroup(PlatformTheme::ColorGroup colorGroup)
432 PlatformThemeChangeTracker tracker(
this, PlatformThemeChangeTracker::PropertyChange::ColorGroup);
433 d->colorGroup = colorGroup;
436 d->data->setColorGroup(
this, colorGroup);
440PlatformTheme::ColorGroup PlatformTheme::colorGroup()
const
442 return d->data ? d->data->colorGroup : Active;
445bool PlatformTheme::inherit()
const
450void PlatformTheme::setInherit(
bool inherit)
452 if (inherit == d->inherit) {
456 d->inherit = inherit;
459 Q_EMIT inheritChanged(inherit);
462QColor PlatformTheme::textColor()
const
464 return d->color(
this, PlatformThemeData::TextColor);
467QColor PlatformTheme::disabledTextColor()
const
469 return d->color(
this, PlatformThemeData::DisabledTextColor);
472QColor PlatformTheme::highlightColor()
const
474 return d->color(
this, PlatformThemeData::HighlightColor);
477QColor PlatformTheme::highlightedTextColor()
const
479 return d->color(
this, PlatformThemeData::HighlightedTextColor);
482QColor PlatformTheme::backgroundColor()
const
484 return d->color(
this, PlatformThemeData::BackgroundColor);
487QColor PlatformTheme::alternateBackgroundColor()
const
489 return d->color(
this, PlatformThemeData::AlternateBackgroundColor);
492QColor PlatformTheme::activeTextColor()
const
494 return d->color(
this, PlatformThemeData::ActiveTextColor);
497QColor PlatformTheme::activeBackgroundColor()
const
499 return d->color(
this, PlatformThemeData::ActiveBackgroundColor);
502QColor PlatformTheme::linkColor()
const
504 return d->color(
this, PlatformThemeData::LinkColor);
507QColor PlatformTheme::linkBackgroundColor()
const
509 return d->color(
this, PlatformThemeData::LinkBackgroundColor);
512QColor PlatformTheme::visitedLinkColor()
const
514 return d->color(
this, PlatformThemeData::VisitedLinkColor);
517QColor PlatformTheme::visitedLinkBackgroundColor()
const
519 return d->color(
this, PlatformThemeData::VisitedLinkBackgroundColor);
522QColor PlatformTheme::negativeTextColor()
const
524 return d->color(
this, PlatformThemeData::NegativeTextColor);
527QColor PlatformTheme::negativeBackgroundColor()
const
529 return d->color(
this, PlatformThemeData::NegativeBackgroundColor);
532QColor PlatformTheme::neutralTextColor()
const
534 return d->color(
this, PlatformThemeData::NeutralTextColor);
537QColor PlatformTheme::neutralBackgroundColor()
const
539 return d->color(
this, PlatformThemeData::NeutralBackgroundColor);
542QColor PlatformTheme::positiveTextColor()
const
544 return d->color(
this, PlatformThemeData::PositiveTextColor);
547QColor PlatformTheme::positiveBackgroundColor()
const
549 return d->color(
this, PlatformThemeData::PositiveBackgroundColor);
552QColor PlatformTheme::focusColor()
const
554 return d->color(
this, PlatformThemeData::FocusColor);
557QColor PlatformTheme::hoverColor()
const
559 return d->color(
this, PlatformThemeData::HoverColor);
563void PlatformTheme::setTextColor(
const QColor &color)
565 d->setDataColor(
this, PlatformThemeData::TextColor, color);
568void PlatformTheme::setDisabledTextColor(
const QColor &color)
570 d->setDataColor(
this, PlatformThemeData::DisabledTextColor, color);
573void PlatformTheme::setBackgroundColor(
const QColor &color)
575 d->setDataColor(
this, PlatformThemeData::BackgroundColor, color);
578void PlatformTheme::setAlternateBackgroundColor(
const QColor &color)
580 d->setDataColor(
this, PlatformThemeData::AlternateBackgroundColor, color);
583void PlatformTheme::setHighlightColor(
const QColor &color)
585 d->setDataColor(
this, PlatformThemeData::HighlightColor, color);
588void PlatformTheme::setHighlightedTextColor(
const QColor &color)
590 d->setDataColor(
this, PlatformThemeData::HighlightedTextColor, color);
593void PlatformTheme::setActiveTextColor(
const QColor &color)
595 d->setDataColor(
this, PlatformThemeData::ActiveTextColor, color);
598void PlatformTheme::setActiveBackgroundColor(
const QColor &color)
600 d->setDataColor(
this, PlatformThemeData::ActiveBackgroundColor, color);
603void PlatformTheme::setLinkColor(
const QColor &color)
605 d->setDataColor(
this, PlatformThemeData::LinkColor, color);
608void PlatformTheme::setLinkBackgroundColor(
const QColor &color)
610 d->setDataColor(
this, PlatformThemeData::LinkBackgroundColor, color);
613void PlatformTheme::setVisitedLinkColor(
const QColor &color)
615 d->setDataColor(
this, PlatformThemeData::VisitedLinkColor, color);
618void PlatformTheme::setVisitedLinkBackgroundColor(
const QColor &color)
620 d->setDataColor(
this, PlatformThemeData::VisitedLinkBackgroundColor, color);
623void PlatformTheme::setNegativeTextColor(
const QColor &color)
625 d->setDataColor(
this, PlatformThemeData::NegativeTextColor, color);
628void PlatformTheme::setNegativeBackgroundColor(
const QColor &color)
630 d->setDataColor(
this, PlatformThemeData::NegativeBackgroundColor, color);
633void PlatformTheme::setNeutralTextColor(
const QColor &color)
635 d->setDataColor(
this, PlatformThemeData::NeutralTextColor, color);
638void PlatformTheme::setNeutralBackgroundColor(
const QColor &color)
640 d->setDataColor(
this, PlatformThemeData::NeutralBackgroundColor, color);
643void PlatformTheme::setPositiveTextColor(
const QColor &color)
645 d->setDataColor(
this, PlatformThemeData::PositiveTextColor, color);
648void PlatformTheme::setPositiveBackgroundColor(
const QColor &color)
650 d->setDataColor(
this, PlatformThemeData::PositiveBackgroundColor, color);
653void PlatformTheme::setHoverColor(
const QColor &color)
655 d->setDataColor(
this, PlatformThemeData::HoverColor, color);
658void PlatformTheme::setFocusColor(
const QColor &color)
660 d->setDataColor(
this, PlatformThemeData::FocusColor, color);
663QFont PlatformTheme::defaultFont()
const
665 return d->data ? d->data->defaultFont :
QFont{};
668void PlatformTheme::setDefaultFont(
const QFont &font)
670 PlatformThemeChangeTracker tracker(
this, PlatformThemeChangeTracker::PropertyChange::Font);
672 d->data->setDefaultFont(
this, font);
676QFont PlatformTheme::smallFont()
const
678 return d->data ? d->data->smallFont :
QFont{};
681void PlatformTheme::setSmallFont(
const QFont &font)
683 PlatformThemeChangeTracker tracker(
this, PlatformThemeChangeTracker::PropertyChange::Font);
685 d->data->setSmallFont(
this, font);
689qreal PlatformTheme::frameContrast()
const
697qreal PlatformTheme::lightFrameContrast()
const
701 return frameContrast() / 2.0;
705void PlatformTheme::setCustomTextColor(
const QColor &color)
707 d->setColor(
this, PlatformThemeData::TextColor, color);
710void PlatformTheme::setCustomDisabledTextColor(
const QColor &color)
712 d->setColor(
this, PlatformThemeData::DisabledTextColor, color);
715void PlatformTheme::setCustomBackgroundColor(
const QColor &color)
717 d->setColor(
this, PlatformThemeData::BackgroundColor, color);
720void PlatformTheme::setCustomAlternateBackgroundColor(
const QColor &color)
722 d->setColor(
this, PlatformThemeData::AlternateBackgroundColor, color);
725void PlatformTheme::setCustomHighlightColor(
const QColor &color)
727 d->setColor(
this, PlatformThemeData::HighlightColor, color);
730void PlatformTheme::setCustomHighlightedTextColor(
const QColor &color)
732 d->setColor(
this, PlatformThemeData::HighlightedTextColor, color);
735void PlatformTheme::setCustomActiveTextColor(
const QColor &color)
737 d->setColor(
this, PlatformThemeData::ActiveTextColor, color);
740void PlatformTheme::setCustomActiveBackgroundColor(
const QColor &color)
742 d->setColor(
this, PlatformThemeData::ActiveBackgroundColor, color);
745void PlatformTheme::setCustomLinkColor(
const QColor &color)
747 d->setColor(
this, PlatformThemeData::LinkColor, color);
750void PlatformTheme::setCustomLinkBackgroundColor(
const QColor &color)
752 d->setColor(
this, PlatformThemeData::LinkBackgroundColor, color);
755void PlatformTheme::setCustomVisitedLinkColor(
const QColor &color)
757 d->setColor(
this, PlatformThemeData::TextColor, color);
760void PlatformTheme::setCustomVisitedLinkBackgroundColor(
const QColor &color)
762 d->setColor(
this, PlatformThemeData::VisitedLinkBackgroundColor, color);
765void PlatformTheme::setCustomNegativeTextColor(
const QColor &color)
767 d->setColor(
this, PlatformThemeData::NegativeTextColor, color);
770void PlatformTheme::setCustomNegativeBackgroundColor(
const QColor &color)
772 d->setColor(
this, PlatformThemeData::NegativeBackgroundColor, color);
775void PlatformTheme::setCustomNeutralTextColor(
const QColor &color)
777 d->setColor(
this, PlatformThemeData::NeutralTextColor, color);
780void PlatformTheme::setCustomNeutralBackgroundColor(
const QColor &color)
782 d->setColor(
this, PlatformThemeData::NeutralBackgroundColor, color);
785void PlatformTheme::setCustomPositiveTextColor(
const QColor &color)
787 d->setColor(
this, PlatformThemeData::PositiveTextColor, color);
790void PlatformTheme::setCustomPositiveBackgroundColor(
const QColor &color)
792 d->setColor(
this, PlatformThemeData::PositiveBackgroundColor, color);
795void PlatformTheme::setCustomHoverColor(
const QColor &color)
797 d->setColor(
this, PlatformThemeData::HoverColor, color);
800void PlatformTheme::setCustomFocusColor(
const QColor &color)
802 d->setColor(
this, PlatformThemeData::FocusColor, color);
805bool PlatformTheme::useAlternateBackgroundColor()
const
807 return d->useAlternateBackgroundColor;
810void PlatformTheme::setUseAlternateBackgroundColor(
bool alternate)
812 if (alternate == d->useAlternateBackgroundColor) {
816 d->useAlternateBackgroundColor = alternate;
817 Q_EMIT useAlternateBackgroundColorChanged(alternate);
820QPalette PlatformTheme::palette()
const
826 auto palette = d->data->palette;
828 if (d->localOverrides) {
829 PlatformThemeData::updatePalette(palette, *d->localOverrides);
837 Q_UNUSED(customColor);
842bool PlatformTheme::supportsIconColoring()
const
844 return d->supportsIconColoring;
847void PlatformTheme::setSupportsIconColoring(
bool support)
849 d->supportsIconColoring = support;
852PlatformTheme *PlatformTheme::qmlAttachedProperties(
QObject *
object)
861 auto plugin = PlatformPluginFactory::findPlugin(pluginName);
862 if (!plugin && !pluginName.
isEmpty()) {
863 plugin = PlatformPluginFactory::findPlugin();
867 if (
auto theme = plugin->createPlatformTheme(
object)) {
872 return new BasicTheme(
object);
875void PlatformTheme::emitSignalsForChanges(
int changes)
881 auto propertyChanges = PlatformThemeChangeTracker::PropertyChanges::fromInt(changes);
883 if (propertyChanges & PlatformThemeChangeTracker::PropertyChange::ColorSet) {
884 Q_EMIT colorSetChanged(ColorSet(d->data->colorSet));
887 if (propertyChanges & PlatformThemeChangeTracker::PropertyChange::ColorGroup) {
888 Q_EMIT colorGroupChanged(ColorGroup(d->data->colorGroup));
891 if (propertyChanges & PlatformThemeChangeTracker::PropertyChange::Color) {
892 Q_EMIT colorsChanged();
895 if (propertyChanges & PlatformThemeChangeTracker::PropertyChange::Palette) {
896 Q_EMIT paletteChanged(d->data->palette);
899 if (propertyChanges & PlatformThemeChangeTracker::PropertyChange::Font) {
900 Q_EMIT defaultFontChanged(d->data->defaultFont);
901 Q_EMIT smallFontChanged(d->data->smallFont);
904 if (propertyChanges & PlatformThemeChangeTracker::PropertyChange::Data) {
905 updateChildren(parent());
909bool PlatformTheme::event(
QEvent *event)
911 PlatformThemeChangeTracker tracker(
this);
913 if (
event->type() == PlatformThemeEvents::DataChangedEvent::type) {
914 auto changeEvent =
static_cast<PlatformThemeEvents::DataChangedEvent *
>(
event);
916 if (changeEvent->sender !=
this) {
920 if (changeEvent->oldValue) {
921 changeEvent->oldValue->removeChangeWatcher(
this);
924 if (changeEvent->newValue) {
925 auto data = changeEvent->newValue;
926 data->addChangeWatcher(
this);
929 tracker.markDirty(PlatformThemeChangeTracker::PropertyChange::All);
933 if (
event->type() == PlatformThemeEvents::ColorSetChangedEvent::type) {
934 tracker.markDirty(PlatformThemeChangeTracker::PropertyChange::ColorSet);
938 if (
event->type() == PlatformThemeEvents::ColorGroupChangedEvent::type) {
939 tracker.markDirty(PlatformThemeChangeTracker::PropertyChange::ColorGroup);
943 if (
event->type() == PlatformThemeEvents::ColorChangedEvent::type) {
944 tracker.markDirty(PlatformThemeChangeTracker::PropertyChange::Color | PlatformThemeChangeTracker::PropertyChange::Palette);
948 if (
event->type() == PlatformThemeEvents::FontChangedEvent::type) {
949 tracker.markDirty(PlatformThemeChangeTracker::PropertyChange::Font);
956void PlatformTheme::update()
958 auto oldData = d->data;
960 bool actualInherit = d->inherit;
961 if (
QQuickItem *item = qobject_cast<QQuickItem *>(parent())) {
963 if (colorGroup() != Disabled && !item->isEnabled()) {
964 actualInherit =
false;
971 candidate = determineParent(candidate);
976 auto t =
static_cast<PlatformTheme *
>(qmlAttachedPropertiesObject<PlatformTheme>(candidate,
false));
977 if (t && t->d->data && t->d->data->owner == t) {
978 if (d->data == t->d->data) {
983 d->data = t->d->data;
985 PlatformThemeEvents::DataChangedEvent
event{
this, oldData, t->d->data};
991 }
else if (d->data && d->data->owner !=
this) {
998 d->data = std::make_shared<PlatformThemeData>();
999 d->data->owner =
this;
1000 d->data->setColorSet(
this,
static_cast<ColorSet
>(d->colorSet));
1001 d->data->setColorGroup(
this,
static_cast<ColorGroup
>(d->colorGroup));
1004 if (d->localOverrides) {
1005 for (
auto entry : *d->localOverrides) {
1006 d->data->setColor(
this, PlatformThemeData::ColorRole(entry.first), entry.second);
1010 PlatformThemeEvents::DataChangedEvent
event{
this, oldData, d->data};
1014void PlatformTheme::updateChildren(
QObject *
object)
1020 const auto children =
object->children();
1021 for (
auto child : children) {
1022 auto t =
static_cast<PlatformTheme *
>(qmlAttachedPropertiesObject<PlatformTheme>(child,
false));
1026 updateChildren(child);
1040 auto item = qobject_cast<QQuickItem *>(
object);
1042 return item->parentItem();
1044 return object->parent();
1048PlatformThemeChangeTracker::PlatformThemeChangeTracker(PlatformTheme *theme, PropertyChanges changes)
1051 auto itr = s_blockedChanges.constFind(theme);
1052 if (itr == s_blockedChanges.constEnd() || (*itr).expired()) {
1053 m_data = std::make_shared<Data>();
1054 s_blockedChanges.insert(theme, m_data);
1056 m_data = (*itr).lock();
1059 m_data->changes |= changes;
1062PlatformThemeChangeTracker::~PlatformThemeChangeTracker() noexcept
1064 std::weak_ptr<Data> dataWatcher = m_data;
1066 auto changes = m_data->changes;
1069 if (dataWatcher.use_count() <= 0) {
1070 m_theme->emitSignalsForChanges(changes);
1071 s_blockedChanges.remove(m_theme);
1075void PlatformThemeChangeTracker::markDirty(PropertyChanges changes)
1077 m_data->changes |= changes;
1082#include "moc_platformtheme.cpp"
1083#include "platformtheme.moc"
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
void update(Part *part, const QByteArray &data, qint64 dataSize)
bool isValid() const const
bool sendEvent(QObject *receiver, QEvent *event)
int registerEventType(int hint)
QIcon fromTheme(const QString &name)
void append(QList< T > &&value)
bool removeOne(const AT &t)
virtual bool event(QEvent *e)
QVariant property(const char *name) const const
QObject * sender() const const
void setColor(ColorGroup group, ColorRole role, const QColor &color)
void setCurrentColorGroup(ColorGroup cg)
void parentChanged(QQuickItem *)
void windowChanged(QQuickWindow *window)
bool isEmpty() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QString toString() const const