diff options
Diffstat (limited to 'src/charts/axis')
70 files changed, 9968 insertions, 0 deletions
diff --git a/src/charts/axis/axis.pri b/src/charts/axis/axis.pri new file mode 100644 index 00000000..6f706aac --- /dev/null +++ b/src/charts/axis/axis.pri @@ -0,0 +1,108 @@ +#Subdirectiores are defined here, because qt creator doesn't handle nested include(foo.pri) chains very well. + +INCLUDEPATH += $$PWD \ + $$PWD/valueaxis \ + $$PWD/barcategoryaxis \ + $$PWD/categoryaxis \ + $$PWD/logvalueaxis + +DEPENDPATH += $$PWD \ + $$PWD/valueaxis \ + $$PWD/barcategoryaxis \ + $$PWD/categoryaxis \ + $$PWD/logvalueaxis + +SOURCES += \ + $$PWD/chartaxiselement.cpp \ + $$PWD/cartesianchartaxis.cpp \ + $$PWD/qabstractaxis.cpp \ + $$PWD/verticalaxis.cpp \ + $$PWD/horizontalaxis.cpp \ + $$PWD/valueaxis/chartvalueaxisx.cpp \ + $$PWD/valueaxis/chartvalueaxisy.cpp \ + $$PWD/valueaxis/qvalueaxis.cpp \ + $$PWD/barcategoryaxis/chartbarcategoryaxisx.cpp \ + $$PWD/barcategoryaxis/chartbarcategoryaxisy.cpp \ + $$PWD/barcategoryaxis/qbarcategoryaxis.cpp \ + $$PWD/categoryaxis/chartcategoryaxisx.cpp \ + $$PWD/categoryaxis/chartcategoryaxisy.cpp \ + $$PWD/categoryaxis/qcategoryaxis.cpp \ + $$PWD/logvalueaxis/chartlogvalueaxisx.cpp \ + $$PWD/logvalueaxis/chartlogvalueaxisy.cpp \ + $$PWD/logvalueaxis/qlogvalueaxis.cpp + +PRIVATE_HEADERS += \ + $$PWD/chartaxiselement_p.h \ + $$PWD/cartesianchartaxis_p.h \ + $$PWD/qabstractaxis_p.h \ + $$PWD/verticalaxis_p.h \ + $$PWD/horizontalaxis_p.h \ + $$PWD/linearrowitem_p.h \ + $$PWD/valueaxis/chartvalueaxisx_p.h \ + $$PWD/valueaxis/chartvalueaxisy_p.h \ + $$PWD/valueaxis/qvalueaxis_p.h \ + $$PWD/barcategoryaxis/chartbarcategoryaxisx_p.h \ + $$PWD/barcategoryaxis/chartbarcategoryaxisy_p.h \ + $$PWD/barcategoryaxis/qbarcategoryaxis_p.h \ + $$PWD/categoryaxis/chartcategoryaxisx_p.h \ + $$PWD/categoryaxis/chartcategoryaxisy_p.h \ + $$PWD/categoryaxis/qcategoryaxis_p.h \ + $$PWD/logvalueaxis/chartlogvalueaxisx_p.h \ + $$PWD/logvalueaxis/chartlogvalueaxisy_p.h \ + $$PWD/logvalueaxis/qlogvalueaxis_p.h + +PUBLIC_HEADERS += \ + $$PWD/qabstractaxis.h \ + $$PWD/valueaxis/qvalueaxis.h \ + $$PWD/barcategoryaxis/qbarcategoryaxis.h \ + $$PWD/categoryaxis/qcategoryaxis.h \ + $$PWD/logvalueaxis/qlogvalueaxis.h \ + +# polar +SOURCES += \ + $$PWD/polarchartaxis.cpp \ + $$PWD/polarchartaxisangular.cpp \ + $$PWD/polarchartaxisradial.cpp \ + $$PWD/valueaxis/polarchartvalueaxisangular.cpp \ + $$PWD/valueaxis/polarchartvalueaxisradial.cpp \ + $$PWD/logvalueaxis/polarchartlogvalueaxisangular.cpp \ + $$PWD/logvalueaxis/polarchartlogvalueaxisradial.cpp \ + $$PWD/categoryaxis/polarchartcategoryaxisangular.cpp \ + $$PWD/categoryaxis/polarchartcategoryaxisradial.cpp + +PRIVATE_HEADERS += \ + $$PWD/polarchartaxis_p.h \ + $$PWD/polarchartaxisangular_p.h \ + $$PWD/polarchartaxisradial_p.h \ + $$PWD/valueaxis/polarchartvalueaxisangular_p.h \ + $$PWD/valueaxis/polarchartvalueaxisradial_p.h \ + $$PWD/logvalueaxis/polarchartlogvalueaxisangular_p.h \ + $$PWD/logvalueaxis/polarchartlogvalueaxisradial_p.h \ + $$PWD/categoryaxis/polarchartcategoryaxisangular_p.h \ + $$PWD/categoryaxis/polarchartcategoryaxisradial_p.h + +!linux-arm*: { +INCLUDEPATH += \ + $$PWD/datetimeaxis + +DEPENDPATH += \ + $$PWD/datetimeaxis + +SOURCES += \ + $$PWD/datetimeaxis/chartdatetimeaxisx.cpp \ + $$PWD/datetimeaxis/chartdatetimeaxisy.cpp \ + $$PWD/datetimeaxis/qdatetimeaxis.cpp \ + $$PWD/datetimeaxis/polarchartdatetimeaxisangular.cpp \ + $$PWD/datetimeaxis/polarchartdatetimeaxisradial.cpp + +PRIVATE_HEADERS += \ + $$PWD/datetimeaxis/chartdatetimeaxisx_p.h \ + $$PWD/datetimeaxis/chartdatetimeaxisy_p.h \ + $$PWD/datetimeaxis/qdatetimeaxis_p.h \ + $$PWD/datetimeaxis/polarchartdatetimeaxisangular_p.h \ + $$PWD/datetimeaxis/polarchartdatetimeaxisradial_p.h + +PUBLIC_HEADERS += \ + $$PWD/datetimeaxis/qdatetimeaxis.h +} + diff --git a/src/charts/axis/barcategoryaxis/chartbarcategoryaxisx.cpp b/src/charts/axis/barcategoryaxis/chartbarcategoryaxisx.cpp new file mode 100644 index 00000000..259cdaa9 --- /dev/null +++ b/src/charts/axis/barcategoryaxis/chartbarcategoryaxisx.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** + ** + ** Copyright (C) 2014 Digia Plc + ** All rights reserved. + ** For any questions to Digia, please use contact form at http://qt.digia.com + ** + ** This file is part of the Qt Enterprise Charts Add-on. + ** + ** $QT_BEGIN_LICENSE$ + ** Licensees holding valid Qt Enterprise licenses may use this file in + ** accordance with the Qt Enterprise License Agreement provided with the + ** Software or, alternatively, in accordance with the terms contained in + ** a written agreement between you and Digia. + ** + ** If you have questions regarding the use of this file, please use + ** contact form at http://qt.digia.com + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#include "chartbarcategoryaxisx_p.h" +#include "chartpresenter_p.h" +#include "qbarcategoryaxis_p.h" +#include "abstractchartlayout_p.h" +#include <QDebug> +#include <qmath.h> + +QT_CHARTS_BEGIN_NAMESPACE + +ChartBarCategoryAxisX::ChartBarCategoryAxisX(QBarCategoryAxis *axis, QGraphicsItem* item) + : HorizontalAxis(axis, item, true), + m_categoriesAxis(axis) +{ + QObject::connect(m_categoriesAxis,SIGNAL(categoriesChanged()),this, SLOT(handleCategoriesChanged())); + handleCategoriesChanged(); +} + +ChartBarCategoryAxisX::~ChartBarCategoryAxisX() +{ +} + +QVector<qreal> ChartBarCategoryAxisX::calculateLayout() const +{ + QVector<qreal> points; + const QRectF& gridRect = gridGeometry(); + qreal range = max() - min(); + const qreal delta = gridRect.width() / range; + + if (delta < 2) + return points; + + qreal adjustedMin = min() + 0.5; + qreal offset = (ceil(adjustedMin) - adjustedMin) * delta; + + int count = qFloor(range); + if (count < 1) + return points; + + points.resize(count + 2); + + for (int i = 0; i < count + 2; ++i) + points[i] = offset + (qreal(i) * delta) + gridRect.left(); + + return points; +} + +QStringList ChartBarCategoryAxisX::createCategoryLabels(const QVector<qreal>& layout) const +{ + QStringList result ; + const QRectF &gridRect = gridGeometry(); + qreal d = (max() - min()) / gridRect.width(); + + for (int i = 0; i < layout.count() - 1; ++i) { + qreal x = qFloor((((layout[i] + layout[i + 1]) / 2 - gridRect.left()) * d + min() + 0.5)); + if ((x < m_categoriesAxis->categories().count()) && (x >= 0)) { + result << m_categoriesAxis->categories().at(x); + } else { + // No label for x coordinate + result << QString(); + } + } + result << QString(); + return result; +} + + +void ChartBarCategoryAxisX::updateGeometry() +{ + const QVector<qreal>& layout = ChartAxisElement::layout(); + if (layout.isEmpty()) + return; + setLabels(createCategoryLabels(layout)); + HorizontalAxis::updateGeometry(); +} + +void ChartBarCategoryAxisX::handleCategoriesChanged() +{ + QGraphicsLayoutItem::updateGeometry(); + if(presenter()) presenter()->layout()->invalidate(); +} + +QSizeF ChartBarCategoryAxisX::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const +{ + Q_UNUSED(constraint) + + QSizeF sh; + QSizeF base = HorizontalAxis::sizeHint(which, constraint); + QStringList ticksList = m_categoriesAxis->categories(); + + qreal width = 0; // Width is irrelevant for X axes with interval labels + qreal height = 0; + + switch (which) { + case Qt::MinimumSize: { + QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), + QStringLiteral("..."), + axis()->labelsAngle()); + height = boundingRect.height() + labelPadding() + base.height() + 1.0; + sh = QSizeF(width, height); + break; + } + case Qt::PreferredSize:{ + qreal labelHeight = 0.0; + foreach (const QString& s, ticksList) { + QRectF rect = ChartPresenter::textBoundingRect(axis()->labelsFont(), s, axis()->labelsAngle()); + labelHeight = qMax(rect.height(), labelHeight); + } + height = labelHeight + labelPadding() + base.height() + 1.0; + sh = QSizeF(width, height); + break; + } + default: + break; + } + return sh; +} + +#include "moc_chartbarcategoryaxisx_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/barcategoryaxis/chartbarcategoryaxisx_p.h b/src/charts/axis/barcategoryaxis/chartbarcategoryaxisx_p.h new file mode 100644 index 00000000..177540e2 --- /dev/null +++ b/src/charts/axis/barcategoryaxis/chartbarcategoryaxisx_p.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef CHARTBARCATEGORYAXISX_H +#define CHARTBARCATEGORYAXISX_H + +#include "horizontalaxis_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class ChartPresenter; +class QBarCategoryAxis; + +class ChartBarCategoryAxisX : public HorizontalAxis +{ + Q_OBJECT +public: + ChartBarCategoryAxisX(QBarCategoryAxis *axis, QGraphicsItem* item = 0); + ~ChartBarCategoryAxisX(); + + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const; +protected: + QVector<qreal> calculateLayout() const; + void updateGeometry(); +private: + QStringList createCategoryLabels(const QVector<qreal>& layout) const; +public Q_SLOTS: + void handleCategoriesChanged(); + +private: + QBarCategoryAxis *m_categoriesAxis; +}; + +QT_CHARTS_END_NAMESPACE + +#endif /* CHARTBARCATEGORYAXISX_H */ diff --git a/src/charts/axis/barcategoryaxis/chartbarcategoryaxisy.cpp b/src/charts/axis/barcategoryaxis/chartbarcategoryaxisy.cpp new file mode 100644 index 00000000..126c7da3 --- /dev/null +++ b/src/charts/axis/barcategoryaxis/chartbarcategoryaxisy.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** + ** + ** Copyright (C) 2014 Digia Plc + ** All rights reserved. + ** For any questions to Digia, please use contact form at http://qt.digia.com + ** + ** This file is part of the Qt Enterprise Charts Add-on. + ** + ** $QT_BEGIN_LICENSE$ + ** Licensees holding valid Qt Enterprise licenses may use this file in + ** accordance with the Qt Enterprise License Agreement provided with the + ** Software or, alternatively, in accordance with the terms contained in + ** a written agreement between you and Digia. + ** + ** If you have questions regarding the use of this file, please use + ** contact form at http://qt.digia.com + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#include "chartbarcategoryaxisy_p.h" +#include "chartpresenter_p.h" +#include "qbarcategoryaxis_p.h" +#include "abstractchartlayout_p.h" +#include <qmath.h> +#include <QDebug> + +QT_CHARTS_BEGIN_NAMESPACE + +ChartBarCategoryAxisY::ChartBarCategoryAxisY(QBarCategoryAxis *axis, QGraphicsItem* item) + : VerticalAxis(axis, item, true), + m_categoriesAxis(axis) +{ + QObject::connect( m_categoriesAxis,SIGNAL(categoriesChanged()),this, SLOT(handleCategoriesChanged())); + handleCategoriesChanged(); +} + +ChartBarCategoryAxisY::~ChartBarCategoryAxisY() +{ +} + +QVector<qreal> ChartBarCategoryAxisY::calculateLayout() const +{ + QVector<qreal> points; + const QRectF& gridRect = gridGeometry(); + qreal range = max() - min(); + const qreal delta = gridRect.height() / range; + + if (delta < 2) + return points; + + qreal adjustedMin = min() + 0.5; + qreal offset = (ceil(adjustedMin) - adjustedMin) * delta; + + int count = qFloor(range); + if (count < 1) + return points; + + points.resize(count + 2); + + for (int i = 0; i < count + 2; ++i) + points[i] = gridRect.bottom() - (qreal(i) * delta) - offset; + + return points; +} + +QStringList ChartBarCategoryAxisY::createCategoryLabels(const QVector<qreal>& layout) const +{ + QStringList result; + const QRectF &gridRect = gridGeometry(); + qreal d = (max() - min()) / gridRect.height(); + + for (int i = 0; i < layout.count() - 1; ++i) { + qreal x = qFloor(((gridRect.height() - (layout[i + 1] + layout[i]) / 2 + gridRect.top()) * d + min() + 0.5)); + if ((x < m_categoriesAxis->categories().count()) && (x >= 0)) { + result << m_categoriesAxis->categories().at(x); + } else { + // No label for x coordinate + result << QString(); + } + } + result << QString(); + return result; +} + +void ChartBarCategoryAxisY::updateGeometry() +{ + const QVector<qreal>& layout = ChartAxisElement::layout(); + if (layout.isEmpty()) + return; + setLabels(createCategoryLabels(layout)); + VerticalAxis::updateGeometry(); +} + +void ChartBarCategoryAxisY::handleCategoriesChanged() +{ + QGraphicsLayoutItem::updateGeometry(); + if(presenter()) presenter()->layout()->invalidate(); +} + +QSizeF ChartBarCategoryAxisY::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const +{ + Q_UNUSED(constraint) + + QSizeF sh; + QSizeF base = VerticalAxis::sizeHint(which, constraint); + QStringList ticksList = m_categoriesAxis->categories(); + qreal width = 0; + qreal height = 0; // Height is irrelevant for Y axes with interval labels + + switch (which) { + case Qt::MinimumSize: { + QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), + QStringLiteral("..."), + axis()->labelsAngle()); + width = boundingRect.width() + labelPadding() + base.width() + 1.0; + if (base.width() > 0.0) + width += labelPadding(); + sh = QSizeF(width, height); + break; + } + case Qt::PreferredSize:{ + qreal labelWidth = 0.0; + foreach (const QString& s, ticksList) { + QRectF rect = ChartPresenter::textBoundingRect(axis()->labelsFont(), s, axis()->labelsAngle()); + labelWidth = qMax(rect.width(), labelWidth); + } + width = labelWidth + labelPadding() + base.width() + 1.0; + if (base.width() > 0.0) + width += labelPadding(); + sh = QSizeF(width, height); + break; + } + default: + break; + } + return sh; +} + +#include "moc_chartbarcategoryaxisy_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/barcategoryaxis/chartbarcategoryaxisy_p.h b/src/charts/axis/barcategoryaxis/chartbarcategoryaxisy_p.h new file mode 100644 index 00000000..82f2c505 --- /dev/null +++ b/src/charts/axis/barcategoryaxis/chartbarcategoryaxisy_p.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef CHARTBARCATEGORYAXISY_H +#define CHARTBARCATEGORYAXISY_H + +#include "verticalaxis_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QBarCategoryAxis; +class ChartPresenter; + +class ChartBarCategoryAxisY : public VerticalAxis +{ + Q_OBJECT +public: + ChartBarCategoryAxisY(QBarCategoryAxis *axis, QGraphicsItem* item = 0); + ~ChartBarCategoryAxisY(); + + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const; +protected: + QVector<qreal> calculateLayout() const; + void updateGeometry(); +private: + QStringList createCategoryLabels(const QVector<qreal>& layout) const; +public Q_SLOTS: + void handleCategoriesChanged(); +private: + QBarCategoryAxis *m_categoriesAxis; +}; + +QT_CHARTS_END_NAMESPACE + +#endif /* CHARTBARCATEGORYAXISY_H */ diff --git a/src/charts/axis/barcategoryaxis/qbarcategoryaxis.cpp b/src/charts/axis/barcategoryaxis/qbarcategoryaxis.cpp new file mode 100644 index 00000000..7818d6f6 --- /dev/null +++ b/src/charts/axis/barcategoryaxis/qbarcategoryaxis.cpp @@ -0,0 +1,620 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qbarcategoryaxis.h" +#include "qbarcategoryaxis_p.h" +#include "chartbarcategoryaxisx_p.h" +#include "chartbarcategoryaxisy_p.h" +#include "abstractdomain_p.h" +#include "qchart.h" +#include <qmath.h> + +QT_CHARTS_BEGIN_NAMESPACE +/*! + \class QBarCategoryAxis + \inmodule Qt Charts + \brief The QBarCategoryAxis class is used for manipulating chart's axis. + \mainclass + + QBarCategoryAxis can be setup to show axis line with tick marks, grid lines and shades. + Categories are drawn between ticks. Note that you can use this also with lineseries too. + See the \l {Line and BarChart Example} {Line and BarChart Example} to learn how to do that. + + Example code on how to use QBarCategoryAxis. + \code + QChartView *chartView = new QChartView; + QBarSeries *series = new QBarSeries; + // ... + chartView->chart()->addSeries(series); + chartView->chart()->createDefaultAxes(); + + QBarCategoryAxis *axisX = new QBarCategoryAxis; + QStringList categories; + categories << "Jan" << "Feb" << "Mar" << "Apr" << "May" << "Jun"; + axisX->append(categories); + axisX->setRange("Feb", "May"); + chartView->chart()->setAxisX(axisX, series); + \endcode +*/ + +/*! + \qmltype BarCategoryAxis + \instantiates QBarCategoryAxis + \inqmlmodule QtCharts + + \inherits AbstractAxis + + \brief The Axis element is used for manipulating chart's axes. + + Axis can be setup to show axis line with tick marks, grid lines and shades. + Categories are drawn between ticks. Note that you can use this also with lineseries too. + + To access BarCategoryAxis you can use ChartView API. For example: + \code + ChartView { + BarCategoryAxis { + id: categoryAxis + categories: ["Jan", "Feb", "Mar", "Apr", "May", "Jun" ] + } + // Add a few series... + } + \endcode +*/ + +/*! + \property QBarCategoryAxis::categories + Defines the categories of axis +*/ +/*! + \qmlproperty QStringList BarCategoryAxis::categories + Defines the categories of axis +*/ + +/*! + \property QBarCategoryAxis::min + Defines the minimum value on the axis. +*/ +/*! + \qmlproperty string BarCategoryAxis::min + Defines the minimum value on the axis. +*/ + +/*! + \property QBarCategoryAxis::max + Defines the maximum value on the axis. +*/ +/*! + \qmlproperty string BarCategoryAxis::max + Defines the maximum value on the axis. +*/ + +/*! + \property QBarCategoryAxis::count + The count of categories. +*/ +/*! + \qmlproperty int BarCategoryAxis::count + The count of categories. +*/ + +/*! + \fn void QBarCategoryAxis::categoriesChanged() + Axis emits signal when the categories of the axis have changed. +*/ + +/*! + \fn void QBarCategoryAxis::minChanged(const QString &min) + Axis emits signal when \a min of axis has changed. +*/ +/*! + \qmlsignal BarCategoryAxis::onMinChanged(const QString &min) + Axis emits signal when \a min of axis has changed. +*/ + +/*! + \fn void QBarCategoryAxis::maxChanged(const QString &max) + Axis emits signal when \a max of axis has changed. +*/ +/*! + \qmlsignal BarCategoryAxis::onMaxChanged(const QString &max) + Axis emits signal when \a max of axis has changed. +*/ + +/*! + \fn void QBarCategoryAxis::countChanged() + Axis emits signal when the count of categories has changed. +*/ +/*! + \qmlsignal BarCategoryAxis::onCountChanged() + Axis emits signal when the count of categories has changed. +*/ + +/*! + \fn void QBarCategoryAxis::rangeChanged(const QString &min, const QString &max) + Axis emits signal when \a min or \a max of axis has changed. +*/ + +/*! + \qmlmethod void BarCategoryAxis::clear() + Removes all categories. Sets the maximum and minimum of the axis's range to QString::null. +*/ + +/*! + Constructs an axis object which is a child of \a parent. +*/ +QBarCategoryAxis::QBarCategoryAxis(QObject *parent): + QAbstractAxis(*new QBarCategoryAxisPrivate(this), parent) +{ +} + +/*! + Destroys the object +*/ +QBarCategoryAxis::~QBarCategoryAxis() +{ + Q_D(QBarCategoryAxis); + if (d->m_chart) + d->m_chart->removeAxis(this); +} + +/*! + \internal +*/ +QBarCategoryAxis::QBarCategoryAxis(QBarCategoryAxisPrivate &d, QObject *parent) + : QAbstractAxis(d, parent) +{ + +} + +/*! + Appends \a categories to axis. A maximum of the axis will be changed to last category in \a categories. + If there were no categories previously defined, minimum of axis will be also changed to first category in \a categories. + A category has to be valid QStrings and can not be duplicated. Duplicated categories will not be appended. +*/ +void QBarCategoryAxis::append(const QStringList &categories) +{ + if (categories.isEmpty()) + return; + + Q_D(QBarCategoryAxis); + + int count = d->m_categories.count(); + + foreach(QString category, categories) { + if (!d->m_categories.contains(category) && !category.isNull()) { + d->m_categories.append(category); + } + } + + if (d->m_categories.count() == count) + return; + + if (count == 0) + setRange(d->m_categories.first(), d->m_categories.last()); + else + setRange(d->m_minCategory, d->m_categories.last()); + + emit categoriesChanged(); + emit countChanged(); +} + +/*! + Appends \a category to axis. A maximum of the axis will be changed to last \a category. + If there were no categories previously defined, minimum of axis will be also changed to \a category. + A \a category has to be valid QStrings and can not be duplicated. Duplicated categories will not be appended. +*/ +void QBarCategoryAxis::append(const QString &category) +{ + Q_D(QBarCategoryAxis); + + int count = d->m_categories.count(); + + if (!d->m_categories.contains(category) && !category.isNull()) + d->m_categories.append(category); + + if (d->m_categories.count() == count) + return; + + if (count == 0) + setRange(d->m_categories.last(), d->m_categories.last()); + else + setRange(d->m_minCategory, d->m_categories.last()); + + emit categoriesChanged(); + emit countChanged(); +} + +/*! + Removes \a category from axis. Removing category which is currently maximum or minimum + will affect the axis range. +*/ +void QBarCategoryAxis::remove(const QString &category) +{ + Q_D(QBarCategoryAxis); + + if (d->m_categories.contains(category)) { + d->m_categories.removeAt(d->m_categories.indexOf(category)); + if (!d->m_categories.isEmpty()) { + if (d->m_minCategory == category) { + setRange(d->m_categories.first(), d->m_maxCategory); + } else if (d->m_maxCategory == category) { + setRange(d->m_minCategory, d->m_categories.last()); + } else { + d->updateCategoryDomain(); + } + } else { + setRange(QString::null, QString::null); + } + emit categoriesChanged(); + emit countChanged(); + } +} + +/*! + Inserts \a category to axis at \a index. A \a category has to be valid QStrings and can not be duplicated. + If \a category is prepended or appended to categories, minimum and maximum of axis is updated accordingly. +*/ +void QBarCategoryAxis::insert(int index, const QString &category) +{ + Q_D(QBarCategoryAxis); + + int count = d->m_categories.count(); + + if (!d->m_categories.contains(category) && !category.isNull()) + d->m_categories.insert(index, category); + + if (d->m_categories.count() == count) + return; + + if (count == 0) { + setRange(d->m_categories.first(), d->m_categories.first()); + } else if (index == 0) { + setRange(d->m_categories.first(), d->m_maxCategory); + } else if (index == count) { + setRange(d->m_minCategory, d->m_categories.last()); + } else { + d->updateCategoryDomain(); + } + + emit categoriesChanged(); + emit countChanged(); +} + +/*! + Replaces \a oldCategory with \a newCategory. If \a oldCategory does not exist on the axis nothing is done. + A \a newCategory has to be valid QStrings and can not be duplicated. In case of replacing minimum or maximum category, + minimum and maximum of axis is updated accordingly. +*/ +void QBarCategoryAxis::replace(const QString &oldCategory, const QString &newCategory) +{ + Q_D(QBarCategoryAxis); + + int pos = d->m_categories.indexOf(oldCategory); + + if (pos != -1 && !d->m_categories.contains(newCategory) && !newCategory.isNull()) { + d->m_categories.replace(pos, newCategory); + if (d->m_minCategory == oldCategory) + setRange(newCategory, d->m_maxCategory); + else if (d->m_maxCategory == oldCategory) + setRange(d->m_minCategory, newCategory); + + emit categoriesChanged(); + emit countChanged(); + } +} + +/*! + Removes all categories. Sets the maximum and minimum of the axis's range to QString::null. + */ +void QBarCategoryAxis::clear() +{ + Q_D(QBarCategoryAxis); + d->m_categories.clear(); + setRange(QString::null, QString::null); + emit categoriesChanged(); + emit countChanged(); +} + +/*! + Set \a categories and discards the old ones, range of axis is adjusted to match first and last category in \a categories. + A category has to be valid QStrings and can not be duplicated. +*/ +void QBarCategoryAxis::setCategories(const QStringList &categories) +{ + Q_D(QBarCategoryAxis); + d->m_categories.clear(); + d->m_minCategory = QString::null; + d->m_maxCategory = QString::null; + d->m_min = 0; + d->m_max = 0; + d->m_count = 0; + append(categories); +} + +/*! + Returns categories +*/ +QStringList QBarCategoryAxis::categories() +{ + Q_D(QBarCategoryAxis); + return d->m_categories; +} + +/*! + Returns number of categories. + */ +int QBarCategoryAxis::count() const +{ + Q_D(const QBarCategoryAxis); + return d->m_categories.count(); +} + +/*! + Returns category at \a index. Index must be valid. +*/ +QString QBarCategoryAxis::at(int index) const +{ + Q_D(const QBarCategoryAxis); + return d->m_categories.at(index); +} + +/*! + Sets minimum category to \a min. +*/ +void QBarCategoryAxis::setMin(const QString &min) +{ + Q_D(QBarCategoryAxis); + d->setRange(min, d->m_maxCategory); +} + +/*! + Returns minimum category. +*/ +QString QBarCategoryAxis::min() const +{ + Q_D(const QBarCategoryAxis); + return d->m_minCategory; +} + +/*! + Sets maximum category to \a max. +*/ +void QBarCategoryAxis::setMax(const QString &max) +{ + Q_D(QBarCategoryAxis); + d->setRange(d->m_minCategory, max); +} + +/*! + Returns maximum category +*/ +QString QBarCategoryAxis::max() const +{ + Q_D(const QBarCategoryAxis); + return d->m_maxCategory; +} + +/*! + Sets range from \a minCategory to \a maxCategory +*/ +void QBarCategoryAxis::setRange(const QString &minCategory, const QString &maxCategory) +{ + Q_D(QBarCategoryAxis); + d->setRange(minCategory,maxCategory); +} + +/*! + Returns the type of the axis +*/ +QAbstractAxis::AxisType QBarCategoryAxis::type() const +{ + return AxisTypeBarCategory; +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +QBarCategoryAxisPrivate::QBarCategoryAxisPrivate(QBarCategoryAxis *q) + : QAbstractAxisPrivate(q), + m_min(0.0), + m_max(0.0), + m_count(0) +{ + +} + +QBarCategoryAxisPrivate::~QBarCategoryAxisPrivate() +{ + +} + +void QBarCategoryAxisPrivate::setMin(const QVariant &min) +{ + setRange(min, m_maxCategory); +} + +void QBarCategoryAxisPrivate::setMax(const QVariant &max) +{ + setRange(m_minCategory, max); +} + +void QBarCategoryAxisPrivate::setRange(const QVariant &min, const QVariant &max) +{ + QString value1 = min.toString(); + QString value2 = max.toString(); + setRange(value1, value2); +} + +void QBarCategoryAxisPrivate::setRange(qreal min, qreal max) +{ + Q_Q(QBarCategoryAxis); + + bool categoryChanged = false; + bool changed = false; + + if (min > max) + return; + + if (!qFuzzyIsNull(m_min - min)) { + m_min = min; + changed = true; + + int imin = m_min + 0.5; + if (imin >= 0 && imin < m_categories.count()) { + QString minCategory = m_categories.at(imin); + if (m_minCategory != minCategory && !minCategory.isEmpty()) { + m_minCategory = minCategory; + categoryChanged = true; + emit q->minChanged(minCategory); + } + } + + } + + if (!qFuzzyIsNull(m_max - max)) { + m_max = max; + changed = true; + + int imax = m_max - 0.5; + if (imax >= 0 && imax < m_categories.count()) { + QString maxCategory = m_categories.at(imax); + if (m_maxCategory != maxCategory && !maxCategory.isEmpty()) { + m_maxCategory = maxCategory; + categoryChanged = true; + emit q->maxChanged(maxCategory); + } + } + } + + if (categoryChanged){ + emit q->rangeChanged(m_minCategory, m_maxCategory); + } + + if (changed) { + emit rangeChanged(m_min,m_max); + } +} + +void QBarCategoryAxisPrivate::setRange(const QString &minCategory, const QString &maxCategory) +{ + Q_Q(QBarCategoryAxis); + bool changed = false; + + //special case in case or clearing all categories + if (minCategory.isNull() && maxCategory.isNull()) { + m_minCategory = minCategory; + m_maxCategory = maxCategory; + m_min = 0; + m_max = 0; + m_count = 0; + emit q->minChanged(minCategory); + emit q->maxChanged(maxCategory); + emit q->rangeChanged(m_minCategory, m_maxCategory); + emit rangeChanged(m_min,m_max); + return; + } + + if (m_categories.indexOf(maxCategory) < m_categories.indexOf(minCategory)) + return; + + if (!minCategory.isNull() && (m_minCategory != minCategory || m_minCategory.isNull()) + && m_categories.contains(minCategory)) { + m_minCategory = minCategory; + m_min = m_categories.indexOf(m_minCategory) - 0.5; + changed = true; + emit q->minChanged(minCategory); + } + + if (!maxCategory.isNull() && (m_maxCategory != maxCategory || m_maxCategory.isNull()) + && m_categories.contains(maxCategory)) { + m_maxCategory = maxCategory; + m_max = m_categories.indexOf(m_maxCategory) + 0.5; + changed = true; + emit q->maxChanged(maxCategory); + } + + if (changed) { + m_count = m_max - m_min; + emit q->rangeChanged(m_minCategory, m_maxCategory); + emit rangeChanged(m_min,m_max); + } +} + +void QBarCategoryAxisPrivate::initializeGraphics(QGraphicsItem* parent) +{ + Q_Q(QBarCategoryAxis); + ChartAxisElement* axis(0); + if (orientation() == Qt::Vertical) + axis = new ChartBarCategoryAxisY(q,parent); + if (orientation() == Qt::Horizontal) + axis = new ChartBarCategoryAxisX(q,parent); + + m_item.reset(axis); + QAbstractAxisPrivate::initializeGraphics(parent); +} + +void QBarCategoryAxisPrivate::updateCategoryDomain() +{ + bool changed = false; + + qreal tmpMin = m_categories.indexOf(m_minCategory) - 0.5; + if (!qFuzzyIsNull(m_min - tmpMin)) { + m_min = tmpMin; + changed = true; + } + qreal tmpMax = m_categories.indexOf(m_maxCategory) + 0.5; + if (!qFuzzyIsNull(m_max - tmpMax)) { + m_max = tmpMax; + changed = true; + } + m_count = m_max - m_min; + + if (changed) + emit rangeChanged(m_min,m_max); +} + + +void QBarCategoryAxisPrivate::initializeDomain(AbstractDomain *domain) +{ + Q_Q(QBarCategoryAxis); + if (m_max == m_min) { + int min; + int max; + if (orientation() == Qt::Vertical) { + min = domain->minY() + 0.5; + max = domain->maxY() - 0.5; + } else { + min = domain->minX() + 0.5; + max = domain->maxX() - 0.5; + } + + if (min > 0 && min < m_categories.count() && max > 0 && max < m_categories.count()) + q->setRange(m_categories.at(min), m_categories.at(max)); + } else { + if (orientation() == Qt::Vertical) + domain->setRangeY(m_min, m_max); + else + domain->setRangeX(m_min, m_max); + } +} + +#include "moc_qbarcategoryaxis.cpp" +#include "moc_qbarcategoryaxis_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/barcategoryaxis/qbarcategoryaxis.h b/src/charts/axis/barcategoryaxis/qbarcategoryaxis.h new file mode 100644 index 00000000..55a2430f --- /dev/null +++ b/src/charts/axis/barcategoryaxis/qbarcategoryaxis.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBARCATEGORYAXIS_H +#define QBARCATEGORYAXIS_H + +#include <QtCharts/qabstractaxis.h> + +QT_CHARTS_BEGIN_NAMESPACE + +class QBarCategoryAxisPrivate; + +class QT_CHARTS_EXPORT QBarCategoryAxis : public QAbstractAxis +{ + Q_OBJECT + Q_PROPERTY(QStringList categories READ categories WRITE setCategories NOTIFY categoriesChanged) + Q_PROPERTY(QString min READ min WRITE setMin NOTIFY minChanged) + Q_PROPERTY(QString max READ max WRITE setMax NOTIFY maxChanged) + Q_PROPERTY(int count READ count NOTIFY countChanged) + +public: + explicit QBarCategoryAxis(QObject *parent = 0); + ~QBarCategoryAxis(); + +protected: + QBarCategoryAxis(QBarCategoryAxisPrivate &d, QObject *parent = 0); + +public: + AxisType type() const; + void append(const QStringList &categories); + void append(const QString &category); + void remove(const QString &category); + void insert(int index, const QString &category); + void replace(const QString &oldCategory, const QString &newCategory); + Q_INVOKABLE void clear(); + void setCategories(const QStringList &categories); + QStringList categories(); + int count() const; + QString at(int index) const; + + //range handling + void setMin(const QString &minCategory); + QString min() const; + void setMax(const QString &maxCategory); + QString max() const; + void setRange(const QString &minCategory, const QString &maxCategory); + +Q_SIGNALS: + void categoriesChanged(); + void minChanged(const QString &min); + void maxChanged(const QString &max); + void rangeChanged(const QString &min, const QString &max); + void countChanged(); + +private: + Q_DECLARE_PRIVATE(QBarCategoryAxis) + Q_DISABLE_COPY(QBarCategoryAxis) + friend class ChartBarCategoryAxisX; + friend class ChartBarCategoryAxisY; +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QBARCATEGORYAXIS_H diff --git a/src/charts/axis/barcategoryaxis/qbarcategoryaxis_p.h b/src/charts/axis/barcategoryaxis/qbarcategoryaxis_p.h new file mode 100644 index 00000000..8ebc5a4c --- /dev/null +++ b/src/charts/axis/barcategoryaxis/qbarcategoryaxis_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QBARCATEGORYAXIS_P_H +#define QBARCATEGORYAXIS_P_H + +#include <qbarcategoryaxis.h> +#include "qabstractaxis_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class AbstractDomain; + +class QBarCategoryAxisPrivate : public QAbstractAxisPrivate +{ + Q_OBJECT + +public: + QBarCategoryAxisPrivate(QBarCategoryAxis *q); + ~QBarCategoryAxisPrivate(); + +public: + void initializeGraphics(QGraphicsItem* parent); + void initializeDomain(AbstractDomain *domain); + void updateCategoryDomain(); + + //interface for manipulating range form base class + void setRange(const QVariant &min, const QVariant &max); + void setMin(const QVariant &min); + void setMax(const QVariant &max); + + //interface manipulating range form domain + qreal min() { return m_min; } + qreal max() { return m_max; } + void setRange(qreal min,qreal max); + +private: + //range handling + void setRange(const QString &minCategory, const QString &maxCategory); + +private: + QStringList m_categories; + QString m_minCategory; + QString m_maxCategory; + qreal m_min; + qreal m_max; + int m_count; + +private: + Q_DECLARE_PUBLIC(QBarCategoryAxis); +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QBARCATEGORYAXIS_P_H diff --git a/src/charts/axis/cartesianchartaxis.cpp b/src/charts/axis/cartesianchartaxis.cpp new file mode 100644 index 00000000..d067921d --- /dev/null +++ b/src/charts/axis/cartesianchartaxis.cpp @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "cartesianchartaxis_p.h" +#include "qabstractaxis.h" +#include "qabstractaxis_p.h" +#include "chartpresenter_p.h" +#include "abstractchartlayout_p.h" +#include "abstractdomain_p.h" +#include "linearrowitem_p.h" +#include <QValueAxis> +#include <QLogValueAxis> +#include <QGraphicsLayout> +#include <QTextDocument> + +QT_CHARTS_BEGIN_NAMESPACE + +CartesianChartAxis::CartesianChartAxis(QAbstractAxis *axis, QGraphicsItem *item , bool intervalAxis) + : ChartAxisElement(axis, item, intervalAxis) +{ + Q_ASSERT(item); +} + + +CartesianChartAxis::~CartesianChartAxis() +{ +} + +void CartesianChartAxis::createItems(int count) +{ + if (arrowItems().size() == 0) { + QGraphicsLineItem *arrow = new LineArrowItem(this, this); + arrow->setPen(axis()->linePen()); + arrowGroup()->addToGroup(arrow); + } + + if (intervalAxis() && gridItems().size() == 0) { + for (int i = 0 ; i < 2 ; i ++){ + QGraphicsLineItem *item = new QGraphicsLineItem(this); + item->setPen(axis()->gridLinePen()); + gridGroup()->addToGroup(item); + } + } + + QGraphicsTextItem *title = titleItem(); + title->setFont(axis()->titleFont()); + title->setDefaultTextColor(axis()->titleBrush().color()); + title->setHtml(axis()->titleText()); + + for (int i = 0; i < count; ++i) { + QGraphicsLineItem *arrow = new QGraphicsLineItem(this); + QGraphicsLineItem *grid = new QGraphicsLineItem(this); + QGraphicsTextItem *label = new QGraphicsTextItem(this); + label->document()->setDocumentMargin(ChartPresenter::textMargin()); + arrow->setPen(axis()->linePen()); + grid->setPen(axis()->gridLinePen()); + label->setFont(axis()->labelsFont()); + label->setDefaultTextColor(axis()->labelsBrush().color()); + label->setRotation(axis()->labelsAngle()); + arrowGroup()->addToGroup(arrow); + gridGroup()->addToGroup(grid); + labelGroup()->addToGroup(label); + + if ((gridItems().size()) % 2 && gridItems().size() > 2) { + QGraphicsRectItem* shades = new QGraphicsRectItem(this); + shades->setPen(axis()->shadesPen()); + shades->setBrush(axis()->shadesBrush()); + shadeGroup()->addToGroup(shades); + } + } + +} + +void CartesianChartAxis::deleteItems(int count) +{ + QList<QGraphicsItem *> lines = gridItems(); + QList<QGraphicsItem *> labels = labelItems(); + QList<QGraphicsItem *> shades = shadeItems(); + QList<QGraphicsItem *> axis = arrowItems(); + + for (int i = 0; i < count; ++i) { + if (lines.size() % 2 && lines.size() > 1) + delete(shades.takeLast()); + delete(lines.takeLast()); + delete(labels.takeLast()); + delete(axis.takeLast()); + } +} + +void CartesianChartAxis::updateLayout(QVector<qreal> &layout) +{ + int diff = ChartAxisElement::layout().size() - layout.size(); + + if (diff > 0) + deleteItems(diff); + else if (diff < 0) + createItems(-diff); + + if (animation()) { + switch (presenter()->state()) { + case ChartPresenter::ZoomInState: + animation()->setAnimationType(AxisAnimation::ZoomInAnimation); + animation()->setAnimationPoint(presenter()->statePoint()); + break; + case ChartPresenter::ZoomOutState: + animation()->setAnimationType(AxisAnimation::ZoomOutAnimation); + animation()->setAnimationPoint(presenter()->statePoint()); + break; + case ChartPresenter::ScrollUpState: + case ChartPresenter::ScrollLeftState: + animation()->setAnimationType(AxisAnimation::MoveBackwordAnimation); + break; + case ChartPresenter::ScrollDownState: + case ChartPresenter::ScrollRightState: + animation()->setAnimationType(AxisAnimation::MoveForwardAnimation); + break; + case ChartPresenter::ShowState: + animation()->setAnimationType(AxisAnimation::DefaultAnimation); + break; + } + animation()->setValues(ChartAxisElement::layout(), layout); + presenter()->startAnimation(animation()); + } else { + setLayout(layout); + updateGeometry(); + } +} + +bool CartesianChartAxis::isEmpty() +{ + return axisGeometry().isEmpty() + || gridGeometry().isEmpty() + || qFuzzyCompare(min(), max()); +} + +void CartesianChartAxis::setGeometry(const QRectF &axis, const QRectF &grid) +{ + m_gridRect = grid; + setAxisGeometry(axis); + + if (isEmpty()) + return; + + QVector<qreal> layout = calculateLayout(); + updateLayout(layout); +} + +QSizeF CartesianChartAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const +{ + Q_UNUSED(which); + Q_UNUSED(constraint); + return QSizeF(); +} + +void CartesianChartAxis::handleArrowPenChanged(const QPen &pen) +{ + foreach (QGraphicsItem *item, arrowItems()) + static_cast<QGraphicsLineItem *>(item)->setPen(pen); +} + +void CartesianChartAxis::handleGridPenChanged(const QPen &pen) +{ + foreach (QGraphicsItem *item, gridItems()) + static_cast<QGraphicsLineItem *>(item)->setPen(pen); +} + +void CartesianChartAxis::handleShadesBrushChanged(const QBrush &brush) +{ + foreach (QGraphicsItem *item, shadeItems()) + static_cast<QGraphicsRectItem *>(item)->setBrush(brush); +} + +void CartesianChartAxis::handleShadesPenChanged(const QPen &pen) +{ + foreach (QGraphicsItem *item, shadeItems()) + static_cast<QGraphicsRectItem *>(item)->setPen(pen); +} + +#include "moc_cartesianchartaxis_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/cartesianchartaxis_p.h b/src/charts/axis/cartesianchartaxis_p.h new file mode 100644 index 00000000..c0c2252b --- /dev/null +++ b/src/charts/axis/cartesianchartaxis_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef CARTESIANCHARTAXIS_H +#define CARTESIANCHARTAXIS_H + +#include "qchartglobal.h" +#include "chartaxiselement_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QAbstractAxis; + +class CartesianChartAxis : public ChartAxisElement +{ + Q_OBJECT + Q_INTERFACES(QGraphicsLayoutItem) +public: + + CartesianChartAxis(QAbstractAxis *axis, QGraphicsItem *item = 0, bool intervalAxis = false); + ~CartesianChartAxis(); + + void setGeometry(const QRectF &axis, const QRectF &grid); + QRectF gridGeometry() const { return m_gridRect; } + bool isEmpty(); + + virtual QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const; + +protected: + void setGeometry(const QRectF &size) { Q_UNUSED(size);} + virtual void updateGeometry() = 0; + void updateLayout(QVector<qreal> &layout); + +public Q_SLOTS: + virtual void handleArrowPenChanged(const QPen &pen); + virtual void handleGridPenChanged(const QPen &pen); + virtual void handleShadesBrushChanged(const QBrush &brush); + virtual void handleShadesPenChanged(const QPen &pen); + +private: + void createItems(int count); + void deleteItems(int count); + +private: + QRectF m_gridRect; + + friend class AxisAnimation; + friend class LineArrowItem; +}; + +QT_CHARTS_END_NAMESPACE + +#endif /* CARTESIANCHARTAXIS_H */ diff --git a/src/charts/axis/categoryaxis/chartcategoryaxisx.cpp b/src/charts/axis/categoryaxis/chartcategoryaxisx.cpp new file mode 100644 index 00000000..2141f353 --- /dev/null +++ b/src/charts/axis/categoryaxis/chartcategoryaxisx.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "chartcategoryaxisx_p.h" +#include "qcategoryaxis.h" +#include "qabstractaxis.h" +#include "chartpresenter_p.h" +#include "abstractchartlayout_p.h" +#include <QGraphicsLayout> +#include <qmath.h> + +QT_CHARTS_BEGIN_NAMESPACE + +ChartCategoryAxisX::ChartCategoryAxisX(QCategoryAxis *axis, QGraphicsItem* item) + : HorizontalAxis(axis, item, true), + m_axis(axis) +{ + QObject::connect(axis, SIGNAL(categoriesChanged()), this, SLOT(handleCategoriesChanged())); +} + +ChartCategoryAxisX::~ChartCategoryAxisX() +{ +} + +QVector<qreal> ChartCategoryAxisX::calculateLayout() const +{ + int tickCount = m_axis->categoriesLabels().count() + 1; + QVector<qreal> points; + + if (tickCount < 2) + return points; + + const QRectF &gridRect = gridGeometry(); + qreal range = max() - min(); + if (range > 0) { + points.resize(tickCount); + qreal scale = gridRect.width() / range; + for (int i = 0; i < tickCount; ++i) { + if (i < tickCount - 1) { + qreal x = (m_axis->startValue(m_axis->categoriesLabels().at(i)) - min()) * scale + gridRect.left(); + points[i] = x; + } else { + qreal x = (m_axis->endValue(m_axis->categoriesLabels().at(i - 1)) - min()) * scale + gridRect.left(); + points[i] = x; + } + } + } + + return points; +} + +void ChartCategoryAxisX::updateGeometry() +{ + setLabels(m_axis->categoriesLabels() << QString()); + HorizontalAxis::updateGeometry(); +} + +QSizeF ChartCategoryAxisX::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const +{ + Q_UNUSED(constraint) + + QSizeF sh; + QSizeF base = HorizontalAxis::sizeHint(which, constraint); + QStringList ticksList = m_axis->categoriesLabels(); + qreal width = 0; // Width is irrelevant for X axes with interval labels + qreal height = 0; + + switch (which) { + case Qt::MinimumSize: { + QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), + QStringLiteral("..."), + axis()->labelsAngle()); + height = boundingRect.height() + labelPadding() + base.height() + 1.0; + sh = QSizeF(width, height); + break; + } + case Qt::PreferredSize: { + qreal labelHeight = 0.0; + foreach (const QString& s, ticksList) { + QRectF rect = ChartPresenter::textBoundingRect(axis()->labelsFont(), s, axis()->labelsAngle()); + labelHeight = qMax(rect.height(), labelHeight); + } + height = labelHeight + labelPadding() + base.height() + 1.0; + sh = QSizeF(width, height); + break; + } + default: + break; + } + + return sh; +} + +void ChartCategoryAxisX::handleCategoriesChanged() +{ + QGraphicsLayoutItem::updateGeometry(); + presenter()->layout()->invalidate(); +} + +#include "moc_chartcategoryaxisx_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/categoryaxis/chartcategoryaxisx_p.h b/src/charts/axis/categoryaxis/chartcategoryaxisx_p.h new file mode 100644 index 00000000..e526b01a --- /dev/null +++ b/src/charts/axis/categoryaxis/chartcategoryaxisx_p.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef CHARTCATEGORYAXISX_H +#define CHARTCATEGORYAXISX_H + +#include "horizontalaxis_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QCategoryAxis; + +class ChartCategoryAxisX : public HorizontalAxis +{ + Q_OBJECT +public: + ChartCategoryAxisX(QCategoryAxis *axis, QGraphicsItem* item = 0); + ~ChartCategoryAxisX(); + + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const; + +public Q_SLOTS: + void handleCategoriesChanged(); + +protected: + QVector<qreal> calculateLayout() const; + void updateGeometry(); + +private: + QCategoryAxis *m_axis; +}; + +QT_CHARTS_END_NAMESPACE + +#endif /* CHARTCATEGORYAXISX_H */ diff --git a/src/charts/axis/categoryaxis/chartcategoryaxisy.cpp b/src/charts/axis/categoryaxis/chartcategoryaxisy.cpp new file mode 100644 index 00000000..7d5ba103 --- /dev/null +++ b/src/charts/axis/categoryaxis/chartcategoryaxisy.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "chartcategoryaxisy_p.h" +#include "qcategoryaxis.h" +#include "qabstractaxis.h" +#include "chartpresenter_p.h" +#include "abstractchartlayout_p.h" +#include <QGraphicsLayout> +#include <qmath.h> +#include <QDebug> + +QT_CHARTS_BEGIN_NAMESPACE + +ChartCategoryAxisY::ChartCategoryAxisY(QCategoryAxis *axis, QGraphicsItem* item) + : VerticalAxis(axis, item, true), + m_axis(axis) +{ + QObject::connect(axis, SIGNAL(categoriesChanged()), this, SLOT(handleCategoriesChanged())); +} + +ChartCategoryAxisY::~ChartCategoryAxisY() +{ +} + +QVector<qreal> ChartCategoryAxisY::calculateLayout() const +{ + int tickCount = m_axis->categoriesLabels().count() + 1; + QVector<qreal> points; + + if (tickCount < 2) + return points; + + const QRectF &gridRect = gridGeometry(); + qreal range = max() - min(); + if (range > 0) { + points.resize(tickCount); + qreal scale = gridRect.height() / range; + for (int i = 0; i < tickCount; ++i) { + if (i < tickCount - 1) { + qreal y = -(m_axis->startValue(m_axis->categoriesLabels().at(i)) - min()) * scale + gridRect.bottom(); + points[i] = y; + } else { + qreal y = -(m_axis->endValue(m_axis->categoriesLabels().at(i - 1)) - min()) * scale + gridRect.bottom(); + points[i] = y; + } + } + } + + return points; +} + +void ChartCategoryAxisY::updateGeometry() +{ + setLabels(m_axis->categoriesLabels() << QString()); + VerticalAxis::updateGeometry(); +} + +QSizeF ChartCategoryAxisY::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const +{ + Q_UNUSED(constraint) + + QSizeF sh; + QSizeF base = VerticalAxis::sizeHint(which, constraint); + QStringList ticksList = m_axis->categoriesLabels(); + qreal width = 0; + qreal height = 0; // Height is irrelevant for Y axes with interval labels + + switch (which) { + case Qt::MinimumSize: { + QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), + QStringLiteral("..."), + axis()->labelsAngle()); + width = boundingRect.width() + labelPadding() + base.width() + 1.0; + sh = QSizeF(width, height); + break; + } + case Qt::PreferredSize: { + qreal labelWidth = 0.0; + foreach (const QString& s, ticksList) { + QRectF rect = ChartPresenter::textBoundingRect(axis()->labelsFont(), s, axis()->labelsAngle()); + labelWidth = qMax(rect.width(), labelWidth); + } + width = labelWidth + labelPadding() + base.width() + 1.0; + sh = QSizeF(width, height); + break; + } + default: + break; + } + return sh; +} + +void ChartCategoryAxisY::handleCategoriesChanged() +{ + QGraphicsLayoutItem::updateGeometry(); + presenter()->layout()->invalidate(); +} + +#include "moc_chartcategoryaxisy_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/categoryaxis/chartcategoryaxisy_p.h b/src/charts/axis/categoryaxis/chartcategoryaxisy_p.h new file mode 100644 index 00000000..e416e4c0 --- /dev/null +++ b/src/charts/axis/categoryaxis/chartcategoryaxisy_p.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef CHARTCATEGORYAXISY_H +#define CHARTCATEGORYAXISY_H + +#include "verticalaxis_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QCategoryAxis; + +class ChartCategoryAxisY : public VerticalAxis +{ + Q_OBJECT +public: + ChartCategoryAxisY(QCategoryAxis *axis, QGraphicsItem* item = 0); + ~ChartCategoryAxisY(); + + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const; + +public Q_SLOTS: + void handleCategoriesChanged(); + +protected: + QVector<qreal> calculateLayout() const; + void updateGeometry(); + +private: + QCategoryAxis *m_axis; +}; + +QT_CHARTS_END_NAMESPACE + +#endif /* CHARTCATEGORYAXISY_H */ diff --git a/src/charts/axis/categoryaxis/polarchartcategoryaxisangular.cpp b/src/charts/axis/categoryaxis/polarchartcategoryaxisangular.cpp new file mode 100644 index 00000000..8c43dd32 --- /dev/null +++ b/src/charts/axis/categoryaxis/polarchartcategoryaxisangular.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "polarchartcategoryaxisangular_p.h" +#include "chartpresenter_p.h" +#include "abstractchartlayout_p.h" +#include "qcategoryaxis.h" +#include <QDebug> + +QT_CHARTS_BEGIN_NAMESPACE + +PolarChartCategoryAxisAngular::PolarChartCategoryAxisAngular(QCategoryAxis *axis, QGraphicsItem *item) + : PolarChartAxisAngular(axis, item, true) +{ + QObject::connect(axis, SIGNAL(categoriesChanged()), this, SLOT(handleCategoriesChanged())); +} + +PolarChartCategoryAxisAngular::~PolarChartCategoryAxisAngular() +{ +} + +QVector<qreal> PolarChartCategoryAxisAngular::calculateLayout() const +{ + QCategoryAxis *catAxis = static_cast<QCategoryAxis *>(axis()); + int tickCount = catAxis->categoriesLabels().count() + 1; + QVector<qreal> points; + + if (tickCount < 2) + return points; + + qreal range = max() - min(); + if (range > 0) { + points.resize(tickCount); + qreal scale = 360.0 / range; + qreal angle; + for (int i = 0; i < tickCount; ++i) { + if (i < tickCount - 1) + angle = (catAxis->startValue(catAxis->categoriesLabels().at(i)) - min()) * scale; + else + angle = (catAxis->endValue(catAxis->categoriesLabels().at(i - 1)) - min()) * scale; + points[i] = angle; + } + } + + return points; +} + +void PolarChartCategoryAxisAngular::createAxisLabels(const QVector<qreal> &layout) +{ + Q_UNUSED(layout); + setLabels(static_cast<QCategoryAxis *>(axis())->categoriesLabels() << QString()); +} + +void PolarChartCategoryAxisAngular::handleCategoriesChanged() +{ + QGraphicsLayoutItem::updateGeometry(); + presenter()->layout()->invalidate(); +} + + +#include "moc_polarchartcategoryaxisangular_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/categoryaxis/polarchartcategoryaxisangular_p.h b/src/charts/axis/categoryaxis/polarchartcategoryaxisangular_p.h new file mode 100644 index 00000000..0432fc11 --- /dev/null +++ b/src/charts/axis/categoryaxis/polarchartcategoryaxisangular_p.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef POLARCHARTCATEGORYAXISANGULAR_P_H +#define POLARCHARTCATEGORYAXISANGULAR_P_H + +#include "polarchartaxisangular_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QCategoryAxis; + +class PolarChartCategoryAxisAngular : public PolarChartAxisAngular +{ + Q_OBJECT + +public: + PolarChartCategoryAxisAngular(QCategoryAxis *axis, QGraphicsItem *item); + ~PolarChartCategoryAxisAngular(); + + virtual QVector<qreal> calculateLayout() const; + virtual void createAxisLabels(const QVector<qreal> &layout); + +public Q_SLOTS: + void handleCategoriesChanged(); +}; + +QT_CHARTS_END_NAMESPACE + +#endif // POLARCHARTCATEGORYAXISANGULAR_P_H diff --git a/src/charts/axis/categoryaxis/polarchartcategoryaxisradial.cpp b/src/charts/axis/categoryaxis/polarchartcategoryaxisradial.cpp new file mode 100644 index 00000000..60b77f0c --- /dev/null +++ b/src/charts/axis/categoryaxis/polarchartcategoryaxisradial.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "polarchartcategoryaxisradial_p.h" +#include "chartpresenter_p.h" +#include "abstractchartlayout_p.h" +#include "qcategoryaxis.h" +#include <QDebug> + +QT_CHARTS_BEGIN_NAMESPACE + +PolarChartCategoryAxisRadial::PolarChartCategoryAxisRadial(QCategoryAxis *axis, QGraphicsItem *item) + : PolarChartAxisRadial(axis, item, true) +{ + QObject::connect(axis, SIGNAL(categoriesChanged()), this, SLOT(handleCategoriesChanged())); +} + +PolarChartCategoryAxisRadial::~PolarChartCategoryAxisRadial() +{ +} + +QVector<qreal> PolarChartCategoryAxisRadial::calculateLayout() const +{ + QCategoryAxis *catAxis = static_cast<QCategoryAxis *>(axis()); + int tickCount = catAxis->categoriesLabels().count() + 1; + QVector<qreal> points; + + if (tickCount < 2) + return points; + + qreal range = max() - min(); + if (range > 0) { + points.resize(tickCount); + qreal scale = (axisGeometry().width() / 2) / range; + qreal angle; + for (int i = 0; i < tickCount; ++i) { + if (i < tickCount - 1) + angle = (catAxis->startValue(catAxis->categoriesLabels().at(i)) - min()) * scale; + else + angle = (catAxis->endValue(catAxis->categoriesLabels().at(i - 1)) - min()) * scale; + points[i] = angle; + } + } + + return points; +} + +void PolarChartCategoryAxisRadial::createAxisLabels(const QVector<qreal> &layout) +{ + Q_UNUSED(layout); + setLabels(static_cast<QCategoryAxis *>(axis())->categoriesLabels() << QString()); +} + +void PolarChartCategoryAxisRadial::handleCategoriesChanged() +{ + QGraphicsLayoutItem::updateGeometry(); + presenter()->layout()->invalidate(); +} + +#include "moc_polarchartcategoryaxisradial_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/categoryaxis/polarchartcategoryaxisradial_p.h b/src/charts/axis/categoryaxis/polarchartcategoryaxisradial_p.h new file mode 100644 index 00000000..3186f5ec --- /dev/null +++ b/src/charts/axis/categoryaxis/polarchartcategoryaxisradial_p.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef POLARCHARTCATEGORYAXISRADIAL_P_H +#define POLARCHARTCATEGORYAXISRADIAL_P_H + +#include "polarchartaxisradial_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QCategoryAxis; + +class PolarChartCategoryAxisRadial : public PolarChartAxisRadial +{ + Q_OBJECT + +public: + PolarChartCategoryAxisRadial(QCategoryAxis *axis, QGraphicsItem *item); + ~PolarChartCategoryAxisRadial(); + + virtual QVector<qreal> calculateLayout() const; + virtual void createAxisLabels(const QVector<qreal> &layout); + +public Q_SLOTS: + void handleCategoriesChanged(); +}; + +QT_CHARTS_END_NAMESPACE + +#endif // POLARCHARTCATEGORYAXISRADIAL_P_H diff --git a/src/charts/axis/categoryaxis/qcategoryaxis.cpp b/src/charts/axis/categoryaxis/qcategoryaxis.cpp new file mode 100644 index 00000000..d5b3d472 --- /dev/null +++ b/src/charts/axis/categoryaxis/qcategoryaxis.cpp @@ -0,0 +1,345 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcategoryaxis.h" +#include "qcategoryaxis_p.h" +#include "chartcategoryaxisx_p.h" +#include "chartcategoryaxisy_p.h" +#include "polarchartcategoryaxisangular_p.h" +#include "polarchartcategoryaxisradial_p.h" +#include "qchart.h" +#include <qmath.h> +#include <QDebug> + +QT_CHARTS_BEGIN_NAMESPACE +/*! + \class QCategoryAxis + \inmodule Qt Charts + \brief The QCategoryAxis class allows putting a named ranges on the axis. + \mainclass + + This class can be used when the underlying data needs to be given extra meaning. + Unlike with the QBarCategoryAxis the QCategoryAxis allows the categories ranges widths to be specified freely. + + Example code on how to use QCategoryAxis: + \table + \row + \li \br + \br + \code + QChartView *chartView = new QChartView; + QLineSeries *series = new QLineSeries; + // ... + chartView->chart()->addSeries(series); + + QCategoryAxis *axisY = new QCategoryAxis; + axisY->setMin(0); + axisY->setMax(52); + axisY->setStartValue(15); + axisY->append("First", 20); + axisY->append("Second", 37); + axisY->append("Third", 52); + chartView->chart()->setAxisY(axisY, series); + \endcode + \li \br + \inlineimage api_category_axis.png + \endtable +*/ +/*! + \qmltype CategoryAxis + \instantiates QCategoryAxis + \inqmlmodule QtCharts + + \inherits AbstractAxis + \brief CategoryAxis allows putting a named ranges on the axis. + + For example: + \table + \row + \li \br + \br + \br + \snippet qmlaxes/qml/qmlaxes/View3.qml 1 + \li \inlineimage examples_qmlaxes3.png + \endtable +*/ + +/*! + \property QCategoryAxis::startValue + Defines the low end of the first category on the axis. +*/ +/*! + \qmlproperty int CategoryAxis::startValue + Defines the low end of the first category on the axis. +*/ + +/*! + \property QCategoryAxis::count + The count of categories. +*/ +/*! + \qmlproperty int CategoryAxis::count + The count of categories. +*/ + +/*! + \property QCategoryAxis::categoriesLabels + The category labels as a string list. +*/ +/*! + \qmlproperty StringList CategoryAxis::categoriesLabels + The category labels as a list of strings. +*/ + +/*! + \fn void QCategoryAxis::categoriesChanged() + Axis emits signal when the categories of the axis have changed. +*/ + + +/*! + Constructs an axis object which is a child of \a parent. +*/ +QCategoryAxis::QCategoryAxis(QObject *parent): + QValueAxis(*new QCategoryAxisPrivate(this), parent) +{ +} + +/*! + Destroys the object +*/ +QCategoryAxis::~QCategoryAxis() +{ + Q_D(QCategoryAxis); + if (d->m_chart) + d->m_chart->removeAxis(this); +} + +/*! + \internal +*/ +QCategoryAxis::QCategoryAxis(QCategoryAxisPrivate &d, QObject *parent): QValueAxis(d, parent) +{ + +} + +/*! + \qmlmethod CategoryAxis::append(string label, real endValue) + Appends new category to the axis with an \a label. Category label has to be unique. + Parameter \a endValue specifies the high end limit of the category. + It has to be greater than the high end limit of the previous category. + Otherwise the method returns without adding a new category. +*/ +/*! + Appends new category to the axis with an \a categoryLabel. + Category label has to be unique. + Parameter \a categoryEndValue specifies the high end limit of the category. + It has to be greater than the high end limit of the previous category. + Otherwise the method returns without adding a new category. +*/ +void QCategoryAxis::append(const QString &categoryLabel, qreal categoryEndValue) +{ + Q_D(QCategoryAxis); + + if (!d->m_categories.contains(categoryLabel)) { + if (d->m_categories.isEmpty()) { + Range range(d->m_categoryMinimum, categoryEndValue); + d->m_categoriesMap.insert(categoryLabel, range); + d->m_categories.append(categoryLabel); + emit categoriesChanged(); + } else if (categoryEndValue > endValue(d->m_categories.last())) { + Range previousRange = d->m_categoriesMap.value(d->m_categories.last()); + d->m_categoriesMap.insert(categoryLabel, Range(previousRange.second, categoryEndValue)); + d->m_categories.append(categoryLabel); + emit categoriesChanged(); + } + } +} + +/*! + Sets \a min to be the low end limit of the first category on the axis. + If there is already some categories added to the axis then passed value must be lower than the high end value of the already defined first category range. + Otherwise nothing is done. +*/ +void QCategoryAxis::setStartValue(qreal min) +{ + Q_D(QCategoryAxis); + if (d->m_categories.isEmpty()) { + d->m_categoryMinimum = min; + emit categoriesChanged(); + } else { + Range range = d->m_categoriesMap.value(d->m_categories.first()); + if (min < range.second) { + d->m_categoriesMap.insert(d->m_categories.first(), Range(min, range.second)); + emit categoriesChanged(); + } + } +} + +/*! + Returns the low end limit of the category specified by an \a categoryLabel +*/ +qreal QCategoryAxis::startValue(const QString &categoryLabel) const +{ + Q_D(const QCategoryAxis); + if (categoryLabel.isEmpty()) + return d->m_categoryMinimum; + return d->m_categoriesMap.value(categoryLabel).first; +} + +/*! + Returns the high end limit of the interval specified by an \a categoryLabel +*/ +qreal QCategoryAxis::endValue(const QString &categoryLabel) const +{ + Q_D(const QCategoryAxis); + return d->m_categoriesMap.value(categoryLabel).second; +} + +/*! + \qmlmethod CategoryAxis::remove(string label) + Removes a category specified by the \a label from the axis +*/ +/*! + Removes an interval specified by the \a categoryLabel from the axis +*/ +void QCategoryAxis::remove(const QString &categoryLabel) +{ + Q_D(QCategoryAxis); + int labelIndex = d->m_categories.indexOf(categoryLabel); + + // check if such label exists + if (labelIndex != -1) { + d->m_categories.removeAt(labelIndex); + d->m_categoriesMap.remove(categoryLabel); + + // the range of the interval that follows (if exists) needs to be updated + if (labelIndex < d->m_categories.count()) { + QString label = d->m_categories.at(labelIndex); + Range range = d->m_categoriesMap.value(label); + + // set the range + if (labelIndex == 0) { + range.first = d->m_categoryMinimum; + d->m_categoriesMap.insert(label, range); + } else { + range.first = d->m_categoriesMap.value(d->m_categories.at(labelIndex - 1)).second; + d->m_categoriesMap.insert(label, range); + } + } + emit categoriesChanged(); + } +} + +/*! + \qmlmethod CategoryAxis::replace(string oldLabel, string newLabel) + Replaces \a oldLabel of an existing category with a \a newLabel. + If the old label does not exist the method returns without making any changes. +*/ +/*! + Replaces \a oldLabel of an existing category with a \a newLabel + If the old label does not exist the method returns without making any changes. + */ +void QCategoryAxis::replaceLabel(const QString &oldLabel, const QString &newLabel) +{ + Q_D(QCategoryAxis); + int labelIndex = d->m_categories.indexOf(oldLabel); + + // check if such label exists + if (labelIndex != -1) { + d->m_categories.replace(labelIndex, newLabel); + Range range = d->m_categoriesMap.value(oldLabel); + d->m_categoriesMap.remove(oldLabel); + d->m_categoriesMap.insert(newLabel, range); + emit categoriesChanged(); + } +} + +/*! + Returns the list of the intervals labels + */ +QStringList QCategoryAxis::categoriesLabels() +{ + Q_D(QCategoryAxis); + return d->m_categories; +} + +/*! + Returns number of intervals. + */ +int QCategoryAxis::count() const +{ + Q_D(const QCategoryAxis); + return d->m_categories.count(); +} + +/*! + Returns the type of the axis +*/ +QAbstractAxis::AxisType QCategoryAxis::type() const +{ + return QAbstractAxis::AxisTypeCategory; +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +QCategoryAxisPrivate::QCategoryAxisPrivate(QCategoryAxis *q) + : QValueAxisPrivate(q), + m_categoryMinimum(0) +{ + +} + +QCategoryAxisPrivate::~QCategoryAxisPrivate() +{ + +} + +int QCategoryAxisPrivate::ticksCount() const +{ + return m_categories.count() + 1; +} + +void QCategoryAxisPrivate::initializeGraphics(QGraphicsItem *parent) +{ + Q_Q(QCategoryAxis); + ChartAxisElement *axis(0); + if (m_chart->chartType() == QChart::ChartTypeCartesian) { + if (orientation() == Qt::Vertical) + axis = new ChartCategoryAxisY(q,parent); + else if (orientation() == Qt::Horizontal) + axis = new ChartCategoryAxisX(q,parent); + } + + if (m_chart->chartType() == QChart::ChartTypePolar) { + if (orientation() == Qt::Vertical) + axis = new PolarChartCategoryAxisRadial(q, parent); + if (orientation() == Qt::Horizontal) + axis = new PolarChartCategoryAxisAngular(q, parent); + } + + m_item.reset(axis); + QAbstractAxisPrivate::initializeGraphics(parent); +} + +#include "moc_qcategoryaxis.cpp" +#include "moc_qcategoryaxis_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/categoryaxis/qcategoryaxis.h b/src/charts/axis/categoryaxis/qcategoryaxis.h new file mode 100644 index 00000000..bd4b3d82 --- /dev/null +++ b/src/charts/axis/categoryaxis/qcategoryaxis.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCATEGORYAXIS_H +#define QCATEGORYAXIS_H + +#include <QtCharts/qabstractaxis.h> +#include <QtCharts/qvalueaxis.h> + +QT_CHARTS_BEGIN_NAMESPACE + +class QCategoryAxisPrivate; + +class QT_CHARTS_EXPORT QCategoryAxis : public QValueAxis +{ + Q_OBJECT + Q_PROPERTY(qreal startValue READ startValue WRITE setStartValue) + Q_PROPERTY(int count READ count) + Q_PROPERTY(QStringList categoriesLabels READ categoriesLabels) + +public: + explicit QCategoryAxis(QObject *parent = 0); + ~QCategoryAxis(); + +protected: + QCategoryAxis(QCategoryAxisPrivate &d, QObject *parent = 0); + +public: + AxisType type() const; + + void append(const QString &label, qreal categoryEndValue); + void remove(const QString &label); + void replaceLabel(const QString &oldLabel, const QString &newLabel); + + qreal startValue(const QString &categoryLabel = QString()) const; + void setStartValue(qreal min); + + qreal endValue(const QString &categoryLabel) const; + + QStringList categoriesLabels(); + int count() const; + +Q_SIGNALS: + void categoriesChanged(); + +private: + Q_DECLARE_PRIVATE(QCategoryAxis) + Q_DISABLE_COPY(QCategoryAxis) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QCATEGORYAXIS_H diff --git a/src/charts/axis/categoryaxis/qcategoryaxis_p.h b/src/charts/axis/categoryaxis/qcategoryaxis_p.h new file mode 100644 index 00000000..bc657521 --- /dev/null +++ b/src/charts/axis/categoryaxis/qcategoryaxis_p.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QCATEGORYAXIS_P_H +#define QCATEGORYAXIS_P_H + +#include <qcategoryaxis.h> +#include "qvalueaxis_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +typedef QPair<qreal, qreal> Range; + +class QCategoryAxisPrivate : public QValueAxisPrivate +{ + Q_OBJECT + +public: + QCategoryAxisPrivate(QCategoryAxis *q); + ~QCategoryAxisPrivate(); + + void initializeGraphics(QGraphicsItem* parent); + int ticksCount() const; + +private: + QMap<QString , Range> m_categoriesMap; + QStringList m_categories; + qreal m_categoryMinimum; + +private: + Q_DECLARE_PUBLIC(QCategoryAxis) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QCATEGORYAXIS_P_H diff --git a/src/charts/axis/chartaxiselement.cpp b/src/charts/axis/chartaxiselement.cpp new file mode 100644 index 00000000..b7a60d27 --- /dev/null +++ b/src/charts/axis/chartaxiselement.cpp @@ -0,0 +1,404 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "chartaxiselement_p.h" +#include "qabstractaxis_p.h" +#include "chartpresenter_p.h" +#include "abstractchartlayout_p.h" +#include <qmath.h> +#include <QDateTime> +#include <QTextDocument> + +QT_CHARTS_BEGIN_NAMESPACE + +static const char *labelFormatMatchString = "%[\\-\\+#\\s\\d\\.lhjztL]*([dicuoxfegXFEG])"; +static const char *labelFormatMatchLocalizedString = "^([^%]*)%\\.(\\d+)([defgiEG])(.*)$"; +static QRegExp *labelFormatMatcher = 0; +static QRegExp *labelFormatMatcherLocalized = 0; +class StaticLabelFormatMatcherDeleter +{ +public: + StaticLabelFormatMatcherDeleter() {} + ~StaticLabelFormatMatcherDeleter() { + delete labelFormatMatcher; + delete labelFormatMatcherLocalized; + } +}; +static StaticLabelFormatMatcherDeleter staticLabelFormatMatcherDeleter; + +ChartAxisElement::ChartAxisElement(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis) + : ChartElement(item), + m_axis(axis), + m_animation(0), + m_grid(new QGraphicsItemGroup(item)), + m_arrow(new QGraphicsItemGroup(item)), + m_shades(new QGraphicsItemGroup(item)), + m_labels(new QGraphicsItemGroup(item)), + m_title(new QGraphicsTextItem(item)), + m_intervalAxis(intervalAxis) + +{ + //initial initialization + m_arrow->setHandlesChildEvents(false); + m_arrow->setZValue(ChartPresenter::AxisZValue); + m_labels->setZValue(ChartPresenter::AxisZValue); + m_shades->setZValue(ChartPresenter::ShadesZValue); + m_grid->setZValue(ChartPresenter::GridZValue); + m_title->setZValue(ChartPresenter::GridZValue); + m_title->document()->setDocumentMargin(ChartPresenter::textMargin()); + handleVisibleChanged(axis->isVisible()); + connectSlots(); + + setFlag(QGraphicsItem::ItemHasNoContents, true); +} + +ChartAxisElement::~ChartAxisElement() +{ +} + +void ChartAxisElement::connectSlots() +{ + QObject::connect(axis(), SIGNAL(visibleChanged(bool)), this, SLOT(handleVisibleChanged(bool))); + QObject::connect(axis(), SIGNAL(lineVisibleChanged(bool)), this, SLOT(handleArrowVisibleChanged(bool))); + QObject::connect(axis(), SIGNAL(gridVisibleChanged(bool)), this, SLOT(handleGridVisibleChanged(bool))); + QObject::connect(axis(), SIGNAL(labelsVisibleChanged(bool)), this, SLOT(handleLabelsVisibleChanged(bool))); + QObject::connect(axis(), SIGNAL(shadesVisibleChanged(bool)), this, SLOT(handleShadesVisibleChanged(bool))); + QObject::connect(axis(), SIGNAL(labelsAngleChanged(int)), this, SLOT(handleLabelsAngleChanged(int))); + QObject::connect(axis(), SIGNAL(linePenChanged(const QPen&)), this, SLOT(handleArrowPenChanged(const QPen&))); + QObject::connect(axis(), SIGNAL(labelsPenChanged(const QPen&)), this, SLOT(handleLabelsPenChanged(const QPen&))); + QObject::connect(axis(), SIGNAL(labelsBrushChanged(const QBrush&)), this, SLOT(handleLabelsBrushChanged(const QBrush&))); + QObject::connect(axis(), SIGNAL(labelsFontChanged(const QFont&)), this, SLOT(handleLabelsFontChanged(const QFont&))); + QObject::connect(axis(), SIGNAL(gridLinePenChanged(const QPen&)), this, SLOT(handleGridPenChanged(const QPen&))); + QObject::connect(axis(), SIGNAL(shadesPenChanged(const QPen&)), this, SLOT(handleShadesPenChanged(const QPen&))); + QObject::connect(axis(), SIGNAL(shadesBrushChanged(const QBrush&)), this, SLOT(handleShadesBrushChanged(const QBrush&))); + QObject::connect(axis(), SIGNAL(titleTextChanged(const QString&)), this, SLOT(handleTitleTextChanged(const QString&))); + QObject::connect(axis(), SIGNAL(titleFontChanged(const QFont&)), this, SLOT(handleTitleFontChanged(const QFont&))); + QObject::connect(axis(), SIGNAL(titlePenChanged(const QPen&)), this, SLOT(handleTitlePenChanged(const QPen&))); + QObject::connect(axis(), SIGNAL(titleBrushChanged(const QBrush&)), this, SLOT(handleTitleBrushChanged(const QBrush&))); + QObject::connect(axis(), SIGNAL(titleVisibleChanged(bool)), this, SLOT(handleTitleVisibleChanged(bool))); + QObject::connect(axis()->d_ptr.data(), SIGNAL(rangeChanged(qreal, qreal)), this, SLOT(handleRangeChanged(qreal, qreal))); +} + +void ChartAxisElement::handleArrowVisibleChanged(bool visible) +{ + m_arrow->setVisible(visible); +} + +void ChartAxisElement::handleGridVisibleChanged(bool visible) +{ + m_grid->setVisible(visible); +} + +void ChartAxisElement::handleLabelsVisibleChanged(bool visible) +{ + QGraphicsLayoutItem::updateGeometry(); + presenter()->layout()->invalidate(); + m_labels->setVisible(visible); +} + +void ChartAxisElement::handleShadesVisibleChanged(bool visible) +{ + m_shades->setVisible(visible); +} + +void ChartAxisElement::handleTitleVisibleChanged(bool visible) +{ + QGraphicsLayoutItem::updateGeometry(); + presenter()->layout()->invalidate(); + m_title->setVisible(visible); +} + +void ChartAxisElement::handleLabelsAngleChanged(int angle) +{ + foreach (QGraphicsItem *item, m_labels->childItems()) + item->setRotation(angle); + + QGraphicsLayoutItem::updateGeometry(); + presenter()->layout()->invalidate(); +} + +void ChartAxisElement::handleLabelsPenChanged(const QPen &pen) +{ + Q_UNUSED(pen) +} + +void ChartAxisElement::handleLabelsBrushChanged(const QBrush &brush) +{ + foreach (QGraphicsItem *item, m_labels->childItems()) + static_cast<QGraphicsTextItem *>(item)->setDefaultTextColor(brush.color()); +} + +void ChartAxisElement::handleLabelsFontChanged(const QFont &font) +{ + foreach (QGraphicsItem *item, m_labels->childItems()) + static_cast<QGraphicsTextItem *>(item)->setFont(font); + QGraphicsLayoutItem::updateGeometry(); + presenter()->layout()->invalidate(); +} + +void ChartAxisElement::handleTitleTextChanged(const QString &title) +{ + QGraphicsLayoutItem::updateGeometry(); + presenter()->layout()->invalidate(); + if (title.isEmpty() || !m_title->isVisible()) + m_title->setHtml(title); +} + +void ChartAxisElement::handleTitlePenChanged(const QPen &pen) +{ + Q_UNUSED(pen) +} + +void ChartAxisElement::handleTitleBrushChanged(const QBrush &brush) +{ + m_title->setDefaultTextColor(brush.color()); +} + +void ChartAxisElement::handleTitleFontChanged(const QFont &font) +{ + if (m_title->font() != font) { + m_title->setFont(font); + QGraphicsLayoutItem::updateGeometry(); + presenter()->layout()->invalidate(); + } +} + +void ChartAxisElement::handleVisibleChanged(bool visible) +{ + setVisible(visible); + if (!visible) { + m_grid->setVisible(visible); + m_arrow->setVisible(visible); + m_shades->setVisible(visible); + m_labels->setVisible(visible); + m_title->setVisible(visible); + } else { + m_grid->setVisible(axis()->isGridLineVisible()); + m_arrow->setVisible(axis()->isLineVisible()); + m_shades->setVisible(axis()->shadesVisible()); + m_labels->setVisible(axis()->labelsVisible()); + m_title->setVisible(axis()->isTitleVisible()); + } + + if (presenter()) presenter()->layout()->invalidate(); +} + +void ChartAxisElement::handleRangeChanged(qreal min, qreal max) +{ + Q_UNUSED(min); + Q_UNUSED(max); + + if (!isEmpty()) { + QVector<qreal> layout = calculateLayout(); + updateLayout(layout); + QSizeF before = effectiveSizeHint(Qt::PreferredSize); + QSizeF after = sizeHint(Qt::PreferredSize); + + if (before != after) { + QGraphicsLayoutItem::updateGeometry(); + // We don't want to call invalidate on layout, since it will change minimum size of + // component, which we would like to avoid since it causes nasty flips when scrolling + // or zooming, instead recalculate layout and use plotArea for extra space. + presenter()->layout()->setGeometry(presenter()->layout()->geometry()); + } + } +} + +bool ChartAxisElement::isEmpty() +{ + return axisGeometry().isEmpty() + || gridGeometry().isEmpty() + || qFuzzyCompare(min(), max()); +} + +qreal ChartAxisElement::min() const +{ + return m_axis->d_ptr->min(); +} + +qreal ChartAxisElement::max() const +{ + return m_axis->d_ptr->max(); +} + +QString ChartAxisElement::formatLabel(const QString &formatSpec, const QByteArray &array, + qreal value, int precision, const QString &preStr, + const QString &postStr) const +{ + QString retVal; + if (!formatSpec.isEmpty()) { + if (formatSpec.at(0) == QLatin1Char('d') + || formatSpec.at(0) == QLatin1Char('i') + || formatSpec.at(0) == QLatin1Char('c')) { + if (presenter()->localizeNumbers()) + retVal = preStr + presenter()->locale().toString(qint64(value)) + postStr; + else + retVal = QString().sprintf(array, qint64(value)); + } else if (formatSpec.at(0) == QLatin1Char('u') + || formatSpec.at(0) == QLatin1Char('o') + || formatSpec.at(0) == QLatin1Char('x') + || formatSpec.at(0) == QLatin1Char('X')) { + // These formats are not supported by localized numbers + retVal = QString().sprintf(array, quint64(value)); + } else if (formatSpec.at(0) == QLatin1Char('f') + || formatSpec.at(0) == QLatin1Char('F') + || formatSpec.at(0) == QLatin1Char('e') + || formatSpec.at(0) == QLatin1Char('E') + || formatSpec.at(0) == QLatin1Char('g') + || formatSpec.at(0) == QLatin1Char('G')) { + if (presenter()->localizeNumbers()) { + retVal = preStr + + presenter()->locale().toString(value, formatSpec.at(0).toLatin1(), + precision) + + postStr; + } else { + retVal = QString().sprintf(array, value); + } + } + } + return retVal; +} + +QStringList ChartAxisElement::createValueLabels(qreal min, qreal max, int ticks, + const QString &format) const +{ + QStringList labels; + + if (max <= min || ticks < 1) + return labels; + + if (format.isNull()) { + int n = qMax(int(-qFloor(log10((max - min) / (ticks - 1)))), 0) + 1; + for (int i = 0; i < ticks; i++) { + qreal value = min + (i * (max - min) / (ticks - 1)); + labels << presenter()->numberToString(value, 'f', n); + } + } else { + QByteArray array = format.toLatin1(); + QString formatSpec; + QString preStr; + QString postStr; + int precision = 6; // Six is the default precision in Qt API + if (presenter()->localizeNumbers()) { + if (!labelFormatMatcherLocalized) + labelFormatMatcherLocalized + = new QRegExp(QString::fromLatin1(labelFormatMatchLocalizedString)); + if (labelFormatMatcherLocalized->indexIn(format, 0) != -1) { + preStr = labelFormatMatcherLocalized->cap(1); + if (!labelFormatMatcherLocalized->cap(2).isEmpty()) + precision = labelFormatMatcherLocalized->cap(2).toInt(); + formatSpec = labelFormatMatcherLocalized->cap(3); + postStr = labelFormatMatcherLocalized->cap(4); + } + } else { + if (!labelFormatMatcher) + labelFormatMatcher = new QRegExp(QString::fromLatin1(labelFormatMatchString)); + if (labelFormatMatcher->indexIn(format, 0) != -1) + formatSpec = labelFormatMatcher->cap(1); + } + for (int i = 0; i < ticks; i++) { + qreal value = min + (i * (max - min) / (ticks - 1)); + labels << formatLabel(formatSpec, array, value, precision, preStr, postStr); + } + } + + return labels; +} + +QStringList ChartAxisElement::createLogValueLabels(qreal min, qreal max, qreal base, int ticks, + const QString &format) const +{ + QStringList labels; + + if (max <= min || ticks < 1) + return labels; + + int firstTick; + if (base > 1) + firstTick = ceil(log10(min) / log10(base)); + else + firstTick = ceil(log10(max) / log10(base)); + + if (format.isNull()) { + int n = 0; + if (ticks > 1) + n = qMax(int(-qFloor(log10((max - min) / (ticks - 1)))), 0); + n++; + for (int i = firstTick; i < ticks + firstTick; i++) { + qreal value = qPow(base, i); + labels << presenter()->numberToString(value, 'f', n); + } + } else { + QByteArray array = format.toLatin1(); + QString formatSpec; + QString preStr; + QString postStr; + int precision = 6; // Six is the default precision in Qt API + if (presenter()->localizeNumbers()) { + if (!labelFormatMatcherLocalized) + labelFormatMatcherLocalized = + new QRegExp(QString::fromLatin1(labelFormatMatchLocalizedString)); + if (labelFormatMatcherLocalized->indexIn(format, 0) != -1) { + preStr = labelFormatMatcherLocalized->cap(1); + if (!labelFormatMatcherLocalized->cap(2).isEmpty()) + precision = labelFormatMatcherLocalized->cap(2).toInt(); + formatSpec = labelFormatMatcherLocalized->cap(3); + postStr = labelFormatMatcherLocalized->cap(4); + } + } else { + if (!labelFormatMatcher) + labelFormatMatcher = new QRegExp(QString::fromLatin1(labelFormatMatchString)); + if (labelFormatMatcher->indexIn(format, 0) != -1) + formatSpec = labelFormatMatcher->cap(1); + } + for (int i = firstTick; i < ticks + firstTick; i++) { + qreal value = qPow(base, i); + labels << formatLabel(formatSpec, array, value, precision, preStr, postStr); + } + } + + return labels; +} + +QStringList ChartAxisElement::createDateTimeLabels(qreal min, qreal max,int ticks, + const QString &format) const +{ + QStringList labels; + + if (max <= min || ticks < 1) + return labels; + + int n = qMax(int(-floor(log10((max - min) / (ticks - 1)))), 0); + n++; + for (int i = 0; i < ticks; i++) { + qreal value = min + (i * (max - min) / (ticks - 1)); + labels << presenter()->locale().toString(QDateTime::fromMSecsSinceEpoch(value), format); + } + return labels; +} + +void ChartAxisElement::axisSelected() +{ + emit clicked(); +} + +#include "moc_chartaxiselement_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/chartaxiselement_p.h b/src/charts/axis/chartaxiselement_p.h new file mode 100644 index 00000000..1cfac64d --- /dev/null +++ b/src/charts/axis/chartaxiselement_p.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef CHARTAXISELEMENT_H +#define CHARTAXISELEMENT_H + +#include "qchartglobal.h" +#include "chartelement_p.h" +#include "axisanimation_p.h" +#include <QGraphicsItem> +#include <QGraphicsLayoutItem> +#include <QFont> + +QT_CHARTS_BEGIN_NAMESPACE + +class ChartPresenter; +class QAbstractAxis; + +class ChartAxisElement : public ChartElement, public QGraphicsLayoutItem +{ + Q_OBJECT + + using QGraphicsLayoutItem::setGeometry; +public: + ChartAxisElement(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis = false); + ~ChartAxisElement(); + + virtual QRectF gridGeometry() const = 0; + virtual void setGeometry(const QRectF &axis, const QRectF &grid) = 0; + virtual bool isEmpty() = 0; + + void setAnimation(AxisAnimation *animation) { m_animation = animation; } + AxisAnimation *animation() const { return m_animation; } + + QAbstractAxis *axis() const { return m_axis; } + void setLayout(QVector<qreal> &layout) { m_layout = layout; } + QVector<qreal> &layout() { return m_layout; } // Modifiable reference + inline qreal labelPadding() const { return qreal(4.0); } + inline qreal titlePadding() const { return qreal(2.0); } + void setLabels(const QStringList &labels) { m_labelsList = labels; } + QStringList labels() const { return m_labelsList; } + + qreal min() const; + qreal max() const; + + QRectF axisGeometry() const { return m_axisRect; } + void setAxisGeometry(const QRectF &axisGeometry) { m_axisRect = axisGeometry; } + + void axisSelected(); + + //this flag indicates that axis is used to show intervals it means labels are in between ticks + bool intervalAxis() const { return m_intervalAxis; } + + QStringList createValueLabels(qreal max, qreal min, int ticks, const QString &format) const; + QStringList createLogValueLabels(qreal min, qreal max, qreal base, int ticks, + const QString &format) const; + QStringList createDateTimeLabels(qreal max, qreal min, int ticks, const QString &format) const; + + // from QGraphicsLayoutItem + QRectF boundingRect() const + { + return QRectF(); + } + + // from QGraphicsLayoutItem + void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) + { + } + +protected: + virtual QVector<qreal> calculateLayout() const = 0; + virtual void updateLayout(QVector<qreal> &layout) = 0; + + QList<QGraphicsItem *> gridItems() { return m_grid->childItems(); } + QList<QGraphicsItem *> labelItems() { return m_labels->childItems(); } + QList<QGraphicsItem *> shadeItems() { return m_shades->childItems(); } + QList<QGraphicsItem *> arrowItems() { return m_arrow->childItems(); } + QGraphicsTextItem *titleItem() const { return m_title.data(); } + QGraphicsItemGroup *gridGroup() { return m_grid.data(); } + QGraphicsItemGroup *labelGroup() { return m_labels.data(); } + QGraphicsItemGroup *shadeGroup() { return m_shades.data(); } + QGraphicsItemGroup *arrowGroup() { return m_arrow.data(); } + +public Q_SLOTS: + void handleVisibleChanged(bool visible); + void handleArrowVisibleChanged(bool visible); + void handleGridVisibleChanged(bool visible); + void handleLabelsVisibleChanged(bool visible); + void handleShadesVisibleChanged(bool visible); + void handleLabelsAngleChanged(int angle); + virtual void handleShadesBrushChanged(const QBrush &brush) = 0; + virtual void handleShadesPenChanged(const QPen &pen) = 0; + virtual void handleArrowPenChanged(const QPen &pen) = 0; + virtual void handleGridPenChanged(const QPen &pen) = 0; + void handleLabelsPenChanged(const QPen &pen); + void handleLabelsBrushChanged(const QBrush &brush); + void handleLabelsFontChanged(const QFont &font); + void handleTitlePenChanged(const QPen &pen); + void handleTitleBrushChanged(const QBrush &brush); + void handleTitleFontChanged(const QFont &font); + void handleTitleTextChanged(const QString &title); + void handleTitleVisibleChanged(bool visible); + void handleRangeChanged(qreal min, qreal max); + +Q_SIGNALS: + void clicked(); + +private: + void connectSlots(); + QString formatLabel(const QString &formatSpec, const QByteArray &array, + qreal value, int precision, const QString &preStr, + const QString &postStr) const; + + QAbstractAxis *m_axis; + AxisAnimation *m_animation; + QVector<qreal> m_layout; + QStringList m_labelsList; + QRectF m_axisRect; + QScopedPointer<QGraphicsItemGroup> m_grid; + QScopedPointer<QGraphicsItemGroup> m_arrow; + QScopedPointer<QGraphicsItemGroup> m_shades; + QScopedPointer<QGraphicsItemGroup> m_labels; + QScopedPointer<QGraphicsTextItem> m_title; + bool m_intervalAxis; +}; + +QT_CHARTS_END_NAMESPACE + +#endif /* CHARTAXISELEMENT_H */ diff --git a/src/charts/axis/datetimeaxis/chartdatetimeaxisx.cpp b/src/charts/axis/datetimeaxis/chartdatetimeaxisx.cpp new file mode 100644 index 00000000..bdd010a0 --- /dev/null +++ b/src/charts/axis/datetimeaxis/chartdatetimeaxisx.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "chartdatetimeaxisx_p.h" +#include "chartpresenter_p.h" +#include "qdatetimeaxis.h" +#include "abstractchartlayout_p.h" +#include <QGraphicsLayout> +#include <QDateTime> +#include <qmath.h> + +QT_CHARTS_BEGIN_NAMESPACE + +ChartDateTimeAxisX::ChartDateTimeAxisX(QDateTimeAxis *axis, QGraphicsItem *item) + : HorizontalAxis(axis, item), + m_axis(axis) +{ + QObject::connect(m_axis, SIGNAL(tickCountChanged(int)), this, SLOT(handleTickCountChanged(int))); + QObject::connect(m_axis, SIGNAL(formatChanged(QString)), this, SLOT(handleFormatChanged(QString))); +} + +ChartDateTimeAxisX::~ChartDateTimeAxisX() +{ +} + +QVector<qreal> ChartDateTimeAxisX::calculateLayout() const +{ + int tickCount = m_axis->tickCount(); + + Q_ASSERT(tickCount >= 2); + + QVector<qreal> points; + points.resize(tickCount); + const QRectF &gridRect = gridGeometry(); + const qreal deltaX = gridRect.width() / (qreal(tickCount) - 1.0); + for (int i = 0; i < tickCount; ++i) + points[i] = qreal(i) * deltaX + gridRect.left(); + return points; +} + +void ChartDateTimeAxisX::updateGeometry() +{ + const QVector<qreal>& layout = ChartAxisElement::layout(); + if (layout.isEmpty()) + return; + setLabels(createDateTimeLabels(min(), max(), layout.size(), m_axis->format())); + HorizontalAxis::updateGeometry(); +} + +void ChartDateTimeAxisX::handleTickCountChanged(int tick) +{ + Q_UNUSED(tick) + QGraphicsLayoutItem::updateGeometry(); + if (presenter()) + presenter()->layout()->invalidate(); +} + +void ChartDateTimeAxisX::handleFormatChanged(const QString &format) +{ + Q_UNUSED(format); + QGraphicsLayoutItem::updateGeometry(); + if (presenter()) + presenter()->layout()->invalidate(); +} + +QSizeF ChartDateTimeAxisX::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const +{ + Q_UNUSED(constraint) + + QSizeF sh; + + QSizeF base = HorizontalAxis::sizeHint(which, constraint); + QStringList ticksList = createDateTimeLabels(min(), max(), m_axis->tickCount(), m_axis->format()); + // Width of horizontal axis sizeHint indicates the maximum distance labels can extend past + // first and last ticks. Base width is irrelevant. + qreal width = 0; + qreal height = 0; + + if (ticksList.empty()) + return sh; + + switch (which) { + case Qt::MinimumSize: { + QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), + QStringLiteral("..."), + axis()->labelsAngle()); + width = boundingRect.width() / 2.0; + height = boundingRect.height() + labelPadding() + base.height() + 1.0; + sh = QSizeF(width, height); + break; + } + case Qt::PreferredSize: { + qreal labelHeight = 0.0; + qreal firstWidth = -1.0; + foreach (const QString& s, ticksList) { + QRectF rect = ChartPresenter::textBoundingRect(axis()->labelsFont(), s, axis()->labelsAngle()); + labelHeight = qMax(rect.height(), labelHeight); + width = rect.width(); + if (firstWidth < 0.0) + firstWidth = width; + } + height = labelHeight + labelPadding() + base.height() + 1.0; + width = qMax(width, firstWidth) / 2.0; + sh = QSizeF(width, height); + break; + } + default: + break; + } + + return sh; +} + +#include "moc_chartdatetimeaxisx_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/datetimeaxis/chartdatetimeaxisx_p.h b/src/charts/axis/datetimeaxis/chartdatetimeaxisx_p.h new file mode 100644 index 00000000..3ca2ef45 --- /dev/null +++ b/src/charts/axis/datetimeaxis/chartdatetimeaxisx_p.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef CHARTDATETIMEAXISX_H +#define CHARTDATETIMEAXISX_H + +#include "horizontalaxis_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QDateTimeAxis; + +class ChartDateTimeAxisX : public HorizontalAxis +{ + Q_OBJECT +public: + ChartDateTimeAxisX(QDateTimeAxis *axis, QGraphicsItem* item = 0); + ~ChartDateTimeAxisX(); + + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const; +protected: + QVector<qreal> calculateLayout() const; + void updateGeometry(); +private Q_SLOTS: + void handleTickCountChanged(int tick); + void handleFormatChanged(const QString &format); + +private: + QDateTimeAxis *m_axis; +}; + +QT_CHARTS_END_NAMESPACE + +#endif /* CHARTDATETIMEAXISX_H */ diff --git a/src/charts/axis/datetimeaxis/chartdatetimeaxisy.cpp b/src/charts/axis/datetimeaxis/chartdatetimeaxisy.cpp new file mode 100644 index 00000000..5e67936b --- /dev/null +++ b/src/charts/axis/datetimeaxis/chartdatetimeaxisy.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "chartdatetimeaxisy_p.h" +#include "chartpresenter_p.h" +#include "qdatetimeaxis.h" +#include "abstractchartlayout_p.h" +#include <QGraphicsLayout> +#include <QDateTime> +#include <qmath.h> + +QT_CHARTS_BEGIN_NAMESPACE + +ChartDateTimeAxisY::ChartDateTimeAxisY(QDateTimeAxis *axis, QGraphicsItem *item) + : VerticalAxis(axis, item), + m_axis(axis) +{ + QObject::connect(m_axis, SIGNAL(tickCountChanged(int)), this, SLOT(handleTickCountChanged(int))); + QObject::connect(m_axis, SIGNAL(formatChanged(QString)), this, SLOT(handleFormatChanged(QString))); +} + +ChartDateTimeAxisY::~ChartDateTimeAxisY() +{ +} + +QVector<qreal> ChartDateTimeAxisY::calculateLayout() const +{ + int tickCount = m_axis->tickCount(); + + Q_ASSERT(tickCount >= 2); + + QVector<qreal> points; + points.resize(tickCount); + const QRectF &gridRect = gridGeometry(); + const qreal deltaY = gridRect.height() / (qreal(tickCount) - 1.0); + for (int i = 0; i < tickCount; ++i) + points[i] = qreal(i) * -deltaY + gridRect.bottom(); + + return points; +} + +void ChartDateTimeAxisY::updateGeometry() +{ + const QVector<qreal> &layout = ChartAxisElement::layout(); + if (layout.isEmpty()) + return; + setLabels(createDateTimeLabels(min(), max(), layout.size(), m_axis->format())); + VerticalAxis::updateGeometry(); +} + +void ChartDateTimeAxisY::handleTickCountChanged(int tick) +{ + Q_UNUSED(tick) + QGraphicsLayoutItem::updateGeometry(); + if (presenter()) + presenter()->layout()->invalidate(); +} + +void ChartDateTimeAxisY::handleFormatChanged(const QString &format) +{ + Q_UNUSED(format); + QGraphicsLayoutItem::updateGeometry(); + if (presenter()) + presenter()->layout()->invalidate(); +} + +QSizeF ChartDateTimeAxisY::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const +{ + Q_UNUSED(constraint) + + QSizeF sh; + + QSizeF base = VerticalAxis::sizeHint(which, constraint); + QStringList ticksList = createDateTimeLabels(min(), max(), m_axis->tickCount(), m_axis->format()); + qreal width = 0; + // Height of vertical axis sizeHint indicates the maximum distance labels can extend past + // first and last ticks. Base height is irrelevant. + qreal height = 0; + + if (ticksList.empty()) + return sh; + + switch (which) { + case Qt::MinimumSize: { + QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), + QStringLiteral("..."), + axis()->labelsAngle()); + width = boundingRect.width() + labelPadding() + base.width() + 1.0; + height = boundingRect.height() / 2.0; + sh = QSizeF(width, height); + break; + } + case Qt::PreferredSize: { + qreal labelWidth = 0.0; + qreal firstHeight = -1.0; + foreach (const QString& s, ticksList) { + QRectF rect = ChartPresenter::textBoundingRect(axis()->labelsFont(), s, axis()->labelsAngle()); + labelWidth = qMax(rect.width(), labelWidth); + height = rect.height(); + if (firstHeight < 0.0) + firstHeight = height; + } + width = labelWidth + labelPadding() + base.width() + 2.0; //two pixels of tolerance + height = qMax(height, firstHeight) / 2.0; + sh = QSizeF(width, height); + break; + } + default: + break; + } + + return sh; +} + +#include "moc_chartdatetimeaxisy_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/datetimeaxis/chartdatetimeaxisy_p.h b/src/charts/axis/datetimeaxis/chartdatetimeaxisy_p.h new file mode 100644 index 00000000..0631e157 --- /dev/null +++ b/src/charts/axis/datetimeaxis/chartdatetimeaxisy_p.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef CHARTDATETIMEAXISY_H +#define CHARTDATETIMEAXISY_H + +#include "verticalaxis_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QDateTimeAxis; + +class ChartDateTimeAxisY : public VerticalAxis +{ + Q_OBJECT +public: + ChartDateTimeAxisY(QDateTimeAxis *axis, QGraphicsItem* item = 0); + ~ChartDateTimeAxisY(); + + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const; +protected: + QVector<qreal> calculateLayout() const; + void updateGeometry(); +private Q_SLOTS: + void handleTickCountChanged(int tick); + void handleFormatChanged(const QString &format); + +private: + QDateTimeAxis *m_axis; +}; + +QT_CHARTS_END_NAMESPACE + +#endif /* CHARTDATETIMEAXISY_H */ diff --git a/src/charts/axis/datetimeaxis/polarchartdatetimeaxisangular.cpp b/src/charts/axis/datetimeaxis/polarchartdatetimeaxisangular.cpp new file mode 100644 index 00000000..4ace5de6 --- /dev/null +++ b/src/charts/axis/datetimeaxis/polarchartdatetimeaxisangular.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "polarchartdatetimeaxisangular_p.h" +#include "chartpresenter_p.h" +#include "abstractchartlayout_p.h" +#include "qdatetimeaxis.h" + +QT_CHARTS_BEGIN_NAMESPACE + +PolarChartDateTimeAxisAngular::PolarChartDateTimeAxisAngular(QDateTimeAxis *axis, QGraphicsItem *item) + : PolarChartAxisAngular(axis, item) +{ + QObject::connect(axis, SIGNAL(tickCountChanged(int)), this, SLOT(handleTickCountChanged(int))); + QObject::connect(axis, SIGNAL(formatChanged(QString)), this, SLOT(handleFormatChanged(QString))); +} + +PolarChartDateTimeAxisAngular::~PolarChartDateTimeAxisAngular() +{ +} + +QVector<qreal> PolarChartDateTimeAxisAngular::calculateLayout() const +{ + int tickCount = static_cast<QDateTimeAxis *>(axis())->tickCount(); + Q_ASSERT(tickCount >= 2); + + QVector<qreal> points; + points.resize(tickCount); + + const qreal d = 360.0 / qreal(tickCount - 1); + + for (int i = 0; i < tickCount; ++i) { + qreal angularCoordinate = qreal(i) * d; + points[i] = angularCoordinate; + } + + return points; +} +void PolarChartDateTimeAxisAngular::createAxisLabels(const QVector<qreal> &layout) +{ + QStringList labelList = createDateTimeLabels(min(), max(), layout.size(), static_cast<QDateTimeAxis *>(axis())->format()); + setLabels(labelList); +} + +void PolarChartDateTimeAxisAngular::handleTickCountChanged(int tick) +{ + Q_UNUSED(tick); + QGraphicsLayoutItem::updateGeometry(); + if (presenter()) + presenter()->layout()->invalidate(); +} + +void PolarChartDateTimeAxisAngular::handleFormatChanged(const QString &format) +{ + Q_UNUSED(format); + QGraphicsLayoutItem::updateGeometry(); + if (presenter()) + presenter()->layout()->invalidate(); +} + +#include "moc_polarchartdatetimeaxisangular_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/datetimeaxis/polarchartdatetimeaxisangular_p.h b/src/charts/axis/datetimeaxis/polarchartdatetimeaxisangular_p.h new file mode 100644 index 00000000..bbfd8260 --- /dev/null +++ b/src/charts/axis/datetimeaxis/polarchartdatetimeaxisangular_p.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef POLARCHARTDATETIMEAXISANGULAR_P_H +#define POLARCHARTDATETIMEAXISANGULAR_P_H + +#include "polarchartaxisangular_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QDateTimeAxis; + +class PolarChartDateTimeAxisAngular : public PolarChartAxisAngular +{ + Q_OBJECT +public: + PolarChartDateTimeAxisAngular(QDateTimeAxis *axis, QGraphicsItem *item); + ~PolarChartDateTimeAxisAngular(); + + virtual QVector<qreal> calculateLayout() const; + virtual void createAxisLabels(const QVector<qreal> &layout); + +private Q_SLOTS: + void handleTickCountChanged(int tick); + void handleFormatChanged(const QString &format); +}; + +QT_CHARTS_END_NAMESPACE + +#endif // POLARCHARTDATETIMEAXISANGULAR_P_H diff --git a/src/charts/axis/datetimeaxis/polarchartdatetimeaxisradial.cpp b/src/charts/axis/datetimeaxis/polarchartdatetimeaxisradial.cpp new file mode 100644 index 00000000..fdcfcc36 --- /dev/null +++ b/src/charts/axis/datetimeaxis/polarchartdatetimeaxisradial.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "polarchartdatetimeaxisradial_p.h" +#include "chartpresenter_p.h" +#include "abstractchartlayout_p.h" +#include "qdatetimeaxis.h" + +QT_CHARTS_BEGIN_NAMESPACE + +PolarChartDateTimeAxisRadial::PolarChartDateTimeAxisRadial(QDateTimeAxis *axis, QGraphicsItem *item) + : PolarChartAxisRadial(axis, item) +{ + QObject::connect(axis, SIGNAL(tickCountChanged(int)), this, SLOT(handleTickCountChanged(int))); + QObject::connect(axis, SIGNAL(formatChanged(QString)), this, SLOT(handleFormatChanged(QString))); +} + +PolarChartDateTimeAxisRadial::~PolarChartDateTimeAxisRadial() +{ +} + +QVector<qreal> PolarChartDateTimeAxisRadial::calculateLayout() const +{ + int tickCount = static_cast<QDateTimeAxis *>(axis())->tickCount(); + Q_ASSERT(tickCount >= 2); + + QVector<qreal> points; + points.resize(tickCount); + + const qreal d = (axisGeometry().width() / 2) / qreal(tickCount - 1); + + for (int i = 0; i < tickCount; ++i) { + qreal radialCoordinate = qreal(i) * d; + points[i] = radialCoordinate; + } + + return points; +} +void PolarChartDateTimeAxisRadial::createAxisLabels(const QVector<qreal> &layout) +{ + setLabels(createDateTimeLabels(min(), max(), layout.size(), static_cast<QDateTimeAxis *>(axis())->format())); +} + +void PolarChartDateTimeAxisRadial::handleTickCountChanged(int tick) +{ + Q_UNUSED(tick); + QGraphicsLayoutItem::updateGeometry(); + if (presenter()) + presenter()->layout()->invalidate(); +} + +void PolarChartDateTimeAxisRadial::handleFormatChanged(const QString &format) +{ + Q_UNUSED(format); + QGraphicsLayoutItem::updateGeometry(); + if (presenter()) + presenter()->layout()->invalidate(); +} + +#include "moc_polarchartdatetimeaxisradial_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/datetimeaxis/polarchartdatetimeaxisradial_p.h b/src/charts/axis/datetimeaxis/polarchartdatetimeaxisradial_p.h new file mode 100644 index 00000000..207d5a3a --- /dev/null +++ b/src/charts/axis/datetimeaxis/polarchartdatetimeaxisradial_p.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef POLARCHARTDATETIMEAXISRADIAL_P_H +#define POLARCHARTDATETIMEAXISRADIAL_P_H + +#include "polarchartaxisradial_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QDateTimeAxis; + +class PolarChartDateTimeAxisRadial : public PolarChartAxisRadial +{ + Q_OBJECT +public: + PolarChartDateTimeAxisRadial(QDateTimeAxis *axis, QGraphicsItem *item); + ~PolarChartDateTimeAxisRadial(); + + virtual QVector<qreal> calculateLayout() const; + virtual void createAxisLabels(const QVector<qreal> &layout); + +private Q_SLOTS: + void handleTickCountChanged(int tick); + void handleFormatChanged(const QString &format); +}; + +QT_CHARTS_END_NAMESPACE + +#endif // POLARCHARTDATETIMEAXISRADIAL_P_H diff --git a/src/charts/axis/datetimeaxis/qdatetimeaxis.cpp b/src/charts/axis/datetimeaxis/qdatetimeaxis.cpp new file mode 100644 index 00000000..fffd80c2 --- /dev/null +++ b/src/charts/axis/datetimeaxis/qdatetimeaxis.cpp @@ -0,0 +1,390 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdatetimeaxis.h" +#include "qdatetimeaxis_p.h" +#include "chartdatetimeaxisx_p.h" +#include "chartdatetimeaxisy_p.h" +#include "polarchartdatetimeaxisangular_p.h" +#include "polarchartdatetimeaxisradial_p.h" +#include "abstractdomain_p.h" +#include "qchart.h" +#include <float.h> +#include <cmath> + +QT_CHARTS_BEGIN_NAMESPACE +/*! + \class QDateTimeAxis + \inmodule Qt Charts + \brief The QDateTimeAxis class is used for manipulating chart's axis. + \mainclass + + The labels can be configured by setting an appropriate DateTime format. + QDateTimeAxis works correctly with dates from 4714 BCE to 287396 CE. + There are also other limitiation related to QDateTime. Please refer to QDateTime documentation. + QDateTimeAxis can be setup to show axis line with tick marks, grid lines and shades. + + Note: QDateTimeAxis is disabled on ARM architecture. + + \image api_datatime_axis.png + + QDateTimeAxis can be used with any QXYSeries. + To add a data point to the series QDateTime::toMSecsSinceEpoch() is used. + \code + QLineSeries *series = new QLineSeries; + + QDateTime xValue; + xValue.setDate(QDate(2012, 1 , 18)); + xValue.setTime(QTime(9, 34)); + qreal yValue = 12; + series->append(xValue.toMSecsSinceEpoch(), yValue); + + xValue.setDate(QDate(2013, 5 , 11)); + xValue.setTime(QTime(11, 14)); + qreal yValue = 22; + series->append(xValue.toMSecsSinceEpoch(), yValue); + \endcode + + Adding the series to the chart and setting up the QDateTimeAxis. + \code + QChartView *chartView = new QChartView; + chartView->chart()->addSeries(series); + + // ... + QDateTimeAxis *axisX = new QDateTimeAxis; + axisX->setFormat("dd-MM-yyyy h:mm"); + chartView->chart()->setAxisX(axisX, series); + \endcode +*/ + +/*! + \qmltype DateTimeAxis + \instantiates QDateTimeAxis + \inqmlmodule QtCharts + + \brief The DateTimeAxis element is used for manipulating chart's axes. + \inherits AbstractAxis + + The labels can be configured by setting an appropriate DateTime format. + Note that any date before 4714 BCE or after about 1.4 million CE may not be accurately stored. + DateTimeAxis can be setup to show axis line with tick marks, grid lines and shades. +*/ + +/*! + \property QDateTimeAxis::min + Defines the minimum value on the axis. + When setting this property the max is adjusted if necessary, to ensure that the range remains valid. +*/ +/*! + \qmlproperty datetime DateTimeAxis::min + Defines the minimum value on the axis. + When setting this property the max is adjusted if necessary, to ensure that the range remains valid. +*/ + +/*! + \property QDateTimeAxis::max + Defines the maximum value on the axis. + When setting this property the min is adjusted if necessary, to ensure that the range remains valid. +*/ +/*! + \qmlproperty datetime DateTimeAxis::max + Defines the maximum value on the axis. + When setting this property the min is adjusted if necessary, to ensure that the range remains valid. +*/ + +/*! + \fn void QDateTimeAxis::minChanged(QDateTime min) + Axis emits signal when \a min of axis has changed. +*/ +/*! + \qmlsignal DateTimeAxis::onMinChanged(datetime min) + Axis emits signal when \a min of axis has changed. +*/ + +/*! + \fn void QDateTimeAxis::maxChanged(QDateTime max) + Axis emits signal when \a max of axis has changed. +*/ +/*! + \qmlsignal DateTimeAxis::onMaxChanged(datetime max) + Axis emits signal when \a max of axis has changed. +*/ + +/*! + \fn void QDateTimeAxis::rangeChanged(QDateTime min, QDateTime max) + Axis emits signal when \a min or \a max of axis has changed. +*/ + +/*! + \property QDateTimeAxis::tickCount + The number of tick marks for the axis. +*/ + +/*! + \qmlproperty int DateTimeAxis::tickCount + The number of tick marks for the axis. +*/ + +/*! + \property QDateTimeAxis::format + The format string that is used when creating label for the axis out of a QDateTime object. + Check QDateTime documentation for information on how the string should be defined. + + \sa QChart::locale +*/ +/*! + \qmlproperty string DateTimeAxis::format + The format string that is used when creating label for the axis out of a QDateTime object. + Check QDateTime documentation for information on how the string should be defined. +*/ + +/*! + \fn void QDateTimeAxis::tickCountChanged(int tickCount) + Axis emits signal when \a tickCount number on axis have changed. +*/ +/*! + \qmlsignal DateTimeAxis::tickCountChanged(int tickCount) + Axis emits signal when \a tickCount number on axis have changed. +*/ + +/*! + \fn void QDateTimeAxis::formatChanged(QString format) + Axis emits signal when \a format of the axis has changed. +*/ +/*! + \qmlsignal DateTimeAxis::onFormatChanged(string format) + Axis emits signal when \a format of the axis has changed. +*/ + +/*! + Constructs an axis object which is a child of \a parent. +*/ +QDateTimeAxis::QDateTimeAxis(QObject *parent) : + QAbstractAxis(*new QDateTimeAxisPrivate(this), parent) +{ + +} + +/*! + \internal +*/ +QDateTimeAxis::QDateTimeAxis(QDateTimeAxisPrivate &d, QObject *parent) : QAbstractAxis(d, parent) +{ + +} + +/*! + Destroys the object. +*/ +QDateTimeAxis::~QDateTimeAxis() +{ + Q_D(QDateTimeAxis); + if (d->m_chart) + d->m_chart->removeAxis(this); +} + +void QDateTimeAxis::setMin(QDateTime min) +{ + Q_D(QDateTimeAxis); + if (min.isValid()) + d->setRange(min.toMSecsSinceEpoch(), qMax(d->m_max, qreal(min.toMSecsSinceEpoch()))); +} + +QDateTime QDateTimeAxis::min() const +{ + Q_D(const QDateTimeAxis); + return QDateTime::fromMSecsSinceEpoch(d->m_min); +} + +void QDateTimeAxis::setMax(QDateTime max) +{ + Q_D(QDateTimeAxis); + if (max.isValid()) + d->setRange(qMin(d->m_min, qreal(max.toMSecsSinceEpoch())), max.toMSecsSinceEpoch()); +} + +QDateTime QDateTimeAxis::max() const +{ + Q_D(const QDateTimeAxis); + return QDateTime::fromMSecsSinceEpoch(d->m_max); +} + +/*! + Sets range from \a min to \a max on the axis. + If min is greater than max then this function returns without making any changes. +*/ +void QDateTimeAxis::setRange(QDateTime min, QDateTime max) +{ + Q_D(QDateTimeAxis); + if (!min.isValid() || !max.isValid() || min > max) + return; + + d->setRange(min.toMSecsSinceEpoch(),max.toMSecsSinceEpoch()); +} + +void QDateTimeAxis::setFormat(QString format) +{ + Q_D(QDateTimeAxis); + if (d->m_format != format) { + d->m_format = format; + emit formatChanged(format); + } +} + +QString QDateTimeAxis::format() const +{ + Q_D(const QDateTimeAxis); + return d->m_format; +} + +/*! + Sets \a count for ticks on the axis. +*/ +void QDateTimeAxis::setTickCount(int count) +{ + Q_D(QDateTimeAxis); + if (d->m_tickCount != count && count >= 2) { + d->m_tickCount = count; + emit tickCountChanged(count); + } +} + +/*! + \fn int QDateTimeAxis::tickCount() const + Return number of ticks on the axis. +*/ +int QDateTimeAxis::tickCount() const +{ + Q_D(const QDateTimeAxis); + return d->m_tickCount; +} + +/*! + Returns the type of the axis. +*/ +QAbstractAxis::AxisType QDateTimeAxis::type() const +{ + return AxisTypeDateTime; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +QDateTimeAxisPrivate::QDateTimeAxisPrivate(QDateTimeAxis *q) + : QAbstractAxisPrivate(q), + m_min(0), + m_max(0), + m_tickCount(5) +{ + m_format = QStringLiteral("dd-MM-yyyy\nh:mm"); +} + +QDateTimeAxisPrivate::~QDateTimeAxisPrivate() +{ + +} + +void QDateTimeAxisPrivate::setRange(qreal min,qreal max) +{ + Q_Q(QDateTimeAxis); + + bool changed = false; + + if (m_min != min) { + m_min = min; + changed = true; + emit q->minChanged(QDateTime::fromMSecsSinceEpoch(min)); + } + + if (m_max != max) { + m_max = max; + changed = true; + emit q->maxChanged(QDateTime::fromMSecsSinceEpoch(max)); + } + + if (changed) { + emit q->rangeChanged(QDateTime::fromMSecsSinceEpoch(min), QDateTime::fromMSecsSinceEpoch(max)); + emit rangeChanged(m_min,m_max); + } +} + + +void QDateTimeAxisPrivate::setMin(const QVariant &min) +{ + Q_Q(QDateTimeAxis); + if (min.canConvert(QVariant::DateTime)) + q->setMin(min.toDateTime()); +} + +void QDateTimeAxisPrivate::setMax(const QVariant &max) +{ + + Q_Q(QDateTimeAxis); + if (max.canConvert(QVariant::DateTime)) + q->setMax(max.toDateTime()); +} + +void QDateTimeAxisPrivate::setRange(const QVariant &min, const QVariant &max) +{ + Q_Q(QDateTimeAxis); + if (min.canConvert(QVariant::DateTime) && max.canConvert(QVariant::DateTime)) + q->setRange(min.toDateTime(), max.toDateTime()); +} + +void QDateTimeAxisPrivate::initializeGraphics(QGraphicsItem* parent) +{ + Q_Q(QDateTimeAxis); + ChartAxisElement *axis(0); + if (m_chart->chartType() == QChart::ChartTypeCartesian) { + if (orientation() == Qt::Vertical) + axis = new ChartDateTimeAxisY(q,parent); + if (orientation() == Qt::Horizontal) + axis = new ChartDateTimeAxisX(q,parent); + } + + if (m_chart->chartType() == QChart::ChartTypePolar) { + if (orientation() == Qt::Vertical) + axis = new PolarChartDateTimeAxisRadial(q, parent); + if (orientation() == Qt::Horizontal) + axis = new PolarChartDateTimeAxisAngular(q, parent); + } + + m_item.reset(axis); + QAbstractAxisPrivate::initializeGraphics(parent); +} + +void QDateTimeAxisPrivate::initializeDomain(AbstractDomain *domain) +{ + if (m_max == m_min) { + if (orientation() == Qt::Vertical) + setRange(domain->minY(), domain->maxY()); + else + setRange(domain->minX(), domain->maxX()); + } else { + if (orientation() == Qt::Vertical) + domain->setRangeY(m_min, m_max); + else + domain->setRangeX(m_min, m_max); + } +} + +#include "moc_qdatetimeaxis.cpp" +#include "moc_qdatetimeaxis_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/datetimeaxis/qdatetimeaxis.h b/src/charts/axis/datetimeaxis/qdatetimeaxis.h new file mode 100644 index 00000000..72d46b5e --- /dev/null +++ b/src/charts/axis/datetimeaxis/qdatetimeaxis.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDATETIMEAXIS_H +#define QDATETIMEAXIS_H + +#include <QtCharts/qabstractaxis.h> + +class QDateTime; + +QT_CHARTS_BEGIN_NAMESPACE + +class QDateTimeAxisPrivate; + +class QT_CHARTS_EXPORT QDateTimeAxis : public QAbstractAxis +{ + Q_OBJECT + Q_PROPERTY(int tickCount READ tickCount WRITE setTickCount NOTIFY tickCountChanged) + Q_PROPERTY(QDateTime min READ min WRITE setMin NOTIFY minChanged) + Q_PROPERTY(QDateTime max READ max WRITE setMax NOTIFY maxChanged) + Q_PROPERTY(QString format READ format WRITE setFormat NOTIFY formatChanged) + +public: + explicit QDateTimeAxis(QObject *parent = 0); + ~QDateTimeAxis(); + +protected: + QDateTimeAxis(QDateTimeAxisPrivate &d, QObject *parent = 0); + +public: + AxisType type() const; + + //range handling + void setMin(QDateTime min); + QDateTime min() const; + void setMax(QDateTime max); + QDateTime max() const; + void setRange(QDateTime min, QDateTime max); + + void setFormat(QString format); + QString format() const; + + //ticks handling + void setTickCount(int count); + int tickCount() const; + +Q_SIGNALS: + void minChanged(QDateTime min); + void maxChanged(QDateTime max); + void rangeChanged(QDateTime min, QDateTime max); + void formatChanged(QString format); + void tickCountChanged(int tick); + +private: + Q_DECLARE_PRIVATE(QDateTimeAxis) + Q_DISABLE_COPY(QDateTimeAxis) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QDATETIMEAXIS_H diff --git a/src/charts/axis/datetimeaxis/qdatetimeaxis_p.h b/src/charts/axis/datetimeaxis/qdatetimeaxis_p.h new file mode 100644 index 00000000..30551d55 --- /dev/null +++ b/src/charts/axis/datetimeaxis/qdatetimeaxis_p.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QDATETIMEAXIS_P_H +#define QDATETIMEAXIS_P_H + +#include "qdatetimeaxis.h" +#include "qabstractaxis_p.h" +#include <QDateTime> + +QT_CHARTS_BEGIN_NAMESPACE + +class QDateTimeAxisPrivate : public QAbstractAxisPrivate +{ + Q_OBJECT +public: + QDateTimeAxisPrivate(QDateTimeAxis *q); + ~QDateTimeAxisPrivate(); + +public: + void initializeGraphics(QGraphicsItem* parent); + void initializeDomain(AbstractDomain *domain); + + //interface for manipulating range form base class + void setMin(const QVariant &min); + void setMax(const QVariant &max); + void setRange(const QVariant &min, const QVariant &max); + + //interface manipulating range form domain + qreal min() { return m_min; } + qreal max() { return m_max; } + void setRange(qreal min,qreal max); + +protected: + int tickCount() const; + +protected: + qreal m_min; + qreal m_max; + int m_tickCount; + QString m_format; + Q_DECLARE_PUBLIC(QDateTimeAxis) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QDATETIMEAXIS_P_H diff --git a/src/charts/axis/horizontalaxis.cpp b/src/charts/axis/horizontalaxis.cpp new file mode 100644 index 00000000..941afc05 --- /dev/null +++ b/src/charts/axis/horizontalaxis.cpp @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "horizontalaxis_p.h" +#include "qabstractaxis_p.h" +#include "chartpresenter_p.h" +#include <qmath.h> +#include <QDebug> + +QT_CHARTS_BEGIN_NAMESPACE + +HorizontalAxis::HorizontalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis) + : CartesianChartAxis(axis, item, intervalAxis) +{ +} + +HorizontalAxis::~HorizontalAxis() +{ +} + +void HorizontalAxis::updateGeometry() +{ + const QVector<qreal> &layout = ChartAxisElement::layout(); + + if (layout.isEmpty()) + return; + + QStringList labelList = labels(); + + QList<QGraphicsItem *> lines = gridItems(); + QList<QGraphicsItem *> labels = labelItems(); + QList<QGraphicsItem *> shades = shadeItems(); + QList<QGraphicsItem *> arrow = arrowItems(); + QGraphicsTextItem *title = titleItem(); + + Q_ASSERT(labels.size() == labelList.size()); + Q_ASSERT(layout.size() == labelList.size()); + + const QRectF &axisRect = axisGeometry(); + const QRectF &gridRect = gridGeometry(); + + //arrow + QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem *>(arrow.at(0)); + + if (axis()->alignment() == Qt::AlignTop) + arrowItem->setLine(gridRect.left(), axisRect.bottom(), gridRect.right(), axisRect.bottom()); + else if (axis()->alignment() == Qt::AlignBottom) + arrowItem->setLine(gridRect.left(), axisRect.top(), gridRect.right(), axisRect.top()); + + qreal width = 0; + const QLatin1String ellipsis("..."); + + //title + QRectF titleBoundingRect; + QString titleText = axis()->titleText(); + qreal availableSpace = axisRect.height() - labelPadding(); + if (!titleText.isEmpty() && titleItem()->isVisible()) { + availableSpace -= titlePadding() * 2.0; + qreal minimumLabelHeight = ChartPresenter::textBoundingRect(axis()->labelsFont(), + QStringLiteral("...")).height(); + qreal titleSpace = availableSpace - minimumLabelHeight; + title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0), + gridRect.width(), titleSpace, + titleBoundingRect)); + title->setTextWidth(titleBoundingRect.width()); + + titleBoundingRect = title->boundingRect(); + + QPointF center = gridRect.center() - titleBoundingRect.center(); + if (axis()->alignment() == Qt::AlignTop) + title->setPos(center.x(), axisRect.top() + titlePadding()); + else if (axis()->alignment() == Qt::AlignBottom) + title->setPos(center.x(), axisRect.bottom() - titleBoundingRect.height() - titlePadding()); + + availableSpace -= titleBoundingRect.height(); + } + + for (int i = 0; i < layout.size(); ++i) { + //items + QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem*>(lines.at(i)); + QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem*>(arrow.at(i + 1)); + QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i)); + + //grid line + gridItem->setLine(layout[i], gridRect.top(), layout[i], gridRect.bottom()); + + //label text wrapping + QString text = labelList.at(i); + QRectF boundingRect; + // don't truncate empty labels + if (text.isEmpty()) { + labelItem->setHtml(text); + } else { + qreal labelWidth = axisRect.width() / layout.count() - (2 * labelPadding()); + QString truncatedText = ChartPresenter::truncatedText(axis()->labelsFont(), text, + axis()->labelsAngle(), + labelWidth, + availableSpace, boundingRect); + labelItem->setTextWidth(ChartPresenter::textBoundingRect(axis()->labelsFont(), + truncatedText).width()); + labelItem->setHtml(truncatedText); + } + + //label transformation origin point + const QRectF& rect = labelItem->boundingRect(); + QPointF center = rect.center(); + labelItem->setTransformOriginPoint(center.x(), center.y()); + qreal heightDiff = rect.height() - boundingRect.height(); + qreal widthDiff = rect.width() - boundingRect.width(); + + //ticks and label position + if (axis()->alignment() == Qt::AlignTop) { + labelItem->setPos(layout[i] - center.x(), axisRect.bottom() - rect.height() + (heightDiff / 2.0) - labelPadding()); + tickItem->setLine(layout[i], axisRect.bottom(), layout[i], axisRect.bottom() - labelPadding()); + } else if (axis()->alignment() == Qt::AlignBottom) { + labelItem->setPos(layout[i] - center.x(), axisRect.top() - (heightDiff / 2.0) + labelPadding()); + tickItem->setLine(layout[i], axisRect.top(), layout[i], axisRect.top() + labelPadding()); + } + + //label in between + bool forceHide = false; + if (intervalAxis() && (i + 1) != layout.size()) { + qreal leftBound = qMax(layout[i], gridRect.left()); + qreal rightBound = qMin(layout[i + 1], gridRect.right()); + const qreal delta = rightBound - leftBound; + // Hide label in case visible part of the category at the grid edge is too narrow + if (delta < boundingRect.width() + && (leftBound == gridRect.left() || rightBound == gridRect.right()) + && !intervalAxis()) { + forceHide = true; + } else { + labelItem->setPos(leftBound + (delta / 2.0) - center.x(), labelItem->pos().y()); + } + } + + //label overlap detection - compensate one pixel for rounding errors + if ((labelItem->pos().x() < width && labelItem->toPlainText() == ellipsis) || forceHide || + (labelItem->pos().x() + (widthDiff / 2.0)) < (axisRect.left() - 1.0) || + (labelItem->pos().x() + (widthDiff / 2.0) - 1.0) > axisRect.right()) { + labelItem->setVisible(false); + } else { + labelItem->setVisible(true); + width = boundingRect.width() + labelItem->pos().x(); + } + + //shades + if ((i + 1) % 2 && i > 1) { + QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem *>(shades.at(i / 2 - 1)); + qreal leftBound = qMax(layout[i - 1], gridRect.left()); + qreal rightBound = qMin(layout[i], gridRect.right()); + rectItem->setRect(leftBound, gridRect.top(), rightBound - leftBound, gridRect.height()); + if (rectItem->rect().width() <= 0.0) + rectItem->setVisible(false); + else + rectItem->setVisible(true); + } + + // check if the grid line and the axis tick should be shown + qreal x = gridItem->line().p1().x(); + if (x < gridRect.left() || x > gridRect.right()) { + gridItem->setVisible(false); + tickItem->setVisible(false); + } else { + gridItem->setVisible(true); + tickItem->setVisible(true); + } + + } + + //begin/end grid line in case labels between + if (intervalAxis()) { + QGraphicsLineItem *gridLine; + gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size())); + gridLine->setLine(gridRect.right(), gridRect.top(), gridRect.right(), gridRect.bottom()); + gridLine->setVisible(true); + gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size()+1)); + gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.left(), gridRect.bottom()); + gridLine->setVisible(true); + } +} + +QSizeF HorizontalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const +{ + Q_UNUSED(constraint); + QSizeF sh(0,0); + + if (axis()->titleText().isEmpty() || !titleItem()->isVisible()) + return sh; + + switch (which) { + case Qt::MinimumSize: { + QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), + QStringLiteral("...")); + sh = QSizeF(titleRect.width(), titleRect.height() + (titlePadding() * 2.0)); + break; + } + case Qt::MaximumSize: + case Qt::PreferredSize: { + QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText()); + sh = QSizeF(titleRect.width(), titleRect.height() + (titlePadding() * 2.0)); + break; + } + default: + break; + } + + return sh; +} + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/horizontalaxis_p.h b/src/charts/axis/horizontalaxis_p.h new file mode 100644 index 00000000..9f1ad596 --- /dev/null +++ b/src/charts/axis/horizontalaxis_p.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef HORIZONTALAXIS_P_H_ +#define HORIZONTALAXIS_P_H_ + +#include "cartesianchartaxis_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class HorizontalAxis : public CartesianChartAxis +{ +public: + HorizontalAxis(QAbstractAxis *axis, QGraphicsItem *item = 0, bool intervalAxis = false); + ~HorizontalAxis(); + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const; +protected: + void updateGeometry(); + +}; + +QT_CHARTS_END_NAMESPACE + +#endif diff --git a/src/charts/axis/linearrowitem_p.h b/src/charts/axis/linearrowitem_p.h new file mode 100644 index 00000000..f1f94acd --- /dev/null +++ b/src/charts/axis/linearrowitem_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef LINEARROWITEM_P_H +#define LINEARROWITEM_P_H + +#include "chartaxiselement_p.h" +#include "qabstractaxis_p.h" +#include <QGraphicsLineItem> + +QT_CHARTS_BEGIN_NAMESPACE + +class LineArrowItem: public QGraphicsLineItem +{ +public: + explicit LineArrowItem(ChartAxisElement *axis, QGraphicsItem *parent = 0) + : QGraphicsLineItem(parent), + m_axis(axis), + m_axisOrientation(axis->axis()->orientation()) + { + } + +protected: + void mousePressEvent(QGraphicsSceneMouseEvent *event) + { + Q_UNUSED(event) + m_axis->axisSelected(); + } + + QRectF boundingRect() const + { + return shape().boundingRect(); + } + + QPainterPath shape() const + { + QPainterPath path = QGraphicsLineItem::shape(); + QRectF rect = path.boundingRect(); + path.addRect(rect.adjusted(0, 0, m_axisOrientation != Qt::Horizontal ? 8 : 0, m_axisOrientation != Qt::Vertical ? 8 : 0)); + return path; + } + +private: + ChartAxisElement *m_axis; + Qt::Orientation m_axisOrientation; +}; + +QT_CHARTS_END_NAMESPACE + +#endif /* LINEARROWITEM_P_H */ diff --git a/src/charts/axis/logvalueaxis/chartlogvalueaxisx.cpp b/src/charts/axis/logvalueaxis/chartlogvalueaxisx.cpp new file mode 100644 index 00000000..6057fbb1 --- /dev/null +++ b/src/charts/axis/logvalueaxis/chartlogvalueaxisx.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "chartlogvalueaxisx_p.h" +#include "chartpresenter_p.h" +#include "qlogvalueaxis.h" +#include "abstractchartlayout_p.h" +#include <QGraphicsLayout> +#include <qmath.h> +#include <QDebug> + +QT_CHARTS_BEGIN_NAMESPACE + +ChartLogValueAxisX::ChartLogValueAxisX(QLogValueAxis *axis, QGraphicsItem *item) + : HorizontalAxis(axis, item), + m_axis(axis) +{ + QObject::connect(m_axis, SIGNAL(baseChanged(qreal)), this, SLOT(handleBaseChanged(qreal))); + QObject::connect(m_axis, SIGNAL(labelFormatChanged(QString)), this, SLOT(handleLabelFormatChanged(QString))); +} + +ChartLogValueAxisX::~ChartLogValueAxisX() +{ +} + +QVector<qreal> ChartLogValueAxisX::calculateLayout() const +{ + QVector<qreal> points; + + qreal logMax = log10(m_axis->max()) / log10(m_axis->base()); + qreal logMin = log10(m_axis->min()) / log10(m_axis->base()); + qreal leftEdge = logMin < logMax ? logMin : logMax; + qreal ceilEdge = ceil(leftEdge); + int tickCount = qAbs(ceil(logMax) - ceil(logMin)); + + points.resize(tickCount); + const QRectF &gridRect = gridGeometry(); + const qreal deltaX = gridRect.width() / qAbs(logMax - logMin); + for (int i = 0; i < tickCount; ++i) + points[i] = (ceilEdge + qreal(i)) * deltaX - leftEdge * deltaX + gridRect.left(); + + return points; +} + +void ChartLogValueAxisX::updateGeometry() +{ + const QVector<qreal>& layout = ChartAxisElement::layout(); + if (layout.isEmpty()) + return; + setLabels(createLogValueLabels(m_axis->min(), m_axis->max(), m_axis->base(), layout.size(), m_axis->labelFormat())); + HorizontalAxis::updateGeometry(); +} + +void ChartLogValueAxisX::handleBaseChanged(qreal base) +{ + Q_UNUSED(base); + QGraphicsLayoutItem::updateGeometry(); + if(presenter()) presenter()->layout()->invalidate(); +} + +void ChartLogValueAxisX::handleLabelFormatChanged(const QString &format) +{ + Q_UNUSED(format); + QGraphicsLayoutItem::updateGeometry(); + if(presenter()) presenter()->layout()->invalidate(); +} + +QSizeF ChartLogValueAxisX::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const +{ + Q_UNUSED(constraint) + + QSizeF sh; + + QSizeF base = HorizontalAxis::sizeHint(which, constraint); + QStringList ticksList; + qreal logMax = log10(m_axis->max()) / log10(m_axis->base()); + qreal logMin = log10(m_axis->min()) / log10(m_axis->base()); + int tickCount = qAbs(ceil(logMax) - ceil(logMin)); + if (m_axis->max() > m_axis->min() && tickCount > 0) + ticksList = createLogValueLabels(m_axis->min(), m_axis->max(), m_axis->base(), tickCount, m_axis->labelFormat()); + else + ticksList.append(QStringLiteral(" ")); + // Width of horizontal axis sizeHint indicates the maximum distance labels can extend past + // first and last ticks. Base width is irrelevant. + qreal width = 0; + qreal height = 0; + + switch (which) { + case Qt::MinimumSize:{ + QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), + QStringLiteral("..."), + axis()->labelsAngle()); + width = boundingRect.width() / 2.0; + height = boundingRect.height() + labelPadding() + base.height() + 1.0; + sh = QSizeF(width, height); + break; + } + case Qt::PreferredSize: { + qreal labelHeight = 0.0; + qreal firstWidth = -1.0; + foreach (const QString& s, ticksList) { + QRectF rect = ChartPresenter::textBoundingRect(axis()->labelsFont(), s, axis()->labelsAngle()); + labelHeight = qMax(rect.height(), labelHeight); + width = rect.width(); + if (firstWidth < 0.0) + firstWidth = width; + } + height = labelHeight + labelPadding() + base.height() + 1.0; + width = qMax(width, firstWidth) / 2.0; + sh = QSizeF(width, height); + break; + } + default: + break; + } + + return sh; +} + +#include "moc_chartlogvalueaxisx_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/logvalueaxis/chartlogvalueaxisx_p.h b/src/charts/axis/logvalueaxis/chartlogvalueaxisx_p.h new file mode 100644 index 00000000..490832b5 --- /dev/null +++ b/src/charts/axis/logvalueaxis/chartlogvalueaxisx_p.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef CHARTLOGVALUEAXISX_H +#define CHARTLOGVALUEAXISX_H + +#include "horizontalaxis_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QLogValueAxis; + +class ChartLogValueAxisX : public HorizontalAxis +{ + Q_OBJECT + +public: + ChartLogValueAxisX(QLogValueAxis *axis, QGraphicsItem *item); + ~ChartLogValueAxisX(); + + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const; + +protected: + QVector<qreal> calculateLayout() const; + void updateGeometry(); + +private Q_SLOTS: + void handleBaseChanged(qreal base); + void handleLabelFormatChanged(const QString &format); + +private: + QLogValueAxis *m_axis; +}; + +QT_CHARTS_END_NAMESPACE + +#endif /* CHARTLOGVALUEAXISX_H */ diff --git a/src/charts/axis/logvalueaxis/chartlogvalueaxisy.cpp b/src/charts/axis/logvalueaxis/chartlogvalueaxisy.cpp new file mode 100644 index 00000000..d0492f97 --- /dev/null +++ b/src/charts/axis/logvalueaxis/chartlogvalueaxisy.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "chartlogvalueaxisy_p.h" +#include "chartpresenter_p.h" +#include "qlogvalueaxis.h" +#include "abstractchartlayout_p.h" +#include <QGraphicsLayout> +#include <qmath.h> +#include <QDebug> + +QT_CHARTS_BEGIN_NAMESPACE + +ChartLogValueAxisY::ChartLogValueAxisY(QLogValueAxis *axis, QGraphicsItem *item) + : VerticalAxis(axis, item), + m_axis(axis) +{ + QObject::connect(m_axis, SIGNAL(baseChanged(qreal)), this, SLOT(handleBaseChanged(qreal))); + QObject::connect(m_axis, SIGNAL(labelFormatChanged(QString)), this, SLOT(handleLabelFormatChanged(QString))); +} + +ChartLogValueAxisY::~ChartLogValueAxisY() +{ +} + +QVector<qreal> ChartLogValueAxisY::calculateLayout() const +{ + QVector<qreal> points; + qreal logMax = log10(m_axis->max()) / log10(m_axis->base()); + qreal logMin = log10(m_axis->min()) / log10(m_axis->base()); + qreal leftEdge = logMin < logMax ? logMin : logMax; + qreal ceilEdge = ceil(leftEdge); + int tickCount = qAbs(ceil(logMax) - ceil(logMin)); + + points.resize(tickCount); + const QRectF &gridRect = gridGeometry(); + const qreal deltaY = gridRect.height() / qAbs(logMax - logMin); + for (int i = 0; i < tickCount; ++i) + points[i] = (ceilEdge + qreal(i)) * -deltaY - leftEdge * -deltaY + gridRect.bottom(); + + return points; +} + + +void ChartLogValueAxisY::updateGeometry() +{ + const QVector<qreal> &layout = ChartAxisElement::layout(); + if (layout.isEmpty()) + return; + setLabels(createLogValueLabels(m_axis->min(), m_axis->max(), m_axis->base(), layout.size(), m_axis->labelFormat())); + VerticalAxis::updateGeometry(); +} + +void ChartLogValueAxisY::handleBaseChanged(qreal base) +{ + Q_UNUSED(base); + QGraphicsLayoutItem::updateGeometry(); + if(presenter()) presenter()->layout()->invalidate(); +} + +void ChartLogValueAxisY::handleLabelFormatChanged(const QString &format) +{ + Q_UNUSED(format); + QGraphicsLayoutItem::updateGeometry(); + if(presenter()) presenter()->layout()->invalidate(); +} + +QSizeF ChartLogValueAxisY::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const +{ + Q_UNUSED(constraint) + + QSizeF sh; + + QSizeF base = VerticalAxis::sizeHint(which, constraint); + QStringList ticksList; + qreal logMax = log10(m_axis->max()) / log10(m_axis->base()); + qreal logMin = log10(m_axis->min()) / log10(m_axis->base()); + int tickCount = qAbs(ceil(logMax) - ceil(logMin)); + if (m_axis->max() > m_axis->min() && tickCount > 0) + ticksList = createLogValueLabels(m_axis->min(), m_axis->max(), m_axis->base(), tickCount, m_axis->labelFormat()); + else + ticksList.append(QStringLiteral(" ")); + qreal width = 0; + // Height of vertical axis sizeHint indicates the maximum distance labels can extend past + // first and last ticks. Base height is irrelevant. + qreal height = 0; + + switch (which) { + case Qt::MinimumSize: { + QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), + QStringLiteral("..."), + axis()->labelsAngle()); + width = boundingRect.width() + labelPadding() + base.width() + 1.0; + height = boundingRect.height() / 2.0; + sh = QSizeF(width, height); + break; + } + case Qt::PreferredSize: { + qreal labelWidth = 0.0; + qreal firstHeight = -1.0; + foreach (const QString& s, ticksList) { + QRectF rect = ChartPresenter::textBoundingRect(axis()->labelsFont(), s, axis()->labelsAngle()); + labelWidth = qMax(rect.width(), labelWidth); + height = rect.height(); + if (firstHeight < 0.0) + firstHeight = height; + } + width = labelWidth + labelPadding() + base.width() + 2.0; //two pixels of tolerance + height = qMax(height, firstHeight) / 2.0; + sh = QSizeF(width, height); + break; + } + default: + break; + } + + return sh; +} + +#include "moc_chartlogvalueaxisy_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/logvalueaxis/chartlogvalueaxisy_p.h b/src/charts/axis/logvalueaxis/chartlogvalueaxisy_p.h new file mode 100644 index 00000000..d65275c3 --- /dev/null +++ b/src/charts/axis/logvalueaxis/chartlogvalueaxisy_p.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef CHARTLOGVALUEAXISY_H +#define CHARTLOGVALUEAXISY_H + +#include "verticalaxis_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QLogValueAxis; + +class ChartLogValueAxisY : public VerticalAxis +{ + Q_OBJECT + +public: + ChartLogValueAxisY(QLogValueAxis *axis, QGraphicsItem *item); + ~ChartLogValueAxisY(); + + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const; + +protected: + QVector<qreal> calculateLayout() const; + void updateGeometry(); + +private Q_SLOTS: + void handleBaseChanged(qreal base); + void handleLabelFormatChanged(const QString &format); + +private: + QLogValueAxis *m_axis; +}; + +QT_CHARTS_END_NAMESPACE + +#endif /* CHARTLOGVALUEAXISY_H */ diff --git a/src/charts/axis/logvalueaxis/polarchartlogvalueaxisangular.cpp b/src/charts/axis/logvalueaxis/polarchartlogvalueaxisangular.cpp new file mode 100644 index 00000000..f9fe664d --- /dev/null +++ b/src/charts/axis/logvalueaxis/polarchartlogvalueaxisangular.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "polarchartlogvalueaxisangular_p.h" +#include "abstractchartlayout_p.h" +#include "chartpresenter_p.h" +#include "qlogvalueaxis.h" +#include <qmath.h> +#include <QDebug> + +QT_CHARTS_BEGIN_NAMESPACE + +PolarChartLogValueAxisAngular::PolarChartLogValueAxisAngular(QLogValueAxis *axis, QGraphicsItem *item) + : PolarChartAxisAngular(axis, item) +{ + QObject::connect(axis, SIGNAL(baseChanged(qreal)), this, SLOT(handleBaseChanged(qreal))); + QObject::connect(axis, SIGNAL(labelFormatChanged(QString)), this, SLOT(handleLabelFormatChanged(QString))); +} + +PolarChartLogValueAxisAngular::~PolarChartLogValueAxisAngular() +{ +} + +QVector<qreal> PolarChartLogValueAxisAngular::calculateLayout() const +{ + QLogValueAxis *logValueAxis = static_cast<QLogValueAxis *>(axis()); + const qreal logMax = log10(logValueAxis->max()) / log10(logValueAxis->base()); + const qreal logMin = log10(logValueAxis->min()) / log10(logValueAxis->base()); + const qreal startEdge = logMin < logMax ? logMin : logMax; + const qreal delta = 360.0 / qAbs(logMax - logMin); + const qreal initialSpan = (ceil(startEdge) - startEdge) * delta; + int tickCount = qAbs(ceil(logMax) - ceil(logMin)); + + QVector<qreal> points; + points.resize(tickCount); + + for (int i = 0; i < tickCount; ++i) { + qreal angularCoordinate = initialSpan + (delta * qreal(i)); + points[i] = angularCoordinate; + } + + return points; +} + +void PolarChartLogValueAxisAngular::createAxisLabels(const QVector<qreal> &layout) +{ + QLogValueAxis *logValueAxis = static_cast<QLogValueAxis *>(axis()); + setLabels(createLogValueLabels(logValueAxis->min(), + logValueAxis->max(), + logValueAxis->base(), + layout.size(), + logValueAxis->labelFormat())); +} + +void PolarChartLogValueAxisAngular::handleBaseChanged(qreal base) +{ + Q_UNUSED(base); + QGraphicsLayoutItem::updateGeometry(); + if (presenter()) + presenter()->layout()->invalidate(); +} + +void PolarChartLogValueAxisAngular::handleLabelFormatChanged(const QString &format) +{ + Q_UNUSED(format); + QGraphicsLayoutItem::updateGeometry(); + if (presenter()) + presenter()->layout()->invalidate(); +} + +#include "moc_polarchartlogvalueaxisangular_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/logvalueaxis/polarchartlogvalueaxisangular_p.h b/src/charts/axis/logvalueaxis/polarchartlogvalueaxisangular_p.h new file mode 100644 index 00000000..d56f7fdc --- /dev/null +++ b/src/charts/axis/logvalueaxis/polarchartlogvalueaxisangular_p.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef POLARCHARTLOGVALUEAXISANGULAR_P_H +#define POLARCHARTLOGVALUEAXISANGULAR_P_H + +#include "polarchartaxisangular_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QLogValueAxis; + +class PolarChartLogValueAxisAngular : public PolarChartAxisAngular +{ + Q_OBJECT +public: + PolarChartLogValueAxisAngular(QLogValueAxis *axis, QGraphicsItem *item); + ~PolarChartLogValueAxisAngular(); + +protected: + virtual QVector<qreal> calculateLayout() const; + virtual void createAxisLabels(const QVector<qreal> &layout); + +private Q_SLOTS: + void handleBaseChanged(qreal base); + void handleLabelFormatChanged(const QString &format); +}; + +QT_CHARTS_END_NAMESPACE + +#endif // POLARCHARTLOGVALUEAXISANGULAR_P_H diff --git a/src/charts/axis/logvalueaxis/polarchartlogvalueaxisradial.cpp b/src/charts/axis/logvalueaxis/polarchartlogvalueaxisradial.cpp new file mode 100644 index 00000000..3c0d01b3 --- /dev/null +++ b/src/charts/axis/logvalueaxis/polarchartlogvalueaxisradial.cpp @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "polarchartlogvalueaxisradial_p.h" +#include "abstractchartlayout_p.h" +#include "chartpresenter_p.h" +#include "qlogvalueaxis.h" +#include <qmath.h> +#include <QDebug> + +QT_CHARTS_BEGIN_NAMESPACE + +PolarChartLogValueAxisRadial::PolarChartLogValueAxisRadial(QLogValueAxis *axis, QGraphicsItem *item) + : PolarChartAxisRadial(axis, item) +{ + QObject::connect(axis, SIGNAL(baseChanged(qreal)), this, SLOT(handleBaseChanged(qreal))); + QObject::connect(axis, SIGNAL(labelFormatChanged(QString)), this, SLOT(handleLabelFormatChanged(QString))); +} + +PolarChartLogValueAxisRadial::~PolarChartLogValueAxisRadial() +{ +} + +QVector<qreal> PolarChartLogValueAxisRadial::calculateLayout() const +{ + QLogValueAxis *logValueAxis = static_cast<QLogValueAxis *>(axis()); + const qreal logMax = log10(logValueAxis->max()) / log10(logValueAxis->base()); + const qreal logMin = log10(logValueAxis->min()) / log10(logValueAxis->base()); + const qreal innerEdge = logMin < logMax ? logMin : logMax; + const qreal outerEdge = logMin > logMax ? logMin : logMax; + const qreal delta = (axisGeometry().width() / 2.0) / qAbs(logMax - logMin); + const qreal initialSpan = (ceil(innerEdge) - innerEdge) * delta; + int tickCount = qAbs(ceil(logMax) - ceil(logMin)); + + // Extra tick if outer edge is exactly at the tick + if (outerEdge == ceil(outerEdge)) + tickCount++; + + QVector<qreal> points; + points.resize(tickCount); + + for (int i = 0; i < tickCount; ++i) { + qreal radialCoordinate = initialSpan + (delta * qreal(i)); + points[i] = radialCoordinate; + } + + return points; +} + +void PolarChartLogValueAxisRadial::createAxisLabels(const QVector<qreal> &layout) +{ + QLogValueAxis *logValueAxis = static_cast<QLogValueAxis *>(axis()); + setLabels(createLogValueLabels(logValueAxis->min(), + logValueAxis->max(), + logValueAxis->base(), + layout.size(), + logValueAxis->labelFormat())); +} + +void PolarChartLogValueAxisRadial::handleBaseChanged(qreal base) +{ + Q_UNUSED(base); + QGraphicsLayoutItem::updateGeometry(); + if (presenter()) + presenter()->layout()->invalidate(); +} + +void PolarChartLogValueAxisRadial::handleLabelFormatChanged(const QString &format) +{ + Q_UNUSED(format); + QGraphicsLayoutItem::updateGeometry(); + if (presenter()) + presenter()->layout()->invalidate(); +} + +#include "moc_polarchartlogvalueaxisradial_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/logvalueaxis/polarchartlogvalueaxisradial_p.h b/src/charts/axis/logvalueaxis/polarchartlogvalueaxisradial_p.h new file mode 100644 index 00000000..4bc59061 --- /dev/null +++ b/src/charts/axis/logvalueaxis/polarchartlogvalueaxisradial_p.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef POLARCHARTLOGVALUEAXISRADIAL_P_H +#define POLARCHARTLOGVALUEAXISRADIAL_P_H + +#include "polarchartaxisradial_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QLogValueAxis; + +class PolarChartLogValueAxisRadial : public PolarChartAxisRadial +{ + Q_OBJECT +public: + PolarChartLogValueAxisRadial(QLogValueAxis *axis, QGraphicsItem *item); + ~PolarChartLogValueAxisRadial(); + +protected: + virtual QVector<qreal> calculateLayout() const; + virtual void createAxisLabels(const QVector<qreal> &layout); + +private Q_SLOTS: + void handleBaseChanged(qreal base); + void handleLabelFormatChanged(const QString &format); +}; + +QT_CHARTS_END_NAMESPACE + +#endif // POLARCHARTLOGVALUEAXISRADIAL_P_H diff --git a/src/charts/axis/logvalueaxis/qlogvalueaxis.cpp b/src/charts/axis/logvalueaxis/qlogvalueaxis.cpp new file mode 100644 index 00000000..ad58905d --- /dev/null +++ b/src/charts/axis/logvalueaxis/qlogvalueaxis.cpp @@ -0,0 +1,400 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlogvalueaxis.h" +#include "qlogvalueaxis_p.h" +#include "chartlogvalueaxisx_p.h" +#include "chartlogvalueaxisy_p.h" +#include "polarchartlogvalueaxisangular_p.h" +#include "polarchartlogvalueaxisradial_p.h" +#include "abstractdomain_p.h" +#include <float.h> +#include <cmath> + +QT_CHARTS_BEGIN_NAMESPACE +/*! + \class QLogValueAxis + \inmodule Qt Charts + \brief The QLogValueAxis class is used for manipulating chart's axis. + \mainclass + + \note If a QLogValueAxis is attached to a series with one or more points with + negative or zero values on the associated dimension, the series will not be + plotted at all. This is particularly relevant when XYModelMappers are used, + since empty cells in models typically contain zero values. +*/ + +/*! + \qmltype LogValueAxis + \instantiates QLogValueAxis + \inqmlmodule QtCharts + + \brief The LogValueAxis element is used for manipulating chart's axes. + \inherits AbstractAxis + + \note If a LogValueAxis is attached to a series with one or more points with + negative or zero values on the associated dimension, the series will not be + plotted at all. This is particularly relevant when XYModelMappers are used, + since empty cells in models typically contain zero values. +*/ + +/*! + \property QLogValueAxis::min + Defines the minimum value on the axis. + When setting this property the max is adjusted if necessary, to ensure that the range remains valid. + Value has to be greater than 0. +*/ +/*! + \qmlproperty real LogValueAxis::min + Defines the minimum value on the axis. + When setting this property the max is adjusted if necessary, to ensure that the range remains valid. + Value has to be greater than 0. +*/ + +/*! + \property QLogValueAxis::max + Defines the maximum value on the axis. + When setting this property the min is adjusted if necessary, to ensure that the range remains valid. + Value has to be greater than 0. +*/ +/*! + \qmlproperty real LogValueAxis::max + Defines the maximum value on the axis. + When setting this property the min is adjusted if necessary, to ensure that the range remains valid. + Value has to be greater than 0. +*/ + +/*! + \property QLogValueAxis::base + Defines the base of the logarithm. + Value has to be greater than 0 and not equal 1 +*/ +/*! + \qmlproperty real LogValueAxis::base + Defines the maximum value on the axis. + Defines the base of the logarithm. + Value has to be greater than 0 and not equal 1 +*/ + +/*! + \property QLogValueAxis::labelFormat + Defines the label format of the axis. + Supported specifiers are: d, i, o, x, X, f, F, e, E, g, G, c + See QString::sprintf() for additional details. +*/ +/*! + \qmlproperty real LogValueAxis::labelFormat + Defines the label format of the axis. + Supported specifiers are: d, i, o, x, X, f, F, e, E, g, G, c + See QString::sprintf() for additional details. +*/ + +/*! + \fn void QLogValueAxis::minChanged(qreal min) + Axis emits signal when \a min of axis has changed. +*/ +/*! + \qmlsignal LogValueAxis::onMinChanged(qreal min) + Axis emits signal when \a min of axis has changed. +*/ + +/*! + \fn void QLogValueAxis::maxChanged(qreal max) + Axis emits signal when \a max of axis has changed. +*/ +/*! + \qmlsignal LogValueAxis::onMaxChanged(qreal max) + Axis emits signal when \a max of axis has changed. +*/ + +/*! + \fn void QLogValueAxis::rangeChanged(qreal min, qreal max) + Axis emits signal when \a min or \a max of axis has changed. +*/ + +/*! + \fn void QLogValueAxis::labelFormatChanged(const QString &format) + Axis emits signal when \a format of axis labels has changed. +*/ +/*! + \qmlsignal LogValueAxis::labelFormatChanged(const QString &format) + Axis emits signal when \a format of axis labels has changed. +*/ + +/*! + \fn void QLogValueAxis::baseChanged(qreal base) + Axis emits signal when \a base of logarithm of the axis has changed. +*/ +/*! + \qmlsignal LogValueAxis::baseChanged(qreal base) + Axis emits signal when \a base of logarithm of the axis has changed. +*/ + +/*! + Constructs an axis object which is a child of \a parent. +*/ +QLogValueAxis::QLogValueAxis(QObject *parent) : + QAbstractAxis(*new QLogValueAxisPrivate(this), parent) +{ + +} + +/*! + \internal +*/ +QLogValueAxis::QLogValueAxis(QLogValueAxisPrivate &d, QObject *parent) : QAbstractAxis(d, parent) +{ + +} + +/*! + Destroys the object +*/ +QLogValueAxis::~QLogValueAxis() +{ + Q_D(QLogValueAxis); + if (d->m_chart) + d->m_chart->removeAxis(this); +} + +void QLogValueAxis::setMin(qreal min) +{ + Q_D(QLogValueAxis); + setRange(min, qMax(d->m_max, min)); +} + +qreal QLogValueAxis::min() const +{ + Q_D(const QLogValueAxis); + return d->m_min; +} + +void QLogValueAxis::setMax(qreal max) +{ + Q_D(QLogValueAxis); + setRange(qMin(d->m_min, max), max); +} + +qreal QLogValueAxis::max() const +{ + Q_D(const QLogValueAxis); + return d->m_max; +} + +/*! + Sets range from \a min to \a max on the axis. + If min is greater than max then this function returns without making any changes. +*/ +void QLogValueAxis::setRange(qreal min, qreal max) +{ + Q_D(QLogValueAxis); + bool changed = false; + + if (min > max) + return; + + if (min > 0) { + if (!qFuzzyCompare(d->m_min, min)) { + d->m_min = min; + changed = true; + emit minChanged(min); + } + + if (!qFuzzyCompare(d->m_max, max)) { + d->m_max = max; + changed = true; + emit maxChanged(max); + } + + if (changed) { + emit rangeChanged(min, max); + emit d->rangeChanged(min,max); + } + } +} + +void QLogValueAxis::setLabelFormat(const QString &format) +{ + Q_D(QLogValueAxis); + d->m_format = format; + emit labelFormatChanged(format); +} + +QString QLogValueAxis::labelFormat() const +{ + Q_D(const QLogValueAxis); + return d->m_format; +} + +void QLogValueAxis::setBase(qreal base) +{ + // check if base is correct + if (qFuzzyCompare(base, 1)) + return; + + if (base > 0) { + Q_D(QLogValueAxis); + d->m_base = base; + emit baseChanged(base); + } +} + +qreal QLogValueAxis::base() const +{ + Q_D(const QLogValueAxis); + return d->m_base; +} + +/*! + Returns the type of the axis +*/ +QAbstractAxis::AxisType QLogValueAxis::type() const +{ + return AxisTypeLogValue; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +QLogValueAxisPrivate::QLogValueAxisPrivate(QLogValueAxis *q) + : QAbstractAxisPrivate(q), + m_min(1), + m_max(1), + m_base(10), + m_format(QString::null) +{ +} + +QLogValueAxisPrivate::~QLogValueAxisPrivate() +{ + +} + +void QLogValueAxisPrivate::setMin(const QVariant &min) +{ + Q_Q(QLogValueAxis); + bool ok; + qreal value = min.toReal(&ok); + if (ok) + q->setMin(value); +} + +void QLogValueAxisPrivate::setMax(const QVariant &max) +{ + + Q_Q(QLogValueAxis); + bool ok; + qreal value = max.toReal(&ok); + if (ok) + q->setMax(value); +} + +void QLogValueAxisPrivate::setRange(const QVariant &min, const QVariant &max) +{ + Q_Q(QLogValueAxis); + bool ok1; + bool ok2; + qreal value1 = min.toReal(&ok1); + qreal value2 = max.toReal(&ok2); + if (ok1 && ok2) + q->setRange(value1, value2); +} + +void QLogValueAxisPrivate::setRange(qreal min, qreal max) +{ + Q_Q(QLogValueAxis); + bool changed = false; + + if (min > max) + return; + + if (min > 0) { + if (!qFuzzyCompare(m_min, min)) { + m_min = min; + changed = true; + emit q->minChanged(min); + } + + if (!qFuzzyCompare(m_max, max)) { + m_max = max; + changed = true; + emit q->maxChanged(max); + } + + if (changed) { + emit rangeChanged(min,max); + emit q->rangeChanged(min, max); + } + } +} + +void QLogValueAxisPrivate::initializeGraphics(QGraphicsItem *parent) +{ + Q_Q(QLogValueAxis); + ChartAxisElement *axis(0); + + if (m_chart->chartType() == QChart::ChartTypeCartesian) { + if (orientation() == Qt::Vertical) + axis = new ChartLogValueAxisY(q,parent); + if (orientation() == Qt::Horizontal) + axis = new ChartLogValueAxisX(q,parent); + } + + if (m_chart->chartType() == QChart::ChartTypePolar) { + if (orientation() == Qt::Vertical) + axis = new PolarChartLogValueAxisRadial(q, parent); + if (orientation() == Qt::Horizontal) + axis = new PolarChartLogValueAxisAngular(q, parent); + } + + m_item.reset(axis); + QAbstractAxisPrivate::initializeGraphics(parent); +} + + +void QLogValueAxisPrivate::initializeDomain(AbstractDomain *domain) +{ + if (orientation() == Qt::Vertical) { + if (!qFuzzyCompare(m_max, m_min)) { + domain->setRangeY(m_min, m_max); + } else if ( domain->minY() > 0) { + setRange(domain->minY(), domain->maxY()); + } else if (domain->maxY() > 0) { + domain->setRangeY(m_min, domain->maxY()); + } else { + domain->setRangeY(1, 10); + } + } + if (orientation() == Qt::Horizontal) { + if (!qFuzzyCompare(m_max, m_min)) { + domain->setRangeX(m_min, m_max); + } else if (domain->minX() > 0){ + setRange(domain->minX(), domain->maxX()); + } else if (domain->maxX() > 0) { + domain->setRangeX(m_min, domain->maxX()); + } else { + domain->setRangeX(1, 10); + } + } +} + +#include "moc_qlogvalueaxis.cpp" +#include "moc_qlogvalueaxis_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/logvalueaxis/qlogvalueaxis.h b/src/charts/axis/logvalueaxis/qlogvalueaxis.h new file mode 100644 index 00000000..2ad1f6ab --- /dev/null +++ b/src/charts/axis/logvalueaxis/qlogvalueaxis.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOGVALUEAXIS_H +#define QLOGVALUEAXIS_H + +#include <QtCharts/qabstractaxis.h> + +class QDateTime; + +QT_CHARTS_BEGIN_NAMESPACE + +class QLogValueAxisPrivate; + +class QT_CHARTS_EXPORT QLogValueAxis : public QAbstractAxis +{ + Q_OBJECT + Q_PROPERTY(qreal min READ min WRITE setMin NOTIFY minChanged) + Q_PROPERTY(qreal max READ max WRITE setMax NOTIFY maxChanged) + Q_PROPERTY(QString labelFormat READ labelFormat WRITE setLabelFormat NOTIFY labelFormatChanged) + Q_PROPERTY(qreal base READ base WRITE setBase NOTIFY baseChanged) + +public: + explicit QLogValueAxis(QObject *parent = 0); + ~QLogValueAxis(); + +protected: + QLogValueAxis(QLogValueAxisPrivate &d, QObject *parent = 0); + +public: + AxisType type() const; + + //range handling + void setMin(qreal min); + qreal min() const; + void setMax(qreal max); + qreal max() const; + void setRange(qreal min, qreal max); + + void setLabelFormat(const QString &format); + QString labelFormat() const; + + void setBase(qreal base); + qreal base() const; + +Q_SIGNALS: + void minChanged(qreal min); + void maxChanged(qreal max); + void rangeChanged(qreal min, qreal max); + void labelFormatChanged(const QString &format); + void baseChanged(qreal base); + +private: + Q_DECLARE_PRIVATE(QLogValueAxis) + Q_DISABLE_COPY(QLogValueAxis) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QLOGVALUEAXIS_H diff --git a/src/charts/axis/logvalueaxis/qlogvalueaxis_p.h b/src/charts/axis/logvalueaxis/qlogvalueaxis_p.h new file mode 100644 index 00000000..741626f3 --- /dev/null +++ b/src/charts/axis/logvalueaxis/qlogvalueaxis_p.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QLOGVALUEAXIS_P_H +#define QLOGVALUEAXIS_P_H + +#include <qlogvalueaxis.h> +#include "qabstractaxis_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QLogValueAxisPrivate : public QAbstractAxisPrivate +{ + Q_OBJECT + public: + QLogValueAxisPrivate(QLogValueAxis *q); + ~QLogValueAxisPrivate(); + + public: + void initializeGraphics(QGraphicsItem* parent); + void initializeDomain(AbstractDomain *domain); + + qreal min() { return m_min; } + qreal max() { return m_max; } + void setRange(qreal min,qreal max); + + protected: + void setMin(const QVariant &min); + void setMax(const QVariant &max); + void setRange(const QVariant &min, const QVariant &max); + int tickCount() const; + + protected: + qreal m_min; + qreal m_max; + qreal m_base; + QString m_format; + Q_DECLARE_PUBLIC(QLogValueAxis) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QLOGVALUEAXIS_P_H diff --git a/src/charts/axis/polarchartaxis.cpp b/src/charts/axis/polarchartaxis.cpp new file mode 100644 index 00000000..bf9caaeb --- /dev/null +++ b/src/charts/axis/polarchartaxis.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "polarchartaxis_p.h" +#include "qabstractaxis_p.h" +#include "chartpresenter_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +PolarChartAxis::PolarChartAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis) + : ChartAxisElement(axis, item, intervalAxis) +{ +} + +PolarChartAxis::~PolarChartAxis() +{ + +} + +void PolarChartAxis::setGeometry(const QRectF &axis, const QRectF &grid) +{ + Q_UNUSED(grid); + setAxisGeometry(axis); + + if (isEmpty()) + return; + + QVector<qreal> layout = calculateLayout(); + updateLayout(layout); +} + +QRectF PolarChartAxis::gridGeometry() const +{ + return QRectF(); +} + +void PolarChartAxis::updateLayout(QVector<qreal> &layout) +{ + int diff = ChartAxisElement::layout().size() - layout.size(); + + if (animation()) { + switch (presenter()->state()) { + case ChartPresenter::ZoomInState: + case ChartPresenter::ZoomOutState: + case ChartPresenter::ScrollUpState: + case ChartPresenter::ScrollLeftState: + case ChartPresenter::ScrollDownState: + case ChartPresenter::ScrollRightState: + case ChartPresenter::ShowState: + animation()->setAnimationType(AxisAnimation::DefaultAnimation); + break; + } + // Update to "old" geometry before starting animation to avoid incorrectly sized + // axes lingering in wrong position compared to series plot before animation can kick in. + // Note that the position mismatch still exists even with this update, but it will be + // far less ugly. + updateGeometry(); + } + + if (diff > 0) + deleteItems(diff); + else if (diff < 0) + createItems(-diff); + + if (animation()) { + animation()->setValues(ChartAxisElement::layout(), layout); + presenter()->startAnimation(animation()); + } else { + setLayout(layout); + updateGeometry(); + } +} + +bool PolarChartAxis::isEmpty() +{ + return !axisGeometry().isValid() || qFuzzyIsNull(min() - max()); +} + +void PolarChartAxis::deleteItems(int count) +{ + QList<QGraphicsItem *> gridLines = gridItems(); + QList<QGraphicsItem *> labels = labelItems(); + QList<QGraphicsItem *> shades = shadeItems(); + QList<QGraphicsItem *> axis = arrowItems(); + + for (int i = 0; i < count; ++i) { + if (gridItems().size() == 1 || (((gridLines.size() + 1) % 2) && gridLines.size() > 0)) + delete(shades.takeLast()); + delete(gridLines.takeLast()); + delete(labels.takeLast()); + delete(axis.takeLast()); + } +} + +void PolarChartAxis::handleShadesBrushChanged(const QBrush &brush) +{ + foreach (QGraphicsItem *item, shadeItems()) + static_cast<QGraphicsPathItem *>(item)->setBrush(brush); +} + +void PolarChartAxis::handleShadesPenChanged(const QPen &pen) +{ + foreach (QGraphicsItem *item, shadeItems()) + static_cast<QGraphicsPathItem *>(item)->setPen(pen); +} + +#include "moc_polarchartaxis_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/polarchartaxis_p.h b/src/charts/axis/polarchartaxis_p.h new file mode 100644 index 00000000..8924b812 --- /dev/null +++ b/src/charts/axis/polarchartaxis_p.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef POLARCHARTAXIS_P_H +#define POLARCHARTAXIS_P_H + +#include "chartaxiselement_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class PolarChartAxis : public ChartAxisElement +{ + Q_OBJECT + Q_INTERFACES(QGraphicsLayoutItem) +public: + PolarChartAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis = false); + ~PolarChartAxis(); + + void setGeometry(const QRectF &axis, const QRectF &grid); + virtual qreal preferredAxisRadius(const QSizeF &maxSize) = 0; + int tickWidth() { return 3; } + +public: // from ChartAxisElement + QRectF gridGeometry() const; + bool isEmpty(); + +protected: + void updateLayout(QVector<qreal> &layout); + +protected: // virtual functions + virtual void createItems(int count) = 0; + virtual void createAxisLabels(const QVector<qreal> &layout) = 0; + +public Q_SLOTS: + virtual void handleShadesBrushChanged(const QBrush &brush); + virtual void handleShadesPenChanged(const QPen &pen); + +private: + void deleteItems(int count); +}; + +QT_CHARTS_END_NAMESPACE + +#endif // POLARCHARTAXIS_P_H diff --git a/src/charts/axis/polarchartaxisangular.cpp b/src/charts/axis/polarchartaxisangular.cpp new file mode 100644 index 00000000..83f1535c --- /dev/null +++ b/src/charts/axis/polarchartaxisangular.cpp @@ -0,0 +1,433 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "polarchartaxisangular_p.h" +#include "chartpresenter_p.h" +#include "abstractchartlayout_p.h" +#include "qabstractaxis.h" +#include "qabstractaxis_p.h" +#include <QDebug> +#include <qmath.h> +#include <QTextDocument> + +QT_CHARTS_BEGIN_NAMESPACE + +PolarChartAxisAngular::PolarChartAxisAngular(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis) + : PolarChartAxis(axis, item, intervalAxis) +{ +} + +PolarChartAxisAngular::~PolarChartAxisAngular() +{ +} + +void PolarChartAxisAngular::updateGeometry() +{ + QGraphicsLayoutItem::updateGeometry(); + + const QVector<qreal> &layout = this->layout(); + if (layout.isEmpty()) + return; + + createAxisLabels(layout); + QStringList labelList = labels(); + QPointF center = axisGeometry().center(); + QList<QGraphicsItem *> arrowItemList = arrowItems(); + QList<QGraphicsItem *> gridItemList = gridItems(); + QList<QGraphicsItem *> labelItemList = labelItems(); + QList<QGraphicsItem *> shadeItemList = shadeItems(); + QGraphicsTextItem *title = titleItem(); + + QGraphicsEllipseItem *axisLine = static_cast<QGraphicsEllipseItem *>(arrowItemList.at(0)); + axisLine->setRect(axisGeometry()); + + qreal radius = axisGeometry().height() / 2.0; + + QRectF previousLabelRect; + QRectF firstLabelRect; + + qreal labelHeight = 0; + + bool firstShade = true; + bool nextTickVisible = false; + if (layout.size()) + nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > 360.0); + + for (int i = 0; i < layout.size(); ++i) { + qreal angularCoordinate = layout.at(i); + + QGraphicsLineItem *gridLineItem = static_cast<QGraphicsLineItem *>(gridItemList.at(i)); + QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1)); + QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labelItemList.at(i)); + QGraphicsPathItem *shadeItem = 0; + if (i == 0) + shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0)); + else if (i % 2) + shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1)); + + // Ignore ticks outside valid range + bool currentTickVisible = nextTickVisible; + if ((i == layout.size() - 1) + || layout.at(i + 1) < 0.0 + || layout.at(i + 1) > 360.0) { + nextTickVisible = false; + } else { + nextTickVisible = true; + } + + qreal labelCoordinate = angularCoordinate; + qreal labelVisible = currentTickVisible; + if (intervalAxis()) { + qreal farEdge; + if (i == (layout.size() - 1)) + farEdge = 360.0; + else + farEdge = qMin(qreal(360.0), layout.at(i + 1)); + + // Adjust the labelCoordinate to show it if next tick is visible + if (nextTickVisible) + labelCoordinate = qMax(qreal(0.0), labelCoordinate); + + labelCoordinate = (labelCoordinate + farEdge) / 2.0; + // Don't display label once the category gets too small near the axis + if (labelCoordinate < 5.0 || labelCoordinate > 355.0) + labelVisible = false; + else + labelVisible = true; + } + + // Need this also in label calculations, so determine it first + QLineF tickLine(QLineF::fromPolar(radius - tickWidth(), 90.0 - angularCoordinate).p2(), + QLineF::fromPolar(radius + tickWidth(), 90.0 - angularCoordinate).p2()); + tickLine.translate(center); + + // Angular axis label + if (axis()->labelsVisible() && labelVisible) { + QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), + labelList.at(i), + axis()->labelsAngle()); + labelItem->setTextWidth(boundingRect.width()); + labelItem->setHtml(labelList.at(i)); + const QRectF &rect = labelItem->boundingRect(); + QPointF labelCenter = rect.center(); + labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y()); + boundingRect.moveCenter(labelCenter); + QPointF positionDiff(rect.topLeft() - boundingRect.topLeft()); + + QPointF labelPoint; + if (intervalAxis()) { + QLineF labelLine = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate); + labelLine.translate(center); + labelPoint = labelLine.p2(); + } else { + labelPoint = tickLine.p2(); + } + + QRectF labelRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect); + labelItem->setPos(labelRect.topLeft() + positionDiff); + + // Store height for title calculations + qreal labelClearance = axisGeometry().top() - labelRect.top(); + labelHeight = qMax(labelHeight, labelClearance); + + // Label overlap detection + if (i && (previousLabelRect.intersects(labelRect) || firstLabelRect.intersects(labelRect))) { + labelVisible = false; + } else { + // Store labelRect for future comparison. Some area is deducted to make things look + // little nicer, as usually intersection happens at label corner with angular labels. + labelRect.adjust(-2.0, -4.0, -2.0, -4.0); + if (firstLabelRect.isEmpty()) + firstLabelRect = labelRect; + + previousLabelRect = labelRect; + labelVisible = true; + } + } + + labelItem->setVisible(labelVisible); + if (!currentTickVisible) { + gridLineItem->setVisible(false); + tickItem->setVisible(false); + if (shadeItem) + shadeItem->setVisible(false); + continue; + } + + // Angular grid line + QLineF gridLine = QLineF::fromPolar(radius, 90.0 - angularCoordinate); + gridLine.translate(center); + gridLineItem->setLine(gridLine); + gridLineItem->setVisible(true); + + // Tick + tickItem->setLine(tickLine); + tickItem->setVisible(true); + + // Shades + if (i % 2 || (i == 0 && !nextTickVisible)) { + QPainterPath path; + path.moveTo(center); + if (i == 0) { + // If first tick is also the last, we need to custom fill the first partial arc + // or it won't get filled. + path.arcTo(axisGeometry(), 90.0 - layout.at(0), layout.at(0)); + path.closeSubpath(); + } else { + qreal nextCoordinate; + if (!nextTickVisible) // Last visible tick + nextCoordinate = 360.0; + else + nextCoordinate = layout.at(i + 1); + qreal arcSpan = angularCoordinate - nextCoordinate; + path.arcTo(axisGeometry(), 90.0 - angularCoordinate, arcSpan); + path.closeSubpath(); + + // Add additional arc for first shade item if there is a partial arc to be filled + if (firstShade) { + QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0)); + if (layout.at(i - 1) > 0.0) { + QPainterPath specialPath; + specialPath.moveTo(center); + specialPath.arcTo(axisGeometry(), 90.0 - layout.at(i - 1), layout.at(i - 1)); + specialPath.closeSubpath(); + specialShadeItem->setPath(specialPath); + specialShadeItem->setVisible(true); + } else { + specialShadeItem->setVisible(false); + } + } + } + shadeItem->setPath(path); + shadeItem->setVisible(true); + firstShade = false; + } + } + + // Title, centered above the chart + QString titleText = axis()->titleText(); + if (!titleText.isEmpty() && axis()->isTitleVisible()) { + QRectF truncatedRect; + qreal availableTitleHeight = axisGeometry().height() - labelPadding() - titlePadding() * 2.0; + qreal minimumLabelHeight = ChartPresenter::textBoundingRect(axis()->labelsFont(), + QStringLiteral("...")).height(); + availableTitleHeight -= minimumLabelHeight; + title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0), + axisGeometry().width(), availableTitleHeight, + truncatedRect)); + title->setTextWidth(truncatedRect.width()); + + QRectF titleBoundingRect = title->boundingRect(); + QPointF titleCenter = center - titleBoundingRect.center(); + title->setPos(titleCenter.x(), axisGeometry().top() - titlePadding() * 2.0 - titleBoundingRect.height() - labelHeight); + } +} + +Qt::Orientation PolarChartAxisAngular::orientation() const +{ + return Qt::Horizontal; +} + +void PolarChartAxisAngular::createItems(int count) +{ + if (arrowItems().count() == 0) { + // angular axis line + QGraphicsEllipseItem *arrow = new QGraphicsEllipseItem(presenter()->rootItem()); + arrow->setPen(axis()->linePen()); + arrowGroup()->addToGroup(arrow); + } + + QGraphicsTextItem *title = titleItem(); + title->setFont(axis()->titleFont()); + title->setDefaultTextColor(axis()->titleBrush().color()); + title->setHtml(axis()->titleText()); + + for (int i = 0; i < count; ++i) { + QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem()); + QGraphicsLineItem *grid = new QGraphicsLineItem(presenter()->rootItem()); + QGraphicsTextItem *label = new QGraphicsTextItem(presenter()->rootItem()); + label->document()->setDocumentMargin(ChartPresenter::textMargin()); + arrow->setPen(axis()->linePen()); + grid->setPen(axis()->gridLinePen()); + label->setFont(axis()->labelsFont()); + label->setDefaultTextColor(axis()->labelsBrush().color()); + label->setRotation(axis()->labelsAngle()); + arrowGroup()->addToGroup(arrow); + gridGroup()->addToGroup(grid); + labelGroup()->addToGroup(label); + if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) { + QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem()); + shade->setPen(axis()->shadesPen()); + shade->setBrush(axis()->shadesBrush()); + shadeGroup()->addToGroup(shade); + } + } +} + +void PolarChartAxisAngular::handleArrowPenChanged(const QPen &pen) +{ + bool first = true; + foreach (QGraphicsItem *item, arrowItems()) { + if (first) { + first = false; + // First arrow item is the outer circle of axis + static_cast<QGraphicsEllipseItem *>(item)->setPen(pen); + } else { + static_cast<QGraphicsLineItem *>(item)->setPen(pen); + } + } +} + +void PolarChartAxisAngular::handleGridPenChanged(const QPen &pen) +{ + foreach (QGraphicsItem *item, gridItems()) + static_cast<QGraphicsLineItem *>(item)->setPen(pen); +} + +QSizeF PolarChartAxisAngular::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const +{ + Q_UNUSED(which); + Q_UNUSED(constraint); + return QSizeF(-1, -1); +} + +qreal PolarChartAxisAngular::preferredAxisRadius(const QSizeF &maxSize) +{ + qreal radius = maxSize.height() / 2.0; + if (maxSize.width() < maxSize.height()) + radius = maxSize.width() / 2.0; + + if (axis()->labelsVisible()) { + QVector<qreal> layout = calculateLayout(); + if (layout.isEmpty()) + return radius; + + createAxisLabels(layout); + QStringList labelList = labels(); + QFont font = axis()->labelsFont(); + + QRectF maxRect; + maxRect.setSize(maxSize); + maxRect.moveCenter(QPointF(0.0, 0.0)); + + // This is a horrible way to find out the maximum radius for angular axis and its labels. + // It just increments the radius down until everyhing fits the constraint size. + // Proper way would be to actually calculate it but this seems to work reasonably fast as it is. + bool nextTickVisible = false; + for (int i = 0; i < layout.size(); ) { + if ((i == layout.size() - 1) + || layout.at(i + 1) < 0.0 + || layout.at(i + 1) > 360.0) { + nextTickVisible = false; + } else { + nextTickVisible = true; + } + + qreal labelCoordinate = layout.at(i); + qreal labelVisible; + + if (intervalAxis()) { + qreal farEdge; + if (i == (layout.size() - 1)) + farEdge = 360.0; + else + farEdge = qMin(qreal(360.0), layout.at(i + 1)); + + // Adjust the labelCoordinate to show it if next tick is visible + if (nextTickVisible) + labelCoordinate = qMax(qreal(0.0), labelCoordinate); + + labelCoordinate = (labelCoordinate + farEdge) / 2.0; + } + + if (labelCoordinate < 0.0 || labelCoordinate > 360.0) + labelVisible = false; + else + labelVisible = true; + + if (!labelVisible) { + i++; + continue; + } + + QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle()); + QPointF labelPoint = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate).p2(); + + boundingRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect); + QRectF intersectRect = maxRect.intersected(boundingRect); + if (boundingRect.isEmpty() || intersectRect == boundingRect) { + i++; + } else { + qreal reduction(0.0); + // If there is no intersection, reduce by smallest dimension of label rect to be on the safe side + if (intersectRect.isEmpty()) { + reduction = qMin(boundingRect.height(), boundingRect.width()); + } else { + // Approximate needed radius reduction is the amount label rect exceeds max rect in either dimension. + // Could be further optimized by figuring out the proper math how to calculate exact needed reduction. + reduction = qMax(boundingRect.height() - intersectRect.height(), + boundingRect.width() - intersectRect.width()); + } + // Typically the approximated reduction is little low, so add one + radius -= (reduction + 1.0); + + if (radius < 1.0) // safeguard + return 1.0; + } + } + } + + if (!axis()->titleText().isEmpty() && axis()->isTitleVisible()) { + QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText()); + + radius -= titlePadding() + (titleRect.height() / 2.0); + if (radius < 1.0) // safeguard + return 1.0; + } + + return radius; +} + +QRectF PolarChartAxisAngular::moveLabelToPosition(qreal angularCoordinate, QPointF labelPoint, QRectF labelRect) const +{ + if (angularCoordinate == 0.0) + labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0)); + else if (angularCoordinate < 90.0) + labelRect.moveBottomLeft(labelPoint); + else if (angularCoordinate == 90.0) + labelRect.moveCenter(labelPoint + QPointF(labelRect.width() / 2.0 + 2.0, 0)); // +2 so that it does not hit the radial axis + else if (angularCoordinate < 180.0) + labelRect.moveTopLeft(labelPoint); + else if (angularCoordinate == 180.0) + labelRect.moveCenter(labelPoint + QPointF(0, labelRect.height() / 2.0)); + else if (angularCoordinate < 270.0) + labelRect.moveTopRight(labelPoint); + else if (angularCoordinate == 270.0) + labelRect.moveCenter(labelPoint + QPointF(-labelRect.width() / 2.0 - 2.0, 0)); // -2 so that it does not hit the radial axis + else if (angularCoordinate < 360.0) + labelRect.moveBottomRight(labelPoint); + else + labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0)); + return labelRect; +} + +#include "moc_polarchartaxisangular_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/polarchartaxisangular_p.h b/src/charts/axis/polarchartaxisangular_p.h new file mode 100644 index 00000000..dd83cba7 --- /dev/null +++ b/src/charts/axis/polarchartaxisangular_p.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef POLARCHARTAXISANGULAR_P_H +#define POLARCHARTAXISANGULAR_P_H + +#include "polarchartaxis_p.h" +#include "qvalueaxis.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class PolarChartAxisAngular : public PolarChartAxis +{ + Q_OBJECT +public: + PolarChartAxisAngular(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis = false); + ~PolarChartAxisAngular(); + + Qt::Orientation orientation() const; + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const; + + virtual void updateGeometry(); + virtual void createItems(int count); + + qreal preferredAxisRadius(const QSizeF &maxSize); + +public Q_SLOTS: + virtual void handleArrowPenChanged(const QPen &pen); + virtual void handleGridPenChanged(const QPen &pen); + +private: + QRectF moveLabelToPosition(qreal angularCoordinate, QPointF labelPoint, QRectF labelRect) const; +}; + +QT_CHARTS_END_NAMESPACE + +#endif // POLARCHARTAXISANGULAR_P_H diff --git a/src/charts/axis/polarchartaxisradial.cpp b/src/charts/axis/polarchartaxisradial.cpp new file mode 100644 index 00000000..93bf1bd9 --- /dev/null +++ b/src/charts/axis/polarchartaxisradial.cpp @@ -0,0 +1,297 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "polarchartaxisradial_p.h" +#include "chartpresenter_p.h" +#include "abstractchartlayout_p.h" +#include "qabstractaxis_p.h" +#include "linearrowitem_p.h" +#include <QTextDocument> + +QT_CHARTS_BEGIN_NAMESPACE + +PolarChartAxisRadial::PolarChartAxisRadial(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis) + : PolarChartAxis(axis, item, intervalAxis) +{ +} + +PolarChartAxisRadial::~PolarChartAxisRadial() +{ +} + +void PolarChartAxisRadial::updateGeometry() +{ + const QVector<qreal> &layout = this->layout(); + if (layout.isEmpty()) + return; + + createAxisLabels(layout); + QStringList labelList = labels(); + QPointF center = axisGeometry().center(); + QList<QGraphicsItem *> arrowItemList = arrowItems(); + QList<QGraphicsItem *> gridItemList = gridItems(); + QList<QGraphicsItem *> labelItemList = labelItems(); + QList<QGraphicsItem *> shadeItemList = shadeItems(); + QGraphicsTextItem* title = titleItem(); + qreal radius = axisGeometry().height() / 2.0; + + QLineF line(center, center + QPointF(0, -radius)); + QGraphicsLineItem *axisLine = static_cast<QGraphicsLineItem *>(arrowItemList.at(0)); + axisLine->setLine(line); + + QRectF previousLabelRect; + bool firstShade = true; + bool nextTickVisible = false; + if (layout.size()) + nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > radius); + + for (int i = 0; i < layout.size(); ++i) { + qreal radialCoordinate = layout.at(i); + + QGraphicsEllipseItem *gridItem = static_cast<QGraphicsEllipseItem *>(gridItemList.at(i)); + QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1)); + QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labelItemList.at(i)); + QGraphicsPathItem *shadeItem = 0; + if (i == 0) + shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0)); + else if (i % 2) + shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1)); + + // Ignore ticks outside valid range + bool currentTickVisible = nextTickVisible; + if ((i == layout.size() - 1) + || layout.at(i + 1) < 0.0 + || layout.at(i + 1) > radius) { + nextTickVisible = false; + } else { + nextTickVisible = true; + } + + qreal labelCoordinate = radialCoordinate; + qreal labelVisible = currentTickVisible; + qreal labelPad = labelPadding() / 2.0; + if (intervalAxis()) { + qreal farEdge; + if (i == (layout.size() - 1)) + farEdge = radius; + else + farEdge = qMin(radius, layout.at(i + 1)); + + // Adjust the labelCoordinate to show it if next tick is visible + if (nextTickVisible) + labelCoordinate = qMax(qreal(0.0), labelCoordinate); + + labelCoordinate = (labelCoordinate + farEdge) / 2.0; + if (labelCoordinate > 0.0 && labelCoordinate < radius) + labelVisible = true; + else + labelVisible = false; + } + + // Radial axis label + if (axis()->labelsVisible() && labelVisible) { + QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), + labelList.at(i), + axis()->labelsAngle()); + labelItem->setTextWidth(boundingRect.width()); + labelItem->setHtml(labelList.at(i)); + QRectF labelRect = labelItem->boundingRect(); + QPointF labelCenter = labelRect.center(); + labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y()); + boundingRect.moveCenter(labelCenter); + QPointF positionDiff(labelRect.topLeft() - boundingRect.topLeft()); + QPointF labelPoint = center; + if (intervalAxis()) + labelPoint += QPointF(labelPad, -labelCoordinate - (boundingRect.height() / 2.0)); + else + labelPoint += QPointF(labelPad, labelPad - labelCoordinate); + labelRect.moveTopLeft(labelPoint); + labelItem->setPos(labelRect.topLeft() + positionDiff); + + // Label overlap detection + labelRect.setSize(boundingRect.size()); + if ((i && previousLabelRect.intersects(labelRect)) + || !axisGeometry().contains(labelRect)) { + labelVisible = false; + } else { + previousLabelRect = labelRect; + labelVisible = true; + } + } + + labelItem->setVisible(labelVisible); + if (!currentTickVisible) { + gridItem->setVisible(false); + tickItem->setVisible(false); + if (shadeItem) + shadeItem->setVisible(false); + continue; + } + + // Radial grid line + QRectF gridRect; + gridRect.setWidth(radialCoordinate * 2.0); + gridRect.setHeight(radialCoordinate * 2.0); + gridRect.moveCenter(center); + + gridItem->setRect(gridRect); + gridItem->setVisible(true); + + // Tick + QLineF tickLine(-tickWidth(), 0.0, tickWidth(), 0.0); + tickLine.translate(center.rx(), gridRect.top()); + tickItem->setLine(tickLine); + tickItem->setVisible(true); + + // Shades + if (i % 2 || (i == 0 && !nextTickVisible)) { + QPainterPath path; + if (i == 0) { + // If first tick is also the last, we need to custom fill the inner circle + // or it won't get filled. + QRectF innerCircle(0.0, 0.0, layout.at(0) * 2.0, layout.at(0) * 2.0); + innerCircle.moveCenter(center); + path.addEllipse(innerCircle); + } else { + QRectF otherGridRect; + if (!nextTickVisible) { // Last visible tick + otherGridRect = axisGeometry(); + } else { + qreal otherGridRectDimension = layout.at(i + 1) * 2.0; + otherGridRect.setWidth(otherGridRectDimension); + otherGridRect.setHeight(otherGridRectDimension); + otherGridRect.moveCenter(center); + } + path.addEllipse(gridRect); + path.addEllipse(otherGridRect); + + // Add additional shading in first visible shade item if there is a partial tick + // to be filled at the center (log & category axes) + if (firstShade) { + QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0)); + if (layout.at(i - 1) > 0.0) { + QRectF innerCircle(0.0, 0.0, layout.at(i - 1) * 2.0, layout.at(i - 1) * 2.0); + innerCircle.moveCenter(center); + QPainterPath specialPath; + specialPath.addEllipse(innerCircle); + specialShadeItem->setPath(specialPath); + specialShadeItem->setVisible(true); + } else { + specialShadeItem->setVisible(false); + } + } + } + shadeItem->setPath(path); + shadeItem->setVisible(true); + firstShade = false; + } + } + + // Title, along the 0 axis + QString titleText = axis()->titleText(); + if (!titleText.isEmpty() && axis()->isTitleVisible()) { + QRectF truncatedRect; + title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0), + radius, radius, truncatedRect)); + title->setTextWidth(truncatedRect.width()); + + QRectF titleBoundingRect = title->boundingRect(); + QPointF titleCenter = titleBoundingRect.center(); + QPointF arrowCenter = axisLine->boundingRect().center(); + QPointF titleCenterDiff = arrowCenter - titleCenter; + title->setPos(titleCenterDiff.x() - titlePadding() - (titleBoundingRect.height() / 2.0), titleCenterDiff.y()); + title->setTransformOriginPoint(titleCenter); + title->setRotation(270.0); + } + + QGraphicsLayoutItem::updateGeometry(); +} + +Qt::Orientation PolarChartAxisRadial::orientation() const +{ + return Qt::Vertical; +} + +void PolarChartAxisRadial::createItems(int count) +{ + if (arrowItems().count() == 0) { + // radial axis center line + QGraphicsLineItem *arrow = new LineArrowItem(this, presenter()->rootItem()); + arrow->setPen(axis()->linePen()); + arrowGroup()->addToGroup(arrow); + } + + QGraphicsTextItem *title = titleItem(); + title->setFont(axis()->titleFont()); + title->setDefaultTextColor(axis()->titleBrush().color()); + title->setHtml(axis()->titleText()); + + for (int i = 0; i < count; ++i) { + QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem()); + QGraphicsEllipseItem *grid = new QGraphicsEllipseItem(presenter()->rootItem()); + QGraphicsTextItem *label = new QGraphicsTextItem(presenter()->rootItem()); + label->document()->setDocumentMargin(ChartPresenter::textMargin()); + arrow->setPen(axis()->linePen()); + grid->setPen(axis()->gridLinePen()); + label->setFont(axis()->labelsFont()); + label->setDefaultTextColor(axis()->labelsBrush().color()); + label->setRotation(axis()->labelsAngle()); + arrowGroup()->addToGroup(arrow); + gridGroup()->addToGroup(grid); + labelGroup()->addToGroup(label); + if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) { + QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem()); + shade->setPen(axis()->shadesPen()); + shade->setBrush(axis()->shadesBrush()); + shadeGroup()->addToGroup(shade); + } + } +} + +void PolarChartAxisRadial::handleArrowPenChanged(const QPen &pen) +{ + foreach (QGraphicsItem *item, arrowItems()) + static_cast<QGraphicsLineItem *>(item)->setPen(pen); +} + +void PolarChartAxisRadial::handleGridPenChanged(const QPen &pen) +{ + foreach (QGraphicsItem *item, gridItems()) + static_cast<QGraphicsEllipseItem *>(item)->setPen(pen); +} + +QSizeF PolarChartAxisRadial::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const +{ + Q_UNUSED(which); + Q_UNUSED(constraint); + return QSizeF(-1.0, -1.0); +} + +qreal PolarChartAxisRadial::preferredAxisRadius(const QSizeF &maxSize) +{ + qreal radius = maxSize.height() / 2.0; + if (maxSize.width() < maxSize.height()) + radius = maxSize.width() / 2.0; + return radius; +} + +#include "moc_polarchartaxisradial_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/polarchartaxisradial_p.h b/src/charts/axis/polarchartaxisradial_p.h new file mode 100644 index 00000000..6ce21513 --- /dev/null +++ b/src/charts/axis/polarchartaxisradial_p.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef POLARCHARTAXISRADIAL_P_H +#define POLARCHARTAXISRADIAL_P_H + +#include "polarchartaxis_p.h" +#include "qvalueaxis.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class PolarChartAxisRadial : public PolarChartAxis +{ + Q_OBJECT +public: + PolarChartAxisRadial(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis = false); + ~PolarChartAxisRadial(); + + Qt::Orientation orientation() const; + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const; + + virtual void updateGeometry(); + virtual void createItems(int count); + + qreal preferredAxisRadius(const QSizeF &maxSize); + +public Q_SLOTS: + virtual void handleArrowPenChanged(const QPen &pen); + virtual void handleGridPenChanged(const QPen &pen); +}; + +QT_CHARTS_END_NAMESPACE + +#endif // POLARCHARTAXISRADIAL_P_H diff --git a/src/charts/axis/qabstractaxis.cpp b/src/charts/axis/qabstractaxis.cpp new file mode 100644 index 00000000..ff7c27b6 --- /dev/null +++ b/src/charts/axis/qabstractaxis.cpp @@ -0,0 +1,1012 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qabstractaxis.h" +#include "qabstractaxis_p.h" +#include "chartdataset_p.h" +#include "charttheme_p.h" +#include "qchart_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +/*! + \class QAbstractAxis + \inmodule Qt Charts + \brief The QAbstractAxis class is used for manipulating chart's axis. + \mainclass + + Each series can be bound to one or more horizontal and vertical axes, but mixing axis types + that would result in different domains is not supported, such as specifying + QValueAxis and QLogValueAxis on the same orientation. + + Properties and visibility of various axis elements such as axis line, title, labels, grid lines, + and shades can be individually controlled. +*/ +/*! + \qmltype AbstractAxis + \instantiates QAbstractAxis + \inqmlmodule QtCharts + + \brief The AbstractAxis is a base element used for specialized axis elements. + + Each series can be bound to only one horizontal and vertical axis. + + Properties and visibility of various axis elements such as axis line, title, labels, grid lines, + and shades can be individually controlled. +*/ + +/*! + \enum QAbstractAxis::AxisType + + The type of the series object. + + \value AxisTypeNoAxis + \value AxisTypeValue + \value AxisTypeBarCategory + \value AxisTypeCategory + \value AxisTypeDateTime + \value AxisTypeLogValue +*/ + +/*! + *\fn void QAbstractAxis::type() const + Returns the type of the axis +*/ + +/*! + \property QAbstractAxis::lineVisible + The visibility of the axis line +*/ +/*! + \qmlproperty bool AbstractAxis::lineVisible + The visibility of the axis line +*/ + +/*! + \property QAbstractAxis::linePen + The pen of the line. +*/ + +/*! + \property QAbstractAxis::labelsVisible + Defines if axis labels are visible. +*/ +/*! + \qmlproperty bool AbstractAxis::labelsVisible + Defines if axis labels are visible. +*/ + +/*! + \property QAbstractAxis::labelsPen + \deprecated + The pen of the labels. +*/ + +/*! + \property QAbstractAxis::labelsBrush + The brush of the labels. Only the color of the brush is relevant. +*/ + +/*! + \property QAbstractAxis::visible + The visibility of the axis. +*/ +/*! + \qmlproperty bool AbstractAxis::visible + The visibility of the axis. +*/ + +/*! + \property QAbstractAxis::gridVisible + The visibility of the grid lines. +*/ +/*! + \qmlproperty bool AbstractAxis::gridVisible + The visibility of the grid lines. +*/ + +/*! + \property QAbstractAxis::color + The color of the axis and ticks. +*/ +/*! + \qmlproperty color AbstractAxis::color + The color of the axis and ticks. +*/ + +/*! + \property QAbstractAxis::gridLinePen + The pen of the grid line. +*/ + +/*! + \property QAbstractAxis::labelsFont + The font of the axis labels. +*/ + +/*! + \qmlproperty Font AbstractAxis::labelsFont + The font of the axis labels. + + See the Qt documentation for more details of Font. +*/ + +/*! + \property QAbstractAxis::labelsColor + The color of the axis labels. +*/ +/*! + \qmlproperty color AbstractAxis::labelsColor + The color of the axis labels. +*/ + +/*! + \property QAbstractAxis::labelsAngle + The angle of the axis labels in degrees. +*/ +/*! + \qmlproperty int AbstractAxis::labelsAngle + The angle of the axis labels in degrees. +*/ + +/*! + \property QAbstractAxis::shadesVisible + The visibility of the axis shades. +*/ +/*! + \qmlproperty bool AbstractAxis::shadesVisible + The visibility of the axis shades. +*/ + +/*! + \property QAbstractAxis::shadesColor + The fill (brush) color of the axis shades. +*/ +/*! + \qmlproperty color AbstractAxis::shadesColor + The fill (brush) color of the axis shades. +*/ + +/*! + \property QAbstractAxis::shadesBorderColor + The border (pen) color of the axis shades. +*/ +/*! + \qmlproperty color AbstractAxis::shadesBorderColor + The border (pen) color of the axis shades. +*/ + +/*! + \property QAbstractAxis::shadesPen + The pen of the axis shades (area between grid lines). +*/ + +/*! + \property QAbstractAxis::shadesBrush + The brush of the axis shades (area between grid lines). +*/ + +/*! + \property QAbstractAxis::titleVisible + The visibility of the axis title. By default the value is true. +*/ +/*! + \qmlproperty bool AbstractAxis::titleVisible + The visibility of the axis title. By default the value is true. +*/ + +/*! + \property QAbstractAxis::titleText + The title of the axis. Empty by default. Axis titles support html formatting. +*/ +/*! + \qmlproperty String AbstractAxis::titleText + The title of the axis. Empty by default. Axis titles support html formatting. +*/ + +/*! + \property QAbstractAxis::titlePen + \deprecated + The pen of the title text. +*/ + +/*! + \property QAbstractAxis::titleBrush + The brush of the title text. Only the color of the brush is relevant. +*/ + +/*! + \property QAbstractAxis::titleFont + The font of the title of the axis. +*/ +/*! + \qmlproperty Font AbstractAxis::titleFont + The font of the title of the axis. +*/ + +/*! + \property QAbstractAxis::orientation + The orientation of the axis. Fixed to either Qt::Horizontal or Qt::Vertical when you add the axis to a chart. +*/ +/*! + \qmlproperty Qt.Orientation AbstractAxis::orientation + The orientation of the axis. Fixed to either Qt.Horizontal or Qt.Vertical when the axis is set to a series. +*/ + +/*! + \property QAbstractAxis::alignment + The alignment of the axis. Can be Qt::AlignLeft, Qt::AlignRight, Qt::AlignBottom, or Qt::AlignTop. +*/ +/*! + \qmlproperty alignment AbstractAxis::alignment + The alignment of the axis. Can be Qt.AlignLeft, Qt.AlignRight, Qt.AlignBottom, or Qt.AlignTop. +*/ + +/*! + \fn void QAbstractAxis::visibleChanged(bool visible) + Visibility of the axis has changed to \a visible. +*/ +/*! + \qmlsignal AbstractAxis::onVisibleChanged(bool visible) + Visibility of the axis has changed to \a visible. +*/ + +/*! + \fn void QAbstractAxis::linePenChanged(const QPen& pen) + The pen of the line of the axis has changed to \a pen. +*/ + +/*! + \fn void QAbstractAxis::lineVisibleChanged(bool visible) + Visibility of the axis line has changed to \a visible. +*/ +/*! + \qmlsignal AbstractAxis::onLineVisibleChanged(bool visible) + Visibility of the axis line has changed to \a visible. +*/ + +/*! + \fn void QAbstractAxis::labelsVisibleChanged(bool visible) + Visibility of the labels of the axis has changed to \a visible. +*/ +/*! + \qmlsignal AbstractAxis::onLabelsVisibleChanged(bool visible) + Visibility of the labels of the axis has changed to \a visible. +*/ + +/*! + \fn void QAbstractAxis::labelsFontChanged(const QFont& font) + The font of the axis labels has changed to \a font. +*/ +/*! + \qmlsignal AbstractAxis::onLabelsFontChanged(Font font) + The font of the axis labels has changed to \a font. +*/ + +/*! + \fn void QAbstractAxis::labelsPenChanged(const QPen& pen) + \deprecated + The pen of the axis labels has changed to \a pen. +*/ + +/*! + \fn void QAbstractAxis::labelsBrushChanged(const QBrush& brush) + The brush of the axis labels has changed to \a brush. +*/ + +/*! + \fn void QAbstractAxis::labelsAngleChanged(int angle) + The angle of the axis labels has changed to \a angle. +*/ +/*! + \qmlsignal AbstractAxis::onLabelsAngleChanged(int angle) + The angle of the axis labels has changed to \a angle. +*/ + +/*! + \fn void QAbstractAxis::gridVisibleChanged(bool visible) + Visibility of the grid lines of the axis has changed to \a visible. +*/ +/*! + \qmlsignal AbstractAxis::onGridVisibleChanged(bool visible) + Visibility of the grid lines of the axis has changed to \a visible. +*/ + +/*! + \fn void QAbstractAxis::gridLinePenChanged(const QPen& pen) + The pen of the grid line has changed to \a pen. +*/ + +/*! + \fn void QAbstractAxis::colorChanged(QColor color) + Emitted if the \a color of the axis is changed. +*/ +/*! + \qmlsignal AbstractAxis::onColorChanged(QColor color) + Emitted if the \a color of the axis is changed. +*/ + +/*! + \fn void QAbstractAxis::labelsColorChanged(QColor color) + Emitted if the \a color of the axis labels is changed. +*/ +/*! + \qmlsignal AbstractAxis::onLabelsColorChanged(QColor color) + Emitted if the \a color of the axis labels is changed. +*/ + +/*! + \fn void QAbstractAxis::titleVisibleChanged(bool visible) + Visibility of the title text of the axis has changed to \a visible. +*/ +/*! + \qmlsignal AbstractAxis::onTitleVisibleChanged(bool visible) + Visibility of the title text of the axis has changed to \a visible. +*/ + +/*! + \fn void QAbstractAxis::titleTextChanged(const QString& text) + The text of the axis title has changed to \a text. +*/ +/*! + \qmlsignal AbstractAxis::onTitleTextChanged(String text) + The text of the axis title has changed to \a text. +*/ + +/*! + \fn void QAbstractAxis::titlePenChanged(const QPen& pen) + \deprecated + The pen of the axis shades has changed to \a pen. +*/ + +/*! + \fn void QAbstractAxis::titleBrushChanged(const QBrush& brush) + The brush of the axis title has changed to \a brush. +*/ + +/*! + \fn void QAbstractAxis::titleFontChanged(const QFont& font) + The font of the axis title has changed to \a font. +*/ +/*! + \qmlsignal AbstractAxis::onTitleFontChanged(Font font) + The font of the axis title has changed to \a font. +*/ + +/*! + \fn void QAbstractAxis::shadesVisibleChanged(bool) + Emitted if the visibility of the axis shades is changed to \a visible. +*/ +/*! + \qmlsignal AbstractAxis::onShadesVisibleChanged(bool visible) + Emitted if the visibility of the axis shades is changed to \a visible. +*/ + +/*! + \fn void QAbstractAxis::shadesColorChanged(QColor color) + Emitted if the \a color of the axis shades is changed. +*/ +/*! + \qmlsignal AbstractAxis::onShadesColorChanged(QColor color) + Emitted if the \a color of the axis shades is changed. +*/ + +/*! + \fn void QAbstractAxis::shadesBorderColorChanged(QColor) + Emitted if the border \a color of the axis shades is changed. +*/ +/*! + \qmlsignal AbstractAxis::onBorderColorChanged(QColor color) + Emitted if the border \a color of the axis shades is changed. +*/ + +/*! + \fn void QAbstractAxis::shadesBrushChanged(const QBrush& brush) + The brush of the axis shades has changed to \a brush. +*/ + +/*! + \fn void QAbstractAxis::shadesPenChanged(const QPen& pen) + The pen of the axis shades has changed to \a pen. +*/ + +/*! + \internal + Constructs new axis object which is a child of \a parent. Ownership is taken by + QChart when axis added. +*/ + +QAbstractAxis::QAbstractAxis(QAbstractAxisPrivate &d, QObject *parent) + : QObject(parent), + d_ptr(&d) +{ +} + +/*! + Destructor of the axis object. When axis is added to chart, chart object takes ownership. +*/ + +QAbstractAxis::~QAbstractAxis() +{ + if (d_ptr->m_chart) + qFatal("Still binded axis detected !"); +} + +/*! + Sets \a pen used to draw axis line and ticks. + */ +void QAbstractAxis::setLinePen(const QPen &pen) +{ + if (d_ptr->m_axisPen != pen) { + d_ptr->m_axisPen = pen; + emit linePenChanged(pen); + } +} + +/*! + Returns pen used to draw axis and ticks. +*/ +QPen QAbstractAxis::linePen() const +{ + if (d_ptr->m_axisPen == QChartPrivate::defaultPen()) + return QPen(); + else + return d_ptr->m_axisPen; +} + +void QAbstractAxis::setLinePenColor(QColor color) +{ + QPen p = d_ptr->m_axisPen; + if (p.color() != color) { + p.setColor(color); + setLinePen(p); + emit colorChanged(color); + } +} + +QColor QAbstractAxis::linePenColor() const +{ + return linePen().color(); +} + +/*! + Sets if axis and ticks are \a visible. + */ +void QAbstractAxis::setLineVisible(bool visible) +{ + if (d_ptr->m_arrowVisible != visible) { + d_ptr->m_arrowVisible = visible; + emit lineVisibleChanged(visible); + } +} + +bool QAbstractAxis::isLineVisible() const +{ + return d_ptr->m_arrowVisible; +} + +void QAbstractAxis::setGridLineVisible(bool visible) +{ + if (d_ptr->m_gridLineVisible != visible) { + d_ptr->m_gridLineVisible = visible; + emit gridVisibleChanged(visible); + } +} + +bool QAbstractAxis::isGridLineVisible() const +{ + return d_ptr->m_gridLineVisible; +} + +/*! + Sets \a pen used to draw grid line. +*/ +void QAbstractAxis::setGridLinePen(const QPen &pen) +{ + if (d_ptr->m_gridLinePen != pen) { + d_ptr->m_gridLinePen = pen; + emit gridLinePenChanged(pen); + } +} + +/*! + Returns pen used to draw grid. +*/ +QPen QAbstractAxis::gridLinePen() const +{ + if (d_ptr->m_gridLinePen == QChartPrivate::defaultPen()) + return QPen(); + else + return d_ptr->m_gridLinePen; +} + +void QAbstractAxis::setLabelsVisible(bool visible) +{ + if (d_ptr->m_labelsVisible != visible) { + d_ptr->m_labelsVisible = visible; + emit labelsVisibleChanged(visible); + } +} + +bool QAbstractAxis::labelsVisible() const +{ + return d_ptr->m_labelsVisible; +} + +void QAbstractAxis::setLabelsPen(const QPen &pen) +{ + if (d_ptr->m_labelsPen != pen) { + d_ptr->m_labelsPen = pen; + emit labelsPenChanged(pen); + } +} + +QPen QAbstractAxis::labelsPen() const +{ + if (d_ptr->m_labelsPen == QChartPrivate::defaultPen()) + return QPen(); + else + return d_ptr->m_labelsPen; +} + +/*! + Sets \a brush used to draw labels. + */ +void QAbstractAxis::setLabelsBrush(const QBrush &brush) +{ + if (d_ptr->m_labelsBrush != brush) { + d_ptr->m_labelsBrush = brush; + emit labelsBrushChanged(brush); + } +} + +/*! + Returns brush used to draw labels. +*/ +QBrush QAbstractAxis::labelsBrush() const +{ + if (d_ptr->m_labelsBrush == QChartPrivate::defaultBrush()) + return QBrush(); + else + return d_ptr->m_labelsBrush; +} + +/*! + Sets \a font used to draw labels. +*/ +void QAbstractAxis::setLabelsFont(const QFont &font) +{ + if (d_ptr->m_labelsFont != font) { + d_ptr->m_labelsFont = font; + emit labelsFontChanged(font); + } +} + +/*! + Returns font used to draw labels. +*/ +QFont QAbstractAxis::labelsFont() const +{ + if (d_ptr->m_labelsFont == QChartPrivate::defaultFont()) + return QFont(); + else + return d_ptr->m_labelsFont; +} + +void QAbstractAxis::setLabelsAngle(int angle) +{ + if (d_ptr->m_labelsAngle != angle) { + d_ptr->m_labelsAngle = angle; + emit labelsAngleChanged(angle); + } +} + +int QAbstractAxis::labelsAngle() const +{ + return d_ptr->m_labelsAngle; +} +void QAbstractAxis::setLabelsColor(QColor color) +{ + QBrush b = d_ptr->m_labelsBrush; + if (b.color() != color) { + b.setColor(color); + setLabelsBrush(b); + emit labelsColorChanged(color); + } +} + +QColor QAbstractAxis::labelsColor() const +{ + return labelsBrush().color(); +} + +void QAbstractAxis::setTitleVisible(bool visible) +{ + if (d_ptr->m_titleVisible != visible) { + d_ptr->m_titleVisible = visible; + emit titleVisibleChanged(visible); + } +} + +bool QAbstractAxis::isTitleVisible() const +{ + return d_ptr->m_titleVisible; +} + +void QAbstractAxis::setTitlePen(const QPen &pen) +{ + if (d_ptr->m_titlePen != pen) { + d_ptr->m_titlePen = pen; + emit titlePenChanged(pen); + } +} + +QPen QAbstractAxis::titlePen() const +{ + if (d_ptr->m_titlePen == QChartPrivate::defaultPen()) + return QPen(); + else + return d_ptr->m_titlePen; +} + +/*! + Sets \a brush used to draw title. + */ +void QAbstractAxis::setTitleBrush(const QBrush &brush) +{ + if (d_ptr->m_titleBrush != brush) { + d_ptr->m_titleBrush = brush; + emit titleBrushChanged(brush); + } +} + +/*! + Returns brush used to draw title. +*/ +QBrush QAbstractAxis::titleBrush() const +{ + if (d_ptr->m_titleBrush == QChartPrivate::defaultBrush()) + return QBrush(); + else + return d_ptr->m_titleBrush; +} + +/*! + Sets \a font used to draw title. +*/ +void QAbstractAxis::setTitleFont(const QFont &font) +{ + if (d_ptr->m_titleFont != font) { + d_ptr->m_titleFont = font; + emit titleFontChanged(font); + } +} + +/*! + Returns font used to draw title. +*/ +QFont QAbstractAxis::titleFont() const +{ + if (d_ptr->m_titleFont == QChartPrivate::defaultFont()) + return QFont(); + else + return d_ptr->m_titleFont; +} + +void QAbstractAxis::setTitleText(const QString &title) +{ + if (d_ptr->m_title != title) { + d_ptr->m_title = title; + emit titleTextChanged(title); + } +} + +QString QAbstractAxis::titleText() const +{ + return d_ptr->m_title; +} + + +void QAbstractAxis::setShadesVisible(bool visible) +{ + if (d_ptr->m_shadesVisible != visible) { + d_ptr->m_shadesVisible = visible; + emit shadesVisibleChanged(visible); + } +} + +bool QAbstractAxis::shadesVisible() const +{ + return d_ptr->m_shadesVisible; +} + +/*! + Sets \a pen used to draw shades. +*/ +void QAbstractAxis::setShadesPen(const QPen &pen) +{ + if (d_ptr->m_shadesPen != pen) { + d_ptr->m_shadesPen = pen; + emit shadesPenChanged(pen); + } +} + +/*! + Returns pen used to draw shades. +*/ +QPen QAbstractAxis::shadesPen() const +{ + if (d_ptr->m_shadesPen == QChartPrivate::defaultPen()) + return QPen(); + else + return d_ptr->m_shadesPen; +} + +/*! + Sets \a brush used to draw shades. +*/ +void QAbstractAxis::setShadesBrush(const QBrush &brush) +{ + if (d_ptr->m_shadesBrush != brush) { + d_ptr->m_shadesBrush = brush; + emit shadesBrushChanged(brush); + } +} + +/*! + Returns brush used to draw shades. +*/ +QBrush QAbstractAxis::shadesBrush() const +{ + if (d_ptr->m_shadesBrush == QChartPrivate::defaultBrush()) + return QBrush(Qt::SolidPattern); + else + return d_ptr->m_shadesBrush; +} + +void QAbstractAxis::setShadesColor(QColor color) +{ + QBrush b = d_ptr->m_shadesBrush; + if (b.color() != color) { + b.setColor(color); + setShadesBrush(b); + emit shadesColorChanged(color); + } +} + +QColor QAbstractAxis::shadesColor() const +{ + return shadesBrush().color(); +} + +void QAbstractAxis::setShadesBorderColor(QColor color) +{ + QPen p = d_ptr->m_shadesPen; + if (p.color() != color) { + p.setColor(color); + setShadesPen(p); + emit shadesColorChanged(color); + } +} + +QColor QAbstractAxis::shadesBorderColor() const +{ + return shadesPen().color(); +} + + +bool QAbstractAxis::isVisible() const +{ + return d_ptr->m_visible; +} + +/*! + Sets axis, shades, labels and grid lines to be visible. +*/ +void QAbstractAxis::setVisible(bool visible) +{ + if (d_ptr->m_visible != visible) { + d_ptr->m_visible = visible; + emit visibleChanged(visible); + } +} + + +/*! + Sets axis, shades, labels and grid lines to be visible. +*/ +void QAbstractAxis::show() +{ + setVisible(true); +} + +/*! + Sets axis, shades, labels and grid lines to not be visible. +*/ +void QAbstractAxis::hide() +{ + setVisible(false); +} + +/*! + Sets the minimum value shown on the axis. + Depending on the actual axis type the \a min parameter is converted to appropriate type. + If the conversion is impossible then the function call does nothing +*/ +void QAbstractAxis::setMin(const QVariant &min) +{ + d_ptr->setMin(min); +} + +/*! + Sets the maximum value shown on the axis. + Depending on the actual axis type the \a max parameter is converted to appropriate type. + If the conversion is impossible then the function call does nothing +*/ +void QAbstractAxis::setMax(const QVariant &max) +{ + d_ptr->setMax(max); +} + +/*! + Sets the range shown on the axis. + Depending on the actual axis type the \a min and \a max parameters are converted to appropriate types. + If the conversion is impossible then the function call does nothing. +*/ +void QAbstractAxis::setRange(const QVariant &min, const QVariant &max) +{ + d_ptr->setRange(min, max); +} + + +/*! + Returns the orientation in which the axis is being used (Vertical or Horizontal) +*/ +Qt::Orientation QAbstractAxis::orientation() +{ + return d_ptr->orientation(); +} + +Qt::Alignment QAbstractAxis::alignment() const +{ + return d_ptr->alignment(); +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +QAbstractAxisPrivate::QAbstractAxisPrivate(QAbstractAxis *q) + : q_ptr(q), + m_chart(0), + m_alignment(0), + m_orientation(Qt::Orientation(0)), + m_visible(true), + m_arrowVisible(true), + m_axisPen(QChartPrivate::defaultPen()), + m_axisBrush(QChartPrivate::defaultBrush()), + m_gridLineVisible(true), + m_gridLinePen(QChartPrivate::defaultPen()), + m_labelsVisible(true), + m_labelsPen(QChartPrivate::defaultPen()), + m_labelsBrush(QChartPrivate::defaultBrush()), + m_labelsFont(QChartPrivate::defaultFont()), + m_labelsAngle(0), + m_titleVisible(true), + m_titlePen(QChartPrivate::defaultPen()), + m_titleBrush(QChartPrivate::defaultBrush()), + m_titleFont(QChartPrivate::defaultFont()), + m_shadesVisible(false), + m_shadesPen(QChartPrivate::defaultPen()), + m_shadesBrush(QChartPrivate::defaultBrush()), + m_shadesOpacity(1.0), + m_dirty(false) +{ +} + +QAbstractAxisPrivate::~QAbstractAxisPrivate() +{ +} + +void QAbstractAxisPrivate::setAlignment( Qt::Alignment alignment) +{ + switch(alignment) { + case Qt::AlignTop: + case Qt::AlignBottom: + m_orientation = Qt::Horizontal; + break; + case Qt::AlignLeft: + case Qt::AlignRight: + m_orientation = Qt::Vertical; + break; + default: + qWarning()<<"No alignment specified !"; + break; + }; + m_alignment=alignment; +} + +void QAbstractAxisPrivate::initializeTheme(ChartTheme* theme, bool forced) +{ + if (forced || QChartPrivate::defaultPen() == m_axisPen) + q_ptr->setLinePen(theme->axisLinePen()); + + if (forced || QChartPrivate::defaultPen() == m_gridLinePen) + q_ptr->setGridLinePen(theme->girdLinePen()); + + if (forced || QChartPrivate::defaultBrush() == m_labelsBrush) + q_ptr->setLabelsBrush(theme->labelBrush()); + if (forced || QChartPrivate::defaultPen() == m_labelsPen) + q_ptr->setLabelsPen(Qt::NoPen); // NoPen for performance reasons + if (forced || QChartPrivate::defaultFont() == m_labelsFont) + q_ptr->setLabelsFont(theme->labelFont()); + + if (forced || QChartPrivate::defaultBrush() == m_titleBrush) + q_ptr->setTitleBrush(theme->labelBrush()); + if (forced || QChartPrivate::defaultPen() == m_titlePen) + q_ptr->setTitlePen(Qt::NoPen); // NoPen for performance reasons + if (forced || QChartPrivate::defaultFont() == m_titleFont) { + QFont font(m_labelsFont); + font.setBold(true); + q_ptr->setTitleFont(font); + } + + if (forced || QChartPrivate::defaultBrush() == m_shadesBrush) + q_ptr->setShadesBrush(theme->backgroundShadesBrush()); + if (forced || QChartPrivate::defaultPen() == m_shadesPen) + q_ptr->setShadesPen(theme->backgroundShadesPen()); + + bool axisX = m_orientation == Qt::Horizontal; + if (forced && (theme->backgroundShades() == ChartTheme::BackgroundShadesBoth + || (theme->backgroundShades() == ChartTheme::BackgroundShadesVertical && axisX) + || (theme->backgroundShades() == ChartTheme::BackgroundShadesHorizontal && !axisX))) { + q_ptr->setShadesVisible(true); + } else if (forced) { + q_ptr->setShadesVisible(false); + } +} + +void QAbstractAxisPrivate::handleRangeChanged(qreal min, qreal max) +{ + setRange(min,max); +} + +void QAbstractAxisPrivate::initializeGraphics(QGraphicsItem* parent) +{ + Q_UNUSED(parent); +} + +void QAbstractAxisPrivate::initializeAnimations(QChart::AnimationOptions options) +{ + ChartAxisElement *axis = m_item.data(); + Q_ASSERT(axis); + if (axis->animation()) + axis->animation()->stopAndDestroyLater(); + + if (options.testFlag(QChart::GridAxisAnimations)) + axis->setAnimation(new AxisAnimation(axis)); + else + axis->setAnimation(0); +} + + + +#include "moc_qabstractaxis.cpp" +#include "moc_qabstractaxis_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/qabstractaxis.h b/src/charts/axis/qabstractaxis.h new file mode 100644 index 00000000..cbad09e8 --- /dev/null +++ b/src/charts/axis/qabstractaxis.h @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTAXIS_H +#define QABSTRACTAXIS_H + +#include <QtCharts/qchartglobal.h> +#include <QPen> +#include <QFont> +#include <QVariant> + +QT_CHARTS_BEGIN_NAMESPACE + +class QAbstractAxisPrivate; + +class QT_CHARTS_EXPORT QAbstractAxis : public QObject +{ + Q_OBJECT + //visibility + Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged) + //arrow + Q_PROPERTY(bool lineVisible READ isLineVisible WRITE setLineVisible NOTIFY lineVisibleChanged) + Q_PROPERTY(QPen linePen READ linePen WRITE setLinePen NOTIFY linePenChanged) + Q_PROPERTY(QColor color READ linePenColor WRITE setLinePenColor NOTIFY colorChanged) + //labels + Q_PROPERTY(bool labelsVisible READ labelsVisible WRITE setLabelsVisible NOTIFY labelsVisibleChanged) + Q_PROPERTY(QPen labelsPen READ labelsPen WRITE setLabelsPen NOTIFY labelsPenChanged) + Q_PROPERTY(QBrush labelsBrush READ labelsBrush WRITE setLabelsBrush NOTIFY labelsBrushChanged) + Q_PROPERTY(int labelsAngle READ labelsAngle WRITE setLabelsAngle NOTIFY labelsAngleChanged) + Q_PROPERTY(QFont labelsFont READ labelsFont WRITE setLabelsFont NOTIFY labelsFontChanged) + Q_PROPERTY(QColor labelsColor READ labelsColor WRITE setLabelsColor NOTIFY labelsColorChanged) + //grid + Q_PROPERTY(bool gridVisible READ isGridLineVisible WRITE setGridLineVisible NOTIFY gridVisibleChanged) + Q_PROPERTY(QPen gridLinePen READ gridLinePen WRITE setGridLinePen NOTIFY gridLinePenChanged) + //shades + Q_PROPERTY(bool shadesVisible READ shadesVisible WRITE setShadesVisible NOTIFY shadesVisibleChanged) + Q_PROPERTY(QColor shadesColor READ shadesColor WRITE setShadesColor NOTIFY shadesColorChanged) + Q_PROPERTY(QColor shadesBorderColor READ shadesBorderColor WRITE setShadesBorderColor NOTIFY shadesBorderColorChanged) + Q_PROPERTY(QPen shadesPen READ shadesPen WRITE setShadesPen NOTIFY shadesPenChanged) + Q_PROPERTY(QBrush shadesBrush READ shadesBrush WRITE setShadesBrush NOTIFY shadesBrushChanged) + //title + Q_PROPERTY(QString titleText READ titleText WRITE setTitleText NOTIFY titleTextChanged) + Q_PROPERTY(QPen titlePen READ titlePen WRITE setTitlePen NOTIFY titlePenChanged) + Q_PROPERTY(QBrush titleBrush READ titleBrush WRITE setTitleBrush NOTIFY titleBrushChanged) + Q_PROPERTY(bool titleVisible READ isTitleVisible WRITE setTitleVisible NOTIFY titleVisibleChanged) + Q_PROPERTY(QFont titleFont READ titleFont WRITE setTitleFont NOTIFY titleFontChanged) + //orientation + Q_PROPERTY(Qt::Orientation orientation READ orientation) + //aligment + Q_PROPERTY(Qt::Alignment alignment READ alignment) + +public: + + enum AxisType { + AxisTypeNoAxis = 0x0, + AxisTypeValue = 0x1, + AxisTypeBarCategory = 0x2, + AxisTypeCategory = 0x3, + AxisTypeDateTime = 0x4, + AxisTypeLogValue = 0x5 + }; + + Q_DECLARE_FLAGS(AxisTypes, AxisType) + +protected: + explicit QAbstractAxis(QAbstractAxisPrivate &d, QObject *parent = 0); + +public: + ~QAbstractAxis(); + + virtual AxisType type() const = 0; + + //visibility handling + bool isVisible() const; + void setVisible(bool visible = true); + void show(); + void hide(); + + //arrow handling + bool isLineVisible() const; + void setLineVisible(bool visible = true); + void setLinePen(const QPen &pen); + QPen linePen() const; + void setLinePenColor(QColor color); + QColor linePenColor() const; + + //grid handling + bool isGridLineVisible() const; + void setGridLineVisible(bool visible = true); + void setGridLinePen(const QPen &pen); + QPen gridLinePen() const; + + //labels handling + bool labelsVisible() const; + void setLabelsVisible(bool visible = true); + void setLabelsPen(const QPen &pen); + QPen labelsPen() const; + void setLabelsBrush(const QBrush &brush); + QBrush labelsBrush() const; + void setLabelsFont(const QFont &font); + QFont labelsFont() const; + void setLabelsAngle(int angle); + int labelsAngle() const; + void setLabelsColor(QColor color); + QColor labelsColor() const; + + //title handling + bool isTitleVisible() const; + void setTitleVisible(bool visible = true); + void setTitlePen(const QPen &pen); + QPen titlePen() const; + void setTitleBrush(const QBrush &brush); + QBrush titleBrush() const; + void setTitleFont(const QFont &font); + QFont titleFont() const; + void setTitleText(const QString &title); + QString titleText() const; + + //shades handling + bool shadesVisible() const; + void setShadesVisible(bool visible = true); + void setShadesPen(const QPen &pen); + QPen shadesPen() const; + void setShadesBrush(const QBrush &brush); + QBrush shadesBrush() const; + void setShadesColor(QColor color); + QColor shadesColor() const; + void setShadesBorderColor(QColor color); + QColor shadesBorderColor() const; + + Qt::Orientation orientation(); + Qt::Alignment alignment() const; + + //range handling + void setMin(const QVariant &min); + void setMax(const QVariant &max); + void setRange(const QVariant &min, const QVariant &max); + +Q_SIGNALS: + void visibleChanged(bool visible); + void linePenChanged(const QPen &pen); + void lineVisibleChanged(bool visible); + void labelsVisibleChanged(bool visible); + void labelsPenChanged(const QPen &pen); + void labelsBrushChanged(const QBrush &brush); + void labelsFontChanged(const QFont &pen); + void labelsAngleChanged(int angle); + void gridLinePenChanged(const QPen &pen); + void gridVisibleChanged(bool visible); + void colorChanged(QColor color); + void labelsColorChanged(QColor color); + void titleTextChanged(const QString &title); + void titlePenChanged(const QPen &pen); + void titleBrushChanged(const QBrush &brush); + void titleVisibleChanged(bool visible); + void titleFontChanged(const QFont &font); + void shadesVisibleChanged(bool visible); + void shadesColorChanged(QColor color); + void shadesBorderColorChanged(QColor color); + void shadesPenChanged(const QPen &pen); + void shadesBrushChanged(const QBrush &brush); + +protected: + QScopedPointer<QAbstractAxisPrivate> d_ptr; + Q_DISABLE_COPY(QAbstractAxis) + friend class ChartDataSet; + friend class ChartPresenter; + friend class ChartThemeManager; + friend class AbstractDomain; + friend class ChartAxisElement; + friend class XYChart; +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QABSTRACTAXIS_H diff --git a/src/charts/axis/qabstractaxis_p.h b/src/charts/axis/qabstractaxis_p.h new file mode 100644 index 00000000..f2f60038 --- /dev/null +++ b/src/charts/axis/qabstractaxis_p.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QABSTRACTAXIS_P_H +#define QABSTRACTAXIS_P_H + +#include "qabstractaxis.h" +#include "chartaxiselement_p.h" +#include "qchart.h" +#include <QDebug> + +class QGraphicsItem; + +QT_CHARTS_BEGIN_NAMESPACE + +class ChartPresenter; +class AbstractDomain; +class QChart; +class QAbstractSeries; +class ChartTheme; +class ChartElement; + +class QT_CHARTS_AUTOTEST_EXPORT QAbstractAxisPrivate : public QObject +{ + Q_OBJECT +public: + QAbstractAxisPrivate(QAbstractAxis *q); + ~QAbstractAxisPrivate(); + +public: + Qt::Alignment alignment() const { return m_alignment; } + Qt::Orientation orientation() const { return m_orientation; } + void setAlignment( Qt::Alignment alignment); + + virtual void initializeDomain(AbstractDomain *domain) = 0; + virtual void initializeGraphics(QGraphicsItem *parent) = 0; + virtual void initializeTheme(ChartTheme* theme, bool forced = false); + virtual void initializeAnimations(QChart::AnimationOptions options); + + //interface for manipulating range form base class + virtual void setMin(const QVariant &min) = 0; + virtual void setMax(const QVariant &max) = 0; + virtual void setRange(const QVariant &min, const QVariant &max) = 0; + + //interface manipulating range form domain + virtual void setRange(qreal min, qreal max) = 0; + virtual qreal min() = 0; + virtual qreal max() = 0; + + ChartAxisElement *axisItem() { return m_item.data(); } + +public Q_SLOTS: + void handleRangeChanged(qreal min, qreal max); + +Q_SIGNALS: + void rangeChanged(qreal min, qreal max); + +protected: + QAbstractAxis *q_ptr; + QChart *m_chart; + QScopedPointer<ChartAxisElement> m_item; + +private: + QList<QAbstractSeries*> m_series; + + Qt::Alignment m_alignment; + Qt::Orientation m_orientation; + + bool m_visible; + + bool m_arrowVisible; + QPen m_axisPen; + QBrush m_axisBrush; + + bool m_gridLineVisible; + QPen m_gridLinePen; + + bool m_labelsVisible; + QPen m_labelsPen; + QBrush m_labelsBrush; + QFont m_labelsFont; + int m_labelsAngle; + + bool m_titleVisible; + QPen m_titlePen; + QBrush m_titleBrush; + QFont m_titleFont; + QString m_title; + + bool m_shadesVisible; + QPen m_shadesPen; + QBrush m_shadesBrush; + qreal m_shadesOpacity; + + bool m_dirty; + + friend class QAbstractAxis; + friend class ChartDataSet; + friend class ChartPresenter; +}; + +QT_CHARTS_END_NAMESPACE + +#endif diff --git a/src/charts/axis/valueaxis/chartvalueaxisx.cpp b/src/charts/axis/valueaxis/chartvalueaxisx.cpp new file mode 100644 index 00000000..abf9c434 --- /dev/null +++ b/src/charts/axis/valueaxis/chartvalueaxisx.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "chartvalueaxisx_p.h" +#include "qabstractaxis.h" +#include "chartpresenter_p.h" +#include "qvalueaxis.h" +#include "abstractchartlayout_p.h" +#include <QGraphicsLayout> +#include <qmath.h> +#include <QDebug> + + +QT_CHARTS_BEGIN_NAMESPACE + +ChartValueAxisX::ChartValueAxisX(QValueAxis *axis, QGraphicsItem *item ) + : HorizontalAxis(axis, item), + m_axis(axis) +{ + QObject::connect(m_axis, SIGNAL(tickCountChanged(int)), this, SLOT(handleTickCountChanged(int))); + QObject::connect(m_axis, SIGNAL(labelFormatChanged(QString)), this, SLOT(handleLabelFormatChanged(QString))); +} + +ChartValueAxisX::~ChartValueAxisX() +{ +} + +QVector<qreal> ChartValueAxisX::calculateLayout() const +{ + int tickCount = m_axis->tickCount(); + + Q_ASSERT(tickCount >= 2); + + QVector<qreal> points; + points.resize(tickCount); + + const QRectF &gridRect = gridGeometry(); + const qreal deltaX = gridRect.width() / (qreal(tickCount) - 1.0); + for (int i = 0; i < tickCount; ++i) + points[i] = qreal(i) * deltaX + gridRect.left(); + return points; +} + +void ChartValueAxisX::updateGeometry() +{ + const QVector<qreal>& layout = ChartAxisElement::layout(); + if (layout.isEmpty()) + return; + setLabels(createValueLabels(min(), max(), layout.size(), m_axis->labelFormat())); + HorizontalAxis::updateGeometry(); +} + +void ChartValueAxisX::handleTickCountChanged(int tick) +{ + Q_UNUSED(tick); + QGraphicsLayoutItem::updateGeometry(); + if(presenter()) presenter()->layout()->invalidate(); +} + +void ChartValueAxisX::handleLabelFormatChanged(const QString &format) +{ + Q_UNUSED(format); + QGraphicsLayoutItem::updateGeometry(); + if(presenter()) presenter()->layout()->invalidate(); +} + +QSizeF ChartValueAxisX::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const +{ + Q_UNUSED(constraint) + + QSizeF sh; + + QSizeF base = HorizontalAxis::sizeHint(which, constraint); + QStringList ticksList = createValueLabels(min(),max(),m_axis->tickCount(),m_axis->labelFormat()); + // Width of horizontal axis sizeHint indicates the maximum distance labels can extend past + // first and last ticks. Base width is irrelevant. + qreal width = 0; + qreal height = 0; + + switch (which) { + case Qt::MinimumSize: { + QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), + QStringLiteral("..."), + axis()->labelsAngle()); + width = boundingRect.width() / 2.0; + height = boundingRect.height() + labelPadding() + base.height() + 1.0; + sh = QSizeF(width, height); + break; + } + case Qt::PreferredSize: { + qreal labelHeight = 0.0; + qreal firstWidth = -1.0; + foreach (const QString& s, ticksList) { + QRectF rect = ChartPresenter::textBoundingRect(axis()->labelsFont(), s, axis()->labelsAngle()); + labelHeight = qMax(rect.height(), labelHeight); + width = rect.width(); + if (firstWidth < 0.0) + firstWidth = width; + } + height = labelHeight + labelPadding() + base.height() + 1.0; + width = qMax(width, firstWidth) / 2.0; + sh = QSizeF(width, height); + break; + } + default: + break; + } + return sh; +} + +#include "moc_chartvalueaxisx_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/valueaxis/chartvalueaxisx_p.h b/src/charts/axis/valueaxis/chartvalueaxisx_p.h new file mode 100644 index 00000000..7f83e5a3 --- /dev/null +++ b/src/charts/axis/valueaxis/chartvalueaxisx_p.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef CHARTVALUEAXISX_H +#define CHARTVALUEAXISX_H + +#include "horizontalaxis_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QValueAxis; + +class ChartValueAxisX : public HorizontalAxis +{ + Q_OBJECT +public: + ChartValueAxisX(QValueAxis *axis, QGraphicsItem *item = 0); + ~ChartValueAxisX(); + + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const; +protected: + QVector<qreal> calculateLayout() const; + void updateGeometry(); +private Q_SLOTS: + void handleTickCountChanged(int tick); + void handleLabelFormatChanged(const QString &format); + +private: + QValueAxis *m_axis; +}; + +QT_CHARTS_END_NAMESPACE + +#endif /* CHARTVALUEAXISX_H */ diff --git a/src/charts/axis/valueaxis/chartvalueaxisy.cpp b/src/charts/axis/valueaxis/chartvalueaxisy.cpp new file mode 100644 index 00000000..d6b7c651 --- /dev/null +++ b/src/charts/axis/valueaxis/chartvalueaxisy.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "chartvalueaxisy_p.h" +#include "qabstractaxis.h" +#include "chartpresenter_p.h" +#include "qvalueaxis.h" +#include "abstractchartlayout_p.h" +#include <QGraphicsLayout> +#include <qmath.h> +#include <QDebug> + +QT_CHARTS_BEGIN_NAMESPACE + +ChartValueAxisY::ChartValueAxisY(QValueAxis *axis, QGraphicsItem *item) + : VerticalAxis(axis, item), + m_axis(axis) +{ + QObject::connect(m_axis, SIGNAL(tickCountChanged(int)), this, SLOT(handleTickCountChanged(int))); + QObject::connect(m_axis, SIGNAL(labelFormatChanged(QString)), this, SLOT(handleLabelFormatChanged(QString))); +} + +ChartValueAxisY::~ChartValueAxisY() +{ +} + +QVector<qreal> ChartValueAxisY::calculateLayout() const +{ + int tickCount = m_axis->tickCount(); + + Q_ASSERT(tickCount >= 2); + + QVector<qreal> points; + points.resize(tickCount); + + const QRectF &gridRect = gridGeometry(); + + const qreal deltaY = gridRect.height() / (qreal(tickCount) - 1.0); + for (int i = 0; i < tickCount; ++i) + points[i] = qreal(i) * -deltaY + gridRect.bottom(); + + return points; +} + +void ChartValueAxisY::updateGeometry() +{ + const QVector<qreal> &layout = ChartAxisElement::layout(); + if (layout.isEmpty()) + return; + setLabels(createValueLabels(min(),max(),layout.size(),m_axis->labelFormat())); + VerticalAxis::updateGeometry(); +} + +void ChartValueAxisY::handleTickCountChanged(int tick) +{ + Q_UNUSED(tick); + QGraphicsLayoutItem::updateGeometry(); + if (presenter()) presenter()->layout()->invalidate(); +} + +void ChartValueAxisY::handleLabelFormatChanged(const QString &format) +{ + Q_UNUSED(format); + QGraphicsLayoutItem::updateGeometry(); + if(presenter()) presenter()->layout()->invalidate(); +} + +QSizeF ChartValueAxisY::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const +{ + Q_UNUSED(constraint) + + QSizeF sh; + QSizeF base = VerticalAxis::sizeHint(which, constraint); + QStringList ticksList = createValueLabels(min(),max(),m_axis->tickCount(),m_axis->labelFormat()); + qreal width = 0; + // Height of vertical axis sizeHint indicates the maximum distance labels can extend past + // first and last ticks. Base height is irrelevant. + qreal height = 0; + + switch (which) { + case Qt::MinimumSize: { + QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), + QStringLiteral("..."), + axis()->labelsAngle()); + width = boundingRect.width() + labelPadding() + base.width() + 1.0; + height = boundingRect.height() / 2.0; + sh = QSizeF(width, height); + break; + } + case Qt::PreferredSize: { + qreal labelWidth = 0.0; + qreal firstHeight = -1.0; + foreach (const QString& s, ticksList) { + QRectF rect = ChartPresenter::textBoundingRect(axis()->labelsFont(), s, axis()->labelsAngle()); + labelWidth = qMax(rect.width(), labelWidth); + height = rect.height(); + if (firstHeight < 0.0) + firstHeight = height; + } + width = labelWidth + labelPadding() + base.width() + 2.0; //two pixels of tolerance + height = qMax(height, firstHeight) / 2.0; + sh = QSizeF(width, height); + break; + } + default: + break; + } + return sh; +} + +#include "moc_chartvalueaxisy_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/valueaxis/chartvalueaxisy_p.h b/src/charts/axis/valueaxis/chartvalueaxisy_p.h new file mode 100644 index 00000000..3ec30faa --- /dev/null +++ b/src/charts/axis/valueaxis/chartvalueaxisy_p.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef CHARTVALUEAXISY_H +#define CHARTVALUEAXISY_H + +#include "verticalaxis_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QValueAxis; + +class ChartValueAxisY : public VerticalAxis +{ + Q_OBJECT +public: + ChartValueAxisY(QValueAxis *axis, QGraphicsItem *item = 0); + ~ChartValueAxisY(); + + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const; +protected: + QVector<qreal> calculateLayout() const; + void updateGeometry(); +private Q_SLOTS: + void handleTickCountChanged(int tick); + void handleLabelFormatChanged(const QString &format); + +private: + QValueAxis *m_axis; +}; + +QT_CHARTS_END_NAMESPACE + +#endif /* CHARTVALUEAXISY_H */ diff --git a/src/charts/axis/valueaxis/polarchartvalueaxisangular.cpp b/src/charts/axis/valueaxis/polarchartvalueaxisangular.cpp new file mode 100644 index 00000000..945449a8 --- /dev/null +++ b/src/charts/axis/valueaxis/polarchartvalueaxisangular.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "polarchartvalueaxisangular_p.h" +#include "chartpresenter_p.h" +#include "abstractchartlayout_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +PolarChartValueAxisAngular::PolarChartValueAxisAngular(QValueAxis *axis, QGraphicsItem *item) + : PolarChartAxisAngular(axis, item) +{ + QObject::connect(axis, SIGNAL(tickCountChanged(int)), this, SLOT(handleTickCountChanged(int))); + QObject::connect(axis, SIGNAL(labelFormatChanged(QString)), this, SLOT(handleLabelFormatChanged(QString))); +} + +PolarChartValueAxisAngular::~PolarChartValueAxisAngular() +{ +} + +QVector<qreal> PolarChartValueAxisAngular::calculateLayout() const +{ + int tickCount = static_cast<QValueAxis *>(axis())->tickCount(); + Q_ASSERT(tickCount >= 2); + + QVector<qreal> points; + points.resize(tickCount); + + const qreal d = 360.0 / qreal(tickCount - 1); + + for (int i = 0; i < tickCount; ++i) { + qreal angularCoordinate = qreal(i) * d; + points[i] = angularCoordinate; + } + + return points; +} + +void PolarChartValueAxisAngular::createAxisLabels(const QVector<qreal> &layout) +{ + QStringList labelList = createValueLabels(min(), max(), layout.size(), static_cast<QValueAxis *>(axis())->labelFormat()); + setLabels(labelList); +} + +void PolarChartValueAxisAngular::handleTickCountChanged(int tick) +{ + Q_UNUSED(tick); + QGraphicsLayoutItem::updateGeometry(); + if (presenter()) + presenter()->layout()->invalidate(); +} + +void PolarChartValueAxisAngular::handleLabelFormatChanged(const QString &format) +{ + Q_UNUSED(format); + QGraphicsLayoutItem::updateGeometry(); + if (presenter()) + presenter()->layout()->invalidate(); +} + +#include "moc_polarchartvalueaxisangular_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/valueaxis/polarchartvalueaxisangular_p.h b/src/charts/axis/valueaxis/polarchartvalueaxisangular_p.h new file mode 100644 index 00000000..d4a2f653 --- /dev/null +++ b/src/charts/axis/valueaxis/polarchartvalueaxisangular_p.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef POLARCHARTVALUEAXISANGULAR_P_H +#define POLARCHARTVALUEAXISANGULAR_P_H + +#include "polarchartaxisangular_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QValueAxis; + +class PolarChartValueAxisAngular : public PolarChartAxisAngular +{ + Q_OBJECT +public: + PolarChartValueAxisAngular(QValueAxis *axis, QGraphicsItem *item); + ~PolarChartValueAxisAngular(); + + virtual QVector<qreal> calculateLayout() const; + virtual void createAxisLabels(const QVector<qreal> &layout); + +private Q_SLOTS: + void handleTickCountChanged(int tick); + void handleLabelFormatChanged(const QString &format); +}; + +QT_CHARTS_END_NAMESPACE + +#endif // POLARCHARTVALUEAXISANGULAR_P_H diff --git a/src/charts/axis/valueaxis/polarchartvalueaxisradial.cpp b/src/charts/axis/valueaxis/polarchartvalueaxisradial.cpp new file mode 100644 index 00000000..006477e8 --- /dev/null +++ b/src/charts/axis/valueaxis/polarchartvalueaxisradial.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "polarchartvalueaxisradial_p.h" +#include "chartpresenter_p.h" +#include "abstractchartlayout_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +PolarChartValueAxisRadial::PolarChartValueAxisRadial(QValueAxis *axis, QGraphicsItem *item) + : PolarChartAxisRadial(axis, item) +{ + QObject::connect(axis, SIGNAL(tickCountChanged(int)), this, SLOT(handleTickCountChanged(int))); + QObject::connect(axis, SIGNAL(labelFormatChanged(QString)), this, SLOT(handleLabelFormatChanged(QString))); +} + +PolarChartValueAxisRadial::~PolarChartValueAxisRadial() +{ +} + +QVector<qreal> PolarChartValueAxisRadial::calculateLayout() const +{ + int tickCount = static_cast<QValueAxis *>(axis())->tickCount(); + Q_ASSERT(tickCount >= 2); + + QVector<qreal> points; + points.resize(tickCount); + + const qreal d = (axisGeometry().width() / 2) / qreal(tickCount - 1); + + for (int i = 0; i < tickCount; ++i) { + qreal radialCoordinate = qreal(i) * d; + points[i] = radialCoordinate; + } + + return points; +} + +void PolarChartValueAxisRadial::createAxisLabels(const QVector<qreal> &layout) +{ + setLabels(createValueLabels(min(), max(), layout.size(), static_cast<QValueAxis *>(axis())->labelFormat())); +} + +void PolarChartValueAxisRadial::handleTickCountChanged(int tick) +{ + Q_UNUSED(tick); + QGraphicsLayoutItem::updateGeometry(); + if (presenter()) + presenter()->layout()->invalidate(); +} + +void PolarChartValueAxisRadial::handleLabelFormatChanged(const QString &format) +{ + Q_UNUSED(format); + QGraphicsLayoutItem::updateGeometry(); + if (presenter()) + presenter()->layout()->invalidate(); +} + +#include "moc_polarchartvalueaxisradial_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/valueaxis/polarchartvalueaxisradial_p.h b/src/charts/axis/valueaxis/polarchartvalueaxisradial_p.h new file mode 100644 index 00000000..4e13b57a --- /dev/null +++ b/src/charts/axis/valueaxis/polarchartvalueaxisradial_p.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef POLARCHARTVALUEAXISRADIAL_P_H +#define POLARCHARTVALUEAXISRADIAL_P_H + +#include "polarchartaxisradial_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QValueAxis; + +class PolarChartValueAxisRadial : public PolarChartAxisRadial +{ + Q_OBJECT +public: + PolarChartValueAxisRadial(QValueAxis *axis, QGraphicsItem *item); + ~PolarChartValueAxisRadial(); + + virtual QVector<qreal> calculateLayout() const; + virtual void createAxisLabels(const QVector<qreal> &layout); + +private Q_SLOTS: + void handleTickCountChanged(int tick); + void handleLabelFormatChanged(const QString &format); +}; + +QT_CHARTS_END_NAMESPACE + +#endif // POLARCHARTVALUEAXISRADIAL_P_H diff --git a/src/charts/axis/valueaxis/qvalueaxis.cpp b/src/charts/axis/valueaxis/qvalueaxis.cpp new file mode 100644 index 00000000..a055dc22 --- /dev/null +++ b/src/charts/axis/valueaxis/qvalueaxis.cpp @@ -0,0 +1,459 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvalueaxis.h" +#include "qvalueaxis_p.h" +#include "chartvalueaxisx_p.h" +#include "chartvalueaxisy_p.h" +#include "abstractdomain_p.h" +#include "polarchartvalueaxisangular_p.h" +#include "polarchartvalueaxisradial_p.h" +#include "chartdataset_p.h" +#include "chartpresenter_p.h" +#include "charttheme_p.h" + + +QT_CHARTS_BEGIN_NAMESPACE +/*! + \class QValueAxis + \inmodule Qt Charts + \brief The QValueAxis class is used for manipulating chart's axis. + \mainclass + + ValueAxis can be setup to show axis line with tick marks, grid lines and shades. + Values of axis are drawn to position of ticks. + + Example code on how to use QValueAxis. + \code + QChartView *chartView = new QChartView; + QLineSeries *series = new QLineSeries; + // ... + chartView->chart()->addSeries(series); + + QValueAxis *axisX = new QValueAxis; + axisX->setRange(10, 20.5); + axisX->setTickCount(10); + axisX->setLabelFormat("%.2f"); + chartView->chart()->setAxisX(axisX, series); + \endcode +*/ +/*! + \qmltype ValueAxis + \instantiates QValueAxis + \inqmlmodule QtCharts + + \inherits AbstractAxis + \brief The ValueAxis element is used for manipulating chart's axes + + ValueAxis can be setup to show axis line with tick marks, grid lines and shades. + Values of axis are drawn to position of ticks + + Example about using ValueAxis: + \code + ChartView { + ValueAxis { + id: xAxis + min: 0 + max: 10 + } + // Add a few series... + } + \endcode +*/ + +/*! + \property QValueAxis::min + Defines the minimum value on the axis. + When setting this property the max is adjusted if necessary, to ensure that the range remains valid. +*/ +/*! + \qmlproperty real ValueAxis::min + Defines the minimum value on the axis. + When setting this property the max is adjusted if necessary, to ensure that the range remains valid. +*/ + +/*! + \property QValueAxis::max + Defines the maximum value on the axis. + When setting this property the min is adjusted if necessary, to ensure that the range remains valid. +*/ +/*! + \qmlproperty real ValueAxis::max + Defines the maximum value on the axis. + When setting this property the min is adjusted if necessary, to ensure that the range remains valid. +*/ + +/*! + \property QValueAxis::tickCount + Defines the number of ticks on the axis. This indicates how many grid lines are draw on the chart. + The default value is 5, and it can not be below 2. +*/ +/*! + \qmlproperty real ValueAxis::tickCount + Defines the number of ticks on the axis. This indicates how many grid lines are draw on the chart. + The default value is 5, and it can not be below 2. +*/ + +/*! + \property QValueAxis::labelFormat + Defines the label format of the axis. + Supported specifiers are: d, i, o, x, X, f, F, e, E, g, G, and c. + See QString::sprintf() for additional details. + + If the QChart::localizeNumbers is \c{true}, 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. +*/ +/*! + \qmlproperty real ValueAxis::labelFormat + Defines the label format of the axis. + Supported specifiers are: d, i, o, x, X, f, F, e, E, g, G, and c. + See QString::sprintf() for additional details. + + If the ChartView::localizeNumbers is \c{true}, 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. +*/ + +/*! + \fn void QValueAxis::minChanged(qreal min) + Axis emits signal when \a min of axis has changed. +*/ +/*! + \qmlsignal ValueAxis::onMinChanged(real min) + Axis emits signal when \a min of axis has changed. +*/ + +/*! + \fn void QValueAxis::maxChanged(qreal max) + Axis emits signal when \a max of axis has changed. +*/ +/*! + \qmlsignal ValueAxis::onMaxChanged(real max) + Axis emits signal when \a max of axis has changed. +*/ + +/*! + \fn void QValueAxis::tickCountChanged(int tickCount) + Axis emits signal when \a tickCount of axis has changed. +*/ +/*! + \qmlsignal ValueAxis::tickCountChanged(int tickCount) + Axis emits signal when \a tickCount of axis has changed. +*/ + +/*! + \fn void QValueAxis::rangeChanged(qreal min, qreal max) + Axis emits signal when \a min or \a max of axis has changed. +*/ + +/*! + \fn void QValueAxis::labelFormatChanged(const QString &format) + Axis emits signal when \a format of axis labels has changed. +*/ +/*! + \qmlsignal ValueAxis::labelFormatChanged(const QString &format) + Axis emits signal when \a format of axis labels has changed. +*/ + +/*! + \property QValueAxis::niceNumbersEnabled + \obsolete + Using this function can lead to unexpected behavior. Use applyNiceNumbers() instead. +*/ + +/*! + \qmlproperty bool ValueAxis::niceNumbersEnabled + Deprecated; Using this function can lead to unexpected behavior. Use applyNiceNumbers() instead. +*/ + +/*! + Constructs an axis object which is a child of \a parent. +*/ +QValueAxis::QValueAxis(QObject *parent) : + QAbstractAxis(*new QValueAxisPrivate(this), parent) +{ + +} + +/*! + \internal +*/ +QValueAxis::QValueAxis(QValueAxisPrivate &d, QObject *parent) + : QAbstractAxis(d, parent) +{ + +} + +/*! + Destroys the object +*/ +QValueAxis::~QValueAxis() +{ + Q_D(QValueAxis); + if (d->m_chart) + d->m_chart->removeAxis(this); +} + +void QValueAxis::setMin(qreal min) +{ + Q_D(QValueAxis); + setRange(min, qMax(d->m_max, min)); +} + +qreal QValueAxis::min() const +{ + Q_D(const QValueAxis); + return d->m_min; +} + +void QValueAxis::setMax(qreal max) +{ + Q_D(QValueAxis); + setRange(qMin(d->m_min, max), max); +} + +qreal QValueAxis::max() const +{ + Q_D(const QValueAxis); + return d->m_max; +} + +/*! + Sets range from \a min to \a max on the axis. + If min is greater than max then this function returns without making any changes. +*/ +void QValueAxis::setRange(qreal min, qreal max) +{ + Q_D(QValueAxis); + d->setRange(min,max); +} + +void QValueAxis::setTickCount(int count) +{ + Q_D(QValueAxis); + if (d->m_tickCount != count && count >= 2) { + d->m_tickCount = count; + emit tickCountChanged(count); + } +} + +int QValueAxis::tickCount() const +{ + Q_D(const QValueAxis); + return d->m_tickCount; +} + +void QValueAxis::setNiceNumbersEnabled(bool enable) +{ + Q_D(QValueAxis); + qWarning() << "Deprecated; Using this function can lead to unexpected behavior. " \ + "Use applyNiceNumbers() instead."; + if(enable) { + QObject::connect(this,SIGNAL(rangeChanged(qreal,qreal)),this,SLOT(applyNiceNumbers())); + QObject::connect(this,SIGNAL(tickCountChanged(int)),this,SLOT(applyNiceNumbers())); + applyNiceNumbers(); + } + else { + QObject::disconnect(this,SIGNAL(rangeChanged(qreal,qreal)),this,SLOT(applyNiceNumbers())); + QObject::disconnect(this,SIGNAL(tickCountChanged(int)),this,SLOT(applyNiceNumbers())); + } + d->m_niceNumbersEnabled=enable; +} + +bool QValueAxis::niceNumbersEnabled() const +{ + Q_D(const QValueAxis); + qWarning() << "Deprecated; Using this function can lead to unexpected behavior. " \ + "Use applyNiceNumbers() instead."; + return d->m_niceNumbersEnabled; +} + +void QValueAxis::setLabelFormat(const QString &format) +{ + Q_D(QValueAxis); + d->m_format = format; + emit labelFormatChanged(format); +} + +QString QValueAxis::labelFormat() const +{ + Q_D(const QValueAxis); + return d->m_format; +} + +/*! + Returns the type of the axis +*/ +QAbstractAxis::AxisType QValueAxis::type() const +{ + return AxisTypeValue; +} + +/*! + This method modifies range and number of ticks on the axis to look "nice". Algorithm considers numbers that + can be expressed as form of 1*10^n, 2* 10^n or 5*10^n as a nice numbers. These numbers are used for spacing the ticks. + This method will modify the current range and number of ticks. + \sa setRange(), setTickCount() +*/ +void QValueAxis::applyNiceNumbers() +{ + Q_D(QValueAxis); + if(d->m_applying) return; + qreal min = d->m_min; + qreal max = d->m_max; + int ticks = d->m_tickCount; + AbstractDomain::looseNiceNumbers(min,max,ticks); + d->m_applying=true; + d->setRange(min,max); + setTickCount(ticks); + d->m_applying=false; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +QValueAxisPrivate::QValueAxisPrivate(QValueAxis *q) + : QAbstractAxisPrivate(q), + m_min(0), + m_max(0), + m_tickCount(5), + m_format(QString::null), + m_applying(false), + m_niceNumbersEnabled(false) +{ + +} + +QValueAxisPrivate::~QValueAxisPrivate() +{ + +} + +void QValueAxisPrivate::setMin(const QVariant &min) +{ + Q_Q(QValueAxis); + bool ok; + qreal value = min.toReal(&ok); + if (ok) + q->setMin(value); +} + +void QValueAxisPrivate::setMax(const QVariant &max) +{ + Q_Q(QValueAxis); + bool ok; + qreal value = max.toReal(&ok); + if (ok) + q->setMax(value); +} + +void QValueAxisPrivate::setRange(const QVariant &min, const QVariant &max) +{ + Q_Q(QValueAxis); + bool ok1; + bool ok2; + qreal value1 = min.toReal(&ok1); + qreal value2 = max.toReal(&ok2); + if (ok1 && ok2) + q->setRange(value1, value2); +} + +void QValueAxisPrivate::setRange(qreal min, qreal max) +{ + Q_Q(QValueAxis); + bool changed = false; + + if (min > max) + return; + + bool changeMin = false; + if (m_min == 0 || min == 0) + changeMin = !qFuzzyCompare(1 + m_min, 1 + min); + else + changeMin = !qFuzzyCompare(m_min, min); + + bool changeMax = false; + if (m_max == 0 || max == 0) + changeMax = !qFuzzyCompare(1 + m_max, 1 + max); + else + changeMax = !qFuzzyCompare(m_max, max); + + if (changeMin) { + m_min = min; + changed = true; + emit q->minChanged(min); + } + + if (changeMax) { + m_max = max; + changed = true; + emit q->maxChanged(max); + } + + if (changed) { + emit rangeChanged(min,max); + emit q->rangeChanged(min, max); + } +} + +void QValueAxisPrivate::initializeGraphics(QGraphicsItem *parent) +{ + Q_Q(QValueAxis); + ChartAxisElement *axis(0); + + if (m_chart->chartType() == QChart::ChartTypeCartesian) { + if (orientation() == Qt::Vertical) + axis = new ChartValueAxisY(q,parent); + if (orientation() == Qt::Horizontal) + axis = new ChartValueAxisX(q,parent); + } + + if (m_chart->chartType() == QChart::ChartTypePolar) { + if (orientation() == Qt::Vertical) + axis = new PolarChartValueAxisRadial(q, parent); + if (orientation() == Qt::Horizontal) + axis = new PolarChartValueAxisAngular(q, parent); + } + + m_item.reset(axis); + QAbstractAxisPrivate::initializeGraphics(parent); +} + + +void QValueAxisPrivate::initializeDomain(AbstractDomain *domain) +{ + if (orientation() == Qt::Vertical) { + if (!qFuzzyIsNull(m_max - m_min)) + domain->setRangeY(m_min, m_max); + else + setRange(domain->minY(), domain->maxY()); + } + if (orientation() == Qt::Horizontal) { + if (!qFuzzyIsNull(m_max - m_min)) + domain->setRangeX(m_min, m_max); + else + setRange(domain->minX(), domain->maxX()); + } +} + +#include "moc_qvalueaxis.cpp" +#include "moc_qvalueaxis_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/valueaxis/qvalueaxis.h b/src/charts/axis/valueaxis/qvalueaxis.h new file mode 100644 index 00000000..a51203a4 --- /dev/null +++ b/src/charts/axis/valueaxis/qvalueaxis.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVALUEAXIS_H +#define QVALUEAXIS_H + +#include <QtCharts/qabstractaxis.h> + +QT_CHARTS_BEGIN_NAMESPACE + +class QValueAxisPrivate; + +class QT_CHARTS_EXPORT QValueAxis : public QAbstractAxis +{ + Q_OBJECT + Q_PROPERTY(int tickCount READ tickCount WRITE setTickCount NOTIFY tickCountChanged) + Q_PROPERTY(bool niceNumbersEnabled READ niceNumbersEnabled WRITE setNiceNumbersEnabled) + Q_PROPERTY(qreal min READ min WRITE setMin NOTIFY minChanged) + Q_PROPERTY(qreal max READ max WRITE setMax NOTIFY maxChanged) + Q_PROPERTY(QString labelFormat READ labelFormat WRITE setLabelFormat NOTIFY labelFormatChanged) + +public: + explicit QValueAxis(QObject *parent = 0); + ~QValueAxis(); + +protected: + QValueAxis(QValueAxisPrivate &d, QObject *parent = 0); + +public: + AxisType type() const; + + //range handling + void setMin(qreal min); + qreal min() const; + void setMax(qreal max); + qreal max() const; + void setRange(qreal min, qreal max); + + //ticks handling + void setTickCount(int count); + int tickCount() const; + + void setLabelFormat(const QString &format); + QString labelFormat() const; + + void setNiceNumbersEnabled(bool enable = true); + bool niceNumbersEnabled() const; + +public Q_SLOTS: + void applyNiceNumbers(); + +Q_SIGNALS: + void minChanged(qreal min); + void maxChanged(qreal max); + void rangeChanged(qreal min, qreal max); + void tickCountChanged(int tickCount); + void labelFormatChanged(const QString &format); + +private: + Q_DECLARE_PRIVATE(QValueAxis) + Q_DISABLE_COPY(QValueAxis) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QVALUEAXIS_H diff --git a/src/charts/axis/valueaxis/qvalueaxis_p.h b/src/charts/axis/valueaxis/qvalueaxis_p.h new file mode 100644 index 00000000..a1d9de5b --- /dev/null +++ b/src/charts/axis/valueaxis/qvalueaxis_p.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QVALUEAXIS_P_H +#define QVALUEAXIS_P_H + +#include <qvalueaxis.h> +#include "qabstractaxis_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QValueAxisPrivate : public QAbstractAxisPrivate +{ + Q_OBJECT +public: + QValueAxisPrivate(QValueAxis *q); + ~QValueAxisPrivate(); + +public: + void initializeGraphics(QGraphicsItem* parent); + void initializeDomain(AbstractDomain *domain); + + qreal min() { return m_min; }; + qreal max() { return m_max; }; + void setRange(qreal min,qreal max); + +protected: + void setMin(const QVariant &min); + void setMax(const QVariant &max); + void setRange(const QVariant &min, const QVariant &max); + +private: + qreal m_min; + qreal m_max; + int m_tickCount; + QString m_format; + bool m_applying; + bool m_niceNumbersEnabled; + Q_DECLARE_PUBLIC(QValueAxis) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QVALUEAXIS_P_H diff --git a/src/charts/axis/verticalaxis.cpp b/src/charts/axis/verticalaxis.cpp new file mode 100644 index 00000000..64c940f1 --- /dev/null +++ b/src/charts/axis/verticalaxis.cpp @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "verticalaxis_p.h" +#include "qabstractaxis.h" +#include "chartpresenter_p.h" +#include <QDebug> + +QT_CHARTS_BEGIN_NAMESPACE + +VerticalAxis::VerticalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis) + : CartesianChartAxis(axis, item, intervalAxis) +{ +} + +VerticalAxis::~VerticalAxis() +{ +} + +void VerticalAxis::updateGeometry() +{ + const QVector<qreal> &layout = ChartAxisElement::layout(); + + if (layout.isEmpty()) + return; + + QStringList labelList = labels(); + + QList<QGraphicsItem *> lines = gridItems(); + QList<QGraphicsItem *> labels = labelItems(); + QList<QGraphicsItem *> shades = shadeItems(); + QList<QGraphicsItem *> arrow = arrowItems(); + QGraphicsTextItem *title = titleItem(); + + Q_ASSERT(labels.size() == labelList.size()); + Q_ASSERT(layout.size() == labelList.size()); + + const QRectF &axisRect = axisGeometry(); + const QRectF &gridRect = gridGeometry(); + + qreal height = axisRect.bottom(); + + + //arrow + QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem*>(arrow.at(0)); + + //arrow position + if (axis()->alignment() == Qt::AlignLeft) + arrowItem->setLine(axisRect.right(), gridRect.top(), axisRect.right(), gridRect.bottom()); + else if (axis()->alignment() == Qt::AlignRight) + arrowItem->setLine(axisRect.left(), gridRect.top(), axisRect.left(), gridRect.bottom()); + + //title + QRectF titleBoundingRect; + QString titleText = axis()->titleText(); + qreal availableSpace = axisRect.width() - labelPadding(); + if (!titleText.isEmpty() && titleItem()->isVisible()) { + availableSpace -= titlePadding() * 2.0; + qreal minimumLabelWidth = ChartPresenter::textBoundingRect(axis()->labelsFont(), + QStringLiteral("...")).width(); + qreal titleSpace = availableSpace - minimumLabelWidth; + title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(90.0), + titleSpace, gridRect.height(), + titleBoundingRect)); + title->setTextWidth(titleBoundingRect.height()); + + titleBoundingRect = title->boundingRect(); + + QPointF center = gridRect.center() - titleBoundingRect.center(); + if (axis()->alignment() == Qt::AlignLeft) + title->setPos(axisRect.left() - titleBoundingRect.width() / 2.0 + titleBoundingRect.height() / 2.0 + titlePadding(), center.y()); + else if (axis()->alignment() == Qt::AlignRight) + title->setPos(axisRect.right() - titleBoundingRect.width() / 2.0 - titleBoundingRect.height() / 2.0 - titlePadding(), center.y()); + + title->setTransformOriginPoint(titleBoundingRect.center()); + title->setRotation(270); + + availableSpace -= titleBoundingRect.height(); + } + + for (int i = 0; i < layout.size(); ++i) { + //items + QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem *>(lines.at(i)); + QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrow.at(i + 1)); + QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i)); + + //grid line + gridItem->setLine(gridRect.left(), layout[i], gridRect.right(), layout[i]); + + //label text wrapping + QString text = labelList.at(i); + QRectF boundingRect; + // don't truncate empty labels + if (text.isEmpty()) { + labelItem->setHtml(text); + } else { + qreal labelHeight = (axisRect.height() / layout.count()) - (2 * labelPadding()); + QString truncatedText = ChartPresenter::truncatedText(axis()->labelsFont(), text, + axis()->labelsAngle(), + availableSpace, + labelHeight, boundingRect); + labelItem->setTextWidth(ChartPresenter::textBoundingRect(axis()->labelsFont(), + truncatedText).width()); + labelItem->setHtml(truncatedText); + } + + //label transformation origin point + const QRectF &rect = labelItem->boundingRect(); + QPointF center = rect.center(); + labelItem->setTransformOriginPoint(center.x(), center.y()); + qreal widthDiff = rect.width() - boundingRect.width(); + qreal heightDiff = rect.height() - boundingRect.height(); + + //ticks and label position + if (axis()->alignment() == Qt::AlignLeft) { + labelItem->setPos(axisRect.right() - rect.width() + (widthDiff / 2.0) - labelPadding(), layout[i] - center.y()); + tickItem->setLine(axisRect.right() - labelPadding(), layout[i], axisRect.right(), layout[i]); + } else if (axis()->alignment() == Qt::AlignRight) { + labelItem->setPos(axisRect.left() + labelPadding() - (widthDiff / 2.0), layout[i] - center.y()); + tickItem->setLine(axisRect.left(), layout[i], axisRect.left() + labelPadding(), layout[i]); + } + + //label in between + bool forceHide = false; + if (intervalAxis() && (i + 1) != layout.size()) { + qreal lowerBound = qMin(layout[i], gridRect.bottom()); + qreal upperBound = qMax(layout[i + 1], gridRect.top()); + const qreal delta = lowerBound - upperBound; + // Hide label in case visible part of the category at the grid edge is too narrow + if (delta < boundingRect.height() + && (lowerBound == gridRect.bottom() || upperBound == gridRect.top()) + && !intervalAxis()) { + forceHide = true; + } else { + labelItem->setPos(labelItem->pos().x() , lowerBound - (delta / 2.0) - center.y()); + } + } + + //label overlap detection - compensate one pixel for rounding errors + if (labelItem->pos().y() + boundingRect.height() > height || forceHide || + (labelItem->pos().y() + (heightDiff / 2.0) - 1.0) > axisRect.bottom() || + labelItem->pos().y() + (heightDiff / 2.0) < (axisRect.top() - 1.0)) { + labelItem->setVisible(false); + } + else { + labelItem->setVisible(true); + height=labelItem->pos().y(); + } + + //shades + if ((i + 1) % 2 && i > 1) { + QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem *>(shades.at(i / 2 - 1)); + qreal lowerBound = qMin(layout[i - 1], gridRect.bottom()); + qreal upperBound = qMax(layout[i], gridRect.top()); + rectItem->setRect(gridRect.left(), upperBound, gridRect.width(), lowerBound - upperBound); + if (rectItem->rect().height() <= 0.0) + rectItem->setVisible(false); + else + rectItem->setVisible(true); + } + + // check if the grid line and the axis tick should be shown + qreal y = gridItem->line().p1().y(); + if ((y < gridRect.top() || y > gridRect.bottom())) + { + gridItem->setVisible(false); + tickItem->setVisible(false); + }else{ + gridItem->setVisible(true); + tickItem->setVisible(true); + } + + } + //begin/end grid line in case labels between + if (intervalAxis()) { + QGraphicsLineItem *gridLine; + gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size())); + gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.right(), gridRect.top()); + gridLine->setVisible(true); + gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size() + 1)); + gridLine->setLine(gridRect.left(), gridRect.bottom(), gridRect.right(), gridRect.bottom()); + gridLine->setVisible(true); + } +} + +QSizeF VerticalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const +{ + Q_UNUSED(constraint); + QSizeF sh(0, 0); + + if (axis()->titleText().isEmpty() || !titleItem()->isVisible()) + return sh; + + switch (which) { + case Qt::MinimumSize: { + QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), + QStringLiteral("...")); + sh = QSizeF(titleRect.height() + (titlePadding() * 2.0), titleRect.width()); + break; + } + case Qt::MaximumSize: + case Qt::PreferredSize: { + QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText()); + sh = QSizeF(titleRect.height() + (titlePadding() * 2.0), titleRect.width()); + break; + } + default: + break; + } + + return sh; +} + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/axis/verticalaxis_p.h b/src/charts/axis/verticalaxis_p.h new file mode 100644 index 00000000..8349ff51 --- /dev/null +++ b/src/charts/axis/verticalaxis_p.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef VERTICALAXIS_P_H_ +#define VERTICALAXIS_P_H_ + +#include "cartesianchartaxis_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class VerticalAxis : public CartesianChartAxis +{ +public: + VerticalAxis(QAbstractAxis *axis, QGraphicsItem *item = 0, bool intervalAxis = false); + ~VerticalAxis(); + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const; +protected: + void updateGeometry(); + +}; + +QT_CHARTS_END_NAMESPACE + +#endif /* VERTICALAXIS_P_H_ */ |