From 8d7d66e44a18136d2d666bce03702543a0a8cf49 Mon Sep 17 00:00:00 2001 From: Michal Klocek Date: Wed, 5 Sep 2012 10:42:37 +0300 Subject: Refactors layout * adds sizeHints to layout managers * adds sizeHiint to axes * adds "..." wraping to titles * adds title for axes * adds "..." wraping to legend markers * adds logic for layouting axes vs legend vs plotArea * renames minimumMargins to margin * marings size is always keept * legend takes contentMargins into consideration during layout * charts takes contentMargins into consideration during layout * adds "..." wraping to chartvaleaxisY * adds logic to resize plotArea during scale and scroll --- plugins/declarative/declarativechart.cpp | 3 +- src/animations/axisanimation.cpp | 6 +- src/axis/barcategoryaxis/chartbarcategoryaxisx.cpp | 85 ++++++-- src/axis/barcategoryaxis/chartbarcategoryaxisx_p.h | 2 +- src/axis/barcategoryaxis/chartbarcategoryaxisy.cpp | 85 ++++++-- src/axis/barcategoryaxis/chartbarcategoryaxisy_p.h | 2 +- src/axis/categoryaxis/chartcategoryaxisx.cpp | 76 +++++-- src/axis/categoryaxis/chartcategoryaxisx_p.h | 2 +- src/axis/categoryaxis/chartcategoryaxisy.cpp | 74 +++++-- src/axis/categoryaxis/chartcategoryaxisy_p.h | 2 +- src/axis/chartaxis.cpp | 150 ++++++++++--- src/axis/chartaxis_p.h | 34 ++- src/axis/datetimeaxis/chartdatetimeaxisx.cpp | 60 ++++-- src/axis/datetimeaxis/chartdatetimeaxisx_p.h | 2 +- src/axis/datetimeaxis/chartdatetimeaxisy.cpp | 61 ++++-- src/axis/datetimeaxis/chartdatetimeaxisy_p.h | 2 +- src/axis/qabstractaxis.cpp | 84 ++++++++ src/axis/qabstractaxis.h | 13 ++ src/axis/qabstractaxis_p.h | 6 + src/axis/valueaxis/chartvalueaxisx.cpp | 75 +++++-- src/axis/valueaxis/chartvalueaxisx_p.h | 2 +- src/axis/valueaxis/chartvalueaxisy.cpp | 90 ++++++-- src/axis/valueaxis/chartvalueaxisy_p.h | 2 +- src/chartbackground_p.h | 1 - src/chartlayout.cpp | 239 ++++++++++++++------- src/chartlayout_p.h | 32 ++- src/chartpresenter.cpp | 135 ++++++------ src/chartpresenter_p.h | 19 +- src/charttitle.cpp | 94 ++++++++ src/charttitle_p.h | 53 +++++ src/domain.cpp | 1 - src/legend/legendlayout.cpp | 118 +++++----- src/legend/legendmarker.cpp | 37 +++- src/legend/legendmarker_p.h | 1 + src/qchart.cpp | 10 +- src/qchart.h | 6 +- src/src.pro | 7 +- 37 files changed, 1228 insertions(+), 443 deletions(-) create mode 100644 src/charttitle.cpp create mode 100644 src/charttitle_p.h diff --git a/plugins/declarative/declarativechart.cpp b/plugins/declarative/declarativechart.cpp index 572befde..6ee43be3 100644 --- a/plugins/declarative/declarativechart.cpp +++ b/plugins/declarative/declarativechart.cpp @@ -245,7 +245,7 @@ DeclarativeChart::DeclarativeChart(QDeclarativeItem *parent) void DeclarativeChart::changeMinimumMargins(int top, int bottom, int left, int right) { - m_chart->setMinimumMargins(QMargins(left, top, right, bottom)); + m_chart->setMargins(QMargins(left, top, right, bottom)); emit minimumMarginsChanged(); emit plotAreaChanged(m_chart->plotArea()); } @@ -501,6 +501,7 @@ qreal DeclarativeChart::topMargin() qreal DeclarativeChart::bottomMargin() { + qWarning() << "ChartView.bottomMargin is deprecated. Use minimumMargins and plotArea instead."; return m_chart->plotArea().bottom(); } diff --git a/src/animations/axisanimation.cpp b/src/animations/axisanimation.cpp index 8a10c848..0d004d6f 100644 --- a/src/animations/axisanimation.cpp +++ b/src/animations/axisanimation.cpp @@ -20,6 +20,7 @@ #include "axisanimation_p.h" #include "chartaxis_p.h" +#include "chartpresenter_p.h" #include #include @@ -61,7 +62,7 @@ void AxisAnimation::setValues(QVector &oldLayout, QVector &newLayo switch (m_type) { case ZoomOutAnimation: { - QRectF rect = m_axis->geometry(); + QRectF rect = m_axis->presenter()->chartsGeometry(); oldLayout.resize(newLayout.count()); for(int i = 0, j = oldLayout.count() - 1; i < (oldLayout.count() + 1) / 2; ++i, --j) { @@ -94,7 +95,7 @@ void AxisAnimation::setValues(QVector &oldLayout, QVector &newLayo break; default: { oldLayout.resize(newLayout.count()); - QRectF rect = m_axis->geometry(); + QRectF rect = m_axis->presenter()->chartsGeometry(); for(int i = 0, j = oldLayout.count() - 1; i < oldLayout.count(); ++i, --j) oldLayout[i] = m_axis->axisType() == ChartAxis::X_AXIS ? rect.left() : rect.top(); } @@ -131,7 +132,6 @@ void AxisAnimation::updateCurrentValue (const QVariant &value ) Q_ASSERT(vector.count() != 0); m_axis->setLayout(vector); m_axis->updateGeometry(); - m_axis->checkLayout(); } } diff --git a/src/axis/barcategoryaxis/chartbarcategoryaxisx.cpp b/src/axis/barcategoryaxis/chartbarcategoryaxisx.cpp index 072c1fd2..9290cd4d 100644 --- a/src/axis/barcategoryaxis/chartbarcategoryaxisx.cpp +++ b/src/axis/barcategoryaxis/chartbarcategoryaxisx.cpp @@ -21,6 +21,7 @@ #include "chartbarcategoryaxisx_p.h" #include "chartpresenter_p.h" #include "qbarcategoryaxis_p.h" +#include #include #include @@ -47,23 +48,25 @@ QVector ChartBarCategoryAxisX::calculateLayout() const QVector points; points.resize(count+2); - const qreal delta = m_rect.width()/(count); + QRectF rect = presenter()->chartsGeometry(); + + const qreal delta = rect.width()/(count); qreal offset =-m_min-0.5; if(delta<1) return points; if(offset<=0) { - offset = int(offset * m_rect.width()/(m_max - m_min))%int(delta) + delta; + offset = int(offset * rect.width()/(m_max - m_min))%int(delta) + delta; } else { - offset = int(offset * m_rect.width()/(m_max - m_min))%int(delta); + offset = int(offset * rect.width()/(m_max - m_min))%int(delta); } - points[0] = m_rect.left(); - points[count+1] = m_rect.right(); + points[0] = rect.left(); + points[count+1] = rect.right(); for (int i = 0; i < count; ++i) { - qreal x = offset + i * delta + m_rect.left(); + qreal x = offset + i * delta + rect.left(); points[i+1] = x; } return points; @@ -72,9 +75,10 @@ QVector ChartBarCategoryAxisX::calculateLayout() const QStringList ChartBarCategoryAxisX::createCategoryLabels(const QVector& layout) const { QStringList result; - qreal d = (m_max - m_min)/m_rect.width(); + QRectF rect = presenter()->chartsGeometry(); + qreal d = (m_max - m_min)/rect.width(); for (int i = 0;i < layout.count()-1; ++i) { - qreal x = qFloor((((layout[i+1] + layout[i])/2-m_rect.left())*d + m_min+0.5)); + qreal x = qFloor((((layout[i+1] + layout[i])/2-rect.left())*d + m_min+0.5)); if ((x < m_categoriesAxis->categories().count()) && (x >= 0)) { result << m_categoriesAxis->categories().at(x); } @@ -92,9 +96,6 @@ void ChartBarCategoryAxisX::updateGeometry() { const QVector& layout = ChartAxis::layout(); - m_minWidth = 0; - m_minHeight = 0; - if(layout.isEmpty()) return; QStringList ticksList = createCategoryLabels(layout); @@ -107,15 +108,17 @@ void ChartBarCategoryAxisX::updateGeometry() Q_ASSERT(labels.size() == ticksList.size()); Q_ASSERT(layout.size() == ticksList.size()); - const qreal delta = m_rect.width()/(m_categoriesAxis->d_ptr->count()); + QRectF chartRect = presenter()->chartsGeometry(); + + const qreal delta = chartRect.width()/(m_categoriesAxis->d_ptr->count()); QGraphicsLineItem *lineItem = static_cast(axis.at(0)); - lineItem->setLine(m_rect.left(), m_rect.bottom(), m_rect.right(), m_rect.bottom()); + lineItem->setLine( chartRect.left(), chartRect.bottom(), chartRect.right(), chartRect.bottom()); - qreal width = m_rect.left(); + qreal width = chartRect.left(); for (int i = 0; i < layout.size(); ++i) { QGraphicsLineItem *lineItem = static_cast(lines.at(i)); - lineItem->setLine(layout[i], m_rect.top(), layout[i], m_rect.bottom()); + lineItem->setLine(layout[i], chartRect.top(), layout[i], chartRect.bottom()); QGraphicsSimpleTextItem *labelItem = static_cast(labels.at(i)); labelItem->setText(ticksList.at(i)); const QRectF& rect = labelItem->boundingRect(); @@ -123,12 +126,12 @@ void ChartBarCategoryAxisX::updateGeometry() labelItem->setTransformOriginPoint(center.x(), center.y()); if(i==0){ - labelItem->setPos(layout[i+1] - (delta)/2 - center.x(), m_rect.bottom() + label_padding); + labelItem->setPos(layout[i+1] - (delta)/2 - center.x(), chartRect.bottom() + label_padding); }else{ - labelItem->setPos(layout[i] + (delta)/2 - center.x(), m_rect.bottom() + label_padding); + labelItem->setPos(layout[i] + (delta)/2 - center.x(), chartRect.bottom() + label_padding); } - if(labelItem->pos().x()<=width || labelItem->pos().x()+ rect.width()>m_rect.right()) { + if(labelItem->pos().x()<=width || labelItem->pos().x()+ rect.width()> chartRect.right()) { labelItem->setVisible(false); } else { @@ -136,15 +139,12 @@ void ChartBarCategoryAxisX::updateGeometry() width=rect.width()+labelItem->pos().x(); } - m_minWidth+=rect.width(); - m_minHeight=qMax(rect.height()+label_padding,m_minHeight); - if ((i+1)%2 && i>1) { QGraphicsRectItem *rectItem = static_cast(shades.at(i/2-1)); - rectItem->setRect(layout[i-1],m_rect.top(),layout[i]-layout[i-1],m_rect.height()); + rectItem->setRect(layout[i-1], chartRect.top(),layout[i]-layout[i-1], chartRect.height()); } lineItem = static_cast(axis.at(i+1)); - lineItem->setLine(layout[i],m_rect.bottom(),layout[i],m_rect.bottom()+5); + lineItem->setLine(layout[i], chartRect.bottom(),layout[i], chartRect.bottom()+5); } } @@ -158,4 +158,43 @@ void ChartBarCategoryAxisX::handleAxisUpdated() ChartAxis::handleAxisUpdated(); } +QSizeF ChartBarCategoryAxisX::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const +{ + Q_UNUSED(constraint) + + QFontMetrics fn(m_font); + QSizeF sh; + QSizeF base = ChartAxis::sizeHint(which, constraint); + QStringList ticksList = createCategoryLabels(ChartAxis::layout()); + qreal width=0; + qreal height=0; + + switch (which) { + case Qt::MinimumSize: + width = fn.boundingRect("...").width(); + height = fn.height()+label_padding; + width=qMax(width,base.width()); + height+=base.height(); + sh = QSizeF(width,height); + break; + case Qt::PreferredSize:{ + + for (int i = 0; i < ticksList.size(); ++i) + { + QRectF rect = fn.boundingRect(ticksList.at(i)); + width+=rect.width(); + height=qMax(rect.height()+label_padding,height); + } + width=qMax(width,base.width()); + height+=base.height(); + sh = QSizeF(width,height); + break; + } + default: + break; + } + + return sh; +} + QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/axis/barcategoryaxis/chartbarcategoryaxisx_p.h b/src/axis/barcategoryaxis/chartbarcategoryaxisx_p.h index 377d4d54..2340ff7d 100644 --- a/src/axis/barcategoryaxis/chartbarcategoryaxisx_p.h +++ b/src/axis/barcategoryaxis/chartbarcategoryaxisx_p.h @@ -45,7 +45,7 @@ public: ~ChartBarCategoryAxisX(); AxisType axisType() const { return X_AXIS;} - + QSizeF sizeHint(Qt::SizeHint which, const QSizeF& constraint) const; protected: QVector calculateLayout() const; void updateGeometry(); diff --git a/src/axis/barcategoryaxis/chartbarcategoryaxisy.cpp b/src/axis/barcategoryaxis/chartbarcategoryaxisy.cpp index f5602368..1a8071aa 100644 --- a/src/axis/barcategoryaxis/chartbarcategoryaxisy.cpp +++ b/src/axis/barcategoryaxis/chartbarcategoryaxisy.cpp @@ -22,6 +22,7 @@ #include "chartpresenter_p.h" #include "qbarcategoryaxis_p.h" #include +#include #include static int label_padding = 5; @@ -46,23 +47,25 @@ QVector ChartBarCategoryAxisY::calculateLayout() const QVector points; points.resize(count+2); - const qreal delta = m_rect.height()/(count); + QRectF rect = presenter()->chartsGeometry(); + + const qreal delta = rect.height()/(count); qreal offset = - m_min - 0.5; if(delta<1) return points; if(offset<=0) { - offset = int(offset * m_rect.height()/(m_max - m_min))%int(delta) + delta; + offset = int(offset * rect.height()/(m_max - m_min))%int(delta) + delta; } else { - offset = int(offset * m_rect.height()/(m_max - m_min))%int(delta); + offset = int(offset * rect.height()/(m_max - m_min))%int(delta); } - points[0] = m_rect.bottom(); - points[count+1] = m_rect.top(); + points[0] = rect.bottom(); + points[count+1] = rect.top(); for (int i = 0; i < count; ++i) { - int y = m_rect.bottom() - i * delta - offset; + int y = rect.bottom() - i * delta - offset; points[i+1] = y; } return points; @@ -71,9 +74,10 @@ QVector ChartBarCategoryAxisY::calculateLayout() const QStringList ChartBarCategoryAxisY::createCategoryLabels(const QVector& layout) const { QStringList result; - qreal d = (m_max - m_min)/m_rect.height(); + QRectF rect = presenter()->chartsGeometry(); + qreal d = (m_max - m_min)/rect.height(); for (int i = 0;i < layout.count()-1; ++i) { - qreal x = qFloor(((m_rect.height()- (layout[i+1] + layout[i])/2 + m_rect.top())*d + m_min+0.5)); + qreal x = qFloor(((rect.height()- (layout[i+1] + layout[i])/2 + rect.top())*d + m_min+0.5)); if ((x < m_categoriesAxis->categories().count()) && (x >= 0)) { result << m_categoriesAxis->categories().at(x); } @@ -90,9 +94,6 @@ void ChartBarCategoryAxisY::updateGeometry() { const QVector& layout = ChartAxis::layout(); - m_minWidth = 0; - m_minHeight = 0; - if(layout.isEmpty()) return; QStringList ticksList = createCategoryLabels(layout); @@ -105,15 +106,17 @@ void ChartBarCategoryAxisY::updateGeometry() Q_ASSERT(labels.size() == ticksList.size()); Q_ASSERT(layout.size() == ticksList.size()); - const qreal delta = m_rect.height()/(m_categoriesAxis->d_ptr->count()); + QRectF chartRect = presenter()->chartsGeometry(); + + const qreal delta = chartRect.height()/(m_categoriesAxis->d_ptr->count()); QGraphicsLineItem *lineItem = static_cast(axis.at(0)); - lineItem->setLine(m_rect.left() , m_rect.top(), m_rect.left(), m_rect.bottom()); + lineItem->setLine(chartRect.left() , chartRect.top(), chartRect.left(), chartRect.bottom()); - qreal height = m_rect.bottom(); + qreal height = chartRect.bottom(); for (int i = 0; i < layout.size(); ++i) { QGraphicsLineItem *lineItem = static_cast(lines.at(i)); - lineItem->setLine(m_rect.left() , layout[i], m_rect.right(), layout[i]); + lineItem->setLine(chartRect.left() , layout[i], chartRect.right(), layout[i]); QGraphicsSimpleTextItem *labelItem = static_cast(labels.at(i)); labelItem->setText(ticksList.at(i)); const QRectF& rect = labelItem->boundingRect(); @@ -121,13 +124,13 @@ void ChartBarCategoryAxisY::updateGeometry() labelItem->setTransformOriginPoint(center.x(), center.y()); if(i==0) { - labelItem->setPos(m_rect.left() - rect.width() - label_padding ,layout[i+1] + (delta)/2 - center.y()); + labelItem->setPos(chartRect.left() - rect.width() - label_padding ,layout[i+1] + (delta)/2 - center.y()); } else { - labelItem->setPos(m_rect.left() - rect.width() - label_padding ,layout[i] - (delta)/2 - center.y()); + labelItem->setPos(chartRect.left() - rect.width() - label_padding ,layout[i] - (delta)/2 - center.y()); } - if(labelItem->pos().y()+rect.height()>= height || labelItem->pos().y() < m_rect.top()) { + if(labelItem->pos().y()+rect.height()>= height || labelItem->pos().y() < chartRect.top()) { labelItem->setVisible(false); } else { @@ -135,15 +138,12 @@ void ChartBarCategoryAxisY::updateGeometry() height=labelItem->pos().y(); } - m_minWidth=qMax(rect.width()+label_padding,m_minWidth); - m_minHeight+=rect.height(); - if ((i+1)%2 && i>1) { QGraphicsRectItem *rectItem = static_cast(shades.at(i/2-1)); - rectItem->setRect(m_rect.left(),layout[i],m_rect.width(),layout[i-1]-layout[i]); + rectItem->setRect(chartRect.left(),layout[i],chartRect.width(),layout[i-1]-layout[i]); } lineItem = static_cast(axis.at(i+1)); - lineItem->setLine(m_rect.left()-5,layout[i],m_rect.left(),layout[i]); + lineItem->setLine(chartRect.left()-5,layout[i],chartRect.left(),layout[i]); } } @@ -160,4 +160,43 @@ void ChartBarCategoryAxisY::handleAxisUpdated() ChartAxis::handleAxisUpdated(); } +QSizeF ChartBarCategoryAxisY::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const +{ + Q_UNUSED(constraint) + + QFontMetrics fn(m_font); + QSizeF sh; + QSizeF base = ChartAxis::sizeHint(which, constraint); + QStringList ticksList = createCategoryLabels(ChartAxis::layout()); + qreal width=0; + qreal height=0; + + switch (which) { + case Qt::MinimumSize: + width = fn.boundingRect("...").width() + label_padding; + height = fn.height(); + width+=base.width(); + height=qMax(height,base.height()); + sh = QSizeF(width,height); + break; + case Qt::PreferredSize:{ + + for (int i = 0; i < ticksList.size(); ++i) + { + QRectF rect = fn.boundingRect(ticksList.at(i)); + height+=rect.height(); + width=qMax(rect.width()+label_padding,width); + } + height=qMax(height,base.height()); + width+=base.width(); + sh = QSizeF(width,height); + break; + } + default: + break; + } + + return sh; +} + QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/axis/barcategoryaxis/chartbarcategoryaxisy_p.h b/src/axis/barcategoryaxis/chartbarcategoryaxisy_p.h index 1db8aef5..1bf399bc 100644 --- a/src/axis/barcategoryaxis/chartbarcategoryaxisy_p.h +++ b/src/axis/barcategoryaxis/chartbarcategoryaxisy_p.h @@ -45,7 +45,7 @@ public: ~ChartBarCategoryAxisY(); AxisType axisType() const { return Y_AXIS;} - + QSizeF sizeHint(Qt::SizeHint which, const QSizeF& constraint) const; protected: QVector calculateLayout() const; void updateGeometry(); diff --git a/src/axis/categoryaxis/chartcategoryaxisx.cpp b/src/axis/categoryaxis/chartcategoryaxisx.cpp index 59d490a5..bd2c27a3 100644 --- a/src/axis/categoryaxis/chartcategoryaxisx.cpp +++ b/src/axis/categoryaxis/chartcategoryaxisx.cpp @@ -47,16 +47,18 @@ QVector ChartCategoryAxisX::calculateLayout() const if (tickCount < 2) return points; + QRectF rect = presenter()->chartsGeometry(); + qreal range = axis->max() - axis->min(); if (range > 0) { points.resize(tickCount); - qreal scale = m_rect.width() / range; + qreal scale = rect.width() / range; for (int i = 0; i < tickCount; ++i) if (i < tickCount - 1) { - int x = (axis->startValue(axis->categoriesLabels().at(i)) - axis->min()) * scale + m_rect.left(); + int x = (axis->startValue(axis->categoriesLabels().at(i)) - axis->min()) * scale + rect.left(); points[i] = x; } else { - int x = (axis->endValue(axis->categoriesLabels().at(i - 1)) - axis->min()) * scale + m_rect.left(); + int x = (axis->endValue(axis->categoriesLabels().at(i - 1)) - axis->min()) * scale + rect.left(); points[i] = x; } } @@ -67,9 +69,6 @@ void ChartCategoryAxisX::updateGeometry() { const QVector& layout = ChartAxis::layout(); - m_minWidth = 0; - m_minHeight = 0; - if(layout.isEmpty()) return; QCategoryAxis *categoryAxis = qobject_cast(m_chartAxis); @@ -85,13 +84,14 @@ void ChartCategoryAxisX::updateGeometry() labels.at(i)->setVisible(false); } + QRectF chartRect = presenter()->chartsGeometry(); // axis base line + QGraphicsLineItem *lineItem = static_cast(axis.at(0)); - lineItem->setLine(m_rect.left(), m_rect.bottom(), m_rect.right(), m_rect.bottom()); + lineItem->setLine(chartRect.left(), chartRect.bottom(), chartRect.right(), chartRect.bottom()); for (int i = 0; i < layout.size(); ++i) { - // label items QGraphicsSimpleTextItem *labelItem = static_cast(labels.at(i)); if (i < ticksList.count()) { labelItem->setText(ticksList.at(i)); @@ -99,43 +99,42 @@ void ChartCategoryAxisX::updateGeometry() const QRectF& rect = labelItem->boundingRect(); QPointF center = rect.center(); labelItem->setTransformOriginPoint(center.x(), center.y()); + if (i < layout.size() - 1) { - labelItem->setPos(layout[i] + (layout[i + 1] - layout[i]) / 2 - center.x(), m_rect.bottom() + label_padding); + labelItem->setPos(layout[i] + (layout[i + 1] - layout[i]) / 2 - center.x(), chartRect.bottom() + label_padding); } else { - labelItem->setPos(layout[i] - center.x(), m_rect.bottom() + label_padding); + labelItem->setPos(layout[i] - center.x(), chartRect.bottom() + label_padding); } // check if the label should be shown - if (labelItem->pos().x() + center.x() < m_rect.left() || labelItem->pos().x() + center.x() > m_rect.right()) + if (labelItem->pos().x() + center.x() < chartRect.left() || labelItem->pos().x() + center.x() > chartRect.right()) labelItem->setVisible(false); else labelItem->setVisible(true); - m_minWidth += rect.width(); - m_minHeight = qMax(rect.height()+ label_padding, m_minHeight); - if ((i + 1) % 2 && i > 1) { QGraphicsRectItem *rectItem = static_cast(shades.at(i / 2 - 1)); - rectItem->setRect(layout[i - 1],m_rect.top(),layout[i]-layout[i - 1],m_rect.height()); + rectItem->setRect(layout[i - 1],chartRect.top(),layout[i]-layout[i - 1],chartRect.height()); } // grid lines and axis line ticks QGraphicsLineItem *lineItem = static_cast(lines.at(i)); - lineItem->setPos(layout[i], m_rect.top()); - lineItem->setLine(0, 0, 0, m_rect.height()); + lineItem->setPos(layout[i], chartRect.top()); + lineItem->setLine(0, 0, 0, chartRect.height()); QGraphicsLineItem *tickLineItem = static_cast(axis.at(i+1)); - tickLineItem->setPos(layout[i], m_rect.bottom()); + tickLineItem->setPos(layout[i], chartRect.bottom()); tickLineItem->setLine(0, 0, 0, 5); // check if the grid line and the axis tick should be shown - if (lineItem->pos().x() < m_rect.left() || lineItem->pos().x() > m_rect.right()) { + if (lineItem->pos().x() < chartRect.left() || lineItem->pos().x() > chartRect.right()) { lineItem->setVisible(false); tickLineItem->setVisible(false); } else { lineItem->setVisible(true); tickLineItem->setVisible(true); } + } } @@ -146,4 +145,43 @@ void ChartCategoryAxisX::handleAxisUpdated() ChartAxis::handleAxisUpdated(); } +QSizeF ChartCategoryAxisX::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const +{ + Q_UNUSED(constraint) + + QFontMetrics fn(m_font); + QSizeF sh; + QSizeF base = ChartAxis::sizeHint(which, constraint); + QStringList ticksList ; //TODO: + qreal width=0; + qreal height=0; + + switch (which) { + case Qt::MinimumSize: + width = fn.boundingRect("...").width(); + height = fn.height() + label_padding; + width=qMax(width,base.width()); + height+=base.height(); + sh = QSizeF(width,height); + break; + case Qt::PreferredSize: { + + for (int i = 0; i < ticksList.size(); ++i) + { + QRectF rect = fn.boundingRect(ticksList.at(i)); + width+=rect.width(); + height=qMax(rect.height()+label_padding,height); + } + width=qMax(width,base.width()); + height+=base.height(); + sh = QSizeF(width,height); + break; + } + default: + break; + } + + return sh; +} + QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/axis/categoryaxis/chartcategoryaxisx_p.h b/src/axis/categoryaxis/chartcategoryaxisx_p.h index 60191f42..4b380bcc 100644 --- a/src/axis/categoryaxis/chartcategoryaxisx_p.h +++ b/src/axis/categoryaxis/chartcategoryaxisx_p.h @@ -44,7 +44,7 @@ public: ~ChartCategoryAxisX(); AxisType axisType() const { return X_AXIS;} - + QSizeF sizeHint(Qt::SizeHint which, const QSizeF& constraint) const; protected: QVector calculateLayout() const; void updateGeometry(); diff --git a/src/axis/categoryaxis/chartcategoryaxisy.cpp b/src/axis/categoryaxis/chartcategoryaxisy.cpp index 82f2e323..80aeab39 100644 --- a/src/axis/categoryaxis/chartcategoryaxisy.cpp +++ b/src/axis/categoryaxis/chartcategoryaxisy.cpp @@ -47,16 +47,18 @@ QVector ChartCategoryAxisY::calculateLayout() const if (tickCount < 2) return points; + QRectF rect = presenter()->chartsGeometry(); + qreal range = axis->max() - axis->min(); if (range > 0) { points.resize(tickCount); - qreal scale = m_rect.height() / range; + qreal scale = rect.height() / range; for (int i = 0; i < tickCount; ++i) if (i < tickCount - 1) { - int y = -(axis->startValue(axis->categoriesLabels().at(i)) - axis->min()) * scale + m_rect.bottom(); + int y = -(axis->startValue(axis->categoriesLabels().at(i)) - axis->min()) * scale + rect.bottom(); points[i] = y; } else { - int y = -(axis->endValue(axis->categoriesLabels().at(i - 1)) - axis->min()) * scale + m_rect.bottom(); + int y = -(axis->endValue(axis->categoriesLabels().at(i - 1)) - axis->min()) * scale + rect.bottom(); points[i] = y; } } @@ -67,8 +69,6 @@ QVector ChartCategoryAxisY::calculateLayout() const void ChartCategoryAxisY::updateGeometry() { const QVector &layout = ChartAxis::layout(); - m_minWidth = 0; - m_minHeight = 0; if(layout.isEmpty()) { return; @@ -88,9 +88,11 @@ void ChartCategoryAxisY::updateGeometry() labels.at(i)->setVisible(false); } + QRectF chartRect = presenter()->chartsGeometry(); + // axis base line QGraphicsLineItem *lineItem = static_cast(axis.at(0)); - lineItem->setLine(m_rect.left() , m_rect.top(), m_rect.left(), m_rect.bottom()); + lineItem->setLine(chartRect.left() , chartRect.top(), chartRect.left(), chartRect.bottom()); for (int i = 0; i < layout.size(); ++i) { @@ -104,13 +106,14 @@ void ChartCategoryAxisY::updateGeometry() QPointF center = rect.center(); labelItem->setTransformOriginPoint(center.x(), center.y()); + if (i < layout.size() - 1) - labelItem->setPos(m_rect.left() - rect.width() - label_padding , layout[i] + (layout[i + 1] - layout[i]) / 2 - center.y()); + labelItem->setPos(chartRect.left() - rect.width() - label_padding , layout[i] + (layout[i + 1] - layout[i]) / 2 - center.y()); else - labelItem->setPos(m_rect.left() - rect.width() - label_padding , layout[i]-center.y()); + labelItem->setPos(chartRect.left() - rect.width() - label_padding , layout[i]-center.y()); // check if the label should be shown - if (labelItem->pos().y() + center.y() < m_rect.top() || labelItem->pos().y() + center.y() > m_rect.bottom()) + if (labelItem->pos().y() + center.y() < chartRect.top() || labelItem->pos().y() + center.y() > chartRect.bottom()) labelItem->setVisible(false); else labelItem->setVisible(true); @@ -123,31 +126,29 @@ void ChartCategoryAxisY::updateGeometry() // height=labelItem->pos().y(); // } - m_minWidth=qMax(rect.width()+label_padding,m_minWidth); - m_minHeight+=rect.height(); - if ((i+1)%2 && i>1) { QGraphicsRectItem *rectItem = static_cast(shades.at(i/2-1)); - rectItem->setRect(m_rect.left(),layout[i],m_rect.width(),layout[i-1]-layout[i]); + rectItem->setRect(chartRect.left(),layout[i],chartRect.width(),layout[i-1]-layout[i]); } // grid lines and axis line ticks QGraphicsLineItem *lineItem = static_cast(lines.at(i)); - lineItem->setPos(m_rect.left(), layout[i]); - lineItem->setLine(0, 0, m_rect.width(), 0); + lineItem->setPos(chartRect.left(), layout[i]); + lineItem->setLine(0, 0, chartRect.width(), 0); QGraphicsLineItem *tickLineItem = static_cast(axis.at(i+1)); - tickLineItem->setPos(m_rect.left(), layout[i]); + tickLineItem->setPos(chartRect.left(), layout[i]); tickLineItem->setLine(-5, 0, 0, 0); // check if the grid line and the axis tick should be shown - if (lineItem->pos().y() < m_rect.top() || lineItem->pos().y() > m_rect.bottom()) { + if (lineItem->pos().y() < chartRect.top() || lineItem->pos().y() > chartRect.bottom()) { lineItem->setVisible(false); tickLineItem->setVisible(false); } else { lineItem->setVisible(true); tickLineItem->setVisible(true); } + } } @@ -158,4 +159,43 @@ void ChartCategoryAxisY::handleAxisUpdated() ChartAxis::handleAxisUpdated(); } +QSizeF ChartCategoryAxisY::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const +{ + Q_UNUSED(constraint) + + QFontMetrics fn(m_font); + QSizeF sh; + QSizeF base = ChartAxis::sizeHint(which, constraint); + QStringList ticksList; //TODO:: + qreal width=0; + qreal height=0; + + switch (which) { + case Qt::MinimumSize: + width = fn.boundingRect("...").width()+label_padding; + height = fn.height(); + width=qMax(width,base.width()); + height+=base.height(); + sh = QSizeF(width,height); + break; + case Qt::PreferredSize:{ + + for (int i = 0; i < ticksList.size(); ++i) + { + QRectF rect = fn.boundingRect(ticksList.at(i)); + height+=rect.height(); + width=qMax(rect.width()+label_padding,width); + } + height=qMax(height,base.height()); + width+=base.width(); + sh = QSizeF(width,height); + break; + } + default: + break; + } + + return sh; +} + QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/axis/categoryaxis/chartcategoryaxisy_p.h b/src/axis/categoryaxis/chartcategoryaxisy_p.h index 9c3186c2..41970b92 100644 --- a/src/axis/categoryaxis/chartcategoryaxisy_p.h +++ b/src/axis/categoryaxis/chartcategoryaxisy_p.h @@ -44,7 +44,7 @@ public: ~ChartCategoryAxisY(); AxisType axisType() const { return Y_AXIS;} - + QSizeF sizeHint(Qt::SizeHint which, const QSizeF& constraint) const; protected: QVector calculateLayout() const; void updateGeometry(); diff --git a/src/axis/chartaxis.cpp b/src/axis/chartaxis.cpp index cdf79be5..7018ac66 100644 --- a/src/axis/chartaxis.cpp +++ b/src/axis/chartaxis.cpp @@ -27,6 +27,7 @@ #include #include #include +#include QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -37,11 +38,10 @@ ChartAxis::ChartAxis(QAbstractAxis *axis,ChartPresenter *presenter) : ChartEleme m_shades(new QGraphicsItemGroup(presenter->rootItem())), m_labels(new QGraphicsItemGroup(presenter->rootItem())), m_arrow(new QGraphicsItemGroup(presenter->rootItem())), + m_title(new QGraphicsSimpleTextItem(presenter->rootItem())), m_min(0), m_max(0), - m_animation(0), - m_minWidth(0), - m_minHeight(0) + m_animation(0) { //initial initialization m_arrow->setZValue(ChartPresenter::AxisZValue); @@ -139,7 +139,6 @@ void ChartAxis::updateLayout(QVector &layout) else { setLayout(layout); updateGeometry(); - checkLayout(); } } @@ -231,7 +230,15 @@ void ChartAxis::setLabelsFont(const QFont &font) foreach(QGraphicsItem* item , m_labels->childItems()) { static_cast(item)->setFont(font); } - m_font = font; + if(m_font!=font) { + m_font = font; + foreach(QGraphicsItem* item , m_labels->childItems()) { + static_cast(item)->setFont(font); + } + QGraphicsLayoutItem::updateGeometry(); + presenter()->layout()->invalidate(); + + } } void ChartAxis::setShadesBrush(const QBrush &brush) @@ -264,7 +271,7 @@ void ChartAxis::setGridPen(const QPen &pen) bool ChartAxis::isEmpty() { - return m_rect.isEmpty() || qFuzzyIsNull(m_min - m_max); + return !m_rect.isValid() || presenter()->chartsGeometry().isEmpty() || qFuzzyIsNull(m_min - m_max); } void ChartAxis::handleDomainUpdated() @@ -289,8 +296,20 @@ void ChartAxis::handleDomainUpdated() m_max = max; if (!isEmpty()) { + QVector layout = calculateLayout(); updateLayout(layout); + QSizeF before = effectiveSizeHint(Qt::MinimumSize); + + QSizeF after= sizeHint(Qt::MinimumSize); + + 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()); + } } } } @@ -314,7 +333,17 @@ void ChartAxis::handleAxisUpdated() setGridPen(m_chartAxis->gridLinePen()); setShadesPen(m_chartAxis->shadesPen()); setShadesBrush(m_chartAxis->shadesBrush()); + setTitleText(m_chartAxis->title()); +} +void ChartAxis::setTitleText(const QString& title) +{ + if(m_titleText!=title) { + m_titleText = title; + m_rect = QRect(); + QGraphicsLayoutItem::updateGeometry(); + presenter()->layout()->invalidate(); + } } void ChartAxis::hide() @@ -325,42 +354,64 @@ void ChartAxis::hide() setShadesVisibility(false); } -void ChartAxis::handleGeometryChanged(const QRectF &rect) +void ChartAxis::setGeometry(const QRectF &rect) { - if(m_rect != rect) - { + m_rect = rect; + if (isEmpty()) return; + + if(!m_titleText.isNull()) { + QFontMetrics fn(m_title->font()); + + int size(0); + + QRectF chartRect = presenter()->chartsGeometry(); + + if(orientation()==Qt::Horizontal) + size = chartRect.width(); + else if(orientation()==Qt::Vertical) + size = chartRect.height(); + + if (fn.boundingRect(m_titleText).width() > size) + { + QString string = m_titleText + "..."; + while (fn.boundingRect(string).width() > size && string.length() > 3) + string.remove(string.length() - 4, 1); + m_title->setText(string); + } + else + m_title->setText(m_titleText); + + QPointF center = chartRect.center() - m_title->boundingRect().center(); + if(orientation()==Qt::Horizontal) { + m_title->setPos(center.x(),m_rect.bottom()-m_title->boundingRect().height()); + } + else if(orientation()==Qt::Vertical) { + m_title->setTransformOriginPoint(m_title->boundingRect().center()); + m_title->setRotation(270); + m_title->setPos(m_rect.left()- m_title->boundingRect().width()/2+m_title->boundingRect().height()/2,center.y()); + } + } + QVector layout = calculateLayout(); updateLayout(layout); - } -} - -qreal ChartAxis::minimumWidth() -{ - if(m_minWidth == 0) updateGeometry(); - return m_minWidth; } -qreal ChartAxis::minimumHeight() -{ - if(m_minHeight == 0) updateGeometry(); - return m_minHeight; -} - - void ChartAxis::axisSelected() { - qDebug()<<"TODO: axis clicked"; + //TODO: axis clicked; } -void ChartAxis::createNumberLabels(QStringList &labels,qreal min, qreal max, int ticks) const +QStringList ChartAxis::createNumberLabels(qreal min, qreal max, int ticks) const { Q_ASSERT(max>min); Q_ASSERT(ticks>1); + QStringList labels; + int n = qMax(int(-qFloor(log10((max-min)/(ticks-1)))),0); n++; @@ -381,17 +432,54 @@ void ChartAxis::createNumberLabels(QStringList &labels,qreal min, qreal max, int labels << QString().sprintf(array, value); } } + + return labels; } -void ChartAxis::checkLayout() +Qt::Orientation ChartAxis::orientation() const { - if(m_minWidth > m_rect.width()) { - presenter()->layout()->invalidate(); - } + return m_chartAxis->orientation(); +} - if(m_minHeight > m_rect.height()) { - presenter()->layout()->invalidate(); +bool ChartAxis::isVisible() +{ + return m_chartAxis->isVisible(); +} + +QSizeF ChartAxis::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const +{ + + Q_UNUSED(constraint); + QFontMetrics fn(m_title->font()); + QSizeF sh; + + if(m_titleText.isNull()) return sh; + + switch(which) { + case Qt::MinimumSize: + if(orientation()==Qt::Horizontal) { + sh = QSizeF(fn.boundingRect ("...").width(),fn.height()); + } + else if(orientation()==Qt::Vertical) { + sh = QSizeF(fn.height(),fn.boundingRect ("...").width()); + } + + break; + case Qt::MaximumSize: + case Qt::PreferredSize: + if(orientation()==Qt::Horizontal) { + sh = QSizeF(fn.boundingRect(m_chartAxis->title()).width(),fn.height()); + } + else if(orientation()==Qt::Vertical) { + sh = QSizeF(fn.height(),fn.boundingRect(m_chartAxis->title()).width()); + } + + break; + default: + break; } + + return sh; } #include "moc_chartaxis_p.cpp" diff --git a/src/axis/chartaxis_p.h b/src/axis/chartaxis_p.h index 389e6540..acfc127a 100644 --- a/src/axis/chartaxis_p.h +++ b/src/axis/chartaxis_p.h @@ -34,6 +34,7 @@ #include "chartelement_p.h" #include "axisanimation_p.h" #include +#include #include QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -41,9 +42,10 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE class QAbstractAxis; class ChartPresenter; -class ChartAxis : public ChartElement +class ChartAxis : public ChartElement, public QGraphicsLayoutItem { Q_OBJECT + Q_INTERFACES(QGraphicsLayoutItem) public: enum AxisType{ X_AXIS,Y_AXIS }; @@ -81,29 +83,38 @@ public: void setLabelsBrush(const QBrush &brush); void setLabelsFont(const QFont &font); + void setTitlePen(const QPen &pen); + void setTitleBrush(const QBrush &brush); + void setTitleFont(const QFont &font); + void setTitleText(const QString& title); + + void setLayout(QVector &layout); QVector layout() const { return m_layoutVector; } void setAnimation(AxisAnimation* animation); ChartAnimation* animation() const { return m_animation; }; - QRectF geometry() const { return m_rect; } - - qreal minimumWidth(); - qreal minimumHeight(); + Qt::Orientation orientation() const; + bool isVisible(); void hide(); + void setGeometry(const QRectF &size); + QRectF geometry() const { return m_rect; } + + virtual QSizeF sizeHint(Qt::SizeHint which, const QSizeF& constraint = QSizeF()) const; + protected: virtual void updateGeometry() = 0; virtual QVector calculateLayout() const = 0; - void createNumberLabels(QStringList &labels,qreal min, qreal max,int ticks) const; - void checkLayout(); + QStringList createNumberLabels(qreal min, qreal max,int ticks) const; + public Q_SLOTS: virtual void handleAxisUpdated(); virtual void handleDomainUpdated(); - void handleGeometryChanged(const QRectF &size); + private: inline bool isEmpty(); @@ -114,19 +125,20 @@ private: protected: QAbstractAxis* m_chartAxis; - QRectF m_rect; int m_labelsAngle; + //TODO: to be removed + QRectF m_rect; QScopedPointer m_grid; QScopedPointer m_shades; QScopedPointer m_labels; QScopedPointer m_arrow; + QGraphicsSimpleTextItem* m_title; QVector m_layoutVector; qreal m_min; qreal m_max; AxisAnimation *m_animation; - qreal m_minWidth; - qreal m_minHeight; QFont m_font; + QString m_titleText; friend class AxisAnimation; friend class AxisItem; diff --git a/src/axis/datetimeaxis/chartdatetimeaxisx.cpp b/src/axis/datetimeaxis/chartdatetimeaxisx.cpp index a7329512..a6e441e5 100644 --- a/src/axis/datetimeaxis/chartdatetimeaxisx.cpp +++ b/src/axis/datetimeaxis/chartdatetimeaxisx.cpp @@ -61,10 +61,10 @@ QVector ChartDateTimeAxisX::calculateLayout() const QVector points; points.resize(m_tickCount); - - const qreal deltaX = m_rect.width()/(m_tickCount-1); + QRectF rect = presenter()->chartsGeometry(); + const qreal deltaX = rect.width()/(m_tickCount-1); for (int i = 0; i < m_tickCount; ++i) { - int x = i * deltaX + m_rect.left(); + int x = i * deltaX + rect.left(); points[i] = x; } return points; @@ -74,9 +74,6 @@ void ChartDateTimeAxisX::updateGeometry() { const QVector& layout = ChartAxis::layout(); - m_minWidth = 0; - m_minHeight = 0; - if(layout.isEmpty()) return; QStringList ticksList; @@ -91,19 +88,21 @@ void ChartDateTimeAxisX::updateGeometry() Q_ASSERT(labels.size() == ticksList.size()); Q_ASSERT(layout.size() == ticksList.size()); + QRectF chartRect = presenter()->chartsGeometry(); + QGraphicsLineItem *lineItem = static_cast(axis.at(0)); - lineItem->setLine(m_rect.left(), m_rect.bottom(), m_rect.right(), m_rect.bottom()); + lineItem->setLine(chartRect.left(), chartRect.bottom(), chartRect.right(), chartRect.bottom()); qreal width = 0; for (int i = 0; i < layout.size(); ++i) { QGraphicsLineItem *lineItem = static_cast(lines.at(i)); - lineItem->setLine(layout[i], m_rect.top(), layout[i], m_rect.bottom()); + lineItem->setLine(layout[i], chartRect.top(), layout[i], chartRect.bottom()); QGraphicsSimpleTextItem *labelItem = static_cast(labels.at(i)); labelItem->setText(ticksList.at(i)); const QRectF& rect = labelItem->boundingRect(); QPointF center = rect.center(); labelItem->setTransformOriginPoint(center.x(), center.y()); - labelItem->setPos(layout[i] - center.x(), m_rect.bottom() + label_padding); + labelItem->setPos(layout[i] - center.x(), chartRect.bottom() + label_padding); if(labelItem->pos().x()<=width){ labelItem->setVisible(false); @@ -113,15 +112,13 @@ void ChartDateTimeAxisX::updateGeometry() lineItem->setVisible(true); width=rect.width()+labelItem->pos().x(); } - m_minWidth+=rect.width(); - m_minHeight=qMax(rect.height(),m_minHeight); if ((i+1)%2 && i>1) { QGraphicsRectItem *rectItem = static_cast(shades.at(i/2-1)); - rectItem->setRect(layout[i-1],m_rect.top(),layout[i]-layout[i-1],m_rect.height()); + rectItem->setRect(layout[i-1],chartRect.top(),layout[i]-layout[i-1],chartRect.height()); } lineItem = static_cast(axis.at(i+1)); - lineItem->setLine(layout[i],m_rect.bottom(),layout[i],m_rect.bottom()+5); + lineItem->setLine(layout[i],chartRect.bottom(),layout[i],chartRect.bottom()+5); } } @@ -133,4 +130,41 @@ void ChartDateTimeAxisX::handleAxisUpdated() ChartAxis::handleAxisUpdated(); } +QSizeF ChartDateTimeAxisX::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const +{ + Q_UNUSED(constraint) + + QFontMetrics fn(m_font); + QSizeF sh; + + switch (which) { + case Qt::MinimumSize: + sh = QSizeF(fn.boundingRect("...").width(),fn.height()); + break; + case Qt::PreferredSize:{ + + const QVector& layout = ChartAxis::layout(); + if(layout.isEmpty()) break; + QStringList ticksList; + + + qreal width=0; + qreal height=0; + + for (int i = 0; i < ticksList.size(); ++i) + { + QRectF rect = fn.boundingRect(ticksList.at(i)); + width+=rect.width(); + height+=qMax(rect.height()+label_padding,height); + } + sh = QSizeF(width,height); + break; + } + default: + break; + } + + return sh; +} + QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/axis/datetimeaxis/chartdatetimeaxisx_p.h b/src/axis/datetimeaxis/chartdatetimeaxisx_p.h index aeb78daa..0e4f170f 100644 --- a/src/axis/datetimeaxis/chartdatetimeaxisx_p.h +++ b/src/axis/datetimeaxis/chartdatetimeaxisx_p.h @@ -44,7 +44,7 @@ public: ~ChartDateTimeAxisX(); AxisType axisType() const { return X_AXIS;} - + QSizeF sizeHint(Qt::SizeHint which, const QSizeF& constraint) const; protected: void createLabels(QStringList &labels,qreal min, qreal max, int ticks); void handleAxisUpdated(); diff --git a/src/axis/datetimeaxis/chartdatetimeaxisy.cpp b/src/axis/datetimeaxis/chartdatetimeaxisy.cpp index 07fc0ddc..d92efcc0 100644 --- a/src/axis/datetimeaxis/chartdatetimeaxisy.cpp +++ b/src/axis/datetimeaxis/chartdatetimeaxisy.cpp @@ -61,10 +61,10 @@ QVector ChartDateTimeAxisY::calculateLayout() const QVector points; points.resize(m_tickCount); - - const qreal deltaY = m_rect.height()/(m_tickCount-1); + QRectF rect = presenter()->chartsGeometry(); + const qreal deltaY = rect.height()/(m_tickCount-1); for (int i = 0; i < m_tickCount; ++i) { - int y = i * -deltaY + m_rect.bottom(); + int y = i * -deltaY + rect.bottom(); points[i] = y; } @@ -74,8 +74,6 @@ QVector ChartDateTimeAxisY::calculateLayout() const void ChartDateTimeAxisY::updateGeometry() { const QVector &layout = ChartAxis::layout(); - m_minWidth = 0; - m_minHeight = 0; if(layout.isEmpty()) return; @@ -91,14 +89,16 @@ void ChartDateTimeAxisY::updateGeometry() Q_ASSERT(labels.size() == ticksList.size()); Q_ASSERT(layout.size() == ticksList.size()); - qreal height = 2*m_rect.bottom(); + QRectF chartRect = presenter()->chartsGeometry(); + + qreal height = chartRect.bottom(); QGraphicsLineItem *lineItem = static_cast(axis.at(0)); - lineItem->setLine(m_rect.left() , m_rect.top(), m_rect.left(), m_rect.bottom()); + lineItem->setLine(chartRect.left() , chartRect.top(), chartRect.left(), chartRect.bottom()); for (int i = 0; i < layout.size(); ++i) { QGraphicsLineItem *lineItem = static_cast(lines.at(i)); - lineItem->setLine(m_rect.left() , layout[i], m_rect.right(), layout[i]); + lineItem->setLine(chartRect.left() , layout[i], chartRect.right(), layout[i]); QGraphicsSimpleTextItem *labelItem = static_cast(labels.at(i)); labelItem->setText(ticksList.at(i)); @@ -106,7 +106,7 @@ void ChartDateTimeAxisY::updateGeometry() QPointF center = rect.center(); labelItem->setTransformOriginPoint(center.x(), center.y()); - labelItem->setPos(m_rect.left() - rect.width() - label_padding , layout[i]-center.y()); + labelItem->setPos(chartRect.left() - rect.width() - label_padding , layout[i]-center.y()); if(labelItem->pos().y()+rect.height()>height) { labelItem->setVisible(false); @@ -118,15 +118,12 @@ void ChartDateTimeAxisY::updateGeometry() height=labelItem->pos().y(); } - m_minWidth=qMax(rect.width()+label_padding,m_minWidth); - m_minHeight+=rect.height(); - if ((i+1)%2 && i>1) { QGraphicsRectItem *rectItem = static_cast(shades.at(i/2-1)); - rectItem->setRect(m_rect.left(),layout[i],m_rect.width(),layout[i-1]-layout[i]); + rectItem->setRect(chartRect.left(),layout[i],chartRect.width(),layout[i-1]-layout[i]); } lineItem = static_cast(axis.at(i+1)); - lineItem->setLine(m_rect.left()-5,layout[i],m_rect.left(),layout[i]); + lineItem->setLine(chartRect.left()-5,layout[i],chartRect.left(),layout[i]); } } @@ -138,5 +135,41 @@ void ChartDateTimeAxisY::handleAxisUpdated() ChartAxis::handleAxisUpdated(); } +QSizeF ChartDateTimeAxisY::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const +{ + Q_UNUSED(constraint) + + QFontMetrics fn(m_font); + QSizeF sh; + + switch (which) { + case Qt::MinimumSize: + sh = QSizeF(fn.boundingRect("...").width(),fn.height()); + break; + case Qt::PreferredSize:{ + + const QVector& layout = ChartAxis::layout(); + if(layout.isEmpty()) break; + QStringList ticksList; + + + qreal width=0; + qreal height=0; + + for (int i = 0; i < ticksList.size(); ++i) + { + QRectF rect = fn.boundingRect(ticksList.at(i)); + width+=rect.width(); + height+=qMax(rect.height()+label_padding,height); + } + sh = QSizeF(width,height); + break; + } + default: + break; + } + + return sh; +} QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/axis/datetimeaxis/chartdatetimeaxisy_p.h b/src/axis/datetimeaxis/chartdatetimeaxisy_p.h index 2c116887..4e3d5944 100644 --- a/src/axis/datetimeaxis/chartdatetimeaxisy_p.h +++ b/src/axis/datetimeaxis/chartdatetimeaxisy_p.h @@ -44,7 +44,7 @@ public: ~ChartDateTimeAxisY(); AxisType axisType() const { return Y_AXIS;} - + QSizeF sizeHint(Qt::SizeHint which, const QSizeF& constraint) const; protected: void createLabels(QStringList &labels,qreal min, qreal max, int ticks); QVector calculateLayout() const; diff --git a/src/axis/qabstractaxis.cpp b/src/axis/qabstractaxis.cpp index b1107890..b098af62 100644 --- a/src/axis/qabstractaxis.cpp +++ b/src/axis/qabstractaxis.cpp @@ -458,6 +458,90 @@ QColor QAbstractAxis::labelsColor() const return d_ptr->m_labelsBrush.color(); } +void QAbstractAxis::setTitleVisible(bool visible) +{ + if (d_ptr->m_titleVisible != visible) { + d_ptr->m_titleVisible = visible; + d_ptr->emitUpdated(); + } +} + +bool QAbstractAxis::titleVisible() const +{ + return d_ptr->m_titleVisible; +} + +/*! + Sets \a pen used to draw title. +*/ +void QAbstractAxis::setTitlePen(const QPen &pen) +{ + if (d_ptr->m_titlePen != pen) { + d_ptr->m_titlePen = pen; + d_ptr->emitUpdated(); + } +} + +/*! + Returns the pen used to title. +*/ +QPen QAbstractAxis::titlePen() const +{ + 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; + d_ptr->emitUpdated(); + } +} + +/*! + Returns brush used to draw title. +*/ +QBrush QAbstractAxis::titleBrush() const +{ + 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; + d_ptr->emitUpdated(); + } +} + +/*! + Returns font used to draw title. +*/ +QFont QAbstractAxis::titleFont() const +{ + return d_ptr->m_titleFont; +} + +void QAbstractAxis::setTitle(const QString& title) +{ + if (d_ptr->m_title != title) { + d_ptr->m_title = title; + d_ptr->emitUpdated(); + } +} + +QString QAbstractAxis::title() const +{ + return d_ptr->m_title; +} + + void QAbstractAxis::setShadesVisible(bool visible) { if (d_ptr->m_shadesVisible != visible) { diff --git a/src/axis/qabstractaxis.h b/src/axis/qabstractaxis.h index afe1629f..f03376c7 100644 --- a/src/axis/qabstractaxis.h +++ b/src/axis/qabstractaxis.h @@ -98,6 +98,19 @@ public: void setLabelsColor(QColor color); QColor labelsColor() const; + //title handling + bool titleVisible() 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 setTitle(const QString& title); + QString title() const; + + //shades handling bool shadesVisible() const; void setShadesVisible(bool visible = true); diff --git a/src/axis/qabstractaxis_p.h b/src/axis/qabstractaxis_p.h index 7860f7c9..b8df5e98 100644 --- a/src/axis/qabstractaxis_p.h +++ b/src/axis/qabstractaxis_p.h @@ -94,6 +94,12 @@ private: 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; diff --git a/src/axis/valueaxis/chartvalueaxisx.cpp b/src/axis/valueaxis/chartvalueaxisx.cpp index c7ebe965..040b388f 100644 --- a/src/axis/valueaxis/chartvalueaxisx.cpp +++ b/src/axis/valueaxis/chartvalueaxisx.cpp @@ -25,6 +25,7 @@ #include #include #include +#include static int label_padding = 5; @@ -46,9 +47,11 @@ QVector ChartValueAxisX::calculateLayout() const QVector points; points.resize(m_tickCount); - const qreal deltaX = m_rect.width()/(m_tickCount-1); + QRectF rect = presenter()->chartsGeometry(); + + const qreal deltaX = rect.width()/(m_tickCount-1); for (int i = 0; i < m_tickCount; ++i) { - int x = i * deltaX + m_rect.left(); + int x = i * deltaX + rect.left(); points[i] = x; } return points; @@ -58,14 +61,9 @@ void ChartValueAxisX::updateGeometry() { const QVector& layout = ChartAxis::layout(); - m_minWidth = 0; - m_minHeight = 0; - if(layout.isEmpty()) return; - QStringList ticksList; - - createNumberLabels(ticksList,m_min,m_max,layout.size()); + QStringList ticksList = createNumberLabels(m_min,m_max,layout.size()); QList lines = m_grid->childItems(); QList labels = m_labels->childItems(); @@ -75,21 +73,24 @@ void ChartValueAxisX::updateGeometry() Q_ASSERT(labels.size() == ticksList.size()); Q_ASSERT(layout.size() == ticksList.size()); + QRectF chartRrect = presenter()->chartsGeometry(); + QGraphicsLineItem *lineItem = static_cast(axis.at(0)); - lineItem->setLine(m_rect.left(), m_rect.bottom(), m_rect.right(), m_rect.bottom()); + lineItem->setLine(chartRrect.left(), chartRrect.bottom(), chartRrect.right(), chartRrect.bottom()); qreal width = 0; for (int i = 0; i < layout.size(); ++i) { QGraphicsLineItem *lineItem = static_cast(lines.at(i)); - lineItem->setLine(layout[i], m_rect.top(), layout[i], m_rect.bottom()); + lineItem->setLine(layout[i], chartRrect.top(), layout[i], chartRrect.bottom()); QGraphicsSimpleTextItem *labelItem = static_cast(labels.at(i)); labelItem->setText(ticksList.at(i)); const QRectF& rect = labelItem->boundingRect(); QPointF center = rect.center(); labelItem->setTransformOriginPoint(center.x(), center.y()); - labelItem->setPos(layout[i] - center.x(), m_rect.bottom() + label_padding); - - if(labelItem->pos().x()<=width){ + labelItem->setPos(layout[i] - center.x(), chartRrect.bottom() + label_padding); + if(labelItem->pos().x() <= width || + labelItem->pos().x() < m_rect.left() || + labelItem->pos().x() + rect.width() > m_rect.right()){ labelItem->setVisible(false); lineItem->setVisible(false); }else{ @@ -97,17 +98,14 @@ void ChartValueAxisX::updateGeometry() lineItem->setVisible(true); width=rect.width()+labelItem->pos().x(); } - m_minWidth+=rect.width(); - m_minHeight=qMax(rect.height(),m_minHeight); if ((i+1)%2 && i>1) { QGraphicsRectItem *rectItem = static_cast(shades.at(i/2-1)); - rectItem->setRect(layout[i-1],m_rect.top(),layout[i]-layout[i-1],m_rect.height()); + rectItem->setRect(layout[i-1],chartRrect.top(),layout[i]-layout[i-1],chartRrect.height()); } lineItem = static_cast(axis.at(i+1)); - lineItem->setLine(layout[i],m_rect.bottom(),layout[i],m_rect.bottom()+5); + lineItem->setLine(layout[i],chartRrect.bottom(),layout[i],chartRrect.bottom()+5); } - } void ChartValueAxisX::handleAxisUpdated() @@ -118,4 +116,45 @@ void ChartValueAxisX::handleAxisUpdated() ChartAxis::handleAxisUpdated(); } +QSizeF ChartValueAxisX::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const +{ + Q_UNUSED(constraint) + + QFontMetrics fn(m_font); + QSizeF sh; + + QSizeF base = ChartAxis::sizeHint(which, constraint); + QStringList ticksList = createNumberLabels(m_min,m_max,m_tickCount); + qreal width=0; + qreal height=0; + + switch (which) { + case Qt::MinimumSize:{ + int count = qMax(ticksList.last().count(),ticksList.first().count()); + width=fn.averageCharWidth()*count; + height=fn.height()+label_padding; + width=qMax(width,base.width()); + height+=base.height(); + sh = QSizeF(width,height); + break; + } + case Qt::PreferredSize:{ + for (int i = 0; i < ticksList.size(); ++i) + { + width+=fn.averageCharWidth()*ticksList.at(i).count(); + + } + height=fn.height()+label_padding; + width=qMax(width,base.width()); + height+=base.height(); + sh = QSizeF(width,height); + break; + } + default: + break; + } + + return sh; +} + QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/axis/valueaxis/chartvalueaxisx_p.h b/src/axis/valueaxis/chartvalueaxisx_p.h index bf7a9cce..da48637c 100644 --- a/src/axis/valueaxis/chartvalueaxisx_p.h +++ b/src/axis/valueaxis/chartvalueaxisx_p.h @@ -44,7 +44,7 @@ public: ~ChartValueAxisX(); AxisType axisType() const { return X_AXIS;} - + QSizeF sizeHint(Qt::SizeHint which, const QSizeF& constraint) const; protected: void handleAxisUpdated(); QVector calculateLayout() const; diff --git a/src/axis/valueaxis/chartvalueaxisy.cpp b/src/axis/valueaxis/chartvalueaxisy.cpp index ea50eb36..5199b67b 100644 --- a/src/axis/valueaxis/chartvalueaxisy.cpp +++ b/src/axis/valueaxis/chartvalueaxisy.cpp @@ -25,6 +25,7 @@ #include #include #include +#include static int label_padding = 5; @@ -46,9 +47,11 @@ QVector ChartValueAxisY::calculateLayout() const QVector points; points.resize(m_tickCount); - const qreal deltaY = m_rect.height()/(m_tickCount-1); + QRectF rect = presenter()->chartsGeometry(); + + const qreal deltaY = rect.height()/(m_tickCount-1); for (int i = 0; i < m_tickCount; ++i) { - int y = i * -deltaY + m_rect.bottom(); + int y = i * -deltaY + rect.bottom(); points[i] = y; } @@ -58,14 +61,10 @@ QVector ChartValueAxisY::calculateLayout() const void ChartValueAxisY::updateGeometry() { const QVector &layout = ChartAxis::layout(); - m_minWidth = 0; - m_minHeight = 0; if(layout.isEmpty()) return; - QStringList ticksList; - - createNumberLabels(ticksList,m_min,m_max,layout.size()); + QStringList ticksList = createNumberLabels(m_min,m_max,layout.size()); QList lines = m_grid->childItems(); QList labels = m_labels->childItems(); @@ -75,44 +74,55 @@ void ChartValueAxisY::updateGeometry() Q_ASSERT(labels.size() == ticksList.size()); Q_ASSERT(layout.size() == ticksList.size()); - qreal height = 2*m_rect.bottom(); + QRectF chartRect = presenter()->chartsGeometry(); + + qreal height = m_rect.bottom(); QGraphicsLineItem *lineItem = static_cast(axis.at(0)); - lineItem->setLine(m_rect.left() , m_rect.top(), m_rect.left(), m_rect.bottom()); + lineItem->setLine( chartRect.left() , chartRect.top(), chartRect.left(), chartRect.bottom()); + + QFontMetrics fn(m_font); for (int i = 0; i < layout.size(); ++i) { QGraphicsLineItem *lineItem = static_cast(lines.at(i)); - lineItem->setLine(m_rect.left() , layout[i], m_rect.right(), layout[i]); + lineItem->setLine( chartRect.left() , layout[i], chartRect.right(), layout[i]); QGraphicsSimpleTextItem *labelItem = static_cast(labels.at(i)); - labelItem->setText(ticksList.at(i)); + QString text = ticksList.at(i); + + if (fn.boundingRect(text).width() > chartRect.left() - m_rect.left() - label_padding ) + { + QString label = text + "..."; + while (fn.boundingRect(label).width() > chartRect.left() - m_rect.left() - label_padding && label.length() > 3) + label.remove(label.length() - 4, 1); + labelItem->setText(label); + }else{ + labelItem->setText(text); + } + const QRectF& rect = labelItem->boundingRect(); QPointF center = rect.center(); labelItem->setTransformOriginPoint(center.x(), center.y()); - labelItem->setPos(m_rect.left() - rect.width() - label_padding , layout[i]-center.y()); + labelItem->setPos( chartRect.left() - rect.width() - label_padding , layout[i]-center.y()); - if(labelItem->pos().y()+rect.height()>height) { + if(labelItem->pos().y() + rect.height() > height || + labelItem->pos().y() < m_rect.top()) { labelItem->setVisible(false); lineItem->setVisible(false); - } - else { + }else{ labelItem->setVisible(true); lineItem->setVisible(true); height=labelItem->pos().y(); } - m_minWidth=qMax(rect.width()+label_padding,m_minWidth); - m_minHeight+=rect.height(); - if ((i+1)%2 && i>1) { QGraphicsRectItem *rectItem = static_cast(shades.at(i/2-1)); - rectItem->setRect(m_rect.left(),layout[i],m_rect.width(),layout[i-1]-layout[i]); + rectItem->setRect( chartRect.left(),layout[i], chartRect.width(),layout[i-1]-layout[i]); } lineItem = static_cast(axis.at(i+1)); - lineItem->setLine(m_rect.left()-5,layout[i],m_rect.left(),layout[i]); + lineItem->setLine( chartRect.left()-5,layout[i], chartRect.left(),layout[i]); } - } void ChartValueAxisY::handleAxisUpdated() @@ -123,5 +133,43 @@ void ChartValueAxisY::handleAxisUpdated() ChartAxis::handleAxisUpdated(); } +QSizeF ChartValueAxisY::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const +{ + Q_UNUSED(constraint) + + QFontMetrics fn(m_font); + QSizeF sh; + QSizeF base = ChartAxis::sizeHint(which, constraint); + QStringList ticksList = createNumberLabels(m_min,m_max,m_tickCount); + qreal width=0; + qreal height=0; + + switch (which) { + case Qt::MinimumSize: { + int count = qMax(ticksList.first().count() , ticksList.last().count()); + width=fn.averageCharWidth()*count+label_padding; + height=fn.height(); + height=qMax(height,base.height()); + width+=base.width(); + sh = QSizeF(width,height); + break; + } + case Qt::PreferredSize: + { + for (int i = 0; i < ticksList.size(); ++i) + { + width=qMax(qreal(fn.averageCharWidth()*ticksList.at(i).count())+label_padding,width); + height+=fn.height(); + } + height=qMax(height,base.height()); + width+=base.width(); + sh = QSizeF(width,height); + break; + } + default: + break; + } + return sh; +} QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/axis/valueaxis/chartvalueaxisy_p.h b/src/axis/valueaxis/chartvalueaxisy_p.h index 46879541..1c099f74 100644 --- a/src/axis/valueaxis/chartvalueaxisy_p.h +++ b/src/axis/valueaxis/chartvalueaxisy_p.h @@ -44,7 +44,7 @@ public: ~ChartValueAxisY(); AxisType axisType() const { return Y_AXIS;} - + QSizeF sizeHint(Qt::SizeHint which, const QSizeF& constraint) const; protected: QVector calculateLayout() const; void updateGeometry(); diff --git a/src/chartbackground_p.h b/src/chartbackground_p.h index 7e97e36c..0a517530 100644 --- a/src/chartbackground_p.h +++ b/src/chartbackground_p.h @@ -50,7 +50,6 @@ public: protected: void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); - private: int roundness(qreal size) const; diff --git a/src/chartlayout.cpp b/src/chartlayout.cpp index 176a0a82..b145518f 100644 --- a/src/chartlayout.cpp +++ b/src/chartlayout.cpp @@ -22,17 +22,20 @@ #include "chartpresenter_p.h" #include "qlegend_p.h" #include "chartaxis_p.h" +#include "charttitle_p.h" +#include "chartbackground_p.h" +#include "layoutdebuger_p.h" +#include "legendmarker_p.h" #include QTCOMMERCIALCHART_BEGIN_NAMESPACE +static const qreal golden_ratio = 0.25; + ChartLayout::ChartLayout(ChartPresenter* presenter): m_presenter(presenter), -m_marginBig(60), -m_marginSmall(20), -m_marginTiny(10), -m_chartMargins(m_marginBig,m_marginBig,m_marginBig,m_marginBig), -m_intialized(false) +m_margins(20,20,20,20), +m_minChartRect(0,0,200,200) { } @@ -44,137 +47,213 @@ ChartLayout::~ChartLayout() void ChartLayout::setGeometry(const QRectF& rect) { + Q_ASSERT(rect.isValid()); - if (!rect.isValid()) return; + QList axes = m_presenter->axisItems(); + ChartTitle* title = m_presenter->titleElement(); + QLegend* legend = m_presenter->legend(); + ChartBackground* background = m_presenter->backgroundElement(); - QGraphicsLayout::setGeometry(rect); + QRectF contentGeometry = calculateBackgroundGeometry(rect,background); - if(!m_intialized){ - m_presenter->setGeometry(rect); - m_intialized=true; - } + contentGeometry = calculateContentGeometry(contentGeometry); - // check title size + if (title && title->isVisible()) { + contentGeometry = calculateTitleGeometry(contentGeometry,title); + } - QSize titleSize = QSize(0,0); + if (legend->isAttachedToChart() && legend->isVisible()) { + contentGeometry = calculateLegendGeometry(contentGeometry,legend); + } - if (m_presenter->titleItem()) { - titleSize= m_presenter->titleItem()->boundingRect().size().toSize(); + calculateChartGeometry(contentGeometry,axes); + + //TODO remove me +#ifdef SHOW_LAYOUT + LayoutDebuger* debuger = LayoutDebuger::instance(); + debuger->reset(); + debuger->setPen(QPen(Qt::red)); + debuger->add(backgroundGeometry,m_presenter->rootItem()); + debuger->add(titleGeometry,m_presenter->rootItem()); + debuger->add(legendGeometry ,m_presenter->rootItem()); + debuger->add(axisGeometry ,m_presenter->rootItem()); + debuger->add(geometry,m_presenter->rootItem()); + foreach(LegendMarker* marker,legend->d_ptr->markers()){ + debuger->add(marker->mapRectToScene(marker->boundingRect()),m_presenter->rootItem()); } +#endif + + QGraphicsLayout::setGeometry(rect); +} + +QRectF ChartLayout::calculateContentGeometry(const QRectF& geometry) const +{ + return geometry.adjusted(m_margins.left(),m_margins.top(),-m_margins.right(),-m_margins.bottom()); +} + +QRectF ChartLayout::calculateContentMinimum(const QRectF& minimum) const +{ + return minimum.adjusted(0,0,m_margins.left()+m_margins.right(),m_margins.top() + m_margins.bottom()); +} - qreal axisHeight = 0; - qreal axisWidth = 0; + +QRectF ChartLayout::calculateBackgroundGeometry(const QRectF& geometry,ChartBackground* background) const +{ + qreal left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + QRectF backgroundGeometry = geometry.adjusted(left,top,-right,-bottom); + if(background) background->setRect(backgroundGeometry); + return backgroundGeometry; +} + +QRectF ChartLayout::calculateBackgroundMinimum(const QRectF& minimum) const +{ + qreal left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + return minimum.adjusted(0,0,left + right,top+bottom); +} + +QRectF ChartLayout::calculateChartGeometry(const QRectF& geometry, const QList& axes) const +{ + + QSizeF vertical(0,0); + QSizeF horizontal(0,0); // check axis size + foreach(ChartAxis* axis , axes) { + if(axis->orientation()==Qt::Vertical && axis->isVisible()) { + vertical = vertical.expandedTo(axis->effectiveSizeHint(Qt::MinimumSize)); + } + else if(axis->orientation()==Qt::Horizontal && axis->isVisible()) { + horizontal = horizontal.expandedTo(axis->effectiveSizeHint(Qt::MinimumSize)); + } - foreach (ChartAxis* axis,m_presenter->axisItems()){ - if(axis->axisType() == ChartAxis::X_AXIS) - axisHeight = qMax(axis->minimumHeight(),axisHeight); - else - axisWidth = qMax(axis->minimumWidth(),axisWidth); } - QLegend* legend = m_presenter->legend(); - Q_ASSERT(legend); + qreal width = qMin(vertical.width(),geometry.width() * golden_ratio); - qreal titlePadding = m_chartMargins.top()/2; + QRectF rect = geometry.adjusted(width,vertical.height()/2,-horizontal.width()/2,-horizontal.height()); - QMargins chartMargins = m_chartMargins; + m_presenter->setChartsGeometry(rect); - //TODO multiple axis handling; - chartMargins.setLeft(qMax(m_chartMargins.left(),int(axisWidth + 2*m_marginTiny))); - chartMargins.setBottom(qMax(m_chartMargins.bottom(),int(axisHeight + 2* m_marginTiny))); + foreach(ChartAxis* axis , axes) { + axis->setGeometry(geometry); + } + return rect; +} - // recalculate legend position - if ((legend->isAttachedToChart() && legend->isVisible())) { +QRectF ChartLayout::calculateAxisMinimum(const QRectF& minimum, const QList& axes) const +{ + QSizeF vertical(0,0); + QSizeF horizontal(0,0); - // Reserve some space for legend - switch (legend->alignment()) { + // check axis size + foreach(ChartAxis* axis , axes) { + if(axis->orientation()==Qt::Vertical && axis->isVisible()){ + vertical = vertical.expandedTo(axis->effectiveSizeHint(Qt::MinimumSize)); + }else if(axis->orientation()==Qt::Horizontal && axis->isVisible()) { + horizontal = horizontal.expandedTo(axis->effectiveSizeHint(Qt::MinimumSize)); + } + } + return minimum.adjusted(0,0,horizontal.width()+vertical.width(),horizontal.height() + vertical.height()); +} - case Qt::AlignTop: { +QRectF ChartLayout::calculateLegendGeometry(const QRectF& geometry,QLegend* legend) const +{ + QSizeF size = legend->effectiveSizeHint(Qt::PreferredSize,QSizeF(-1,-1)); + QRectF legendRect; + QRectF result; - QSizeF legendSize = legend->effectiveSizeHint(Qt::PreferredSize,QSizeF(rect.width(),-1)); - int topMargin = 2*m_marginTiny + titleSize.height() + legendSize.height() + m_marginTiny; - chartMargins = QMargins(chartMargins.left(),topMargin,chartMargins.right(),chartMargins.bottom()); - m_legendMargins = QMargins(chartMargins.left(),topMargin - (legendSize.height() + m_marginTiny),chartMargins.right(),rect.height()-topMargin + m_marginTiny); - titlePadding = m_marginTiny + m_marginTiny; + switch (legend->alignment()) { + + case Qt::AlignTop: { + legendRect = QRectF(geometry.topLeft(),QSizeF(geometry.width(),size.height())); + result = geometry.adjusted(0,legendRect.height(),0,0); break; } case Qt::AlignBottom: { - QSizeF legendSize = legend->effectiveSizeHint(Qt::PreferredSize,QSizeF(rect.width(),-1)); - int bottomMargin = m_marginTiny + legendSize.height() + m_marginTiny + axisHeight; - chartMargins = QMargins(chartMargins.left(),chartMargins.top(),chartMargins.right(),bottomMargin); - m_legendMargins = QMargins(chartMargins.left(),rect.height()-bottomMargin + m_marginTiny + axisHeight,chartMargins.right(),m_marginTiny + m_marginSmall); - titlePadding = chartMargins.top()/2; + legendRect = QRectF(QPointF(geometry.left(),geometry.bottom()-size.height()),QSizeF(geometry.width(),size.height())); + result = geometry.adjusted(0,0,0,-legendRect.height()); break; } case Qt::AlignLeft: { - QSizeF legendSize = legend->effectiveSizeHint(Qt::PreferredSize,QSizeF(-1,rect.height())); - int leftPadding = m_marginTiny + legendSize.width() + m_marginTiny + axisWidth; - chartMargins = QMargins(leftPadding,chartMargins.top(),chartMargins.right(),chartMargins.bottom()); - m_legendMargins = QMargins(m_marginTiny + m_marginSmall,chartMargins.top(),rect.width()-leftPadding + m_marginTiny + axisWidth,chartMargins.bottom()); - titlePadding = chartMargins.top()/2; + qreal width = qMin(size.width(),geometry.width()*golden_ratio); + legendRect = QRectF(geometry.topLeft(),QSizeF(width,geometry.height())); + result = geometry.adjusted(width,0,0,0); break; } case Qt::AlignRight: { - QSizeF legendSize = legend->effectiveSizeHint(Qt::PreferredSize,QSizeF(-1,rect.height())); - int rightPadding = m_marginTiny + legendSize.width() + m_marginTiny; - chartMargins = QMargins(chartMargins.left(),chartMargins.top(),rightPadding,chartMargins.bottom()); - m_legendMargins = QMargins(rect.width()- rightPadding+ m_marginTiny ,chartMargins.top(),m_marginTiny + m_marginSmall,chartMargins.bottom()); - titlePadding = chartMargins.top()/2; + qreal width = qMin(size.width(),geometry.width()*golden_ratio); + legendRect = QRectF(QPointF(geometry.right()-width,geometry.top()),QSizeF(width,geometry.height())); + result = geometry.adjusted(0,0,-width,0); break; } default: { break; } - } - - legend->setGeometry(rect.adjusted(m_legendMargins.left(),m_legendMargins.top(),-m_legendMargins.right(),-m_legendMargins.bottom())); } - // recalculate title position - if (m_presenter->titleItem()) { - QPointF center = rect.center() - m_presenter->titleItem()->boundingRect().center(); - m_presenter->titleItem()->setPos(center.x(),titlePadding); - } + legend->setGeometry(legendRect); - //recalculate background gradient - if (m_presenter->backgroundItem()) { - m_presenter->backgroundItem()->setRect(rect.adjusted(m_marginTiny,m_marginTiny, -m_marginTiny, -m_marginTiny)); - } + return result; +} - QRectF chartRect = rect.adjusted(chartMargins.left(),chartMargins.top(),-chartMargins.right(),-chartMargins.bottom()); +QRectF ChartLayout::calculateLegendMinimum(const QRectF& geometry,QLegend* legend) const +{ + QSizeF minSize = legend->effectiveSizeHint(Qt::MinimumSize,QSizeF(-1,-1)); + return geometry.adjusted(0,0,minSize.width(),minSize.height()); +} - if(m_presenter->geometry()!=chartRect && chartRect.isValid()){ - m_presenter->setGeometry(chartRect); - }else if(chartRect.size().isEmpty()){ - m_presenter->setGeometry(QRect(rect.width()/2,rect.height()/2,1,1)); - } +QRectF ChartLayout::calculateTitleGeometry(const QRectF& geometry,ChartTitle* title) const +{ + title->setGeometry(geometry); + QPointF center = geometry.center() - title->boundingRect().center(); + title->setPos(center.x(),title->pos().y()); + return geometry.adjusted(0,title->boundingRect().height(),0,0); } +QRectF ChartLayout::calculateTitleMinimum(const QRectF& minimum,ChartTitle* title) const +{ + QSizeF min = title->sizeHint(Qt::MinimumSize); + return minimum.adjusted(0,0,min.width(),min.height()); +} QSizeF ChartLayout::sizeHint ( Qt::SizeHint which, const QSizeF & constraint) const { Q_UNUSED(constraint); - if(which == Qt::MinimumSize) - return QSize(2*(m_chartMargins.top()+m_chartMargins.bottom()),2*(m_chartMargins.top() + m_chartMargins.bottom())); - else + if(which == Qt::MinimumSize){ + QList axes = m_presenter->axisItems(); + ChartTitle* title = m_presenter->titleElement(); + QLegend* legend = m_presenter->legend(); + QRectF minimumRect(0,0,0,0); + minimumRect = calculateBackgroundMinimum(minimumRect); + minimumRect = calculateContentMinimum(minimumRect); + minimumRect = calculateTitleMinimum(minimumRect,title); + minimumRect = calculateLegendMinimum(minimumRect,legend); + minimumRect = calculateAxisMinimum(minimumRect,axes); + return minimumRect.united(m_minChartRect).size().toSize(); + }else return QSize(-1,-1); } -void ChartLayout::setMinimumMargins(const QMargins& margins) +void ChartLayout::setMargins(const QMargins& margins) { - if(m_chartMargins != margins){ - m_chartMargins = margins; + if(m_margins != margins){ + m_margins = margins; updateGeometry(); } } -QMargins ChartLayout::minimumMargins() const +QMargins ChartLayout::margins() const +{ + return m_margins; +} + +void ChartLayout::adjustChartGeometry() { - return m_chartMargins; + setGeometry(geometry()); } QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/chartlayout_p.h b/src/chartlayout_p.h index 0785d222..ff3c6349 100644 --- a/src/chartlayout_p.h +++ b/src/chartlayout_p.h @@ -27,6 +27,10 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE class ChartPresenter; +class ChartTitle; +class QLegend; +class ChartAxis; +class ChartBackground; class ChartLayout : public QGraphicsLayout { @@ -35,10 +39,11 @@ public: ChartLayout(ChartPresenter* presenter); virtual ~ChartLayout(); - void setMinimumMargins(const QMargins& margins); - QMargins minimumMargins() const; + void setMargins(const QMargins& margins); + QMargins margins() const; void setGeometry(const QRectF& rect); + void adjustChartGeometry(); protected: QSizeF sizeHint ( Qt::SizeHint which, const QSizeF & constraint = QSizeF() ) const; @@ -47,15 +52,22 @@ protected: void removeAt(int){}; private: - ChartPresenter* m_presenter; - int m_marginBig; - int m_marginSmall; - int m_marginTiny; - QMargins m_chartMargins; - QMargins m_legendMargins; - bool m_intialized; - + QRectF calculateBackgroundGeometry(const QRectF& geometry,ChartBackground* background) const; + QRectF calculateContentGeometry(const QRectF& geometry) const; + QRectF calculateTitleGeometry(const QRectF& geometry, ChartTitle* title) const; + QRectF calculateChartGeometry(const QRectF& geometry,const QList& axes) const; + QRectF calculateLegendGeometry(const QRectF& geometry, QLegend* legend) const; + QRectF calculateBackgroundMinimum(const QRectF& minimum) const; + QRectF calculateContentMinimum(const QRectF& minimum) const; + QRectF calculateTitleMinimum(const QRectF& minimum,ChartTitle* title) const; + QRectF calculateAxisMinimum(const QRectF& minimum,const QList& axes) const; + QRectF calculateLegendMinimum(const QRectF& minimum,QLegend* legend) const; +private: + ChartPresenter* m_presenter; + QMargins m_margins; + QRectF m_minChartRect; + QRectF m_minAxisRect; }; QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/chartpresenter.cpp b/src/chartpresenter.cpp index 3554b634..4e51b84d 100644 --- a/src/chartpresenter.cpp +++ b/src/chartpresenter.cpp @@ -28,11 +28,9 @@ #include "qabstractseries_p.h" #include "qareaseries.h" #include "chartaxis_p.h" -//#include "chartaxisx_p.h" -//#include "chartaxisy_p.h" -#include "areachartitem_p.h" #include "chartbackground_p.h" #include "chartlayout_p.h" +#include "charttitle_p.h" #include QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -44,8 +42,8 @@ m_chartTheme(0), m_options(QChart::NoAnimation), m_state(ShowState), m_layout(new ChartLayout(this)), -m_backgroundItem(0), -m_titleItem(0) +m_background(0), +m_title(0) { } @@ -55,17 +53,24 @@ ChartPresenter::~ChartPresenter() delete m_chartTheme; } -void ChartPresenter::setGeometry(const QRectF& rect) +void ChartPresenter::setChartsGeometry(const QRectF& rect) { - Q_ASSERT(rect.isValid()); - if(m_rect!=rect) { - m_rect=rect; - emit geometryChanged(m_rect); + if(m_chartsRect!=rect) { + m_chartsRect=rect; + foreach(ChartElement* chart, m_chartItems) + { + chart->handleGeometryChanged(rect); + } } } +QRectF ChartPresenter::chartsGeometry() const +{ + return m_chartsRect; +} + void ChartPresenter::handleAxisAdded(QAbstractAxis* axis,Domain* domain) { ChartAxis* item = axis->d_ptr->createGraphics(this); @@ -84,7 +89,7 @@ void ChartPresenter::handleAxisAdded(QAbstractAxis* axis,Domain* domain) m_chartTheme->decorate(axis); axis->d_ptr->setDirty(false); axis->d_ptr->emitUpdated(); - if(m_rect.isValid()) item->handleGeometryChanged(m_rect); + if(m_chartsRect.isValid()) item->handleGeometryChanged(m_chartsRect); m_axisItems.insert(axis, item); selectVisibleAxis(); @@ -113,7 +118,7 @@ void ChartPresenter::handleSeriesAdded(QAbstractSeries* series,Domain* domain) //initialize item->handleDomainUpdated(); - if(m_rect.isValid()) item->handleGeometryChanged(m_rect); + if(m_chartsRect.isValid()) item->handleGeometryChanged(m_chartsRect); m_chartItems.insert(series,item); } @@ -222,27 +227,29 @@ void ChartPresenter::resetAllElements() handleSeriesRemoved(series); handleSeriesAdded(series,domain); } + + layout()->invalidate(); } void ChartPresenter::zoomIn(qreal factor) { - QRectF rect = geometry(); + QRectF rect = chartsGeometry(); rect.setWidth(rect.width()/factor); rect.setHeight(rect.height()/factor); - rect.moveCenter(geometry().center()); + rect.moveCenter(chartsGeometry().center()); zoomIn(rect); } void ChartPresenter::zoomIn(const QRectF& rect) { QRectF r = rect.normalized(); - r.translate(-geometry().topLeft()); + r.translate(-chartsGeometry().topLeft()); if (!r.isValid()) return; m_state = ZoomInState; - m_statePoint = QPointF(r.center().x()/geometry().width(),r.center().y()/geometry().height()); - m_dataset->zoomInDomain(r,geometry().size()); + m_statePoint = QPointF(r.center().x()/chartsGeometry().width(),r.center().y()/chartsGeometry().height()); + m_dataset->zoomInDomain(r,chartsGeometry().size()); m_state = ShowState; } @@ -251,14 +258,14 @@ void ChartPresenter::zoomOut(qreal factor) m_state = ZoomOutState; QRectF chartRect; - chartRect.setSize(geometry().size()); + chartRect.setSize(chartsGeometry().size()); QRectF rect; rect.setSize(chartRect.size()/factor); rect.moveCenter(chartRect.center()); if (!rect.isValid()) return; - m_statePoint = QPointF(rect.center().x()/geometry().width(),rect.center().y()/geometry().height()); + m_statePoint = QPointF(rect.center().x()/chartsGeometry().width(),rect.center().y()/chartsGeometry().height()); m_dataset->zoomOutDomain(rect, chartRect.size()); m_state = ShowState; } @@ -270,7 +277,7 @@ void ChartPresenter::scroll(qreal dx,qreal dy) if(dy<0) m_state=ScrollUpState; if(dy>0) m_state=ScrollDownState; - m_dataset->scrollDomain(dx,dy,geometry().size()); + m_dataset->scrollDomain(dx,dy,chartsGeometry().size()); m_state = ShowState; } @@ -281,18 +288,18 @@ QChart::AnimationOptions ChartPresenter::animationOptions() const void ChartPresenter::createBackgroundItem() { - if (!m_backgroundItem) { - m_backgroundItem = new ChartBackground(rootItem()); - m_backgroundItem->setPen(Qt::NoPen); - m_backgroundItem->setZValue(ChartPresenter::BackgroundZValue); + if (!m_background) { + m_background = new ChartBackground(rootItem()); + m_background->setPen(Qt::NoPen); + m_background->setZValue(ChartPresenter::BackgroundZValue); } } void ChartPresenter::createTitleItem() { - if (!m_titleItem) { - m_titleItem = new QGraphicsSimpleTextItem(rootItem()); - m_titleItem->setZValue(ChartPresenter::BackgroundZValue); + if (!m_title) { + m_title = new ChartTitle(rootItem()); + m_title->setZValue(ChartPresenter::BackgroundZValue); } } @@ -313,104 +320,94 @@ void ChartPresenter::startAnimation(ChartAnimation* animation) QTimer::singleShot(0, animation, SLOT(start())); } -QGraphicsRectItem* ChartPresenter::backgroundItem() -{ - return m_backgroundItem; -} - void ChartPresenter::setBackgroundBrush(const QBrush& brush) { createBackgroundItem(); - m_backgroundItem->setBrush(brush); + m_background->setBrush(brush); m_layout->invalidate(); } QBrush ChartPresenter::backgroundBrush() const { - if (!m_backgroundItem) return QBrush(); - return m_backgroundItem->brush(); + if (!m_background) return QBrush(); + return m_background->brush(); } void ChartPresenter::setBackgroundPen(const QPen& pen) { createBackgroundItem(); - m_backgroundItem->setPen(pen); + m_background->setPen(pen); m_layout->invalidate(); } QPen ChartPresenter::backgroundPen() const { - if (!m_backgroundItem) return QPen(); - return m_backgroundItem->pen(); -} - -QGraphicsItem* ChartPresenter::titleItem() -{ - return m_titleItem; + if (!m_background) return QPen(); + return m_background->pen(); } void ChartPresenter::setTitle(const QString& title) { createTitleItem(); - m_titleItem->setText(title); + m_title->setText(title); m_layout->invalidate(); } QString ChartPresenter::title() const { - if (!m_titleItem) return QString(); - return m_titleItem->text(); + if (!m_title) return QString(); + return m_title->text(); } void ChartPresenter::setTitleFont(const QFont& font) { createTitleItem(); - m_titleItem->setFont(font); + m_title->setFont(font); m_layout->invalidate(); } QFont ChartPresenter::titleFont() const { - if (!m_titleItem) return QFont(); - return m_titleItem->font(); + if (!m_title) return QFont(); + return m_title->font(); } void ChartPresenter::setTitleBrush(const QBrush &brush) { createTitleItem(); - m_titleItem->setBrush(brush); + m_title->setBrush(brush); m_layout->invalidate(); } QBrush ChartPresenter::titleBrush() const { - if (!m_titleItem) return QBrush(); - return m_titleItem->brush(); + if (!m_title) return QBrush(); + return m_title->brush(); } void ChartPresenter::setBackgroundVisible(bool visible) { createBackgroundItem(); - m_backgroundItem->setVisible(visible); + m_background->setVisible(visible); } bool ChartPresenter::isBackgroundVisible() const { - if (!m_backgroundItem) return false; - return m_backgroundItem->isVisible(); + if (!m_background) return false; + return m_background->isVisible(); } void ChartPresenter::setBackgroundDropShadowEnabled(bool enabled) { createBackgroundItem(); - m_backgroundItem->setDropShadowEnabled(enabled); + m_background->setDropShadowEnabled(enabled); } bool ChartPresenter::isBackgroundDropShadowEnabled() const { - if (!m_backgroundItem) return false; - return m_backgroundItem->isDropShadowEnabled(); + if (!m_background) return false; + return m_background->isDropShadowEnabled(); } @@ -419,14 +416,14 @@ QGraphicsLayout* ChartPresenter::layout() return m_layout; } -void ChartPresenter::setMinimumMargins(const QMargins& margins) +void ChartPresenter::setMargins(const QMargins& margins) { - m_layout->setMinimumMargins(margins); + m_layout->setMargins(margins); } -QMargins ChartPresenter::minimumMargins() const +QMargins ChartPresenter::margins() const { - return m_layout->minimumMargins(); + return m_layout->margins(); } QLegend* ChartPresenter::legend() @@ -434,14 +431,24 @@ QLegend* ChartPresenter::legend() return m_chart->legend(); } +void ChartPresenter::setVisible(bool visible) +{ + m_chart->setVisible(visible); +} + +ChartBackground* ChartPresenter::backgroundElement() +{ + return m_background; +} + QList ChartPresenter::axisItems() const { return m_axisItems.values(); } -void ChartPresenter::setVisible(bool visible) +ChartTitle* ChartPresenter::titleElement() { - m_chart->setVisible(visible); + return m_title; } #include "moc_chartpresenter_p.cpp" diff --git a/src/chartpresenter_p.h b/src/chartpresenter_p.h index 7a78cfdb..a17264bd 100644 --- a/src/chartpresenter_p.h +++ b/src/chartpresenter_p.h @@ -45,6 +45,7 @@ class ChartAxis; class ChartTheme; class ChartAnimator; class ChartBackground; +class ChartTitle; class ChartAnimation; class ChartLayout; @@ -83,8 +84,8 @@ public: ChartTheme *chartTheme() const { return m_chartTheme; } ChartDataSet *dataSet() const { return m_dataset; } QGraphicsItem* rootItem() const { return m_chart; } - QGraphicsRectItem* backgroundItem(); - QGraphicsItem* titleItem(); + ChartBackground* backgroundElement(); + ChartTitle* titleElement(); QList axisItems() const; QLegend* legend(); @@ -123,8 +124,8 @@ public: void zoomOut(qreal factor); void scroll(qreal dx,qreal dy); - void setGeometry(const QRectF& rect); - QRectF geometry() { return m_rect; } + void setChartsGeometry(const QRectF& rect); + QRectF chartsGeometry() const; void startAnimation(ChartAnimation* animation); State state() const { return m_state; } @@ -132,8 +133,8 @@ public: void resetAllElements(); - void setMinimumMargins(const QMargins& margins); - QMargins minimumMargins() const; + void setMargins(const QMargins& margins); + QMargins margins() const; QGraphicsLayout* layout(); private: @@ -162,14 +163,14 @@ private: ChartTheme *m_chartTheme; QMap m_chartItems; QMap m_axisItems; - QRectF m_rect; + QRectF m_chartsRect; QChart::AnimationOptions m_options; State m_state; QPointF m_statePoint; QList m_animations; ChartLayout* m_layout; - ChartBackground* m_backgroundItem; - QGraphicsSimpleTextItem* m_titleItem; + ChartBackground* m_background; + ChartTitle* m_title; }; QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/charttitle.cpp b/src/charttitle.cpp new file mode 100644 index 00000000..816bdbf6 --- /dev/null +++ b/src/charttitle.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2012 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 "charttitle_p.h" +#include +#include +#include + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +ChartTitle::ChartTitle(QGraphicsItem* parent):QGraphicsSimpleTextItem(parent) +{ + +} + +ChartTitle::~ChartTitle() +{ + +} + +void ChartTitle::setText(const QString &text) +{ + m_text=text; +} + +QString ChartTitle::text() const +{ + return m_text; +} + +void ChartTitle::setGeometry(const QRectF &rect) +{ + QFontMetrics fn(font()); + + int width = rect.width(); + + if (fn.boundingRect(m_text).width() > width) + { + QString string = m_text + "..."; + while (fn.boundingRect(string).width() > width && string.length() > 3) + string.remove(string.length() - 4, 1); + QGraphicsSimpleTextItem::setText(string); + } + else + QGraphicsSimpleTextItem::setText(m_text); + + setPos(rect.topLeft()); +} + + +QSizeF ChartTitle::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const +{ + Q_UNUSED(constraint); + QFontMetrics fn (font ()); + QSizeF sh; + + switch(which) { + case Qt::MinimumSize: + sh = QSizeF(fn.boundingRect ("...").width(),fn.height()); + break; + case Qt::PreferredSize: + sh = QSizeF(fn.boundingRect(m_text).width(),fn.height()); + break; + case Qt::MaximumSize: + sh = QSizeF(fn.boundingRect(m_text).width(),fn.height()); + break; + case Qt::MinimumDescent: + sh = QSizeF(0, fn.descent ()); + break; + default: + break; + } + + return sh; +} + +QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/charttitle_p.h b/src/charttitle_p.h new file mode 100644 index 00000000..9c9bf514 --- /dev/null +++ b/src/charttitle_p.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2012 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$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the QtCommercial 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 CHARTTITLE_P_H_ +#define CHARTTITLE_P_H_ + +#include "qchartglobal.h" +#include + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +class ChartTitle : public QGraphicsSimpleTextItem +{ +public: + ChartTitle(QGraphicsItem* parent = 0); + ~ChartTitle(); + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const; + void setText(const QString &text); + QString text() const; + void setGeometry(const QRectF &rect); +private: + QString m_text; +}; + +QTCOMMERCIALCHART_END_NAMESPACE + +#endif /* CHARTTITLE_P_H_ */ diff --git a/src/domain.cpp b/src/domain.cpp index be38098d..84d6183e 100644 --- a/src/domain.cpp +++ b/src/domain.cpp @@ -178,7 +178,6 @@ void Domain::handleAxisUpdated() }else if(axis->orientation()==Qt::Vertical){ setRangeY(axis->min(),axis->max()); } - } bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const Domain &domain1, const Domain &domain2) diff --git a/src/legend/legendlayout.cpp b/src/legend/legendlayout.cpp index 3a181f75..bd3a3325 100644 --- a/src/legend/legendlayout.cpp +++ b/src/legend/legendlayout.cpp @@ -22,6 +22,7 @@ #include "chartpresenter_p.h" #include "legendmarker_p.h" #include "qlegend_p.h" +#include QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -58,6 +59,9 @@ void LegendLayout::setOffset(qreal x, qreal y) } QRectF boundingRect = geometry(); + qreal left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + boundingRect.adjust(left,top,-right,-bottom); // Limit offset between m_minOffset and m_maxOffset if (scrollHorizontal) { @@ -112,16 +116,20 @@ void LegendLayout::setAttachedGeometry(const QRectF& rect) m_width=0; m_height=0; + qreal left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + + QRectF geometry = rect.adjusted(left,top,-right,-bottom); + switch(m_legend->alignment()) { case Qt::AlignTop: - case Qt::AlignBottom: { QPointF point(0,0); foreach (LegendMarker* marker, m_legend->d_ptr->markers()) { if (marker->isVisible()) { - marker->setGeometry(QRectF(QPointF(0,0),marker->effectiveSizeHint(Qt::PreferredSize))); - marker->setPos(point.x(),rect.height()/2 - marker->boundingRect().height()/2); + marker->setGeometry(geometry); + marker->setPos(point.x(),geometry.height()/2 - marker->boundingRect().height()/2); const QRectF& rect = marker->boundingRect(); size = size.expandedTo(rect.size()); qreal w = rect.width(); @@ -129,12 +137,12 @@ void LegendLayout::setAttachedGeometry(const QRectF& rect) point.setX(point.x() + w); } } - if(m_widthd_ptr->items()->setPos(rect.width()/2-m_width/2,rect.top()); + if(m_widthd_ptr->items()->setPos(geometry.width()/2-m_width/2,geometry.top()); } else { - m_legend->d_ptr->items()->setPos(rect.topLeft()); + m_legend->d_ptr->items()->setPos(geometry.topLeft()); } m_height=size.height(); } @@ -144,7 +152,7 @@ void LegendLayout::setAttachedGeometry(const QRectF& rect) QPointF point(0,0); foreach (LegendMarker* marker, m_legend->d_ptr->markers()) { if (marker->isVisible()) { - marker->setGeometry(QRectF(QPointF(0,0),marker->effectiveSizeHint(Qt::PreferredSize))); + marker->setGeometry(geometry); marker->setPos(point); const QRectF& rect = marker->boundingRect(); qreal h = rect.height(); @@ -153,21 +161,22 @@ void LegendLayout::setAttachedGeometry(const QRectF& rect) point.setY(point.y() + h); } } - if(m_heightd_ptr->items()->setPos(rect.left(),rect.height()/2-m_height/2); + if(m_heightd_ptr->items()->setPos(geometry.left(),geometry.height()/2-m_height/2); } else { - m_legend->d_ptr->items()->setPos(rect.topLeft()); + m_legend->d_ptr->items()->setPos(geometry.topLeft()); } m_width=size.width(); } break; } - m_minOffsetX = 0; - m_minOffsetY = 0; - m_maxOffsetX = m_width - rect.width(); - m_maxOffsetY = m_height - rect.height(); + + m_minOffsetX = -left; + m_minOffsetY = - top; + m_maxOffsetX = m_width - geometry.width() - right; + m_maxOffsetY = m_height - geometry.height() - bottom; } void LegendLayout::setDettachedGeometry(const QRectF& rect) @@ -182,6 +191,10 @@ void LegendLayout::setDettachedGeometry(const QRectF& rect) m_offsetX=0; m_offsetY=0; + qreal left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + QRectF geometry = rect.adjusted(left,top,-right,-bottom); + QSizeF size(0,0); QList markers = m_legend->d_ptr->markers(); @@ -190,13 +203,13 @@ void LegendLayout::setDettachedGeometry(const QRectF& rect) switch (m_legend->alignment()) { case Qt::AlignTop: { - QPointF point = rect.topLeft(); + QPointF point(0,0); m_width = 0; m_height = 0; for (int i=0; iisVisible()) { - marker->setGeometry(QRectF(QPointF(0,0),marker->effectiveSizeHint(Qt::PreferredSize))); + marker->setGeometry(geometry); marker->setPos(point.x(),point.y()); const QRectF& boundingRect = marker->boundingRect(); qreal w = boundingRect.width(); @@ -204,9 +217,9 @@ void LegendLayout::setDettachedGeometry(const QRectF& rect) m_width = qMax(m_width,w); m_height = qMax(m_height,h); point.setX(point.x() + w); - if (point.x() + w > rect.topLeft().x() + rect.width()) { + if (point.x() + w > geometry.left() + geometry.width() - right) { // Next item would go off rect. - point.setX(rect.topLeft().x()); + point.setX(0); point.setY(point.y() + h); if (i+1 < markers.count()) { m_height += h; @@ -214,22 +227,22 @@ void LegendLayout::setDettachedGeometry(const QRectF& rect) } } } - m_legend->d_ptr->items()->setPos(rect.topLeft()); + m_legend->d_ptr->items()->setPos(geometry.topLeft()); - m_minOffsetX = 0; - m_minOffsetY = 0; - m_maxOffsetX = m_width - rect.width(); - m_maxOffsetY = m_height - rect.height(); + m_minOffsetX = -left; + m_minOffsetY = -top; + m_maxOffsetX = m_width - geometry.width() - right; + m_maxOffsetY = m_height - geometry.height() - bottom; } break; case Qt::AlignBottom: { - QPointF point = rect.bottomLeft(); + QPointF point(0,geometry.height()); m_width = 0; m_height = 0; for (int i=0; iisVisible()) { - marker->setGeometry(QRectF(QPointF(0,0),marker->effectiveSizeHint(Qt::PreferredSize))); + marker->setGeometry(geometry); const QRectF& boundingRect = marker->boundingRect(); qreal w = boundingRect.width(); qreal h = boundingRect.height(); @@ -237,9 +250,9 @@ void LegendLayout::setDettachedGeometry(const QRectF& rect) m_height = qMax(m_height,h); marker->setPos(point.x(),point.y() - h); point.setX(point.x() + w); - if (point.x() + w > rect.bottomLeft().x() + rect.width()) { + if (point.x() + w > geometry.left() + geometry.width() - right) { // Next item would go off rect. - point.setX(rect.bottomLeft().x()); + point.setX(0); point.setY(point.y() - h); if (i+1 < markers.count()) { m_height += h; @@ -247,23 +260,23 @@ void LegendLayout::setDettachedGeometry(const QRectF& rect) } } } - m_legend->d_ptr->items()->setPos(rect.topLeft()); + m_legend->d_ptr->items()->setPos(geometry.topLeft()); - m_minOffsetX = 0; - m_minOffsetY = qMin(rect.topLeft().y(), rect.topLeft().y() - m_height + rect.height()); - m_maxOffsetX = m_width - rect.width(); - m_maxOffsetY = 0; + m_minOffsetX = -left; + m_minOffsetY = -m_height + geometry.height() - top; + m_maxOffsetX = m_width - geometry.width() - right; + m_maxOffsetY = -bottom; } break; case Qt::AlignLeft: { - QPointF point = rect.topLeft(); + QPointF point(0,0); m_width = 0; m_height = 0; qreal maxWidth = 0; for (int i=0; iisVisible()) { - marker->setGeometry(QRectF(QPointF(0,0),marker->effectiveSizeHint(Qt::PreferredSize))); + marker->setGeometry(geometry); const QRectF& boundingRect = marker->boundingRect(); qreal w = boundingRect.width(); qreal h = boundingRect.height(); @@ -271,10 +284,10 @@ void LegendLayout::setDettachedGeometry(const QRectF& rect) maxWidth = qMax(maxWidth,w); marker->setPos(point.x(),point.y()); point.setY(point.y() + h); - if (point.y() + h > rect.topLeft().y() + rect.height()) { + if (point.y() + h > geometry.bottom() - bottom) { // Next item would go off rect. point.setX(point.x() + maxWidth); - point.setY(rect.topLeft().y()); + point.setY(0); if (i+1 < markers.count()) { m_width += maxWidth; maxWidth = 0; @@ -283,23 +296,23 @@ void LegendLayout::setDettachedGeometry(const QRectF& rect) } } m_width += maxWidth; - m_legend->d_ptr->items()->setPos(rect.topLeft()); + m_legend->d_ptr->items()->setPos(geometry.topLeft()); - m_minOffsetX = 0; - m_minOffsetY = 0; - m_maxOffsetX = m_width - rect.width(); - m_maxOffsetY = m_height - rect.height(); + m_minOffsetX = -left; + m_minOffsetY = -top; + m_maxOffsetX = m_width - geometry.width() - right; + m_maxOffsetY = m_height - geometry.height() - bottom; } break; case Qt::AlignRight: { - QPointF point = rect.topRight(); + QPointF point(geometry.width(),0); m_width = 0; m_height = 0; qreal maxWidth = 0; for (int i=0; iisVisible()) { - marker->setGeometry(QRectF(QPointF(0,0),marker->effectiveSizeHint(Qt::PreferredSize))); + marker->setGeometry(geometry); const QRectF& boundingRect = marker->boundingRect(); qreal w = boundingRect.width(); qreal h = boundingRect.height(); @@ -307,10 +320,10 @@ void LegendLayout::setDettachedGeometry(const QRectF& rect) maxWidth = qMax(maxWidth,w); marker->setPos(point.x() - w,point.y()); point.setY(point.y() + h); - if (point.y() + h > rect.topLeft().y() + rect.height()) { + if (point.y() + h > geometry.bottom()-bottom) { // Next item would go off rect. point.setX(point.x() - maxWidth); - point.setY(rect.topLeft().y()); + point.setY(0); if (i+1 < markers.count()) { m_width += maxWidth; maxWidth = 0; @@ -319,12 +332,12 @@ void LegendLayout::setDettachedGeometry(const QRectF& rect) } } m_width += maxWidth; - m_legend->d_ptr->items()->setPos(rect.topLeft()); + m_legend->d_ptr->items()->setPos(geometry.topLeft()); - m_minOffsetX = qMin(rect.topLeft().x(), rect.topLeft().x() - m_width + rect.width()); - m_minOffsetY = 0; - m_maxOffsetX = 0; - m_maxOffsetY = m_height - rect.height(); + m_minOffsetX = - m_width + geometry.width() - left; + m_minOffsetY = -top; + m_maxOffsetX = - right; + m_maxOffsetY = m_height - geometry.height() - bottom; } break; default: @@ -339,8 +352,6 @@ QSizeF LegendLayout::sizeHint ( Qt::SizeHint which, const QSizeF & constraint) c qreal left, top, right, bottom; getContentsMargins(&left, &top, &right, &bottom); - if(which!=Qt::PreferredSize) return QSizeF(-1,-1); - if(constraint.isValid()) { foreach(LegendMarker* marker, m_legend->d_ptr->markers()) { size = size.expandedTo(marker->effectiveSizeHint(which)); @@ -372,10 +383,7 @@ QSizeF LegendLayout::sizeHint ( Qt::SizeHint which, const QSizeF & constraint) c } } size += QSize(left + right, top + bottom); - return size; - - } QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/legend/legendmarker.cpp b/src/legend/legendmarker.cpp index e6c370f8..6857a209 100644 --- a/src/legend/legendmarker.cpp +++ b/src/legend/legendmarker.cpp @@ -44,7 +44,7 @@ LegendMarker::LegendMarker(QAbstractSeries *series, QLegend *legend) : m_legend(legend), m_textItem(new QGraphicsSimpleTextItem(this)), m_rectItem(new QGraphicsRectItem(this)), - m_margin(2), + m_margin(4), m_space(4) { //setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton); @@ -86,12 +86,13 @@ QFont LegendMarker::font() const void LegendMarker::setLabel(const QString label) { - m_textItem->setText(label); + m_text = label; + updateGeometry(); } QString LegendMarker::label() const { - return m_textItem->text(); + return m_text; } QRectF LegendMarker::boundingRect() const @@ -112,14 +113,31 @@ QBrush LegendMarker::labelBrush() const void LegendMarker::setGeometry(const QRectF& rect) { + QFontMetrics fn (font()); + + int width = rect.width(); + qreal x = m_margin + m_markerRect.width() + m_space + m_margin; + qreal y = qMax(m_markerRect.height()+2*m_margin,fn.height()+2*m_margin); + + if (fn.boundingRect(m_text).width() + x > width) + { + QString string = m_text + "..."; + while(fn.boundingRect(string).width() + x > width && string.length() > 3) + string.remove(string.length() - 4, 1); + m_textItem->setText(string); + } + else + m_textItem->setText(m_text); + const QRectF& textRect = m_textItem->boundingRect(); - m_textItem->setPos(m_markerRect.width() + m_space + m_margin,rect.height()/2 - textRect.height()/2); + + m_textItem->setPos(x-m_margin,y/2 - textRect.height()/2); m_rectItem->setRect(m_markerRect); - m_rectItem->setPos(m_margin,rect.height()/2 - m_markerRect.height()/2); + m_rectItem->setPos(m_margin,y/2 - m_markerRect.height()/2); prepareGeometryChange(); - m_boundingRect = rect; + m_boundingRect = QRectF(0,0,x+textRect.width()+m_margin,y); } void LegendMarker::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) @@ -129,7 +147,6 @@ void LegendMarker::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti Q_UNUSED(painter) } - QSizeF LegendMarker::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const { Q_UNUSED(constraint) @@ -139,10 +156,10 @@ QSizeF LegendMarker::sizeHint(Qt::SizeHint which, const QSizeF& constraint) cons switch (which) { case Qt::MinimumSize: - sh = QSizeF(fn.boundingRect("...").width(),fn.height()); + sh = QSizeF(fn.boundingRect("...").width() + 2*m_margin + m_space +m_markerRect.width(),qMax(m_markerRect.height()+2*m_margin,fn.height()+2*m_margin)); break; case Qt::PreferredSize: - sh = QSizeF(fn.boundingRect(m_textItem->text()).width() + 2*m_margin + m_space +m_markerRect.width(),qMax(m_markerRect.height()+2*m_margin,fn.height()+2*m_margin)); + sh = QSizeF(fn.boundingRect(m_text).width() + 2*m_margin + m_space +m_markerRect.width(),qMax(m_markerRect.height()+2*m_margin,fn.height()+2*m_margin)); break; default: break; @@ -154,7 +171,7 @@ QSizeF LegendMarker::sizeHint(Qt::SizeHint which, const QSizeF& constraint) cons void LegendMarker::mousePressEvent(QGraphicsSceneMouseEvent *event) { QGraphicsObject::mousePressEvent(event); - qDebug()<<"Not implemented"; //TODO: selected signal removed for now + //TODO: selected signal removed for now } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/legend/legendmarker_p.h b/src/legend/legendmarker_p.h index 6ae225a7..462370f3 100644 --- a/src/legend/legendmarker_p.h +++ b/src/legend/legendmarker_p.h @@ -96,6 +96,7 @@ protected: QGraphicsRectItem *m_rectItem; qreal m_margin; qreal m_space; + QString m_text; }; diff --git a/src/qchart.cpp b/src/qchart.cpp index 36fef48a..66151ce1 100644 --- a/src/qchart.cpp +++ b/src/qchart.cpp @@ -373,18 +373,18 @@ QLegend* QChart::legend() const /*! Sets the minimum \a margins between the plot area (axes) and the edge of the chart widget. */ -void QChart::setMinimumMargins(const QMargins& margins) +void QChart::setMargins(const QMargins& margins) { - d_ptr->m_presenter->setMinimumMargins(margins); + d_ptr->m_presenter->setMargins(margins); } /*! Returns the rect that contains information about margins (distance between chart widget edge and axes). Individual margins can be obtained by calling left, top, right, bottom on the returned rect. */ -QMargins QChart::minimumMargins() const +QMargins QChart::margins() const { - return d_ptr->m_presenter->minimumMargins(); + return d_ptr->m_presenter->margins(); } /*! @@ -393,7 +393,7 @@ QMargins QChart::minimumMargins() const */ QRectF QChart::plotArea() const { - return d_ptr->m_presenter->geometry(); + return d_ptr->m_presenter->chartsGeometry(); } ///*! diff --git a/src/qchart.h b/src/qchart.h index 136eaab9..e9a0fd56 100644 --- a/src/qchart.h +++ b/src/qchart.h @@ -43,7 +43,7 @@ class QTCOMMERCIALCHART_EXPORT QChart : public QGraphicsWidget Q_PROPERTY(bool backgroundVisible READ isBackgroundVisible WRITE setBackgroundVisible) Q_PROPERTY(bool dropShadowEnabled READ isDropShadowEnabled WRITE setDropShadowEnabled) Q_PROPERTY(QChart::AnimationOptions animationOptions READ animationOptions WRITE setAnimationOptions) - Q_PROPERTY(QMargins minimumMargins READ minimumMargins WRITE setMinimumMargins) + Q_PROPERTY(QMargins margins READ margins WRITE setMargins) Q_ENUMS(ChartTheme) Q_ENUMS(AnimationOption) @@ -114,8 +114,8 @@ public: QLegend* legend() const; - void setMinimumMargins(const QMargins& margins); - QMargins minimumMargins() const; + void setMargins(const QMargins& margins); + QMargins margins() const; QRectF plotArea() const; diff --git a/src/src.pro b/src/src.pro index 44037049..e0490dac 100644 --- a/src/src.pro +++ b/src/src.pro @@ -38,7 +38,8 @@ SOURCES += \ $$PWD/chartbackground.cpp \ $$PWD/chartelement.cpp \ $$PWD/scroller.cpp \ - $$PWD/chartlayout.cpp + $$PWD/chartlayout.cpp \ + $$PWD/charttitle.cpp PRIVATE_HEADERS += \ $$PWD/chartdataset_p.h \ $$PWD/chartitem_p.h \ @@ -52,8 +53,8 @@ PRIVATE_HEADERS += \ $$PWD/qchartview_p.h \ $$PWD/scroller_p.h \ $$PWD/qabstractseries_p.h \ - $$PWD/chartlayout_p.h - + $$PWD/chartlayout_p.h \ + $$PWD/charttitle_p.h PUBLIC_HEADERS += \ $$PWD/qchart.h \ $$PWD/qchartglobal.h \ -- cgit v1.2.3