1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <QtGraphs/qabstractseries.h>
5#include <QtGraphs/qbarseries.h>
6#include <QtGraphs/qbarset.h>
7#include <private/qabstractseries_p.h>
8#include <private/qbarseries_p.h>
9#include <private/qbarset_p.h>
10#include <private/qgraphsview_p.h>
11
12QT_BEGIN_NAMESPACE
13
14/*!
15 \class QBarSeries
16 \inmodule QtGraphs
17 \ingroup graphs_2D
18 \brief The QBarSeries class presents data in bar graphs.
19
20 This class draws data by default as a series of bars grouped by category,
21 with one bar per category from each bar set added to the series.
22 It also supports horizontal bars and grouping bars as stacked.
23
24 A bar series needs the GraphsView x-axis to be set to a BarCategoryAxis and
25 the y-axis set to ValueAxis.
26
27 \sa QBarSet, QAbstractSeries
28*/
29/*!
30 \qmltype BarSeries
31 \nativetype QBarSeries
32 \inqmlmodule QtGraphs
33 \ingroup graphs_qml_2D
34 \inherits AbstractSeries
35
36 \brief Presents data in bar graphs.
37
38 Draws data by default as a series of bars grouped by category,
39 with one bar per category from each bar set added to the series.
40 It also supports horizontal bars and grouping bars as stacked.
41*/
42
43/*!
44 \property QBarSeries::barWidth
45 \brief The width of the bars of the series.
46
47 The unit of width is the unit of the x-axis. The minimum width for bars is zero, and negative
48 values are treated as zero. Setting the width to zero means that the width of the bar on the
49 screen is one pixel regardless of the scale of the x-axis. Bars wider than zero are scaled
50 using the x-axis scale.
51
52 By default, the barWidth is 0.5 (bars will take 50% of the available width).
53 The valid values range from 0.0 (0%) to 1.0 (100%).
54
55 \note When used with QBarSeries, this value specifies the width of a group of bars instead of
56 that of a single bar.
57 \sa QBarSeries
58*/
59
60/*!
61 \enum QBarSeries::BarsType
62
63 This enum value describes the type of the bar series:
64
65 \value Groups Bar sets are grouped by category.
66 \value Stacked Bar sets are stacked after each other by category.
67 \value StackedPercent Bar sets are stacked after each other by category.
68 The segment size corresponds to the percentage of the segment value
69 compared with the total value of all segments in the stack.
70*/
71/*!
72 \property QBarSeries::barsType
73 \brief The type of the bar series.
74*/
75/*!
76 \qmlproperty enumeration BarSeries::barsType
77
78 The type of the bar series:
79
80 \value BarSeries.BarsType.Groups
81 Bar sets are grouped by category. This is the default value.
82 \value BarSeries.BarsType.Stacked
83 Bar sets are stacked after each other by category.
84 \value BarSeries.BarsType.StackedPercent
85 Bar sets are stacked after each other by category. The segment size corresponds
86 to the percentage of the segment value compared with the total value of all
87 segments in the stack.
88*/
89
90/*!
91 \qmlproperty real BarSeries::barWidth
92 The unit of width is the unit of the x-axis. The minimum width for bars is zero, and negative
93 values are treated as zero. Setting the width to zero means that the width of the bar on the
94 screen is one pixel regardless of the scale of the x-axis. Bars wider than zero are scaled
95 using the x-axis scale.
96
97 By default, the barWidth is 0.5 (bars will take 50% of the available width).
98 The valid values range from 0.0 (0%) to 1.0 (100%).
99
100 \note When used with the BarSeries type, this value specifies the width of a group of bars
101 instead of that of a single bar.
102*/
103
104/*!
105 \property QBarSeries::count
106 \brief The number of bar sets in a bar series.
107*/
108/*!
109 \qmlproperty int BarSeries::count
110 The number of bar sets in a bar series.
111*/
112
113/*!
114 \property QBarSeries::labelsVisible
115 \brief The visibility of the labels in a bar series.
116 The default label visibility is \c false.
117*/
118/*!
119 \qmlproperty bool BarSeries::labelsVisible
120 The visibility of the labels in a bar series.
121 The default label visibility is \c false.
122*/
123
124/*!
125 \property QBarSeries::labelsFormat
126 \brief The format used for showing labels in a bar series.
127
128 QBarSeries supports the following format tag:
129 \table
130 \row
131 \li @value \li The value of the bar
132 \endtable
133
134 For example, the following usage of the format tags would produce labels that show the value
135 followed by the unit (u):
136 \code
137 series->setLabelsFormat("@value u");
138 \endcode
139
140 By default, the labels show the value of the bar. For the percent bar series, \e % is added
141 after the value. The labels are shown on the plot area, if the bars are close to each other,
142 the labels may overlap.
143
144 \sa labelsVisible, labelsPosition, labelsPrecision
145*/
146/*!
147 \qmlproperty string BarSeries::labelsFormat
148 The format used for showing labels in a bar series.
149
150 \sa QBarSeries::labelsFormat, labelsVisible, labelsPosition
151*/
152
153/*!
154 \enum QBarSeries::LabelsPosition
155
156 This enum value describes the position of the data value labels:
157
158 \value Center Label is located in the center of the bar.
159 \value InsideEnd Label is located inside the bar at the top.
160 \value InsideBase Label is located inside the bar at the bottom.
161 \value OutsideEnd Label is located outside the bar at the top.
162*/
163
164/*!
165 \property QBarSeries::labelsPosition
166 \brief The position of value labels.
167
168 \sa labelsVisible, labelsFormat
169*/
170/*!
171 \qmlproperty enumeration BarSeries::labelsPosition
172
173 The position of the data value labels:
174
175 \value BarSeries.LabelsPosition.Center
176 Label is located in the center of the bar.
177 \value BarSeries.LabelsPosition.InsideEnd
178 Label is located inside the bar at the top.
179 \value BarSeries.LabelsPosition.InsideBase
180 Label is located inside the bar at the bottom.
181 \value BarSeries.LabelsPosition.OutsideEnd
182 Label is located outside the bar at the top.
183
184 \sa labelsVisible, labelsFormat
185*/
186
187/*!
188 \property QBarSeries::labelsMargin
189 \brief The margin of the value labels in pixels.
190
191 This margin from side is used when \l labelsPosition is set to something else
192 than \c LabelsPosition.Center. The default value is \c 0.
193*/
194/*!
195 \qmlproperty real BarSeries::labelsMargin
196 The margin of the value labels in pixels.
197
198 This margin from side is used when \l labelsPosition is set to something else
199 than \c LabelsPosition.Center. The default value is \c 0.
200*/
201
202/*!
203 \property QBarSeries::labelsAngle
204 \brief The angle of the value labels in degrees.
205*/
206/*!
207 \qmlproperty real BarSeries::labelsAngle
208 The angle of the value labels in degrees.
209*/
210
211/*!
212 \property QBarSeries::labelsPrecision
213 \brief The maximum amount of significant digits shown in value labels.
214
215 Default value is 6.
216*/
217/*!
218 \qmlproperty real BarSeries::labelsPrecision
219 The maximum amount of significant digits shown in value labels.
220
221 Default value is 6.
222*/
223
224/*!
225 \property QBarSeries::barDelegate
226 \brief A custom QML component used for visualizing each of the bars.
227 Instance of this component is created for each of the bar.
228 When this is not defined, a default rectangle visualization for bars is used.
229
230 The dynamic properties available for this component are:
231
232 \table
233 \header
234 \li Type
235 \li Name
236 \li Description
237 \row
238 \li QColor
239 \li barColor
240 \li The fill color of the bar. This value comes either from the \l QGraphsTheme
241 or from \l{QBarSet::color} if the \l QBarSet overrides the color.
242 \row
243 \li QColor
244 \li barBorderColor
245 \li The border color of the bar. This value comes either from the \l QGraphsTheme
246 or from \l{QBarSet::borderColor} if the \l QBarSet overrides the color.
247 \row
248 \li qreal
249 \li barBorderWidth
250 \li The width of the bar border. This value comes either from the \l QGraphsTheme
251 or from \l{QBarSet::borderWidth} if the \l QBarSet overrides the width.
252 \row
253 \li qreal
254 \li barValue
255 \li The value of the bar. This value comes from the \l{QBarSet::values}.
256 \row
257 \li QString
258 \li barLabel
259 \li The label of the bar. This value comes from the \l{QBarSet::label}.
260 \row
261 \li bool
262 \li barSelected
263 \li This value is true when the bar is selected, meaning that the bar index
264 is in \l{QBarSet::selectedBars}.
265 \endtable
266
267 To use any of these, add property with the defined name into your custom component.
268 For example \c{"property color barColor"} and \c{"property real barValue"}.
269*/
270/*!
271 \qmlproperty Component BarSeries::barDelegate
272 A custom QML component used for visualizing each of the bars.
273 Instance of this component is created for each of the bar.
274 When this is not defined, a default rectangle visualization for bars is used.
275
276 The dynamic properties available for this component are:
277
278 \table
279 \header
280 \li Type
281 \li Name
282 \li Description
283 \row
284 \li color
285 \li barColor
286 \li The fill color of the bar. This value comes either from the \l GraphsTheme
287 or from \l{BarSet::color} if the \l BarSet overrides the color.
288 \row
289 \li color
290 \li barBorderColor
291 \li The border color of the bar. This value comes either from the \l GraphsTheme
292 or from \l{BarSet::borderColor} if the \l BarSet overrides the color.
293 \row
294 \li real
295 \li barBorderWidth
296 \li The width of the bar border. This value comes either from the \l GraphsTheme
297 or from \l{BarSet::borderWidth} if the \l BarSet overrides the width.
298 \row
299 \li real
300 \li barValue
301 \li The value of the bar. This value comes from the \l{BarSet::values}.
302 \row
303 \li string
304 \li barLabel
305 \li The label of the bar. This value comes from the \l{BarSet::label}.
306 \row
307 \li bool
308 \li barSelected
309 \li This value is true when the bar is selected, meaning that the bar index
310 is in \l{BarSet::selectedBars}.
311 \endtable
312
313 To use any of these, add property with the defined name into your custom component.
314 For example \c{"property color barColor"} and \c{"property real barValue"}.
315*/
316
317/*!
318 \property QBarSeries::barSets
319 \brief A list of sets added to the series.
320 */
321/*!
322 \qmlproperty list<BarSet> BarSeries::barSets
323 A list of sets added to the series.
324*/
325
326/*!
327 \fn void QBarSeries::updatedBars()
328 This signal is emitted when bars are updated.
329*/
330
331/*!
332 \fn void QBarSeries::labelsVisibleChanged(bool visible)
333 This signal is emitted when the labels' visibility changes to \a visible.
334 \sa labelsVisible(), setLabelsVisible()
335*/
336
337/*!
338 \fn void QBarSeries::barsetsAdded(const QList<QBarSet *> &sets)
339 This signal is emitted when the bar sets specified by \a sets are added to the series.
340 \sa append(), insert()
341*/
342/*!
343 \qmlsignal BarSeries::barsetsAdded()
344 This signal is emitted when bar sets are added to the series.
345*/
346
347/*!
348 \fn void QBarSeries::barsetsRemoved(const QList<QBarSet *> &sets)
349 This signal is emitted when the bar sets specified by \a sets are removed from the series.
350 \sa remove()
351*/
352/*!
353 \qmlsignal BarSeries::barsetsRemoved()
354 This signal is emitted when bar sets are removed from the series.
355*/
356
357/*!
358 \fn void QBarSeries::setValueChanged(qsizetype index, QBarSet *barset)
359 This signal is emitted when a barset's value is changed. \a index is the index of
360 the barset in the series. The \a barset is a pointer to the changed set.
361*/
362/*!
363 \fn void QBarSeries::setValueAdded(qsizetype index, qsizetype count, QBarSet *barset)
364 This signal is emitted when a barset's value is changed. \a index is the index of
365 the barset in the series. The number of the added values is indicated \a count.
366 The \a barset is a pointer to the changed set.
367*/
368/*!
369 \fn void QBarSeries::setValueRemoved(qsizetype index, qsizetype count, QBarSet *barset)
370 This signal is emitted when a barset's value is changed. \a index is the index of
371 the barset in the series. The number of the removed values is indicated \a count.
372 The \a barset is a pointer to the changed set.
373*/
374
375/*!
376 \qmlmethod BarSet BarSeries::at(int index)
377 Returns the bar set at \a index. Returns null if the index is not valid.
378*/
379
380/*!
381 \qmlmethod BarSet BarSeries::insert(int index, string label, VariantList values)
382 Adds a new bar set with \a label and \a values to \a index. \a values can be a list
383 of real values or a list of XYPoint types.
384
385 If the index value is equal to or less than zero, the new bar set is prepended to the bar
386 series. If the index value is equal to or greater than the number of bar sets in the bar
387 series, the new bar set is appended to the bar series.
388
389 \sa append()
390*/
391
392/*!
393 \qmlmethod bool BarSeries::remove(BarSet barset)
394 Removes the bar set specified by \a barset from the series. Returns \c true if successful,
395 \c false otherwise.
396*/
397
398/*!
399 \qmlmethod BarSeries::clear()
400 Removes all bar sets from the series.
401*/
402
403/*!
404 \qmlmethod bool BarSeries::replace(int index, BarSet barset)
405 Replaces the bar set at the position specified by \a index from the series and replaces it
406 with \a barset. Returns \c true if successful, \c false otherwise.
407*/
408
409/*!
410 \qmlmethod Barset BarSeries::at(int index)
411 Returns the bar set specified by \a index from the series. Returns \c null otherwise.
412*/
413
414/*!
415 \qmlmethod int BarSeries::find(BarSet barset)
416 Returns the index of the bar set specified by \a barset from the series. Returns \c -1 if
417 not found.
418*/
419
420/*!
421 \qmlmethod BarSeries::removeMultiple(int index, int count)
422 Removes a range of bar sets as specified by the \a index and \a count. The call
423 traverses over all sets even if removal of one fails.
424*/
425
426/*!
427 \qmlmethod bool BarSeries::remove(int index)
428 Removes the bar set specified by \a index from the series. Returns \c true if the
429 removal was successful, \c false otherwise.
430*/
431
432/*!
433 \qmlmethod bool BarSeries::replace(BarSet oldSet, BarSet newSet)
434 Replaces the bar set specified by \a oldSet with newSet. Returns \c true if the
435 removal was successful, \c false otherwise. \a oldSet is destroyed if this
436 is successful.
437*/
438
439/*!
440 \qmlmethod bool BarSeries::replace(list<BarSet> sets)
441 Completely replaces all current bar set with \a sets. The size does not need
442 to match. Returns false if any of the bar set in \a sets are invalid.
443*/
444
445/*!
446 \internal
447*/
448
449/*!
450 Constructs an empty bar series that is a QObject and a child of \a parent.
451*/
452QBarSeries::QBarSeries(QObject *parent)
453 : QAbstractSeries(*(new QBarSeriesPrivate()), parent)
454{}
455
456QBarSeries::~QBarSeries() {}
457
458QBarSeries::QBarSeries(QBarSeriesPrivate &dd, QObject *parent)
459 : QAbstractSeries(dd, parent)
460{}
461
462/*!
463 Returns the bar series.
464*/
465QAbstractSeries::SeriesType QBarSeries::type() const
466{
467 return QAbstractSeries::SeriesType::Bar;
468}
469
470/*!
471 \property QBarSeries::seriesColors
472 \brief The list of base colors to be used for all the objects in the series.
473
474 If there are more series than colors, the color list wraps and starts again
475 with the first color in the list. If this is not set (default), colors
476 from the \l{QGraphsTheme::seriesColors} will be used.
477*/
478/*!
479 \qmlproperty list<color> BarSeries::seriesColors
480 The list of base colors to be used for all the objects in the series.
481
482 If there are more series than colors, the color list wraps and starts again
483 with the first color in the list. If this is not set (default), colors
484 from the \l{GraphsTheme::seriesColors} will be used.
485*/
486QList<QColor> QBarSeries::seriesColors() const
487{
488 Q_D(const QBarSeries);
489 return d->m_seriesColors;
490}
491
492void QBarSeries::setSeriesColors(const QList<QColor> &newSeriesColors)
493{
494 Q_D(QBarSeries);
495 if (d->m_seriesColors == newSeriesColors)
496 return;
497 d->m_seriesColors = newSeriesColors;
498 emit seriesColorsChanged();
499 emit update();
500}
501
502/*!
503 \property QBarSeries::borderColors
504 \brief The list of border colors to be used for all the objects in the series.
505
506 If there are more series than colors, the color list wraps and starts again
507 with the first color in the list. If this is not set (default), colors
508 from the \l{QGraphsTheme::borderColors} will be used.
509*/
510/*!
511 \qmlproperty list<color> BarSeries::borderColors
512 The list of border colors to be used for all the objects in the series.
513
514 If there are more series than colors, the color list wraps and starts again
515 with the first color in the list. If this is not set (default), colors
516 from the \l{GraphsTheme::borderColors} will be used.
517*/
518QList<QColor> QBarSeries::borderColors() const
519{
520 Q_D(const QBarSeries);
521 return d->m_borderColors;
522}
523
524void QBarSeries::setBorderColors(const QList<QColor> &newBorderColors)
525{
526 Q_D(QBarSeries);
527 if (d->m_borderColors == newBorderColors)
528 return;
529 d->m_borderColors = newBorderColors;
530 emit borderColorsChanged();
531 emit update();
532}
533
534void QBarSeries::setBarsType(QBarSeries::BarsType type)
535{
536 Q_D(QBarSeries);
537 if (d->m_barsType != type) {
538 d->m_barsType = type;
539 emit barsTypeChanged(type);
540 emit update();
541 }
542}
543
544QBarSeries::BarsType QBarSeries::barsType() const
545{
546 Q_D(const QBarSeries);
547 return d->m_barsType;
548}
549
550/*!
551 Sets the width of the bars of the series to \a width.
552*/
553void QBarSeries::setBarWidth(qreal width)
554{
555 Q_D(QBarSeries);
556 if (d->barWidth() != width) {
557 d->setBarWidth(width);
558 emit barWidthChanged();
559 }
560}
561
562/*!
563 Returns the width of the bars of the series.
564 \sa setBarWidth()
565*/
566qreal QBarSeries::barWidth() const
567{
568 Q_D(const QBarSeries);
569 return d->barWidth();
570}
571
572/*!
573 Adds a set of bars specified by \a set to the bar series and takes ownership of it. If the set
574 is null or it already belongs to the series, it will not be appended.
575 Returns \c true if appending succeeded.
576*/
577bool QBarSeries::append(QBarSet *set)
578{
579 Q_D(QBarSeries);
580 bool success = d->append(set);
581 if (success) {
582 QList<QBarSet *> sets;
583 sets.append(t: set);
584 set->setParent(this);
585 QObject::connect(sender: set, signal: &QBarSet::update, context: this, slot: &QBarSeries::update);
586 emit barsetsAdded(sets);
587 emit barSetsChanged();
588 emit countChanged();
589 emit update();
590 }
591 return success;
592}
593
594/*!
595 Removes the bar set specified by \a set from the series and permanently deletes it if
596 the removal succeeds. Returns \c true if the set was removed.
597*/
598bool QBarSeries::remove(QBarSet *set)
599{
600 Q_D(QBarSeries);
601 bool success = d->remove(set);
602 if (success) {
603 QList<QBarSet *> sets;
604 sets.append(t: set);
605 set->setParent(0);
606 QObject::disconnect(sender: set, signal: &QBarSet::update, receiver: this, slot: &QBarSeries::update);
607 emit barsetsRemoved(sets);
608 emit barSetsChanged();
609 emit countChanged();
610 emit update();
611 delete set;
612 set = 0;
613 }
614 return success;
615}
616
617/*!
618 Takes a single \a set from the series. Does not delete the bar set object.
619 \note The series remains the barset's parent object. You must set the
620 parent object to take full ownership.
621
622 Returns \c true if the take operation succeeds.
623*/
624bool QBarSeries::take(QBarSet *set)
625{
626 Q_D(QBarSeries);
627 bool success = d->remove(set);
628 if (success) {
629 QList<QBarSet *> sets;
630 sets.append(t: set);
631 QObject::disconnect(sender: set, signal: &QBarSet::update, receiver: this, slot: &QBarSeries::update);
632 emit barsetsRemoved(sets);
633 emit barSetsChanged();
634 emit countChanged();
635 emit update();
636 }
637 return success;
638}
639
640/*!
641 Adds a list of bar sets specified by \a sets to a bar series and takes ownership of the sets.
642 Returns \c true if all sets were appended successfully. If any of the sets is null or was
643 previously appended to the series, nothing is appended and this function returns \c false.
644 If any of the sets appears in the list more than once, nothing is appended and this function
645 returns \c false.
646*/
647bool QBarSeries::append(const QList<QBarSet *> &sets)
648{
649 Q_D(QBarSeries);
650 if (!d->append(sets))
651 return false;
652
653 for (auto *set : sets) {
654 set->setParent(this);
655 QObject::connect(sender: set, signal: &QBarSet::update, context: this, slot: &QBarSeries::update);
656 }
657
658 emit barsetsAdded(sets);
659 emit barSetsChanged();
660 emit countChanged();
661 emit update();
662 return true;
663}
664
665/*!
666 Inserts a bar set specified by \a set to a series at the position specified by \a index
667 and takes ownership of the set. If the set is null or already belongs to the series, it will
668 not be appended. Returns \c true if inserting succeeds.
669*/
670bool QBarSeries::insert(qsizetype index, QBarSet *set)
671{
672 Q_D(QBarSeries);
673 bool success = d->insert(index, set);
674 if (success) {
675 QList<QBarSet *> sets;
676 sets.append(t: set);
677 QObject::connect(sender: set, signal: &QBarSet::update, context: this, slot: &QBarSeries::update);
678 emit barsetsAdded(sets);
679 emit barSetsChanged();
680 emit countChanged();
681 emit update();
682 }
683 return success;
684}
685
686/*!
687 Removes all bar sets from the series and permanently deletes them.
688*/
689void QBarSeries::clear()
690{
691 Q_D(QBarSeries);
692 const QList<QBarSet *> sets = barSets();
693 bool success = d->remove(sets);
694 if (success) {
695 emit barsetsRemoved(sets);
696 emit barSetsChanged();
697 emit countChanged();
698 for (QBarSet *set : sets) {
699 QObject::disconnect(sender: set, signal: &QBarSet::update, receiver: this, slot: &QBarSeries::update);
700 set->deleteLater();
701 }
702 emit update();
703 }
704}
705
706/*!
707 Replaces the BarSet which is present at \a index with \a set.
708 The original BarSet will be permanently deleted.
709*/
710void QBarSeries::replace(qsizetype index, QBarSet *set)
711{
712 Q_D(QBarSeries);
713
714 if (d->m_barSets.size() <= index)
715 return;
716 if (!set)
717 return;
718 if (index < 0)
719 index = 0;
720
721 remove(set: d->m_barSets[index]);
722 d->insert(index, set);
723
724 QList<QBarSet *> sets;
725 sets.append(t: set);
726 QObject::connect(sender: set, signal: &QBarSet::update, context: this, slot: &QBarSeries::update);
727 emit barsetsReplaced(sets);
728}
729
730/*!
731 Retrieves the BarSet specified at the location \a index.
732 Returns null if no BarSet was found.
733*/
734QBarSet *QBarSeries::at(qsizetype index)
735{
736 Q_D(QBarSeries);
737
738 if (d->m_barSets.size() <= index)
739 return nullptr;
740 if (index < 0)
741 return nullptr;
742
743 return d->m_barSets[index];
744}
745
746/*!
747 Returns the index of the first BarSet found as defined by \a set. Returns -1 if no BarSet was found.
748*/
749qsizetype QBarSeries::find(QBarSet *set) const
750{
751 Q_D(const QBarSeries);
752
753 for (qsizetype i = 0; i < d->m_barSets.size(); ++i) {
754 if (set == d->m_barSets[i])
755 return i;
756 }
757
758 return -1;
759}
760
761/*!
762 Removes multiple BarSets from the series starting from \a index to a number of \a count.
763 The BarSets will be permanently deleted.
764*/
765void QBarSeries::removeMultiple(qsizetype index, qsizetype count)
766{
767 Q_D(QBarSeries);
768
769 if (index + count >= d->m_barSets.size())
770 return;
771 if (index < 0 || count < 0)
772 return;
773
774 for (qsizetype i = index; i < index + count; ++i)
775 remove(set: d->m_barSets[index]);
776}
777
778/*!
779 Removes the BarSet at the location \a index. The BarSet will be permanently deleted.
780*/
781bool QBarSeries::remove(qsizetype index)
782{
783 Q_D(QBarSeries);
784
785 if (index >= d->m_barSets.size())
786 return false;
787 if (index < 0)
788 return false;
789
790 return remove(set: d->m_barSets[index]);
791}
792
793/*!
794 Replaces the BarSet specified by \a oldValue with the one in \a newValue. The BarSet
795 in \a oldValue will be permanently deleted if found inside the series. Returns \c true if
796 the replace is successful.
797*/
798bool QBarSeries::replace(QBarSet *oldValue, QBarSet *newValue)
799{
800 Q_D(QBarSeries);
801
802 if (!oldValue || !newValue)
803 return false;
804 if (oldValue == newValue)
805 return false;
806
807 for (qsizetype i = 0; i < d->m_barSets.size(); ++i) {
808 if (d->m_barSets[i] == oldValue) {
809 remove(set: d->m_barSets[i]);
810 d->insert(index: i, set: newValue);
811
812 QList<QBarSet *> sets;
813 sets.append(t: newValue);
814 QObject::connect(sender: newValue, signal: &QBarSet::update, context: this, slot: &QBarSeries::update);
815 emit barsetsReplaced(sets);
816 return true;
817 }
818 }
819
820 return false;
821}
822
823/*!
824 Replaces the entire BarSet list inside of this BarSeries with the BarSets specified by \a sets.
825 All of the original BarSets will be permanently deleted. Returns \c true if all BarSets are replaced.
826*/
827bool QBarSeries::replace(const QList<QBarSet *> &sets)
828{
829 Q_D(QBarSeries);
830
831 for (const auto set : sets) {
832 if (!set)
833 return false;
834 }
835
836 for (const auto set : d->m_barSets) {
837 remove(set);
838 }
839
840 for (const auto set : sets) {
841 QObject::connect(sender: set, signal: &QBarSet::update, context: this, slot: &QBarSeries::update);
842 }
843
844 d->append(sets);
845 emit barsetsReplaced(sets);
846
847 return true;
848}
849
850/*!
851 Returns the number of bar sets in a bar series.
852*/
853qsizetype QBarSeries::count() const
854{
855 Q_D(const QBarSeries);
856 return d->m_barSets.size();
857}
858
859/*!
860 Returns a list of bar sets in a bar series. Keeps the ownership of the bar sets.
861 */
862QList<QBarSet *> QBarSeries::barSets() const
863{
864 Q_D(const QBarSeries);
865 return d->m_barSets;
866}
867
868/*!
869 Sets the visibility of labels in a bar series to \a visible.
870*/
871void QBarSeries::setLabelsVisible(bool visible)
872{
873 Q_D(QBarSeries);
874 if (d->m_labelsVisible != visible) {
875 d->setLabelsVisible(visible);
876 emit labelsVisibleChanged(visible);
877 emit update();
878 }
879}
880
881/*!
882 Returns the visibility of labels.
883*/
884bool QBarSeries::labelsVisible() const
885{
886 Q_D(const QBarSeries);
887 return d->m_labelsVisible;
888}
889
890void QBarSeries::setLabelsFormat(const QString &format)
891{
892 Q_D(QBarSeries);
893 if (d->m_labelsFormat != format) {
894 d->m_labelsFormat = format;
895 d->setLabelsDirty(true);
896 emit labelsFormatChanged(format);
897 emit update();
898 }
899}
900
901QString QBarSeries::labelsFormat() const
902{
903 Q_D(const QBarSeries);
904 return d->m_labelsFormat;
905}
906
907void QBarSeries::setLabelsMargin(qreal margin)
908{
909 Q_D(QBarSeries);
910 if (d->m_labelsMargin != margin) {
911 d->m_labelsMargin = margin;
912 d->setLabelsDirty(true);
913 emit labelsMarginChanged(margin);
914 emit update();
915 }
916}
917
918qreal QBarSeries::labelsMargin() const
919{
920 Q_D(const QBarSeries);
921 return d->m_labelsMargin;
922}
923
924void QBarSeries::setLabelsAngle(qreal angle)
925{
926 Q_D(QBarSeries);
927 if (d->m_labelsAngle != angle) {
928 d->m_labelsAngle = angle;
929 d->setLabelsDirty(true);
930 emit labelsAngleChanged(angle);
931 emit update();
932 }
933}
934
935qreal QBarSeries::labelsAngle() const
936{
937 Q_D(const QBarSeries);
938 return d->m_labelsAngle;
939}
940
941void QBarSeries::setLabelsPosition(QBarSeries::LabelsPosition position)
942{
943 Q_D(QBarSeries);
944 if (d->m_labelsPosition != position) {
945 d->m_labelsPosition = position;
946 emit labelsPositionChanged(position);
947 emit update();
948 }
949}
950
951QBarSeries::LabelsPosition QBarSeries::labelsPosition() const
952{
953 Q_D(const QBarSeries);
954 return d->m_labelsPosition;
955}
956
957void QBarSeries::setLabelsPrecision(int precision)
958{
959 Q_D(QBarSeries);
960 if (d->m_labelsPrecision != precision) {
961 d->m_labelsPrecision = precision;
962 d->setLabelsDirty(true);
963 emit labelsPrecisionChanged(precision);
964 emit update();
965 }
966}
967
968int QBarSeries::labelsPrecision() const
969{
970 Q_D(const QBarSeries);
971 return d->m_labelsPrecision;
972}
973
974QQmlComponent *QBarSeries::barDelegate() const
975{
976 Q_D(const QBarSeries);
977 return d->m_barDelegate;
978}
979
980void QBarSeries::setBarDelegate(QQmlComponent *newBarDelegate)
981{
982 Q_D(QBarSeries);
983 if (d->m_barDelegate == newBarDelegate)
984 return;
985 d->m_barDelegate = newBarDelegate;
986 d->m_barDelegateDirty = true;
987 emit barDelegateChanged();
988 emit update();
989}
990
991// Select all the elements in the series
992void QBarSeries::selectAll()
993{
994 Q_D(QBarSeries);
995 for (auto s : d->m_barSets) {
996 s->selectAllBars();
997 }
998}
999
1000// Deselect all the elements in the series
1001void QBarSeries::deselectAll()
1002{
1003 Q_D(QBarSeries);
1004 for (auto s : d->m_barSets) {
1005 s->deselectAllBars();
1006 }
1007}
1008
1009void QBarSeries::componentComplete()
1010{
1011 for (auto *child : children()) {
1012 if (auto bs = qobject_cast<QBarSet *>(object: child))
1013 append(set: bs);
1014 }
1015 QAbstractSeries::componentComplete();
1016}
1017
1018void QBarSeries::handleSetValueChange(qsizetype index)
1019{
1020 QBarSet *set = qobject_cast<QBarSet *>(object: sender());
1021 if (set)
1022 emit setValueChanged(index, barset: set);
1023 emit update();
1024}
1025
1026void QBarSeries::handleSetValueAdd(qsizetype index, qsizetype count)
1027{
1028 QBarSet *set = qobject_cast<QBarSet *>(object: sender());
1029 if (set)
1030 emit setValueAdded(index, count, barset: set);
1031 emit update();
1032}
1033
1034void QBarSeries::handleSetValueRemove(qsizetype index, qsizetype count)
1035{
1036 QBarSet *set = qobject_cast<QBarSet *>(object: sender());
1037 if (set)
1038 emit setValueRemoved(index, count, barset: set);
1039 emit update();
1040}
1041
1042bool QBarSeries::barDelegateDirty() const
1043{
1044 Q_D(const QBarSeries);
1045 return d->m_barDelegateDirty;
1046}
1047
1048void QBarSeries::setBarDelegateDirty(bool dirty)
1049{
1050 Q_D(QBarSeries);
1051 d->m_barDelegateDirty = dirty;
1052}
1053
1054QBarSeriesPrivate::QBarSeriesPrivate()
1055 : m_barWidth(0.5) // Default value is 50% of category width
1056 , m_labelsVisible(false)
1057 , m_visible(true)
1058 , m_blockBarUpdate(false)
1059 , m_labelsFormat()
1060 , m_labelsMargin(0)
1061 , m_labelsAngle(0)
1062 , m_labelsPrecision(6)
1063 , m_labelsDirty(true)
1064 , m_barDelegateDirty(false)
1065{
1066}
1067
1068qsizetype QBarSeriesPrivate::categoryCount() const
1069{
1070 // No categories defined. return count of longest set.
1071 qsizetype count = 0;
1072 for (qsizetype i = 0; i < m_barSets.size(); i++) {
1073 if (m_barSets.at(i)->count() > count)
1074 count = m_barSets.at(i)->count();
1075 }
1076
1077 return count;
1078}
1079
1080void QBarSeriesPrivate::setBarWidth(qreal width)
1081{
1082 Q_Q(QBarSeries);
1083 width = std::clamp<qreal>(val: width, lo: 0.0, hi: 1.0);
1084 if (!qFuzzyCompare(p1: width, p2: m_barWidth)) {
1085 m_barWidth = width;
1086 q->update();
1087 }
1088}
1089
1090qreal QBarSeriesPrivate::barWidth() const
1091{
1092 return m_barWidth;
1093}
1094
1095QBarSet *QBarSeriesPrivate::barsetAt(qsizetype index)
1096{
1097 return m_barSets.at(i: index);
1098}
1099
1100void QBarSeriesPrivate::setVisible(bool visible)
1101{
1102 Q_Q(QBarSeries);
1103 m_visible = visible;
1104 emit q->visibleChanged();
1105}
1106
1107void QBarSeriesPrivate::setLabelsVisible(bool visible)
1108{
1109 m_labelsVisible = visible;
1110}
1111
1112qreal QBarSeriesPrivate::min()
1113{
1114 if (m_barSets.size() <= 0)
1115 return 0;
1116
1117 qreal min = INT_MAX;
1118
1119 for (int i = 0; i < m_barSets.size(); i++) {
1120 qsizetype categoryCount = m_barSets.at(i)->count();
1121 for (qsizetype j = 0; j < categoryCount; j++) {
1122 qreal temp = m_barSets.at(i)->at(index: j);
1123 if (temp < min)
1124 min = temp;
1125 }
1126 }
1127 return min;
1128}
1129
1130qreal QBarSeriesPrivate::max()
1131{
1132 if (m_barSets.size() <= 0)
1133 return 0;
1134
1135 qreal max = INT_MIN;
1136
1137 for (int i = 0; i < m_barSets.size(); i++) {
1138 qsizetype categoryCount = m_barSets.at(i)->count();
1139 for (qsizetype j = 0; j < categoryCount; j++) {
1140 qreal temp = m_barSets.at(i)->at(index: j);
1141 if (temp > max)
1142 max = temp;
1143 }
1144 }
1145
1146 return max;
1147}
1148
1149qreal QBarSeriesPrivate::valueAt(int set, int category)
1150{
1151 if ((set < 0) || (set >= m_barSets.size()))
1152 return 0; // No set, no value.
1153 else if ((category < 0) || (category >= m_barSets.at(i: set)->count()))
1154 return 0; // No category, no value.
1155
1156 return m_barSets.at(i: set)->at(index: category);
1157}
1158
1159qreal QBarSeriesPrivate::percentageAt(int set, int category)
1160{
1161 if ((set < 0) || (set >= m_barSets.size()))
1162 return 0; // No set, no value.
1163 else if ((category < 0) || (category >= m_barSets.at(i: set)->count()))
1164 return 0; // No category, no value.
1165
1166 qreal value = m_barSets.at(i: set)->at(index: category);
1167 qreal sum = categorySum(category);
1168 if (qFuzzyCompare(p1: sum, p2: 0))
1169 return 0;
1170
1171 return value / sum;
1172}
1173
1174qreal QBarSeriesPrivate::categorySum(qsizetype category)
1175{
1176 qreal sum(0);
1177 qsizetype count = m_barSets.size(); // Count sets
1178 for (qsizetype set = 0; set < count; set++) {
1179 if (category < m_barSets.at(i: set)->count())
1180 sum += m_barSets.at(i: set)->at(index: category);
1181 }
1182 return sum;
1183}
1184
1185qreal QBarSeriesPrivate::absoluteCategorySum(int category)
1186{
1187 qreal sum(0);
1188 qsizetype count = m_barSets.size(); // Count sets
1189 for (qsizetype set = 0; set < count; set++) {
1190 if (category < m_barSets.at(i: set)->count())
1191 sum += qAbs(t: m_barSets.at(i: set)->at(index: category));
1192 }
1193 return sum;
1194}
1195
1196qreal QBarSeriesPrivate::maxCategorySum()
1197{
1198 qreal max = INT_MIN;
1199 qsizetype count = categoryCount();
1200 for (qsizetype i = 0; i < count; i++) {
1201 qreal sum = categorySum(category: i);
1202 if (sum > max)
1203 max = sum;
1204 }
1205 return max;
1206}
1207
1208qreal QBarSeriesPrivate::minX()
1209{
1210 if (m_barSets.size() <= 0)
1211 return 0;
1212
1213 qreal min = INT_MAX;
1214
1215 for (int i = 0; i < m_barSets.size(); i++) {
1216 qsizetype categoryCount = m_barSets.at(i)->count();
1217 for (qsizetype j = 0; j < categoryCount; j++) {
1218 qreal temp = m_barSets.at(i)->d_func()->m_values.at(i: j).x();
1219 if (temp < min)
1220 min = temp;
1221 }
1222 }
1223 return min;
1224}
1225
1226qreal QBarSeriesPrivate::maxX()
1227{
1228 if (m_barSets.size() <= 0)
1229 return 0;
1230
1231 qreal max = INT_MIN;
1232
1233 for (int i = 0; i < m_barSets.size(); i++) {
1234 qsizetype categoryCount = m_barSets.at(i)->count();
1235 for (qsizetype j = 0; j < categoryCount; j++) {
1236 qreal temp = m_barSets.at(i)->d_func()->m_values.at(i: j).x();
1237 if (temp > max)
1238 max = temp;
1239 }
1240 }
1241
1242 return max;
1243}
1244
1245qreal QBarSeriesPrivate::categoryTop(qsizetype category)
1246{
1247 // Returns top (sum of all positive values) of category.
1248 // Returns 0, if all values are negative
1249 qreal top(0);
1250 qsizetype count = m_barSets.size();
1251 for (qsizetype set = 0; set < count; set++) {
1252 if (category < m_barSets.at(i: set)->count()) {
1253 qreal temp = m_barSets.at(i: set)->at(index: category);
1254 if (temp > 0) {
1255 top += temp;
1256 }
1257 }
1258 }
1259 return top;
1260}
1261
1262qreal QBarSeriesPrivate::categoryBottom(qsizetype category)
1263{
1264 // Returns bottom (sum of all negative values) of category
1265 // Returns 0, if all values are positive
1266 qreal bottom(0);
1267 qsizetype count = m_barSets.size();
1268 for (qsizetype set = 0; set < count; set++) {
1269 if (category < m_barSets.at(i: set)->count()) {
1270 qreal temp = m_barSets.at(i: set)->at(index: category);
1271 if (temp < 0) {
1272 bottom += temp;
1273 }
1274 }
1275 }
1276 return bottom;
1277}
1278qreal QBarSeriesPrivate::top()
1279{
1280 // Returns top of all categories
1281 qreal top(0);
1282 qsizetype count = categoryCount();
1283 for (qsizetype i = 0; i < count; i++) {
1284 qreal temp = categoryTop(category: i);
1285 if (temp > top)
1286 top = temp;
1287 }
1288 return top;
1289}
1290
1291qreal QBarSeriesPrivate::bottom()
1292{
1293 // Returns bottom of all categories
1294 qreal bottom(0);
1295 qsizetype count = categoryCount();
1296 for (qsizetype i = 0; i < count; i++) {
1297 qreal temp = categoryBottom(category: i);
1298 if (temp < bottom)
1299 bottom = temp;
1300 }
1301 return bottom;
1302}
1303
1304bool QBarSeriesPrivate::blockBarUpdate()
1305{
1306 return m_blockBarUpdate;
1307}
1308
1309bool QBarSeriesPrivate::append(QBarSet *set)
1310{
1311 if ((m_barSets.contains(t: set)) || (set == 0))
1312 return false; // Fail if set is already in list or set is null.
1313
1314 m_barSets.append(t: set);
1315 Q_Q(QBarSeries);
1316 QObject::connect(sender: set, signal: &QBarSet::updatedBars, context: q, slot: &QBarSeries::updatedBars);
1317 QObject::connect(sender: set, signal: &QBarSet::valueChanged, context: q, slot: &QBarSeries::handleSetValueChange);
1318 QObject::connect(sender: set, signal: &QBarSet::valueAdded, context: q, slot: &QBarSeries::handleSetValueAdd);
1319 QObject::connect(sender: set, signal: &QBarSet::valueRemoved, context: q, slot: &QBarSeries::handleSetValueRemove);
1320 QObject::connect(sender: set, signal: &QBarSet::selectedBarsChanged, context: q, slot: &QBarSeries::updatedBars);
1321
1322 return true;
1323}
1324
1325bool QBarSeriesPrivate::remove(QBarSet *set)
1326{
1327 if (!m_barSets.contains(t: set))
1328 return false; // Fail if set is not in list
1329
1330 m_barSets.removeOne(t: set);
1331 Q_Q(QBarSeries);
1332 QObject::disconnect(sender: set, signal: &QBarSet::updatedBars, receiver: q, slot: &QBarSeries::updatedBars);
1333 QObject::disconnect(sender: set, signal: &QBarSet::valueChanged, receiver: q, slot: &QBarSeries::handleSetValueChange);
1334 QObject::disconnect(sender: set, signal: &QBarSet::valueAdded, receiver: q, slot: &QBarSeries::handleSetValueAdd);
1335 QObject::disconnect(sender: set, signal: &QBarSet::valueRemoved, receiver: q, slot: &QBarSeries::handleSetValueRemove);
1336 QObject::disconnect(sender: set, signal: &QBarSet::selectedBarsChanged, receiver: q, slot: &QBarSeries::updatedBars);
1337
1338 return true;
1339}
1340
1341bool QBarSeriesPrivate::append(const QList<QBarSet *> &sets)
1342{
1343 for (auto *set : sets) {
1344 if ((set == 0) || (m_barSets.contains(t: set)))
1345 return false; // Fail if any of the sets is null or is already appended.
1346 if (sets.count(t: set) != 1)
1347 return false; // Also fail if same set is more than once in given list.
1348 }
1349
1350 Q_Q(QBarSeries);
1351 for (auto *set : sets) {
1352 m_barSets.append(t: set);
1353 QObject::connect(sender: set, signal: &QBarSet::updatedBars, context: q, slot: &QBarSeries::updatedBars);
1354 QObject::connect(sender: set, signal: &QBarSet::valueChanged, context: q, slot: &QBarSeries::handleSetValueChange);
1355 QObject::connect(sender: set, signal: &QBarSet::valueAdded, context: q, slot: &QBarSeries::handleSetValueAdd);
1356 QObject::connect(sender: set, signal: &QBarSet::valueRemoved, context: q, slot: &QBarSeries::handleSetValueRemove);
1357 QObject::connect(sender: set, signal: &QBarSet::selectedBarsChanged, context: q, slot: &QBarSeries::updatedBars);
1358 }
1359
1360 return true;
1361}
1362
1363bool QBarSeriesPrivate::remove(const QList<QBarSet *> &sets)
1364{
1365 if (sets.size() == 0)
1366 return false;
1367
1368 for (QBarSet *set : sets) {
1369 if ((set == 0) || (!m_barSets.contains(t: set)))
1370 return false; // Fail if any of the sets is null or is not in series
1371 if (sets.count(t: set) != 1)
1372 return false; // Also fail if same set is more than once in given list.
1373 }
1374
1375 Q_Q(QBarSeries);
1376 for (QBarSet *set : sets) {
1377 m_barSets.removeOne(t: set);
1378 QObject::disconnect(sender: set, signal: &QBarSet::updatedBars, receiver: q, slot: &QBarSeries::updatedBars);
1379 QObject::disconnect(sender: set,
1380 signal: &QBarSet::valueChanged,
1381 receiver: q,
1382 slot: &QBarSeries::handleSetValueChange);
1383 QObject::disconnect(sender: set, signal: &QBarSet::valueAdded, receiver: q, slot: &QBarSeries::handleSetValueAdd);
1384 QObject::disconnect(sender: set,
1385 signal: &QBarSet::valueRemoved,
1386 receiver: q,
1387 slot: &QBarSeries::handleSetValueRemove);
1388 QObject::disconnect(sender: set, signal: &QBarSet::selectedBarsChanged, receiver: q, slot: &QBarSeries::updatedBars);
1389 }
1390
1391 return true;
1392}
1393
1394bool QBarSeriesPrivate::insert(qsizetype index, QBarSet *set)
1395{
1396 if ((m_barSets.contains(t: set)) || (set == 0))
1397 return false; // Fail if set is already in list or set is null.
1398
1399 m_barSets.insert(i: index, t: set);
1400 Q_Q(QBarSeries);
1401 QObject::connect(sender: set, signal: &QBarSet::updatedBars, context: q, slot: &QBarSeries::updatedBars);
1402 QObject::connect(sender: set, signal: &QBarSet::valueChanged, context: q, slot: &QBarSeries::handleSetValueChange);
1403 QObject::connect(sender: set, signal: &QBarSet::valueAdded, context: q, slot: &QBarSeries::handleSetValueAdd);
1404 QObject::connect(sender: set, signal: &QBarSet::valueRemoved, context: q, slot: &QBarSeries::handleSetValueRemove);
1405 QObject::disconnect(sender: set, signal: &QBarSet::selectedBarsChanged, receiver: q, slot: &QBarSeries::updatedBars);
1406
1407 return true;
1408}
1409
1410QT_END_NAMESPACE
1411
1412#include "moc_qbarseries.cpp"
1413

source code of qtgraphs/src/graphs2d/barchart/qbarseries.cpp