1 | /* |
2 | * SPDX-FileCopyrightText: 2017 by Marco Martin <mart@kde.org> |
3 | * |
4 | * SPDX-License-Identifier: LGPL-2.0-or-later |
5 | */ |
6 | |
7 | #ifndef KIRIGAMI_PLATFORMTHEME_H |
8 | #define KIRIGAMI_PLATFORMTHEME_H |
9 | |
10 | #include <QColor> |
11 | #include <QIcon> |
12 | #include <QObject> |
13 | #include <QPalette> |
14 | #include <QQuickItem> |
15 | #include <qqmlregistration.h> |
16 | |
17 | #include "kirigamiplatform_export.h" |
18 | |
19 | namespace Kirigami |
20 | { |
21 | namespace Platform |
22 | { |
23 | class PlatformThemeData; |
24 | class PlatformThemePrivate; |
25 | |
26 | /** |
27 | * @class PlatformTheme platformtheme.h <Kirigami/PlatformTheme> |
28 | * |
29 | * This class is the base for color management in Kirigami, |
30 | * different platforms can reimplement this class to integrate with |
31 | * system platform colors of a given platform |
32 | */ |
33 | class KIRIGAMIPLATFORM_EXPORT PlatformTheme : public QObject |
34 | { |
35 | Q_OBJECT |
36 | QML_NAMED_ELEMENT(Theme) |
37 | QML_ATTACHED(Kirigami::Platform::PlatformTheme) |
38 | QML_UNCREATABLE("Attached Property" ) |
39 | |
40 | /** |
41 | * This enumeration describes the color set for which a color is being selected. |
42 | * |
43 | * Color sets define a color "environment", suitable for drawing all parts of a |
44 | * given region. Colors from different sets should not be combined. |
45 | */ |
46 | Q_PROPERTY(ColorSet colorSet READ colorSet WRITE setColorSet NOTIFY colorSetChanged FINAL) |
47 | |
48 | /** |
49 | * This enumeration describes the color group used to generate the colors. |
50 | * The enum value is based upon QPalette::ColorGroup and has the same values. |
51 | * It's redefined here in order to make it work with QML. |
52 | * @since 4.43 |
53 | */ |
54 | Q_PROPERTY(ColorGroup colorGroup READ colorGroup WRITE setColorGroup NOTIFY colorGroupChanged FINAL) |
55 | |
56 | /** |
57 | * If true, the colorSet will be inherited from the colorset of a theme of one |
58 | * of the ancestor items |
59 | * default: true |
60 | */ |
61 | Q_PROPERTY(bool inherit READ inherit WRITE setInherit NOTIFY inheritChanged FINAL) |
62 | |
63 | // foreground colors |
64 | /** |
65 | * Color for normal foregrounds, usually text, but not limited to it, |
66 | * anything that should be painted with a clear contrast should use this color |
67 | */ |
68 | Q_PROPERTY(QColor textColor READ textColor WRITE setCustomTextColor RESET setCustomTextColor NOTIFY colorsChanged FINAL) |
69 | |
70 | /** |
71 | * Foreground color for disabled areas, usually a mid-gray |
72 | * @note Depending on the implementation, the color used for this property may not be |
73 | * based on the disabled palette. For example, for the Plasma implementation, |
74 | * "Inactive Text Color" of the active palette is used. |
75 | */ |
76 | Q_PROPERTY(QColor disabledTextColor READ disabledTextColor WRITE setCustomDisabledTextColor RESET setCustomDisabledTextColor NOTIFY colorsChanged FINAL) |
77 | |
78 | /** |
79 | * Color for text that has been highlighted, often is a light color while normal text is dark |
80 | */ |
81 | Q_PROPERTY( |
82 | QColor highlightedTextColor READ highlightedTextColor WRITE setCustomHighlightedTextColor RESET setCustomHighlightedTextColor NOTIFY colorsChanged) |
83 | |
84 | /** |
85 | * Foreground for areas that are active or requesting attention |
86 | */ |
87 | Q_PROPERTY(QColor activeTextColor READ activeTextColor WRITE setCustomActiveTextColor RESET setCustomActiveTextColor NOTIFY colorsChanged FINAL) |
88 | |
89 | /** |
90 | * Color for links |
91 | */ |
92 | Q_PROPERTY(QColor linkColor READ linkColor WRITE setCustomLinkColor RESET setCustomLinkColor NOTIFY colorsChanged FINAL) |
93 | |
94 | /** |
95 | * Color for visited links, usually a bit darker than linkColor |
96 | */ |
97 | Q_PROPERTY(QColor visitedLinkColor READ visitedLinkColor WRITE setCustomVisitedLinkColor RESET setCustomVisitedLinkColor NOTIFY colorsChanged FINAL) |
98 | |
99 | /** |
100 | * Foreground color for negative areas, such as critical error text |
101 | */ |
102 | Q_PROPERTY(QColor negativeTextColor READ negativeTextColor WRITE setCustomNegativeTextColor RESET setCustomNegativeTextColor NOTIFY colorsChanged FINAL) |
103 | |
104 | /** |
105 | * Foreground color for neutral areas, such as warning texts (but not critical) |
106 | */ |
107 | Q_PROPERTY(QColor neutralTextColor READ neutralTextColor WRITE setCustomNeutralTextColor RESET setCustomNeutralTextColor NOTIFY colorsChanged FINAL) |
108 | |
109 | /** |
110 | * Success messages, trusted content |
111 | */ |
112 | Q_PROPERTY(QColor positiveTextColor READ positiveTextColor WRITE setCustomPositiveTextColor RESET setCustomPositiveTextColor NOTIFY colorsChanged FINAL) |
113 | |
114 | // background colors |
115 | /** |
116 | * The generic background color |
117 | */ |
118 | Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setCustomBackgroundColor RESET setCustomBackgroundColor NOTIFY colorsChanged FINAL) |
119 | |
120 | /** |
121 | * The generic background color |
122 | * Alternate background; for example, for use in lists. |
123 | * This color may be the same as BackgroundNormal, |
124 | * especially in sets other than View and Window. |
125 | */ |
126 | Q_PROPERTY(QColor alternateBackgroundColor READ alternateBackgroundColor WRITE setCustomAlternateBackgroundColor RESET setCustomAlternateBackgroundColor |
127 | NOTIFY colorsChanged) |
128 | |
129 | /** |
130 | * The background color for selected areas |
131 | */ |
132 | Q_PROPERTY(QColor highlightColor READ highlightColor WRITE setCustomHighlightColor RESET setCustomHighlightColor NOTIFY colorsChanged FINAL) |
133 | |
134 | /** |
135 | * Background for areas that are active or requesting attention |
136 | */ |
137 | Q_PROPERTY( |
138 | QColor activeBackgroundColor READ activeBackgroundColor WRITE setCustomActiveBackgroundColor RESET setCustomActiveBackgroundColor NOTIFY colorsChanged) |
139 | |
140 | /** |
141 | * Background color for links |
142 | */ |
143 | Q_PROPERTY( |
144 | QColor linkBackgroundColor READ linkBackgroundColor WRITE setCustomLinkBackgroundColor RESET setCustomLinkBackgroundColor NOTIFY colorsChanged FINAL) |
145 | |
146 | /** |
147 | * Background color for visited links, usually a bit darker than linkBackgroundColor |
148 | */ |
149 | Q_PROPERTY(QColor visitedLinkBackgroundColor READ visitedLinkBackgroundColor WRITE setCustomVisitedLinkBackgroundColor RESET |
150 | setCustomVisitedLinkBackgroundColor NOTIFY colorsChanged) |
151 | |
152 | /** |
153 | * Background color for negative areas, such as critical errors and destructive actions |
154 | */ |
155 | Q_PROPERTY(QColor negativeBackgroundColor READ negativeBackgroundColor WRITE setCustomNegativeBackgroundColor RESET setCustomNegativeBackgroundColor NOTIFY |
156 | colorsChanged) |
157 | |
158 | /** |
159 | * Background color for neutral areas, such as warnings (but not critical) |
160 | */ |
161 | Q_PROPERTY(QColor neutralBackgroundColor READ neutralBackgroundColor WRITE setCustomNeutralBackgroundColor RESET setCustomNeutralBackgroundColor NOTIFY |
162 | colorsChanged) |
163 | |
164 | /** |
165 | * Background color for positive areas, such as success messages and trusted content |
166 | */ |
167 | Q_PROPERTY(QColor positiveBackgroundColor READ positiveBackgroundColor WRITE setCustomPositiveBackgroundColor RESET setCustomPositiveBackgroundColor NOTIFY |
168 | colorsChanged) |
169 | |
170 | // decoration colors |
171 | /** |
172 | * A decoration color that indicates active focus |
173 | */ |
174 | Q_PROPERTY(QColor focusColor READ focusColor WRITE setCustomFocusColor RESET setCustomFocusColor NOTIFY colorsChanged FINAL) |
175 | |
176 | /** |
177 | * A decoration color that indicates mouse hovering |
178 | */ |
179 | Q_PROPERTY(QColor hoverColor READ hoverColor WRITE setCustomHoverColor RESET setCustomHoverColor NOTIFY colorsChanged FINAL) |
180 | |
181 | /** |
182 | * Hint for item views to actually make use of the alternate background color feature |
183 | */ |
184 | Q_PROPERTY( |
185 | bool useAlternateBackgroundColor READ useAlternateBackgroundColor WRITE setUseAlternateBackgroundColor NOTIFY useAlternateBackgroundColorChanged FINAL) |
186 | |
187 | // font and palette |
188 | Q_PROPERTY(QFont defaultFont READ defaultFont NOTIFY defaultFontChanged FINAL) |
189 | |
190 | // small font |
191 | Q_PROPERTY(QFont smallFont READ smallFont NOTIFY smallFontChanged FINAL) |
192 | |
193 | // Active palette |
194 | Q_PROPERTY(QPalette palette READ palette NOTIFY paletteChanged FINAL) |
195 | |
196 | // Frame contrast value, usually used for separators and outlines |
197 | // Value is between 0.0 and 1.0 |
198 | Q_PROPERTY(qreal frameContrast READ frameContrast CONSTANT FINAL) |
199 | |
200 | // Returns half of the frameContrast value; used by Separator.Weight.Light |
201 | // Value is between 0.0 and 1.0 |
202 | Q_PROPERTY(qreal lightFrameContrast READ lightFrameContrast CONSTANT FINAL) |
203 | |
204 | public: |
205 | enum ColorSet { |
206 | View = 0, /** Color set for item views, usually the lightest of all */ |
207 | Window, /** Default Color set for windows and "chrome" areas */ |
208 | Button, /** Color set used by buttons */ |
209 | Selection, /** Color set used by selectged areas */ |
210 | Tooltip, /** Color set used by tooltips */ |
211 | Complementary, /** Color set meant to be complementary to Window: usually is a dark theme for light themes */ |
212 | , /** Color set to be used by heading areas of applications, such as toolbars */ |
213 | |
214 | ColorSetCount, // Number of items in this enum, this should always be the last item. |
215 | }; |
216 | Q_ENUM(ColorSet) |
217 | |
218 | enum ColorGroup { |
219 | Disabled = QPalette::Disabled, |
220 | Active = QPalette::Active, |
221 | Inactive = QPalette::Inactive, |
222 | Normal = QPalette::Normal, |
223 | |
224 | ColorGroupCount, // Number of items in this enum, this should always be the last item. |
225 | }; |
226 | Q_ENUM(ColorGroup) |
227 | |
228 | explicit PlatformTheme(QObject *parent = nullptr); |
229 | ~PlatformTheme() override; |
230 | |
231 | void setColorSet(PlatformTheme::ColorSet); |
232 | PlatformTheme::ColorSet colorSet() const; |
233 | |
234 | void setColorGroup(PlatformTheme::ColorGroup); |
235 | PlatformTheme::ColorGroup colorGroup() const; |
236 | |
237 | bool inherit() const; |
238 | void setInherit(bool inherit); |
239 | |
240 | // foreground colors |
241 | QColor textColor() const; |
242 | QColor disabledTextColor() const; |
243 | QColor highlightedTextColor() const; |
244 | QColor activeTextColor() const; |
245 | QColor linkColor() const; |
246 | QColor visitedLinkColor() const; |
247 | QColor negativeTextColor() const; |
248 | QColor neutralTextColor() const; |
249 | QColor positiveTextColor() const; |
250 | |
251 | // background colors |
252 | QColor backgroundColor() const; |
253 | QColor alternateBackgroundColor() const; |
254 | QColor highlightColor() const; |
255 | QColor activeBackgroundColor() const; |
256 | QColor linkBackgroundColor() const; |
257 | QColor visitedLinkBackgroundColor() const; |
258 | QColor negativeBackgroundColor() const; |
259 | QColor neutralBackgroundColor() const; |
260 | QColor positiveBackgroundColor() const; |
261 | |
262 | // decoration colors |
263 | QColor focusColor() const; |
264 | QColor hoverColor() const; |
265 | |
266 | QFont defaultFont() const; |
267 | QFont smallFont() const; |
268 | |
269 | // this may is used by the desktop QQC2 to set the styleoption palettes |
270 | QPalette palette() const; |
271 | |
272 | qreal frameContrast() const; |
273 | qreal lightFrameContrast() const; |
274 | |
275 | // this will be used by desktopicon to fetch icons with KIconLoader |
276 | virtual Q_INVOKABLE QIcon iconFromTheme(const QString &name, const QColor &customColor = Qt::transparent); |
277 | |
278 | bool supportsIconColoring() const; |
279 | |
280 | // foreground colors |
281 | void setCustomTextColor(const QColor &color = QColor()); |
282 | void setCustomDisabledTextColor(const QColor &color = QColor()); |
283 | void setCustomHighlightedTextColor(const QColor &color = QColor()); |
284 | void setCustomActiveTextColor(const QColor &color = QColor()); |
285 | void setCustomLinkColor(const QColor &color = QColor()); |
286 | void setCustomVisitedLinkColor(const QColor &color = QColor()); |
287 | void setCustomNegativeTextColor(const QColor &color = QColor()); |
288 | void setCustomNeutralTextColor(const QColor &color = QColor()); |
289 | void setCustomPositiveTextColor(const QColor &color = QColor()); |
290 | // background colors |
291 | void setCustomBackgroundColor(const QColor &color = QColor()); |
292 | void setCustomAlternateBackgroundColor(const QColor &color = QColor()); |
293 | void setCustomHighlightColor(const QColor &color = QColor()); |
294 | void setCustomActiveBackgroundColor(const QColor &color = QColor()); |
295 | void setCustomLinkBackgroundColor(const QColor &color = QColor()); |
296 | void setCustomVisitedLinkBackgroundColor(const QColor &color = QColor()); |
297 | void setCustomNegativeBackgroundColor(const QColor &color = QColor()); |
298 | void setCustomNeutralBackgroundColor(const QColor &color = QColor()); |
299 | void setCustomPositiveBackgroundColor(const QColor &color = QColor()); |
300 | // decoration colors |
301 | void setCustomFocusColor(const QColor &color = QColor()); |
302 | void setCustomHoverColor(const QColor &color = QColor()); |
303 | |
304 | bool useAlternateBackgroundColor() const; |
305 | void setUseAlternateBackgroundColor(bool alternate); |
306 | |
307 | // QML attached property |
308 | static PlatformTheme *qmlAttachedProperties(QObject *object); |
309 | |
310 | Q_SIGNALS: |
311 | void colorsChanged(); |
312 | void defaultFontChanged(const QFont &font); |
313 | void smallFontChanged(const QFont &font); |
314 | void colorSetChanged(Kirigami::Platform::PlatformTheme::ColorSet colorSet); |
315 | void colorGroupChanged(Kirigami::Platform::PlatformTheme::ColorGroup colorGroup); |
316 | void paletteChanged(const QPalette &pal); |
317 | void inheritChanged(bool inherit); |
318 | void useAlternateBackgroundColorChanged(bool alternate); |
319 | |
320 | protected: |
321 | // Setters, not accessible from QML but from implementations |
322 | void setSupportsIconColoring(bool support); |
323 | |
324 | // foreground colors |
325 | void setTextColor(const QColor &color); |
326 | void setDisabledTextColor(const QColor &color); |
327 | void setHighlightedTextColor(const QColor &color); |
328 | void setActiveTextColor(const QColor &color); |
329 | void setLinkColor(const QColor &color); |
330 | void setVisitedLinkColor(const QColor &color); |
331 | void setNegativeTextColor(const QColor &color); |
332 | void setNeutralTextColor(const QColor &color); |
333 | void setPositiveTextColor(const QColor &color); |
334 | |
335 | // background colors |
336 | void setBackgroundColor(const QColor &color); |
337 | void setAlternateBackgroundColor(const QColor &color); |
338 | void setHighlightColor(const QColor &color); |
339 | void setActiveBackgroundColor(const QColor &color); |
340 | void setLinkBackgroundColor(const QColor &color); |
341 | void setVisitedLinkBackgroundColor(const QColor &color); |
342 | void setNegativeBackgroundColor(const QColor &color); |
343 | void setNeutralBackgroundColor(const QColor &color); |
344 | void setPositiveBackgroundColor(const QColor &color); |
345 | |
346 | // decoration colors |
347 | void setFocusColor(const QColor &color); |
348 | void setHoverColor(const QColor &color); |
349 | |
350 | void setDefaultFont(const QFont &defaultFont); |
351 | void setSmallFont(const QFont &smallFont); |
352 | |
353 | bool event(QEvent *event) override; |
354 | |
355 | private: |
356 | KIRIGAMIPLATFORM_NO_EXPORT void update(); |
357 | KIRIGAMIPLATFORM_NO_EXPORT void updateChildren(QObject *item); |
358 | KIRIGAMIPLATFORM_NO_EXPORT void emitSignals(); |
359 | KIRIGAMIPLATFORM_NO_EXPORT void emitColorChanged(); |
360 | KIRIGAMIPLATFORM_NO_EXPORT QObject *determineParent(QObject *object); |
361 | |
362 | PlatformThemePrivate *d; |
363 | friend class PlatformThemePrivate; |
364 | friend class PlatformThemeData; |
365 | }; |
366 | |
367 | namespace PlatformThemeEvents |
368 | { |
369 | // To avoid the overhead of Qt's signal/slot connections, we use custom events |
370 | // to communicate with subclasses. This way, we can indicate what actually |
371 | // changed without needing to add new virtual functions to PlatformTheme which |
372 | // would break binary compatibility. |
373 | // |
374 | // To handle these events in your subclass, override QObject::event() and check |
375 | // if you receive one of these events, then do what is needed. Finally, make |
376 | // sure to call PlatformTheme::event() since that will also do some processing |
377 | // of these events. |
378 | |
379 | template<typename T> |
380 | class KIRIGAMIPLATFORM_EXPORT PropertyChangedEvent : public QEvent |
381 | { |
382 | public: |
383 | PropertyChangedEvent(PlatformTheme *theme, const T &previous, const T ¤t) |
384 | : QEvent(PropertyChangedEvent<T>::type) |
385 | , sender(theme) |
386 | , oldValue(previous) |
387 | , newValue(current) |
388 | { |
389 | } |
390 | |
391 | PlatformTheme *sender; |
392 | T oldValue; |
393 | T newValue; |
394 | |
395 | static QEvent::Type type; |
396 | }; |
397 | |
398 | using DataChangedEvent = PropertyChangedEvent<std::shared_ptr<PlatformThemeData>>; |
399 | using ColorSetChangedEvent = PropertyChangedEvent<PlatformTheme::ColorSet>; |
400 | using ColorGroupChangedEvent = PropertyChangedEvent<PlatformTheme::ColorGroup>; |
401 | using ColorChangedEvent = PropertyChangedEvent<QColor>; |
402 | using FontChangedEvent = PropertyChangedEvent<QFont>; |
403 | |
404 | } |
405 | |
406 | } |
407 | } // namespace Kirigami |
408 | |
409 | #endif // PLATFORMTHEME_H |
410 | |