1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Data Visualization module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 or (at your option) any later version |
20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by |
21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 |
22 | ** included in the packaging of this file. Please review the following |
23 | ** information to ensure the GNU General Public License requirements will |
24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
25 | ** |
26 | ** $QT_END_LICENSE$ |
27 | ** |
28 | ****************************************************************************/ |
29 | |
30 | #include "declarativetheme_p.h" |
31 | |
32 | QT_BEGIN_NAMESPACE_DATAVISUALIZATION |
33 | |
34 | DeclarativeTheme3D::DeclarativeTheme3D(QObject *parent) |
35 | : Q3DTheme(parent), |
36 | m_colors(QList<DeclarativeColor *>()), |
37 | m_gradients(QList<ColorGradient *>()), |
38 | m_singleHLGradient(0), |
39 | m_multiHLGradient(0), |
40 | m_dummyGradients(false), |
41 | m_dummyColors(false) |
42 | { |
43 | connect(sender: this, signal: &Q3DTheme::typeChanged, receiver: this, slot: &DeclarativeTheme3D::handleTypeChange); |
44 | } |
45 | |
46 | DeclarativeTheme3D::~DeclarativeTheme3D() |
47 | { |
48 | } |
49 | |
50 | QQmlListProperty<QObject> DeclarativeTheme3D::themeChildren() |
51 | { |
52 | return QQmlListProperty<QObject>(this, this, &DeclarativeTheme3D::appendThemeChildren, |
53 | 0, 0, 0); |
54 | } |
55 | |
56 | void DeclarativeTheme3D::appendThemeChildren(QQmlListProperty<QObject> *list, QObject *element) |
57 | { |
58 | Q_UNUSED(list) |
59 | Q_UNUSED(element) |
60 | // Nothing to do, themeChildren is there only to enable scoping gradient items in Theme3D item. |
61 | } |
62 | |
63 | void DeclarativeTheme3D::handleTypeChange(Theme themeType) |
64 | { |
65 | Q_UNUSED(themeType) |
66 | |
67 | // Theme changed, disconnect base color/gradient connections |
68 | if (!m_colors.isEmpty()) { |
69 | foreach (DeclarativeColor *item, m_colors) |
70 | disconnect(sender: item, signal: 0, receiver: this, member: 0); |
71 | m_colors.clear(); |
72 | } |
73 | if (!m_gradients.isEmpty()) { |
74 | foreach (ColorGradient *item, m_gradients) |
75 | disconnect(sender: item, signal: 0, receiver: this, member: 0); |
76 | m_gradients.clear(); |
77 | } |
78 | } |
79 | |
80 | void DeclarativeTheme3D::handleBaseColorUpdate() |
81 | { |
82 | int colorCount = m_colors.size(); |
83 | int changed = 0; |
84 | // Check which one changed |
85 | DeclarativeColor *color = qobject_cast<DeclarativeColor *>(object: QObject::sender()); |
86 | for (int i = 0; i < colorCount; i++) { |
87 | if (color == m_colors.at(i)) { |
88 | changed = i; |
89 | break; |
90 | } |
91 | } |
92 | // Update the changed one from the list |
93 | QList<QColor> list = Q3DTheme::baseColors(); |
94 | list[changed] = m_colors.at(i: changed)->color(); |
95 | // Set the changed list |
96 | Q3DTheme::setBaseColors(list); |
97 | } |
98 | |
99 | void DeclarativeTheme3D::handleBaseGradientUpdate() |
100 | { |
101 | int gradientCount = m_gradients.size(); |
102 | int changed = 0; |
103 | // Check which one changed |
104 | ColorGradient *gradient = qobject_cast<ColorGradient *>(object: QObject::sender()); |
105 | for (int i = 0; i < gradientCount; i++) { |
106 | if (gradient == m_gradients.at(i)) { |
107 | changed = i; |
108 | break; |
109 | } |
110 | } |
111 | // Update the changed one from the list |
112 | QList<QLinearGradient> list = Q3DTheme::baseGradients(); |
113 | list[changed] = convertGradient(gradient); |
114 | // Set the changed list |
115 | Q3DTheme::setBaseGradients(list); |
116 | } |
117 | |
118 | void DeclarativeTheme3D::handleSingleHLGradientUpdate() |
119 | { |
120 | if (m_singleHLGradient) |
121 | setThemeGradient(gradient: m_singleHLGradient, type: GradientTypeSingleHL); |
122 | } |
123 | |
124 | void DeclarativeTheme3D::handleMultiHLGradientUpdate() |
125 | { |
126 | if (m_multiHLGradient) |
127 | setThemeGradient(gradient: m_multiHLGradient, type: GradientTypeMultiHL); |
128 | } |
129 | |
130 | void DeclarativeTheme3D::setSingleHighlightGradient(ColorGradient *gradient) |
131 | { |
132 | // connect new / disconnect old |
133 | if (gradient != m_singleHLGradient) { |
134 | if (m_singleHLGradient) |
135 | QObject::disconnect(sender: m_singleHLGradient, signal: 0, receiver: this, member: 0); |
136 | |
137 | m_singleHLGradient = gradient; |
138 | |
139 | if (m_singleHLGradient) { |
140 | QObject::connect(sender: m_singleHLGradient, signal: &ColorGradient::updated, receiver: this, |
141 | slot: &DeclarativeTheme3D::handleSingleHLGradientUpdate); |
142 | } |
143 | |
144 | emit singleHighlightGradientChanged(gradient: m_singleHLGradient); |
145 | } |
146 | |
147 | if (m_singleHLGradient) |
148 | setThemeGradient(gradient: m_singleHLGradient, type: GradientTypeSingleHL); |
149 | } |
150 | |
151 | ColorGradient *DeclarativeTheme3D::singleHighlightGradient() const |
152 | { |
153 | return m_singleHLGradient; |
154 | } |
155 | |
156 | void DeclarativeTheme3D::setMultiHighlightGradient(ColorGradient *gradient) |
157 | { |
158 | // connect new / disconnect old |
159 | if (gradient != m_multiHLGradient) { |
160 | if (m_multiHLGradient) |
161 | QObject::disconnect(sender: m_multiHLGradient, signal: 0, receiver: this, member: 0); |
162 | |
163 | m_multiHLGradient = gradient; |
164 | |
165 | if (m_multiHLGradient) { |
166 | QObject::connect(sender: m_multiHLGradient, signal: &ColorGradient::updated, receiver: this, |
167 | slot: &DeclarativeTheme3D::handleMultiHLGradientUpdate); |
168 | } |
169 | |
170 | emit multiHighlightGradientChanged(gradient: m_multiHLGradient); |
171 | } |
172 | |
173 | if (m_multiHLGradient) |
174 | setThemeGradient(gradient: m_multiHLGradient, type: GradientTypeMultiHL); |
175 | } |
176 | |
177 | ColorGradient *DeclarativeTheme3D::multiHighlightGradient() const |
178 | { |
179 | return m_multiHLGradient; |
180 | } |
181 | |
182 | void DeclarativeTheme3D::classBegin() |
183 | { |
184 | // Turn off predefined type forcing for the duration of initial class construction |
185 | // so that predefined type customization can be done. |
186 | d_ptr->setForcePredefinedType(false); |
187 | } |
188 | |
189 | void DeclarativeTheme3D::componentComplete() |
190 | { |
191 | d_ptr->setForcePredefinedType(true); |
192 | } |
193 | |
194 | |
195 | void DeclarativeTheme3D::setThemeGradient(ColorGradient *gradient, GradientType type) |
196 | { |
197 | QLinearGradient newGradient = convertGradient(gradient); |
198 | |
199 | switch (type) { |
200 | case GradientTypeSingleHL: |
201 | Q3DTheme::setSingleHighlightGradient(newGradient); |
202 | break; |
203 | case GradientTypeMultiHL: |
204 | Q3DTheme::setMultiHighlightGradient(newGradient); |
205 | break; |
206 | default: |
207 | qWarning(msg: "Incorrect usage. Type may be GradientTypeSingleHL or GradientTypeMultiHL." ); |
208 | break; |
209 | } |
210 | } |
211 | |
212 | QLinearGradient DeclarativeTheme3D::convertGradient(ColorGradient *gradient) |
213 | { |
214 | QLinearGradient newGradient; |
215 | QGradientStops stops; |
216 | QList<ColorGradientStop *> qmlstops = gradient->m_stops; |
217 | |
218 | // Get sorted gradient stops |
219 | for (int i = 0; i < qmlstops.size(); i++) { |
220 | int j = 0; |
221 | while (j < stops.size() && stops.at(i: j).first < qmlstops[i]->position()) |
222 | j++; |
223 | stops.insert(i: j, t: QGradientStop(qmlstops.at(i)->position(), qmlstops.at(i)->color())); |
224 | } |
225 | |
226 | newGradient.setStops(stops); |
227 | |
228 | return newGradient; |
229 | } |
230 | |
231 | ColorGradient *DeclarativeTheme3D::convertGradient(const QLinearGradient &gradient) |
232 | { |
233 | ColorGradient *newGradient = new ColorGradient(this); |
234 | QGradientStops stops = gradient.stops(); |
235 | ColorGradientStop *qmlstop; |
236 | |
237 | // Convert stops |
238 | for (int i = 0; i < stops.size(); i++) { |
239 | qmlstop = new ColorGradientStop(newGradient); |
240 | qmlstop->setColor(stops.at(i).second); |
241 | qmlstop->setPosition(stops.at(i).first); |
242 | newGradient->m_stops.append(t: qmlstop); |
243 | } |
244 | |
245 | return newGradient; |
246 | } |
247 | |
248 | void DeclarativeTheme3D::addColor(DeclarativeColor *color) |
249 | { |
250 | if (!color) { |
251 | qWarning(msg: "Color is invalid, use ThemeColor" ); |
252 | return; |
253 | } |
254 | clearDummyColors(); |
255 | m_colors.append(t: color); |
256 | connect(sender: color, signal: &DeclarativeColor::colorChanged, |
257 | receiver: this, slot: &DeclarativeTheme3D::handleBaseColorUpdate); |
258 | QList<QColor> list = Q3DTheme::baseColors(); |
259 | list.append(t: color->color()); |
260 | Q3DTheme::setBaseColors(list); |
261 | } |
262 | |
263 | QList<DeclarativeColor *> DeclarativeTheme3D::colorList() |
264 | { |
265 | if (m_colors.isEmpty()) { |
266 | // Create dummy ThemeColors from theme's colors |
267 | m_dummyColors = true; |
268 | QList<QColor> list = Q3DTheme::baseColors(); |
269 | foreach (QColor item, list) { |
270 | DeclarativeColor *color = new DeclarativeColor(this); |
271 | color->setColor(item); |
272 | m_colors.append(t: color); |
273 | connect(sender: color, signal: &DeclarativeColor::colorChanged, |
274 | receiver: this, slot: &DeclarativeTheme3D::handleBaseColorUpdate); |
275 | } |
276 | } |
277 | return m_colors; |
278 | } |
279 | |
280 | void DeclarativeTheme3D::clearColors() |
281 | { |
282 | clearDummyColors(); |
283 | foreach (DeclarativeColor *item, m_colors) |
284 | disconnect(sender: item, signal: 0, receiver: this, member: 0); |
285 | m_colors.clear(); |
286 | Q3DTheme::setBaseColors(QList<QColor>()); |
287 | } |
288 | |
289 | void DeclarativeTheme3D::clearDummyColors() |
290 | { |
291 | if (m_dummyColors) { |
292 | foreach (DeclarativeColor *item, m_colors) |
293 | delete item; |
294 | m_colors.clear(); |
295 | m_dummyColors = false; |
296 | } |
297 | } |
298 | |
299 | void DeclarativeTheme3D::addGradient(ColorGradient *gradient) |
300 | { |
301 | if (!gradient) { |
302 | qWarning(msg: "Gradient is invalid, use ColorGradient" ); |
303 | return; |
304 | } |
305 | clearDummyGradients(); |
306 | m_gradients.append(t: gradient); |
307 | connect(sender: gradient, signal: &ColorGradient::updated, |
308 | receiver: this, slot: &DeclarativeTheme3D::handleBaseGradientUpdate); |
309 | QList<QLinearGradient> list = Q3DTheme::baseGradients(); |
310 | list.append(t: convertGradient(gradient)); |
311 | Q3DTheme::setBaseGradients(list); |
312 | } |
313 | |
314 | QList<ColorGradient *> DeclarativeTheme3D::gradientList() |
315 | { |
316 | if (m_gradients.isEmpty()) { |
317 | // Create dummy ColorGradients from theme's gradients |
318 | m_dummyGradients = true; |
319 | QList<QLinearGradient> list = Q3DTheme::baseGradients(); |
320 | foreach (QLinearGradient item, list) { |
321 | ColorGradient *gradient = convertGradient(gradient: item); |
322 | m_gradients.append(t: gradient); |
323 | connect(sender: gradient, signal: &ColorGradient::updated, |
324 | receiver: this, slot: &DeclarativeTheme3D::handleBaseGradientUpdate); |
325 | } |
326 | } |
327 | |
328 | return m_gradients; |
329 | } |
330 | |
331 | void DeclarativeTheme3D::clearGradients() |
332 | { |
333 | clearDummyGradients(); |
334 | foreach (ColorGradient *item, m_gradients) |
335 | disconnect(sender: item, signal: 0, receiver: this, member: 0); |
336 | m_gradients.clear(); |
337 | Q3DTheme::setBaseGradients(QList<QLinearGradient>()); |
338 | } |
339 | |
340 | void DeclarativeTheme3D::clearDummyGradients() |
341 | { |
342 | if (m_dummyGradients) { |
343 | foreach (ColorGradient *item, m_gradients) |
344 | delete item; |
345 | m_gradients.clear(); |
346 | m_dummyGradients = false; |
347 | } |
348 | } |
349 | |
350 | QQmlListProperty<DeclarativeColor> DeclarativeTheme3D::baseColors() |
351 | { |
352 | return QQmlListProperty<DeclarativeColor>(this, this, |
353 | &DeclarativeTheme3D::appendBaseColorsFunc, |
354 | &DeclarativeTheme3D::countBaseColorsFunc, |
355 | &DeclarativeTheme3D::atBaseColorsFunc, |
356 | &DeclarativeTheme3D::clearBaseColorsFunc); |
357 | } |
358 | |
359 | void DeclarativeTheme3D::appendBaseColorsFunc(QQmlListProperty<DeclarativeColor> *list, |
360 | DeclarativeColor *color) |
361 | { |
362 | reinterpret_cast<DeclarativeTheme3D *>(list->data)->addColor(color); |
363 | } |
364 | |
365 | int DeclarativeTheme3D::countBaseColorsFunc(QQmlListProperty<DeclarativeColor> *list) |
366 | { |
367 | return reinterpret_cast<DeclarativeTheme3D *>(list->data)->colorList().size(); |
368 | } |
369 | |
370 | DeclarativeColor *DeclarativeTheme3D::atBaseColorsFunc(QQmlListProperty<DeclarativeColor> *list, |
371 | int index) |
372 | { |
373 | return reinterpret_cast<DeclarativeTheme3D *>(list->data)->colorList().at(i: index); |
374 | } |
375 | |
376 | void DeclarativeTheme3D::clearBaseColorsFunc(QQmlListProperty<DeclarativeColor> *list) |
377 | { |
378 | reinterpret_cast<DeclarativeTheme3D *>(list->data)->clearColors(); |
379 | } |
380 | |
381 | QQmlListProperty<ColorGradient> DeclarativeTheme3D::baseGradients() |
382 | { |
383 | return QQmlListProperty<ColorGradient>(this, this, |
384 | &DeclarativeTheme3D::appendBaseGradientsFunc, |
385 | &DeclarativeTheme3D::countBaseGradientsFunc, |
386 | &DeclarativeTheme3D::atBaseGradientsFunc, |
387 | &DeclarativeTheme3D::clearBaseGradientsFunc); |
388 | } |
389 | |
390 | void DeclarativeTheme3D::appendBaseGradientsFunc(QQmlListProperty<ColorGradient> *list, |
391 | ColorGradient *gradient) |
392 | { |
393 | reinterpret_cast<DeclarativeTheme3D *>(list->data)->addGradient(gradient); |
394 | } |
395 | |
396 | int DeclarativeTheme3D::countBaseGradientsFunc(QQmlListProperty<ColorGradient> *list) |
397 | { |
398 | return reinterpret_cast<DeclarativeTheme3D *>(list->data)->gradientList().size(); |
399 | } |
400 | |
401 | ColorGradient *DeclarativeTheme3D::atBaseGradientsFunc(QQmlListProperty<ColorGradient> *list, |
402 | int index) |
403 | { |
404 | return reinterpret_cast<DeclarativeTheme3D *>(list->data)->gradientList().at(i: index); |
405 | } |
406 | |
407 | void DeclarativeTheme3D::clearBaseGradientsFunc(QQmlListProperty<ColorGradient> *list) |
408 | { |
409 | reinterpret_cast<DeclarativeTheme3D *>(list->data)->clearGradients(); |
410 | } |
411 | |
412 | QT_END_NAMESPACE_DATAVISUALIZATION |
413 | |