8#include "platformtheme.h"
9#include "basictheme_p.h"
10#include "platformpluginfactory.h"
13#include <QFontDatabase>
14#include <QGuiApplication>
15#include <QPluginLoader>
20#include <QQuickWindow>
26#include <unordered_map>
48struct TypeInitializer {
58static TypeInitializer initializer;
63class PlatformThemeData :
public QObject
83 AlternateBackgroundColor,
85 ActiveBackgroundColor,
87 VisitedLinkBackgroundColor,
88 NegativeBackgroundColor,
89 NeutralBackgroundColor,
90 PositiveBackgroundColor,
99 using ColorMap = std::unordered_map<std::underlying_type<ColorRole>::type, QColor>;
103 QPointer<PlatformTheme> owner;
106 PlatformTheme::ColorGroup colorGroup = PlatformTheme::Active;
108 std::array<QColor, ColorRoleCount> colors;
119 using Watcher = PlatformTheme *;
120 QList<Watcher> watchers;
124 if (
sender != owner || colorSet == set) {
128 auto oldValue = colorSet;
132 notifyWatchers<PlatformTheme::ColorSet>(
sender, oldValue, set);
135 inline void setColorGroup(PlatformTheme *
sender, PlatformTheme::ColorGroup group)
137 if (
sender != owner || colorGroup == group) {
141 auto oldValue = colorGroup;
146 notifyWatchers<PlatformTheme::ColorGroup>(
sender, oldValue, group);
149 inline void setColor(PlatformTheme *
sender, ColorRole role,
const QColor &color)
151 if (
sender != owner || colors[role] == color) {
155 auto oldValue = colors[role];
157 colors[role] = color;
158 updatePalette(palette, colors);
160 notifyWatchers<QColor>(
sender, oldValue, colors[role]);
163 inline void setDefaultFont(PlatformTheme *
sender,
const QFont &font)
165 if (
sender != owner || font == defaultFont) {
169 auto oldValue = defaultFont;
173 notifyWatchers<QFont>(
sender, oldValue, font);
176 inline void setSmallFont(PlatformTheme *
sender,
const QFont &font)
178 if (
sender != owner || font == smallFont) {
182 auto oldValue = smallFont;
186 notifyWatchers<QFont>(
sender, oldValue, smallFont);
189 inline void addChangeWatcher(PlatformTheme *
object)
191 watchers.append(
object);
194 inline void removeChangeWatcher(PlatformTheme *
object)
196 watchers.removeOne(
object);
200 inline void notifyWatchers(PlatformTheme *
sender,
const T &oldValue,
const T &newValue)
202 for (
auto object : std::as_const(watchers)) {
203 PlatformThemeEvents::PropertyChangedEvent<T>
event(
sender, oldValue, newValue);
209 inline static void updatePalette(QPalette &palette,
const std::array<QColor, ColorRoleCount> &colors)
211 for (std::size_t i = 0; i < colors.size(); ++i) {
212 setPaletteColor(palette, ColorRole(i), colors.at(i));
217 inline static void updatePalette(QPalette &palette,
const ColorMap &colors)
219 for (
auto entry : colors) {
220 setPaletteColor(palette, ColorRole(entry.first), entry.second);
224 inline static void setPaletteColor(QPalette &palette, ColorRole role,
const QColor &color)
232 case BackgroundColor:
237 case AlternateBackgroundColor:
244 case HighlightedTextColor:
250 case VisitedLinkColor:
260class PlatformThemePrivate
263 PlatformThemePrivate()
265 , supportsIconColoring(false)
266 , pendingColorChange(false)
267 , pendingChildUpdate(false)
268 , useAlternateBackgroundColor(false)
269 , colorSet(PlatformTheme::
Window)
270 , colorGroup(PlatformTheme::Active)
274 inline QColor color(
const PlatformTheme *theme, PlatformThemeData::ColorRole color)
const
280 QColor value = data->colors.at(color);
282 if (data->owner != theme && localOverrides) {
283 auto itr = localOverrides->find(color);
284 if (itr != localOverrides->end()) {
292 inline void setColor(PlatformTheme *theme, PlatformThemeData::ColorRole color,
const QColor &value)
294 if (!localOverrides) {
295 localOverrides = std::make_unique<PlatformThemeData::ColorMap>();
300 auto itr = localOverrides->find(color);
301 if (itr != localOverrides->end()) {
302 PlatformThemeChangeTracker tracker(theme, PlatformThemeChangeTracker::PropertyChange::Color);
303 localOverrides->erase(itr);
317 auto itr = localOverrides->find(color);
318 if (itr != localOverrides->end() && itr->second == value && (data && data->owner != theme)) {
322 PlatformThemeChangeTracker tracker(theme, PlatformThemeChangeTracker::PropertyChange::Color);
324 (*localOverrides)[color] = value;
327 data->setColor(theme, color, value);
331 inline void setDataColor(PlatformTheme *theme, PlatformThemeData::ColorRole color,
const QColor &value)
337 if (localOverrides) {
338 auto itr = localOverrides->find(color);
339 if (itr != localOverrides->end()) {
344 PlatformThemeChangeTracker tracker(theme, PlatformThemeChangeTracker::PropertyChange::Color);
347 data->setColor(theme, color, value);
361 std::shared_ptr<PlatformThemeData> data;
364 std::unique_ptr<PlatformThemeData::ColorMap> localOverrides;
367 bool supportsIconColoring : 1;
368 bool pendingColorChange : 1;
369 bool pendingChildUpdate : 1;
370 bool useAlternateBackgroundColor : 1;
376 uint8_t colorSet : 4;
377 uint8_t colorGroup : 4;
381 static_assert(PlatformTheme::ColorGroupCount <= 16,
"PlatformTheme::ColorGroup contains more elements than can be stored in PlatformThemePrivate");
382 static_assert(PlatformTheme::ColorSetCount <= 16,
"PlatformTheme::ColorSet contains more elements than can be stored in PlatformThemePrivate");
384 inline static PlatformPluginFactory *s_pluginFactory =
nullptr;
387PlatformTheme::PlatformTheme(QObject *parent)
389 , d(new PlatformThemePrivate)
391 if (
QQuickItem *item = qobject_cast<QQuickItem *>(parent)) {
408PlatformTheme::~PlatformTheme()
411 d->data->removeChangeWatcher(
this);
417void PlatformTheme::setColorSet(PlatformTheme::ColorSet colorSet)
419 PlatformThemeChangeTracker tracker(
this, PlatformThemeChangeTracker::PropertyChange::ColorSet);
420 d->colorSet = colorSet;
423 d->data->setColorSet(
this, colorSet);
427PlatformTheme::ColorSet PlatformTheme::colorSet()
const
429 return d->data ? d->data->colorSet :
Window;
432void PlatformTheme::setColorGroup(PlatformTheme::ColorGroup colorGroup)
434 PlatformThemeChangeTracker tracker(
this, PlatformThemeChangeTracker::PropertyChange::ColorGroup);
435 d->colorGroup = colorGroup;
438 d->data->setColorGroup(
this, colorGroup);
442PlatformTheme::ColorGroup PlatformTheme::colorGroup()
const
444 return d->data ? d->data->colorGroup : Active;
447bool PlatformTheme::inherit()
const
452void PlatformTheme::setInherit(
bool inherit)
454 if (inherit == d->inherit) {
458 d->inherit = inherit;
461 Q_EMIT inheritChanged(inherit);
464QColor PlatformTheme::textColor()
const
466 return d->color(
this, PlatformThemeData::TextColor);
469QColor PlatformTheme::disabledTextColor()
const
471 return d->color(
this, PlatformThemeData::DisabledTextColor);
474QColor PlatformTheme::highlightColor()
const
476 return d->color(
this, PlatformThemeData::HighlightColor);
479QColor PlatformTheme::highlightedTextColor()
const
481 return d->color(
this, PlatformThemeData::HighlightedTextColor);
484QColor PlatformTheme::backgroundColor()
const
486 return d->color(
this, PlatformThemeData::BackgroundColor);
489QColor PlatformTheme::alternateBackgroundColor()
const
491 return d->color(
this, PlatformThemeData::AlternateBackgroundColor);
494QColor PlatformTheme::activeTextColor()
const
496 return d->color(
this, PlatformThemeData::ActiveTextColor);
499QColor PlatformTheme::activeBackgroundColor()
const
501 return d->color(
this, PlatformThemeData::ActiveBackgroundColor);
504QColor PlatformTheme::linkColor()
const
506 return d->color(
this, PlatformThemeData::LinkColor);
509QColor PlatformTheme::linkBackgroundColor()
const
511 return d->color(
this, PlatformThemeData::LinkBackgroundColor);
514QColor PlatformTheme::visitedLinkColor()
const
516 return d->color(
this, PlatformThemeData::VisitedLinkColor);
519QColor PlatformTheme::visitedLinkBackgroundColor()
const
521 return d->color(
this, PlatformThemeData::VisitedLinkBackgroundColor);
524QColor PlatformTheme::negativeTextColor()
const
526 return d->color(
this, PlatformThemeData::NegativeTextColor);
529QColor PlatformTheme::negativeBackgroundColor()
const
531 return d->color(
this, PlatformThemeData::NegativeBackgroundColor);
534QColor PlatformTheme::neutralTextColor()
const
536 return d->color(
this, PlatformThemeData::NeutralTextColor);
539QColor PlatformTheme::neutralBackgroundColor()
const
541 return d->color(
this, PlatformThemeData::NeutralBackgroundColor);
544QColor PlatformTheme::positiveTextColor()
const
546 return d->color(
this, PlatformThemeData::PositiveTextColor);
549QColor PlatformTheme::positiveBackgroundColor()
const
551 return d->color(
this, PlatformThemeData::PositiveBackgroundColor);
554QColor PlatformTheme::focusColor()
const
556 return d->color(
this, PlatformThemeData::FocusColor);
559QColor PlatformTheme::hoverColor()
const
561 return d->color(
this, PlatformThemeData::HoverColor);
565void PlatformTheme::setTextColor(
const QColor &color)
567 d->setDataColor(
this, PlatformThemeData::TextColor, color);
570void PlatformTheme::setDisabledTextColor(
const QColor &color)
572 d->setDataColor(
this, PlatformThemeData::DisabledTextColor, color);
575void PlatformTheme::setBackgroundColor(
const QColor &color)
577 d->setDataColor(
this, PlatformThemeData::BackgroundColor, color);
580void PlatformTheme::setAlternateBackgroundColor(
const QColor &color)
582 d->setDataColor(
this, PlatformThemeData::AlternateBackgroundColor, color);
585void PlatformTheme::setHighlightColor(
const QColor &color)
587 d->setDataColor(
this, PlatformThemeData::HighlightColor, color);
590void PlatformTheme::setHighlightedTextColor(
const QColor &color)
592 d->setDataColor(
this, PlatformThemeData::HighlightedTextColor, color);
595void PlatformTheme::setActiveTextColor(
const QColor &color)
597 d->setDataColor(
this, PlatformThemeData::ActiveTextColor, color);
600void PlatformTheme::setActiveBackgroundColor(
const QColor &color)
602 d->setDataColor(
this, PlatformThemeData::ActiveBackgroundColor, color);
605void PlatformTheme::setLinkColor(
const QColor &color)
607 d->setDataColor(
this, PlatformThemeData::LinkColor, color);
610void PlatformTheme::setLinkBackgroundColor(
const QColor &color)
612 d->setDataColor(
this, PlatformThemeData::LinkBackgroundColor, color);
615void PlatformTheme::setVisitedLinkColor(
const QColor &color)
617 d->setDataColor(
this, PlatformThemeData::VisitedLinkColor, color);
620void PlatformTheme::setVisitedLinkBackgroundColor(
const QColor &color)
622 d->setDataColor(
this, PlatformThemeData::VisitedLinkBackgroundColor, color);
625void PlatformTheme::setNegativeTextColor(
const QColor &color)
627 d->setDataColor(
this, PlatformThemeData::NegativeTextColor, color);
630void PlatformTheme::setNegativeBackgroundColor(
const QColor &color)
632 d->setDataColor(
this, PlatformThemeData::NegativeBackgroundColor, color);
635void PlatformTheme::setNeutralTextColor(
const QColor &color)
637 d->setDataColor(
this, PlatformThemeData::NeutralTextColor, color);
640void PlatformTheme::setNeutralBackgroundColor(
const QColor &color)
642 d->setDataColor(
this, PlatformThemeData::NeutralBackgroundColor, color);
645void PlatformTheme::setPositiveTextColor(
const QColor &color)
647 d->setDataColor(
this, PlatformThemeData::PositiveTextColor, color);
650void PlatformTheme::setPositiveBackgroundColor(
const QColor &color)
652 d->setDataColor(
this, PlatformThemeData::PositiveBackgroundColor, color);
655void PlatformTheme::setHoverColor(
const QColor &color)
657 d->setDataColor(
this, PlatformThemeData::HoverColor, color);
660void PlatformTheme::setFocusColor(
const QColor &color)
662 d->setDataColor(
this, PlatformThemeData::FocusColor, color);
665QFont PlatformTheme::defaultFont()
const
667 return d->data ? d->data->defaultFont :
QFont{};
670void PlatformTheme::setDefaultFont(
const QFont &font)
672 PlatformThemeChangeTracker tracker(
this, PlatformThemeChangeTracker::PropertyChange::Font);
674 d->data->setDefaultFont(
this, font);
678QFont PlatformTheme::smallFont()
const
680 return d->data ? d->data->smallFont :
QFont{};
683void PlatformTheme::setSmallFont(
const QFont &font)
685 PlatformThemeChangeTracker tracker(
this, PlatformThemeChangeTracker::PropertyChange::Font);
687 d->data->setSmallFont(
this, font);
691qreal PlatformTheme::frameContrast()
const
699qreal PlatformTheme::lightFrameContrast()
const
703 return frameContrast() / 2.0;
707void PlatformTheme::setCustomTextColor(
const QColor &color)
709 d->setColor(
this, PlatformThemeData::TextColor, color);
712void PlatformTheme::setCustomDisabledTextColor(
const QColor &color)
714 d->setColor(
this, PlatformThemeData::DisabledTextColor, color);
717void PlatformTheme::setCustomBackgroundColor(
const QColor &color)
719 d->setColor(
this, PlatformThemeData::BackgroundColor, color);
722void PlatformTheme::setCustomAlternateBackgroundColor(
const QColor &color)
724 d->setColor(
this, PlatformThemeData::AlternateBackgroundColor, color);
727void PlatformTheme::setCustomHighlightColor(
const QColor &color)
729 d->setColor(
this, PlatformThemeData::HighlightColor, color);
732void PlatformTheme::setCustomHighlightedTextColor(
const QColor &color)
734 d->setColor(
this, PlatformThemeData::HighlightedTextColor, color);
737void PlatformTheme::setCustomActiveTextColor(
const QColor &color)
739 d->setColor(
this, PlatformThemeData::ActiveTextColor, color);
742void PlatformTheme::setCustomActiveBackgroundColor(
const QColor &color)
744 d->setColor(
this, PlatformThemeData::ActiveBackgroundColor, color);
747void PlatformTheme::setCustomLinkColor(
const QColor &color)
749 d->setColor(
this, PlatformThemeData::LinkColor, color);
752void PlatformTheme::setCustomLinkBackgroundColor(
const QColor &color)
754 d->setColor(
this, PlatformThemeData::LinkBackgroundColor, color);
757void PlatformTheme::setCustomVisitedLinkColor(
const QColor &color)
759 d->setColor(
this, PlatformThemeData::TextColor, color);
762void PlatformTheme::setCustomVisitedLinkBackgroundColor(
const QColor &color)
764 d->setColor(
this, PlatformThemeData::VisitedLinkBackgroundColor, color);
767void PlatformTheme::setCustomNegativeTextColor(
const QColor &color)
769 d->setColor(
this, PlatformThemeData::NegativeTextColor, color);
772void PlatformTheme::setCustomNegativeBackgroundColor(
const QColor &color)
774 d->setColor(
this, PlatformThemeData::NegativeBackgroundColor, color);
777void PlatformTheme::setCustomNeutralTextColor(
const QColor &color)
779 d->setColor(
this, PlatformThemeData::NeutralTextColor, color);
782void PlatformTheme::setCustomNeutralBackgroundColor(
const QColor &color)
784 d->setColor(
this, PlatformThemeData::NeutralBackgroundColor, color);
787void PlatformTheme::setCustomPositiveTextColor(
const QColor &color)
789 d->setColor(
this, PlatformThemeData::PositiveTextColor, color);
792void PlatformTheme::setCustomPositiveBackgroundColor(
const QColor &color)
794 d->setColor(
this, PlatformThemeData::PositiveBackgroundColor, color);
797void PlatformTheme::setCustomHoverColor(
const QColor &color)
799 d->setColor(
this, PlatformThemeData::HoverColor, color);
802void PlatformTheme::setCustomFocusColor(
const QColor &color)
804 d->setColor(
this, PlatformThemeData::FocusColor, color);
807bool PlatformTheme::useAlternateBackgroundColor()
const
809 return d->useAlternateBackgroundColor;
812void PlatformTheme::setUseAlternateBackgroundColor(
bool alternate)
814 if (alternate == d->useAlternateBackgroundColor) {
818 d->useAlternateBackgroundColor = alternate;
819 Q_EMIT useAlternateBackgroundColorChanged(alternate);
822QPalette PlatformTheme::palette()
const
828 auto palette = d->data->palette;
830 if (d->localOverrides) {
831 PlatformThemeData::updatePalette(palette, *d->localOverrides);
839 Q_UNUSED(customColor);
844bool PlatformTheme::supportsIconColoring()
const
846 return d->supportsIconColoring;
849void PlatformTheme::setSupportsIconColoring(
bool support)
851 d->supportsIconColoring = support;
854PlatformTheme *PlatformTheme::qmlAttachedProperties(
QObject *
object)
863 auto plugin = PlatformPluginFactory::findPlugin(pluginName);
864 if (!plugin && !pluginName.
isEmpty()) {
865 plugin = PlatformPluginFactory::findPlugin();
869 if (
auto theme = plugin->createPlatformTheme(
object)) {
874 return new BasicTheme(
object);
877void PlatformTheme::emitSignalsForChanges(
int changes)
883 auto propertyChanges = PlatformThemeChangeTracker::PropertyChanges::fromInt(changes);
885 if (propertyChanges & PlatformThemeChangeTracker::PropertyChange::ColorSet) {
886 Q_EMIT colorSetChanged(ColorSet(d->data->colorSet));
889 if (propertyChanges & PlatformThemeChangeTracker::PropertyChange::ColorGroup) {
890 Q_EMIT colorGroupChanged(ColorGroup(d->data->colorGroup));
893 if (propertyChanges & PlatformThemeChangeTracker::PropertyChange::Color) {
894 Q_EMIT colorsChanged();
897 if (propertyChanges & PlatformThemeChangeTracker::PropertyChange::Palette) {
898 Q_EMIT paletteChanged(d->data->palette);
901 if (propertyChanges & PlatformThemeChangeTracker::PropertyChange::Font) {
902 Q_EMIT defaultFontChanged(d->data->defaultFont);
903 Q_EMIT smallFontChanged(d->data->smallFont);
906 if (propertyChanges & PlatformThemeChangeTracker::PropertyChange::Data) {
907 updateChildren(parent());
911bool PlatformTheme::event(
QEvent *event)
913 PlatformThemeChangeTracker tracker(
this);
915 if (
event->type() == PlatformThemeEvents::DataChangedEvent::type) {
916 auto changeEvent =
static_cast<PlatformThemeEvents::DataChangedEvent *
>(
event);
918 if (changeEvent->sender !=
this) {
922 if (changeEvent->oldValue) {
923 changeEvent->oldValue->removeChangeWatcher(
this);
926 if (changeEvent->newValue) {
927 auto data = changeEvent->newValue;
928 data->addChangeWatcher(
this);
931 tracker.markDirty(PlatformThemeChangeTracker::PropertyChange::All);
935 if (
event->type() == PlatformThemeEvents::ColorSetChangedEvent::type) {
936 tracker.markDirty(PlatformThemeChangeTracker::PropertyChange::ColorSet);
940 if (
event->type() == PlatformThemeEvents::ColorGroupChangedEvent::type) {
941 tracker.markDirty(PlatformThemeChangeTracker::PropertyChange::ColorGroup);
945 if (
event->type() == PlatformThemeEvents::ColorChangedEvent::type) {
946 tracker.markDirty(PlatformThemeChangeTracker::PropertyChange::Color | PlatformThemeChangeTracker::PropertyChange::Palette);
950 if (
event->type() == PlatformThemeEvents::FontChangedEvent::type) {
951 tracker.markDirty(PlatformThemeChangeTracker::PropertyChange::Font);
958void PlatformTheme::update()
960 auto oldData = d->data;
962 bool actualInherit = d->inherit;
963 if (
QQuickItem *item = qobject_cast<QQuickItem *>(parent())) {
965 if (colorGroup() != Disabled && !item->isEnabled()) {
966 actualInherit =
false;
973 candidate = determineParent(candidate);
978 auto t =
static_cast<PlatformTheme *
>(qmlAttachedPropertiesObject<PlatformTheme>(candidate,
false));
979 if (t && t->d->data && t->d->data->owner == t) {
980 if (d->data == t->d->data) {
985 d->data = t->d->data;
987 PlatformThemeEvents::DataChangedEvent
event{
this, oldData, t->d->data};
993 }
else if (d->data && d->data->owner !=
this) {
1000 d->data = std::make_shared<PlatformThemeData>();
1001 d->data->owner =
this;
1003 d->data->setColorSet(
this,
static_cast<ColorSet
>(d->colorSet));
1004 d->data->setColorGroup(
this,
static_cast<ColorGroup
>(d->colorGroup));
1009 if (d->inherit && !actualInherit && oldData) {
1010 d->data->setColorSet(
this, oldData->colorSet);
1014 if (d->localOverrides) {
1015 for (
auto entry : *d->localOverrides) {
1016 d->data->setColor(
this, PlatformThemeData::ColorRole(entry.first), entry.second);
1020 PlatformThemeEvents::DataChangedEvent
event{
this, oldData, d->data};
1024void PlatformTheme::updateChildren(
QObject *
object)
1030 const auto children =
object->children();
1031 for (
auto child : children) {
1032 auto t =
static_cast<PlatformTheme *
>(qmlAttachedPropertiesObject<PlatformTheme>(child,
false));
1036 updateChildren(child);
1050 auto item = qobject_cast<QQuickItem *>(
object);
1052 return item->parentItem();
1054 return object->parent();
1058PlatformThemeChangeTracker::PlatformThemeChangeTracker(PlatformTheme *theme, PropertyChanges changes)
1061 auto itr = s_blockedChanges.constFind(theme);
1062 if (itr == s_blockedChanges.constEnd() || (*itr).expired()) {
1063 m_data = std::make_shared<Data>();
1064 s_blockedChanges.insert(theme, m_data);
1066 m_data = (*itr).lock();
1069 m_data->changes |= changes;
1072PlatformThemeChangeTracker::~PlatformThemeChangeTracker() noexcept
1074 std::weak_ptr<Data> dataWatcher = m_data;
1076 auto changes = m_data->changes;
1079 if (dataWatcher.use_count() <= 0) {
1080 m_theme->emitSignalsForChanges(changes);
1081 s_blockedChanges.remove(m_theme);
1085void PlatformThemeChangeTracker::markDirty(PropertyChanges changes)
1087 m_data->changes |= changes;
1092#include "moc_platformtheme.cpp"
1093#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)
QFont systemFont(SystemFont type)
QIcon fromTheme(const QString &name)
virtual bool event(QEvent *e)
QVariant property(const char *name) const const
QObject * sender() const const
void parentChanged(QQuickItem *)
void windowChanged(QQuickWindow *window)
bool isEmpty() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QString toString() const const