chartaxiselement.cpp
349 lines
| 11.9 KiB
| text/x-c
|
CppLexer
Miikka Heikkinen
|
r2483 | /**************************************************************************** | ||
** | ||||
** Copyright (C) 2013 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 Commercial Charts Add-on. | ||||
** | ||||
** $QT_BEGIN_LICENSE$ | ||||
** Licensees holding valid Qt Commercial licenses may use this file in | ||||
** accordance with the Qt Commercial 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 <QFontMetrics> | ||||
QTCOMMERCIALCHART_BEGIN_NAMESPACE | ||||
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 QGraphicsSimpleTextItem(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); | ||||
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) | ||||
{ | ||||
foreach (QGraphicsItem *item, m_labels->childItems()) | ||||
static_cast<QGraphicsSimpleTextItem *>(item)->setPen(pen); | ||||
} | ||||
void ChartAxisElement::handleLabelsBrushChanged(const QBrush &brush) | ||||
{ | ||||
foreach (QGraphicsItem *item, m_labels->childItems()) | ||||
static_cast<QGraphicsSimpleTextItem *>(item)->setBrush(brush); | ||||
} | ||||
void ChartAxisElement::handleLabelsFontChanged(const QFont &font) | ||||
{ | ||||
foreach (QGraphicsItem *item, m_labels->childItems()) | ||||
static_cast<QGraphicsSimpleTextItem *>(item)->setFont(font); | ||||
QGraphicsLayoutItem::updateGeometry(); | ||||
presenter()->layout()->invalidate(); | ||||
} | ||||
void ChartAxisElement::handleTitleTextChanged(const QString &title) | ||||
{ | ||||
QGraphicsLayoutItem::updateGeometry(); | ||||
presenter()->layout()->invalidate(); | ||||
m_title->setText(title); | ||||
} | ||||
void ChartAxisElement::handleTitlePenChanged(const QPen &pen) | ||||
{ | ||||
m_title->setPen(pen); | ||||
} | ||||
void ChartAxisElement::handleTitleBrushChanged(const QBrush &brush) | ||||
{ | ||||
m_title->setBrush(brush); | ||||
} | ||||
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(); | ||||
} | ||||
QRect ChartAxisElement::labelBoundingRect(const QFontMetrics &fn, const QString &label) const | ||||
{ | ||||
QRect boundingRect = fn.boundingRect(label); | ||||
// Take label rotation into account | ||||
if (axis()->labelsAngle()) { | ||||
QTransform transform; | ||||
transform.rotate(axis()->labelsAngle()); | ||||
boundingRect = transform.mapRect(boundingRect); | ||||
} | ||||
return boundingRect; | ||||
} | ||||
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(); | ||||
} | ||||
QStringList ChartAxisElement::createValueLabels(qreal min, qreal max, int ticks, const QString &format) | ||||
{ | ||||
QStringList labels; | ||||
if (max <= min || ticks < 1) | ||||
return labels; | ||||
int n = qMax(int(-qFloor(log10((max - min) / (ticks - 1)))), 0); | ||||
n++; | ||||
if (format.isNull()) { | ||||
for (int i = 0; i < ticks; i++) { | ||||
qreal value = min + (i * (max - min) / (ticks - 1)); | ||||
labels << QString::number(value, 'f', n); | ||||
} | ||||
} else { | ||||
QByteArray array = format.toLatin1(); | ||||
for (int i = 0; i < ticks; i++) { | ||||
qreal value = min + (i * (max - min) / (ticks - 1)); | ||||
if (format.contains("d") | ||||
|| format.contains("i") | ||||
|| format.contains("c")) { | ||||
labels << QString().sprintf(array, (qint64)value); | ||||
} else if (format.contains("u") | ||||
|| format.contains("o") | ||||
|| format.contains("x", Qt::CaseInsensitive)) { | ||||
labels << QString().sprintf(array, (quint64)value); | ||||
} else if (format.contains("f", Qt::CaseInsensitive) | ||||
|| format.contains("e", Qt::CaseInsensitive) | ||||
|| format.contains("g", Qt::CaseInsensitive)) { | ||||
labels << QString().sprintf(array, value); | ||||
} else { | ||||
labels << QString(); | ||||
} | ||||
} | ||||
} | ||||
return labels; | ||||
} | ||||
QStringList ChartAxisElement::createLogValueLabels(qreal min, qreal max, qreal base, int ticks, const QString &format) | ||||
{ | ||||
QStringList labels; | ||||
if (max <= min || ticks < 1) | ||||
return labels; | ||||
int n = 0; | ||||
if (ticks > 1) | ||||
n = qMax(int(-qFloor(log10((max - min) / (ticks - 1)))), 0); | ||||
n++; | ||||
int firstTick; | ||||
if (base > 1) | ||||
firstTick = ceil(log10(min) / log10(base)); | ||||
else | ||||
firstTick = ceil(log10(max) / log10(base)); | ||||
if (format.isNull()) { | ||||
for (int i = firstTick; i < ticks + firstTick; i++) { | ||||
qreal value = qPow(base, i); | ||||
labels << QString::number(value, 'f', n); | ||||
} | ||||
} else { | ||||
QByteArray array = format.toLatin1(); | ||||
for (int i = firstTick; i < ticks + firstTick; i++) { | ||||
qreal value = qPow(base, i); | ||||
if (format.contains("d") | ||||
|| format.contains("i") | ||||
|| format.contains("c")) { | ||||
labels << QString().sprintf(array, (qint64)value); | ||||
} else if (format.contains("u") | ||||
|| format.contains("o") | ||||
|| format.contains("x", Qt::CaseInsensitive)) { | ||||
labels << QString().sprintf(array, (quint64)value); | ||||
} else if (format.contains("f", Qt::CaseInsensitive) | ||||
|| format.contains("e", Qt::CaseInsensitive) | ||||
|| format.contains("g", Qt::CaseInsensitive)) { | ||||
labels << QString().sprintf(array, value); | ||||
} else { | ||||
labels << QString(); | ||||
} | ||||
} | ||||
} | ||||
return labels; | ||||
} | ||||
QStringList ChartAxisElement::createDateTimeLabels(qreal min, qreal max,int ticks,const QString &format) | ||||
{ | ||||
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 << QDateTime::fromMSecsSinceEpoch(value).toString(format); | ||||
} | ||||
return labels; | ||||
} | ||||
void ChartAxisElement::axisSelected() | ||||
{ | ||||
emit clicked(); | ||||
} | ||||
#include "moc_chartaxiselement_p.cpp" | ||||
QTCOMMERCIALCHART_END_NAMESPACE | ||||