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 
DeclarativeTheme3D(QObject * parent)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(this, &Q3DTheme::typeChanged, this, &DeclarativeTheme3D::handleTypeChange);
44 }
45 
~DeclarativeTheme3D()46 DeclarativeTheme3D::~DeclarativeTheme3D()
47 {
48 }
49 
themeChildren()50 QQmlListProperty<QObject> DeclarativeTheme3D::themeChildren()
51 {
52     return QQmlListProperty<QObject>(this, this, &DeclarativeTheme3D::appendThemeChildren,
53                                      0, 0, 0);
54 }
55 
appendThemeChildren(QQmlListProperty<QObject> * list,QObject * element)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 
handleTypeChange(Theme themeType)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(item, 0, this, 0);
71         m_colors.clear();
72     }
73     if (!m_gradients.isEmpty()) {
74         foreach (ColorGradient *item, m_gradients)
75             disconnect(item, 0, this, 0);
76         m_gradients.clear();
77     }
78 }
79 
handleBaseColorUpdate()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 *>(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(changed)->color();
95     // Set the changed list
96     Q3DTheme::setBaseColors(list);
97 }
98 
handleBaseGradientUpdate()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 *>(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 
handleSingleHLGradientUpdate()118 void DeclarativeTheme3D::handleSingleHLGradientUpdate()
119 {
120     if (m_singleHLGradient)
121         setThemeGradient(m_singleHLGradient, GradientTypeSingleHL);
122 }
123 
handleMultiHLGradientUpdate()124 void DeclarativeTheme3D::handleMultiHLGradientUpdate()
125 {
126     if (m_multiHLGradient)
127         setThemeGradient(m_multiHLGradient, GradientTypeMultiHL);
128 }
129 
setSingleHighlightGradient(ColorGradient * gradient)130 void DeclarativeTheme3D::setSingleHighlightGradient(ColorGradient *gradient)
131 {
132     // connect new / disconnect old
133     if (gradient != m_singleHLGradient) {
134         if (m_singleHLGradient)
135             QObject::disconnect(m_singleHLGradient, 0, this, 0);
136 
137         m_singleHLGradient = gradient;
138 
139         if (m_singleHLGradient) {
140             QObject::connect(m_singleHLGradient, &ColorGradient::updated, this,
141                              &DeclarativeTheme3D::handleSingleHLGradientUpdate);
142         }
143 
144         emit singleHighlightGradientChanged(m_singleHLGradient);
145     }
146 
147     if (m_singleHLGradient)
148         setThemeGradient(m_singleHLGradient, GradientTypeSingleHL);
149 }
150 
singleHighlightGradient() const151 ColorGradient *DeclarativeTheme3D::singleHighlightGradient() const
152 {
153     return m_singleHLGradient;
154 }
155 
setMultiHighlightGradient(ColorGradient * gradient)156 void DeclarativeTheme3D::setMultiHighlightGradient(ColorGradient *gradient)
157 {
158     // connect new / disconnect old
159     if (gradient != m_multiHLGradient) {
160         if (m_multiHLGradient)
161             QObject::disconnect(m_multiHLGradient, 0, this, 0);
162 
163         m_multiHLGradient = gradient;
164 
165         if (m_multiHLGradient) {
166             QObject::connect(m_multiHLGradient, &ColorGradient::updated, this,
167                              &DeclarativeTheme3D::handleMultiHLGradientUpdate);
168         }
169 
170         emit multiHighlightGradientChanged(m_multiHLGradient);
171     }
172 
173     if (m_multiHLGradient)
174         setThemeGradient(m_multiHLGradient, GradientTypeMultiHL);
175 }
176 
multiHighlightGradient() const177 ColorGradient *DeclarativeTheme3D::multiHighlightGradient() const
178 {
179     return m_multiHLGradient;
180 }
181 
classBegin()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 
componentComplete()189 void DeclarativeTheme3D::componentComplete()
190 {
191     d_ptr->setForcePredefinedType(true);
192 }
193 
194 
setThemeGradient(ColorGradient * gradient,GradientType type)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("Incorrect usage. Type may be GradientTypeSingleHL or GradientTypeMultiHL.");
208         break;
209     }
210 }
211 
convertGradient(ColorGradient * gradient)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(j).first < qmlstops[i]->position())
222             j++;
223         stops.insert(j, QGradientStop(qmlstops.at(i)->position(), qmlstops.at(i)->color()));
224     }
225 
226     newGradient.setStops(stops);
227 
228     return newGradient;
229 }
230 
convertGradient(const QLinearGradient & gradient)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(qmlstop);
243     }
244 
245     return newGradient;
246 }
247 
addColor(DeclarativeColor * color)248 void DeclarativeTheme3D::addColor(DeclarativeColor *color)
249 {
250     if (!color) {
251         qWarning("Color is invalid, use ThemeColor");
252         return;
253     }
254     clearDummyColors();
255     m_colors.append(color);
256     connect(color, &DeclarativeColor::colorChanged,
257             this, &DeclarativeTheme3D::handleBaseColorUpdate);
258     QList<QColor> list = Q3DTheme::baseColors();
259     list.append(color->color());
260     Q3DTheme::setBaseColors(list);
261 }
262 
colorList()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(color);
273             connect(color, &DeclarativeColor::colorChanged,
274                     this, &DeclarativeTheme3D::handleBaseColorUpdate);
275         }
276     }
277     return m_colors;
278 }
279 
clearColors()280 void DeclarativeTheme3D::clearColors()
281 {
282     clearDummyColors();
283     foreach (DeclarativeColor *item, m_colors)
284         disconnect(item, 0, this, 0);
285     m_colors.clear();
286     Q3DTheme::setBaseColors(QList<QColor>());
287 }
288 
clearDummyColors()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 
addGradient(ColorGradient * gradient)299 void DeclarativeTheme3D::addGradient(ColorGradient *gradient)
300 {
301     if (!gradient) {
302         qWarning("Gradient is invalid, use ColorGradient");
303         return;
304     }
305     clearDummyGradients();
306     m_gradients.append(gradient);
307     connect(gradient, &ColorGradient::updated,
308             this, &DeclarativeTheme3D::handleBaseGradientUpdate);
309     QList<QLinearGradient> list = Q3DTheme::baseGradients();
310     list.append(convertGradient(gradient));
311     Q3DTheme::setBaseGradients(list);
312 }
313 
gradientList()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(item);
322             m_gradients.append(gradient);
323             connect(gradient, &ColorGradient::updated,
324                     this, &DeclarativeTheme3D::handleBaseGradientUpdate);
325         }
326     }
327 
328     return m_gradients;
329 }
330 
clearGradients()331 void DeclarativeTheme3D::clearGradients()
332 {
333     clearDummyGradients();
334     foreach (ColorGradient *item, m_gradients)
335         disconnect(item, 0, this, 0);
336     m_gradients.clear();
337     Q3DTheme::setBaseGradients(QList<QLinearGradient>());
338 }
339 
clearDummyGradients()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 
baseColors()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 
appendBaseColorsFunc(QQmlListProperty<DeclarativeColor> * list,DeclarativeColor * color)359 void DeclarativeTheme3D::appendBaseColorsFunc(QQmlListProperty<DeclarativeColor> *list,
360                                               DeclarativeColor *color)
361 {
362     reinterpret_cast<DeclarativeTheme3D *>(list->data)->addColor(color);
363 }
364 
countBaseColorsFunc(QQmlListProperty<DeclarativeColor> * list)365 int DeclarativeTheme3D::countBaseColorsFunc(QQmlListProperty<DeclarativeColor> *list)
366 {
367     return reinterpret_cast<DeclarativeTheme3D *>(list->data)->colorList().size();
368 }
369 
atBaseColorsFunc(QQmlListProperty<DeclarativeColor> * list,int index)370 DeclarativeColor *DeclarativeTheme3D::atBaseColorsFunc(QQmlListProperty<DeclarativeColor> *list,
371                                                        int index)
372 {
373     return reinterpret_cast<DeclarativeTheme3D *>(list->data)->colorList().at(index);
374 }
375 
clearBaseColorsFunc(QQmlListProperty<DeclarativeColor> * list)376 void DeclarativeTheme3D::clearBaseColorsFunc(QQmlListProperty<DeclarativeColor> *list)
377 {
378     reinterpret_cast<DeclarativeTheme3D *>(list->data)->clearColors();
379 }
380 
baseGradients()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 
appendBaseGradientsFunc(QQmlListProperty<ColorGradient> * list,ColorGradient * gradient)390 void DeclarativeTheme3D::appendBaseGradientsFunc(QQmlListProperty<ColorGradient> *list,
391                                                  ColorGradient *gradient)
392 {
393     reinterpret_cast<DeclarativeTheme3D *>(list->data)->addGradient(gradient);
394 }
395 
countBaseGradientsFunc(QQmlListProperty<ColorGradient> * list)396 int DeclarativeTheme3D::countBaseGradientsFunc(QQmlListProperty<ColorGradient> *list)
397 {
398     return reinterpret_cast<DeclarativeTheme3D *>(list->data)->gradientList().size();
399 }
400 
atBaseGradientsFunc(QQmlListProperty<ColorGradient> * list,int index)401 ColorGradient *DeclarativeTheme3D::atBaseGradientsFunc(QQmlListProperty<ColorGradient> *list,
402                                                        int index)
403 {
404     return reinterpret_cast<DeclarativeTheme3D *>(list->data)->gradientList().at(index);
405 }
406 
clearBaseGradientsFunc(QQmlListProperty<ColorGradient> * list)407 void DeclarativeTheme3D::clearBaseGradientsFunc(QQmlListProperty<ColorGradient> *list)
408 {
409     reinterpret_cast<DeclarativeTheme3D *>(list->data)->clearGradients();
410 }
411 
412 QT_END_NAMESPACE_DATAVISUALIZATION
413