1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Charts module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 or (at your option) any later version |
20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by |
21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 |
22 | ** included in the packaging of this file. Please review the following |
23 | ** information to ensure the GNU General Public License requirements will |
24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
25 | ** |
26 | ** $QT_END_LICENSE$ |
27 | ** |
28 | ****************************************************************************/ |
29 | |
30 | #include <QtCharts/QAbstractBarSeries> |
31 | #include <private/qabstractbarseries_p.h> |
32 | #include <QtCharts/QBarSet> |
33 | #include <private/qbarset_p.h> |
34 | #include <private/abstractdomain_p.h> |
35 | #include <private/chartdataset_p.h> |
36 | #include <private/charttheme_p.h> |
37 | #include <QtCharts/QValueAxis> |
38 | #include <QtCharts/QBarCategoryAxis> |
39 | #include <QtCharts/QBarLegendMarker> |
40 | #include <private/baranimation_p.h> |
41 | #include <private/abstractbarchartitem_p.h> |
42 | #include <private/qchart_p.h> |
43 | |
44 | QT_CHARTS_BEGIN_NAMESPACE |
45 | |
46 | /*! |
47 | \class QAbstractBarSeries |
48 | \inmodule QtCharts |
49 | \brief The QAbstractBarSeries class is an abstract parent class for all bar series classes. |
50 | |
51 | In bar charts, bars are defined as bar sets that contain one data value for each category. |
52 | The position of a bar is specified by the category and its height by the data value. Bar |
53 | series that contain multiple bar sets group together bars that belong to the same category. |
54 | The way the bars are displayed is determined by the subclass of this class chosen to create |
55 | the bar chart. |
56 | |
57 | If a QValueAxis is used instead of QBarCategoryAxis for the main bar axis, the bars are |
58 | grouped around the index value of the category. |
59 | |
60 | See the \l {BarChart Example} {bar chart example} to learn how to use the QBarSeries class |
61 | to create a simple bar chart. |
62 | \image examples_barchart.png |
63 | |
64 | \sa QBarSet, QBarSeries, QStackedBarSeries, QPercentBarSeries |
65 | \sa QHorizontalBarSeries, QHorizontalStackedBarSeries, QHorizontalPercentBarSeries |
66 | */ |
67 | /*! |
68 | \qmltype AbstractBarSeries |
69 | \instantiates QAbstractBarSeries |
70 | \inqmlmodule QtCharts |
71 | |
72 | \inherits AbstractSeries |
73 | |
74 | \brief An abstract parent type for all bar series types. |
75 | |
76 | In bar charts, bars are defined as bar sets that contain one data value for each category. |
77 | The position of a bar is specified by the category and its height by the data value. Bar |
78 | series that contain multiple bar sets group together bars that belong to the same category. |
79 | The way the bars are displayed is determined by the type chosen to create the bar chart: |
80 | BarSeries, StackedBarSeries, PercentBarSeries, HorizontalBarSeries, HorizontalStackedBarSeries, |
81 | or HorizontalPercentBarSeries. |
82 | |
83 | If a ValueAxis type is used instead of a BarCategoryAxis type for the main bar axis, the |
84 | bars are grouped around the index value of the category. |
85 | |
86 | The following QML code snippet shows how to use the BarSeries and BarCategoryAxis type |
87 | to create a simple bar chart: |
88 | \snippet qmlchart/qml/qmlchart/View6.qml 1 |
89 | |
90 | \beginfloatleft |
91 | \image examples_qmlchart6.png |
92 | \endfloat |
93 | \clearfloat |
94 | */ |
95 | |
96 | /*! |
97 | \qmlproperty AbstractAxis AbstractBarSeries::axisX |
98 | The x-axis used for the series. If you leave both axisX and axisXTop undefined, a |
99 | BarCategoryAxis is created for the series. |
100 | \sa axisXTop |
101 | */ |
102 | |
103 | /*! |
104 | \qmlproperty AbstractAxis AbstractBarSeries::axisY |
105 | The y-axis used for the series. If you leave both axisY and axisYRight undefined, a |
106 | ValueAxis is created for the series. |
107 | \sa axisYRight |
108 | */ |
109 | |
110 | /*! |
111 | \qmlproperty AbstractAxis AbstractBarSeries::axisXTop |
112 | The x-axis used for the series, drawn on top of the chart view. |
113 | |
114 | \note You can only provide either axisX or axisXTop, but not both. |
115 | \sa axisX |
116 | */ |
117 | |
118 | /*! |
119 | \qmlproperty AbstractAxis AbstractBarSeries::axisYRight |
120 | The y-axis used for the series, drawn to the right of the chart view. |
121 | |
122 | \note You can only provide either axisY or axisYRight, but not both. |
123 | \sa axisY |
124 | */ |
125 | |
126 | /*! |
127 | \property QAbstractBarSeries::barWidth |
128 | \brief The width of the bars of the series. |
129 | |
130 | The unit of width is the unit of the x-axis. The minimum width for bars is zero, and negative |
131 | values are treated as zero. Setting the width to zero means that the width of the bar on the |
132 | screen is one pixel regardless of the scale of the x-axis. Bars wider than zero are scaled |
133 | using the x-axis scale. |
134 | |
135 | \note When used with QBarSeries, this value specifies the width of a group of bars instead of |
136 | that of a single bar. |
137 | \sa QBarSeries |
138 | */ |
139 | /*! |
140 | \qmlproperty real AbstractBarSeries::barWidth |
141 | The unit of width is the unit of the x-axis. The minimum width for bars is zero, and negative |
142 | values are treated as zero. Setting the width to zero means that the width of the bar on the |
143 | screen is one pixel regardless of the scale of the x-axis. Bars wider than zero are scaled |
144 | using the x-axis scale. |
145 | |
146 | \note When used with the BarSeries type, this value specifies the width of a group of bars |
147 | instead of that of a single bar. |
148 | */ |
149 | |
150 | /*! |
151 | \property QAbstractBarSeries::count |
152 | \brief The number of bar sets in a bar series. |
153 | */ |
154 | /*! |
155 | \qmlproperty int AbstractBarSeries::count |
156 | The number of bar sets in a bar series. |
157 | */ |
158 | |
159 | /*! |
160 | \property QAbstractBarSeries::labelsVisible |
161 | \brief The visibility of the labels in a bar series. |
162 | */ |
163 | /*! |
164 | \qmlproperty bool AbstractBarSeries::labelsVisible |
165 | The visibility of the labels in a bar series. |
166 | */ |
167 | |
168 | /*! |
169 | \property QAbstractBarSeries::labelsFormat |
170 | \brief The format used for showing labels in a bar series. |
171 | |
172 | QAbstractBarSeries supports the following format tag: |
173 | \table |
174 | \row |
175 | \li @value \li The value of the bar |
176 | \endtable |
177 | |
178 | For example, the following usage of the format tags would produce labels that show the value |
179 | followed by the unit (u): |
180 | \code |
181 | series->setLabelsFormat("@value u"); |
182 | \endcode |
183 | |
184 | By default, the labels show the value of the bar. For the percent bar series, \e % is added |
185 | after the value. The labels are shown on the plot area, if the bars are close to each other, |
186 | the labels may overlap. |
187 | |
188 | \sa labelsVisible, labelsPosition, labelsPrecision |
189 | */ |
190 | /*! |
191 | \qmlproperty string AbstractBarSeries::labelsFormat |
192 | The format used for showing labels in a bar series. |
193 | |
194 | \sa QAbstractBarSeries::labelsFormat, labelsVisible, labelsPosition |
195 | */ |
196 | /*! |
197 | \fn void QAbstractBarSeries::labelsFormatChanged(const QString &format) |
198 | This signal is emitted when the \a format of data value labels changes. |
199 | */ |
200 | |
201 | /*! |
202 | \enum QAbstractBarSeries::LabelsPosition |
203 | |
204 | This enum value describes the position of the data value labels: |
205 | |
206 | \value LabelsCenter Label is located in the center of the bar. |
207 | \value LabelsInsideEnd Label is located inside the bar at the top. |
208 | \value LabelsInsideBase Label is located inside the bar at the bottom. |
209 | \value LabelsOutsideEnd Label is located outside the bar at the top. |
210 | */ |
211 | |
212 | /*! |
213 | \property QAbstractBarSeries::labelsPosition |
214 | \brief The position of value labels. |
215 | |
216 | \sa labelsVisible, labelsFormat |
217 | */ |
218 | /*! |
219 | \qmlproperty enumeration AbstractBarSeries::labelsPosition |
220 | |
221 | The position of the data value labels: |
222 | |
223 | \value AbstractBarSeries.LabelsCenter |
224 | Label is located in the center of the bar. |
225 | \value AbstractBarSeries.LabelsInsideEnd |
226 | Label is located inside the bar at the top. |
227 | \value AbstractBarSeries.LabelsInsideBase |
228 | Label is located inside the bar at the bottom. |
229 | \value AbstractBarSeries.LabelsOutsideEnd |
230 | Label is located outside the bar at the top. |
231 | |
232 | \sa labelsVisible, labelsFormat |
233 | */ |
234 | /*! |
235 | \fn void QAbstractBarSeries::labelsPositionChanged(QAbstractBarSeries::LabelsPosition position) |
236 | This signal is emitted when the \a position of value labels changes. |
237 | */ |
238 | |
239 | /*! |
240 | \property QAbstractBarSeries::labelsAngle |
241 | \brief The angle of the value labels in degrees. |
242 | */ |
243 | /*! |
244 | \qmlproperty real AbstractBarSeries::labelsAngle |
245 | The angle of the value labels in degrees. |
246 | */ |
247 | /*! |
248 | \fn void QAbstractBarSeries::labelsAngleChanged(qreal angle) |
249 | This signal is emitted when the \a angle of the value labels changes. |
250 | */ |
251 | |
252 | /*! |
253 | \property QAbstractBarSeries::labelsPrecision |
254 | \brief The maximum amount of significant digits shown in value labels. |
255 | |
256 | Default value is 6. |
257 | */ |
258 | /*! |
259 | \qmlproperty real AbstractBarSeries::labelsPrecision |
260 | The maximum amount of significant digits shown in value labels. |
261 | |
262 | Default value is 6. |
263 | */ |
264 | /*! |
265 | \fn void QAbstractBarSeries::labelsPrecisionChanged(int precision) |
266 | This signal is emitted when the \a precision of the value labels changes. |
267 | */ |
268 | |
269 | /*! |
270 | \fn void QAbstractBarSeries::clicked(int index, QBarSet *barset) |
271 | This signal is emitted when the user clicks the bar specified by \a index |
272 | in the bar set specified by \a barset. |
273 | */ |
274 | /*! |
275 | \qmlsignal AbstractBarSeries::clicked(int index, BarSet barset) |
276 | This signal is emitted when the user clicks the bar specified by \a index |
277 | in the bar set specified by \a barset. |
278 | |
279 | The corresponding signal handler is \c onClicked. |
280 | */ |
281 | |
282 | /*! |
283 | \fn void QAbstractBarSeries::pressed(int index, QBarSet *barset) |
284 | This signal is emitted when the user clicks the bar specified by \a index |
285 | in the bar set specified by \a barset and holds down the mouse button. |
286 | */ |
287 | /*! |
288 | \qmlsignal AbstractBarSeries::pressed(int index, BarSet barset) |
289 | This signal is emitted when the user clicks the bar specified by \a index |
290 | in the bar set specified by \a barset and holds down the mouse button. |
291 | |
292 | The corresponding signal handler is \c onPressed. |
293 | */ |
294 | |
295 | /*! |
296 | \fn void QAbstractBarSeries::released(int index, QBarSet *barset) |
297 | This signal is emitted when the user releases the mouse press on the bar |
298 | specified by \a index in the bar set specified by \a barset. |
299 | */ |
300 | /*! |
301 | \qmlsignal AbstractBarSeries::released(int index, BarSet barset) |
302 | This signal is emitted when the user releases the mouse press on the bar |
303 | specified by \a index in the bar set specified by \a barset. |
304 | |
305 | The corresponding signal handler is \c onReleased. |
306 | */ |
307 | |
308 | /*! |
309 | \fn void QAbstractBarSeries::doubleClicked(int index, QBarSet *barset) |
310 | This signal is emitted when the user double-clicks the bar specified by \a index |
311 | in the bar set specified by \a barset. |
312 | */ |
313 | /*! |
314 | \qmlsignal AbstractBarSeries::doubleClicked(int index, BarSet barset) |
315 | This signal is emitted when the user double-clicks the bar specified by \a index |
316 | in the bar set specified by \a barset. |
317 | |
318 | The corresponding signal handler is \c onDoubleClicked. |
319 | */ |
320 | |
321 | /*! |
322 | \fn void QAbstractBarSeries::hovered(bool status, int index, QBarSet* barset) |
323 | |
324 | This signal is emitted when a mouse is hovered over the bar specified by \a index in the |
325 | bar set specified by \a barset. When the mouse moves over the bar, \a status turns \c true, |
326 | and when the mouse moves away again, it turns \c false. |
327 | */ |
328 | /*! |
329 | \qmlsignal AbstractBarSeries::hovered(bool status, int index, BarSet barset) |
330 | |
331 | This signal is emitted when a mouse is hovered over the bar specified by \a index in the |
332 | bar set specified by \a barset. When the mouse moves over the bar, \a status turns \c true, |
333 | and when the mouse moves away again, it turns \c false. |
334 | |
335 | The corresponding signal handler is \c onHovered. |
336 | */ |
337 | |
338 | /*! |
339 | \fn void QAbstractBarSeries::countChanged() |
340 | This signal is emitted when the number of bar sets is changed, for example by append() or |
341 | remove(). |
342 | */ |
343 | |
344 | /*! |
345 | \fn void QAbstractBarSeries::labelsVisibleChanged() |
346 | This signal is emitted when the labels' visibility changes. |
347 | \sa isLabelsVisible(), setLabelsVisible() |
348 | */ |
349 | |
350 | /*! |
351 | \fn void QAbstractBarSeries::barsetsAdded(QList<QBarSet*> sets) |
352 | This signal is emitted when the bar sets specified by \a sets are added to the series. |
353 | \sa append(), insert() |
354 | */ |
355 | /*! |
356 | \qmlsignal AbstractBarSeries::barsetsAdded() |
357 | This signal is emitted when bar sets are added to the series. |
358 | |
359 | The corresponding signal handler is \c onBarsetsAdded. |
360 | */ |
361 | |
362 | /*! |
363 | \fn void QAbstractBarSeries::barsetsRemoved(QList<QBarSet*> sets) |
364 | This signal is emitted when the bar sets specified by \a sets are removed from the series. |
365 | \sa remove() |
366 | */ |
367 | /*! |
368 | \qmlsignal AbstractBarSeries::barsetsRemoved() |
369 | This signal is emitted when bar sets are removed from the series. |
370 | |
371 | The corresponding signal handler is \c onBarsetsRemoved. |
372 | */ |
373 | |
374 | /*! |
375 | \qmlmethod BarSet AbstractBarSeries::at(int index) |
376 | Returns the bar set at \a index. Returns null if the index is not valid. |
377 | */ |
378 | |
379 | /*! |
380 | \qmlmethod BarSet AbstractBarSeries::append(string label, VariantList values) |
381 | Adds a new bar set with \a label and \a values to the index. \a values is |
382 | a list of real values. |
383 | |
384 | For example: |
385 | \code |
386 | myBarSeries.append("set 1", [0, 0.2, 0.2, 0.5, 0.4, 1.5, 0.9]); |
387 | \endcode |
388 | */ |
389 | |
390 | /*! |
391 | \qmlmethod BarSet AbstractBarSeries::insert(int index, string label, VariantList values) |
392 | Adds a new bar set with \a label and \a values to \a index. \a values can be a list |
393 | of real values or a list of XYPoint types. |
394 | |
395 | If the index value is equal to or less than zero, the new bar set is prepended to the bar |
396 | series. If the index value is equal to or greater than the number of bar sets in the bar |
397 | series, the new bar set is appended to the bar series. |
398 | |
399 | \sa append() |
400 | */ |
401 | |
402 | /*! |
403 | \qmlmethod bool AbstractBarSeries::remove(BarSet barset) |
404 | Removes the bar set specified by \a barset from the series. Returns \c true if successful, |
405 | \c false otherwise. |
406 | */ |
407 | |
408 | /*! |
409 | \qmlmethod AbstractBarSeries::clear() |
410 | Removes all bar sets from the series. |
411 | */ |
412 | |
413 | /*! |
414 | Removes the abstract bar series and the bar sets owned by it. |
415 | */ |
416 | QAbstractBarSeries::~QAbstractBarSeries() |
417 | { |
418 | |
419 | } |
420 | |
421 | /*! |
422 | \internal |
423 | */ |
424 | QAbstractBarSeries::QAbstractBarSeries(QAbstractBarSeriesPrivate &o, QObject *parent) |
425 | : QAbstractSeries(o, parent) |
426 | { |
427 | Q_D(QAbstractSeries); |
428 | QObject::connect(sender: this, SIGNAL(countChanged()), receiver: d, SIGNAL(countChanged())); |
429 | } |
430 | |
431 | /*! |
432 | Sets the width of the bars of the series to \a width. |
433 | */ |
434 | void QAbstractBarSeries::setBarWidth(qreal width) |
435 | { |
436 | Q_D(QAbstractBarSeries); |
437 | d->setBarWidth(width); |
438 | } |
439 | |
440 | /*! |
441 | Returns the width of the bars of the series. |
442 | \sa setBarWidth() |
443 | */ |
444 | qreal QAbstractBarSeries::barWidth() const |
445 | { |
446 | Q_D(const QAbstractBarSeries); |
447 | return d->barWidth(); |
448 | } |
449 | |
450 | /*! |
451 | Adds a set of bars specified by \a set to the bar series and takes ownership of it. If the set |
452 | is null or it already belongs to the series, it will not be appended. |
453 | Returns \c true if appending succeeded. |
454 | */ |
455 | bool QAbstractBarSeries::append(QBarSet *set) |
456 | { |
457 | Q_D(QAbstractBarSeries); |
458 | bool success = d->append(set); |
459 | if (success) { |
460 | QList<QBarSet *> sets; |
461 | sets.append(t: set); |
462 | set->setParent(this); |
463 | emit barsetsAdded(sets); |
464 | emit countChanged(); |
465 | } |
466 | return success; |
467 | } |
468 | |
469 | /*! |
470 | Removes the bar set specified by \a set from the series and permanently deletes it if |
471 | the removal succeeds. Returns \c true if the set was removed. |
472 | */ |
473 | bool QAbstractBarSeries::remove(QBarSet *set) |
474 | { |
475 | Q_D(QAbstractBarSeries); |
476 | bool success = d->remove(set); |
477 | if (success) { |
478 | QList<QBarSet *> sets; |
479 | sets.append(t: set); |
480 | set->setParent(0); |
481 | emit barsetsRemoved(sets); |
482 | emit countChanged(); |
483 | delete set; |
484 | set = 0; |
485 | } |
486 | return success; |
487 | } |
488 | |
489 | /*! |
490 | Takes a single \a set from the series. Does not delete the bar set object. |
491 | \note The series remains the barset's parent object. You must set the |
492 | parent object to take full ownership. |
493 | |
494 | Returns \c true if the take operation succeeds. |
495 | */ |
496 | bool QAbstractBarSeries::take(QBarSet *set) |
497 | { |
498 | Q_D(QAbstractBarSeries); |
499 | bool success = d->remove(set); |
500 | if (success) { |
501 | QList<QBarSet *> sets; |
502 | sets.append(t: set); |
503 | emit barsetsRemoved(sets); |
504 | emit countChanged(); |
505 | } |
506 | return success; |
507 | } |
508 | |
509 | /*! |
510 | Adds a list of bar sets specified by \a sets to a bar series and takes ownership of the sets. |
511 | Returns \c true if all sets were appended successfully. If any of the sets is null or was |
512 | previously appended to the series, nothing is appended and this function returns \c false. |
513 | If any of the sets appears in the list more than once, nothing is appended and this function |
514 | returns \c false. |
515 | */ |
516 | bool QAbstractBarSeries::append(QList<QBarSet *> sets) |
517 | { |
518 | Q_D(QAbstractBarSeries); |
519 | bool success = d->append(sets); |
520 | if (success) { |
521 | foreach (QBarSet *set, sets) |
522 | set->setParent(this); |
523 | emit barsetsAdded(sets); |
524 | emit countChanged(); |
525 | } |
526 | return success; |
527 | } |
528 | |
529 | /*! |
530 | Inserts a bar set specified by \a set to a series at the position specified by \a index |
531 | and takes ownership of the set. If the set is null or already belongs to the series, it will |
532 | not be appended. Returns \c true if inserting succeeds. |
533 | */ |
534 | bool QAbstractBarSeries::insert(int index, QBarSet *set) |
535 | { |
536 | Q_D(QAbstractBarSeries); |
537 | bool success = d->insert(index, set); |
538 | if (success) { |
539 | QList<QBarSet *> sets; |
540 | sets.append(t: set); |
541 | emit barsetsAdded(sets); |
542 | emit countChanged(); |
543 | } |
544 | return success; |
545 | } |
546 | |
547 | /*! |
548 | Removes all bar sets from the series and permanently deletes them. |
549 | */ |
550 | void QAbstractBarSeries::clear() |
551 | { |
552 | Q_D(QAbstractBarSeries); |
553 | QList<QBarSet *> sets = barSets(); |
554 | bool success = d->remove(sets); |
555 | if (success) { |
556 | emit barsetsRemoved(sets); |
557 | emit countChanged(); |
558 | foreach (QBarSet *set, sets) |
559 | delete set; |
560 | } |
561 | } |
562 | |
563 | /*! |
564 | Returns the number of bar sets in a bar series. |
565 | */ |
566 | int QAbstractBarSeries::count() const |
567 | { |
568 | Q_D(const QAbstractBarSeries); |
569 | return d->m_barSets.count(); |
570 | } |
571 | |
572 | /*! |
573 | Returns a list of bar sets in a bar series. Keeps the ownership of the bar sets. |
574 | */ |
575 | QList<QBarSet *> QAbstractBarSeries::barSets() const |
576 | { |
577 | Q_D(const QAbstractBarSeries); |
578 | return d->m_barSets; |
579 | } |
580 | |
581 | /*! |
582 | Sets the visibility of labels in a bar series to \a visible. |
583 | */ |
584 | void QAbstractBarSeries::setLabelsVisible(bool visible) |
585 | { |
586 | Q_D(QAbstractBarSeries); |
587 | if (d->m_labelsVisible != visible) { |
588 | d->setLabelsVisible(visible); |
589 | emit labelsVisibleChanged(); |
590 | } |
591 | } |
592 | |
593 | /*! |
594 | Returns the visibility of labels. |
595 | */ |
596 | bool QAbstractBarSeries::isLabelsVisible() const |
597 | { |
598 | Q_D(const QAbstractBarSeries); |
599 | return d->m_labelsVisible; |
600 | } |
601 | |
602 | void QAbstractBarSeries::setLabelsFormat(const QString &format) |
603 | { |
604 | Q_D(QAbstractBarSeries); |
605 | if (d->m_labelsFormat != format) { |
606 | d->m_labelsFormat = format; |
607 | d->setLabelsDirty(true); |
608 | emit labelsFormatChanged(format); |
609 | } |
610 | } |
611 | |
612 | QString QAbstractBarSeries::labelsFormat() const |
613 | { |
614 | Q_D(const QAbstractBarSeries); |
615 | return d->m_labelsFormat; |
616 | } |
617 | |
618 | void QAbstractBarSeries::setLabelsAngle(qreal angle) |
619 | { |
620 | Q_D(QAbstractBarSeries); |
621 | if (d->m_labelsAngle != angle) { |
622 | d->m_labelsAngle = angle; |
623 | d->setLabelsDirty(true); |
624 | emit labelsAngleChanged(angle); |
625 | } |
626 | } |
627 | |
628 | qreal QAbstractBarSeries::labelsAngle() const |
629 | { |
630 | Q_D(const QAbstractBarSeries); |
631 | return d->m_labelsAngle; |
632 | } |
633 | |
634 | void QAbstractBarSeries::setLabelsPosition(QAbstractBarSeries::LabelsPosition position) |
635 | { |
636 | Q_D(QAbstractBarSeries); |
637 | if (d->m_labelsPosition != position) { |
638 | d->m_labelsPosition = position; |
639 | emit labelsPositionChanged(position); |
640 | } |
641 | } |
642 | |
643 | QAbstractBarSeries::LabelsPosition QAbstractBarSeries::labelsPosition() const |
644 | { |
645 | Q_D(const QAbstractBarSeries); |
646 | return d->m_labelsPosition; |
647 | } |
648 | |
649 | void QAbstractBarSeries::setLabelsPrecision(int precision) |
650 | { |
651 | Q_D(QAbstractBarSeries); |
652 | if (d->m_labelsPrecision != precision) { |
653 | d->m_labelsPrecision = precision; |
654 | d->setLabelsDirty(true); |
655 | emit labelsPrecisionChanged(precision); |
656 | } |
657 | } |
658 | |
659 | int QAbstractBarSeries::labelsPrecision() const |
660 | { |
661 | Q_D(const QAbstractBarSeries); |
662 | return d->m_labelsPrecision; |
663 | } |
664 | |
665 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
666 | |
667 | QAbstractBarSeriesPrivate::QAbstractBarSeriesPrivate(QAbstractBarSeries *q) : |
668 | QAbstractSeriesPrivate(q), |
669 | m_barWidth(0.5), // Default value is 50% of category width |
670 | m_labelsVisible(false), |
671 | m_visible(true), |
672 | m_blockBarUpdate(false), |
673 | m_labelsFormat(), |
674 | m_labelsPosition(QAbstractBarSeries::LabelsCenter), |
675 | m_labelsAngle(0), |
676 | m_labelsPrecision(6), |
677 | m_visualsDirty(true), |
678 | m_labelsDirty(true) |
679 | { |
680 | } |
681 | |
682 | int QAbstractBarSeriesPrivate::categoryCount() const |
683 | { |
684 | // No categories defined. return count of longest set. |
685 | int count = 0; |
686 | for (int i = 0; i < m_barSets.count(); i++) { |
687 | if (m_barSets.at(i)->count() > count) |
688 | count = m_barSets.at(i)->count(); |
689 | } |
690 | |
691 | return count; |
692 | } |
693 | |
694 | void QAbstractBarSeriesPrivate::setBarWidth(qreal width) |
695 | { |
696 | if (width < 0.0) |
697 | width = 0.0; |
698 | m_barWidth = width; |
699 | emit updatedLayout(); |
700 | } |
701 | |
702 | qreal QAbstractBarSeriesPrivate::barWidth() const |
703 | { |
704 | return m_barWidth; |
705 | } |
706 | |
707 | QBarSet *QAbstractBarSeriesPrivate::barsetAt(int index) |
708 | { |
709 | return m_barSets.at(i: index); |
710 | } |
711 | |
712 | void QAbstractBarSeriesPrivate::setVisible(bool visible) |
713 | { |
714 | m_visible = visible; |
715 | emit visibleChanged(); |
716 | } |
717 | |
718 | void QAbstractBarSeriesPrivate::setLabelsVisible(bool visible) |
719 | { |
720 | m_labelsVisible = visible; |
721 | emit labelsVisibleChanged(visible); |
722 | } |
723 | |
724 | qreal QAbstractBarSeriesPrivate::min() |
725 | { |
726 | if (m_barSets.count() <= 0) |
727 | return 0; |
728 | |
729 | qreal min = INT_MAX; |
730 | |
731 | for (int i = 0; i < m_barSets.count(); i++) { |
732 | int categoryCount = m_barSets.at(i)->count(); |
733 | for (int j = 0; j < categoryCount; j++) { |
734 | qreal temp = m_barSets.at(i)->at(index: j); |
735 | if (temp < min) |
736 | min = temp; |
737 | } |
738 | } |
739 | return min; |
740 | } |
741 | |
742 | qreal QAbstractBarSeriesPrivate::max() |
743 | { |
744 | if (m_barSets.count() <= 0) |
745 | return 0; |
746 | |
747 | qreal max = INT_MIN; |
748 | |
749 | for (int i = 0; i < m_barSets.count(); i++) { |
750 | int categoryCount = m_barSets.at(i)->count(); |
751 | for (int j = 0; j < categoryCount; j++) { |
752 | qreal temp = m_barSets.at(i)->at(index: j); |
753 | if (temp > max) |
754 | max = temp; |
755 | } |
756 | } |
757 | |
758 | return max; |
759 | } |
760 | |
761 | qreal QAbstractBarSeriesPrivate::valueAt(int set, int category) |
762 | { |
763 | if ((set < 0) || (set >= m_barSets.count())) |
764 | return 0; // No set, no value. |
765 | else if ((category < 0) || (category >= m_barSets.at(i: set)->count())) |
766 | return 0; // No category, no value. |
767 | |
768 | return m_barSets.at(i: set)->at(index: category); |
769 | } |
770 | |
771 | qreal QAbstractBarSeriesPrivate::percentageAt(int set, int category) |
772 | { |
773 | if ((set < 0) || (set >= m_barSets.count())) |
774 | return 0; // No set, no value. |
775 | else if ((category < 0) || (category >= m_barSets.at(i: set)->count())) |
776 | return 0; // No category, no value. |
777 | |
778 | qreal value = m_barSets.at(i: set)->at(index: category); |
779 | qreal sum = categorySum(category); |
780 | if (qFuzzyCompare(p1: sum, p2: 0)) |
781 | return 0; |
782 | |
783 | return value / sum; |
784 | } |
785 | |
786 | qreal QAbstractBarSeriesPrivate::categorySum(int category) |
787 | { |
788 | qreal sum(0); |
789 | int count = m_barSets.count(); // Count sets |
790 | for (int set = 0; set < count; set++) { |
791 | if (category < m_barSets.at(i: set)->count()) |
792 | sum += m_barSets.at(i: set)->at(index: category); |
793 | } |
794 | return sum; |
795 | } |
796 | |
797 | qreal QAbstractBarSeriesPrivate::absoluteCategorySum(int category) |
798 | { |
799 | qreal sum(0); |
800 | int count = m_barSets.count(); // Count sets |
801 | for (int set = 0; set < count; set++) { |
802 | if (category < m_barSets.at(i: set)->count()) |
803 | sum += qAbs(t: m_barSets.at(i: set)->at(index: category)); |
804 | } |
805 | return sum; |
806 | } |
807 | |
808 | qreal QAbstractBarSeriesPrivate::maxCategorySum() |
809 | { |
810 | qreal max = INT_MIN; |
811 | int count = categoryCount(); |
812 | for (int i = 0; i < count; i++) { |
813 | qreal sum = categorySum(category: i); |
814 | if (sum > max) |
815 | max = sum; |
816 | } |
817 | return max; |
818 | } |
819 | |
820 | qreal QAbstractBarSeriesPrivate::minX() |
821 | { |
822 | if (m_barSets.count() <= 0) |
823 | return 0; |
824 | |
825 | qreal min = INT_MAX; |
826 | |
827 | for (int i = 0; i < m_barSets.count(); i++) { |
828 | int categoryCount = m_barSets.at(i)->count(); |
829 | for (int j = 0; j < categoryCount; j++) { |
830 | qreal temp = m_barSets.at(i)->d_ptr.data()->m_values.at(i: j).x(); |
831 | if (temp < min) |
832 | min = temp; |
833 | } |
834 | } |
835 | return min; |
836 | } |
837 | |
838 | qreal QAbstractBarSeriesPrivate::maxX() |
839 | { |
840 | if (m_barSets.count() <= 0) |
841 | return 0; |
842 | |
843 | qreal max = INT_MIN; |
844 | |
845 | for (int i = 0; i < m_barSets.count(); i++) { |
846 | int categoryCount = m_barSets.at(i)->count(); |
847 | for (int j = 0; j < categoryCount; j++) { |
848 | qreal temp = m_barSets.at(i)->d_ptr.data()->m_values.at(i: j).x(); |
849 | if (temp > max) |
850 | max = temp; |
851 | } |
852 | } |
853 | |
854 | return max; |
855 | } |
856 | |
857 | qreal QAbstractBarSeriesPrivate::categoryTop(int category) |
858 | { |
859 | // Returns top (sum of all positive values) of category. |
860 | // Returns 0, if all values are negative |
861 | qreal top(0); |
862 | int count = m_barSets.count(); |
863 | for (int set = 0; set < count; set++) { |
864 | if (category < m_barSets.at(i: set)->count()) { |
865 | qreal temp = m_barSets.at(i: set)->at(index: category); |
866 | if (temp > 0) { |
867 | top += temp; |
868 | } |
869 | } |
870 | } |
871 | return top; |
872 | } |
873 | |
874 | qreal QAbstractBarSeriesPrivate::categoryBottom(int category) |
875 | { |
876 | // Returns bottom (sum of all negative values) of category |
877 | // Returns 0, if all values are positive |
878 | qreal bottom(0); |
879 | int count = m_barSets.count(); |
880 | for (int set = 0; set < count; set++) { |
881 | if (category < m_barSets.at(i: set)->count()) { |
882 | qreal temp = m_barSets.at(i: set)->at(index: category); |
883 | if (temp < 0) { |
884 | bottom += temp; |
885 | } |
886 | } |
887 | } |
888 | return bottom; |
889 | } |
890 | |
891 | qreal QAbstractBarSeriesPrivate::top() |
892 | { |
893 | // Returns top of all categories |
894 | qreal top(0); |
895 | int count = categoryCount(); |
896 | for (int i = 0; i < count; i++) { |
897 | qreal temp = categoryTop(category: i); |
898 | if (temp > top) |
899 | top = temp; |
900 | } |
901 | return top; |
902 | } |
903 | |
904 | qreal QAbstractBarSeriesPrivate::bottom() |
905 | { |
906 | // Returns bottom of all categories |
907 | qreal bottom(0); |
908 | int count = categoryCount(); |
909 | for (int i = 0; i < count; i++) { |
910 | qreal temp = categoryBottom(category: i); |
911 | if (temp < bottom) |
912 | bottom = temp; |
913 | } |
914 | return bottom; |
915 | } |
916 | |
917 | bool QAbstractBarSeriesPrivate::blockBarUpdate() |
918 | { |
919 | return m_blockBarUpdate; |
920 | } |
921 | |
922 | qreal QAbstractBarSeriesPrivate::labelsAngle() const |
923 | { |
924 | return m_labelsAngle; |
925 | } |
926 | |
927 | void QAbstractBarSeriesPrivate::initializeDomain() |
928 | { |
929 | qreal minX(domain()->minX()); |
930 | qreal minY(domain()->minY()); |
931 | qreal maxX(domain()->maxX()); |
932 | qreal maxY(domain()->maxY()); |
933 | |
934 | qreal seriesMinX = this->minX(); |
935 | qreal seriesMaxX = this->maxX(); |
936 | qreal y = max(); |
937 | minX = qMin(a: minX, b: seriesMinX - (qreal)0.5); |
938 | minY = qMin(a: minY, b: y); |
939 | maxX = qMax(a: maxX, b: seriesMaxX + (qreal)0.5); |
940 | maxY = qMax(a: maxY, b: y); |
941 | |
942 | domain()->setRange(minX, maxX, minY, maxY); |
943 | } |
944 | |
945 | QList<QLegendMarker*> QAbstractBarSeriesPrivate::createLegendMarkers(QLegend* legend) |
946 | { |
947 | Q_Q(QAbstractBarSeries); |
948 | QList<QLegendMarker*> markers; |
949 | |
950 | foreach(QBarSet* set, q->barSets()) { |
951 | QBarLegendMarker* marker = new QBarLegendMarker(q,set,legend); |
952 | markers << marker; |
953 | } |
954 | return markers; |
955 | } |
956 | |
957 | |
958 | bool QAbstractBarSeriesPrivate::append(QBarSet *set) |
959 | { |
960 | if ((m_barSets.contains(t: set)) || (set == 0)) |
961 | return false; // Fail if set is already in list or set is null. |
962 | |
963 | m_barSets.append(t: set); |
964 | QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::updatedBars, |
965 | receiver: this, slot: &QAbstractBarSeriesPrivate::updatedBars); |
966 | QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueChanged, |
967 | receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueChange); |
968 | QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueAdded, |
969 | receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueAdd); |
970 | QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueRemoved, |
971 | receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueRemove); |
972 | |
973 | emit restructuredBars(); // this notifies barchartitem |
974 | return true; |
975 | } |
976 | |
977 | bool QAbstractBarSeriesPrivate::remove(QBarSet *set) |
978 | { |
979 | if (!m_barSets.contains(t: set)) |
980 | return false; // Fail if set is not in list |
981 | |
982 | m_barSets.removeOne(t: set); |
983 | QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::updatedBars, |
984 | receiver: this, slot: &QAbstractBarSeriesPrivate::updatedBars); |
985 | QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueChanged, |
986 | receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueChange); |
987 | QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueAdded, |
988 | receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueAdd); |
989 | QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueRemoved, |
990 | receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueRemove); |
991 | |
992 | emit restructuredBars(); // this notifies barchartitem |
993 | return true; |
994 | } |
995 | |
996 | bool QAbstractBarSeriesPrivate::append(QList<QBarSet * > sets) |
997 | { |
998 | foreach (QBarSet *set, sets) { |
999 | if ((set == 0) || (m_barSets.contains(t: set))) |
1000 | return false; // Fail if any of the sets is null or is already appended. |
1001 | if (sets.count(t: set) != 1) |
1002 | return false; // Also fail if same set is more than once in given list. |
1003 | } |
1004 | |
1005 | foreach (QBarSet *set, sets) { |
1006 | m_barSets.append(t: set); |
1007 | QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::updatedBars, |
1008 | receiver: this, slot: &QAbstractBarSeriesPrivate::updatedBars); |
1009 | QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueChanged, |
1010 | receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueChange); |
1011 | QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueAdded, |
1012 | receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueAdd); |
1013 | QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueRemoved, |
1014 | receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueRemove); |
1015 | } |
1016 | |
1017 | emit restructuredBars(); // this notifies barchartitem |
1018 | return true; |
1019 | } |
1020 | |
1021 | bool QAbstractBarSeriesPrivate::remove(QList<QBarSet * > sets) |
1022 | { |
1023 | if (sets.count() == 0) |
1024 | return false; |
1025 | |
1026 | foreach (QBarSet *set, sets) { |
1027 | if ((set == 0) || (!m_barSets.contains(t: set))) |
1028 | return false; // Fail if any of the sets is null or is not in series |
1029 | if (sets.count(t: set) != 1) |
1030 | return false; // Also fail if same set is more than once in given list. |
1031 | } |
1032 | |
1033 | foreach (QBarSet *set, sets) { |
1034 | m_barSets.removeOne(t: set); |
1035 | QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::updatedBars, |
1036 | receiver: this, slot: &QAbstractBarSeriesPrivate::updatedBars); |
1037 | QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueChanged, |
1038 | receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueChange); |
1039 | QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueAdded, |
1040 | receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueAdd); |
1041 | QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueRemoved, |
1042 | receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueRemove); |
1043 | } |
1044 | |
1045 | emit restructuredBars(); // this notifies barchartitem |
1046 | |
1047 | return true; |
1048 | } |
1049 | |
1050 | bool QAbstractBarSeriesPrivate::insert(int index, QBarSet *set) |
1051 | { |
1052 | if ((m_barSets.contains(t: set)) || (set == 0)) |
1053 | return false; // Fail if set is already in list or set is null. |
1054 | |
1055 | m_barSets.insert(i: index, t: set); |
1056 | QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::updatedBars, |
1057 | receiver: this, slot: &QAbstractBarSeriesPrivate::updatedBars); |
1058 | QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueChanged, |
1059 | receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueChange); |
1060 | QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueAdded, |
1061 | receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueAdd); |
1062 | QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueRemoved, |
1063 | receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueRemove); |
1064 | |
1065 | emit restructuredBars(); // this notifies barchartitem |
1066 | return true; |
1067 | } |
1068 | |
1069 | void QAbstractBarSeriesPrivate::initializeAxes() |
1070 | { |
1071 | Q_Q(QAbstractBarSeries); |
1072 | |
1073 | foreach(QAbstractAxis* axis, m_axes) { |
1074 | if (axis->type() == QAbstractAxis::AxisTypeBarCategory) { |
1075 | switch (q->type()) { |
1076 | case QAbstractSeries::SeriesTypeHorizontalBar: |
1077 | case QAbstractSeries::SeriesTypeHorizontalPercentBar: |
1078 | case QAbstractSeries::SeriesTypeHorizontalStackedBar: |
1079 | if (axis->orientation() == Qt::Vertical) |
1080 | populateCategories(axis: qobject_cast<QBarCategoryAxis *>(object: axis)); |
1081 | break; |
1082 | case QAbstractSeries::SeriesTypeBar: |
1083 | case QAbstractSeries::SeriesTypePercentBar: |
1084 | case QAbstractSeries::SeriesTypeStackedBar: |
1085 | case QAbstractSeries::SeriesTypeBoxPlot: |
1086 | case QAbstractSeries::SeriesTypeCandlestick: |
1087 | if (axis->orientation() == Qt::Horizontal) |
1088 | populateCategories(axis: qobject_cast<QBarCategoryAxis *>(object: axis)); |
1089 | break; |
1090 | default: |
1091 | qWarning() << "Unexpected series type" ; |
1092 | break; |
1093 | } |
1094 | } |
1095 | } |
1096 | |
1097 | // Make sure series animations are reset when axes change |
1098 | AbstractBarChartItem *item = qobject_cast<AbstractBarChartItem *>(object: m_item.data()); |
1099 | if (item) |
1100 | item->resetAnimation(); |
1101 | } |
1102 | |
1103 | QAbstractAxis::AxisType QAbstractBarSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const |
1104 | { |
1105 | Q_Q(const QAbstractBarSeries); |
1106 | |
1107 | switch (q->type()) { |
1108 | case QAbstractSeries::SeriesTypeHorizontalBar: |
1109 | case QAbstractSeries::SeriesTypeHorizontalPercentBar: |
1110 | case QAbstractSeries::SeriesTypeHorizontalStackedBar: |
1111 | if (orientation == Qt::Vertical) |
1112 | return QAbstractAxis::AxisTypeBarCategory; |
1113 | break; |
1114 | case QAbstractSeries::SeriesTypeBar: |
1115 | case QAbstractSeries::SeriesTypePercentBar: |
1116 | case QAbstractSeries::SeriesTypeStackedBar: |
1117 | case QAbstractSeries::SeriesTypeBoxPlot: |
1118 | case QAbstractSeries::SeriesTypeCandlestick: |
1119 | if (orientation == Qt::Horizontal) |
1120 | return QAbstractAxis::AxisTypeBarCategory; |
1121 | break; |
1122 | default: |
1123 | qWarning() << "Unexpected series type" ; |
1124 | break; |
1125 | } |
1126 | return QAbstractAxis::AxisTypeValue; |
1127 | |
1128 | } |
1129 | |
1130 | void QAbstractBarSeriesPrivate::handleSetValueChange(int index) |
1131 | { |
1132 | QBarSetPrivate *priv = qobject_cast<QBarSetPrivate *>(object: sender()); |
1133 | if (priv) |
1134 | emit setValueChanged(index, barset: priv->q_ptr); |
1135 | } |
1136 | |
1137 | void QAbstractBarSeriesPrivate::handleSetValueAdd(int index, int count) |
1138 | { |
1139 | QBarSetPrivate *priv = qobject_cast<QBarSetPrivate *>(object: sender()); |
1140 | if (priv) |
1141 | emit setValueAdded(index, count, barset: priv->q_ptr); |
1142 | } |
1143 | |
1144 | void QAbstractBarSeriesPrivate::handleSetValueRemove(int index, int count) |
1145 | { |
1146 | QBarSetPrivate *priv = qobject_cast<QBarSetPrivate *>(object: sender()); |
1147 | if (priv) |
1148 | emit setValueRemoved(index, count, barset: priv->q_ptr); |
1149 | } |
1150 | |
1151 | void QAbstractBarSeriesPrivate::populateCategories(QBarCategoryAxis *axis) |
1152 | { |
1153 | QStringList categories; |
1154 | if (axis->categories().isEmpty()) { |
1155 | for (int i(1); i < categoryCount() + 1; i++) |
1156 | categories << presenter()->numberToString(value: i); |
1157 | axis->append(categories); |
1158 | } |
1159 | } |
1160 | |
1161 | QAbstractAxis* QAbstractBarSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const |
1162 | { |
1163 | if (defaultAxisType(orientation) == QAbstractAxis::AxisTypeBarCategory) |
1164 | return new QBarCategoryAxis; |
1165 | else |
1166 | return new QValueAxis; |
1167 | } |
1168 | |
1169 | void QAbstractBarSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool forced) |
1170 | { |
1171 | m_blockBarUpdate = true; // Ensures that the bars are not updated before the theme is ready |
1172 | |
1173 | const QList<QGradient> gradients = theme->seriesGradients(); |
1174 | |
1175 | // Since each bar series uses different number of colors, we need to account for other |
1176 | // bar series in the chart that are also themed when choosing colors. |
1177 | // First series count is used to determine the color stepping to keep old applications |
1178 | // with single bar series with a lot of sets colored as they always have been. |
1179 | int actualIndex = 0; |
1180 | int firstSeriesSetCount = m_barSets.count(); |
1181 | if (!m_item.isNull()) { |
1182 | auto seriesMap = m_item->themeManager()->seriesMap(); |
1183 | int lowestSeries = index; |
1184 | for (auto it = seriesMap.cbegin(), end = seriesMap.cend(); it != end; ++it) { |
1185 | if (it.value() != index) { |
1186 | auto barSeries = qobject_cast<QAbstractBarSeries *>(object: it.key()); |
1187 | if (barSeries) { |
1188 | actualIndex += barSeries->count(); |
1189 | if (it.value() < lowestSeries) { |
1190 | firstSeriesSetCount = qMax(a: barSeries->count(), b: gradients.count()); |
1191 | lowestSeries = it.value(); |
1192 | } |
1193 | } |
1194 | } |
1195 | } |
1196 | } |
1197 | |
1198 | qreal takeAtPos = 0.5; |
1199 | qreal step = 0.2; |
1200 | if (firstSeriesSetCount > 1) { |
1201 | step = 1.0 / qreal(firstSeriesSetCount); |
1202 | if (firstSeriesSetCount % gradients.count()) |
1203 | step *= gradients.count(); |
1204 | else |
1205 | step *= (gradients.count() - 1); |
1206 | if (index > 0) { |
1207 | // Take necessary amount of initial steps |
1208 | int initialStepper = actualIndex; |
1209 | while (initialStepper > gradients.count()) { |
1210 | initialStepper -= gradients.count(); |
1211 | takeAtPos += step; |
1212 | if (takeAtPos == 1.0) |
1213 | takeAtPos += step; |
1214 | takeAtPos -= int(takeAtPos); |
1215 | } |
1216 | } |
1217 | } |
1218 | |
1219 | for (int i(0); i < m_barSets.count(); i++) { |
1220 | int colorIndex = (actualIndex + i) % gradients.count(); |
1221 | if ((actualIndex + i) > 0 && (actualIndex + i) % gradients.count() == 0) { |
1222 | // There is no dedicated base color for each sets, generate more colors |
1223 | takeAtPos += step; |
1224 | if (takeAtPos == 1.0) |
1225 | takeAtPos += step; |
1226 | takeAtPos -= (int) takeAtPos; |
1227 | } |
1228 | if (forced || QChartPrivate::defaultBrush() == m_barSets.at(i)->d_ptr->m_brush) |
1229 | m_barSets.at(i)->setBrush(ChartThemeManager::colorAt(gradient: gradients.at(i: colorIndex), pos: takeAtPos)); |
1230 | |
1231 | // Pick label color from the opposite end of the gradient. |
1232 | // 0.3 as a boundary seems to work well. |
1233 | if (forced || QChartPrivate::defaultBrush() == m_barSets.at(i)->d_ptr->m_labelBrush) { |
1234 | if (takeAtPos < 0.3) |
1235 | m_barSets.at(i)->setLabelBrush(ChartThemeManager::colorAt(gradient: gradients.at(i: actualIndex % gradients.size()), pos: 1)); |
1236 | else |
1237 | m_barSets.at(i)->setLabelBrush(ChartThemeManager::colorAt(gradient: gradients.at(i: actualIndex % gradients.size()), pos: 0)); |
1238 | } |
1239 | if (forced || QChartPrivate::defaultPen() == m_barSets.at(i)->d_ptr->m_pen) { |
1240 | QColor c = ChartThemeManager::colorAt(gradient: gradients.at(i: actualIndex % gradients.size()), pos: 0.0); |
1241 | m_barSets.at(i)->setPen(c); |
1242 | } |
1243 | } |
1244 | m_blockBarUpdate = false; |
1245 | emit updatedBars(); |
1246 | } |
1247 | |
1248 | void QAbstractBarSeriesPrivate::initializeAnimations(QChart::AnimationOptions options, int duration, |
1249 | QEasingCurve &curve) |
1250 | { |
1251 | AbstractBarChartItem *bar = static_cast<AbstractBarChartItem *>(m_item.data()); |
1252 | Q_ASSERT(bar); |
1253 | if (bar->animation()) |
1254 | bar->animation()->stopAndDestroyLater(); |
1255 | |
1256 | if (options.testFlag(flag: QChart::SeriesAnimations)) |
1257 | bar->setAnimation(new BarAnimation(bar, duration, curve)); |
1258 | else |
1259 | bar->setAnimation(0); |
1260 | QAbstractSeriesPrivate::initializeAnimations(options, duration, curve); |
1261 | } |
1262 | |
1263 | QT_CHARTS_END_NAMESPACE |
1264 | |
1265 | #include "moc_qabstractbarseries.cpp" |
1266 | #include "moc_qabstractbarseries_p.cpp" |
1267 | |