// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "qvalue3daxis_p.h" #include "qvalue3daxisformatter_p.h" QT_BEGIN_NAMESPACE /*! * \class QValue3DAxis * \inmodule QtGraphs * \ingroup graphs_3D * \brief The QValue3DAxis class manipulates an axis of a graph. * * A value axis can be given a range of values and segment and subsegment * counts to divide the range into. * * Labels are drawn between each segment, and grid lines are drawn between each * segment and each subsegment. \note If visible, there will always be at least * two grid lines and labels indicating the minimum and maximum values of * the range, as there is always at least one segment. */ /*! * \qmltype Value3DAxis * \inqmlmodule QtGraphs * \ingroup graphs_qml_3D * \nativetype QValue3DAxis * \inherits Abstract3DAxis * \brief Manipulates an axis of a graph. * * This type provides an axis that can be given a range of values and segment * and subsegment counts to divide the range into. */ /*! * \qmlproperty qsizetype Value3DAxis::segmentCount * * The number of segments on the axis. This indicates how many labels are drawn. * The number of grid lines to be drawn is calculated with the following * formula: \c {segments * subsegments + 1}. The preset default is \c 5. The * value cannot be below \c 1. */ /*! * \qmlproperty qsizetype Value3DAxis::subSegmentCount * * The number of subsegments inside each segment on the axis. Grid lines are * drawn between each subsegment, in addition to each segment. The preset * default is \c 1. The value cannot be below \c 1. */ /*! * \qmlproperty string Value3DAxis::labelFormat * * The label format to be used for the labels on this axis. * * The format string supports the following conversion specifiers, length * modifiers, and flags provided by \c printf() in the standard C++ library: * d, i, o, x, X, f, F, e, E, g, G, c. * * If GraphsItem3D::locale is anything else than \c{"C"}, the supported * specifiers are limited to: d, e, E, f, g, G, and i. Also, only the precision * modifier is supported. The rest of the formatting comes from the default * \l [QML] Locale of the application. * * \sa GraphsItem3D::locale */ /*! * \qmlproperty Value3DAxisFormatter Value3DAxis::formatter * * The axis formatter to be used. Any existing formatter is deleted when a new * formatter is set. * */ /*! * \qmlproperty bool Value3DAxis::reversed * * If \c{true}, the axis will be rendered in reverse. That is, the positions of * the minimum and maximum values are swapped when the graph is rendered. This * property does not affect the actual minimum and maximum values of the axis. */ /*! \qmlsignal Value3DAxis::segmentCountChanged(qsizetype count) This signal is emitted when segmentCount changes to \a count. */ /*! \qmlsignal Value3DAxis::subSegmentCountChanged(qsizetype count) This signal is emitted when subSegmentCount changes to \a count. */ /*! \qmlsignal Value3DAxis::labelFormatChanged(string format) This signal is emitted when labelFormat changes to \a format. */ /*! \qmlsignal Value3DAxis::formatterChanged(Value3DAxisFormatter formatter) This signal is emitted when \l formatter changes to \a formatter. */ /*! \qmlsignal Value3DAxis::reversedChanged(bool enable) This signal is emitted when \l reversed changes to \a enable. */ /*! * Constructs QValue3DAxis with the given \a parent. */ QValue3DAxis::QValue3DAxis(QObject *parent) : QAbstract3DAxis(*(new QValue3DAxisPrivate()), parent) { setFormatter(new QValue3DAxisFormatter); } /*! * Destroys QValue3DAxis. */ QValue3DAxis::~QValue3DAxis() {} /*! * \property QValue3DAxis::segmentCount * * \brief The number of segments on the axis. * * This indicates how many labels are drawn. The number * of grid lines to be drawn is calculated with formula: \c {segments * * subsegments + 1}. The preset default is \c 5. The value cannot be below \c 1. * * \sa setSubSegmentCount() */ void QValue3DAxis::setSegmentCount(qsizetype count) { Q_D(QValue3DAxis); if (count <= 0) { qWarning( "Warning: Illegal segment count automatically adjusted to a legal one: %" PRIdQSIZETYPE " --> 1", count); count = 1; } if (d->m_segmentCount != count) { d->m_segmentCount = count; d->emitLabelsChanged(); emit segmentCountChanged(count); } } qsizetype QValue3DAxis::segmentCount() const { Q_D(const QValue3DAxis); return d->m_segmentCount; } /*! * \property QValue3DAxis::subSegmentCount * * \brief The number of subsegments inside each segment on the axis. * * Grid lines are drawn between * each subsegment, in addition to each segment. * The preset default is \c 1. The value cannot be below \c 1. * * \sa setSegmentCount() */ void QValue3DAxis::setSubSegmentCount(qsizetype count) { Q_D(QValue3DAxis); if (count <= 0) { qWarning("Warning: Illegal subsegment count automatically adjusted to a legal one: " "%" PRIdQSIZETYPE " -> 1", count); count = 1; } if (d->m_subSegmentCount != count) { d->m_subSegmentCount = count; emit subSegmentCountChanged(count); } } qsizetype QValue3DAxis::subSegmentCount() const { Q_D(const QValue3DAxis); return d->m_subSegmentCount; } /*! * \property QValue3DAxis::labelFormat * * \brief The label format to be used for the labels on this axis. * * The format string supports the following conversion specifiers, length * modifiers, and flags provided by \c printf() in the standard C++ library: * d, i, o, x, X, f, F, e, E, g, G, c. * * If Q3DGraphsWidgetItem::locale is anything else than \c{"C"}, the supported * specifiers are limited to: d, e, E, f, g, G, and i. Also, only the precision * modifier is supported. The rest of the formatting comes from the default * QLocale of the application. * * Usage example: * * \c {axis->setLabelFormat("%.2f mm");} * * \sa formatter, Q3DGraphsWidgetItem::locale */ void QValue3DAxis::setLabelFormat(const QString &format) { Q_D(QValue3DAxis); if (d->m_labelFormat != format) { d->m_labelFormat = format; d->emitLabelsChanged(); emit labelFormatChanged(format); } } QString QValue3DAxis::labelFormat() const { Q_D(const QValue3DAxis); return d->m_labelFormat; } /*! * \property QValue3DAxis::formatter * * \brief The axis formatter to be used. * * Any existing formatter is deleted when a new formatter * is set. */ void QValue3DAxis::setFormatter(QValue3DAxisFormatter *formatter) { Q_ASSERT(formatter); Q_D(QValue3DAxis); if (formatter != d->m_formatter) { delete d->m_formatter; d->m_formatter = formatter; formatter->setParent(this); formatter->setAxis(this); emit formatterChanged(formatter); emit formatterDirty(); } } QValue3DAxisFormatter *QValue3DAxis::formatter() const { Q_D(const QValue3DAxis); return d->m_formatter; } /*! * \property QValue3DAxis::reversed * * \brief Whether the axis is rendered in reverse. * * If \c{true}, the axis will be rendered in reverse, which means the positions * of minimum and maximum values are swapped when the graph is rendered. This * property doesn't affect the actual minimum and maximum values of the axis. */ void QValue3DAxis::setReversed(bool enable) { Q_D(QValue3DAxis); if (d->m_reversed != enable) { d->m_reversed = enable; emit reversedChanged(enable); } } bool QValue3DAxis::reversed() const { Q_D(const QValue3DAxis); return d->m_reversed; } void QValue3DAxis::recalculate() { formatter()->d_func()->recalculate(); } qsizetype QValue3DAxis::gridSize() { return formatter()->gridPositions().size(); } qsizetype QValue3DAxis::subGridSize() { return formatter()->subGridPositions().size(); } float QValue3DAxis::gridPositionAt(qsizetype gridLine) { return formatter()->gridPositions().at(gridLine); } float QValue3DAxis::subGridPositionAt(qsizetype gridLine) { return formatter()->subGridPositions().at(gridLine); } float QValue3DAxis::labelPositionAt(qsizetype index) { return formatter()->labelPositions().at(index); } float QValue3DAxis::positionAt(float x) { return formatter()->positionAt(x); } QString QValue3DAxis::stringForValue(float x) { return formatter()->stringForValue(x, labelFormat()); } QValue3DAxisPrivate::QValue3DAxisPrivate() : QAbstract3DAxisPrivate(QAbstract3DAxis::AxisType::Value) , m_segmentCount(5) , m_subSegmentCount(1) , m_labelFormat(Utils::defaultLabelFormat()) , m_labelsDirty(true) , m_formatter(0) , m_reversed(false) {} QValue3DAxisPrivate::~QValue3DAxisPrivate() {} void QValue3DAxisPrivate::setRange(float min, float max, bool suppressWarnings) { bool dirty = (min != m_min || max != m_max); QAbstract3DAxisPrivate::setRange(min, max, suppressWarnings); if (dirty) emitLabelsChanged(); } void QValue3DAxisPrivate::setMin(float min) { bool dirty = (min != m_min); QAbstract3DAxisPrivate::setMin(min); if (dirty) emitLabelsChanged(); } void QValue3DAxisPrivate::setMax(float max) { bool dirty = (max != m_max); QAbstract3DAxisPrivate::setMax(max); if (dirty) emitLabelsChanged(); } void QValue3DAxisPrivate::emitLabelsChanged() { Q_Q(QValue3DAxis); m_labelsDirty = true; emit q->labelsChanged(); } void QValue3DAxisPrivate::emitFormatterDirty() { Q_Q(QValue3DAxis); m_labelsDirty = true; emit q->formatterDirty(); } void QValue3DAxisPrivate::updateLabels() { if (!m_labelsDirty) return; m_labelsDirty = false; m_formatter->d_func()->recalculate(); m_labels = m_formatter->labelStrings(); } bool QValue3DAxisPrivate::allowZero() { return m_formatter->allowZero(); } bool QValue3DAxisPrivate::allowNegatives() { return m_formatter->allowNegatives(); } bool QValue3DAxisPrivate::allowMinMaxSame() { return false; } QT_END_NAMESPACE