1 /*
2     SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
3     SPDX-FileCopyrightText: 2011 Artur Duque de Souza <asouza@kde.org>
4     SPDX-FileCopyrightText: 2013 Sebastian Kügler <sebas@kde.org>
5 
6     SPDX-License-Identifier: GPL-2.0-or-later
7 */
8 
9 #include "colorscope.h"
10 
11 #include <QColor>
12 #include <QQmlContext>
13 #include <QQmlEngine>
14 #include <QQuickWindow>
15 
16 #include <PlasmaQuick/AppletQuickItem>
17 
18 QHash<QObject *, ColorScope *> ColorScope::s_attachedScopes = QHash<QObject *, ColorScope *>();
19 
20 QWeakPointer<Plasma::Theme> ColorScope::s_theme;
21 
ColorScope(QQuickItem * parent,QObject * parentObject)22 ColorScope::ColorScope(QQuickItem *parent, QObject *parentObject)
23     : QQuickItem(parent)
24     , m_inherit(false)
25     , m_group(Plasma::Theme::NormalColorGroup)
26     , m_parent(parentObject)
27     , m_actualGroup(Plasma::Theme::NormalColorGroup)
28 {
29     m_theme = s_theme.toStrongRef();
30     if (!m_theme) {
31         QSharedPointer<Plasma::Theme> themePtr(new Plasma::Theme);
32         s_theme = themePtr;
33         m_theme = s_theme.toStrongRef();
34     }
35 
36     connect(m_theme.data(), &Plasma::Theme::themeChanged, this, &ColorScope::colorsChanged);
37 
38     connect(this, &ColorScope::colorGroupChanged, this, &ColorScope::colorsChanged);
39 
40     if (parentObject && qobject_cast<QQuickItem *>(parentObject)) {
41         connect(static_cast<QQuickItem *>(parentObject), &QQuickItem::windowChanged, this, [this]() {
42             findParentScope();
43             checkColorGroupChanged();
44         });
45 
46         connect(static_cast<QQuickItem *>(parentObject), &QQuickItem::parentChanged, this, [this]() {
47             findParentScope();
48             checkColorGroupChanged();
49         });
50     } else if (parent) {
51         connect(parent, &QQuickItem::parentChanged, this, &ColorScope::checkColorGroupChanged);
52     }
53 }
54 
~ColorScope()55 ColorScope::~ColorScope()
56 {
57     m_deleting = true;
58     s_attachedScopes.remove(m_parent);
59 }
60 
qmlAttachedProperties(QObject * object)61 ColorScope *ColorScope::qmlAttachedProperties(QObject *object)
62 {
63     const auto cs = s_attachedScopes.value(object);
64     if (cs) {
65         return cs;
66     }
67 
68     ColorScope *s = new ColorScope(nullptr, object);
69     s_attachedScopes[object] = s;
70     s->m_inherit = true;
71     s->setParent(object);
72     s->checkColorGroupChanged();
73 
74     return s;
75 }
76 
setParentScope(ColorScope * parentScope)77 void ColorScope::setParentScope(ColorScope *parentScope)
78 {
79     if (parentScope == m_parentScope) {
80         return;
81     }
82 
83     if (m_parentScope) {
84         disconnect(m_parentScope.data(), &ColorScope::colorGroupChanged, this, &ColorScope::checkColorGroupChanged);
85     }
86 
87     m_parentScope = parentScope;
88 
89     if (parentScope) {
90         connect(parentScope, &ColorScope::colorGroupChanged, this, &ColorScope::checkColorGroupChanged);
91     }
92 }
93 
findParentScope()94 ColorScope *ColorScope::findParentScope()
95 {
96     QObject *candidate = parentItem();
97     if (!candidate) {
98         candidate = parent();
99     }
100 
101     while (candidate) {
102         auto *quickCandidate = qobject_cast<QQuickItem *>(candidate);
103         if (quickCandidate && quickCandidate->parentItem()) {
104             candidate = quickCandidate->parentItem();
105         } else {
106             candidate = candidate->parent();
107         }
108 
109         ColorScope *s = qobject_cast<ColorScope *>(candidate);
110         if (!s) {
111             // Make sure AppletInterface always has a ColorScope
112             s = static_cast<ColorScope *>(qmlAttachedPropertiesObject<ColorScope>(candidate, qobject_cast<PlasmaQuick::AppletQuickItem *>(candidate)));
113         }
114         if (s && !s->m_deleting) {
115             setParentScope(s);
116             return s;
117         }
118     }
119 
120     return nullptr;
121 }
122 
setColorGroup(Plasma::Theme::ColorGroup group)123 void ColorScope::setColorGroup(Plasma::Theme::ColorGroup group)
124 {
125     if (m_group == group) {
126         return;
127     }
128 
129     m_group = group;
130 
131     checkColorGroupChanged();
132 }
133 
colorGroup() const134 Plasma::Theme::ColorGroup ColorScope::colorGroup() const
135 {
136     return m_actualGroup;
137 }
138 
textColor() const139 QColor ColorScope::textColor() const
140 {
141     return m_theme->color(Plasma::Theme::TextColor, colorGroup());
142 }
143 
highlightColor() const144 QColor ColorScope::highlightColor() const
145 {
146     return m_theme->color(Plasma::Theme::HighlightColor, colorGroup());
147 }
148 
highlightedTextColor() const149 QColor ColorScope::highlightedTextColor() const
150 {
151     return m_theme->color(Plasma::Theme::HighlightedTextColor, colorGroup());
152 }
153 
backgroundColor() const154 QColor ColorScope::backgroundColor() const
155 {
156     return m_theme->color(Plasma::Theme::BackgroundColor, colorGroup());
157 }
158 
positiveTextColor() const159 QColor ColorScope::positiveTextColor() const
160 {
161     return m_theme->color(Plasma::Theme::PositiveTextColor, colorGroup());
162 }
163 
neutralTextColor() const164 QColor ColorScope::neutralTextColor() const
165 {
166     return m_theme->color(Plasma::Theme::NeutralTextColor, colorGroup());
167 }
168 
negativeTextColor() const169 QColor ColorScope::negativeTextColor() const
170 {
171     return m_theme->color(Plasma::Theme::NegativeTextColor, colorGroup());
172 }
173 
disabledTextColor() const174 QColor ColorScope::disabledTextColor() const
175 {
176     return m_theme->color(Plasma::Theme::DisabledTextColor, colorGroup());
177 }
178 
inherit() const179 bool ColorScope::inherit() const
180 {
181     return m_inherit;
182 }
183 
setInherit(bool inherit)184 void ColorScope::setInherit(bool inherit)
185 {
186     if (m_inherit == inherit) {
187         return;
188     }
189     m_inherit = inherit;
190     Q_EMIT inheritChanged();
191     checkColorGroupChanged();
192 }
193 
itemChange(ItemChange change,const ItemChangeData & value)194 void ColorScope::itemChange(ItemChange change, const ItemChangeData &value)
195 {
196     if (change == QQuickItem::ItemSceneChange) {
197         // we have a window: create the representations if needed
198         if (value.window) {
199             findParentScope();
200             checkColorGroupChanged();
201         }
202     }
203 
204     QQuickItem::itemChange(change, value);
205 }
206 
checkColorGroupChanged()207 void ColorScope::checkColorGroupChanged()
208 {
209     const auto last = m_actualGroup;
210     if (m_inherit) {
211         findParentScope();
212         m_actualGroup = m_parentScope ? m_parentScope->colorGroup() : m_group;
213     } else {
214         m_actualGroup = m_group;
215     }
216 
217     if (m_actualGroup != last) {
218         Q_EMIT colorGroupChanged();
219     }
220 }
221 
222 #include "moc_colorscope.cpp"
223