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 | |
17 | namespace Kirigami |
18 | { |
19 | namespace Platform |
20 | { |
21 | |
22 | BasicThemeDefinition::BasicThemeDefinition(QObject *parent) |
23 | : QObject(parent) |
24 | { |
25 | defaultFont = qGuiApp->font(); |
26 | |
27 | smallFont = QFontDatabase::systemFont(type: QFontDatabase::SmallestReadableFont); |
28 | } |
29 | |
30 | void 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 | |
38 | BasicThemeInstance::BasicThemeInstance(QObject *parent) |
39 | : QObject(parent) |
40 | { |
41 | } |
42 | |
43 | BasicThemeDefinition &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 | |
75 | void BasicThemeInstance::onDefinitionChanged() |
76 | { |
77 | for (auto watcher : std::as_const(t&: watchers)) { |
78 | watcher->sync(); |
79 | } |
80 | } |
81 | |
82 | Q_GLOBAL_STATIC(BasicThemeInstance, basicThemeInstance) |
83 | |
84 | BasicTheme::BasicTheme(QObject *parent) |
85 | : PlatformTheme(parent) |
86 | { |
87 | basicThemeInstance()->watchers.append(t: this); |
88 | |
89 | sync(); |
90 | } |
91 | |
92 | BasicTheme::~BasicTheme() |
93 | { |
94 | basicThemeInstance()->watchers.removeOne(t: this); |
95 | } |
96 | |
97 | void 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 | |
169 | bool 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 | |
194 | QColor 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 | |