1 | // Copyright (C) 2023 The Qt Company Ltd. |
---|---|
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include <QtCore/qmath.h> |
5 | #include "qabstract3daxis_p.h" |
6 | #include "qbar3dseries_p.h" |
7 | #include "qcategory3daxis_p.h" |
8 | #include "qquickgraphsbars_p.h" |
9 | #include "qvalue3daxis_p.h" |
10 | |
11 | QT_BEGIN_NAMESPACE |
12 | |
13 | /*! |
14 | * \class QBar3DSeries |
15 | * \inmodule QtGraphs |
16 | * \ingroup graphs_3D |
17 | * \brief The QBar3DSeries class represents a data series in a 3D bar graph. |
18 | * |
19 | * This class manages the series specific visual elements, as well as the series |
20 | * data (via a data proxy). |
21 | * |
22 | * Regarding the proxy-series relationship, it is crucial to highlight |
23 | * a couple of key points. In this context, data is stored in series and |
24 | * users can access the dataset through the series. This series is controlled |
25 | * or represented by a proxy object. Thus, the proxy can be used to manage various |
26 | * operations on the data and update the actual dataset. However, it is necessary |
27 | * to create a series associated with this proxy to edit the dataset. |
28 | * |
29 | * If no data proxy is set explicitly for the series, the series creates a |
30 | * default proxy. Setting another proxy will destroy the existing proxy and all |
31 | * data added to the series. |
32 | * |
33 | * QBar3DSeries supports the following format tags for QAbstract3DSeries::setItemLabelFormat(): |
34 | * \table |
35 | * \row |
36 | * \li @rowTitle \li Title from row axis |
37 | * \row |
38 | * \li @colTitle \li Title from column axis |
39 | * \row |
40 | * \li @valueTitle \li Title from value axis |
41 | * \row |
42 | * \li @rowIdx \li Visible row index. Localized using the graph locale. |
43 | * \row |
44 | * \li @colIdx \li Visible column index. Localized using the graph locale. |
45 | * \row |
46 | * \li @rowLabel \li Label from row axis |
47 | * \row |
48 | * \li @colLabel \li Label from column axis |
49 | * \row |
50 | * \li @valueLabel \li Item value formatted using the format of the value |
51 | * axis attached to the graph. For more information, |
52 | * see \l{QValue3DAxis::labelFormat}. |
53 | * \row |
54 | * \li @seriesName \li Name of the series |
55 | * \row |
56 | * \li %<format spec> \li Item value in the specified format. Formatted |
57 | * using the same rules as \l{QValue3DAxis::labelFormat}. |
58 | * \endtable |
59 | * |
60 | * For example: |
61 | * \snippet doc_src_qtgraphs.cpp labelformat |
62 | * |
63 | * \sa {Qt Graphs Data Handling with 3D}, Q3DGraphsWidgetItem::locale |
64 | */ |
65 | |
66 | /*! |
67 | * \qmltype Bar3DSeries |
68 | * \inqmlmodule QtGraphs |
69 | * \ingroup graphs_qml_3D |
70 | * \nativetype QBar3DSeries |
71 | * \inherits Abstract3DSeries |
72 | * \brief Represents a data series in a 3D bar graph. |
73 | * |
74 | * This type manages the series specific visual elements, as well as the series |
75 | * data (via a data proxy). |
76 | * |
77 | * Bar3DSeries supports the following format tags for itemLabelFormat: |
78 | * \table |
79 | * \row |
80 | * \li @rowTitle \li Title from row axis |
81 | * \row |
82 | * \li @colTitle \li Title from column axis |
83 | * \row |
84 | * \li @valueTitle \li Title from value axis |
85 | * \row |
86 | * \li @rowIdx \li Visible row index. Localized using the graph locale. |
87 | * \row |
88 | * \li @colIdx \li Visible column index. Localized using the graph locale. |
89 | * \row |
90 | * \li @rowLabel \li Label from row axis |
91 | * \row |
92 | * \li @colLabel \li Label from column axis |
93 | * \row |
94 | * \li @valueLabel \li Item value formatted using the format of the value |
95 | * axis attached to the graph. For more information, |
96 | * see \l{QValue3DAxis::labelFormat}{labelFormat}. |
97 | * \row |
98 | * \li @seriesName \li Name of the series |
99 | * \row |
100 | * \li %<format spec> \li Item value in the specified format. Formatted |
101 | * using the same rules as \l{QValue3DAxis::labelFormat}{labelFormat}. |
102 | * \endtable |
103 | * |
104 | * For a more complete description, see QBar3DSeries. |
105 | * |
106 | * \sa {Qt Graphs Data Handling with 3D} |
107 | */ |
108 | |
109 | /*! |
110 | * \qmlproperty BarDataProxy Bar3DSeries::dataProxy |
111 | * |
112 | * The active data proxy. The series assumes ownership of any proxy set to |
113 | * it and deletes any previously set proxy when a new one is added. The proxy |
114 | * cannot be null or set to another series. |
115 | */ |
116 | |
117 | /*! |
118 | * \qmlproperty point Bar3DSeries::selectedBar |
119 | * |
120 | * The bar in the series that is selected. |
121 | * |
122 | * The position of the selected bar is specified as a row and column in the |
123 | * data array of the series. |
124 | * |
125 | * Only one bar can be selected at a time. |
126 | * |
127 | * To clear the selection from this series, assign invalidSelectionPosition as the |
128 | * position. |
129 | * |
130 | * If this series is added to a graph, the graph can adjust the selection |
131 | * according to user interaction or if it becomes invalid. Selecting a bar on |
132 | * another added series will also clear the selection. |
133 | * |
134 | * Removing rows from or inserting rows into the series before the row of the |
135 | * selected bar will adjust the selection so that the same bar will stay |
136 | * selected. |
137 | * |
138 | * \sa {GraphsItem3D::clearSelection()}{GraphsItem3D.clearSelection()} |
139 | */ |
140 | |
141 | /*! |
142 | * \qmlproperty point Bar3DSeries::invalidSelectionPosition |
143 | * \readonly |
144 | * |
145 | * A constant property providing an invalid position for selection. This |
146 | * position is assigned to the selectedBar property to clear the selection from this |
147 | * series. |
148 | * |
149 | * \sa {GraphsItem3D::clearSelection()}{GraphsItem3D.clearSelection()} |
150 | */ |
151 | |
152 | /*! |
153 | * \qmlproperty real Bar3DSeries::meshAngle |
154 | * |
155 | * A convenience property for defining the series rotation angle in degrees. |
156 | * |
157 | * \note When reading this property, it is calculated from the |
158 | * \l{Abstract3DSeries::meshRotation}{Abstract3DSeries.meshRotation} value |
159 | * using floating point precision and always returns a value from zero to 360 |
160 | * degrees. |
161 | * |
162 | * \sa {Abstract3DSeries::meshRotation}{Abstract3DSeries.meshRotation} |
163 | */ |
164 | |
165 | /*! |
166 | * \qmlproperty list<Color> Bar3DSeries::rowColors |
167 | * This property can be used to draw the rows of the series in different colors. |
168 | * The \l{QGraphsTheme::colorStyle}{GraphsTheme.colorStyle} must be set to |
169 | * \c Uniform to use this property. |
170 | * \note If the property is set and the theme is changed, |
171 | * the rowColors list is not cleared automatically. |
172 | * |
173 | * \sa QGraphsTheme::ColorStyle::Uniform |
174 | */ |
175 | |
176 | /*! |
177 | * \qmlproperty list Bar3DSeries::rowLabels |
178 | * |
179 | * The optional row labels for the array. Indexes in this array match the row |
180 | * indexes in the data array. |
181 | * If the list is shorter than the number of rows, all rows will not get labels. |
182 | */ |
183 | |
184 | /*! |
185 | * \qmlproperty list Bar3DSeries::columnLabels |
186 | * |
187 | * The optional column labels for the array. Indexes in this array match column |
188 | * indexes in rows. If the list is shorter than the longest row, all columns |
189 | * will not get labels. |
190 | */ |
191 | |
192 | /*! |
193 | * \qmlproperty BarDataArray Bar3DSeries::dataArray |
194 | * |
195 | * Holds the reference of the data array. |
196 | * |
197 | * dataArrayChanged signal is emitted when data array is set, unless \a newDataArray |
198 | * is identical to the previous one. |
199 | * |
200 | * \note Before doing anything regarding the dataArray, a series must be created for |
201 | * the relevant proxy. |
202 | */ |
203 | |
204 | /*! |
205 | \qmlsignal Bar3DSeries::dataProxyChanged(BarDataProxy proxy) |
206 | |
207 | This signal is emitted when dataProxy changes to \a proxy. |
208 | */ |
209 | |
210 | /*! |
211 | \qmlsignal Bar3DSeries::selectedBarChanged(point position) |
212 | |
213 | This signal is emitted when selectedBar changes to \a position. |
214 | */ |
215 | |
216 | /*! |
217 | \qmlsignal Bar3DSeries::meshAngleChanged(real angle) |
218 | |
219 | This signal is emitted when meshAngle changes to \a angle. |
220 | */ |
221 | |
222 | /*! |
223 | \qmlsignal Bar3DSeries::rowColorsChanged(list<color> rowcolors) |
224 | |
225 | This signal is emitted when rowColors changes to \a rowcolors. |
226 | */ |
227 | |
228 | /*! |
229 | \qmlsignal Bar3DSeries::rowLabelsChanged() |
230 | |
231 | This signal is emitted when row labels change. |
232 | */ |
233 | |
234 | /*! |
235 | \qmlsignal Bar3DSeries::columnLabelsChanged() |
236 | |
237 | This signal is emitted when column labels change. |
238 | */ |
239 | |
240 | /*! |
241 | \qmlsignal Bar3DSeries::dataArrayChanged(BarDataArray array) |
242 | |
243 | This signal is emitted when dataArray changes to \a array. |
244 | */ |
245 | |
246 | /*! |
247 | * Constructs a bar 3D series with the parent \a parent. |
248 | */ |
249 | QBar3DSeries::QBar3DSeries(QObject *parent) |
250 | : QAbstract3DSeries(*(new QBar3DSeriesPrivate()), parent) |
251 | { |
252 | Q_D(QBar3DSeries); |
253 | // Default proxy |
254 | d->setDataProxy(new QBarDataProxy); |
255 | connectSignals(); |
256 | } |
257 | |
258 | /*! |
259 | * Constructs a bar 3D series with the data proxy \a dataProxy and the parent |
260 | * \a parent. |
261 | */ |
262 | QBar3DSeries::QBar3DSeries(QBarDataProxy *dataProxy, QObject *parent) |
263 | : QAbstract3DSeries(*(new QBar3DSeriesPrivate()), parent) |
264 | { |
265 | Q_D(QBar3DSeries); |
266 | d->setDataProxy(dataProxy); |
267 | connectSignals(); |
268 | } |
269 | |
270 | /*! |
271 | * Deletes a bar 3D series. |
272 | */ |
273 | QBar3DSeries::~QBar3DSeries() |
274 | { |
275 | clearArray(); |
276 | } |
277 | |
278 | /*! |
279 | * \property QBar3DSeries::dataProxy |
280 | * |
281 | * \brief The active data proxy. |
282 | * |
283 | * The series assumes ownership of any proxy set to it and deletes any |
284 | * previously set proxy when a new one is added. The proxy cannot be null or |
285 | * set to another series. |
286 | */ |
287 | void QBar3DSeries::setDataProxy(QBarDataProxy *proxy) |
288 | { |
289 | Q_D(QBar3DSeries); |
290 | d->setDataProxy(proxy); |
291 | } |
292 | |
293 | QBarDataProxy *QBar3DSeries::dataProxy() const |
294 | { |
295 | Q_D(const QBar3DSeries); |
296 | return static_cast<QBarDataProxy *>(d->dataProxy()); |
297 | } |
298 | |
299 | /*! |
300 | * \property QBar3DSeries::selectedBar |
301 | * |
302 | * \brief The bar in the series that is selected. |
303 | * |
304 | */ |
305 | |
306 | /*! |
307 | * Selects the bar at the \a position position, specified as a row and column in |
308 | * the data array of the series. |
309 | * |
310 | * Only one bar can be selected at a time. |
311 | * |
312 | * To clear the selection from this series, invalidSelectionPosition() is set as |
313 | * \a position. |
314 | * |
315 | * If this series is added to a graph, the graph can adjust the selection |
316 | * according to user interaction or if it becomes invalid. Selecting a bar on |
317 | * another added series will also clear the selection. |
318 | * |
319 | * Removing rows from or inserting rows into the series before the row of the |
320 | * selected bar will adjust the selection so that the same bar will stay |
321 | * selected. |
322 | * |
323 | * \sa Q3DGraphsWidgetItem::clearSelection() |
324 | */ |
325 | void QBar3DSeries::setSelectedBar(QPoint position) |
326 | { |
327 | Q_D(QBar3DSeries); |
328 | // Don't do this in private to avoid loops, as that is used for callback from |
329 | // graph. |
330 | if (d->m_graph) |
331 | static_cast<QQuickGraphsBars *>(d->m_graph)->setSelectedBar(coord: position, series: this, enterSlice: true); |
332 | else |
333 | d->setSelectedBar(position); |
334 | } |
335 | |
336 | QPoint QBar3DSeries::selectedBar() const |
337 | { |
338 | Q_D(const QBar3DSeries); |
339 | return d->m_selectedBar; |
340 | } |
341 | |
342 | /*! |
343 | * Returns an invalid position for selection. This position is set to the |
344 | * selectedBar property to clear the selection from this series. |
345 | * |
346 | * \sa Q3DGraphsWidgetItem::clearSelection() |
347 | */ |
348 | QPoint QBar3DSeries::invalidSelectionPosition() |
349 | { |
350 | return QQuickGraphsBars::invalidSelectionPosition(); |
351 | } |
352 | |
353 | static inline float quaternionAngle(const QQuaternion &rotation) |
354 | { |
355 | return qRadiansToDegrees(radians: qAcos(v: rotation.scalar())) * 2.f; |
356 | } |
357 | |
358 | /*! |
359 | \property QBar3DSeries::meshAngle |
360 | |
361 | \brief The series rotation angle in degrees. |
362 | |
363 | Setting this property is equivalent to the following call: |
364 | |
365 | \code |
366 | setMeshRotation(QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, angle)) |
367 | \endcode |
368 | |
369 | \note When reading this property, it is calculated from the |
370 | QAbstract3DSeries::meshRotation value using floating point precision |
371 | and always returns a value from zero to 360 degrees. |
372 | |
373 | \sa QAbstract3DSeries::meshRotation |
374 | */ |
375 | void QBar3DSeries::setMeshAngle(float angle) |
376 | { |
377 | setMeshRotation(QQuaternion::fromAxisAndAngle(axis: upVector, angle)); |
378 | } |
379 | |
380 | float QBar3DSeries::meshAngle() const |
381 | { |
382 | QQuaternion rotation = meshRotation(); |
383 | |
384 | if (rotation.isIdentity() || rotation.x() != 0.0f || rotation.z() != 0.0f) |
385 | return 0.0f; |
386 | else |
387 | return quaternionAngle(rotation); |
388 | } |
389 | |
390 | /*! |
391 | * \property QBar3DSeries::rowColors |
392 | * |
393 | * \brief The list of row colors in the series. |
394 | * |
395 | * This property can be used to color |
396 | * the rows of the series in different colors. |
397 | * The QGraphsTheme::ColorStyle must be set to |
398 | * QGraphsTheme::ColorStyle::Uniform to use this property. |
399 | * |
400 | * \sa QGraphsTheme::ColorStyle::Uniform |
401 | */ |
402 | void QBar3DSeries::setRowColors(const QList<QColor> &colors) |
403 | { |
404 | Q_D(QBar3DSeries); |
405 | d->setRowColors(colors); |
406 | } |
407 | |
408 | /*! |
409 | * \property QBar3DSeries::dataArray |
410 | * |
411 | * \brief Data array for the series. |
412 | * |
413 | * Holds the reference of the data array. |
414 | * |
415 | * dataArrayChanged signal is emitted when data array is set, unless \a newDataArray |
416 | * is identical to the previous one. |
417 | * |
418 | * \note Before doing anything regarding the dataArray, a series must be created for |
419 | * the relevant proxy. |
420 | * |
421 | *\sa clearRow(qsizetype rowIndex) |
422 | * |
423 | *\sa clearArray() |
424 | */ |
425 | void QBar3DSeries::setDataArray(const QBarDataArray &newDataArray) |
426 | { |
427 | Q_D(QBar3DSeries); |
428 | if (d->m_dataArray.data() != newDataArray.data()) |
429 | d->m_dataArray = newDataArray; |
430 | } |
431 | |
432 | /*! |
433 | * Clears the existing row in the array according to given \a rowIndex. |
434 | */ |
435 | void QBar3DSeries::clearRow(qsizetype rowIndex) |
436 | { |
437 | Q_D(QBar3DSeries); |
438 | d->clearRow(rowIndex); |
439 | } |
440 | |
441 | /*! |
442 | * Clears the existing array. |
443 | */ |
444 | void QBar3DSeries::clearArray() |
445 | { |
446 | Q_D(QBar3DSeries); |
447 | d->clearArray(); |
448 | } |
449 | |
450 | const QBarDataArray &QBar3DSeries::dataArray() const & |
451 | { |
452 | Q_D(const QBar3DSeries); |
453 | return d->m_dataArray; |
454 | } |
455 | |
456 | QBarDataArray QBar3DSeries::dataArray() && |
457 | { |
458 | Q_D(QBar3DSeries); |
459 | return std::move(d->m_dataArray); |
460 | } |
461 | |
462 | /*! |
463 | * \property QBar3DSeries::rowLabels |
464 | * |
465 | * \brief The optional row labels for the array. |
466 | * |
467 | * Indexes in this array match the row indexes in the data array. |
468 | * If the list is shorter than the number of rows, all rows will not get labels. |
469 | */ |
470 | QStringList QBar3DSeries::rowLabels() const |
471 | { |
472 | Q_D(const QBar3DSeries); |
473 | return d->m_rowLabels; |
474 | } |
475 | |
476 | void QBar3DSeries::setRowLabels(const QStringList &labels) |
477 | { |
478 | Q_D(QBar3DSeries); |
479 | if (rowLabels() != labels) { |
480 | d->setRowLabels(labels); |
481 | emit rowLabelsChanged(); |
482 | } |
483 | } |
484 | |
485 | /*! |
486 | * \property QBar3DSeries::columnLabels |
487 | * |
488 | * \brief The optional column labels for the array. |
489 | * |
490 | * Indexes in this array match column indexes in rows. |
491 | * If the list is shorter than the longest row, all columns will not get labels. |
492 | */ |
493 | QStringList QBar3DSeries::columnLabels() const |
494 | { |
495 | Q_D(const QBar3DSeries); |
496 | return d->m_columnLabels; |
497 | } |
498 | |
499 | void QBar3DSeries::setColumnLabels(const QStringList &labels) |
500 | { |
501 | Q_D(QBar3DSeries); |
502 | if (columnLabels() != labels) { |
503 | d->setColumnLabels(labels); |
504 | emit columnLabelsChanged(); |
505 | } |
506 | } |
507 | |
508 | QList<QColor> QBar3DSeries::rowColors() const |
509 | { |
510 | Q_D(const QBar3DSeries); |
511 | return d->m_rowColors; |
512 | } |
513 | |
514 | /*! |
515 | * \internal |
516 | */ |
517 | void QBar3DSeries::connectSignals() |
518 | { |
519 | QObject::connect(sender: this, |
520 | signal: &QAbstract3DSeries::meshRotationChanged, |
521 | context: this, |
522 | slot: &QBar3DSeries::handleMeshRotationChanged); |
523 | } |
524 | |
525 | /*! |
526 | * \internal |
527 | */ |
528 | void QBar3DSeries::handleMeshRotationChanged(const QQuaternion &rotation) |
529 | { |
530 | emit meshAngleChanged(angle: quaternionAngle(rotation)); |
531 | } |
532 | |
533 | // QBar3DSeriesPrivate |
534 | |
535 | QBar3DSeriesPrivate::QBar3DSeriesPrivate() |
536 | : QAbstract3DSeriesPrivate(QAbstract3DSeries::SeriesType::Bar) |
537 | , m_selectedBar(QQuickGraphsBars::invalidSelectionPosition()) |
538 | { |
539 | m_itemLabelFormat = QStringLiteral("@valueLabel"); |
540 | m_mesh = QAbstract3DSeries::Mesh::BevelBar; |
541 | } |
542 | |
543 | QBar3DSeriesPrivate::~QBar3DSeriesPrivate() {} |
544 | |
545 | void QBar3DSeriesPrivate::fixRowLabels(qsizetype startIndex, |
546 | qsizetype count, |
547 | const QStringList &newLabels, |
548 | bool isInsert) |
549 | { |
550 | bool changed = false; |
551 | qsizetype currentSize = m_rowLabels.size(); |
552 | |
553 | qsizetype newSize = newLabels.size(); |
554 | if (startIndex >= currentSize) { |
555 | // Adding labels past old label array, create empty strings to fill |
556 | // intervening space |
557 | if (newSize) { |
558 | for (qsizetype i = currentSize; i < startIndex; i++) |
559 | m_rowLabels << QString(); |
560 | // Doesn't matter if insert, append, or just change when there were no |
561 | // existing strings, just append new strings. |
562 | m_rowLabels << newLabels; |
563 | changed = true; |
564 | } |
565 | } else { |
566 | if (isInsert) { |
567 | qsizetype insertIndex = startIndex; |
568 | if (count) |
569 | changed = true; |
570 | for (qsizetype i = 0; i < count; i++) { |
571 | if (i < newSize) |
572 | m_rowLabels.insert(i: insertIndex++, t: newLabels.at(i)); |
573 | else |
574 | m_rowLabels.insert(i: insertIndex++, t: QString()); |
575 | } |
576 | } else { |
577 | // Either append or change, replace labels up to array end and then add |
578 | // new ones |
579 | qsizetype lastChangeIndex = count + startIndex; |
580 | qsizetype newIndex = 0; |
581 | for (qsizetype i = startIndex; i < lastChangeIndex; i++) { |
582 | if (i >= currentSize) { |
583 | // Label past the current size, so just append the new label |
584 | if (newSize < newIndex) { |
585 | changed = true; |
586 | m_rowLabels << newLabels.at(i: newIndex); |
587 | } else { |
588 | break; // No point appending empty strings, so just exit |
589 | } |
590 | } else if (newSize > newIndex) { |
591 | // Replace existing label |
592 | if (m_rowLabels.at(i) != newLabels.at(i: newIndex)) { |
593 | changed = true; |
594 | m_rowLabels[i] = newLabels.at(i: newIndex); |
595 | } |
596 | } else { |
597 | // No more new labels, so clear existing label |
598 | if (!m_rowLabels.at(i).isEmpty()) { |
599 | changed = true; |
600 | m_rowLabels[i] = QString(); |
601 | } |
602 | } |
603 | newIndex++; |
604 | } |
605 | } |
606 | } |
607 | |
608 | if (changed) { |
609 | Q_Q(QBar3DSeries); |
610 | emit q->rowLabelsChanged(); |
611 | } |
612 | } |
613 | |
614 | void QBar3DSeriesPrivate::setDataProxy(QAbstractDataProxy *proxy) |
615 | { |
616 | Q_ASSERT(proxy->type() == QAbstractDataProxy::DataType::Bar); |
617 | Q_Q(QBar3DSeries); |
618 | |
619 | QAbstract3DSeriesPrivate::setDataProxy(proxy); |
620 | |
621 | emit q->dataProxyChanged(proxy: static_cast<QBarDataProxy *>(proxy)); |
622 | } |
623 | |
624 | void QBar3DSeriesPrivate::connectGraphAndProxy(QQuickGraphsItem *newGraph) |
625 | { |
626 | Q_Q(QBar3DSeries); |
627 | QBarDataProxy *barDataProxy = static_cast<QBarDataProxy *>(m_dataProxy); |
628 | |
629 | if (m_graph && barDataProxy) { |
630 | // Disconnect old graph/old proxy |
631 | QObject::disconnect(sender: barDataProxy, signal: 0, receiver: m_graph, member: 0); |
632 | QObject::disconnect(sender: q, signal: 0, receiver: m_graph, member: 0); |
633 | } |
634 | |
635 | if (newGraph && barDataProxy) { |
636 | QQuickGraphsBars *graph = static_cast<QQuickGraphsBars *>(newGraph); |
637 | QObject::connect(sender: barDataProxy, |
638 | signal: &QBarDataProxy::arrayReset, |
639 | context: graph, |
640 | slot: &QQuickGraphsBars::handleArrayReset); |
641 | QObject::connect(sender: barDataProxy, |
642 | signal: &QBarDataProxy::rowsAdded, |
643 | context: graph, |
644 | slot: &QQuickGraphsBars::handleRowsAdded); |
645 | QObject::connect(sender: barDataProxy, |
646 | signal: &QBarDataProxy::rowsChanged, |
647 | context: graph, |
648 | slot: &QQuickGraphsBars::handleRowsChanged); |
649 | QObject::connect(sender: barDataProxy, |
650 | signal: &QBarDataProxy::rowsRemoved, |
651 | context: graph, |
652 | slot: &QQuickGraphsBars::handleRowsRemoved); |
653 | QObject::connect(sender: barDataProxy, |
654 | signal: &QBarDataProxy::rowsInserted, |
655 | context: graph, |
656 | slot: &QQuickGraphsBars::handleRowsInserted); |
657 | QObject::connect(sender: barDataProxy, |
658 | signal: &QBarDataProxy::itemChanged, |
659 | context: graph, |
660 | slot: &QQuickGraphsBars::handleItemChanged); |
661 | QObject::connect(sender: q, |
662 | signal: &QBar3DSeries::rowLabelsChanged, |
663 | context: graph, |
664 | slot: &QQuickGraphsBars::handleDataRowLabelsChanged); |
665 | QObject::connect(sender: q, |
666 | signal: &QBar3DSeries::columnLabelsChanged, |
667 | context: graph, |
668 | slot: &QQuickGraphsBars::handleDataColumnLabelsChanged); |
669 | QObject::connect(sender: q, |
670 | signal: &QBar3DSeries::dataProxyChanged, |
671 | context: graph, |
672 | slot: &QQuickGraphsBars::handleArrayReset); |
673 | QObject::connect(sender: q, |
674 | signal: &QBar3DSeries::rowColorsChanged, |
675 | context: graph, |
676 | slot: &QQuickGraphsBars::handleRowColorsChanged); |
677 | } |
678 | } |
679 | |
680 | void QBar3DSeriesPrivate::createItemLabel() |
681 | { |
682 | Q_Q(QBar3DSeries); |
683 | static const QString rowIndexTag(QStringLiteral("@rowIdx")); |
684 | static const QString rowLabelTag(QStringLiteral("@rowLabel")); |
685 | static const QString rowTitleTag(QStringLiteral("@rowTitle")); |
686 | static const QString colIndexTag(QStringLiteral("@colIdx")); |
687 | static const QString colLabelTag(QStringLiteral("@colLabel")); |
688 | static const QString colTitleTag(QStringLiteral("@colTitle")); |
689 | static const QString valueTitleTag(QStringLiteral("@valueTitle")); |
690 | static const QString valueLabelTag(QStringLiteral("@valueLabel")); |
691 | static const QString seriesNameTag(QStringLiteral("@seriesName")); |
692 | |
693 | if (m_selectedBar == QBar3DSeries::invalidSelectionPosition()) { |
694 | m_itemLabel = QString(); |
695 | return; |
696 | } |
697 | |
698 | QLocale locale(QLocale::c()); |
699 | if (m_graph) |
700 | locale = m_graph->locale(); |
701 | else |
702 | return; |
703 | |
704 | QCategory3DAxis *categoryAxisZ = static_cast<QCategory3DAxis *>(m_graph->axisZ()); |
705 | QCategory3DAxis *categoryAxisX = static_cast<QCategory3DAxis *>(m_graph->axisX()); |
706 | QValue3DAxis *valueAxis = static_cast<QValue3DAxis *>(m_graph->axisY()); |
707 | qreal selectedBarValue = qreal(q->dataProxy()->itemAt(position: m_selectedBar).value()); |
708 | |
709 | // Custom format expects printf format specifier. There is no tag for it. |
710 | m_itemLabel = valueAxis->formatter()->stringForValue(value: selectedBarValue, format: m_itemLabelFormat); |
711 | |
712 | int selBarPosRow = m_selectedBar.x(); |
713 | int selBarPosCol = m_selectedBar.y(); |
714 | m_itemLabel.replace(before: rowIndexTag, after: locale.toString(i: selBarPosRow)); |
715 | if (categoryAxisZ->labels().size() > selBarPosRow) |
716 | m_itemLabel.replace(before: rowLabelTag, after: categoryAxisZ->labels().at(i: selBarPosRow)); |
717 | else |
718 | m_itemLabel.replace(before: rowLabelTag, after: QString()); |
719 | m_itemLabel.replace(before: rowTitleTag, after: categoryAxisZ->title()); |
720 | m_itemLabel.replace(before: colIndexTag, after: locale.toString(i: selBarPosCol)); |
721 | if (categoryAxisX->labels().size() > selBarPosCol) |
722 | m_itemLabel.replace(before: colLabelTag, after: categoryAxisX->labels().at(i: selBarPosCol)); |
723 | else |
724 | m_itemLabel.replace(before: colLabelTag, after: QString()); |
725 | m_itemLabel.replace(before: colTitleTag, after: categoryAxisX->title()); |
726 | m_itemLabel.replace(before: valueTitleTag, after: valueAxis->title()); |
727 | |
728 | if (m_itemLabel.contains(s: valueLabelTag)) { |
729 | QString valueLabelText = valueAxis->formatter()->stringForValue(value: selectedBarValue, |
730 | format: valueAxis->labelFormat()); |
731 | m_itemLabel.replace(before: valueLabelTag, after: valueLabelText); |
732 | } |
733 | |
734 | m_itemLabel.replace(before: seriesNameTag, after: m_name); |
735 | } |
736 | |
737 | void QBar3DSeriesPrivate::setSelectedBar(QPoint position) |
738 | { |
739 | Q_Q(QBar3DSeries); |
740 | if (position != m_selectedBar) { |
741 | markItemLabelDirty(); |
742 | m_selectedBar = position; |
743 | emit q->selectedBarChanged(position: m_selectedBar); |
744 | } |
745 | } |
746 | |
747 | void QBar3DSeriesPrivate::setRowColors(const QList<QColor> &colors) |
748 | { |
749 | Q_Q(QBar3DSeries); |
750 | if (m_rowColors != colors) { |
751 | m_rowColors = colors; |
752 | emit q->rowColorsChanged(rowcolors: m_rowColors); |
753 | } |
754 | } |
755 | |
756 | void QBar3DSeriesPrivate::setDataArray(const QBarDataArray &newDataArray) |
757 | { |
758 | m_dataArray = newDataArray; |
759 | } |
760 | |
761 | void QBar3DSeriesPrivate::clearRow(qsizetype rowIndex) |
762 | { |
763 | m_dataArray[rowIndex].clear(); |
764 | } |
765 | |
766 | void QBar3DSeriesPrivate::clearArray() |
767 | { |
768 | m_dataArray.clear(); |
769 | } |
770 | |
771 | void QBar3DSeriesPrivate::setRowLabels(const QStringList &labels) |
772 | { |
773 | m_rowLabels = labels; |
774 | } |
775 | |
776 | void QBar3DSeriesPrivate::setColumnLabels(const QStringList &labels) |
777 | { |
778 | m_columnLabels = labels; |
779 | } |
780 | |
781 | QT_END_NAMESPACE |
782 |
Definitions
- QBar3DSeries
- QBar3DSeries
- ~QBar3DSeries
- setDataProxy
- dataProxy
- setSelectedBar
- selectedBar
- invalidSelectionPosition
- quaternionAngle
- setMeshAngle
- meshAngle
- setRowColors
- setDataArray
- clearRow
- clearArray
- dataArray
- dataArray
- rowLabels
- setRowLabels
- columnLabels
- setColumnLabels
- rowColors
- connectSignals
- handleMeshRotationChanged
- QBar3DSeriesPrivate
- ~QBar3DSeriesPrivate
- fixRowLabels
- setDataProxy
- connectGraphAndProxy
- createItemLabel
- setSelectedBar
- setRowColors
- setDataArray
- clearRow
- clearArray
- setRowLabels
Start learning QML with our Intro Training
Find out more