##// END OF EJS Templates
Add support for reversed axis when useOpenGL is true...
Andy Shaw -
r2863:15eed6371853
parent child
Show More
@@ -1,650 +1,657
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
4 ** Contact: https://www.qt.io/licensing/
5 **
5 **
6 ** This file is part of the Qt Charts module of the Qt Toolkit.
6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 **
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
8 ** $QT_BEGIN_LICENSE:GPL$
9 ** Commercial License Usage
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
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
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.
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
16 **
17 ** GNU General Public License Usage
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
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
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
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
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
25 **
26 ** $QT_END_LICENSE$
26 ** $QT_END_LICENSE$
27 **
27 **
28 ****************************************************************************/
28 ****************************************************************************/
29
29
30 #include <private/chartdataset_p.h>
30 #include <private/chartdataset_p.h>
31 #include <private/chartpresenter_p.h>
31 #include <private/chartpresenter_p.h>
32 #include <QtCharts/QChart>
32 #include <QtCharts/QChart>
33 #include <private/qchart_p.h>
33 #include <private/qchart_p.h>
34 #include <QtCharts/QValueAxis>
34 #include <QtCharts/QValueAxis>
35 #include <QtCharts/QBarCategoryAxis>
35 #include <QtCharts/QBarCategoryAxis>
36 #include <private/qvalueaxis_p.h>
36 #include <private/qvalueaxis_p.h>
37 #include <QtCharts/QCategoryAxis>
37 #include <QtCharts/QCategoryAxis>
38 #include <private/qabstractseries_p.h>
38 #include <private/qabstractseries_p.h>
39 #include <QtCharts/QAbstractBarSeries>
39 #include <QtCharts/QAbstractBarSeries>
40 #include <QtCharts/QStackedBarSeries>
40 #include <QtCharts/QStackedBarSeries>
41 #include <QtCharts/QPercentBarSeries>
41 #include <QtCharts/QPercentBarSeries>
42 #include <QtCharts/QPieSeries>
42 #include <QtCharts/QPieSeries>
43 #include <private/chartitem_p.h>
43 #include <private/chartitem_p.h>
44 #include <private/xydomain_p.h>
44 #include <private/xydomain_p.h>
45 #include <private/xypolardomain_p.h>
45 #include <private/xypolardomain_p.h>
46 #include <private/xlogydomain_p.h>
46 #include <private/xlogydomain_p.h>
47 #include <private/logxydomain_p.h>
47 #include <private/logxydomain_p.h>
48 #include <private/logxlogydomain_p.h>
48 #include <private/logxlogydomain_p.h>
49 #include <private/xlogypolardomain_p.h>
49 #include <private/xlogypolardomain_p.h>
50 #include <private/logxypolardomain_p.h>
50 #include <private/logxypolardomain_p.h>
51 #include <private/logxlogypolardomain_p.h>
51 #include <private/logxlogypolardomain_p.h>
52 #include <private/glxyseriesdata_p.h>
52 #include <private/glxyseriesdata_p.h>
53
53
54 #ifndef QT_QREAL_IS_FLOAT
54 #ifndef QT_QREAL_IS_FLOAT
55 #include <QtCharts/QDateTimeAxis>
55 #include <QtCharts/QDateTimeAxis>
56 #endif
56 #endif
57
57
58 QT_CHARTS_BEGIN_NAMESPACE
58 QT_CHARTS_BEGIN_NAMESPACE
59
59
60 ChartDataSet::ChartDataSet(QChart *chart)
60 ChartDataSet::ChartDataSet(QChart *chart)
61 : QObject(chart),
61 : QObject(chart),
62 m_chart(chart),
62 m_chart(chart),
63 m_glXYSeriesDataManager(new GLXYSeriesDataManager(this))
63 m_glXYSeriesDataManager(new GLXYSeriesDataManager(this))
64 {
64 {
65
65
66 }
66 }
67
67
68 ChartDataSet::~ChartDataSet()
68 ChartDataSet::~ChartDataSet()
69 {
69 {
70 deleteAllSeries();
70 deleteAllSeries();
71 deleteAllAxes();
71 deleteAllAxes();
72 }
72 }
73
73
74 /*
74 /*
75 * This method adds series to chartdataset, series ownership is taken from caller.
75 * This method adds series to chartdataset, series ownership is taken from caller.
76 */
76 */
77 void ChartDataSet::addSeries(QAbstractSeries *series)
77 void ChartDataSet::addSeries(QAbstractSeries *series)
78 {
78 {
79 if (m_seriesList.contains(series)) {
79 if (m_seriesList.contains(series)) {
80 qWarning() << QObject::tr("Can not add series. Series already on the chart.");
80 qWarning() << QObject::tr("Can not add series. Series already on the chart.");
81 return;
81 return;
82 }
82 }
83
83
84 // Ignore unsupported series added to polar chart
84 // Ignore unsupported series added to polar chart
85 if (m_chart && m_chart->chartType() == QChart::ChartTypePolar) {
85 if (m_chart && m_chart->chartType() == QChart::ChartTypePolar) {
86 if (!(series->type() == QAbstractSeries::SeriesTypeArea
86 if (!(series->type() == QAbstractSeries::SeriesTypeArea
87 || series->type() == QAbstractSeries::SeriesTypeLine
87 || series->type() == QAbstractSeries::SeriesTypeLine
88 || series->type() == QAbstractSeries::SeriesTypeScatter
88 || series->type() == QAbstractSeries::SeriesTypeScatter
89 || series->type() == QAbstractSeries::SeriesTypeSpline)) {
89 || series->type() == QAbstractSeries::SeriesTypeSpline)) {
90 qWarning() << QObject::tr("Can not add series. Series type is not supported by a polar chart.");
90 qWarning() << QObject::tr("Can not add series. Series type is not supported by a polar chart.");
91 return;
91 return;
92 }
92 }
93 // Disable OpenGL for series in polar charts
93 // Disable OpenGL for series in polar charts
94 series->setUseOpenGL(false);
94 series->setUseOpenGL(false);
95 series->d_ptr->setDomain(new XYPolarDomain());
95 series->d_ptr->setDomain(new XYPolarDomain());
96 // Set the correct domain for upper and lower series too
96 // Set the correct domain for upper and lower series too
97 if (series->type() == QAbstractSeries::SeriesTypeArea) {
97 if (series->type() == QAbstractSeries::SeriesTypeArea) {
98 foreach (QObject *child, series->children()) {
98 foreach (QObject *child, series->children()) {
99 if (qobject_cast<QAbstractSeries *>(child)) {
99 if (qobject_cast<QAbstractSeries *>(child)) {
100 QAbstractSeries *childSeries = qobject_cast<QAbstractSeries *>(child);
100 QAbstractSeries *childSeries = qobject_cast<QAbstractSeries *>(child);
101 childSeries->d_ptr->setDomain(new XYPolarDomain());
101 childSeries->d_ptr->setDomain(new XYPolarDomain());
102 }
102 }
103 }
103 }
104 }
104 }
105 } else {
105 } else {
106 series->d_ptr->setDomain(new XYDomain());
106 series->d_ptr->setDomain(new XYDomain());
107 }
107 }
108
108
109 series->d_ptr->initializeDomain();
109 series->d_ptr->initializeDomain();
110 m_seriesList.append(series);
110 m_seriesList.append(series);
111
111
112 series->setParent(this); // take ownership
112 series->setParent(this); // take ownership
113 series->d_ptr->m_chart = m_chart;
113 series->d_ptr->m_chart = m_chart;
114
114
115 emit seriesAdded(series);
115 emit seriesAdded(series);
116 }
116 }
117
117
118 /*
118 /*
119 * This method adds axis to chartdataset, axis ownership is taken from caller.
119 * This method adds axis to chartdataset, axis ownership is taken from caller.
120 */
120 */
121 void ChartDataSet::addAxis(QAbstractAxis *axis, Qt::Alignment aligment)
121 void ChartDataSet::addAxis(QAbstractAxis *axis, Qt::Alignment aligment)
122 {
122 {
123 if (m_axisList.contains(axis)) {
123 if (m_axisList.contains(axis)) {
124 qWarning() << QObject::tr("Can not add axis. Axis already on the chart.");
124 qWarning() << QObject::tr("Can not add axis. Axis already on the chart.");
125 return;
125 return;
126 }
126 }
127
127
128 axis->d_ptr->setAlignment(aligment);
128 axis->d_ptr->setAlignment(aligment);
129
129
130 if (!axis->alignment()) {
130 if (!axis->alignment()) {
131 qWarning() << QObject::tr("No alignment specified !");
131 qWarning() << QObject::tr("No alignment specified !");
132 return;
132 return;
133 };
133 };
134
134
135 AbstractDomain *newDomain;
135 AbstractDomain *newDomain;
136 if (m_chart && m_chart->chartType() == QChart::ChartTypePolar)
136 if (m_chart && m_chart->chartType() == QChart::ChartTypePolar)
137 newDomain = new XYPolarDomain();
137 newDomain = new XYPolarDomain();
138 else
138 else
139 newDomain = new XYDomain();
139 newDomain = new XYDomain();
140
140
141 QSharedPointer<AbstractDomain> domain(newDomain);
141 QSharedPointer<AbstractDomain> domain(newDomain);
142 axis->d_ptr->initializeDomain(domain.data());
142 axis->d_ptr->initializeDomain(domain.data());
143
143
144 axis->setParent(this);
144 axis->setParent(this);
145 axis->d_ptr->m_chart = m_chart;
145 axis->d_ptr->m_chart = m_chart;
146 m_axisList.append(axis);
146 m_axisList.append(axis);
147
147
148 emit axisAdded(axis);
148 emit axisAdded(axis);
149 }
149 }
150
150
151 /*
151 /*
152 * This method removes series form chartdataset, series ownership is passed back to caller.
152 * This method removes series form chartdataset, series ownership is passed back to caller.
153 */
153 */
154 void ChartDataSet::removeSeries(QAbstractSeries *series)
154 void ChartDataSet::removeSeries(QAbstractSeries *series)
155 {
155 {
156
156
157 if (! m_seriesList.contains(series)) {
157 if (! m_seriesList.contains(series)) {
158 qWarning() << QObject::tr("Can not remove series. Series not found on the chart.");
158 qWarning() << QObject::tr("Can not remove series. Series not found on the chart.");
159 return;
159 return;
160 }
160 }
161
161
162 QList<QAbstractAxis*> axes = series->d_ptr->m_axes;
162 QList<QAbstractAxis*> axes = series->d_ptr->m_axes;
163
163
164 foreach(QAbstractAxis* axis, axes) {
164 foreach(QAbstractAxis* axis, axes) {
165 detachAxis(series,axis);
165 detachAxis(series,axis);
166 }
166 }
167
167
168 emit seriesRemoved(series);
168 emit seriesRemoved(series);
169 m_seriesList.removeAll(series);
169 m_seriesList.removeAll(series);
170
170
171 // Reset domain to default
171 // Reset domain to default
172 series->d_ptr->setDomain(new XYDomain());
172 series->d_ptr->setDomain(new XYDomain());
173 series->setParent(0);
173 series->setParent(0);
174 series->d_ptr->m_chart = 0;
174 series->d_ptr->m_chart = 0;
175
175
176 QXYSeries *xySeries = qobject_cast<QXYSeries *>(series);
176 QXYSeries *xySeries = qobject_cast<QXYSeries *>(series);
177 if (xySeries)
177 if (xySeries)
178 m_glXYSeriesDataManager->removeSeries(xySeries);
178 m_glXYSeriesDataManager->removeSeries(xySeries);
179 }
179 }
180
180
181 /*
181 /*
182 * This method removes axis form chartdataset, series ownership is passed back to caller.
182 * This method removes axis form chartdataset, series ownership is passed back to caller.
183 */
183 */
184 void ChartDataSet::removeAxis(QAbstractAxis *axis)
184 void ChartDataSet::removeAxis(QAbstractAxis *axis)
185 {
185 {
186 if (! m_axisList.contains(axis)) {
186 if (! m_axisList.contains(axis)) {
187 qWarning() << QObject::tr("Can not remove axis. Axis not found on the chart.");
187 qWarning() << QObject::tr("Can not remove axis. Axis not found on the chart.");
188 return;
188 return;
189 }
189 }
190
190
191 QList<QAbstractSeries*> series = axis->d_ptr->m_series;
191 QList<QAbstractSeries*> series = axis->d_ptr->m_series;
192
192
193 foreach(QAbstractSeries* s, series) {
193 foreach(QAbstractSeries* s, series) {
194 detachAxis(s,axis);
194 detachAxis(s,axis);
195 }
195 }
196
196
197 emit axisRemoved(axis);
197 emit axisRemoved(axis);
198 m_axisList.removeAll(axis);
198 m_axisList.removeAll(axis);
199
199
200 axis->setParent(0);
200 axis->setParent(0);
201 axis->d_ptr->m_chart = 0;
201 axis->d_ptr->m_chart = 0;
202 }
202 }
203
203
204 /*
204 /*
205 * This method attaches axis to series, return true if success.
205 * This method attaches axis to series, return true if success.
206 */
206 */
207 bool ChartDataSet::attachAxis(QAbstractSeries *series,QAbstractAxis *axis)
207 bool ChartDataSet::attachAxis(QAbstractSeries *series,QAbstractAxis *axis)
208 {
208 {
209 Q_ASSERT(axis);
209 Q_ASSERT(axis);
210
210
211 if (!series)
211 if (!series)
212 return false;
212 return false;
213
213
214 QList<QAbstractSeries *> attachedSeriesList = axis->d_ptr->m_series;
214 QList<QAbstractSeries *> attachedSeriesList = axis->d_ptr->m_series;
215 QList<QAbstractAxis *> attachedAxisList = series->d_ptr->m_axes;
215 QList<QAbstractAxis *> attachedAxisList = series->d_ptr->m_axes;
216
216
217 if (!m_seriesList.contains(series)) {
217 if (!m_seriesList.contains(series)) {
218 qWarning() << QObject::tr("Can not find series on the chart.");
218 qWarning() << QObject::tr("Can not find series on the chart.");
219 return false;
219 return false;
220 }
220 }
221
221
222 if (axis && !m_axisList.contains(axis)) {
222 if (axis && !m_axisList.contains(axis)) {
223 qWarning() << QObject::tr("Can not find axis on the chart.");
223 qWarning() << QObject::tr("Can not find axis on the chart.");
224 return false;
224 return false;
225 }
225 }
226
226
227 if (attachedAxisList.contains(axis)) {
227 if (attachedAxisList.contains(axis)) {
228 qWarning() << QObject::tr("Axis already attached to series.");
228 qWarning() << QObject::tr("Axis already attached to series.");
229 return false;
229 return false;
230 }
230 }
231
231
232 if (attachedSeriesList.contains(series)) {
232 if (attachedSeriesList.contains(series)) {
233 qWarning() << QObject::tr("Axis already attached to series.");
233 qWarning() << QObject::tr("Axis already attached to series.");
234 return false;
234 return false;
235 }
235 }
236
236
237 AbstractDomain *domain = series->d_ptr->domain();
237 AbstractDomain *domain = series->d_ptr->domain();
238 AbstractDomain::DomainType type = selectDomain(attachedAxisList<<axis);
238 AbstractDomain::DomainType type = selectDomain(attachedAxisList<<axis);
239
239
240 if (type == AbstractDomain::UndefinedDomain) return false;
240 if (type == AbstractDomain::UndefinedDomain) return false;
241
241
242 if (domain->type() != type) {
242 if (domain->type() != type) {
243 AbstractDomain *old = domain;
243 AbstractDomain *old = domain;
244 domain = createDomain(type);
244 domain = createDomain(type);
245 domain->setRange(old->minX(), old->maxX(), old->minY(), old->maxY());
245 domain->setRange(old->minX(), old->maxX(), old->minY(), old->maxY());
246 // Initialize domain size to old domain size, as it won't get updated
246 // Initialize domain size to old domain size, as it won't get updated
247 // unless geometry changes.
247 // unless geometry changes.
248 domain->setSize(old->size());
248 domain->setSize(old->size());
249 }
249 }
250
250
251 if (!domain)
251 if (!domain)
252 return false;
252 return false;
253
253
254 if (!domain->attachAxis(axis))
254 if (!domain->attachAxis(axis))
255 return false;
255 return false;
256
256
257 QList<AbstractDomain *> blockedDomains;
257 QList<AbstractDomain *> blockedDomains;
258 domain->blockRangeSignals(true);
258 domain->blockRangeSignals(true);
259 blockedDomains << domain;
259 blockedDomains << domain;
260
260
261 if (domain != series->d_ptr->domain()) {
261 if (domain != series->d_ptr->domain()) {
262 foreach (QAbstractAxis *axis, series->d_ptr->m_axes) {
262 foreach (QAbstractAxis *axis, series->d_ptr->m_axes) {
263 series->d_ptr->domain()->detachAxis(axis);
263 series->d_ptr->domain()->detachAxis(axis);
264 domain->attachAxis(axis);
264 domain->attachAxis(axis);
265 foreach (QAbstractSeries *otherSeries, axis->d_ptr->m_series) {
265 foreach (QAbstractSeries *otherSeries, axis->d_ptr->m_series) {
266 if (otherSeries != series && otherSeries->d_ptr->domain()) {
266 if (otherSeries != series && otherSeries->d_ptr->domain()) {
267 if (!otherSeries->d_ptr->domain()->rangeSignalsBlocked()) {
267 if (!otherSeries->d_ptr->domain()->rangeSignalsBlocked()) {
268 otherSeries->d_ptr->domain()->blockRangeSignals(true);
268 otherSeries->d_ptr->domain()->blockRangeSignals(true);
269 blockedDomains << otherSeries->d_ptr->domain();
269 blockedDomains << otherSeries->d_ptr->domain();
270 }
270 }
271 }
271 }
272 }
272 }
273 }
273 }
274 series->d_ptr->setDomain(domain);
274 series->d_ptr->setDomain(domain);
275 series->d_ptr->initializeDomain();
275 series->d_ptr->initializeDomain();
276 }
276 }
277
277
278 series->d_ptr->m_axes<<axis;
278 series->d_ptr->m_axes<<axis;
279 axis->d_ptr->m_series<<series;
279 axis->d_ptr->m_series<<series;
280
280
281 series->d_ptr->initializeAxes();
281 series->d_ptr->initializeAxes();
282 axis->d_ptr->initializeDomain(domain);
282 axis->d_ptr->initializeDomain(domain);
283
283 connect(axis, &QAbstractAxis::reverseChanged, this, &ChartDataSet::reverseChanged);
284 foreach (AbstractDomain *blockedDomain, blockedDomains)
284 foreach (AbstractDomain *blockedDomain, blockedDomains)
285 blockedDomain->blockRangeSignals(false);
285 blockedDomain->blockRangeSignals(false);
286
286
287 return true;
287 return true;
288 }
288 }
289
289
290 /*
290 /*
291 * This method detaches axis to series, return true if success.
291 * This method detaches axis to series, return true if success.
292 */
292 */
293 bool ChartDataSet::detachAxis(QAbstractSeries* series,QAbstractAxis *axis)
293 bool ChartDataSet::detachAxis(QAbstractSeries* series,QAbstractAxis *axis)
294 {
294 {
295 Q_ASSERT(series);
295 Q_ASSERT(series);
296 Q_ASSERT(axis);
296 Q_ASSERT(axis);
297
297
298 QList<QAbstractSeries* > attachedSeriesList = axis->d_ptr->m_series;
298 QList<QAbstractSeries* > attachedSeriesList = axis->d_ptr->m_series;
299 QList<QAbstractAxis* > attachedAxisList = series->d_ptr->m_axes;
299 QList<QAbstractAxis* > attachedAxisList = series->d_ptr->m_axes;
300 AbstractDomain* domain = series->d_ptr->domain();
300 AbstractDomain* domain = series->d_ptr->domain();
301
301
302 if (!m_seriesList.contains(series)) {
302 if (!m_seriesList.contains(series)) {
303 qWarning() << QObject::tr("Can not find series on the chart.");
303 qWarning() << QObject::tr("Can not find series on the chart.");
304 return false;
304 return false;
305 }
305 }
306
306
307 if (axis && !m_axisList.contains(axis)) {
307 if (axis && !m_axisList.contains(axis)) {
308 qWarning() << QObject::tr("Can not find axis on the chart.");
308 qWarning() << QObject::tr("Can not find axis on the chart.");
309 return false;
309 return false;
310 }
310 }
311
311
312 if (!attachedAxisList.contains(axis)) {
312 if (!attachedAxisList.contains(axis)) {
313 qWarning() << QObject::tr("Axis not attached to series.");
313 qWarning() << QObject::tr("Axis not attached to series.");
314 return false;
314 return false;
315 }
315 }
316
316
317 Q_ASSERT(axis->d_ptr->m_series.contains(series));
317 Q_ASSERT(axis->d_ptr->m_series.contains(series));
318
318
319 domain->detachAxis(axis);
319 domain->detachAxis(axis);
320 series->d_ptr->m_axes.removeAll(axis);
320 series->d_ptr->m_axes.removeAll(axis);
321 axis->d_ptr->m_series.removeAll(series);
321 axis->d_ptr->m_series.removeAll(series);
322
322 disconnect(axis, &QAbstractAxis::reverseChanged, this, &ChartDataSet::reverseChanged);
323 return true;
323 return true;
324 }
324 }
325
325
326 void ChartDataSet::createDefaultAxes()
326 void ChartDataSet::createDefaultAxes()
327 {
327 {
328 if (m_seriesList.isEmpty())
328 if (m_seriesList.isEmpty())
329 return;
329 return;
330
330
331 QAbstractAxis::AxisTypes typeX(0);
331 QAbstractAxis::AxisTypes typeX(0);
332 QAbstractAxis::AxisTypes typeY(0);
332 QAbstractAxis::AxisTypes typeY(0);
333
333
334 // Remove possibly existing axes
334 // Remove possibly existing axes
335 deleteAllAxes();
335 deleteAllAxes();
336
336
337 Q_ASSERT(m_axisList.isEmpty());
337 Q_ASSERT(m_axisList.isEmpty());
338
338
339 // Select the required axis x and axis y types based on the types of the current series
339 // Select the required axis x and axis y types based on the types of the current series
340 foreach(QAbstractSeries* s, m_seriesList) {
340 foreach(QAbstractSeries* s, m_seriesList) {
341 typeX |= s->d_ptr->defaultAxisType(Qt::Horizontal);
341 typeX |= s->d_ptr->defaultAxisType(Qt::Horizontal);
342 typeY |= s->d_ptr->defaultAxisType(Qt::Vertical);
342 typeY |= s->d_ptr->defaultAxisType(Qt::Vertical);
343 }
343 }
344
344
345 createAxes(typeX, Qt::Horizontal);
345 createAxes(typeX, Qt::Horizontal);
346 createAxes(typeY, Qt::Vertical);
346 createAxes(typeY, Qt::Vertical);
347 }
347 }
348
348
349 void ChartDataSet::createAxes(QAbstractAxis::AxisTypes type, Qt::Orientation orientation)
349 void ChartDataSet::createAxes(QAbstractAxis::AxisTypes type, Qt::Orientation orientation)
350 {
350 {
351 QAbstractAxis *axis = 0;
351 QAbstractAxis *axis = 0;
352 //decide what axis should be created
352 //decide what axis should be created
353
353
354 switch (type) {
354 switch (type) {
355 case QAbstractAxis::AxisTypeValue:
355 case QAbstractAxis::AxisTypeValue:
356 axis = new QValueAxis(this);
356 axis = new QValueAxis(this);
357 break;
357 break;
358 case QAbstractAxis::AxisTypeBarCategory:
358 case QAbstractAxis::AxisTypeBarCategory:
359 axis = new QBarCategoryAxis(this);
359 axis = new QBarCategoryAxis(this);
360 break;
360 break;
361 case QAbstractAxis::AxisTypeCategory:
361 case QAbstractAxis::AxisTypeCategory:
362 axis = new QCategoryAxis(this);
362 axis = new QCategoryAxis(this);
363 break;
363 break;
364 #ifndef QT_QREAL_IS_FLOAT
364 #ifndef QT_QREAL_IS_FLOAT
365 case QAbstractAxis::AxisTypeDateTime:
365 case QAbstractAxis::AxisTypeDateTime:
366 axis = new QDateTimeAxis(this);
366 axis = new QDateTimeAxis(this);
367 break;
367 break;
368 #endif
368 #endif
369 default:
369 default:
370 axis = 0;
370 axis = 0;
371 break;
371 break;
372 }
372 }
373
373
374 if (axis) {
374 if (axis) {
375 //create one axis for all
375 //create one axis for all
376
376
377 addAxis(axis,orientation==Qt::Horizontal?Qt::AlignBottom:Qt::AlignLeft);
377 addAxis(axis,orientation==Qt::Horizontal?Qt::AlignBottom:Qt::AlignLeft);
378 qreal min = 0;
378 qreal min = 0;
379 qreal max = 0;
379 qreal max = 0;
380 findMinMaxForSeries(m_seriesList,orientation,min,max);
380 findMinMaxForSeries(m_seriesList,orientation,min,max);
381 foreach(QAbstractSeries *s, m_seriesList) {
381 foreach(QAbstractSeries *s, m_seriesList) {
382 attachAxis(s,axis);
382 attachAxis(s,axis);
383 }
383 }
384 axis->setRange(min,max);
384 axis->setRange(min,max);
385 } else {
385 } else {
386 // Create separate axis for each series
386 // Create separate axis for each series
387 foreach(QAbstractSeries *s, m_seriesList) {
387 foreach(QAbstractSeries *s, m_seriesList) {
388 QAbstractAxis *axis = s->d_ptr->createDefaultAxis(orientation);
388 QAbstractAxis *axis = s->d_ptr->createDefaultAxis(orientation);
389 if(axis) {
389 if(axis) {
390 addAxis(axis,orientation==Qt::Horizontal?Qt::AlignBottom:Qt::AlignLeft);
390 addAxis(axis,orientation==Qt::Horizontal?Qt::AlignBottom:Qt::AlignLeft);
391 attachAxis(s,axis);
391 attachAxis(s,axis);
392 }
392 }
393 }
393 }
394 }
394 }
395 }
395 }
396
396
397 void ChartDataSet::findMinMaxForSeries(QList<QAbstractSeries *> series,Qt::Orientations orientation, qreal &min, qreal &max)
397 void ChartDataSet::findMinMaxForSeries(QList<QAbstractSeries *> series,Qt::Orientations orientation, qreal &min, qreal &max)
398 {
398 {
399 Q_ASSERT(!series.isEmpty());
399 Q_ASSERT(!series.isEmpty());
400
400
401 AbstractDomain *domain = series.first()->d_ptr->domain();
401 AbstractDomain *domain = series.first()->d_ptr->domain();
402 min = (orientation == Qt::Vertical) ? domain->minY() : domain->minX();
402 min = (orientation == Qt::Vertical) ? domain->minY() : domain->minX();
403 max = (orientation == Qt::Vertical) ? domain->maxY() : domain->maxX();
403 max = (orientation == Qt::Vertical) ? domain->maxY() : domain->maxX();
404
404
405 for (int i = 1; i< series.size(); i++) {
405 for (int i = 1; i< series.size(); i++) {
406 AbstractDomain *domain = series[i]->d_ptr->domain();
406 AbstractDomain *domain = series[i]->d_ptr->domain();
407 min = qMin((orientation == Qt::Vertical) ? domain->minY() : domain->minX(), min);
407 min = qMin((orientation == Qt::Vertical) ? domain->minY() : domain->minX(), min);
408 max = qMax((orientation == Qt::Vertical) ? domain->maxY() : domain->maxX(), max);
408 max = qMax((orientation == Qt::Vertical) ? domain->maxY() : domain->maxX(), max);
409 }
409 }
410 if (min == max) {
410 if (min == max) {
411 min -= 0.5;
411 min -= 0.5;
412 max += 0.5;
412 max += 0.5;
413 }
413 }
414 }
414 }
415
415
416 void ChartDataSet::deleteAllSeries()
416 void ChartDataSet::deleteAllSeries()
417 {
417 {
418 foreach (QAbstractSeries *s , m_seriesList){
418 foreach (QAbstractSeries *s , m_seriesList){
419 removeSeries(s);
419 removeSeries(s);
420 s->deleteLater();
420 s->deleteLater();
421 }
421 }
422 Q_ASSERT(m_seriesList.count() == 0);
422 Q_ASSERT(m_seriesList.count() == 0);
423 }
423 }
424
424
425 void ChartDataSet::deleteAllAxes()
425 void ChartDataSet::deleteAllAxes()
426 {
426 {
427 foreach (QAbstractAxis *a , m_axisList){
427 foreach (QAbstractAxis *a , m_axisList){
428 removeAxis(a);
428 removeAxis(a);
429 a->deleteLater();
429 a->deleteLater();
430 }
430 }
431 Q_ASSERT(m_axisList.count() == 0);
431 Q_ASSERT(m_axisList.count() == 0);
432 }
432 }
433
433
434 void ChartDataSet::zoomInDomain(const QRectF &rect)
434 void ChartDataSet::zoomInDomain(const QRectF &rect)
435 {
435 {
436 QList<AbstractDomain*> domains;
436 QList<AbstractDomain*> domains;
437 foreach(QAbstractSeries *s, m_seriesList) {
437 foreach(QAbstractSeries *s, m_seriesList) {
438 AbstractDomain* domain = s->d_ptr->domain();
438 AbstractDomain* domain = s->d_ptr->domain();
439 s->d_ptr->m_domain->blockRangeSignals(true);
439 s->d_ptr->m_domain->blockRangeSignals(true);
440 domains<<domain;
440 domains<<domain;
441 }
441 }
442
442
443 foreach(AbstractDomain *domain, domains)
443 foreach(AbstractDomain *domain, domains)
444 domain->zoomIn(rect);
444 domain->zoomIn(rect);
445
445
446 foreach(AbstractDomain *domain, domains)
446 foreach(AbstractDomain *domain, domains)
447 domain->blockRangeSignals(false);
447 domain->blockRangeSignals(false);
448 }
448 }
449
449
450 void ChartDataSet::zoomOutDomain(const QRectF &rect)
450 void ChartDataSet::zoomOutDomain(const QRectF &rect)
451 {
451 {
452 QList<AbstractDomain*> domains;
452 QList<AbstractDomain*> domains;
453 foreach(QAbstractSeries *s, m_seriesList) {
453 foreach(QAbstractSeries *s, m_seriesList) {
454 AbstractDomain* domain = s->d_ptr->domain();
454 AbstractDomain* domain = s->d_ptr->domain();
455 s->d_ptr->m_domain->blockRangeSignals(true);
455 s->d_ptr->m_domain->blockRangeSignals(true);
456 domains<<domain;
456 domains<<domain;
457 }
457 }
458
458
459 foreach(AbstractDomain *domain, domains)
459 foreach(AbstractDomain *domain, domains)
460 domain->zoomOut(rect);
460 domain->zoomOut(rect);
461
461
462 foreach(AbstractDomain *domain, domains)
462 foreach(AbstractDomain *domain, domains)
463 domain->blockRangeSignals(false);
463 domain->blockRangeSignals(false);
464 }
464 }
465
465
466 void ChartDataSet::zoomResetDomain()
466 void ChartDataSet::zoomResetDomain()
467 {
467 {
468 QList<AbstractDomain*> domains;
468 QList<AbstractDomain*> domains;
469 foreach (QAbstractSeries *s, m_seriesList) {
469 foreach (QAbstractSeries *s, m_seriesList) {
470 AbstractDomain *domain = s->d_ptr->domain();
470 AbstractDomain *domain = s->d_ptr->domain();
471 s->d_ptr->m_domain->blockRangeSignals(true);
471 s->d_ptr->m_domain->blockRangeSignals(true);
472 domains << domain;
472 domains << domain;
473 }
473 }
474
474
475 foreach (AbstractDomain *domain, domains)
475 foreach (AbstractDomain *domain, domains)
476 domain->zoomReset();
476 domain->zoomReset();
477
477
478 foreach (AbstractDomain *domain, domains)
478 foreach (AbstractDomain *domain, domains)
479 domain->blockRangeSignals(false);
479 domain->blockRangeSignals(false);
480 }
480 }
481
481
482 bool ChartDataSet::isZoomedDomain()
482 bool ChartDataSet::isZoomedDomain()
483 {
483 {
484 foreach (QAbstractSeries *s, m_seriesList) {
484 foreach (QAbstractSeries *s, m_seriesList) {
485 if (s->d_ptr->domain()->isZoomed())
485 if (s->d_ptr->domain()->isZoomed())
486 return true;
486 return true;
487 }
487 }
488 return false;
488 return false;
489 }
489 }
490
490
491 void ChartDataSet::scrollDomain(qreal dx, qreal dy)
491 void ChartDataSet::scrollDomain(qreal dx, qreal dy)
492 {
492 {
493 QList<AbstractDomain*> domains;
493 QList<AbstractDomain*> domains;
494 foreach(QAbstractSeries *s, m_seriesList) {
494 foreach(QAbstractSeries *s, m_seriesList) {
495 AbstractDomain* domain = s->d_ptr->domain();
495 AbstractDomain* domain = s->d_ptr->domain();
496 s->d_ptr->m_domain->blockRangeSignals(true);
496 s->d_ptr->m_domain->blockRangeSignals(true);
497 domains<<domain;
497 domains<<domain;
498 }
498 }
499
499
500 foreach(AbstractDomain *domain, domains)
500 foreach(AbstractDomain *domain, domains)
501 domain->move(dx, dy);
501 domain->move(dx, dy);
502
502
503 foreach(AbstractDomain *domain, domains)
503 foreach(AbstractDomain *domain, domains)
504 domain->blockRangeSignals(false);
504 domain->blockRangeSignals(false);
505 }
505 }
506
506
507 QPointF ChartDataSet::mapToValue(const QPointF &position, QAbstractSeries *series)
507 QPointF ChartDataSet::mapToValue(const QPointF &position, QAbstractSeries *series)
508 {
508 {
509 QPointF point;
509 QPointF point;
510 if (series == 0 && !m_seriesList.isEmpty())
510 if (series == 0 && !m_seriesList.isEmpty())
511 series = m_seriesList.first();
511 series = m_seriesList.first();
512
512
513 if (series && series->type() == QAbstractSeries::SeriesTypePie)
513 if (series && series->type() == QAbstractSeries::SeriesTypePie)
514 return point;
514 return point;
515
515
516 if (series && m_seriesList.contains(series))
516 if (series && m_seriesList.contains(series))
517 point = series->d_ptr->m_domain->calculateDomainPoint(position - m_chart->plotArea().topLeft());
517 point = series->d_ptr->m_domain->calculateDomainPoint(position - m_chart->plotArea().topLeft());
518 return point;
518 return point;
519 }
519 }
520
520
521 QPointF ChartDataSet::mapToPosition(const QPointF &value, QAbstractSeries *series)
521 QPointF ChartDataSet::mapToPosition(const QPointF &value, QAbstractSeries *series)
522 {
522 {
523 QPointF point = m_chart->plotArea().topLeft();
523 QPointF point = m_chart->plotArea().topLeft();
524 if (series == 0 && !m_seriesList.isEmpty())
524 if (series == 0 && !m_seriesList.isEmpty())
525 series = m_seriesList.first();
525 series = m_seriesList.first();
526
526
527 if (series && series->type() == QAbstractSeries::SeriesTypePie)
527 if (series && series->type() == QAbstractSeries::SeriesTypePie)
528 return QPoint(0, 0);
528 return QPoint(0, 0);
529
529
530 bool ok;
530 bool ok;
531 if (series && m_seriesList.contains(series))
531 if (series && m_seriesList.contains(series))
532 point += series->d_ptr->m_domain->calculateGeometryPoint(value, ok);
532 point += series->d_ptr->m_domain->calculateGeometryPoint(value, ok);
533 return point;
533 return point;
534 }
534 }
535
535
536 QList<QAbstractAxis *> ChartDataSet::axes() const
536 QList<QAbstractAxis *> ChartDataSet::axes() const
537 {
537 {
538 return m_axisList;
538 return m_axisList;
539 }
539 }
540
540
541 QList<QAbstractSeries *> ChartDataSet::series() const
541 QList<QAbstractSeries *> ChartDataSet::series() const
542 {
542 {
543 return m_seriesList;
543 return m_seriesList;
544 }
544 }
545
545
546 AbstractDomain::DomainType ChartDataSet::selectDomain(QList<QAbstractAxis *> axes)
546 AbstractDomain::DomainType ChartDataSet::selectDomain(QList<QAbstractAxis *> axes)
547 {
547 {
548 enum Type {
548 enum Type {
549 Undefined = 0,
549 Undefined = 0,
550 LogType = 0x1,
550 LogType = 0x1,
551 ValueType = 0x2
551 ValueType = 0x2
552 };
552 };
553
553
554 int horizontal(Undefined);
554 int horizontal(Undefined);
555 int vertical(Undefined);
555 int vertical(Undefined);
556
556
557 // Assume cartesian chart type, unless chart is set
557 // Assume cartesian chart type, unless chart is set
558 QChart::ChartType chartType(QChart::ChartTypeCartesian);
558 QChart::ChartType chartType(QChart::ChartTypeCartesian);
559 if (m_chart)
559 if (m_chart)
560 chartType = m_chart->chartType();
560 chartType = m_chart->chartType();
561
561
562 foreach (QAbstractAxis *axis, axes)
562 foreach (QAbstractAxis *axis, axes)
563 {
563 {
564 switch (axis->type()) {
564 switch (axis->type()) {
565 case QAbstractAxis::AxisTypeLogValue:
565 case QAbstractAxis::AxisTypeLogValue:
566 if (axis->orientation() == Qt::Horizontal)
566 if (axis->orientation() == Qt::Horizontal)
567 horizontal |= LogType;
567 horizontal |= LogType;
568 if (axis->orientation() == Qt::Vertical)
568 if (axis->orientation() == Qt::Vertical)
569 vertical |= LogType;
569 vertical |= LogType;
570 break;
570 break;
571 case QAbstractAxis::AxisTypeValue:
571 case QAbstractAxis::AxisTypeValue:
572 case QAbstractAxis::AxisTypeBarCategory:
572 case QAbstractAxis::AxisTypeBarCategory:
573 case QAbstractAxis::AxisTypeCategory:
573 case QAbstractAxis::AxisTypeCategory:
574 case QAbstractAxis::AxisTypeDateTime:
574 case QAbstractAxis::AxisTypeDateTime:
575 if (axis->orientation() == Qt::Horizontal)
575 if (axis->orientation() == Qt::Horizontal)
576 horizontal |= ValueType;
576 horizontal |= ValueType;
577 if (axis->orientation() == Qt::Vertical)
577 if (axis->orientation() == Qt::Vertical)
578 vertical |= ValueType;
578 vertical |= ValueType;
579 break;
579 break;
580 default:
580 default:
581 qWarning() << "Undefined type";
581 qWarning() << "Undefined type";
582 break;
582 break;
583 }
583 }
584 }
584 }
585
585
586 if (vertical == Undefined)
586 if (vertical == Undefined)
587 vertical = ValueType;
587 vertical = ValueType;
588 if (horizontal == Undefined)
588 if (horizontal == Undefined)
589 horizontal = ValueType;
589 horizontal = ValueType;
590
590
591 if (vertical == ValueType && horizontal == ValueType) {
591 if (vertical == ValueType && horizontal == ValueType) {
592 if (chartType == QChart::ChartTypeCartesian)
592 if (chartType == QChart::ChartTypeCartesian)
593 return AbstractDomain::XYDomain;
593 return AbstractDomain::XYDomain;
594 else if (chartType == QChart::ChartTypePolar)
594 else if (chartType == QChart::ChartTypePolar)
595 return AbstractDomain::XYPolarDomain;
595 return AbstractDomain::XYPolarDomain;
596 }
596 }
597
597
598 if (vertical == LogType && horizontal == ValueType) {
598 if (vertical == LogType && horizontal == ValueType) {
599 if (chartType == QChart::ChartTypeCartesian)
599 if (chartType == QChart::ChartTypeCartesian)
600 return AbstractDomain::XLogYDomain;
600 return AbstractDomain::XLogYDomain;
601 if (chartType == QChart::ChartTypePolar)
601 if (chartType == QChart::ChartTypePolar)
602 return AbstractDomain::XLogYPolarDomain;
602 return AbstractDomain::XLogYPolarDomain;
603 }
603 }
604
604
605 if (vertical == ValueType && horizontal == LogType) {
605 if (vertical == ValueType && horizontal == LogType) {
606 if (chartType == QChart::ChartTypeCartesian)
606 if (chartType == QChart::ChartTypeCartesian)
607 return AbstractDomain::LogXYDomain;
607 return AbstractDomain::LogXYDomain;
608 else if (chartType == QChart::ChartTypePolar)
608 else if (chartType == QChart::ChartTypePolar)
609 return AbstractDomain::LogXYPolarDomain;
609 return AbstractDomain::LogXYPolarDomain;
610 }
610 }
611
611
612 if (vertical == LogType && horizontal == LogType) {
612 if (vertical == LogType && horizontal == LogType) {
613 if (chartType == QChart::ChartTypeCartesian)
613 if (chartType == QChart::ChartTypeCartesian)
614 return AbstractDomain::LogXLogYDomain;
614 return AbstractDomain::LogXLogYDomain;
615 else if (chartType == QChart::ChartTypePolar)
615 else if (chartType == QChart::ChartTypePolar)
616 return AbstractDomain::LogXLogYPolarDomain;
616 return AbstractDomain::LogXLogYPolarDomain;
617 }
617 }
618
618
619 return AbstractDomain::UndefinedDomain;
619 return AbstractDomain::UndefinedDomain;
620 }
620 }
621
621
622 //refactor create factory
622 //refactor create factory
623 AbstractDomain* ChartDataSet::createDomain(AbstractDomain::DomainType type)
623 AbstractDomain* ChartDataSet::createDomain(AbstractDomain::DomainType type)
624 {
624 {
625 switch (type)
625 switch (type)
626 {
626 {
627 case AbstractDomain::LogXLogYDomain:
627 case AbstractDomain::LogXLogYDomain:
628 return new LogXLogYDomain();
628 return new LogXLogYDomain();
629 case AbstractDomain::XYDomain:
629 case AbstractDomain::XYDomain:
630 return new XYDomain();
630 return new XYDomain();
631 case AbstractDomain::XLogYDomain:
631 case AbstractDomain::XLogYDomain:
632 return new XLogYDomain();
632 return new XLogYDomain();
633 case AbstractDomain::LogXYDomain:
633 case AbstractDomain::LogXYDomain:
634 return new LogXYDomain();
634 return new LogXYDomain();
635 case AbstractDomain::XYPolarDomain:
635 case AbstractDomain::XYPolarDomain:
636 return new XYPolarDomain();
636 return new XYPolarDomain();
637 case AbstractDomain::XLogYPolarDomain:
637 case AbstractDomain::XLogYPolarDomain:
638 return new XLogYPolarDomain();
638 return new XLogYPolarDomain();
639 case AbstractDomain::LogXYPolarDomain:
639 case AbstractDomain::LogXYPolarDomain:
640 return new LogXYPolarDomain();
640 return new LogXYPolarDomain();
641 case AbstractDomain::LogXLogYPolarDomain:
641 case AbstractDomain::LogXLogYPolarDomain:
642 return new LogXLogYPolarDomain();
642 return new LogXLogYPolarDomain();
643 default:
643 default:
644 return 0;
644 return 0;
645 }
645 }
646 }
646 }
647
647
648 void ChartDataSet::reverseChanged()
649 {
650 QAbstractAxis *axis = qobject_cast<QAbstractAxis *>(sender());
651 if (axis)
652 m_glXYSeriesDataManager->handleAxisReverseChanged(axis->d_ptr->m_series);
653 }
654
648 #include "moc_chartdataset_p.cpp"
655 #include "moc_chartdataset_p.cpp"
649
656
650 QT_CHARTS_END_NAMESPACE
657 QT_CHARTS_END_NAMESPACE
@@ -1,107 +1,108
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
4 ** Contact: https://www.qt.io/licensing/
5 **
5 **
6 ** This file is part of the Qt Charts module of the Qt Toolkit.
6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 **
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
8 ** $QT_BEGIN_LICENSE:GPL$
9 ** Commercial License Usage
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
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
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.
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
16 **
17 ** GNU General Public License Usage
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
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
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
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
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
25 **
26 ** $QT_END_LICENSE$
26 ** $QT_END_LICENSE$
27 **
27 **
28 ****************************************************************************/
28 ****************************************************************************/
29
29
30 // W A R N I N G
30 // W A R N I N G
31 // -------------
31 // -------------
32 //
32 //
33 // This file is not part of the Qt Chart API. It exists purely as an
33 // This file is not part of the Qt Chart API. It exists purely as an
34 // implementation detail. This header file may change from version to
34 // implementation detail. This header file may change from version to
35 // version without notice, or even be removed.
35 // version without notice, or even be removed.
36 //
36 //
37 // We mean it.
37 // We mean it.
38
38
39 #ifndef CHARTDATASET_P_H
39 #ifndef CHARTDATASET_P_H
40 #define CHARTDATASET_P_H
40 #define CHARTDATASET_P_H
41
41
42 #include <QtCharts/QAbstractSeries>
42 #include <QtCharts/QAbstractSeries>
43 #include <private/abstractdomain_p.h>
43 #include <private/abstractdomain_p.h>
44 #include <private/qabstractaxis_p.h>
44 #include <private/qabstractaxis_p.h>
45 #include <QtCore/QVector>
45 #include <QtCore/QVector>
46
46
47 QT_CHARTS_BEGIN_NAMESPACE
47 QT_CHARTS_BEGIN_NAMESPACE
48
48
49 class QAbstractAxis;
49 class QAbstractAxis;
50 class ChartPresenter;
50 class ChartPresenter;
51 class GLXYSeriesDataManager;
51 class GLXYSeriesDataManager;
52
52
53 class Q_AUTOTEST_EXPORT ChartDataSet : public QObject
53 class Q_AUTOTEST_EXPORT ChartDataSet : public QObject
54 {
54 {
55 Q_OBJECT
55 Q_OBJECT
56 public:
56 public:
57 ChartDataSet(QChart *chart);
57 ChartDataSet(QChart *chart);
58 virtual ~ChartDataSet();
58 virtual ~ChartDataSet();
59
59
60 void addSeries(QAbstractSeries *series);
60 void addSeries(QAbstractSeries *series);
61 void removeSeries(QAbstractSeries *series);
61 void removeSeries(QAbstractSeries *series);
62 QList<QAbstractSeries *> series() const;
62 QList<QAbstractSeries *> series() const;
63
63
64 void addAxis(QAbstractAxis *axis,Qt::Alignment aligment);
64 void addAxis(QAbstractAxis *axis,Qt::Alignment aligment);
65 void removeAxis(QAbstractAxis *axis);
65 void removeAxis(QAbstractAxis *axis);
66 QList<QAbstractAxis*> axes() const;
66 QList<QAbstractAxis*> axes() const;
67
67
68 bool attachAxis(QAbstractSeries* series,QAbstractAxis *axis);
68 bool attachAxis(QAbstractSeries* series,QAbstractAxis *axis);
69 bool detachAxis(QAbstractSeries* series,QAbstractAxis *axis);
69 bool detachAxis(QAbstractSeries* series,QAbstractAxis *axis);
70
70
71 void createDefaultAxes();
71 void createDefaultAxes();
72
72
73 void zoomInDomain(const QRectF &rect);
73 void zoomInDomain(const QRectF &rect);
74 void zoomOutDomain(const QRectF &rect);
74 void zoomOutDomain(const QRectF &rect);
75 void zoomResetDomain();
75 void zoomResetDomain();
76 bool isZoomedDomain();
76 bool isZoomedDomain();
77 void scrollDomain(qreal dx, qreal dy);
77 void scrollDomain(qreal dx, qreal dy);
78
78
79 QPointF mapToValue(const QPointF &position, QAbstractSeries *series = 0);
79 QPointF mapToValue(const QPointF &position, QAbstractSeries *series = 0);
80 QPointF mapToPosition(const QPointF &value, QAbstractSeries *series = 0);
80 QPointF mapToPosition(const QPointF &value, QAbstractSeries *series = 0);
81
81
82 GLXYSeriesDataManager *glXYSeriesDataManager() { return m_glXYSeriesDataManager; }
82 GLXYSeriesDataManager *glXYSeriesDataManager() { return m_glXYSeriesDataManager; }
83
83
84 Q_SIGNALS:
84 Q_SIGNALS:
85 void axisAdded(QAbstractAxis* axis);
85 void axisAdded(QAbstractAxis* axis);
86 void axisRemoved(QAbstractAxis* axis);
86 void axisRemoved(QAbstractAxis* axis);
87 void seriesAdded(QAbstractSeries* series);
87 void seriesAdded(QAbstractSeries* series);
88 void seriesRemoved(QAbstractSeries* series);
88 void seriesRemoved(QAbstractSeries* series);
89
89 public Q_SLOTS:
90 void reverseChanged();
90 private:
91 private:
91 void createAxes(QAbstractAxis::AxisTypes type, Qt::Orientation orientation);
92 void createAxes(QAbstractAxis::AxisTypes type, Qt::Orientation orientation);
92 QAbstractAxis *createAxis(QAbstractAxis::AxisType type, Qt::Orientation orientation);
93 QAbstractAxis *createAxis(QAbstractAxis::AxisType type, Qt::Orientation orientation);
93 AbstractDomain::DomainType selectDomain(QList<QAbstractAxis* > axes);
94 AbstractDomain::DomainType selectDomain(QList<QAbstractAxis* > axes);
94 AbstractDomain* createDomain(AbstractDomain::DomainType type);
95 AbstractDomain* createDomain(AbstractDomain::DomainType type);
95 void deleteAllAxes();
96 void deleteAllAxes();
96 void deleteAllSeries();
97 void deleteAllSeries();
97 void findMinMaxForSeries(QList<QAbstractSeries *> series,Qt::Orientations orientation, qreal &min, qreal &max);
98 void findMinMaxForSeries(QList<QAbstractSeries *> series,Qt::Orientations orientation, qreal &min, qreal &max);
98 private:
99 private:
99 QList<QAbstractSeries *> m_seriesList;
100 QList<QAbstractSeries *> m_seriesList;
100 QList<QAbstractAxis *> m_axisList;
101 QList<QAbstractAxis *> m_axisList;
101 QChart* m_chart;
102 QChart* m_chart;
102 GLXYSeriesDataManager *m_glXYSeriesDataManager;
103 GLXYSeriesDataManager *m_glXYSeriesDataManager;
103 };
104 };
104
105
105 QT_CHARTS_END_NAMESPACE
106 QT_CHARTS_END_NAMESPACE
106
107
107 #endif /* CHARTENGINE_P_H */
108 #endif /* CHARTENGINE_P_H */
@@ -1,233 +1,236
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
4 ** Contact: https://www.qt.io/licensing/
5 **
5 **
6 ** This file is part of the Qt Charts module of the Qt Toolkit.
6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 **
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
8 ** $QT_BEGIN_LICENSE:GPL$
9 ** Commercial License Usage
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
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
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.
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
16 **
17 ** GNU General Public License Usage
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
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
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
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
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
25 **
26 ** $QT_END_LICENSE$
26 ** $QT_END_LICENSE$
27 **
27 **
28 ****************************************************************************/
28 ****************************************************************************/
29
29
30 #ifndef QT_NO_OPENGL
30 #ifndef QT_NO_OPENGL
31
31
32 #include "private/glwidget_p.h"
32 #include "private/glwidget_p.h"
33 #include "private/glxyseriesdata_p.h"
33 #include "private/glxyseriesdata_p.h"
34 #include <QtGui/QOpenGLShaderProgram>
34 #include <QtGui/QOpenGLShaderProgram>
35 #include <QtGui/QOpenGLContext>
35 #include <QtGui/QOpenGLContext>
36 #include <QtGui/QOpenGLBuffer>
36 #include <QtGui/QOpenGLBuffer>
37
37
38 //#define QDEBUG_TRACE_GL_FPS
38 //#define QDEBUG_TRACE_GL_FPS
39 #ifdef QDEBUG_TRACE_GL_FPS
39 #ifdef QDEBUG_TRACE_GL_FPS
40 # include <QElapsedTimer>
40 # include <QElapsedTimer>
41 #endif
41 #endif
42
42
43 QT_CHARTS_BEGIN_NAMESPACE
43 QT_CHARTS_BEGIN_NAMESPACE
44
44
45 GLWidget::GLWidget(GLXYSeriesDataManager *xyDataManager, QWidget *parent)
45 GLWidget::GLWidget(GLXYSeriesDataManager *xyDataManager, QWidget *parent)
46 : QOpenGLWidget(parent),
46 : QOpenGLWidget(parent),
47 m_program(0),
47 m_program(0),
48 m_shaderAttribLoc(-1),
48 m_shaderAttribLoc(-1),
49 m_colorUniformLoc(-1),
49 m_colorUniformLoc(-1),
50 m_minUniformLoc(-1),
50 m_minUniformLoc(-1),
51 m_deltaUniformLoc(-1),
51 m_deltaUniformLoc(-1),
52 m_pointSizeUniformLoc(-1),
52 m_pointSizeUniformLoc(-1),
53 m_xyDataManager(xyDataManager)
53 m_xyDataManager(xyDataManager)
54 {
54 {
55 setAttribute(Qt::WA_TranslucentBackground);
55 setAttribute(Qt::WA_TranslucentBackground);
56 setAttribute(Qt::WA_AlwaysStackOnTop);
56 setAttribute(Qt::WA_AlwaysStackOnTop);
57 setAttribute(Qt::WA_TransparentForMouseEvents);
57 setAttribute(Qt::WA_TransparentForMouseEvents);
58
58
59 QSurfaceFormat surfaceFormat;
59 QSurfaceFormat surfaceFormat;
60 surfaceFormat.setDepthBufferSize(0);
60 surfaceFormat.setDepthBufferSize(0);
61 surfaceFormat.setStencilBufferSize(0);
61 surfaceFormat.setStencilBufferSize(0);
62 surfaceFormat.setRedBufferSize(8);
62 surfaceFormat.setRedBufferSize(8);
63 surfaceFormat.setGreenBufferSize(8);
63 surfaceFormat.setGreenBufferSize(8);
64 surfaceFormat.setBlueBufferSize(8);
64 surfaceFormat.setBlueBufferSize(8);
65 surfaceFormat.setAlphaBufferSize(8);
65 surfaceFormat.setAlphaBufferSize(8);
66 surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
66 surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
67 surfaceFormat.setRenderableType(QSurfaceFormat::DefaultRenderableType);
67 surfaceFormat.setRenderableType(QSurfaceFormat::DefaultRenderableType);
68 setFormat(surfaceFormat);
68 setFormat(surfaceFormat);
69
69
70 connect(xyDataManager, &GLXYSeriesDataManager::seriesRemoved,
70 connect(xyDataManager, &GLXYSeriesDataManager::seriesRemoved,
71 this, &GLWidget::cleanXYSeriesResources);
71 this, &GLWidget::cleanXYSeriesResources);
72 }
72 }
73
73
74 GLWidget::~GLWidget()
74 GLWidget::~GLWidget()
75 {
75 {
76 cleanup();
76 cleanup();
77 }
77 }
78
78
79 void GLWidget::cleanup()
79 void GLWidget::cleanup()
80 {
80 {
81 makeCurrent();
81 makeCurrent();
82
82
83 delete m_program;
83 delete m_program;
84 m_program = 0;
84 m_program = 0;
85
85
86 foreach (QOpenGLBuffer *buffer, m_seriesBufferMap.values())
86 foreach (QOpenGLBuffer *buffer, m_seriesBufferMap.values())
87 delete buffer;
87 delete buffer;
88 m_seriesBufferMap.clear();
88 m_seriesBufferMap.clear();
89
89
90 doneCurrent();
90 doneCurrent();
91 }
91 }
92
92
93 void GLWidget::cleanXYSeriesResources(const QXYSeries *series)
93 void GLWidget::cleanXYSeriesResources(const QXYSeries *series)
94 {
94 {
95 makeCurrent();
95 makeCurrent();
96 if (series) {
96 if (series) {
97 delete m_seriesBufferMap.take(series);
97 delete m_seriesBufferMap.take(series);
98 } else {
98 } else {
99 // Null series means all series were removed
99 // Null series means all series were removed
100 foreach (QOpenGLBuffer *buffer, m_seriesBufferMap.values())
100 foreach (QOpenGLBuffer *buffer, m_seriesBufferMap.values())
101 delete buffer;
101 delete buffer;
102 m_seriesBufferMap.clear();
102 m_seriesBufferMap.clear();
103 }
103 }
104 doneCurrent();
104 doneCurrent();
105 }
105 }
106
106
107 static const char *vertexSource =
107 static const char *vertexSource =
108 "attribute highp vec2 points;\n"
108 "attribute highp vec2 points;\n"
109 "uniform highp vec2 min;\n"
109 "uniform highp vec2 min;\n"
110 "uniform highp vec2 delta;\n"
110 "uniform highp vec2 delta;\n"
111 "uniform highp float pointSize;\n"
111 "uniform highp float pointSize;\n"
112 "uniform highp mat4 matrix;\n"
112 "void main() {\n"
113 "void main() {\n"
113 " vec2 normalPoint = vec2(-1, -1) + ((points - min) / delta);\n"
114 " vec2 normalPoint = vec2(-1, -1) + ((points - min) / delta);\n"
114 " gl_Position = vec4(normalPoint, 0, 1);\n"
115 " gl_Position = matrix * vec4(normalPoint, 0, 1);\n"
115 " gl_PointSize = pointSize;\n"
116 " gl_PointSize = pointSize;\n"
116 "}";
117 "}";
117 static const char *fragmentSource =
118 static const char *fragmentSource =
118 "uniform highp vec3 color;\n"
119 "uniform highp vec3 color;\n"
119 "void main() {\n"
120 "void main() {\n"
120 " gl_FragColor = vec4(color,1);\n"
121 " gl_FragColor = vec4(color,1);\n"
121 "}\n";
122 "}\n";
122
123
123 void GLWidget::initializeGL()
124 void GLWidget::initializeGL()
124 {
125 {
125 connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &GLWidget::cleanup);
126 connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &GLWidget::cleanup);
126
127
127 initializeOpenGLFunctions();
128 initializeOpenGLFunctions();
128 glClearColor(0, 0, 0, 0);
129 glClearColor(0, 0, 0, 0);
129
130
130 m_program = new QOpenGLShaderProgram;
131 m_program = new QOpenGLShaderProgram;
131 m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource);
132 m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource);
132 m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentSource);
133 m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentSource);
133 m_program->bindAttributeLocation("points", 0);
134 m_program->bindAttributeLocation("points", 0);
134 m_program->link();
135 m_program->link();
135
136
136 m_program->bind();
137 m_program->bind();
137 m_colorUniformLoc = m_program->uniformLocation("color");
138 m_colorUniformLoc = m_program->uniformLocation("color");
138 m_minUniformLoc = m_program->uniformLocation("min");
139 m_minUniformLoc = m_program->uniformLocation("min");
139 m_deltaUniformLoc = m_program->uniformLocation("delta");
140 m_deltaUniformLoc = m_program->uniformLocation("delta");
140 m_pointSizeUniformLoc = m_program->uniformLocation("pointSize");
141 m_pointSizeUniformLoc = m_program->uniformLocation("pointSize");
142 m_matrixUniformLoc = m_program->uniformLocation("matrix");
141
143
142
144
143 // Create a vertex array object. In OpenGL ES 2.0 and OpenGL 2.x
145 // Create a vertex array object. In OpenGL ES 2.0 and OpenGL 2.x
144 // implementations this is optional and support may not be present
146 // implementations this is optional and support may not be present
145 // at all. Nonetheless the below code works in all cases and makes
147 // at all. Nonetheless the below code works in all cases and makes
146 // sure there is a VAO when one is needed.
148 // sure there is a VAO when one is needed.
147 m_vao.create();
149 m_vao.create();
148 QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
150 QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
149
151
150 glEnableVertexAttribArray(0);
152 glEnableVertexAttribArray(0);
151
153
152 glDisable(GL_DEPTH_TEST);
154 glDisable(GL_DEPTH_TEST);
153 glDisable(GL_STENCIL_TEST);
155 glDisable(GL_STENCIL_TEST);
154
156
155 #if !defined(QT_OPENGL_ES_2)
157 #if !defined(QT_OPENGL_ES_2)
156 if (!QOpenGLContext::currentContext()->isOpenGLES()) {
158 if (!QOpenGLContext::currentContext()->isOpenGLES()) {
157 // Make it possible to change point primitive size and use textures with them in
159 // Make it possible to change point primitive size and use textures with them in
158 // the shaders. These are implicitly enabled in ES2.
160 // the shaders. These are implicitly enabled in ES2.
159 glEnable(GL_PROGRAM_POINT_SIZE);
161 glEnable(GL_PROGRAM_POINT_SIZE);
160 }
162 }
161 #endif
163 #endif
162
164
163 m_program->release();
165 m_program->release();
164 }
166 }
165
167
166 void GLWidget::paintGL()
168 void GLWidget::paintGL()
167 {
169 {
168 glClear(GL_COLOR_BUFFER_BIT);
170 glClear(GL_COLOR_BUFFER_BIT);
169
171
170 QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
172 QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
171 m_program->bind();
173 m_program->bind();
172
174
173 GLXYDataMapIterator i(m_xyDataManager->dataMap());
175 GLXYDataMapIterator i(m_xyDataManager->dataMap());
174 while (i.hasNext()) {
176 while (i.hasNext()) {
175 i.next();
177 i.next();
176 QOpenGLBuffer *vbo = m_seriesBufferMap.value(i.key());
178 QOpenGLBuffer *vbo = m_seriesBufferMap.value(i.key());
177 GLXYSeriesData *data = i.value();
179 GLXYSeriesData *data = i.value();
178
180
179 m_program->setUniformValue(m_colorUniformLoc, data->color);
181 m_program->setUniformValue(m_colorUniformLoc, data->color);
180 m_program->setUniformValue(m_minUniformLoc, data->min);
182 m_program->setUniformValue(m_minUniformLoc, data->min);
181 m_program->setUniformValue(m_deltaUniformLoc, data->delta);
183 m_program->setUniformValue(m_deltaUniformLoc, data->delta);
184 m_program->setUniformValue(m_matrixUniformLoc, data->matrix);
182
185
183 if (!vbo) {
186 if (!vbo) {
184 vbo = new QOpenGLBuffer;
187 vbo = new QOpenGLBuffer;
185 m_seriesBufferMap.insert(i.key(), vbo);
188 m_seriesBufferMap.insert(i.key(), vbo);
186 vbo->create();
189 vbo->create();
187 }
190 }
188 vbo->bind();
191 vbo->bind();
189 if (data->dirty) {
192 if (data->dirty) {
190 vbo->allocate(data->array.constData(), data->array.count() * sizeof(GLfloat));
193 vbo->allocate(data->array.constData(), data->array.count() * sizeof(GLfloat));
191 data->dirty = false;
194 data->dirty = false;
192 }
195 }
193
196
194 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
197 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
195 if (data->type == QAbstractSeries::SeriesTypeLine) {
198 if (data->type == QAbstractSeries::SeriesTypeLine) {
196 glLineWidth(data->width);
199 glLineWidth(data->width);
197 glDrawArrays(GL_LINE_STRIP, 0, data->array.size() / 2);
200 glDrawArrays(GL_LINE_STRIP, 0, data->array.size() / 2);
198 } else { // Scatter
201 } else { // Scatter
199 m_program->setUniformValue(m_pointSizeUniformLoc, data->width);
202 m_program->setUniformValue(m_pointSizeUniformLoc, data->width);
200 glDrawArrays(GL_POINTS, 0, data->array.size() / 2);
203 glDrawArrays(GL_POINTS, 0, data->array.size() / 2);
201 }
204 }
202 vbo->release();
205 vbo->release();
203 }
206 }
204
207
205 #ifdef QDEBUG_TRACE_GL_FPS
208 #ifdef QDEBUG_TRACE_GL_FPS
206 static QElapsedTimer stopWatch;
209 static QElapsedTimer stopWatch;
207 static int frameCount = -1;
210 static int frameCount = -1;
208 if (frameCount == -1) {
211 if (frameCount == -1) {
209 stopWatch.start();
212 stopWatch.start();
210 frameCount = 0;
213 frameCount = 0;
211 }
214 }
212 frameCount++;
215 frameCount++;
213 int elapsed = stopWatch.elapsed();
216 int elapsed = stopWatch.elapsed();
214 if (elapsed >= 1000) {
217 if (elapsed >= 1000) {
215 elapsed = stopWatch.restart();
218 elapsed = stopWatch.restart();
216 qreal fps = qreal(0.1 * int(10000.0 * (qreal(frameCount) / qreal(elapsed))));
219 qreal fps = qreal(0.1 * int(10000.0 * (qreal(frameCount) / qreal(elapsed))));
217 qDebug() << "FPS:" << fps;
220 qDebug() << "FPS:" << fps;
218 frameCount = 0;
221 frameCount = 0;
219 }
222 }
220 #endif
223 #endif
221
224
222 m_program->release();
225 m_program->release();
223 }
226 }
224
227
225 void GLWidget::resizeGL(int w, int h)
228 void GLWidget::resizeGL(int w, int h)
226 {
229 {
227 Q_UNUSED(w)
230 Q_UNUSED(w)
228 Q_UNUSED(h)
231 Q_UNUSED(h)
229 }
232 }
230
233
231 QT_CHARTS_END_NAMESPACE
234 QT_CHARTS_END_NAMESPACE
232
235
233 #endif
236 #endif
@@ -1,90 +1,91
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
4 ** Contact: https://www.qt.io/licensing/
5 **
5 **
6 ** This file is part of the Qt Charts module of the Qt Toolkit.
6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 **
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
8 ** $QT_BEGIN_LICENSE:GPL$
9 ** Commercial License Usage
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
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
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.
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
16 **
17 ** GNU General Public License Usage
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
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
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
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
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
25 **
26 ** $QT_END_LICENSE$
26 ** $QT_END_LICENSE$
27 **
27 **
28 ****************************************************************************/
28 ****************************************************************************/
29
29
30 // W A R N I N G
30 // W A R N I N G
31 // -------------
31 // -------------
32 //
32 //
33 // This file is not part of the Qt Chart API. It exists purely as an
33 // This file is not part of the Qt Chart API. It exists purely as an
34 // implementation detail. This header file may change from version to
34 // implementation detail. This header file may change from version to
35 // version without notice, or even be removed.
35 // version without notice, or even be removed.
36 //
36 //
37 // We mean it.
37 // We mean it.
38
38
39 #ifndef GLWIDGET_H
39 #ifndef GLWIDGET_H
40 #define GLWIDGET_H
40 #define GLWIDGET_H
41
41
42 #ifndef QT_NO_OPENGL
42 #ifndef QT_NO_OPENGL
43
43
44 #include <QtWidgets/QOpenGLWidget>
44 #include <QtWidgets/QOpenGLWidget>
45 #include <QtGui/QOpenGLFunctions>
45 #include <QtGui/QOpenGLFunctions>
46 #include <QtGui/QOpenGLVertexArrayObject>
46 #include <QtGui/QOpenGLVertexArrayObject>
47 #include <QtGui/QOpenGLBuffer>
47 #include <QtGui/QOpenGLBuffer>
48 #include <QtCore/QHash>
48 #include <QtCore/QHash>
49 #include <QtCharts/QAbstractSeries>
49 #include <QtCharts/QAbstractSeries>
50 #include <QtCharts/QXYSeries>
50 #include <QtCharts/QXYSeries>
51
51
52 QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram)
52 QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram)
53
53
54 QT_CHARTS_BEGIN_NAMESPACE
54 QT_CHARTS_BEGIN_NAMESPACE
55
55
56 class GLXYSeriesDataManager;
56 class GLXYSeriesDataManager;
57
57
58 class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions
58 class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions
59 {
59 {
60 Q_OBJECT
60 Q_OBJECT
61
61
62 public:
62 public:
63 GLWidget(GLXYSeriesDataManager *xyDataManager, QWidget *parent = 0);
63 GLWidget(GLXYSeriesDataManager *xyDataManager, QWidget *parent = 0);
64 ~GLWidget();
64 ~GLWidget();
65
65
66 public Q_SLOTS:
66 public Q_SLOTS:
67 void cleanup();
67 void cleanup();
68 void cleanXYSeriesResources(const QXYSeries *series);
68 void cleanXYSeriesResources(const QXYSeries *series);
69
69
70 protected:
70 protected:
71 void initializeGL() Q_DECL_OVERRIDE;
71 void initializeGL() Q_DECL_OVERRIDE;
72 void paintGL() Q_DECL_OVERRIDE;
72 void paintGL() Q_DECL_OVERRIDE;
73 void resizeGL(int width, int height) Q_DECL_OVERRIDE;
73 void resizeGL(int width, int height) Q_DECL_OVERRIDE;
74
74
75 private:
75 private:
76 QOpenGLShaderProgram *m_program;
76 QOpenGLShaderProgram *m_program;
77 int m_shaderAttribLoc;
77 int m_shaderAttribLoc;
78 int m_colorUniformLoc;
78 int m_colorUniformLoc;
79 int m_minUniformLoc;
79 int m_minUniformLoc;
80 int m_deltaUniformLoc;
80 int m_deltaUniformLoc;
81 int m_pointSizeUniformLoc;
81 int m_pointSizeUniformLoc;
82 int m_matrixUniformLoc;
82 QOpenGLVertexArrayObject m_vao;
83 QOpenGLVertexArrayObject m_vao;
83
84
84 QHash<const QAbstractSeries *, QOpenGLBuffer *> m_seriesBufferMap;
85 QHash<const QAbstractSeries *, QOpenGLBuffer *> m_seriesBufferMap;
85 GLXYSeriesDataManager *m_xyDataManager;
86 GLXYSeriesDataManager *m_xyDataManager;
86 };
87 };
87
88
88 QT_CHARTS_END_NAMESPACE
89 QT_CHARTS_END_NAMESPACE
89 #endif
90 #endif
90 #endif
91 #endif
@@ -1,189 +1,233
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
4 ** Contact: https://www.qt.io/licensing/
5 **
5 **
6 ** This file is part of the Qt Charts module of the Qt Toolkit.
6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 **
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
8 ** $QT_BEGIN_LICENSE:GPL$
9 ** Commercial License Usage
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
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
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.
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
16 **
17 ** GNU General Public License Usage
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
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
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
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
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
25 **
26 ** $QT_END_LICENSE$
26 ** $QT_END_LICENSE$
27 **
27 **
28 ****************************************************************************/
28 ****************************************************************************/
29
29
30 #include "private/glxyseriesdata_p.h"
30 #include "private/glxyseriesdata_p.h"
31 #include "private/abstractdomain_p.h"
31 #include "private/abstractdomain_p.h"
32 #include <QtCharts/QScatterSeries>
32 #include <QtCharts/QScatterSeries>
33
33
34 QT_CHARTS_BEGIN_NAMESPACE
34 QT_CHARTS_BEGIN_NAMESPACE
35
35
36 GLXYSeriesDataManager::GLXYSeriesDataManager(QObject *parent)
36 GLXYSeriesDataManager::GLXYSeriesDataManager(QObject *parent)
37 : QObject(parent),
37 : QObject(parent),
38 m_mapDirty(false)
38 m_mapDirty(false)
39 {
39 {
40 }
40 }
41
41
42 GLXYSeriesDataManager::~GLXYSeriesDataManager()
42 GLXYSeriesDataManager::~GLXYSeriesDataManager()
43 {
43 {
44 cleanup();
44 cleanup();
45 }
45 }
46
46
47 void GLXYSeriesDataManager::setPoints(QXYSeries *series, const AbstractDomain *domain)
47 void GLXYSeriesDataManager::setPoints(QXYSeries *series, const AbstractDomain *domain)
48 {
48 {
49 GLXYSeriesData *data = m_seriesDataMap.value(series);
49 GLXYSeriesData *data = m_seriesDataMap.value(series);
50 if (!data) {
50 if (!data) {
51 data = new GLXYSeriesData;
51 data = new GLXYSeriesData;
52 data->type = series->type();
52 data->type = series->type();
53 QColor sc;
53 QColor sc;
54 if (data->type == QAbstractSeries::SeriesTypeScatter) {
54 if (data->type == QAbstractSeries::SeriesTypeScatter) {
55 QScatterSeries *scatter = static_cast<QScatterSeries *>(series);
55 QScatterSeries *scatter = static_cast<QScatterSeries *>(series);
56 data->width = float(scatter->markerSize());
56 data->width = float(scatter->markerSize());
57 sc = scatter->color(); // Scatter overwrites color property
57 sc = scatter->color(); // Scatter overwrites color property
58 connect(scatter, &QScatterSeries::colorChanged, this,
58 connect(scatter, &QScatterSeries::colorChanged, this,
59 &GLXYSeriesDataManager::handleScatterColorChange);
59 &GLXYSeriesDataManager::handleScatterColorChange);
60 connect(scatter, &QScatterSeries::markerSizeChanged, this,
60 connect(scatter, &QScatterSeries::markerSizeChanged, this,
61 &GLXYSeriesDataManager::handleScatterMarkerSizeChange);
61 &GLXYSeriesDataManager::handleScatterMarkerSizeChange);
62 } else {
62 } else {
63 data->width = float(series->pen().widthF());
63 data->width = float(series->pen().widthF());
64 sc = series->color();
64 sc = series->color();
65 connect(series, &QXYSeries::penChanged, this,
65 connect(series, &QXYSeries::penChanged, this,
66 &GLXYSeriesDataManager::handleSeriesPenChange);
66 &GLXYSeriesDataManager::handleSeriesPenChange);
67 }
67 }
68 data->color = QVector3D(float(sc.redF()), float(sc.greenF()), float(sc.blueF()));
68 data->color = QVector3D(float(sc.redF()), float(sc.greenF()), float(sc.blueF()));
69 connect(series, &QXYSeries::useOpenGLChanged, this,
69 connect(series, &QXYSeries::useOpenGLChanged, this,
70 &GLXYSeriesDataManager::handleSeriesOpenGLChange);
70 &GLXYSeriesDataManager::handleSeriesOpenGLChange);
71 m_seriesDataMap.insert(series, data);
71 m_seriesDataMap.insert(series, data);
72 m_mapDirty = true;
72 m_mapDirty = true;
73 }
73 }
74 QVector<float> &array = data->array;
74 QVector<float> &array = data->array;
75
75
76 bool logAxis = false;
76 bool logAxis = false;
77 bool reverseX = false;
78 bool reverseY = false;
77 foreach (QAbstractAxis* axis, series->attachedAxes()) {
79 foreach (QAbstractAxis* axis, series->attachedAxes()) {
78 if (axis->type() == QAbstractAxis::AxisTypeLogValue) {
80 if (axis->type() == QAbstractAxis::AxisTypeLogValue) {
79 logAxis = true;
81 logAxis = true;
80 break;
82 }
83 if (axis->isReverse()) {
84 if (axis->orientation() == Qt::Horizontal)
85 reverseX = true;
86 else
87 reverseY = true;
88 if (reverseX && reverseY)
89 break;
81 }
90 }
82 }
91 }
83
84 int count = series->count();
92 int count = series->count();
85 int index = 0;
93 int index = 0;
86 array.resize(count * 2);
94 array.resize(count * 2);
95 QMatrix4x4 matrix;
96 if (reverseX)
97 matrix.scale(-1.0, 1.0);
98 if (reverseY)
99 matrix.scale(1.0, -1.0);
100 data->matrix = matrix;
87 if (logAxis) {
101 if (logAxis) {
88 // Use domain to resolve geometry points. Not as fast as shaders, but simpler that way
102 // Use domain to resolve geometry points. Not as fast as shaders, but simpler that way
89 QVector<QPointF> geometryPoints = domain->calculateGeometryPoints(series->pointsVector());
103 QVector<QPointF> geometryPoints = domain->calculateGeometryPoints(series->pointsVector());
90 const float height = domain->size().height();
104 const float height = domain->size().height();
91 if (geometryPoints.size()) {
105 if (geometryPoints.size()) {
92 for (int i = 0; i < count; i++) {
106 for (int i = 0; i < count; i++) {
93 const QPointF &point = geometryPoints.at(i);
107 const QPointF &point = geometryPoints.at(i);
94 array[index++] = float(point.x());
108 array[index++] = float(point.x());
95 array[index++] = float(height - point.y());
109 array[index++] = float(height - point.y());
96 }
110 }
97 } else {
111 } else {
98 // If there are invalid log values, geometry points generation fails
112 // If there are invalid log values, geometry points generation fails
99 for (int i = 0; i < count; i++) {
113 for (int i = 0; i < count; i++) {
100 array[index++] = 0.0f;
114 array[index++] = 0.0f;
101 array[index++] = 0.0f;
115 array[index++] = 0.0f;
102 }
116 }
103 }
117 }
104 data->min = QVector2D(0, 0);
118 data->min = QVector2D(0, 0);
105 data->delta = QVector2D(domain->size().width() / 2.0f, domain->size().height() / 2.0f);
119 data->delta = QVector2D(domain->size().width() / 2.0f, domain->size().height() / 2.0f);
106 } else {
120 } else {
107 // Regular value axes, so we can do the math easily on shaders.
121 // Regular value axes, so we can do the math easily on shaders.
108 QVector<QPointF> seriesPoints = series->pointsVector();
122 QVector<QPointF> seriesPoints = series->pointsVector();
109 for (int i = 0; i < count; i++) {
123 for (int i = 0; i < count; i++) {
110 const QPointF &point = seriesPoints.at(i);
124 const QPointF &point = seriesPoints.at(i);
111 array[index++] = float(point.x());
125 array[index++] = float(point.x());
112 array[index++] = float(point.y());
126 array[index++] = float(point.y());
113 }
127 }
114 data->min = QVector2D(domain->minX(), domain->minY());
128 data->min = QVector2D(domain->minX(), domain->minY());
115 data->delta = QVector2D((domain->maxX() - domain->minX()) / 2.0f,
129 data->delta = QVector2D((domain->maxX() - domain->minX()) / 2.0f,
116 (domain->maxY() - domain->minY()) / 2.0f);
130 (domain->maxY() - domain->minY()) / 2.0f);
117 }
131 }
118 data->dirty = true;
132 data->dirty = true;
119 }
133 }
120
134
121 void GLXYSeriesDataManager::removeSeries(const QXYSeries *series)
135 void GLXYSeriesDataManager::removeSeries(const QXYSeries *series)
122 {
136 {
123 GLXYSeriesData *data = m_seriesDataMap.take(series);
137 GLXYSeriesData *data = m_seriesDataMap.take(series);
124 if (data) {
138 if (data) {
125 disconnect(series, 0, this, 0);
139 disconnect(series, 0, this, 0);
126 delete data;
140 delete data;
127 emit seriesRemoved(series);
141 emit seriesRemoved(series);
128 m_mapDirty = true;
142 m_mapDirty = true;
129 }
143 }
130 }
144 }
131
145
132 void GLXYSeriesDataManager::cleanup()
146 void GLXYSeriesDataManager::cleanup()
133 {
147 {
134 foreach (GLXYSeriesData *data, m_seriesDataMap.values())
148 foreach (GLXYSeriesData *data, m_seriesDataMap.values())
135 delete data;
149 delete data;
136 m_seriesDataMap.clear();
150 m_seriesDataMap.clear();
137 m_mapDirty = true;
151 m_mapDirty = true;
138 // Signal all series removal by using zero as parameter
152 // Signal all series removal by using zero as parameter
139 emit seriesRemoved(0);
153 emit seriesRemoved(0);
140 }
154 }
141
155
142 void GLXYSeriesDataManager::handleSeriesPenChange()
156 void GLXYSeriesDataManager::handleSeriesPenChange()
143 {
157 {
144 QXYSeries *series = qobject_cast<QXYSeries *>(sender());
158 QXYSeries *series = qobject_cast<QXYSeries *>(sender());
145 if (series) {
159 if (series) {
146 GLXYSeriesData *data = m_seriesDataMap.value(series);
160 GLXYSeriesData *data = m_seriesDataMap.value(series);
147 if (data) {
161 if (data) {
148 QColor sc = series->color();
162 QColor sc = series->color();
149 data->color = QVector3D(float(sc.redF()), float(sc.greenF()), float(sc.blueF()));
163 data->color = QVector3D(float(sc.redF()), float(sc.greenF()), float(sc.blueF()));
150 data->width = float(series->pen().widthF());
164 data->width = float(series->pen().widthF());
151 data->dirty = true;
165 data->dirty = true;
152 }
166 }
153 }
167 }
154 }
168 }
155
169
156 void GLXYSeriesDataManager::handleSeriesOpenGLChange()
170 void GLXYSeriesDataManager::handleSeriesOpenGLChange()
157 {
171 {
158 QXYSeries *series = qobject_cast<QXYSeries *>(sender());
172 QXYSeries *series = qobject_cast<QXYSeries *>(sender());
159 if (!series->useOpenGL())
173 if (!series->useOpenGL())
160 removeSeries(series);
174 removeSeries(series);
161 }
175 }
162
176
163 void GLXYSeriesDataManager::handleScatterColorChange()
177 void GLXYSeriesDataManager::handleScatterColorChange()
164 {
178 {
165 QScatterSeries *series = qobject_cast<QScatterSeries *>(sender());
179 QScatterSeries *series = qobject_cast<QScatterSeries *>(sender());
166 if (series) {
180 if (series) {
167 GLXYSeriesData *data = m_seriesDataMap.value(series);
181 GLXYSeriesData *data = m_seriesDataMap.value(series);
168 if (data) {
182 if (data) {
169 QColor sc = series->color();
183 QColor sc = series->color();
170 data->color = QVector3D(float(sc.redF()), float(sc.greenF()), float(sc.blueF()));
184 data->color = QVector3D(float(sc.redF()), float(sc.greenF()), float(sc.blueF()));
171 data->dirty = true;
185 data->dirty = true;
172 }
186 }
173 }
187 }
174 }
188 }
175
189
176 void GLXYSeriesDataManager::handleScatterMarkerSizeChange()
190 void GLXYSeriesDataManager::handleScatterMarkerSizeChange()
177 {
191 {
178 QScatterSeries *series = qobject_cast<QScatterSeries *>(sender());
192 QScatterSeries *series = qobject_cast<QScatterSeries *>(sender());
179 if (series) {
193 if (series) {
180 GLXYSeriesData *data = m_seriesDataMap.value(series);
194 GLXYSeriesData *data = m_seriesDataMap.value(series);
181 if (data) {
195 if (data) {
182 data->width =float(series->markerSize());
196 data->width =float(series->markerSize());
183 data->dirty = true;
197 data->dirty = true;
184 }
198 }
185 }
199 }
186 }
200 }
187
201
202 void GLXYSeriesDataManager::handleAxisReverseChanged(const QList<QAbstractSeries *> &seriesList)
203 {
204 bool reverseX = false;
205 bool reverseY = false;
206 foreach (QAbstractSeries *series, seriesList) {
207 if (QXYSeries *xyseries = qobject_cast<QXYSeries *>(series)) {
208 GLXYSeriesData *data = m_seriesDataMap.value(xyseries);
209 if (data) {
210 foreach (QAbstractAxis* axis, xyseries->attachedAxes()) {
211 if (axis->isReverse()) {
212 if (axis->orientation() == Qt::Horizontal)
213 reverseX = true;
214 else
215 reverseY = true;
216 }
217 if (reverseX && reverseY)
218 break;
219 }
220 QMatrix4x4 matrix;
221 if (reverseX)
222 matrix.scale(-1.0, 1.0);
223 if (reverseY)
224 matrix.scale(1.0, -1.0);
225 data->matrix = matrix;
226 data->dirty = true;
227 }
228 }
229 }
230 }
231
188 QT_CHARTS_END_NAMESPACE
232 QT_CHARTS_END_NAMESPACE
189
233
@@ -1,104 +1,119
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
4 ** Contact: https://www.qt.io/licensing/
5 **
5 **
6 ** This file is part of the Qt Charts module of the Qt Toolkit.
6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 **
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
8 ** $QT_BEGIN_LICENSE:GPL$
9 ** Commercial License Usage
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
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
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.
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
16 **
17 ** GNU General Public License Usage
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
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
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
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
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
25 **
26 ** $QT_END_LICENSE$
26 ** $QT_END_LICENSE$
27 **
27 **
28 ****************************************************************************/
28 ****************************************************************************/
29
29
30 // W A R N I N G
30 // W A R N I N G
31 // -------------
31 // -------------
32 //
32 //
33 // This file is not part of the Qt Chart API. It exists purely as an
33 // This file is not part of the Qt Chart API. It exists purely as an
34 // implementation detail. This header file may change from version to
34 // implementation detail. This header file may change from version to
35 // version without notice, or even be removed.
35 // version without notice, or even be removed.
36 //
36 //
37 // We mean it.
37 // We mean it.
38
38
39 #ifndef GLXYSERIESDATA_H
39 #ifndef GLXYSERIESDATA_H
40 #define GLXYSERIESDATA_H
40 #define GLXYSERIESDATA_H
41
41
42 #include <QtCore/QMap>
42 #include <QtCore/QMap>
43 #include <QtCharts/QAbstractSeries>
43 #include <QtCharts/QAbstractSeries>
44 #include <QtCharts/QXYSeries>
44 #include <QtCharts/QXYSeries>
45 #include <QtGui/QVector3D>
45 #include <QtGui/QVector3D>
46 #include <QtGui/QVector2D>
46 #include <QtGui/QVector2D>
47 #include <QtGui/QMatrix4x4>
47
48
48 QT_CHARTS_BEGIN_NAMESPACE
49 QT_CHARTS_BEGIN_NAMESPACE
49
50
50 class AbstractDomain;
51 class AbstractDomain;
51
52
52 struct GLXYSeriesData {
53 struct GLXYSeriesData {
53 QVector<float> array;
54 QVector<float> array;
54 bool dirty;
55 bool dirty;
55 QVector3D color;
56 QVector3D color;
56 float width;
57 float width;
57 QAbstractSeries::SeriesType type;
58 QAbstractSeries::SeriesType type;
58 QVector2D min;
59 QVector2D min;
59 QVector2D delta;
60 QVector2D delta;
61 QMatrix4x4 matrix;
62 public:
63 GLXYSeriesData &operator=(const GLXYSeriesData &data) {
64 array = data.array;
65 dirty = data.dirty;
66 color = data.color;
67 width = data.width;
68 type = data.type;
69 min = data.min;
70 delta = data.delta;
71 matrix = data.matrix;
72 return *this;
73 }
60 };
74 };
61
75
62 typedef QMap<const QXYSeries *, GLXYSeriesData *> GLXYDataMap;
76 typedef QMap<const QXYSeries *, GLXYSeriesData *> GLXYDataMap;
63 typedef QMapIterator<const QXYSeries *, GLXYSeriesData *> GLXYDataMapIterator;
77 typedef QMapIterator<const QXYSeries *, GLXYSeriesData *> GLXYDataMapIterator;
64
78
65 class GLXYSeriesDataManager : public QObject
79 class GLXYSeriesDataManager : public QObject
66 {
80 {
67 Q_OBJECT
81 Q_OBJECT
68
82
69 public:
83 public:
70 GLXYSeriesDataManager(QObject *parent = 0);
84 GLXYSeriesDataManager(QObject *parent = 0);
71 ~GLXYSeriesDataManager();
85 ~GLXYSeriesDataManager();
72
86
73 void setPoints(QXYSeries *series, const AbstractDomain *domain);
87 void setPoints(QXYSeries *series, const AbstractDomain *domain);
74
88
75 void removeSeries(const QXYSeries *series);
89 void removeSeries(const QXYSeries *series);
76
90
77 GLXYDataMap &dataMap() { return m_seriesDataMap; }
91 GLXYDataMap &dataMap() { return m_seriesDataMap; }
78
92
79 // These functions are needed by qml side, so they must be inline
93 // These functions are needed by qml side, so they must be inline
80 bool mapDirty() const { return m_mapDirty; }
94 bool mapDirty() const { return m_mapDirty; }
81 void clearAllDirty() {
95 void clearAllDirty() {
82 m_mapDirty = false;
96 m_mapDirty = false;
83 foreach (GLXYSeriesData *data, m_seriesDataMap.values())
97 foreach (GLXYSeriesData *data, m_seriesDataMap.values())
84 data->dirty = false;
98 data->dirty = false;
85 }
99 }
100 void handleAxisReverseChanged(const QList<QAbstractSeries *> &seriesList);
86
101
87 public Q_SLOTS:
102 public Q_SLOTS:
88 void cleanup();
103 void cleanup();
89 void handleSeriesPenChange();
104 void handleSeriesPenChange();
90 void handleSeriesOpenGLChange();
105 void handleSeriesOpenGLChange();
91 void handleScatterColorChange();
106 void handleScatterColorChange();
92 void handleScatterMarkerSizeChange();
107 void handleScatterMarkerSizeChange();
93
108
94 Q_SIGNALS:
109 Q_SIGNALS:
95 void seriesRemoved(const QXYSeries *series);
110 void seriesRemoved(const QXYSeries *series);
96
111
97 private:
112 private:
98 GLXYDataMap m_seriesDataMap;
113 GLXYDataMap m_seriesDataMap;
99 bool m_mapDirty;
114 bool m_mapDirty;
100 };
115 };
101
116
102 QT_CHARTS_END_NAMESPACE
117 QT_CHARTS_END_NAMESPACE
103
118
104 #endif
119 #endif
@@ -1,332 +1,322
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
4 ** Contact: https://www.qt.io/licensing/
5 **
5 **
6 ** This file is part of the Qt Charts module of the Qt Toolkit.
6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 **
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
8 ** $QT_BEGIN_LICENSE:GPL$
9 ** Commercial License Usage
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
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
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.
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
16 **
17 ** GNU General Public License Usage
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
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
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
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
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
25 **
26 ** $QT_END_LICENSE$
26 ** $QT_END_LICENSE$
27 **
27 **
28 ****************************************************************************/
28 ****************************************************************************/
29
29
30 #include "declarativerendernode.h"
30 #include "declarativerendernode.h"
31
31
32 #include <QtGui/QOpenGLContext>
32 #include <QtGui/QOpenGLContext>
33 #include <QtGui/QOpenGLFunctions>
33 #include <QtGui/QOpenGLFunctions>
34 #include <QtGui/QOpenGLFramebufferObjectFormat>
34 #include <QtGui/QOpenGLFramebufferObjectFormat>
35 #include <QtGui/QOpenGLFramebufferObject>
35 #include <QtGui/QOpenGLFramebufferObject>
36 #include <QOpenGLShaderProgram>
36 #include <QOpenGLShaderProgram>
37 #include <QtGui/QOpenGLBuffer>
37 #include <QtGui/QOpenGLBuffer>
38
38
39 //#define QDEBUG_TRACE_GL_FPS
39 //#define QDEBUG_TRACE_GL_FPS
40 #ifdef QDEBUG_TRACE_GL_FPS
40 #ifdef QDEBUG_TRACE_GL_FPS
41 # include <QElapsedTimer>
41 # include <QElapsedTimer>
42 #endif
42 #endif
43
43
44 QT_CHARTS_BEGIN_NAMESPACE
44 QT_CHARTS_BEGIN_NAMESPACE
45
45
46 // This node draws the xy series data on a transparent background using OpenGL.
46 // This node draws the xy series data on a transparent background using OpenGL.
47 // It is used as a child node of the chart node.
47 // It is used as a child node of the chart node.
48 DeclarativeRenderNode::DeclarativeRenderNode(QQuickWindow *window) :
48 DeclarativeRenderNode::DeclarativeRenderNode(QQuickWindow *window) :
49 QObject(),
49 QObject(),
50 QSGSimpleTextureNode(),
50 QSGSimpleTextureNode(),
51 m_texture(0),
51 m_texture(0),
52 m_window(window),
52 m_window(window),
53 m_textureOptions(QQuickWindow::TextureHasAlphaChannel),
53 m_textureOptions(QQuickWindow::TextureHasAlphaChannel),
54 m_textureSize(1, 1),
54 m_textureSize(1, 1),
55 m_recreateFbo(false),
55 m_recreateFbo(false),
56 m_fbo(0),
56 m_fbo(0),
57 m_program(0),
57 m_program(0),
58 m_shaderAttribLoc(-1),
58 m_shaderAttribLoc(-1),
59 m_colorUniformLoc(-1),
59 m_colorUniformLoc(-1),
60 m_minUniformLoc(-1),
60 m_minUniformLoc(-1),
61 m_deltaUniformLoc(-1),
61 m_deltaUniformLoc(-1),
62 m_pointSizeUniformLoc(-1),
62 m_pointSizeUniformLoc(-1),
63 m_renderNeeded(true)
63 m_renderNeeded(true)
64 {
64 {
65 initializeOpenGLFunctions();
65 initializeOpenGLFunctions();
66
66
67 // Our texture node must have a texture, so use a default one pixel texture
67 // Our texture node must have a texture, so use a default one pixel texture
68 GLuint defaultTexture = 0;
68 GLuint defaultTexture = 0;
69 glGenTextures(1, &defaultTexture);
69 glGenTextures(1, &defaultTexture);
70 glBindTexture(GL_TEXTURE_2D, defaultTexture);
70 glBindTexture(GL_TEXTURE_2D, defaultTexture);
71 uchar buf[4] = { 0, 0, 0, 0 };
71 uchar buf[4] = { 0, 0, 0, 0 };
72 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &buf);
72 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &buf);
73
73
74 QQuickWindow::CreateTextureOptions defaultTextureOptions = QQuickWindow::CreateTextureOptions(
74 QQuickWindow::CreateTextureOptions defaultTextureOptions = QQuickWindow::CreateTextureOptions(
75 QQuickWindow::TextureHasAlphaChannel | QQuickWindow::TextureOwnsGLTexture);
75 QQuickWindow::TextureHasAlphaChannel | QQuickWindow::TextureOwnsGLTexture);
76 m_texture = m_window->createTextureFromId(defaultTexture, QSize(1, 1), defaultTextureOptions);
76 m_texture = m_window->createTextureFromId(defaultTexture, QSize(1, 1), defaultTextureOptions);
77
77
78 setTexture(m_texture);
78 setTexture(m_texture);
79 setFiltering(QSGTexture::Linear);
79 setFiltering(QSGTexture::Linear);
80 setTextureCoordinatesTransform(QSGSimpleTextureNode::MirrorVertically);
80 setTextureCoordinatesTransform(QSGSimpleTextureNode::MirrorVertically);
81 }
81 }
82
82
83 DeclarativeRenderNode::~DeclarativeRenderNode()
83 DeclarativeRenderNode::~DeclarativeRenderNode()
84 {
84 {
85 delete m_texture;
85 delete m_texture;
86 delete m_fbo;
86 delete m_fbo;
87
87
88 delete m_program;
88 delete m_program;
89 m_program = 0;
89 m_program = 0;
90
90
91 cleanXYSeriesResources(0);
91 cleanXYSeriesResources(0);
92 }
92 }
93
93
94 static const char *vertexSource =
94 static const char *vertexSource =
95 "attribute highp vec2 points;\n"
95 "attribute highp vec2 points;\n"
96 "uniform highp vec2 min;\n"
96 "uniform highp vec2 min;\n"
97 "uniform highp vec2 delta;\n"
97 "uniform highp vec2 delta;\n"
98 "uniform highp float pointSize;\n"
98 "uniform highp float pointSize;\n"
99 "uniform highp mat4 matrix;\n"
99 "void main() {\n"
100 "void main() {\n"
100 " vec2 normalPoint = vec2(-1, -1) + ((points - min) / delta);\n"
101 " vec2 normalPoint = vec2(-1, -1) + ((points - min) / delta);\n"
101 " gl_Position = vec4(normalPoint, 0, 1);\n"
102 " gl_Position = matrix * vec4(normalPoint, 0, 1);\n"
102 " gl_PointSize = pointSize;\n"
103 " gl_PointSize = pointSize;\n"
103 "}";
104 "}";
104 static const char *fragmentSource =
105 static const char *fragmentSource =
105 "uniform highp vec3 color;\n"
106 "uniform highp vec3 color;\n"
106 "void main() {\n"
107 "void main() {\n"
107 " gl_FragColor = vec4(color,1);\n"
108 " gl_FragColor = vec4(color,1);\n"
108 "}\n";
109 "}\n";
109
110
110 // Must be called on render thread and in context
111 // Must be called on render thread and in context
111 void DeclarativeRenderNode::initGL()
112 void DeclarativeRenderNode::initGL()
112 {
113 {
113 recreateFBO();
114 recreateFBO();
114
115
115 m_program = new QOpenGLShaderProgram;
116 m_program = new QOpenGLShaderProgram;
116 m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource);
117 m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource);
117 m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentSource);
118 m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentSource);
118 m_program->bindAttributeLocation("points", 0);
119 m_program->bindAttributeLocation("points", 0);
119 m_program->link();
120 m_program->link();
120
121
121 m_program->bind();
122 m_program->bind();
122 m_colorUniformLoc = m_program->uniformLocation("color");
123 m_colorUniformLoc = m_program->uniformLocation("color");
123 m_minUniformLoc = m_program->uniformLocation("min");
124 m_minUniformLoc = m_program->uniformLocation("min");
124 m_deltaUniformLoc = m_program->uniformLocation("delta");
125 m_deltaUniformLoc = m_program->uniformLocation("delta");
125 m_pointSizeUniformLoc = m_program->uniformLocation("pointSize");
126 m_pointSizeUniformLoc = m_program->uniformLocation("pointSize");
127 m_matrixUniformLoc = m_program->uniformLocation("matrix");
126
128
127 // Create a vertex array object. In OpenGL ES 2.0 and OpenGL 2.x
129 // Create a vertex array object. In OpenGL ES 2.0 and OpenGL 2.x
128 // implementations this is optional and support may not be present
130 // implementations this is optional and support may not be present
129 // at all. Nonetheless the below code works in all cases and makes
131 // at all. Nonetheless the below code works in all cases and makes
130 // sure there is a VAO when one is needed.
132 // sure there is a VAO when one is needed.
131 m_vao.create();
133 m_vao.create();
132 QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
134 QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
133
135
134 #if !defined(QT_OPENGL_ES_2)
136 #if !defined(QT_OPENGL_ES_2)
135 if (!QOpenGLContext::currentContext()->isOpenGLES()) {
137 if (!QOpenGLContext::currentContext()->isOpenGLES()) {
136 // Make it possible to change point primitive size and use textures with them in
138 // Make it possible to change point primitive size and use textures with them in
137 // the shaders. These are implicitly enabled in ES2.
139 // the shaders. These are implicitly enabled in ES2.
138 // Qt Quick doesn't change these flags, so it should be safe to just enable them
140 // Qt Quick doesn't change these flags, so it should be safe to just enable them
139 // at initialization.
141 // at initialization.
140 glEnable(GL_PROGRAM_POINT_SIZE);
142 glEnable(GL_PROGRAM_POINT_SIZE);
141 }
143 }
142 #endif
144 #endif
143
145
144 m_program->release();
146 m_program->release();
145 }
147 }
146
148
147 void DeclarativeRenderNode::recreateFBO()
149 void DeclarativeRenderNode::recreateFBO()
148 {
150 {
149 QOpenGLFramebufferObjectFormat fboFormat;
151 QOpenGLFramebufferObjectFormat fboFormat;
150 fboFormat.setAttachment(QOpenGLFramebufferObject::NoAttachment);
152 fboFormat.setAttachment(QOpenGLFramebufferObject::NoAttachment);
151 delete m_fbo;
153 delete m_fbo;
152 m_fbo = new QOpenGLFramebufferObject(m_textureSize.width(),
154 m_fbo = new QOpenGLFramebufferObject(m_textureSize.width(),
153 m_textureSize.height(),
155 m_textureSize.height(),
154 fboFormat);
156 fboFormat);
155
157
156 delete m_texture;
158 delete m_texture;
157 m_texture = m_window->createTextureFromId(m_fbo->texture(), m_textureSize, m_textureOptions);
159 m_texture = m_window->createTextureFromId(m_fbo->texture(), m_textureSize, m_textureOptions);
158 setTexture(m_texture);
160 setTexture(m_texture);
159
161
160 m_recreateFbo = false;
162 m_recreateFbo = false;
161 }
163 }
162
164
163 // Must be called on render thread and in context
165 // Must be called on render thread and in context
164 void DeclarativeRenderNode::setTextureSize(const QSize &size)
166 void DeclarativeRenderNode::setTextureSize(const QSize &size)
165 {
167 {
166 m_textureSize = size;
168 m_textureSize = size;
167 m_recreateFbo = true;
169 m_recreateFbo = true;
168 m_renderNeeded = true;
170 m_renderNeeded = true;
169 }
171 }
170
172
171 // Must be called on render thread while gui thread is blocked, and in context
173 // Must be called on render thread while gui thread is blocked, and in context
172 void DeclarativeRenderNode::setSeriesData(bool mapDirty, const GLXYDataMap &dataMap)
174 void DeclarativeRenderNode::setSeriesData(bool mapDirty, const GLXYDataMap &dataMap)
173 {
175 {
174 if (mapDirty) {
176 if (mapDirty) {
175 // Series have changed, recreate map, but utilize old data where feasible
177 // Series have changed, recreate map, but utilize old data where feasible
176 GLXYDataMap oldMap = m_xyDataMap;
178 GLXYDataMap oldMap = m_xyDataMap;
177 m_xyDataMap.clear();
179 m_xyDataMap.clear();
178
180
179 GLXYDataMapIterator i(dataMap);
181 GLXYDataMapIterator i(dataMap);
180 while (i.hasNext()) {
182 while (i.hasNext()) {
181 i.next();
183 i.next();
182 GLXYSeriesData *data = oldMap.take(i.key());
184 GLXYSeriesData *data = oldMap.take(i.key());
183 const GLXYSeriesData *newData = i.value();
185 const GLXYSeriesData *newData = i.value();
184 if (!data || newData->dirty) {
186 if (!data || newData->dirty) {
185 data = new GLXYSeriesData;
187 data = new GLXYSeriesData;
186 data->array = newData->array;
188 *data = *newData;
187 data->color = newData->color;
188 data->dirty = newData->dirty;
189 data->width = newData->width;
190 data->type = newData->type;
191 data->min = newData->min;
192 data->delta = newData->delta;
193 }
189 }
194 m_xyDataMap.insert(i.key(), data);
190 m_xyDataMap.insert(i.key(), data);
195 }
191 }
196 // Delete remaining old data
192 // Delete remaining old data
197 i = oldMap;
193 i = oldMap;
198 while (i.hasNext()) {
194 while (i.hasNext()) {
199 i.next();
195 i.next();
200 delete i.value();
196 delete i.value();
201 cleanXYSeriesResources(i.key());
197 cleanXYSeriesResources(i.key());
202 }
198 }
203 } else {
199 } else {
204 // Series have not changed, so just copy dirty data over
200 // Series have not changed, so just copy dirty data over
205 GLXYDataMapIterator i(dataMap);
201 GLXYDataMapIterator i(dataMap);
206 while (i.hasNext()) {
202 while (i.hasNext()) {
207 i.next();
203 i.next();
208 const GLXYSeriesData *newData = i.value();
204 const GLXYSeriesData *newData = i.value();
209 if (i.value()->dirty) {
205 if (i.value()->dirty) {
210 GLXYSeriesData *data = m_xyDataMap.value(i.key());
206 GLXYSeriesData *data = m_xyDataMap.value(i.key());
211 if (data) {
207 if (data)
212 data->array = newData->array;
208 *data = *newData;
213 data->color = newData->color;
214 data->dirty = newData->dirty;
215 data->width = newData->width;
216 data->type = newData->type;
217 data->min = newData->min;
218 data->delta = newData->delta;
219 }
220 }
209 }
221 }
210 }
222 }
211 }
223 markDirty(DirtyMaterial);
212 markDirty(DirtyMaterial);
224 m_renderNeeded = true;
213 m_renderNeeded = true;
225 }
214 }
226
215
227 void DeclarativeRenderNode::renderGL()
216 void DeclarativeRenderNode::renderGL()
228 {
217 {
229 glClearColor(0, 0, 0, 0);
218 glClearColor(0, 0, 0, 0);
230
219
231 QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
220 QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
232 m_program->bind();
221 m_program->bind();
233 m_fbo->bind();
222 m_fbo->bind();
234
223
235 glClear(GL_COLOR_BUFFER_BIT);
224 glClear(GL_COLOR_BUFFER_BIT);
236 glEnableVertexAttribArray(0);
225 glEnableVertexAttribArray(0);
237
226
238 glViewport(0, 0, m_textureSize.width(), m_textureSize.height());
227 glViewport(0, 0, m_textureSize.width(), m_textureSize.height());
239
228
240 GLXYDataMapIterator i(m_xyDataMap);
229 GLXYDataMapIterator i(m_xyDataMap);
241 while (i.hasNext()) {
230 while (i.hasNext()) {
242 i.next();
231 i.next();
243 QOpenGLBuffer *vbo = m_seriesBufferMap.value(i.key());
232 QOpenGLBuffer *vbo = m_seriesBufferMap.value(i.key());
244 GLXYSeriesData *data = i.value();
233 GLXYSeriesData *data = i.value();
245
234
246 m_program->setUniformValue(m_colorUniformLoc, data->color);
235 m_program->setUniformValue(m_colorUniformLoc, data->color);
247 m_program->setUniformValue(m_minUniformLoc, data->min);
236 m_program->setUniformValue(m_minUniformLoc, data->min);
248 m_program->setUniformValue(m_deltaUniformLoc, data->delta);
237 m_program->setUniformValue(m_deltaUniformLoc, data->delta);
238 m_program->setUniformValue(m_matrixUniformLoc, data->matrix);
249
239
250 if (!vbo) {
240 if (!vbo) {
251 vbo = new QOpenGLBuffer;
241 vbo = new QOpenGLBuffer;
252 m_seriesBufferMap.insert(i.key(), vbo);
242 m_seriesBufferMap.insert(i.key(), vbo);
253 vbo->create();
243 vbo->create();
254 }
244 }
255 vbo->bind();
245 vbo->bind();
256 if (data->dirty) {
246 if (data->dirty) {
257 vbo->allocate(data->array.constData(), data->array.count() * sizeof(GLfloat));
247 vbo->allocate(data->array.constData(), data->array.count() * sizeof(GLfloat));
258 data->dirty = false;
248 data->dirty = false;
259 }
249 }
260
250
261 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
251 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
262 if (data->type == QAbstractSeries::SeriesTypeLine) {
252 if (data->type == QAbstractSeries::SeriesTypeLine) {
263 glLineWidth(data->width);
253 glLineWidth(data->width);
264 glDrawArrays(GL_LINE_STRIP, 0, data->array.size() / 2);
254 glDrawArrays(GL_LINE_STRIP, 0, data->array.size() / 2);
265 } else { // Scatter
255 } else { // Scatter
266 m_program->setUniformValue(m_pointSizeUniformLoc, data->width);
256 m_program->setUniformValue(m_pointSizeUniformLoc, data->width);
267 glDrawArrays(GL_POINTS, 0, data->array.size() / 2);
257 glDrawArrays(GL_POINTS, 0, data->array.size() / 2);
268 }
258 }
269 vbo->release();
259 vbo->release();
270 }
260 }
271
261
272 #ifdef QDEBUG_TRACE_GL_FPS
262 #ifdef QDEBUG_TRACE_GL_FPS
273 static QElapsedTimer stopWatch;
263 static QElapsedTimer stopWatch;
274 static int frameCount = -1;
264 static int frameCount = -1;
275 if (frameCount == -1) {
265 if (frameCount == -1) {
276 stopWatch.start();
266 stopWatch.start();
277 frameCount = 0;
267 frameCount = 0;
278 }
268 }
279 frameCount++;
269 frameCount++;
280 int elapsed = stopWatch.elapsed();
270 int elapsed = stopWatch.elapsed();
281 if (elapsed >= 1000) {
271 if (elapsed >= 1000) {
282 elapsed = stopWatch.restart();
272 elapsed = stopWatch.restart();
283 qreal fps = qreal(0.1 * int(10000.0 * (qreal(frameCount) / qreal(elapsed))));
273 qreal fps = qreal(0.1 * int(10000.0 * (qreal(frameCount) / qreal(elapsed))));
284 qDebug() << "FPS:" << fps;
274 qDebug() << "FPS:" << fps;
285 frameCount = 0;
275 frameCount = 0;
286 }
276 }
287 #endif
277 #endif
288
278
289 markDirty(DirtyMaterial);
279 markDirty(DirtyMaterial);
290 m_window->resetOpenGLState();
280 m_window->resetOpenGLState();
291 }
281 }
292
282
293 // Must be called on render thread as response to beforeRendering signal
283 // Must be called on render thread as response to beforeRendering signal
294 void DeclarativeRenderNode::render()
284 void DeclarativeRenderNode::render()
295 {
285 {
296 if (m_renderNeeded) {
286 if (m_renderNeeded) {
297 if (m_xyDataMap.size()) {
287 if (m_xyDataMap.size()) {
298 if (!m_program)
288 if (!m_program)
299 initGL();
289 initGL();
300 if (m_recreateFbo)
290 if (m_recreateFbo)
301 recreateFBO();
291 recreateFBO();
302 renderGL();
292 renderGL();
303 } else {
293 } else {
304 if (rect() != QRectF()) {
294 if (rect() != QRectF()) {
305 glClearColor(0, 0, 0, 0);
295 glClearColor(0, 0, 0, 0);
306 m_fbo->bind();
296 m_fbo->bind();
307 glClear(GL_COLOR_BUFFER_BIT);
297 glClear(GL_COLOR_BUFFER_BIT);
308
298
309 // If last series was removed, zero out the node rect
299 // If last series was removed, zero out the node rect
310 setRect(QRectF());
300 setRect(QRectF());
311 }
301 }
312 }
302 }
313 m_renderNeeded = false;
303 m_renderNeeded = false;
314 }
304 }
315 }
305 }
316
306
317 void DeclarativeRenderNode::cleanXYSeriesResources(const QXYSeries *series)
307 void DeclarativeRenderNode::cleanXYSeriesResources(const QXYSeries *series)
318 {
308 {
319 if (series) {
309 if (series) {
320 delete m_seriesBufferMap.take(series);
310 delete m_seriesBufferMap.take(series);
321 delete m_xyDataMap.take(series);
311 delete m_xyDataMap.take(series);
322 } else {
312 } else {
323 foreach (QOpenGLBuffer *buffer, m_seriesBufferMap.values())
313 foreach (QOpenGLBuffer *buffer, m_seriesBufferMap.values())
324 delete buffer;
314 delete buffer;
325 m_seriesBufferMap.clear();
315 m_seriesBufferMap.clear();
326 foreach (GLXYSeriesData *data, m_xyDataMap.values())
316 foreach (GLXYSeriesData *data, m_xyDataMap.values())
327 delete data;
317 delete data;
328 m_xyDataMap.clear();
318 m_xyDataMap.clear();
329 }
319 }
330 }
320 }
331
321
332 QT_CHARTS_END_NAMESPACE
322 QT_CHARTS_END_NAMESPACE
@@ -1,84 +1,85
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
4 ** Contact: https://www.qt.io/licensing/
5 **
5 **
6 ** This file is part of the Qt Charts module of the Qt Toolkit.
6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 **
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
8 ** $QT_BEGIN_LICENSE:GPL$
9 ** Commercial License Usage
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
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
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.
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
16 **
17 ** GNU General Public License Usage
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
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
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
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
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
25 **
26 ** $QT_END_LICENSE$
26 ** $QT_END_LICENSE$
27 **
27 **
28 ****************************************************************************/
28 ****************************************************************************/
29
29
30 #ifndef DECLARATIVERENDERNODE_P_H
30 #ifndef DECLARATIVERENDERNODE_P_H
31 #define DECLARATIVERENDERNODE_P_H
31 #define DECLARATIVERENDERNODE_P_H
32
32
33 #include <QtCharts/QChartGlobal>
33 #include <QtCharts/QChartGlobal>
34 #include <private/glxyseriesdata_p.h>
34 #include <private/glxyseriesdata_p.h>
35 #include <QtQuick/QSGSimpleTextureNode>
35 #include <QtQuick/QSGSimpleTextureNode>
36 #include <QtQuick/QQuickWindow>
36 #include <QtQuick/QQuickWindow>
37 #include <QtGui/QOpenGLVertexArrayObject>
37 #include <QtGui/QOpenGLVertexArrayObject>
38 #include <QtGui/QOpenGLFunctions>
38 #include <QtGui/QOpenGLFunctions>
39 #include <QtGui/QOpenGLFramebufferObject>
39 #include <QtGui/QOpenGLFramebufferObject>
40 #include <QtGui/QOpenGLBuffer>
40 #include <QtGui/QOpenGLBuffer>
41
41
42 QT_CHARTS_BEGIN_NAMESPACE
42 QT_CHARTS_BEGIN_NAMESPACE
43
43
44 class DeclarativeRenderNode : public QObject, public QSGSimpleTextureNode, QOpenGLFunctions
44 class DeclarativeRenderNode : public QObject, public QSGSimpleTextureNode, QOpenGLFunctions
45 {
45 {
46 Q_OBJECT
46 Q_OBJECT
47 public:
47 public:
48 DeclarativeRenderNode(QQuickWindow *window);
48 DeclarativeRenderNode(QQuickWindow *window);
49 ~DeclarativeRenderNode();
49 ~DeclarativeRenderNode();
50
50
51 void initGL();
51 void initGL();
52 QSize textureSize() const { return m_textureSize; }
52 QSize textureSize() const { return m_textureSize; }
53 void setTextureSize(const QSize &size);
53 void setTextureSize(const QSize &size);
54 void setSeriesData(bool mapDirty, const GLXYDataMap &dataMap);
54 void setSeriesData(bool mapDirty, const GLXYDataMap &dataMap);
55
55
56 public Q_SLOTS:
56 public Q_SLOTS:
57 void render();
57 void render();
58
58
59 private:
59 private:
60 void renderGL();
60 void renderGL();
61 void recreateFBO();
61 void recreateFBO();
62 void cleanXYSeriesResources(const QXYSeries *series);
62 void cleanXYSeriesResources(const QXYSeries *series);
63
63
64 QSGTexture *m_texture;
64 QSGTexture *m_texture;
65 QQuickWindow *m_window;
65 QQuickWindow *m_window;
66 QQuickWindow::CreateTextureOptions m_textureOptions;
66 QQuickWindow::CreateTextureOptions m_textureOptions;
67 QSize m_textureSize;
67 QSize m_textureSize;
68 bool m_recreateFbo;
68 bool m_recreateFbo;
69 GLXYDataMap m_xyDataMap;
69 GLXYDataMap m_xyDataMap;
70 QOpenGLFramebufferObject *m_fbo;
70 QOpenGLFramebufferObject *m_fbo;
71 QOpenGLShaderProgram *m_program;
71 QOpenGLShaderProgram *m_program;
72 int m_shaderAttribLoc;
72 int m_shaderAttribLoc;
73 int m_colorUniformLoc;
73 int m_colorUniformLoc;
74 int m_minUniformLoc;
74 int m_minUniformLoc;
75 int m_deltaUniformLoc;
75 int m_deltaUniformLoc;
76 int m_pointSizeUniformLoc;
76 int m_pointSizeUniformLoc;
77 int m_matrixUniformLoc;
77 QOpenGLVertexArrayObject m_vao;
78 QOpenGLVertexArrayObject m_vao;
78 QHash<const QAbstractSeries *, QOpenGLBuffer *> m_seriesBufferMap;
79 QHash<const QAbstractSeries *, QOpenGLBuffer *> m_seriesBufferMap;
79 bool m_renderNeeded;
80 bool m_renderNeeded;
80 };
81 };
81
82
82 QT_CHARTS_END_NAMESPACE
83 QT_CHARTS_END_NAMESPACE
83
84
84 #endif // DECLARATIVERENDERNODE_P_H
85 #endif // DECLARATIVERENDERNODE_P_H
General Comments 0
You need to be logged in to leave comments. Login now