blob: 72754ac8691c50b527f84e6af54c421818b82eca [file] [log] [blame]
/****************************************************************************
**
** 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