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