// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE /*! \class QBarSeries \inmodule QtGraphs \ingroup graphs_2D \brief The QBarSeries class presents data in bar graphs. This class draws data by default as a series of bars grouped by category, with one bar per category from each bar set added to the series. It also supports horizontal bars and grouping bars as stacked. A bar series needs the GraphsView x-axis to be set to a BarCategoryAxis and the y-axis set to ValueAxis. \sa QBarSet, QAbstractSeries */ /*! \qmltype BarSeries \nativetype QBarSeries \inqmlmodule QtGraphs \ingroup graphs_qml_2D \inherits AbstractSeries \brief Presents data in bar graphs. Draws data by default as a series of bars grouped by category, with one bar per category from each bar set added to the series. It also supports horizontal bars and grouping bars as stacked. */ /*! \property QBarSeries::barWidth \brief The width of the bars of the series. The unit of width is the unit of the x-axis. The minimum width for bars is zero, and negative values are treated as zero. Setting the width to zero means that the width of the bar on the screen is one pixel regardless of the scale of the x-axis. Bars wider than zero are scaled using the x-axis scale. By default, the barWidth is 0.5 (bars will take 50% of the available width). The valid values range from 0.0 (0%) to 1.0 (100%). \note When used with QBarSeries, this value specifies the width of a group of bars instead of that of a single bar. \sa QBarSeries */ /*! \enum QBarSeries::BarsType This enum value describes the type of the bar series: \value Groups Bar sets are grouped by category. \value Stacked Bar sets are stacked after each other by category. \value StackedPercent Bar sets are stacked after each other by category. The segment size corresponds to the percentage of the segment value compared with the total value of all segments in the stack. */ /*! \property QBarSeries::barsType \brief The type of the bar series. */ /*! \qmlproperty enumeration BarSeries::barsType The type of the bar series: \value BarSeries.BarsType.Groups Bar sets are grouped by category. This is the default value. \value BarSeries.BarsType.Stacked Bar sets are stacked after each other by category. \value BarSeries.BarsType.StackedPercent Bar sets are stacked after each other by category. The segment size corresponds to the percentage of the segment value compared with the total value of all segments in the stack. */ /*! \qmlproperty real BarSeries::barWidth The unit of width is the unit of the x-axis. The minimum width for bars is zero, and negative values are treated as zero. Setting the width to zero means that the width of the bar on the screen is one pixel regardless of the scale of the x-axis. Bars wider than zero are scaled using the x-axis scale. By default, the barWidth is 0.5 (bars will take 50% of the available width). The valid values range from 0.0 (0%) to 1.0 (100%). \note When used with the BarSeries type, this value specifies the width of a group of bars instead of that of a single bar. */ /*! \property QBarSeries::count \brief The number of bar sets in a bar series. */ /*! \qmlproperty int BarSeries::count The number of bar sets in a bar series. */ /*! \property QBarSeries::labelsVisible \brief The visibility of the labels in a bar series. The default label visibility is \c false. */ /*! \qmlproperty bool BarSeries::labelsVisible The visibility of the labels in a bar series. The default label visibility is \c false. */ /*! \property QBarSeries::labelsFormat \brief The format used for showing labels in a bar series. QBarSeries supports the following format tag: \table \row \li @value \li The value of the bar \endtable For example, the following usage of the format tags would produce labels that show the value followed by the unit (u): \code series->setLabelsFormat("@value u"); \endcode By default, the labels show the value of the bar. For the percent bar series, \e % is added after the value. The labels are shown on the plot area, if the bars are close to each other, the labels may overlap. \sa labelsVisible, labelsPosition, labelsPrecision */ /*! \qmlproperty string BarSeries::labelsFormat The format used for showing labels in a bar series. \sa QBarSeries::labelsFormat, labelsVisible, labelsPosition */ /*! \enum QBarSeries::LabelsPosition This enum value describes the position of the data value labels: \value Center Label is located in the center of the bar. \value InsideEnd Label is located inside the bar at the top. \value InsideBase Label is located inside the bar at the bottom. \value OutsideEnd Label is located outside the bar at the top. */ /*! \property QBarSeries::labelsPosition \brief The position of value labels. \sa labelsVisible, labelsFormat */ /*! \qmlproperty enumeration BarSeries::labelsPosition The position of the data value labels: \value BarSeries.LabelsPosition.Center Label is located in the center of the bar. \value BarSeries.LabelsPosition.InsideEnd Label is located inside the bar at the top. \value BarSeries.LabelsPosition.InsideBase Label is located inside the bar at the bottom. \value BarSeries.LabelsPosition.OutsideEnd Label is located outside the bar at the top. \sa labelsVisible, labelsFormat */ /*! \property QBarSeries::labelsMargin \brief The margin of the value labels in pixels. This margin from side is used when \l labelsPosition is set to something else than \c LabelsPosition.Center. The default value is \c 0. */ /*! \qmlproperty real BarSeries::labelsMargin The margin of the value labels in pixels. This margin from side is used when \l labelsPosition is set to something else than \c LabelsPosition.Center. The default value is \c 0. */ /*! \property QBarSeries::labelsAngle \brief The angle of the value labels in degrees. */ /*! \qmlproperty real BarSeries::labelsAngle The angle of the value labels in degrees. */ /*! \property QBarSeries::labelsPrecision \brief The maximum amount of significant digits shown in value labels. Default value is 6. */ /*! \qmlproperty real BarSeries::labelsPrecision The maximum amount of significant digits shown in value labels. Default value is 6. */ /*! \property QBarSeries::barDelegate \brief A custom QML component used for visualizing each of the bars. Instance of this component is created for each of the bar. When this is not defined, a default rectangle visualization for bars is used. The dynamic properties available for this component are: \table \header \li Type \li Name \li Description \row \li QColor \li barColor \li The fill color of the bar. This value comes either from the \l QGraphsTheme or from \l{QBarSet::color} if the \l QBarSet overrides the color. \row \li QColor \li barBorderColor \li The border color of the bar. This value comes either from the \l QGraphsTheme or from \l{QBarSet::borderColor} if the \l QBarSet overrides the color. \row \li qreal \li barBorderWidth \li The width of the bar border. This value comes either from the \l QGraphsTheme or from \l{QBarSet::borderWidth} if the \l QBarSet overrides the width. \row \li qreal \li barValue \li The value of the bar. This value comes from the \l{QBarSet::values}. \row \li QString \li barLabel \li The label of the bar. This value comes from the \l{QBarSet::label}. \row \li bool \li barSelected \li This value is true when the bar is selected, meaning that the bar index is in \l{QBarSet::selectedBars}. \row \li int \li barIndex \li Index of the bar, from 0 to the amount of bars - 1. [since 6.9] \endtable To use any of these, add property with the defined name into your custom component. For example \c{"property color barColor"} and \c{"property real barValue"}. */ /*! \qmlproperty Component BarSeries::barDelegate A custom QML component used for visualizing each of the bars. Instance of this component is created for each of the bar. When this is not defined, a default rectangle visualization for bars is used. The dynamic properties available for this component are: \table \header \li Type \li Name \li Description \row \li color \li barColor \li The fill color of the bar. This value comes either from the \l GraphsTheme or from \l{BarSet::color} if the \l BarSet overrides the color. \row \li color \li barBorderColor \li The border color of the bar. This value comes either from the \l GraphsTheme or from \l{BarSet::borderColor} if the \l BarSet overrides the color. \row \li real \li barBorderWidth \li The width of the bar border. This value comes either from the \l GraphsTheme or from \l{BarSet::borderWidth} if the \l BarSet overrides the width. \row \li real \li barValue \li The value of the bar. This value comes from the \l{BarSet::values}. \row \li string \li barLabel \li The label of the bar. This value comes from the \l{BarSet::label}. \row \li bool \li barSelected \li This value is true when the bar is selected, meaning that the bar index is in \l{BarSet::selectedBars}. \row \li int \li barIndex \li Index of the bar, from 0 to the amount of bars - 1. [since 6.9] \endtable To use any of these, add property with the defined name into your custom component. For example \c{"property color barColor"} and \c{"property real barValue"}. */ /*! \property QBarSeries::barSets \brief A list of sets added to the series. */ /*! \qmlproperty list BarSeries::barSets A list of sets added to the series. */ /*! \fn void QBarSeries::updatedBars() This signal is emitted when bars are updated. */ /*! \fn void QBarSeries::labelsVisibleChanged(bool visible) This signal is emitted when the labels' visibility changes to \a visible. \sa labelsVisible(), setLabelsVisible() */ /*! \fn void QBarSeries::barsetsAdded(const QList &sets) This signal is emitted when the bar sets specified by \a sets are added to the series. \sa append(), insert() */ /*! \qmlsignal BarSeries::barsetsAdded() This signal is emitted when bar sets are added to the series. */ /*! \fn void QBarSeries::barsetsRemoved(const QList &sets) This signal is emitted when the bar sets specified by \a sets are removed from the series. \sa remove() */ /*! \qmlsignal BarSeries::barsetsRemoved() This signal is emitted when bar sets are removed from the series. */ /*! \fn void QBarSeries::setValueChanged(qsizetype index, QBarSet *barset) This signal is emitted when a barset's value is changed. \a index is the index of the barset in the series. The \a barset is a pointer to the changed set. */ /*! \fn void QBarSeries::setValueAdded(qsizetype index, qsizetype count, QBarSet *barset) This signal is emitted when a barset's value is changed. \a index is the index of the barset in the series. The number of the added values is indicated \a count. The \a barset is a pointer to the changed set. */ /*! \fn void QBarSeries::setValueRemoved(qsizetype index, qsizetype count, QBarSet *barset) This signal is emitted when a barset's value is changed. \a index is the index of the barset in the series. The number of the removed values is indicated \a count. The \a barset is a pointer to the changed set. */ /*! \qmlmethod BarSet BarSeries::at(int index) Returns the bar set at \a index. Returns null if the index is not valid. */ /*! \qmlmethod BarSet BarSeries::insert(int index, string label, VariantList values) Adds a new bar set with \a label and \a values to \a index. \a values can be a list of real values or a list of XYPoint types. If the index value is equal to or less than zero, the new bar set is prepended to the bar series. If the index value is equal to or greater than the number of bar sets in the bar series, the new bar set is appended to the bar series. \sa append() */ /*! \qmlmethod bool BarSeries::append(BarSet barset) Adds a set of bars specified by \a barset to the bar series and takes ownership of it. If the set is null or it already belongs to the series, it will not be appended. Returns \c true if appending succeeded. \sa insert() */ /*! \qmlmethod bool BarSeries::remove(BarSet barset) Removes the bar set specified by \a barset from the series. Returns \c true if successful, \c false otherwise. */ /*! \qmlmethod BarSeries::clear() Removes all bar sets from the series. */ /*! \qmlmethod bool BarSeries::replace(int index, BarSet barset) Replaces the bar set at the position specified by \a index from the series and replaces it with \a barset. Returns \c true if successful, \c false otherwise. */ /*! \qmlmethod Barset BarSeries::at(int index) Returns the bar set specified by \a index from the series. Returns \c null otherwise. */ /*! \qmlmethod int BarSeries::find(BarSet barset) Returns the index of the bar set specified by \a barset from the series. Returns \c -1 if not found. */ /*! \qmlmethod BarSeries::removeMultiple(int index, int count) Removes a range of bar sets as specified by the \a index and \a count. The call traverses over all sets even if removal of one fails. */ /*! \qmlmethod bool BarSeries::remove(int index) Removes the bar set specified by \a index from the series. Returns \c true if the removal was successful, \c false otherwise. */ /*! \qmlmethod bool BarSeries::replace(BarSet oldSet, BarSet newSet) Replaces the bar set specified by \a oldSet with newSet. Returns \c true if the removal was successful, \c false otherwise. \a oldSet is destroyed if this is successful. */ /*! \qmlmethod bool BarSeries::replace(list sets) Completely replaces all current bar set with \a sets. The size does not need to match. Returns false if any of the bar set in \a sets are invalid. */ /*! \qmlsignal BarSeries::clicked(int index, BarSet barset) This signal is emitted when the user clicks or taps the bar specified by \a index in the bar set specified by \a barset. */ /*! \qmlsignal BarSeries::doubleClicked(int index, BarSet barset) This signal is emitted when the user double-clicks or double-taps the bar specified by \a index in the bar set specified by \a barset. This signal always occurs after \l clicked. */ /*! \qmlsignal BarSeries::pressed(int index, BarSet barset) This signal is emitted when the user clicks or taps the bar specified by \a index in the bar set specified by \a barset and holds down the mouse button or gesture. */ /*! \qmlsignal BarSeries::released(int index, BarSet barset); This signal is emitted when the user releases a previously pressed mouse button or gesture on the bar specified by \a index in the bar set specified by \a barset. */ /*! \internal */ /*! Constructs an empty bar series that is a QObject and a child of \a parent. */ QBarSeries::QBarSeries(QObject *parent) : QAbstractSeries(*(new QBarSeriesPrivate()), parent) {} QBarSeries::~QBarSeries() {} QBarSeries::QBarSeries(QBarSeriesPrivate &dd, QObject *parent) : QAbstractSeries(dd, parent) {} /*! Returns the bar series. */ QAbstractSeries::SeriesType QBarSeries::type() const { return QAbstractSeries::SeriesType::Bar; } /*! \property QBarSeries::seriesColors \brief The list of base colors to be used for all the objects in the series. If there are more series than colors, the color list wraps and starts again with the first color in the list. If this is not set (default), colors from the \l{QGraphsTheme::seriesColors} will be used. */ /*! \qmlproperty list BarSeries::seriesColors The list of base colors to be used for all the objects in the series. If there are more series than colors, the color list wraps and starts again with the first color in the list. If this is not set (default), colors from the \l{GraphsTheme::seriesColors} will be used. */ QList QBarSeries::seriesColors() const { Q_D(const QBarSeries); return d->m_seriesColors; } void QBarSeries::setSeriesColors(const QList &newSeriesColors) { Q_D(QBarSeries); for (const QColor &color : newSeriesColors) { if (!color.isValid()) { qCWarning(lcProperties2D, "QBarSeries::setSeriesColors. Tried to use invalid color value."); break; } } if (d->m_seriesColors == newSeriesColors) { qCDebug(lcProperties2D) << "QBarSeries::setSeriesColors. Set value of" << newSeriesColors << "is the same as it already was."; return; } d->m_seriesColors = newSeriesColors; emit seriesColorsChanged(); emit update(); } /*! \property QBarSeries::borderColors \brief The list of border colors to be used for all the objects in the series. If there are more series than colors, the color list wraps and starts again with the first color in the list. If this is not set (default), colors from the \l{QGraphsTheme::borderColors} will be used. */ /*! \qmlproperty list BarSeries::borderColors The list of border colors to be used for all the objects in the series. If there are more series than colors, the color list wraps and starts again with the first color in the list. If this is not set (default), colors from the \l{GraphsTheme::borderColors} will be used. */ QList QBarSeries::borderColors() const { Q_D(const QBarSeries); return d->m_borderColors; } void QBarSeries::setBorderColors(const QList &newBorderColors) { Q_D(QBarSeries); for (const QColor &color : newBorderColors) { if (!color.isValid()) { qCWarning(lcProperties2D, "QBarSeries::setBorderColors. Tried to use invalid color value."); break; } } if (d->m_borderColors == newBorderColors) { qCDebug(lcProperties2D) << "QBarSeries::setBorderColors. Set value of:" << newBorderColors << "is the same than it already was."; return; } d->m_borderColors = newBorderColors; emit borderColorsChanged(); emit update(); } void QBarSeries::setBarsType(QBarSeries::BarsType type) { Q_D(QBarSeries); if (d->m_barsType != type) { d->m_barsType = type; emit barsTypeChanged(type); emit update(); } else { qCDebug(lcProperties2D) << "QBarSeries::setBarsType. Set value of:" << type << "is the same than it already was."; } } QBarSeries::BarsType QBarSeries::barsType() const { Q_D(const QBarSeries); return d->m_barsType; } /*! Sets the width of the bars of the series to \a width. */ void QBarSeries::setBarWidth(qreal width) { Q_D(QBarSeries); if (d->barWidth() != width) { d->setBarWidth(width); emit barWidthChanged(); } else { qCDebug(lcProperties2D, "QBarSeries::setBarWidth. Set value of: %f is the same than it already was.", width); } } /*! Returns the width of the bars of the series. \sa setBarWidth() */ qreal QBarSeries::barWidth() const { Q_D(const QBarSeries); return d->barWidth(); } /*! Adds a set of bars specified by \a set to the bar series and takes ownership of it. If the set is null or it already belongs to the series, it will not be appended. Returns \c true if appending succeeded. */ bool QBarSeries::append(QBarSet *set) { Q_D(QBarSeries); bool success = d->append(set); if (success) { QList sets; sets.append(set); set->setParent(this); QObject::connect(set, &QBarSet::update, this, &QBarSeries::update); emit barsetsAdded(sets); emit barSetsChanged(); emit countChanged(); emit update(); } return success; } /*! Removes the bar set specified by \a set from the series and permanently deletes it if the removal succeeds. Returns \c true if the set was removed. */ bool QBarSeries::remove(QBarSet *set) { Q_D(QBarSeries); bool success = d->remove(set); if (success) { QList sets; sets.append(set); set->setParent(0); QObject::disconnect(set, &QBarSet::update, this, &QBarSeries::update); emit barsetsRemoved(sets); emit barSetsChanged(); emit countChanged(); emit update(); delete set; set = 0; } return success; } /*! Takes a single \a set from the series. Does not delete the bar set object. \note The series remains the barset's parent object. You must set the parent object to take full ownership. Returns \c true if the take operation succeeds. */ bool QBarSeries::take(QBarSet *set) { Q_D(QBarSeries); bool success = d->remove(set); if (success) { QList sets; sets.append(set); QObject::disconnect(set, &QBarSet::update, this, &QBarSeries::update); emit barsetsRemoved(sets); emit barSetsChanged(); emit countChanged(); emit update(); } return success; } /*! Adds a list of bar sets specified by \a sets to a bar series and takes ownership of the sets. Returns \c true if all sets were appended successfully. If any of the sets is null or was previously appended to the series, nothing is appended and this function returns \c false. If any of the sets appears in the list more than once, nothing is appended and this function returns \c false. */ bool QBarSeries::append(const QList &sets) { Q_D(QBarSeries); if (!d->append(sets)) return false; for (auto *set : sets) { set->setParent(this); QObject::connect(set, &QBarSet::update, this, &QBarSeries::update); } emit barsetsAdded(sets); emit barSetsChanged(); emit countChanged(); emit update(); return true; } /*! Inserts a bar set specified by \a set to a series at the position specified by \a index and takes ownership of the set. If the set is null or already belongs to the series, it will not be appended. Returns \c true if inserting succeeds. */ bool QBarSeries::insert(qsizetype index, QBarSet *set) { Q_D(QBarSeries); bool success = d->insert(index, set); if (success) { QList sets; sets.append(set); QObject::connect(set, &QBarSet::update, this, &QBarSeries::update); emit barsetsAdded(sets); emit barSetsChanged(); emit countChanged(); emit update(); } return success; } /*! Removes all bar sets from the series and permanently deletes them. */ void QBarSeries::clear() { Q_D(QBarSeries); const QList sets = barSets(); bool success = d->remove(sets); if (success) { emit barsetsRemoved(sets); emit barSetsChanged(); emit countChanged(); for (QBarSet *set : sets) { QObject::disconnect(set, &QBarSet::update, this, &QBarSeries::update); set->deleteLater(); } emit update(); } } /*! Replaces the BarSet which is present at \a index with \a set. The original BarSet will be permanently deleted. */ void QBarSeries::replace(qsizetype index, QBarSet *set) { Q_D(QBarSeries); if (d->m_barSets.size() <= index) return; if (!set) return; if (index < 0) index = 0; remove(d->m_barSets[index]); d->insert(index, set); QList sets; sets.append(set); QObject::connect(set, &QBarSet::update, this, &QBarSeries::update); emit barsetsReplaced(sets); } /*! Retrieves the BarSet specified at the location \a index. Returns null if no BarSet was found. */ QBarSet *QBarSeries::at(qsizetype index) { Q_D(QBarSeries); if (d->m_barSets.size() <= index) return nullptr; if (index < 0) return nullptr; return d->m_barSets[index]; } /*! Returns the index of the first BarSet found as defined by \a set. Returns -1 if no BarSet was found. */ qsizetype QBarSeries::find(QBarSet *set) const { Q_D(const QBarSeries); for (qsizetype i = 0; i < d->m_barSets.size(); ++i) { if (set == d->m_barSets[i]) return i; } return -1; } /*! Removes multiple BarSets from the series starting from \a index to a number of \a count. The BarSets will be permanently deleted. */ void QBarSeries::removeMultiple(qsizetype index, qsizetype count) { Q_D(QBarSeries); if (index < 0 || count < 1 || index + count > d->m_barSets.size()) return; for (qsizetype i = index; i < index + count; ++i) remove(d->m_barSets[index]); } /*! Removes the BarSet at the location \a index. The BarSet will be permanently deleted. */ bool QBarSeries::remove(qsizetype index) { Q_D(QBarSeries); if (index >= d->m_barSets.size()) return false; if (index < 0) return false; return remove(d->m_barSets[index]); } /*! Replaces the BarSet specified by \a oldValue with the one in \a newValue. The BarSet in \a oldValue will be permanently deleted if found inside the series. Returns \c true if the replace is successful. */ bool QBarSeries::replace(QBarSet *oldValue, QBarSet *newValue) { Q_D(QBarSeries); if (!oldValue || !newValue) return false; if (oldValue == newValue) return false; for (qsizetype i = 0; i < d->m_barSets.size(); ++i) { if (d->m_barSets[i] == oldValue) { remove(d->m_barSets[i]); d->insert(i, newValue); QList sets; sets.append(newValue); QObject::connect(newValue, &QBarSet::update, this, &QBarSeries::update); emit barsetsReplaced(sets); return true; } } return false; } /*! Replaces the entire BarSet list inside of this BarSeries with the BarSets specified by \a sets. All of the original BarSets will be permanently deleted. Returns \c true if all BarSets are replaced. */ bool QBarSeries::replace(const QList &sets) { Q_D(QBarSeries); for (const auto set : sets) { if (!set) return false; } for (const auto set : d->m_barSets) { remove(set); } for (const auto set : sets) { QObject::connect(set, &QBarSet::update, this, &QBarSeries::update); } d->append(sets); emit barsetsReplaced(sets); return true; } /*! Returns the number of bar sets in a bar series. */ qsizetype QBarSeries::count() const { Q_D(const QBarSeries); return d->m_barSets.size(); } /*! Returns a list of bar sets in a bar series. Keeps the ownership of the bar sets. */ QList QBarSeries::barSets() const { Q_D(const QBarSeries); return d->m_barSets; } /*! Sets the visibility of labels in a bar series to \a visible. */ void QBarSeries::setLabelsVisible(bool visible) { Q_D(QBarSeries); if (d->m_labelsVisible != visible) { d->setLabelsVisible(visible); emit labelsVisibleChanged(visible); emit update(); } else { qCDebug(lcProperties2D) << "QBarSeries::setLabelsVisible. Label visibility is already set to:" << visible; } } /*! Returns the visibility of labels. */ bool QBarSeries::labelsVisible() const { Q_D(const QBarSeries); return d->m_labelsVisible; } void QBarSeries::setLabelsFormat(const QString &format) { Q_D(QBarSeries); if (d->m_labelsFormat != format) { d->m_labelsFormat = format; d->setLabelsDirty(true); emit labelsFormatChanged(format); emit update(); } else { qCDebug(lcProperties2D) << "QBarSeries::setLabelsFormat. Format is already set to value:" << format; } } QString QBarSeries::labelsFormat() const { Q_D(const QBarSeries); return d->m_labelsFormat; } void QBarSeries::setLabelsMargin(qreal margin) { Q_D(QBarSeries); if (d->m_labelsMargin != margin) { d->m_labelsMargin = margin; d->setLabelsDirty(true); emit labelsMarginChanged(margin); emit update(); } else { qCDebug(lcProperties2D, "QBarSeries::setLabelsMargin. Margin is already set to value: %f", margin); } } qreal QBarSeries::labelsMargin() const { Q_D(const QBarSeries); return d->m_labelsMargin; } void QBarSeries::setLabelsAngle(qreal angle) { Q_D(QBarSeries); if (d->m_labelsAngle != angle) { d->m_labelsAngle = angle; d->setLabelsDirty(true); emit labelsAngleChanged(angle); emit update(); } else { qCDebug(lcProperties2D, "QBarSeries::setLabelsAngle. Label angle is already set to value: %f", angle); } } qreal QBarSeries::labelsAngle() const { Q_D(const QBarSeries); return d->m_labelsAngle; } void QBarSeries::setLabelsPosition(QBarSeries::LabelsPosition position) { Q_D(QBarSeries); if (d->m_labelsPosition != position) { d->m_labelsPosition = position; emit labelsPositionChanged(position); emit update(); } else { qCDebug(lcProperties2D) << "QBarSeries::setLabelsPosition. Position is already set to:" << position; } } QBarSeries::LabelsPosition QBarSeries::labelsPosition() const { Q_D(const QBarSeries); return d->m_labelsPosition; } void QBarSeries::setLabelsPrecision(int precision) { Q_D(QBarSeries); if (d->m_labelsPrecision != precision) { d->m_labelsPrecision = precision; d->setLabelsDirty(true); emit labelsPrecisionChanged(precision); emit update(); } else { qCDebug(lcProperties2D, "QBarSeries::setLabelsPrecision. Precision is already set to: %d", precision); } } int QBarSeries::labelsPrecision() const { Q_D(const QBarSeries); return d->m_labelsPrecision; } QQmlComponent *QBarSeries::barDelegate() const { Q_D(const QBarSeries); return d->m_barDelegate; } void QBarSeries::setBarDelegate(QQmlComponent *newBarDelegate) { Q_D(QBarSeries); if (d->m_barDelegate == newBarDelegate) { qCDebug(lcProperties2D) << "QBarSeries::setBarDelegate. BarDelegate is already set to:" << newBarDelegate; return; } d->m_barDelegate = newBarDelegate; d->m_barDelegateDirty = true; emit barDelegateChanged(); emit update(); } // Select all the elements in the series void QBarSeries::selectAll() { Q_D(QBarSeries); for (auto s : d->m_barSets) { s->selectAllBars(); } } // Deselect all the elements in the series void QBarSeries::deselectAll() { Q_D(QBarSeries); for (auto s : d->m_barSets) { s->deselectAllBars(); } } void QBarSeries::componentComplete() { for (auto *child : children()) { if (auto bs = qobject_cast(child)) { append(bs); qCDebug(lcSeries2D) << "append barset" << bs << "to barseries. barset values:" << bs->values(); } } qCDebug(lcEvents2D) << "QBarSeries::componentComplete."; QAbstractSeries::componentComplete(); } void QBarSeries::handleSetValueChange(qsizetype index) { QBarSet *set = qobject_cast(sender()); if (set) emit setValueChanged(index, set); emit update(); } void QBarSeries::handleSetValueAdd(qsizetype index, qsizetype count) { QBarSet *set = qobject_cast(sender()); if (set) emit setValueAdded(index, count, set); emit update(); } void QBarSeries::handleSetValueRemove(qsizetype index, qsizetype count) { QBarSet *set = qobject_cast(sender()); if (set) emit setValueRemoved(index, count, set); emit update(); } bool QBarSeries::barDelegateDirty() const { Q_D(const QBarSeries); return d->m_barDelegateDirty; } void QBarSeries::setBarDelegateDirty(bool dirty) { Q_D(QBarSeries); d->m_barDelegateDirty = dirty; } QBarSeriesPrivate::QBarSeriesPrivate() : m_barWidth(0.5) // Default value is 50% of category width , m_labelsVisible(false) , m_visible(true) , m_blockBarUpdate(false) , m_labelsFormat() , m_labelsMargin(0) , m_labelsAngle(0) , m_labelsPrecision(6) , m_labelsDirty(true) , m_barDelegateDirty(false) { } qsizetype QBarSeriesPrivate::categoryCount() const { // No categories defined. return count of longest set. qsizetype count = 0; for (qsizetype i = 0; i < m_barSets.size(); i++) { if (m_barSets.at(i)->count() > count) count = m_barSets.at(i)->count(); } return count; } void QBarSeriesPrivate::setBarWidth(qreal width) { Q_Q(QBarSeries); width = std::clamp(width, 0.0, 1.0); if (!qFuzzyCompare(width, m_barWidth)) { m_barWidth = width; q->update(); } } qreal QBarSeriesPrivate::barWidth() const { return m_barWidth; } QBarSet *QBarSeriesPrivate::barsetAt(qsizetype index) { return m_barSets.at(index); } void QBarSeriesPrivate::setVisible(bool visible) { Q_Q(QBarSeries); m_visible = visible; emit q->visibleChanged(); } void QBarSeriesPrivate::setLabelsVisible(bool visible) { m_labelsVisible = visible; } qreal QBarSeriesPrivate::min() { if (m_barSets.size() <= 0) return 0; qreal min = INT_MAX; for (int i = 0; i < m_barSets.size(); i++) { qsizetype categoryCount = m_barSets.at(i)->count(); for (qsizetype j = 0; j < categoryCount; j++) { qreal temp = m_barSets.at(i)->at(j); if (temp < min) min = temp; } } return min; } qreal QBarSeriesPrivate::max() { if (m_barSets.size() <= 0) return 0; qreal max = INT_MIN; for (int i = 0; i < m_barSets.size(); i++) { qsizetype categoryCount = m_barSets.at(i)->count(); for (qsizetype j = 0; j < categoryCount; j++) { qreal temp = m_barSets.at(i)->at(j); if (temp > max) max = temp; } } return max; } qreal QBarSeriesPrivate::valueAt(int set, int category) { if ((set < 0) || (set >= m_barSets.size())) return 0; // No set, no value. else if ((category < 0) || (category >= m_barSets.at(set)->count())) return 0; // No category, no value. return m_barSets.at(set)->at(category); } qreal QBarSeriesPrivate::percentageAt(int set, int category) { if ((set < 0) || (set >= m_barSets.size())) return 0; // No set, no value. else if ((category < 0) || (category >= m_barSets.at(set)->count())) return 0; // No category, no value. qreal value = m_barSets.at(set)->at(category); qreal sum = categorySum(category); if (qFuzzyCompare(sum, 0)) return 0; return value / sum; } qreal QBarSeriesPrivate::categorySum(qsizetype category) { qreal sum(0); qsizetype count = m_barSets.size(); // Count sets for (qsizetype set = 0; set < count; set++) { if (category < m_barSets.at(set)->count()) sum += m_barSets.at(set)->at(category); } return sum; } qreal QBarSeriesPrivate::absoluteCategorySum(int category) { qreal sum(0); qsizetype count = m_barSets.size(); // Count sets for (qsizetype set = 0; set < count; set++) { if (category < m_barSets.at(set)->count()) sum += qAbs(m_barSets.at(set)->at(category)); } return sum; } qreal QBarSeriesPrivate::maxCategorySum() { qreal max = INT_MIN; qsizetype count = categoryCount(); for (qsizetype i = 0; i < count; i++) { qreal sum = categorySum(i); if (sum > max) max = sum; } return max; } qreal QBarSeriesPrivate::minX() { if (m_barSets.size() <= 0) return 0; qreal min = INT_MAX; for (int i = 0; i < m_barSets.size(); i++) { qsizetype categoryCount = m_barSets.at(i)->count(); for (qsizetype j = 0; j < categoryCount; j++) { qreal temp = m_barSets.at(i)->d_func()->m_values.at(j).x(); if (temp < min) min = temp; } } return min; } qreal QBarSeriesPrivate::maxX() { if (m_barSets.size() <= 0) return 0; qreal max = INT_MIN; for (int i = 0; i < m_barSets.size(); i++) { qsizetype categoryCount = m_barSets.at(i)->count(); for (qsizetype j = 0; j < categoryCount; j++) { qreal temp = m_barSets.at(i)->d_func()->m_values.at(j).x(); if (temp > max) max = temp; } } return max; } qreal QBarSeriesPrivate::categoryTop(qsizetype category) { // Returns top (sum of all positive values) of category. // Returns 0, if all values are negative qreal top(0); qsizetype count = m_barSets.size(); for (qsizetype set = 0; set < count; set++) { if (category < m_barSets.at(set)->count()) { qreal temp = m_barSets.at(set)->at(category); if (temp > 0) { top += temp; } } } return top; } qreal QBarSeriesPrivate::categoryBottom(qsizetype category) { // Returns bottom (sum of all negative values) of category // Returns 0, if all values are positive qreal bottom(0); qsizetype count = m_barSets.size(); for (qsizetype set = 0; set < count; set++) { if (category < m_barSets.at(set)->count()) { qreal temp = m_barSets.at(set)->at(category); if (temp < 0) { bottom += temp; } } } return bottom; } qreal QBarSeriesPrivate::top() { // Returns top of all categories qreal top(0); qsizetype count = categoryCount(); for (qsizetype i = 0; i < count; i++) { qreal temp = categoryTop(i); if (temp > top) top = temp; } return top; } qreal QBarSeriesPrivate::bottom() { // Returns bottom of all categories qreal bottom(0); qsizetype count = categoryCount(); for (qsizetype i = 0; i < count; i++) { qreal temp = categoryBottom(i); if (temp < bottom) bottom = temp; } return bottom; } bool QBarSeriesPrivate::blockBarUpdate() { return m_blockBarUpdate; } bool QBarSeriesPrivate::append(QBarSet *set) { if ((m_barSets.contains(set)) || (set == 0)) return false; // Fail if set is already in list or set is null. m_barSets.append(set); Q_Q(QBarSeries); QObject::connect(set, &QBarSet::updatedBars, q, &QBarSeries::updatedBars); QObject::connect(set, &QBarSet::valueChanged, q, &QBarSeries::handleSetValueChange); QObject::connect(set, &QBarSet::valueAdded, q, &QBarSeries::handleSetValueAdd); QObject::connect(set, &QBarSet::valueRemoved, q, &QBarSeries::handleSetValueRemove); QObject::connect(set, &QBarSet::selectedBarsChanged, q, &QBarSeries::updatedBars); return true; } bool QBarSeriesPrivate::remove(QBarSet *set) { if (!m_barSets.contains(set)) return false; // Fail if set is not in list m_barSets.removeOne(set); Q_Q(QBarSeries); QObject::disconnect(set, &QBarSet::updatedBars, q, &QBarSeries::updatedBars); QObject::disconnect(set, &QBarSet::valueChanged, q, &QBarSeries::handleSetValueChange); QObject::disconnect(set, &QBarSet::valueAdded, q, &QBarSeries::handleSetValueAdd); QObject::disconnect(set, &QBarSet::valueRemoved, q, &QBarSeries::handleSetValueRemove); QObject::disconnect(set, &QBarSet::selectedBarsChanged, q, &QBarSeries::updatedBars); return true; } bool QBarSeriesPrivate::append(const QList &sets) { for (auto *set : sets) { if ((set == 0) || (m_barSets.contains(set))) return false; // Fail if any of the sets is null or is already appended. if (sets.count(set) != 1) return false; // Also fail if same set is more than once in given list. } Q_Q(QBarSeries); for (auto *set : sets) { m_barSets.append(set); QObject::connect(set, &QBarSet::updatedBars, q, &QBarSeries::updatedBars); QObject::connect(set, &QBarSet::valueChanged, q, &QBarSeries::handleSetValueChange); QObject::connect(set, &QBarSet::valueAdded, q, &QBarSeries::handleSetValueAdd); QObject::connect(set, &QBarSet::valueRemoved, q, &QBarSeries::handleSetValueRemove); QObject::connect(set, &QBarSet::selectedBarsChanged, q, &QBarSeries::updatedBars); } return true; } bool QBarSeriesPrivate::remove(const QList &sets) { if (sets.size() == 0) return false; for (QBarSet *set : sets) { if ((set == 0) || (!m_barSets.contains(set))) return false; // Fail if any of the sets is null or is not in series if (sets.count(set) != 1) return false; // Also fail if same set is more than once in given list. } Q_Q(QBarSeries); for (QBarSet *set : sets) { m_barSets.removeOne(set); QObject::disconnect(set, &QBarSet::updatedBars, q, &QBarSeries::updatedBars); QObject::disconnect(set, &QBarSet::valueChanged, q, &QBarSeries::handleSetValueChange); QObject::disconnect(set, &QBarSet::valueAdded, q, &QBarSeries::handleSetValueAdd); QObject::disconnect(set, &QBarSet::valueRemoved, q, &QBarSeries::handleSetValueRemove); QObject::disconnect(set, &QBarSet::selectedBarsChanged, q, &QBarSeries::updatedBars); } return true; } bool QBarSeriesPrivate::insert(qsizetype index, QBarSet *set) { if ((m_barSets.contains(set)) || (set == 0)) return false; // Fail if set is already in list or set is null. m_barSets.insert(index, set); Q_Q(QBarSeries); QObject::connect(set, &QBarSet::updatedBars, q, &QBarSeries::updatedBars); QObject::connect(set, &QBarSet::valueChanged, q, &QBarSeries::handleSetValueChange); QObject::connect(set, &QBarSet::valueAdded, q, &QBarSeries::handleSetValueAdd); QObject::connect(set, &QBarSet::valueRemoved, q, &QBarSeries::handleSetValueRemove); QObject::disconnect(set, &QBarSet::selectedBarsChanged, q, &QBarSeries::updatedBars); return true; } QT_END_NAMESPACE #include "moc_qbarseries.cpp"