/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Data Visualization module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 or (at your option) any later version ** approved by the KDE Free Qt Foundation. The licenses are as published by ** the Free Software Foundation and appearing in the file LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qabstract3daxis_p.h" QT_BEGIN_NAMESPACE_DATAVISUALIZATION /*! * \class QAbstract3DAxis * \inmodule QtDataVisualization * \brief The QAbstract3DAxis class is a base class for the axes of a graph. * \since QtDataVisualization 1.0 * * This class specifies the enumerations, properties, and functions shared by * graph axes. It should not be used directly, but one of its subclasses should * be used instead. * * \sa QCategory3DAxis, QValue3DAxis */ /*! * \qmltype AbstractAxis3D * \inqmlmodule QtDataVisualization * \since QtDataVisualization 1.0 * \ingroup datavisualization_qml * \instantiates QAbstract3DAxis * \brief A base type for the axes of a graph. * * This type is uncreatable, but contains properties that are exposed via subtypes. * * For AbstractAxis3D enums, see \l QAbstract3DAxis::AxisOrientation and * \l{QAbstract3DAxis::AxisType}. */ /*! * \qmlproperty string AbstractAxis3D::title * The title for the axis. * * \sa titleVisible, titleFixed */ /*! * \qmlproperty list AbstractAxis3D::labels * The labels for the axis. * \note Setting this property for ValueAxis3D does nothing, as it generates labels automatically. */ /*! * \qmlproperty AbstractAxis3D.AxisOrientation AbstractAxis3D::orientation * The orientation of the axis. */ /*! * \qmlproperty AbstractAxis3D.AxisType AbstractAxis3D::type * The type of the axis. */ /*! * \qmlproperty real AbstractAxis3D::min * * The minimum value on the axis. * When setting this property, the maximum value is adjusted if necessary, to * ensure that the range remains valid. */ /*! * \qmlproperty real AbstractAxis3D::max * * The maximum value on the axis. * When setting this property, the minimum value is adjusted if necessary, to * ensure that the range remains valid. */ /*! * \qmlproperty bool AbstractAxis3D::autoAdjustRange * * Defines whether the axis will automatically adjust the range so that all data fits in it. */ /*! * \qmlproperty real AbstractAxis3D::labelAutoRotation * * The maximum angle the labels can autorotate when the camera angle changes. * The angle can be between 0 and 90, inclusive. The default value is 0. * If the value is 0, axis labels do not automatically rotate. * If the value is greater than zero, labels attempt to orient themselves toward the camera, up to * the specified angle. */ /*! * \qmlproperty bool AbstractAxis3D::titleVisible * * Defines whether the axis title is visible in the primary graph view. * * The default value is \c{false}. * * \sa title, titleFixed */ /*! * \qmlproperty bool AbstractAxis3D::titleFixed * * The rotation of axis titles. * * If \c{true}, axis titles in the primary graph view will be rotated towards the camera similarly * to the axis labels. * If \c{false}, axis titles are only rotated around their axis but are not otherwise oriented * towards the camera. * This property does not have any effect if the labelAutoRotation property * value is zero. * Default value is \c{true}. * * \sa labelAutoRotation, title, titleVisible */ /*! * \enum QAbstract3DAxis::AxisOrientation * * The orientation of the axis object. * * \value AxisOrientationNone * \value AxisOrientationX * \value AxisOrientationY * \value AxisOrientationZ */ /*! * \enum QAbstract3DAxis::AxisType * * The type of the axis object. * * \value AxisTypeNone * \value AxisTypeCategory * \value AxisTypeValue */ /*! * \internal */ QAbstract3DAxis::QAbstract3DAxis(QAbstract3DAxisPrivate *d, QObject *parent) : QObject(parent), d_ptr(d) { } /*! * Destroys QAbstract3DAxis. */ QAbstract3DAxis::~QAbstract3DAxis() { } /*! * \property QAbstract3DAxis::orientation * * \brief The orientation of the axis. * * The value is one of AxisOrientation values. */ QAbstract3DAxis::AxisOrientation QAbstract3DAxis::orientation() const { return d_ptr->m_orientation; } /*! * \property QAbstract3DAxis::type * * \brief The type of the axis. * * The value is one of AxisType values. */ QAbstract3DAxis::AxisType QAbstract3DAxis::type() const { return d_ptr->m_type; } /*! * \property QAbstract3DAxis::title * * \brief The title for the axis. * * \sa titleVisible, titleFixed */ void QAbstract3DAxis::setTitle(const QString &title) { if (d_ptr->m_title != title) { d_ptr->m_title = title; emit titleChanged(title); } } QString QAbstract3DAxis::title() const { return d_ptr->m_title; } /*! * \property QAbstract3DAxis::labels * * \brief The labels for the axis. * \note Setting this property for QValue3DAxis does nothing, as it generates labels automatically. */ void QAbstract3DAxis::setLabels(const QStringList &labels) { Q_UNUSED(labels); } QStringList QAbstract3DAxis::labels() const { d_ptr->updateLabels(); return d_ptr->m_labels; } /*! * Sets the value range of the axis from \a min to \a max. * When setting the range, the maximum value is adjusted if necessary, to ensure * that the range remains valid. * \note For QCategory3DAxis, specifies the index range of rows or columns to * show. */ void QAbstract3DAxis::setRange(float min, float max) { d_ptr->setRange(min, max); setAutoAdjustRange(false); } /*! * \property QAbstract3DAxis::labelAutoRotation * * \brief The maximum angle the labels can autorotate when the camera angle changes. * * The angle can be between 0 and 90, inclusive. The default value is 0. * If the value is 0, axis labels do not automatically rotate. * If the value is greater than zero, labels attempt to orient themselves toward the camera, up to * the specified angle. */ void QAbstract3DAxis::setLabelAutoRotation(float angle) { if (angle < 0.0f) angle = 0.0f; if (angle > 90.0f) angle = 90.0f; if (d_ptr->m_labelAutoRotation != angle) { d_ptr->m_labelAutoRotation = angle; emit labelAutoRotationChanged(angle); } } float QAbstract3DAxis::labelAutoRotation() const { return d_ptr->m_labelAutoRotation; } /*! * \property QAbstract3DAxis::titleVisible * * \brief Whether the axis title is visible in the primary graph view. * * The default value is \c{false}. * * \sa title, titleFixed */ void QAbstract3DAxis::setTitleVisible(bool visible) { if (d_ptr->m_titleVisible != visible) { d_ptr->m_titleVisible = visible; emit titleVisibilityChanged(visible); } } bool QAbstract3DAxis::isTitleVisible() const { return d_ptr->m_titleVisible; } /*! * \property QAbstract3DAxis::titleFixed * * \brief The rotation of the axis titles. * * If \c{true}, axis titles in the primary graph view will be rotated towards the camera similarly * to the axis labels. * If \c{false}, axis titles are only rotated around their axis but are not otherwise oriented * towards the camera. * This property does not have any effect if the labelAutoRotation property * value is zero. * Default value is \c{true}. * * \sa labelAutoRotation, title, titleVisible */ void QAbstract3DAxis::setTitleFixed(bool fixed) { if (d_ptr->m_titleFixed != fixed) { d_ptr->m_titleFixed = fixed; emit titleFixedChanged(fixed); } } bool QAbstract3DAxis::isTitleFixed() const { return d_ptr->m_titleFixed; } /*! * \property QAbstract3DAxis::min * * \brief The minimum value on the axis. * * When setting this property, the maximum value is adjusted if necessary, to * ensure that the range remains valid. * \note For QCategory3DAxis, specifies the index of the first row or column to * show. */ void QAbstract3DAxis::setMin(float min) { d_ptr->setMin(min); setAutoAdjustRange(false); } /*! * \property QAbstract3DAxis::max * * \brief The maximum value on the axis. * * When setting this property, the minimum value is adjusted if necessary, to * ensure that the range remains valid. * \note For QCategory3DAxis, specifies the index of the last row or column to * show. */ void QAbstract3DAxis::setMax(float max) { d_ptr->setMax(max); setAutoAdjustRange(false); } float QAbstract3DAxis::min() const { return d_ptr->m_min; } float QAbstract3DAxis::max() const { return d_ptr->m_max; } /*! * \property QAbstract3DAxis::autoAdjustRange * * \brief Whether the axis will automatically adjust the range so that all data fits in it. * * \sa setRange(), setMin(), setMax() */ void QAbstract3DAxis::setAutoAdjustRange(bool autoAdjust) { if (d_ptr->m_autoAdjust != autoAdjust) { d_ptr->m_autoAdjust = autoAdjust; emit autoAdjustRangeChanged(autoAdjust); } } bool QAbstract3DAxis::isAutoAdjustRange() const { return d_ptr->m_autoAdjust; } /*! * \fn QAbstract3DAxis::rangeChanged(float min, float max) * * Emits the minimum and maximum values of the range, \a min and \a max, when * the range changes. */ // QAbstract3DAxisPrivate QAbstract3DAxisPrivate::QAbstract3DAxisPrivate(QAbstract3DAxis *q, QAbstract3DAxis::AxisType type) : QObject(0), q_ptr(q), m_orientation(QAbstract3DAxis::AxisOrientationNone), m_type(type), m_isDefaultAxis(false), m_min(0.0f), m_max(10.0f), m_autoAdjust(true), m_labelAutoRotation(0.0f), m_titleVisible(false), m_titleFixed(true) { } QAbstract3DAxisPrivate::~QAbstract3DAxisPrivate() { } void QAbstract3DAxisPrivate::setOrientation(QAbstract3DAxis::AxisOrientation orientation) { if (m_orientation == QAbstract3DAxis::AxisOrientationNone) { m_orientation = orientation; emit q_ptr->orientationChanged(orientation); } else { Q_ASSERT("Attempted to reset axis orientation."); } } void QAbstract3DAxisPrivate::updateLabels() { // Default implementation does nothing } void QAbstract3DAxisPrivate::setRange(float min, float max, bool suppressWarnings) { bool adjusted = false; if (!allowNegatives()) { if (allowZero()) { if (min < 0.0f) { min = 0.0f; adjusted = true; } if (max < 0.0f) { max = 0.0f; adjusted = true; } } else { if (min <= 0.0f) { min = 1.0f; adjusted = true; } if (max <= 0.0f) { max = 1.0f; adjusted = true; } } } // If min >= max, we adjust ranges so that // m_max becomes (min + 1.0f) // as axes need some kind of valid range. bool minDirty = false; bool maxDirty = false; if (m_min != min) { m_min = min; minDirty = true; } if (m_max != max || min > max || (!allowMinMaxSame() && min == max)) { if (min > max || (!allowMinMaxSame() && min == max)) { m_max = min + 1.0f; adjusted = true; } else { m_max = max; } maxDirty = true; } if (minDirty || maxDirty) { if (adjusted && !suppressWarnings) { qWarning() << "Warning: Tried to set invalid range for axis." " Range automatically adjusted to a valid one:" << min << "-" << max << "-->" << m_min << "-" << m_max; } emit q_ptr->rangeChanged(m_min, m_max); } if (minDirty) emit q_ptr->minChanged(m_min); if (maxDirty) emit q_ptr->maxChanged(m_max); } void QAbstract3DAxisPrivate::setMin(float min) { if (!allowNegatives()) { if (allowZero()) { if (min < 0.0f) { min = 0.0f; qWarning() << "Warning: Tried to set negative minimum for an axis that only" "supports positive values and zero:" << min; } } else { if (min <= 0.0f) { min = 1.0f; qWarning() << "Warning: Tried to set negative or zero minimum for an axis that only" "supports positive values:" << min; } } } if (m_min != min) { bool maxChanged = false; if (min > m_max || (!allowMinMaxSame() && min == m_max)) { float oldMax = m_max; m_max = min + 1.0f; qWarning() << "Warning: Tried to set minimum to equal or larger than maximum for" " value axis. Maximum automatically adjusted to a valid one:" << oldMax << "-->" << m_max; maxChanged = true; } m_min = min; emit q_ptr->rangeChanged(m_min, m_max); emit q_ptr->minChanged(m_min); if (maxChanged) emit q_ptr->maxChanged(m_max); } } void QAbstract3DAxisPrivate::setMax(float max) { if (!allowNegatives()) { if (allowZero()) { if (max < 0.0f) { max = 0.0f; qWarning() << "Warning: Tried to set negative maximum for an axis that only" "supports positive values and zero:" << max; } } else { if (max <= 0.0f) { max = 1.0f; qWarning() << "Warning: Tried to set negative or zero maximum for an axis that only" "supports positive values:" << max; } } } if (m_max != max) { bool minChanged = false; if (m_min > max || (!allowMinMaxSame() && m_min == max)) { float oldMin = m_min; m_min = max - 1.0f; if (!allowNegatives() && m_min < 0.0f) { if (allowZero()) m_min = 0.0f; else m_min = max / 2.0f; // Need some positive value smaller than max if (!allowMinMaxSame() && max == 0.0f) { m_min = oldMin; qWarning() << "Unable to set maximum value to zero."; return; } } qWarning() << "Warning: Tried to set maximum to equal or smaller than minimum for" " value axis. Minimum automatically adjusted to a valid one:" << oldMin << "-->" << m_min; minChanged = true; } m_max = max; emit q_ptr->rangeChanged(m_min, m_max); emit q_ptr->maxChanged(m_max); if (minChanged) emit q_ptr->minChanged(m_min); } } QT_END_NAMESPACE_DATAVISUALIZATION