1/*
2 * SPDX-FileCopyrightText: 2017 Marco Martin <mart@kde.org>
3 * SPDX-FileCopyrightText: 2021 Arjen Hiemstra <ahiemstra@heimr.nl>
4 *
5 * SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7
8#include "basictheme_p.h"
9#include "styleselector.h"
10
11#include <QFile>
12#include <QFontDatabase>
13#include <QGuiApplication>
14
15#include "kirigamiplatform_logging.h"
16
17namespace Kirigami
18{
19namespace Platform
20{
21
22BasicThemeDefinition::BasicThemeDefinition(QObject *parent)
23 : QObject(parent)
24{
25 defaultFont = qGuiApp->font();
26
27 smallFont = QFontDatabase::systemFont(type: QFontDatabase::SmallestReadableFont);
28}
29
30void BasicThemeDefinition::syncToQml(PlatformTheme *object)
31{
32 auto item = qobject_cast<QQuickItem *>(o: object->parent());
33 if (item && qmlAttachedPropertiesObject<PlatformTheme>(obj: item, create: false) == object) {
34 Q_EMIT sync(object: item);
35 }
36}
37
38BasicThemeInstance::BasicThemeInstance(QObject *parent)
39 : QObject(parent)
40{
41}
42
43BasicThemeDefinition &BasicThemeInstance::themeDefinition(QQmlEngine *engine)
44{
45 if (m_themeDefinition) {
46 return *m_themeDefinition;
47 }
48
49 if (!engine) {
50 qCWarning(KirigamiPlatform) << "No QML engine found, using default Basic theme.";
51 m_themeDefinition = std::make_unique<BasicThemeDefinition>();
52 } else {
53 auto themeUrl = StyleSelector::componentUrl(QStringLiteral("Theme.qml"));
54 QQmlComponent component(engine);
55 component.loadUrl(url: themeUrl);
56
57 if (auto themeDefinition = qobject_cast<BasicThemeDefinition *>(object: component.create())) {
58 m_themeDefinition.reset(p: themeDefinition);
59 } else {
60 const auto errors = component.errors();
61 for (auto error : errors) {
62 qCWarning(KirigamiPlatform) << error.toString();
63 }
64
65 qCWarning(KirigamiPlatform) << "Invalid Theme file, using default Basic theme.";
66 m_themeDefinition = std::make_unique<BasicThemeDefinition>();
67 }
68 }
69
70 connect(sender: m_themeDefinition.get(), signal: &BasicThemeDefinition::changed, context: this, slot: &BasicThemeInstance::onDefinitionChanged);
71
72 return *m_themeDefinition;
73}
74
75void BasicThemeInstance::onDefinitionChanged()
76{
77 for (auto watcher : std::as_const(t&: watchers)) {
78 watcher->sync();
79 }
80}
81
82Q_GLOBAL_STATIC(BasicThemeInstance, basicThemeInstance)
83
84BasicTheme::BasicTheme(QObject *parent)
85 : PlatformTheme(parent)
86{
87 basicThemeInstance()->watchers.append(t: this);
88
89 sync();
90}
91
92BasicTheme::~BasicTheme()
93{
94 basicThemeInstance()->watchers.removeOne(t: this);
95}
96
97void BasicTheme::sync()
98{
99 PlatformThemeChangeTracker tracker{this};
100
101 auto &definition = basicThemeInstance()->themeDefinition(engine: qmlEngine(parent()));
102
103 switch (colorSet()) {
104 case BasicTheme::Button:
105 setTextColor(tint(color: definition.buttonTextColor));
106 setBackgroundColor(tint(color: definition.buttonBackgroundColor));
107 setAlternateBackgroundColor(tint(color: definition.buttonAlternateBackgroundColor));
108 setHoverColor(tint(color: definition.buttonHoverColor));
109 setFocusColor(tint(color: definition.buttonFocusColor));
110 break;
111 case BasicTheme::View:
112 setTextColor(tint(color: definition.viewTextColor));
113 setBackgroundColor(tint(color: definition.viewBackgroundColor));
114 setAlternateBackgroundColor(tint(color: definition.viewAlternateBackgroundColor));
115 setHoverColor(tint(color: definition.viewHoverColor));
116 setFocusColor(tint(color: definition.viewFocusColor));
117 break;
118 case BasicTheme::Selection:
119 setTextColor(tint(color: definition.selectionTextColor));
120 setBackgroundColor(tint(color: definition.selectionBackgroundColor));
121 setAlternateBackgroundColor(tint(color: definition.selectionAlternateBackgroundColor));
122 setHoverColor(tint(color: definition.selectionHoverColor));
123 setFocusColor(tint(color: definition.selectionFocusColor));
124 break;
125 case BasicTheme::Tooltip:
126 setTextColor(tint(color: definition.tooltipTextColor));
127 setBackgroundColor(tint(color: definition.tooltipBackgroundColor));
128 setAlternateBackgroundColor(tint(color: definition.tooltipAlternateBackgroundColor));
129 setHoverColor(tint(color: definition.tooltipHoverColor));
130 setFocusColor(tint(color: definition.tooltipFocusColor));
131 break;
132 case BasicTheme::Complementary:
133 setTextColor(tint(color: definition.complementaryTextColor));
134 setBackgroundColor(tint(color: definition.complementaryBackgroundColor));
135 setAlternateBackgroundColor(tint(color: definition.complementaryAlternateBackgroundColor));
136 setHoverColor(tint(color: definition.complementaryHoverColor));
137 setFocusColor(tint(color: definition.complementaryFocusColor));
138 break;
139 case BasicTheme::Window:
140 default:
141 setTextColor(tint(color: definition.textColor));
142 setBackgroundColor(tint(color: definition.backgroundColor));
143 setAlternateBackgroundColor(tint(color: definition.alternateBackgroundColor));
144 setHoverColor(tint(color: definition.hoverColor));
145 setFocusColor(tint(color: definition.focusColor));
146 break;
147 }
148
149 setDisabledTextColor(tint(color: definition.disabledTextColor));
150 setHighlightColor(tint(color: definition.highlightColor));
151 setHighlightedTextColor(tint(color: definition.highlightedTextColor));
152 setActiveTextColor(tint(color: definition.activeTextColor));
153 setActiveBackgroundColor(tint(color: definition.activeBackgroundColor));
154 setLinkColor(tint(color: definition.linkColor));
155 setLinkBackgroundColor(tint(color: definition.linkBackgroundColor));
156 setVisitedLinkColor(tint(color: definition.visitedLinkColor));
157 setVisitedLinkBackgroundColor(tint(color: definition.visitedLinkBackgroundColor));
158 setNegativeTextColor(tint(color: definition.negativeTextColor));
159 setNegativeBackgroundColor(tint(color: definition.negativeBackgroundColor));
160 setNeutralTextColor(tint(color: definition.neutralTextColor));
161 setNeutralBackgroundColor(tint(color: definition.neutralBackgroundColor));
162 setPositiveTextColor(tint(color: definition.positiveTextColor));
163 setPositiveBackgroundColor(tint(color: definition.positiveBackgroundColor));
164
165 setDefaultFont(definition.defaultFont);
166 setSmallFont(definition.smallFont);
167}
168
169bool BasicTheme::event(QEvent *event)
170{
171 if (event->type() == PlatformThemeEvents::DataChangedEvent::type) {
172 sync();
173 }
174
175 if (event->type() == PlatformThemeEvents::ColorSetChangedEvent::type) {
176 sync();
177 }
178
179 if (event->type() == PlatformThemeEvents::ColorGroupChangedEvent::type) {
180 sync();
181 }
182
183 if (event->type() == PlatformThemeEvents::ColorChangedEvent::type) {
184 basicThemeInstance()->themeDefinition(engine: qmlEngine(parent())).syncToQml(object: this);
185 }
186
187 if (event->type() == PlatformThemeEvents::FontChangedEvent::type) {
188 basicThemeInstance()->themeDefinition(engine: qmlEngine(parent())).syncToQml(object: this);
189 }
190
191 return PlatformTheme::event(event);
192}
193
194QColor BasicTheme::tint(const QColor &color)
195{
196 if (QQuickItem *item = qobject_cast<QQuickItem *>(o: parent()); item && !item->isEnabled()) {
197 return QColor::fromHsvF(h: color.hueF(), s: color.saturationF() * 0.5, v: color.valueF() * 0.8);
198 }
199 switch (colorGroup()) {
200 case PlatformTheme::Inactive:
201 return QColor::fromHsvF(h: color.hueF(), s: color.saturationF() * 0.5, v: color.valueF());
202 case PlatformTheme::Disabled:
203 return QColor::fromHsvF(h: color.hueF(), s: color.saturationF() * 0.5, v: color.valueF() * 0.8);
204 default:
205 return color;
206 }
207}
208
209}
210}
211
212#include "moc_basictheme_p.cpp"
213

source code of kirigami/src/platform/basictheme.cpp