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