8 #include "platformtheme.h"
9 #include "basictheme_p.h"
10 #include "kirigamipluginfactory.h"
13 #include <QGuiApplication>
14 #include <QPluginLoader>
16 #include <QQmlContext>
18 #include <QQuickStyle>
19 #include <QQuickWindow>
25 #include <unordered_map>
45 struct TypeInitializer {
55 static TypeInitializer initializer;
60 class PlatformThemeData :
public QObject
80 AlternateBackgroundColor,
82 ActiveBackgroundColor,
84 VisitedLinkBackgroundColor,
85 NegativeBackgroundColor,
86 NeutralBackgroundColor,
87 PositiveBackgroundColor,
96 using ColorMap = std::unordered_map<std::underlying_type<ColorRole>::type,
QColor>;
103 PlatformTheme::ColorGroup colorGroup = PlatformTheme::Active;
105 std::array<QColor, ColorRoleCount> colors;
116 using Watcher = PlatformTheme *;
121 if (sender != owner || colorSet == set) {
125 auto oldValue = colorSet;
129 notifyWatchers<PlatformTheme::ColorSet>(sender, oldValue, set);
132 inline void setColorGroup(PlatformTheme *sender, PlatformTheme::ColorGroup group)
134 if (sender != owner || colorGroup == group) {
138 auto oldValue = colorGroup;
143 notifyWatchers<PlatformTheme::ColorGroup>(sender, oldValue, group);
146 inline void setColor(PlatformTheme *sender, ColorRole role,
const QColor &color)
148 if (sender != owner || colors[role] == color) {
152 auto oldValue = colors[role];
154 colors[role] = color;
155 updatePalette(palette, colors);
157 notifyWatchers<QColor>(sender, oldValue, colors[role]);
160 inline void setDefaultFont(PlatformTheme *sender,
const QFont &font)
162 if (sender != owner || font == defaultFont) {
166 auto oldValue = defaultFont;
170 notifyWatchers<QFont>(sender, oldValue, font);
173 inline void setSmallFont(PlatformTheme *sender,
const QFont &font)
175 if (sender != owner || font == smallFont) {
179 auto oldValue = smallFont;
183 notifyWatchers<QFont>(sender, oldValue, smallFont);
186 inline void addChangeWatcher(PlatformTheme *
object)
191 inline void removeChangeWatcher(PlatformTheme *
object)
197 inline void notifyWatchers(PlatformTheme *sender,
const T &oldValue,
const T &newValue)
199 for (
auto object : std::as_const(watchers)) {
200 PlatformThemeEvents::PropertyChangedEvent<T>
event(sender, oldValue, newValue);
206 inline static void updatePalette(
QPalette &palette,
const std::array<QColor, ColorRoleCount> &colors)
208 for (std::size_t i = 0; i < colors.size(); ++i) {
209 setPaletteColor(palette,
ColorRole(i), colors.at(i));
214 inline static void updatePalette(
QPalette &palette,
const ColorMap &colors)
216 for (
auto entry : colors) {
217 setPaletteColor(palette,
ColorRole(entry.first), entry.second);
221 inline static void setPaletteColor(
QPalette &palette, ColorRole role,
const QColor &color)
229 case BackgroundColor:
234 case AlternateBackgroundColor:
240 case HighlightedTextColor:
246 case VisitedLinkColor:
256 class PlatformThemePrivate
259 PlatformThemePrivate()
261 , supportsIconColoring(false)
262 , pendingColorChange(false)
263 , pendingChildUpdate(false)
264 , colorSet(PlatformTheme::
Window)
265 , colorGroup(PlatformTheme::
Active)
269 inline QColor color(
const PlatformTheme *theme, PlatformThemeData::ColorRole color)
const
275 QColor value = data->colors.at(color);
277 if (data->owner != theme && localOverrides) {
278 auto itr = localOverrides->find(color);
279 if (itr != localOverrides->end()) {
287 inline void setColor(PlatformTheme *theme, PlatformThemeData::ColorRole color,
const QColor &value)
289 if (!localOverrides) {
290 localOverrides = std::make_unique<PlatformThemeData::ColorMap>();
295 auto itr = localOverrides->find(color);
296 if (itr != localOverrides->end()) {
297 localOverrides->erase(itr);
307 emitCompressedColorChanged(theme);
313 auto itr = localOverrides->find(color);
314 if (itr != localOverrides->end() && itr->second == value && (data && data->owner != theme)) {
318 (*localOverrides)[color] = value;
321 data->setColor(theme, color, value);
324 emitCompressedColorChanged(theme);
327 inline void setDataColor(PlatformTheme *theme, PlatformThemeData::ColorRole color,
const QColor &value)
333 if (localOverrides) {
334 auto itr = localOverrides->find(color);
335 if (itr != localOverrides->end()) {
341 data->setColor(theme, color, value);
345 inline void emitCompressedColorChanged(PlatformTheme *theme)
347 if (pendingColorChange) {
351 pendingColorChange =
true;
355 inline void queueChildUpdate(PlatformTheme *theme)
357 if (pendingChildUpdate) {
361 pendingChildUpdate =
true;
365 pendingChildUpdate =
false;
366 theme->updateChildren(theme->parent());
381 std::shared_ptr<PlatformThemeData> data;
384 std::unique_ptr<PlatformThemeData::ColorMap> localOverrides;
387 bool supportsIconColoring : 1;
388 bool pendingColorChange : 1;
389 bool pendingChildUpdate : 1;
395 uint8_t colorSet : 4;
396 uint8_t colorGroup : 4;
400 static_assert(PlatformTheme::ColorGroupCount <= 16,
"PlatformTheme::ColorGroup contains more elements than can be stored in PlatformThemePrivate");
401 static_assert(
PlatformTheme::ColorSetCount <= 16,
"PlatformTheme::ColorSet contains more elements than can be stored in PlatformThemePrivate");
403 static KirigamiPluginFactory *s_pluginFactory;
406 KirigamiPluginFactory *PlatformThemePrivate::s_pluginFactory =
nullptr;
408 PlatformTheme::PlatformTheme(
QObject *parent)
410 , d(new PlatformThemePrivate)
412 if (
QQuickItem *item = qobject_cast<QQuickItem *>(parent)) {
420 PlatformTheme::~PlatformTheme()
423 d->data->removeChangeWatcher(
this);
429 void PlatformTheme::setColorSet(PlatformTheme::ColorSet colorSet)
431 d->colorSet = colorSet;
434 d->data->setColorSet(
this, colorSet);
438 PlatformTheme::ColorSet PlatformTheme::colorSet()
const
440 return d->data ? d->data->colorSet :
Window;
443 void PlatformTheme::setColorGroup(PlatformTheme::ColorGroup colorGroup)
445 d->colorGroup = colorGroup;
448 d->data->setColorGroup(
this, colorGroup);
452 PlatformTheme::ColorGroup PlatformTheme::colorGroup()
const
454 return d->data ? d->data->colorGroup :
Active;
457 bool PlatformTheme::inherit()
const
462 void PlatformTheme::setInherit(
bool inherit)
464 if (inherit == d->inherit) {
468 d->inherit = inherit;
471 Q_EMIT inheritChanged(inherit);
474 QColor PlatformTheme::textColor()
const
476 return d->color(
this, PlatformThemeData::TextColor);
479 QColor PlatformTheme::disabledTextColor()
const
481 return d->color(
this, PlatformThemeData::DisabledTextColor);
484 QColor PlatformTheme::highlightColor()
const
486 return d->color(
this, PlatformThemeData::HighlightColor);
489 QColor PlatformTheme::highlightedTextColor()
const
491 return d->color(
this, PlatformThemeData::HighlightedTextColor);
494 QColor PlatformTheme::backgroundColor()
const
496 return d->color(
this, PlatformThemeData::BackgroundColor);
499 QColor PlatformTheme::alternateBackgroundColor()
const
501 return d->color(
this, PlatformThemeData::AlternateBackgroundColor);
504 QColor PlatformTheme::activeTextColor()
const
506 return d->color(
this, PlatformThemeData::ActiveTextColor);
509 QColor PlatformTheme::activeBackgroundColor()
const
511 return d->color(
this, PlatformThemeData::ActiveBackgroundColor);
514 QColor PlatformTheme::linkColor()
const
516 return d->color(
this, PlatformThemeData::LinkColor);
519 QColor PlatformTheme::linkBackgroundColor()
const
521 return d->color(
this, PlatformThemeData::LinkBackgroundColor);
524 QColor PlatformTheme::visitedLinkColor()
const
526 return d->color(
this, PlatformThemeData::VisitedLinkColor);
529 QColor PlatformTheme::visitedLinkBackgroundColor()
const
531 return d->color(
this, PlatformThemeData::VisitedLinkBackgroundColor);
534 QColor PlatformTheme::negativeTextColor()
const
536 return d->color(
this, PlatformThemeData::NegativeTextColor);
539 QColor PlatformTheme::negativeBackgroundColor()
const
541 return d->color(
this, PlatformThemeData::NegativeBackgroundColor);
544 QColor PlatformTheme::neutralTextColor()
const
546 return d->color(
this, PlatformThemeData::NeutralTextColor);
549 QColor PlatformTheme::neutralBackgroundColor()
const
551 return d->color(
this, PlatformThemeData::NeutralBackgroundColor);
554 QColor PlatformTheme::positiveTextColor()
const
556 return d->color(
this, PlatformThemeData::PositiveTextColor);
559 QColor PlatformTheme::positiveBackgroundColor()
const
561 return d->color(
this, PlatformThemeData::PositiveBackgroundColor);
564 QColor PlatformTheme::focusColor()
const
566 return d->color(
this, PlatformThemeData::FocusColor);
569 QColor PlatformTheme::hoverColor()
const
571 return d->color(
this, PlatformThemeData::HoverColor);
575 void PlatformTheme::setTextColor(
const QColor &color)
577 d->setDataColor(
this, PlatformThemeData::TextColor, color);
580 void PlatformTheme::setDisabledTextColor(
const QColor &color)
582 d->setDataColor(
this, PlatformThemeData::DisabledTextColor, color);
585 void PlatformTheme::setBackgroundColor(
const QColor &color)
587 d->setDataColor(
this, PlatformThemeData::BackgroundColor, color);
590 void PlatformTheme::setAlternateBackgroundColor(
const QColor &color)
592 d->setDataColor(
this, PlatformThemeData::AlternateBackgroundColor, color);
595 void PlatformTheme::setHighlightColor(
const QColor &color)
597 d->setDataColor(
this, PlatformThemeData::HighlightColor, color);
600 void PlatformTheme::setHighlightedTextColor(
const QColor &color)
602 d->setDataColor(
this, PlatformThemeData::HighlightedTextColor, color);
605 void PlatformTheme::setActiveTextColor(
const QColor &color)
607 d->setDataColor(
this, PlatformThemeData::ActiveTextColor, color);
610 void PlatformTheme::setActiveBackgroundColor(
const QColor &color)
612 d->setDataColor(
this, PlatformThemeData::ActiveBackgroundColor, color);
615 void PlatformTheme::setLinkColor(
const QColor &color)
617 d->setDataColor(
this, PlatformThemeData::LinkColor, color);
620 void PlatformTheme::setLinkBackgroundColor(
const QColor &color)
622 d->setDataColor(
this, PlatformThemeData::LinkBackgroundColor, color);
625 void PlatformTheme::setVisitedLinkColor(
const QColor &color)
627 d->setDataColor(
this, PlatformThemeData::VisitedLinkColor, color);
630 void PlatformTheme::setVisitedLinkBackgroundColor(
const QColor &color)
632 d->setDataColor(
this, PlatformThemeData::VisitedLinkBackgroundColor, color);
635 void PlatformTheme::setNegativeTextColor(
const QColor &color)
637 d->setDataColor(
this, PlatformThemeData::NegativeTextColor, color);
640 void PlatformTheme::setNegativeBackgroundColor(
const QColor &color)
642 d->setDataColor(
this, PlatformThemeData::NegativeBackgroundColor, color);
645 void PlatformTheme::setNeutralTextColor(
const QColor &color)
647 d->setDataColor(
this, PlatformThemeData::NeutralTextColor, color);
650 void PlatformTheme::setNeutralBackgroundColor(
const QColor &color)
652 d->setDataColor(
this, PlatformThemeData::NeutralBackgroundColor, color);
655 void PlatformTheme::setPositiveTextColor(
const QColor &color)
657 d->setDataColor(
this, PlatformThemeData::PositiveTextColor, color);
660 void PlatformTheme::setPositiveBackgroundColor(
const QColor &color)
662 d->setDataColor(
this, PlatformThemeData::PositiveBackgroundColor, color);
665 void PlatformTheme::setHoverColor(
const QColor &color)
667 d->setDataColor(
this, PlatformThemeData::HoverColor, color);
670 void PlatformTheme::setFocusColor(
const QColor &color)
672 d->setDataColor(
this, PlatformThemeData::FocusColor, color);
675 QFont PlatformTheme::defaultFont()
const
677 return d->data ? d->data->defaultFont :
QFont{};
680 void PlatformTheme::setDefaultFont(
const QFont &font)
683 d->data->setDefaultFont(
this, font);
687 QFont PlatformTheme::smallFont()
const
689 return d->data ? d->data->smallFont :
QFont{};
692 void PlatformTheme::setSmallFont(
const QFont &font)
695 d->data->setSmallFont(
this, font);
700 void PlatformTheme::setCustomTextColor(
const QColor &color)
702 d->setColor(
this, PlatformThemeData::TextColor, color);
705 void PlatformTheme::setCustomDisabledTextColor(
const QColor &color)
707 d->setColor(
this, PlatformThemeData::DisabledTextColor, color);
710 void PlatformTheme::setCustomBackgroundColor(
const QColor &color)
712 d->setColor(
this, PlatformThemeData::BackgroundColor, color);
715 void PlatformTheme::setCustomAlternateBackgroundColor(
const QColor &color)
717 d->setColor(
this, PlatformThemeData::AlternateBackgroundColor, color);
720 void PlatformTheme::setCustomHighlightColor(
const QColor &color)
722 d->setColor(
this, PlatformThemeData::HighlightColor, color);
725 void PlatformTheme::setCustomHighlightedTextColor(
const QColor &color)
727 d->setColor(
this, PlatformThemeData::HighlightedTextColor, color);
730 void PlatformTheme::setCustomActiveTextColor(
const QColor &color)
732 d->setColor(
this, PlatformThemeData::ActiveTextColor, color);
735 void PlatformTheme::setCustomActiveBackgroundColor(
const QColor &color)
737 d->setColor(
this, PlatformThemeData::ActiveBackgroundColor, color);
740 void PlatformTheme::setCustomLinkColor(
const QColor &color)
742 d->setColor(
this, PlatformThemeData::LinkColor, color);
745 void PlatformTheme::setCustomLinkBackgroundColor(
const QColor &color)
747 d->setColor(
this, PlatformThemeData::LinkBackgroundColor, color);
750 void PlatformTheme::setCustomVisitedLinkColor(
const QColor &color)
752 d->setColor(
this, PlatformThemeData::TextColor, color);
755 void PlatformTheme::setCustomVisitedLinkBackgroundColor(
const QColor &color)
757 d->setColor(
this, PlatformThemeData::VisitedLinkBackgroundColor, color);
760 void PlatformTheme::setCustomNegativeTextColor(
const QColor &color)
762 d->setColor(
this, PlatformThemeData::NegativeTextColor, color);
765 void PlatformTheme::setCustomNegativeBackgroundColor(
const QColor &color)
767 d->setColor(
this, PlatformThemeData::NegativeBackgroundColor, color);
770 void PlatformTheme::setCustomNeutralTextColor(
const QColor &color)
772 d->setColor(
this, PlatformThemeData::NeutralTextColor, color);
775 void PlatformTheme::setCustomNeutralBackgroundColor(
const QColor &color)
777 d->setColor(
this, PlatformThemeData::NeutralBackgroundColor, color);
780 void PlatformTheme::setCustomPositiveTextColor(
const QColor &color)
782 d->setColor(
this, PlatformThemeData::PositiveTextColor, color);
785 void PlatformTheme::setCustomPositiveBackgroundColor(
const QColor &color)
787 d->setColor(
this, PlatformThemeData::PositiveBackgroundColor, color);
790 void PlatformTheme::setCustomHoverColor(
const QColor &color)
792 d->setColor(
this, PlatformThemeData::HoverColor, color);
795 void PlatformTheme::setCustomFocusColor(
const QColor &color)
797 d->setColor(
this, PlatformThemeData::FocusColor, color);
800 QPalette PlatformTheme::palette()
const
806 auto palette = d->data->palette;
808 if (d->localOverrides) {
809 PlatformThemeData::updatePalette(palette, *d->localOverrides);
815 #if KIRIGAMI2_BUILD_DEPRECATED_SINCE(5, 80)
816 void PlatformTheme::setPalette(
const QPalette &palette)
824 Q_UNUSED(customColor);
829 bool PlatformTheme::supportsIconColoring()
const
831 return d->supportsIconColoring;
834 void PlatformTheme::setSupportsIconColoring(
bool support)
836 d->supportsIconColoring = support;
839 PlatformTheme *PlatformTheme::qmlAttachedProperties(
QObject *
object)
841 auto plugin = KirigamiPluginFactory::findPlugin();
843 if (
auto theme = plugin->createPlatformTheme(
object)) {
848 return new BasicTheme(
object);
851 bool PlatformTheme::event(
QEvent *event)
853 if (
event->type() == PlatformThemeEvents::DataChangedEvent::type) {
854 auto changeEvent =
static_cast<PlatformThemeEvents::DataChangedEvent *
>(
event);
856 if (changeEvent->sender !=
this) {
860 if (changeEvent->oldValue) {
861 changeEvent->oldValue->removeChangeWatcher(
this);
864 if (changeEvent->newValue) {
865 auto data = changeEvent->newValue;
866 data->addChangeWatcher(
this);
868 Q_EMIT colorSetChanged(data->colorSet);
869 Q_EMIT colorGroupChanged(data->colorGroup);
870 Q_EMIT defaultFontChanged(data->defaultFont);
871 Q_EMIT smallFontChanged(data->smallFont);
872 d->emitCompressedColorChanged(
this);
878 if (
event->type() == PlatformThemeEvents::ColorSetChangedEvent::type) {
880 Q_EMIT colorSetChanged(d->data->colorSet);
885 if (
event->type() == PlatformThemeEvents::ColorGroupChangedEvent::type) {
887 Q_EMIT colorGroupChanged(d->data->colorGroup);
892 if (
event->type() == PlatformThemeEvents::ColorChangedEvent::type) {
893 d->emitCompressedColorChanged(
this);
897 if (
event->type() == PlatformThemeEvents::FontChangedEvent::type) {
899 Q_EMIT defaultFontChanged(d->data->defaultFont);
900 Q_EMIT smallFontChanged(d->data->smallFont);
908 void PlatformTheme::update()
910 d->queueChildUpdate(
this);
912 auto oldData = d->data;
917 candidate = determineParent(candidate);
922 auto t =
static_cast<PlatformTheme *
>(qmlAttachedPropertiesObject<PlatformTheme>(candidate,
false));
923 if (t && t->d->data && t->d->data->owner == t) {
924 if (d->data == t->d->data) {
929 d->data = t->d->data;
931 PlatformThemeEvents::DataChangedEvent
event{
this, oldData, t->d->data};
937 }
else if (d->data->owner !=
this) {
944 d->data = std::make_shared<PlatformThemeData>();
945 d->data->owner =
this;
946 d->data->setColorSet(
this,
static_cast<ColorSet
>(d->colorSet));
947 d->data->setColorGroup(
this,
static_cast<ColorGroup>(d->colorGroup));
950 if (d->localOverrides) {
951 for (
auto entry : *d->localOverrides) {
952 d->data->setColor(
this, PlatformThemeData::ColorRole(entry.first), entry.second);
956 PlatformThemeEvents::DataChangedEvent
event{
this, oldData, d->data};
960 void PlatformTheme::updateChildren(
QObject *
object)
966 const auto children =
object->children();
967 for (
auto child : children) {
968 auto t =
static_cast<PlatformTheme *
>(qmlAttachedPropertiesObject<PlatformTheme>(child,
false));
972 updateChildren(child);
977 void PlatformTheme::emitColorChanged()
980 Q_EMIT paletteChanged(d->data->palette);
983 Q_EMIT colorsChanged();
984 d->pendingColorChange =
false;
996 auto item = qobject_cast<QQuickItem *>(
object);
998 return item->parentItem();
1000 return object->parent();
1006 #include "platformtheme.moc"