From d9bcc3bd9d82e9a6422a0a418a49c28de81aa316 2012-06-26 11:44:35 From: Michal Klocek Date: 2012-06-26 11:44:35 Subject: [PATCH] Refactors layout managment * adds chartlayout class * adds lagendlayout class * refactors handling to setGeometry instead of resize * implmements all TODOs from presenter and qchart * refactors layout handling in legend * adds QGraphicsLayoutItem sublcassing --- diff --git a/examples/legend/mainwidget.cpp b/examples/legend/mainwidget.cpp index 52f8b9a..cb2ddb5 100644 --- a/examples/legend/mainwidget.cpp +++ b/examples/legend/mainwidget.cpp @@ -252,10 +252,10 @@ void MainWidget::fontSizeChanged() void MainWidget::updateLegendLayout() { //![4] - m_chart->legend()->setGeometry(m_legendPosX->value() + m_chart->legend()->setGeometry(QRectF(m_legendPosX->value() ,m_legendPosY->value() ,m_legendWidth->value() - ,m_legendHeight->value()); + ,m_legendHeight->value())); m_chart->legend()->update(); //![4] } diff --git a/src/axis/chartaxis.cpp b/src/axis/chartaxis.cpp index b78a56b..c5c63ce 100644 --- a/src/axis/chartaxis.cpp +++ b/src/axis/chartaxis.cpp @@ -40,7 +40,9 @@ ChartAxis::ChartAxis(QAxis *axis,ChartPresenter *presenter) : Chart(presenter), m_min(0), m_max(0), m_ticksCount(0), - m_animation(0) + m_animation(0), + m_minWidth(0), + m_minHeight(0) { //initial initialization m_axis->setZValue(ChartPresenter::AxisZValue); @@ -52,6 +54,9 @@ ChartAxis::ChartAxis(QAxis *axis,ChartPresenter *presenter) : Chart(presenter), QObject::connect(m_chartAxis->d_ptr.data(),SIGNAL(updated()),this,SLOT(handleAxisUpdated())); QObject::connect(m_chartAxis->categories()->d_ptr.data(),SIGNAL(updated()),this,SLOT(handleAxisCategoriesUpdated())); + QGraphicsSimpleTextItem item; + m_font = item.font(); + handleAxisUpdated(); } @@ -243,6 +248,7 @@ void ChartAxis::setLabelsFont(const QFont &font) foreach(QGraphicsItem* item , m_labels->childItems()) { static_cast(item)->setFont(font); } + m_font = font; } void ChartAxis::setShadesBrush(const QBrush &brush) @@ -351,6 +357,20 @@ void ChartAxis::handleGeometryChanged(const QRectF &rect) } } + +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"; diff --git a/src/axis/chartaxis_p.h b/src/axis/chartaxis_p.h index d2573d0..a971bc4 100644 --- a/src/axis/chartaxis_p.h +++ b/src/axis/chartaxis_p.h @@ -34,6 +34,7 @@ #include "chart_p.h" #include "axisanimation_p.h" #include +#include QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -84,6 +85,9 @@ public: QRectF geometry() const { return m_rect; } + qreal minimumWidth(); + qreal minimumHeight(); + protected: virtual void updateGeometry() = 0; virtual QVector calculateLayout() const = 0; @@ -115,6 +119,9 @@ protected: qreal m_max; int m_ticksCount; AxisAnimation *m_animation; + qreal m_minWidth; + qreal m_minHeight; + QFont m_font; friend class AxisAnimation; friend class AxisItem; diff --git a/src/axis/chartaxisx.cpp b/src/axis/chartaxisx.cpp index 5414ed0..24b81f3 100644 --- a/src/axis/chartaxisx.cpp +++ b/src/axis/chartaxisx.cpp @@ -24,6 +24,9 @@ #include "qaxiscategories_p.h" #include "chartpresenter_p.h" #include "chartanimator_p.h" +#include +#include +#include static int label_padding = 5; @@ -56,6 +59,11 @@ void ChartAxisX::updateGeometry() { const QVector& layout = ChartAxis::layout(); + m_minWidth = 0; + m_minHeight = 0; + + if(layout.isEmpty()) return; + QStringList ticksList; bool categories = createLabels(ticksList,m_min,m_max,layout.size()); @@ -68,12 +76,10 @@ void ChartAxisX::updateGeometry() Q_ASSERT(labels.size() == ticksList.size()); Q_ASSERT(layout.size() == ticksList.size()); - qreal minWidth = 0; - qreal minHeight = 0; - QGraphicsLineItem *lineItem = static_cast(axis.at(0)); lineItem->setLine(m_rect.left(), m_rect.bottom(), m_rect.right(), m_rect.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()); @@ -81,20 +87,29 @@ void ChartAxisX::updateGeometry() if (!categories || i<1) { labelItem->setText(ticksList.at(i)); const QRectF& rect = labelItem->boundingRect(); - minWidth+=rect.width(); - minHeight=qMax(rect.height(),minHeight); 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->setVisible(false); + lineItem->setVisible(false); + }else{ + labelItem->setVisible(true); + lineItem->setVisible(true); + width=rect.width()+labelItem->pos().x(); + } + m_minWidth+=rect.width(); + m_minHeight=qMax(rect.height(),m_minHeight); } else { labelItem->setText(ticksList.at(i)); const QRectF& rect = labelItem->boundingRect(); - minWidth+=rect.width(); - minHeight=qMax(rect.height()+label_padding,minHeight); QPointF center = rect.center(); labelItem->setTransformOriginPoint(center.x(), center.y()); labelItem->setPos(layout[i] - (layout[i] - layout[i-1])/2 - center.x(), m_rect.bottom() + label_padding); + m_minWidth+=rect.width(); + m_minHeight=qMax(rect.height()+label_padding,m_minHeight); } if ((i+1)%2 && i>1) { @@ -104,9 +119,6 @@ void ChartAxisX::updateGeometry() lineItem = static_cast(axis.at(i+1)); lineItem->setLine(layout[i],m_rect.bottom(),layout[i],m_rect.bottom()+5); } - - presenter()->setMinimumMarginWidth(this,minWidth); - presenter()->setMinimumMarginHeight(this,minHeight); } QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/axis/chartaxisy.cpp b/src/axis/chartaxisy.cpp index b357aa7..ae909a3 100644 --- a/src/axis/chartaxisy.cpp +++ b/src/axis/chartaxisy.cpp @@ -24,7 +24,9 @@ #include "qaxiscategories_p.h" #include "chartpresenter_p.h" #include "chartanimator_p.h" - +#include +#include +#include static int label_padding = 5; @@ -57,6 +59,10 @@ QVector ChartAxisY::calculateLayout() const void ChartAxisY::updateGeometry() { const QVector &layout = ChartAxis::layout(); + m_minWidth = 0; + m_minHeight = 0; + + if(layout.isEmpty()) return; QStringList ticksList; @@ -70,8 +76,7 @@ void ChartAxisY::updateGeometry() Q_ASSERT(labels.size() == ticksList.size()); Q_ASSERT(layout.size() == ticksList.size()); - qreal minWidth = 0; - qreal minHeight = 0; + qreal height = 2*m_rect.bottom(); QGraphicsLineItem *lineItem = static_cast(axis.at(0)); lineItem->setLine(m_rect.left() , m_rect.top(), m_rect.left(), m_rect.bottom()); @@ -84,17 +89,29 @@ void ChartAxisY::updateGeometry() if (!categories || i<1) { labelItem->setText(ticksList.at(i)); const QRectF& rect = labelItem->boundingRect(); - minWidth=qMax(rect.width()+label_padding,minWidth); - minHeight+=rect.height(); + QPointF center = rect.center(); labelItem->setTransformOriginPoint(center.x(), center.y()); labelItem->setPos(m_rect.left() - rect.width() - label_padding , layout[i]-center.y()); + + if(labelItem->pos().y()+rect.height()>height) { + labelItem->setVisible(false); + lineItem->setVisible(false); + } + else { + labelItem->setVisible(true); + lineItem->setVisible(true); + height=labelItem->pos().y(); + } + + m_minWidth=qMax(rect.width()+label_padding,m_minWidth); + m_minHeight+=rect.height(); } else { labelItem->setText(ticksList.at(i)); const QRectF& rect = labelItem->boundingRect(); - minWidth=qMax(rect.width(),minWidth); - minHeight+=rect.height(); + m_minWidth=qMax(rect.width(),m_minWidth); + m_minHeight+=rect.height(); QPointF center = rect.center(); labelItem->setTransformOriginPoint(center.x(), center.y()); labelItem->setPos(m_rect.left() - rect.width() - label_padding , layout[i] - (layout[i] - layout[i-1])/2 -center.y()); @@ -107,10 +124,7 @@ void ChartAxisY::updateGeometry() lineItem = static_cast(axis.at(i+1)); lineItem->setLine(m_rect.left()-5,layout[i],m_rect.left(),layout[i]); } - - presenter()->setMinimumMarginWidth(this,minWidth); - presenter()->setMinimumMarginHeight(this,minHeight); - } + QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/axis/chartaxisy_p.h b/src/axis/chartaxisy_p.h index 919c35c..d192fa8 100644 --- a/src/axis/chartaxisy_p.h +++ b/src/axis/chartaxisy_p.h @@ -48,6 +48,7 @@ public: protected: QVector calculateLayout() const; void updateGeometry(); + }; QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/chartlayout.cpp b/src/chartlayout.cpp new file mode 100644 index 0000000..b71f6d4 --- /dev/null +++ b/src/chartlayout.cpp @@ -0,0 +1,144 @@ +#include "chartlayout_p.h" +#include "chartpresenter_p.h" +#include "chartaxis_p.h" +#include +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +ChartLayout::ChartLayout(ChartPresenter* presenter): +m_presenter(presenter), +m_marginBig(60), +m_marginSmall(20), +m_marginTiny(10), +m_chartMargins(QPointF(m_marginBig,m_marginBig),QPointF(m_marginBig,m_marginBig)) +{ + +} + +ChartLayout::~ChartLayout() +{ + +} + +void ChartLayout::setGeometry(const QRectF& rect) +{ + if (!rect.isValid()) return; + + QGraphicsLayout::setGeometry(rect); + + // check title size + + QSize titleSize = QSize(0,0); + + if (m_presenter->titleItem()) { + titleSize= m_presenter->titleItem()->boundingRect().size().toSize(); + } + + qreal axisHeight = 0; + qreal axisWidth = 0; + + // check axis size + + 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(); + + qreal titlePadding = m_chartMargins.top()/2; + + QRectF chartMargins = m_chartMargins; + + // recalculate legend position + if (legend != 0 && legend->isVisible() && legend->isAttachedToChart()) { + + // Reserve some space for legend + switch (legend->alignment()) { + + case Qt::AlignTop: { + QSizeF legendSize = legend->effectiveSizeHint(Qt::PreferredSize,QSizeF(rect.width(),-1)); + int topMargin = 2*m_marginTiny + titleSize.height() + legendSize.height() + m_marginTiny; + chartMargins = QRect(QPoint(m_chartMargins.left(),topMargin),QPoint(m_chartMargins.right(),m_chartMargins.bottom())); + m_legendMargins = QRect(QPoint(chartMargins.left(),topMargin - (legendSize.height() + m_marginTiny)),QPoint(chartMargins.right(),rect.height()-topMargin + m_marginTiny)); + titlePadding = m_marginTiny + m_marginTiny; + break; + } + case Qt::AlignBottom: { + QSizeF legendSize = legend->effectiveSizeHint(Qt::PreferredSize,QSizeF(rect.width(),-1)); + int bottomMargin = m_marginTiny + m_marginSmall + legendSize.height() + m_marginTiny + axisHeight; + chartMargins = QRect(QPoint(m_chartMargins.left(),m_chartMargins.top()),QPoint(m_chartMargins.right(),bottomMargin)); + m_legendMargins = QRect(QPoint(chartMargins.left(),rect.height()-bottomMargin + m_marginTiny + axisHeight),QPoint(chartMargins.right(),m_marginTiny + m_marginSmall)); + titlePadding = chartMargins.top()/2; + break; + } + case Qt::AlignLeft: { + QSizeF legendSize = legend->effectiveSizeHint(Qt::PreferredSize,QSizeF(-1,rect.height())); + int leftPadding = m_marginTiny + m_marginSmall + legendSize.width() + m_marginTiny + axisWidth; + chartMargins = QRect(QPoint(leftPadding,m_chartMargins.top()),QPoint(m_chartMargins.right(),m_chartMargins.bottom())); + m_legendMargins = QRect(QPoint(m_marginTiny + m_marginSmall,chartMargins.top()),QPoint(rect.width()-leftPadding + m_marginTiny + axisWidth,chartMargins.bottom())); + titlePadding = chartMargins.top()/2; + break; + } + case Qt::AlignRight: { + QSizeF legendSize = legend->effectiveSizeHint(Qt::PreferredSize,QSizeF(-1,rect.height())); + int rightPadding = m_marginTiny + m_marginSmall + legendSize.width() + m_marginTiny; + chartMargins = QRect(QPoint(m_chartMargins.left(),m_chartMargins.top()),QPoint(rightPadding,m_chartMargins.bottom())); + m_legendMargins = QRect(QPoint(rect.width()- rightPadding+ m_marginTiny ,chartMargins.top()),QPoint(m_marginTiny + m_marginSmall,chartMargins.bottom())); + titlePadding = chartMargins.top()/2; + 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); + } + + //recalculate background gradient + if (m_presenter->backgroundItem()) { + m_presenter->backgroundItem()->setRect(rect.adjusted(m_marginTiny,m_marginTiny, -m_marginTiny, -m_marginTiny)); + } + + QRectF chartRect = rect.adjusted(chartMargins.left(),chartMargins.top(),-chartMargins.right(),-chartMargins.bottom()); + + 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)); + } + +} + + +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 + return QSize(-1,-1); +} + +void ChartLayout::setMarginsMinimum(const QRectF& margins) +{ + if(m_chartMargins != margins){ + m_chartMargins = margins; + updateGeometry(); + } +} + +QRectF ChartLayout::margins() const +{ + return m_chartMargins; +} + +QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/chartlayout_p.h b/src/chartlayout_p.h new file mode 100644 index 0000000..1ae011f --- /dev/null +++ b/src/chartlayout_p.h @@ -0,0 +1,43 @@ +#ifndef CHARTLAYOUT_H_ +#define CHARTLAYOUT_H_ +#include +#include "qchartglobal.h" + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +class ChartPresenter; + +class ChartLayout : public QGraphicsLayout +{ +public: + + ChartLayout(ChartPresenter* presenter); + virtual ~ChartLayout(); + + void setMarginsMinimum(const QRectF& margins); + QRectF margins() const; + + void setGeometry(const QRectF& rect); + +protected: + QSizeF sizeHint ( Qt::SizeHint which, const QSizeF & constraint = QSizeF() ) const; + int count() const { return 0; } + QGraphicsLayoutItem* itemAt(int) const { return 0; }; + void removeAt(int){}; + +private: + ChartPresenter* m_presenter; + int m_marginBig; + int m_marginSmall; + int m_marginTiny; + + QRectF m_chartMargins; + QRectF m_legendMargins; + + + +}; + +QTCOMMERCIALCHART_END_NAMESPACE + +#endif diff --git a/src/chartpresenter.cpp b/src/chartpresenter.cpp index eae233c..628d990 100644 --- a/src/chartpresenter.cpp +++ b/src/chartpresenter.cpp @@ -32,6 +32,7 @@ #include "chartaxisy_p.h" #include "areachartitem_p.h" #include "chartbackground_p.h" +#include "chartlayout_p.h" #include QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -41,17 +42,11 @@ m_chart(chart), m_animator(0), m_dataset(dataset), m_chartTheme(0), -m_chartRect(QRectF(QPoint(0,0),m_chart->size())), m_options(QChart::NoAnimation), -m_minLeftMargin(0), -m_minBottomMargin(0), m_state(ShowState), +m_layout(new ChartLayout(this)), m_backgroundItem(0), -m_titleItem(0), -m_marginBig(60), -m_marginSmall(20), -m_marginTiny(10), -m_chartMargins(QRect(m_marginBig,m_marginBig,0,0)) +m_titleItem(0) { } @@ -63,56 +58,12 @@ ChartPresenter::~ChartPresenter() void ChartPresenter::setGeometry(const QRectF& rect) { - m_rect = rect; - Q_ASSERT(m_rect.isValid()); - updateLayout(); -} - -void ChartPresenter::setMinimumMarginWidth(ChartAxis* axis, qreal width) -{ - switch(axis->axisType()){ - case ChartAxis::X_AXIS: - { - if(width>m_chartRect.width()+ m_chartMargins.left()) { - m_minLeftMargin= width - m_chartRect.width(); - updateLayout(); - } - break; - } - case ChartAxis::Y_AXIS: - { - if(m_minLeftMargin!=width){ - m_minLeftMargin= width; - updateLayout(); - } - break; - } - - } -} - -void ChartPresenter::setMinimumMarginHeight(ChartAxis* axis, qreal height) -{ - switch(axis->axisType()){ - case ChartAxis::X_AXIS: - { - if(m_minBottomMargin!=height) { - m_minBottomMargin= height; - updateLayout(); - } - break; - } - case ChartAxis::Y_AXIS: - { - - if(height>m_chartMargins.bottom()+m_chartRect.height()){ - m_minBottomMargin= height - m_chartRect.height(); - updateLayout(); - } - break; - } + Q_ASSERT(rect.isValid()); + if(m_rect!=rect) { + m_rect=rect; + emit geometryChanged(m_rect); } } @@ -147,7 +98,7 @@ void ChartPresenter::handleAxisAdded(QAxis* axis,Domain* domain) QObject::connect(this,SIGNAL(geometryChanged(QRectF)),item,SLOT(handleGeometryChanged(QRectF))); //initialize - if(m_chartRect.isValid()) item->handleGeometryChanged(m_chartRect); + if(m_rect.isValid()) item->handleGeometryChanged(m_rect); m_axisItems.insert(axis, item); } @@ -168,7 +119,7 @@ void ChartPresenter::handleSeriesAdded(QAbstractSeries* series,Domain* domain) QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),item,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal))); //initialize item->handleDomainChanged(domain->minX(),domain->maxX(),domain->minY(),domain->maxY()); - if(m_chartRect.isValid()) item->handleGeometryChanged(m_chartRect); + if(m_rect.isValid()) item->handleGeometryChanged(m_rect); m_chartItems.insert(series,item); } @@ -243,23 +194,23 @@ void ChartPresenter::resetAllElements() void ChartPresenter::zoomIn(qreal factor) { - QRectF rect = chartGeometry(); + QRectF rect = geometry(); rect.setWidth(rect.width()/factor); rect.setHeight(rect.height()/factor); - rect.moveCenter(chartGeometry().center()); + rect.moveCenter(geometry().center()); zoomIn(rect); } void ChartPresenter::zoomIn(const QRectF& rect) { QRectF r = rect.normalized(); - r.translate(-m_chartMargins.topLeft()); + r.translate(-geometry().topLeft()); if (!r.isValid()) return; m_state = ZoomInState; - m_statePoint = QPointF(r.center().x()/chartGeometry().width(),r.center().y()/chartGeometry().height()); - m_dataset->zoomInDomain(r,chartGeometry().size()); + m_statePoint = QPointF(r.center().x()/geometry().width(),r.center().y()/geometry().height()); + m_dataset->zoomInDomain(r,geometry().size()); m_state = ShowState; } @@ -268,14 +219,14 @@ void ChartPresenter::zoomOut(qreal factor) m_state = ZoomOutState; QRectF chartRect; - chartRect.setSize(chartGeometry().size()); + chartRect.setSize(geometry().size()); QRectF rect; rect.setSize(chartRect.size()/factor); rect.moveCenter(chartRect.center()); if (!rect.isValid()) return; - m_statePoint = QPointF(rect.center().x()/chartGeometry().width(),rect.center().y()/chartGeometry().height()); + m_statePoint = QPointF(rect.center().x()/geometry().width(),rect.center().y()/geometry().height()); m_dataset->zoomOutDomain(rect, chartRect.size()); m_state = ShowState; } @@ -287,7 +238,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,chartGeometry().size()); + m_dataset->scrollDomain(dx,dy,geometry().size()); m_state = ShowState; } @@ -296,136 +247,170 @@ QChart::AnimationOptions ChartPresenter::animationOptions() const return m_options; } -void ChartPresenter::updateLayout() +void ChartPresenter::createBackgroundItem() { - if (!m_rect.isValid()) return; + if (!m_backgroundItem) { + m_backgroundItem = new ChartBackground(rootItem()); + m_backgroundItem->setPen(Qt::NoPen); + m_backgroundItem->setZValue(ChartPresenter::BackgroundZValue); + } +} - QRectF oldChargMargins = m_chartMargins; +void ChartPresenter::createTitleItem() +{ + if (!m_titleItem) { + m_titleItem = new QGraphicsSimpleTextItem(rootItem()); + m_titleItem->setZValue(ChartPresenter::BackgroundZValue); + } +} - // recalculate title size - QSize titleSize; - int titlePadding=0; +void ChartPresenter::handleAnimationFinished() +{ + m_animations.removeAll(qobject_cast(sender())); + if(m_animations.empty()) emit animationsFinished(); +} - if (m_titleItem) { - titleSize= m_titleItem->boundingRect().size().toSize(); +void ChartPresenter::startAnimation(ChartAnimation* animation) +{ + if (animation->state() != QAbstractAnimation::Stopped) animation->stop(); + QObject::connect(animation, SIGNAL(finished()),this,SLOT(handleAnimationFinished()),Qt::UniqueConnection); + if(!m_animations.isEmpty()){ + m_animations.append(animation); } + QTimer::singleShot(0, animation, SLOT(start())); +} - //defaults - m_chartMargins = QRect(QPoint(m_minLeftMargin>m_marginBig?m_minLeftMargin:m_marginBig,m_marginBig),QPoint(m_marginBig,m_minBottomMargin>m_marginBig?m_minBottomMargin:m_marginBig)); - titlePadding = m_chartMargins.top()/2; +QGraphicsRectItem* ChartPresenter::backgroundItem() +{ + return m_backgroundItem; +} - QLegend* legend = m_chart->d_ptr->m_legend; +void ChartPresenter::setBackgroundBrush(const QBrush& brush) +{ + createBackgroundItem(); + m_backgroundItem->setBrush(brush); + m_layout->invalidate(); +} - // recalculate legend position - if (legend != 0 && legend->isAttachedToChart() && legend->isEnabled()) { +QBrush ChartPresenter::backgroundBrush() const +{ + if (!m_backgroundItem) return QBrush(); + return m_backgroundItem->brush(); +} - // Reserve some space for legend - switch (legend->alignment()) { +void ChartPresenter::setBackgroundPen(const QPen& pen) +{ + createBackgroundItem(); + m_backgroundItem->setPen(pen); + m_layout->invalidate(); +} - case Qt::AlignTop: { - int ledgendSize = legend->minHeight(); - int topPadding = 2*m_marginTiny + titleSize.height() + ledgendSize + m_marginTiny; - m_chartMargins = QRect(QPoint(m_chartMargins.left(),topPadding),QPoint(m_chartMargins.right(),m_chartMargins.bottom())); - m_legendMargins = QRect(QPoint(m_chartMargins.left(),topPadding - (ledgendSize + m_marginTiny)),QPoint(m_chartMargins.right(),m_rect.height()-topPadding + m_marginTiny)); - titlePadding = m_marginTiny + m_marginTiny; - break; - } - case Qt::AlignBottom: { - int ledgendSize = legend->minHeight(); - int bottomPadding = m_marginTiny + m_marginSmall + ledgendSize + m_marginTiny + m_minBottomMargin; - m_chartMargins = QRect(QPoint(m_chartMargins.left(),m_chartMargins.top()),QPoint(m_chartMargins.right(),bottomPadding)); - m_legendMargins = QRect(QPoint(m_chartMargins.left(),m_rect.height()-bottomPadding + m_marginTiny + m_minBottomMargin),QPoint(m_chartMargins.right(),m_marginTiny + m_marginSmall)); - titlePadding = m_chartMargins.top()/2; - break; - } - case Qt::AlignLeft: { - int ledgendSize = legend->minWidth(); - int leftPadding = m_marginTiny + m_marginSmall + ledgendSize + m_marginTiny + m_minLeftMargin; - m_chartMargins = QRect(QPoint(leftPadding,m_chartMargins.top()),QPoint(m_chartMargins.right(),m_chartMargins.bottom())); - m_legendMargins = QRect(QPoint(m_marginTiny + m_marginSmall,m_chartMargins.top()),QPoint(m_rect.width()-leftPadding + m_marginTiny + m_minLeftMargin,m_chartMargins.bottom())); - titlePadding = m_chartMargins.top()/2; - break; - } - case Qt::AlignRight: { - int ledgendSize = legend->minWidth(); - int rightPadding = m_marginTiny + m_marginSmall + ledgendSize + m_marginTiny; - m_chartMargins = QRect(QPoint(m_chartMargins.left(),m_chartMargins.top()),QPoint(rightPadding,m_chartMargins.bottom())); - m_legendMargins = QRect(QPoint(m_rect.width()- rightPadding+ m_marginTiny ,m_chartMargins.top()),QPoint(m_marginTiny + m_marginSmall,m_chartMargins.bottom())); - titlePadding = m_chartMargins.top()/2; - break; - } - default: { - break; - } - } - } +QPen ChartPresenter::backgroundPen() const +{ + if (!m_backgroundItem) return QPen(); + return m_backgroundItem->pen(); +} - if(m_rect.width()<2*(m_chartMargins.top()+m_chartMargins.bottom()) || m_rect.height()< 2*(m_chartMargins.top() + m_chartMargins.bottom())) - { - m_chart->setMinimumSize(2*(m_chartMargins.top()+m_chartMargins.bottom()),2*(m_chartMargins.top() + m_chartMargins.bottom())); - return; - } +QGraphicsItem* ChartPresenter::titleItem() +{ + return m_titleItem; +} +void ChartPresenter::setTitle(const QString& title) +{ + createTitleItem(); + m_titleItem->setText(title); + m_layout->invalidate(); +} - // recalculate title position - if (m_titleItem) { - QPointF center = m_rect.center() -m_titleItem->boundingRect().center(); - m_titleItem->setPos(center.x(),titlePadding); - } +QString ChartPresenter::title() const +{ + if (!m_titleItem) return QString(); + return m_titleItem->text(); +} - //recalculate background gradient - if (m_backgroundItem) { - m_backgroundItem->setRect(m_rect.adjusted(m_marginTiny,m_marginTiny, -m_marginTiny, -m_marginTiny)); - } +void ChartPresenter::setTitleFont(const QFont& font) +{ + createTitleItem(); + m_titleItem->setFont(font); + m_layout->invalidate(); +} +QFont ChartPresenter::titleFont() const +{ + if (!m_titleItem) return QFont(); + return m_titleItem->font(); +} - QRectF chartRect = m_rect.adjusted(m_chartMargins.left(),m_chartMargins.top(),-m_chartMargins.right(),-m_chartMargins.bottom()); +void ChartPresenter::setTitleBrush(const QBrush &brush) +{ + createTitleItem(); + m_titleItem->setBrush(brush); + m_layout->invalidate(); +} - if (legend != 0 && legend->isAttachedToChart() && legend->isEnabled()) { - legend->setGeometry(m_rect.adjusted(m_legendMargins.left(),m_legendMargins.top(),-m_legendMargins.right(),-m_legendMargins.bottom())); - } +QBrush ChartPresenter::titleBrush() const +{ + if (!m_titleItem) return QBrush(); + return m_titleItem->brush(); +} + +void ChartPresenter::setBackgroundVisible(bool visible) +{ + createBackgroundItem(); + m_backgroundItem->setVisible(visible); +} - if(m_chartRect!=chartRect && chartRect.isValid()){ - m_chartRect=chartRect; - emit geometryChanged(m_chartRect); - } - if (oldChargMargins != m_chartMargins) - emit marginsChanged(m_chartMargins); +bool ChartPresenter::isBackgroundVisible() const +{ + if (!m_backgroundItem) return false; + return m_backgroundItem->isVisible(); } -void ChartPresenter::createChartBackgroundItem() +void ChartPresenter::setBackgroundDropShadowEnabled(bool enabled) { - if (!m_backgroundItem) { - m_backgroundItem = new ChartBackground(rootItem()); - m_backgroundItem->setPen(Qt::NoPen); - m_backgroundItem->setZValue(ChartPresenter::BackgroundZValue); - } + createBackgroundItem(); + m_backgroundItem->setDropShadowEnabled(enabled); } -void ChartPresenter::createChartTitleItem() +bool ChartPresenter::isBackgroundDropShadowEnabled() const { - if (!m_titleItem) { - m_titleItem = new QGraphicsSimpleTextItem(rootItem()); - m_titleItem->setZValue(ChartPresenter::BackgroundZValue); - } + if (!m_backgroundItem) return false; + return m_backgroundItem->isDropShadowEnabled(); } -void ChartPresenter::handleAnimationFinished() + +QGraphicsLayout* ChartPresenter::layout() { - m_animations.removeAll(qobject_cast(sender())); - if(m_animations.empty()) emit animationsFinished(); + return m_layout; } -void ChartPresenter::startAnimation(ChartAnimation* animation) +void ChartPresenter::setMarginsMinimum(const QRectF& margins) { - if (animation->state() != QAbstractAnimation::Stopped) animation->stop(); - QObject::connect(animation, SIGNAL(finished()),this,SLOT(handleAnimationFinished()),Qt::UniqueConnection); - if(!m_animations.isEmpty()){ - m_animations.append(animation); - } - QTimer::singleShot(0, animation, SLOT(start())); + Q_UNUSED(margins); + // m_layout->setMarginsMinimum(margins); +} + +QRectF ChartPresenter::margins() const +{ + return QRectF();//m_layout->margins(); +} + +QLegend* ChartPresenter::legend() +{ + return m_chart->legend(); +} + +QList ChartPresenter::axisItems() const +{ + return m_axisItems.values(); +} + +void ChartPresenter::setVisible(bool visible) +{ + m_chart->setVisible(visible); } #include "moc_chartpresenter_p.cpp" diff --git a/src/chartpresenter_p.h b/src/chartpresenter_p.h index fdae5e7..20ff531 100644 --- a/src/chartpresenter_p.h +++ b/src/chartpresenter_p.h @@ -45,6 +45,7 @@ class ChartTheme; class ChartAnimator; class ChartBackground; class ChartAnimation; +class ChartLayout; class ChartPresenter: public QObject { @@ -80,6 +81,34 @@ public: ChartTheme *chartTheme() const { return m_chartTheme; } ChartDataSet *dataSet() const { return m_dataset; } QGraphicsItem* rootItem() const { return m_chart; } + QGraphicsRectItem* backgroundItem(); + QGraphicsItem* titleItem(); + QList axisItems() const; + + QLegend* legend(); + + void setBackgroundBrush(const QBrush& brush); + QBrush backgroundBrush() const; + + void setBackgroundPen(const QPen& pen); + QPen backgroundPen() const; + + void setTitle(const QString& title); + QString title() const; + + void setTitleFont(const QFont& font); + QFont titleFont() const; + + void setTitleBrush(const QBrush &brush); + QBrush titleBrush() const; + + void setBackgroundVisible(bool visible); + bool isBackgroundVisible() const; + + void setBackgroundDropShadowEnabled(bool enabled); + bool isBackgroundDropShadowEnabled() const; + + void setVisible(bool visible); void setTheme(QChart::ChartTheme theme,bool force = true); QChart::ChartTheme theme(); @@ -93,28 +122,27 @@ public: void scroll(qreal dx,qreal dy); void setGeometry(const QRectF& rect); - QRectF chartGeometry() const { return m_chartRect; } - - void setMinimumMarginHeight(ChartAxis* axis, qreal height); - void setMinimumMarginWidth(ChartAxis* axis, qreal width); - qreal minimumLeftMargin() const { return m_minLeftMargin; } - qreal minimumBottomMargin() const { return m_minBottomMargin; } + QRectF geometry() { return m_rect; } void startAnimation(ChartAnimation* animation); State state() const { return m_state; } QPointF statePoint() const { return m_statePoint; } -public: //TODO: fix me + void resetAllElements(); - void createChartBackgroundItem(); - void createChartTitleItem(); - QRectF margins() const { return m_chartMargins;} + + void setMarginsMinimum(const QRectF& margins); + QRectF margins() const; + QGraphicsLayout* layout(); + +private: + void createBackgroundItem(); + void createTitleItem(); public Q_SLOTS: void handleSeriesAdded(QAbstractSeries* series,Domain* domain); void handleSeriesRemoved(QAbstractSeries* series); void handleAxisAdded(QAxis* axis,Domain* domain); void handleAxisRemoved(QAxis* axis); - void updateLayout(); private Q_SLOTS: void handleAnimationFinished(); @@ -132,22 +160,13 @@ private: QMap m_chartItems; QMap m_axisItems; QRectF m_rect; - QRectF m_chartRect; QChart::AnimationOptions m_options; - qreal m_minLeftMargin; - qreal m_minBottomMargin; State m_state; QPointF m_statePoint; QList m_animations; - -public: //TODO: fixme + ChartLayout* m_layout; ChartBackground* m_backgroundItem; QGraphicsSimpleTextItem* m_titleItem; - int m_marginBig; - int m_marginSmall; - int m_marginTiny; - QRectF m_chartMargins; - QRectF m_legendMargins; }; QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/legend/legend.pri b/src/legend/legend.pri index 6353ba7..9aea390 100644 --- a/src/legend/legend.pri +++ b/src/legend/legend.pri @@ -3,12 +3,14 @@ DEPENDPATH += $$PWD SOURCES += \ $$PWD/qlegend.cpp \ - $$PWD/legendmarker.cpp + $$PWD/legendmarker.cpp \ + $$PWD/legendlayout.cpp PRIVATE_HEADERS += \ $$PWD/legendmarker_p.h \ $$PWD/legendscroller_p.h \ - $$PWD/qlegend_p.h + $$PWD/qlegend_p.h \ + $$PWD/legendlayout_p.h PUBLIC_HEADERS += \ diff --git a/src/legend/legendlayout.cpp b/src/legend/legendlayout.cpp new file mode 100644 index 0000000..4fee146 --- /dev/null +++ b/src/legend/legendlayout.cpp @@ -0,0 +1,348 @@ +#include "legendlayout_p.h" +#include "chartpresenter_p.h" +#include "legendmarker_p.h" +#include "qlegend_p.h" +#include +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +LegendLayout::LegendLayout(QLegend* legend): +m_legend(legend) +{ + +} + +LegendLayout::~LegendLayout() +{ + +} + +void LegendLayout::setOffset(qreal x, qreal y) +{ + bool scrollHorizontal = true; + switch(m_legend->alignment()) { + case Qt::AlignTop: + case Qt::AlignBottom: { + scrollHorizontal = true; + break; + } + case Qt::AlignLeft: + case Qt::AlignRight: { + scrollHorizontal = false; + break; + } + } + + // If detached, the scrolling direction is vertical instead of horizontal and vice versa. + if (!m_legend->isAttachedToChart()) { + scrollHorizontal = !scrollHorizontal; + } + + QRectF boundingRect = geometry(); + + // Limit offset between m_minOffset and m_maxOffset + if (scrollHorizontal) { + if(m_width<=boundingRect.width()) return; + + if (x != m_offsetX) { + m_offsetX = qBound(m_minOffsetX, x, m_maxOffsetX); + m_legend->d_ptr->items()->setPos(-m_offsetX,boundingRect.top()); + } + } + else { + if(m_height<=boundingRect.height()) return; + + if (y != m_offsetY) { + m_offsetY = qBound(m_minOffsetY, y, m_maxOffsetY); + m_legend->d_ptr->items()->setPos(boundingRect.left(),-m_offsetY); + } + } +} + +QPointF LegendLayout::offset() const +{ + return QPointF(m_offsetX,m_offsetY); +} + +void LegendLayout::setGeometry(const QRectF& rect) +{ + if (!rect.isValid()) return; + + QGraphicsLayout::setGeometry(rect); + + if(m_legend->isAttachedToChart()) { + setAttachedGeometry(rect); + } + else { + setDettachedGeometry(rect); + } +} + +void LegendLayout::setAttachedGeometry(const QRectF& rect) +{ + + m_offsetX=0; + m_offsetY=0; + + QSizeF size(0,0); + + if( m_legend->d_ptr->markers().isEmpty()) return; + + m_width=0; + m_height=0; + + 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(QPoint(0,0),marker->effectiveSizeHint(Qt::PreferredSize))); + marker->setPos(point.x(),rect.height()/2 - marker->boundingRect().height()/2); + const QRectF& rect = marker->boundingRect(); + size = size.expandedTo(rect.size()); + qreal w = rect.width(); + m_width+=w; + point.setX(point.x() + w); + } + } + if(m_widthd_ptr->items()->setPos(rect.width()/2-m_width/2,rect.top()); + + } + else { + m_legend->d_ptr->items()->setPos(rect.topLeft()); + } + m_height=size.height(); + } + break; + case Qt::AlignLeft: + case Qt::AlignRight: { + QPointF point(0,0); + foreach (LegendMarker* marker, m_legend->d_ptr->markers()) { + if (marker->isVisible()) { + marker->setGeometry(QRectF(QPoint(0,0),marker->effectiveSizeHint(Qt::PreferredSize))); + marker->setPos(point); + const QRectF& rect = marker->boundingRect(); + qreal h = rect.height(); + size = size.expandedTo(rect.size()); + m_height+=h; + point.setY(point.y() + h); + } + } + if(m_heightd_ptr->items()->setPos(rect.left(),rect.height()/2-m_height/2); + } + else { + m_legend->d_ptr->items()->setPos(rect.topLeft()); + } + m_width=size.width(); + } + break; + } + + m_minOffsetX = 0; + m_minOffsetY = 0; + m_maxOffsetX = m_width - rect.width(); + m_maxOffsetY = m_height - rect.height(); +} + +void LegendLayout::setDettachedGeometry(const QRectF& rect) +{ + // Detached layout is different. + // In detached mode legend may have multiple rows and columns, so layout calculations + // differ a log from attached mode. + // Also the scrolling logic is bit different. + + m_offsetX=0; + m_offsetY=0; + + QSizeF size(0,0); + + if( m_legend->d_ptr->markers().isEmpty()) return; + + QList items = m_legend->d_ptr->items()->childItems(); + + switch (m_legend->alignment()) { + case Qt::AlignTop: { + QPointF point = rect.topLeft(); + m_width = 0; + m_height = 0; + for (int i=0; iisVisible()) { + const QRectF& boundingRect = item->boundingRect(); + qreal w = boundingRect.width(); + qreal h = boundingRect.height(); + m_width = qMax(m_width,w); + m_height = qMax(m_height,h); + item->setPos(point.x(),point.y()); + point.setX(point.x() + w); + if (point.x() + w > rect.topLeft().x() + rect.width()) { + // Next item would go off rect. + point.setX(rect.topLeft().x()); + point.setY(point.y() + h); + if (i+1 < items.count()) { + m_height += h; + } + } + } + } + m_legend->d_ptr->items()->setPos(rect.topLeft()); + + m_minOffsetX = 0; + m_minOffsetY = 0; + m_maxOffsetX = m_width - rect.width(); + m_maxOffsetY = m_height - rect.height(); + } + break; + case Qt::AlignBottom: { + QPointF point = rect.bottomLeft(); + m_width = 0; + m_height = 0; + for (int i=0; iisVisible()) { + const QRectF& boundingRect = item->boundingRect(); + qreal w = boundingRect.width(); + qreal h = boundingRect.height(); + m_width = qMax(m_width,w); + m_height = qMax(m_height,h); + item->setPos(point.x(),point.y() - h); + point.setX(point.x() + w); + if (point.x() + w > rect.bottomLeft().x() + rect.width()) { + // Next item would go off rect. + point.setX(rect.bottomLeft().x()); + point.setY(point.y() - h); + if (i+1 < items.count()) { + m_height += h; + } + } + } + } + m_legend->d_ptr->items()->setPos(rect.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; + } + break; + case Qt::AlignLeft: { + QPointF point = rect.topLeft(); + m_width = 0; + m_height = 0; + qreal maxWidth = 0; + for (int i=0; iisVisible()) { + const QRectF& boundingRect = item->boundingRect(); + qreal w = boundingRect.width(); + qreal h = boundingRect.height(); + m_height = qMax(m_height,h); + maxWidth = qMax(maxWidth,w); + item->setPos(point.x(),point.y()); + point.setY(point.y() + h); + if (point.y() + h > rect.topLeft().y() + rect.height()) { + // Next item would go off rect. + point.setX(point.x() + maxWidth); + point.setY(rect.topLeft().y()); + if (i+1 < items.count()) { + m_width += maxWidth; + maxWidth = 0; + } + } + } + } + m_width += maxWidth; + m_legend->d_ptr->items()->setPos(rect.topLeft()); + + m_minOffsetX = 0; + m_minOffsetY = 0; + m_maxOffsetX = m_width - rect.width(); + m_maxOffsetY = m_height - rect.height(); + } + break; + case Qt::AlignRight: { + QPointF point = rect.topRight(); + m_width = 0; + m_height = 0; + qreal maxWidth = 0; + for (int i=0; iisVisible()) { + const QRectF& boundingRect = item->boundingRect(); + qreal w = boundingRect.width(); + qreal h = boundingRect.height(); + m_height = qMax(m_height,h); + maxWidth = qMax(maxWidth,w); + item->setPos(point.x() - w,point.y()); + point.setY(point.y() + h); + if (point.y() + h > rect.topLeft().y() + rect.height()) { + // Next item would go off rect. + point.setX(point.x() - maxWidth); + point.setY(rect.topLeft().y()); + if (i+1 < items.count()) { + m_width += maxWidth; + maxWidth = 0; + } + } + } + } + m_width += maxWidth; + m_legend->d_ptr->items()->setPos(rect.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(); + } + break; + default: + break; + } + +} + +QSizeF LegendLayout::sizeHint ( Qt::SizeHint which, const QSizeF & constraint) const +{ + QSizeF size(0, 0); + qreal left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + + if(constraint.isValid()) { + foreach(LegendMarker* marker, m_legend->d_ptr->markers()) { + size = size.expandedTo(marker->effectiveSizeHint(which)); + } + size = size.boundedTo(constraint); + } + else if (constraint.width() >= 0) { + qreal width = 0; + qreal height = 0; + foreach(LegendMarker* marker, m_legend->d_ptr->markers()) { + width+=marker->effectiveSizeHint(which).width(); + height=qMax(height,marker->effectiveSizeHint(which).height()); + } + + size = QSizeF(qMin(constraint.width(),width), height); + } + else if (constraint.height() >= 0) { + qreal width = 0; + qreal height = 0; + foreach(LegendMarker* marker, m_legend->d_ptr->markers()) { + width=qMax(width,marker->effectiveSizeHint(which).width()); + height+=height,marker->effectiveSizeHint(which).height(); + } + size = QSizeF(width,qMin(constraint.height(),height)); + } + else { + foreach(LegendMarker* marker, m_legend->d_ptr->markers()) { + size = size.expandedTo(marker->effectiveSizeHint(which)); + } + } + size += QSize(left + right, top + bottom); + return size; +} + +QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/legend/legendlayout_p.h b/src/legend/legendlayout_p.h new file mode 100644 index 0000000..3ab8605 --- /dev/null +++ b/src/legend/legendlayout_p.h @@ -0,0 +1,50 @@ +#ifndef LEGENDLAYOUT_H_ +#define LEGENDLAYOUT_H_ +#include +#include "qchartglobal.h" + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +class QLegend; + +class LegendLayout : public QGraphicsLayout +{ +public: + + LegendLayout(QLegend* legend); + virtual ~LegendLayout(); + + void setGeometry(const QRectF& rect); + + void setOffset(qreal x, qreal y); + QPointF offset() const; + +protected: + QSizeF sizeHint ( Qt::SizeHint which, const QSizeF & constraint = QSizeF() ) const; + int count() const { return 0; } + QGraphicsLayoutItem* itemAt(int) const { return 0; }; + void removeAt(int){}; + +private: + void setAttachedGeometry(const QRectF& rect); + void setDettachedGeometry(const QRectF& rect); + +private: + QLegend* m_legend; + int m_marginBig; + int m_marginSmall; + int m_marginTiny; + qreal m_offsetX; + qreal m_offsetY; + qreal m_minOffsetX; + qreal m_minOffsetY; + qreal m_maxOffsetX; + qreal m_maxOffsetY; + qreal m_width; + qreal m_height; + +}; + +QTCOMMERCIALCHART_END_NAMESPACE + +#endif diff --git a/src/legend/legendmarker.cpp b/src/legend/legendmarker.cpp index 296519e..7107ffc 100644 --- a/src/legend/legendmarker.cpp +++ b/src/legend/legendmarker.cpp @@ -43,17 +43,18 @@ LegendMarker::LegendMarker(QAbstractSeries *series, QLegend *legend) : m_boundingRect(0,0,0,0), m_legend(legend), m_textItem(new QGraphicsSimpleTextItem(this)), - m_rectItem(new QGraphicsRectItem(this)) + m_rectItem(new QGraphicsRectItem(this)), + m_margin(2), + m_space(4) { //setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton); m_rectItem->setRect(m_markerRect); - updateLayout(); } void LegendMarker::setPen(const QPen &pen) { m_rectItem->setPen(pen); - updateLayout(); + m_textItem->setPen(pen); } QPen LegendMarker::pen() const @@ -74,7 +75,6 @@ QBrush LegendMarker::brush() const void LegendMarker::setFont(const QFont &font) { m_textItem->setFont(font); - updateLayout(); } QFont LegendMarker::font() const @@ -85,23 +85,21 @@ QFont LegendMarker::font() const void LegendMarker::setLabel(const QString label) { m_textItem->setText(label); - updateLayout(); } -void LegendMarker::setSize(const QSize& size) +QString LegendMarker::label() const { - m_markerRect = QRectF(0,0,size.width(),size.height()); + return m_textItem->text(); } -QString LegendMarker::label() const +QRectF LegendMarker::boundingRect() const { - return m_textItem->text(); + return m_boundingRect; } void LegendMarker::setLabelBrush(const QBrush &brush) { m_textItem->setBrush(brush); - updateLayout(); } QBrush LegendMarker::labelBrush() const @@ -109,6 +107,18 @@ QBrush LegendMarker::labelBrush() const return m_textItem->brush(); } + +void LegendMarker::setGeometry(const QRectF& rect) +{ + const QRectF& textRect = m_textItem->boundingRect(); + + m_textItem->setPos(m_markerRect.width() + m_space + m_margin,rect.height()/2 - textRect.height()/2); + m_rectItem->setPos(m_margin,rect.height()/2 - m_markerRect.height()/2); + + prepareGeometryChange(); + m_boundingRect = rect; +} + void LegendMarker::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option) @@ -116,23 +126,26 @@ void LegendMarker::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti Q_UNUSED(painter) } -QRectF LegendMarker::boundingRect() const -{ - return m_boundingRect; -} -void LegendMarker::updateLayout() +QSizeF LegendMarker::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const { + Q_UNUSED(constraint) - static const qreal margin = 2; - static const qreal space = 4; + QFontMetrics fn(m_textItem->font()); + QSizeF sh; - const QRectF& textRect = m_textItem->boundingRect(); - prepareGeometryChange(); - m_boundingRect = QRectF(0,0,m_markerRect.width() + 2*margin + space + textRect.width(),qMax(m_markerRect.height()+2*margin,textRect.height()+2*margin)); - m_textItem->setPos(m_markerRect.width() + space + margin,m_boundingRect.height()/2 - textRect.height()/2); - m_rectItem->setPos(margin,m_boundingRect.height()/2 - m_markerRect.height()/2); + switch (which) { + case Qt::MinimumSize: + sh = QSizeF(fn.boundingRect("...").width(),fn.height()); + 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)); + break; + default: + break; + } + return sh; } void LegendMarker::mousePressEvent(QGraphicsSceneMouseEvent *event) diff --git a/src/legend/legendmarker_p.h b/src/legend/legendmarker_p.h index 87ed0d9..1327be7 100644 --- a/src/legend/legendmarker_p.h +++ b/src/legend/legendmarker_p.h @@ -35,6 +35,7 @@ #include #include #include +#include QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -47,35 +48,37 @@ class QPieSlice; class QLegend; class QPieSeries; -class LegendMarker : public QGraphicsObject +class LegendMarker : public QGraphicsObject, public QGraphicsLayoutItem { Q_OBJECT - + Q_INTERFACES(QGraphicsLayoutItem) public: explicit LegendMarker(QAbstractSeries *m_series, QLegend *parent); void setPen(const QPen &pen); QPen pen() const; + void setBrush(const QBrush &brush); QBrush brush() const; void setFont(const QFont &font); QFont font() const; - void setSize(const QSize& size); - void setLabel(const QString label); QString label() const; + void setLabelBrush(const QBrush &brush); QBrush labelBrush() const; QAbstractSeries *series() const { return m_series;} - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + void setGeometry(const QRectF& rect); QRectF boundingRect() const; - void updateLayout(); + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + QSizeF sizeHint (Qt::SizeHint which, const QSizeF& constraint) const; protected: // From QGraphicsObject @@ -91,6 +94,8 @@ protected: QLegend* m_legend; QGraphicsSimpleTextItem *m_textItem; QGraphicsRectItem *m_rectItem; + qreal m_margin; + qreal m_space; }; diff --git a/src/legend/qlegend.cpp b/src/legend/qlegend.cpp index 7502e93..5e32ae3 100644 --- a/src/legend/qlegend.cpp +++ b/src/legend/qlegend.cpp @@ -23,7 +23,7 @@ #include "qabstractseries.h" #include "qabstractseries_p.h" #include "qchart_p.h" - +#include "legendlayout_p.h" #include "legendmarker_p.h" #include "qxyseries.h" #include "qlineseries.h" @@ -41,7 +41,7 @@ #include #include #include - +#include #include QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -190,6 +190,7 @@ d_ptr(new QLegendPrivate(chart->d_ptr->m_presenter,chart,this)) QObject::connect(chart->d_ptr->m_dataset,SIGNAL(seriesAdded(QAbstractSeries*,Domain*)),d_ptr.data(),SLOT(handleSeriesAdded(QAbstractSeries*,Domain*))); QObject::connect(chart->d_ptr->m_dataset,SIGNAL(seriesRemoved(QAbstractSeries*)),d_ptr.data(),SLOT(handleSeriesRemoved(QAbstractSeries*))); QObject::connect(chart->d_ptr->m_dataset,SIGNAL(seriesUpdated(QAbstractSeries*)),d_ptr.data(),SLOT(handleSeriesUpdated(QAbstractSeries*))); + setLayout(d_ptr->m_layout); } /*! @@ -212,16 +213,10 @@ void QLegend::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q painter->setPen(d_ptr->m_pen); painter->setBrush(d_ptr->m_brush); painter->drawRoundRect(rect(),d_ptr->roundness(rect().width()),d_ptr->roundness(rect().height())); -} -/*! - \internal - */ -QRectF QLegend::boundingRect() const -{ - return d_ptr->m_rect; } + /*! Sets the \a brush of legend. Brush affects the background of legend. */ @@ -277,6 +272,23 @@ QPen QLegend::pen() const return d_ptr->m_pen; } +void QLegend::setFont(const QFont &font) +{ + if (d_ptr->m_font != font) { + d_ptr->m_font = font; + + foreach (LegendMarker *marker, d_ptr->markers()) { + marker->setFont(d_ptr->m_font); + } + emit fontChanged(font); + } +} + +QFont QLegend::font() const +{ + return d_ptr->m_font; +} + void QLegend::setBorderColor(QColor color) { QPen p = d_ptr->m_pen; @@ -292,26 +304,18 @@ QColor QLegend::borderColor() return d_ptr->m_pen.color(); } -void QLegend::setFont(const QFont &font) -{ - if (d_ptr->m_font != font) { - d_ptr->setFont(font); - emit fontChanged(font); - } -} - -QFont QLegend::font() const -{ - return d_ptr->m_font; -} - /*! Set brush used to draw labels to \a brush. */ void QLegend::setLabelBrush(const QBrush &brush) { if (d_ptr->m_labelBrush != brush) { - d_ptr->setLabelBrush(brush); + + d_ptr->m_labelBrush = brush; + + foreach (LegendMarker *marker, d_ptr->markers()) { + marker->setLabelBrush(d_ptr->m_labelBrush); + } emit labelBrushChanged(brush); } } @@ -340,11 +344,17 @@ QColor QLegend::labelColor() const return d_ptr->m_labelBrush.color(); } + void QLegend::setAlignment(Qt::Alignment alignment) { if(d_ptr->m_alignment!=alignment) { d_ptr->m_alignment = alignment; - d_ptr->updateLayout(); + updateGeometry(); + if(isAttachedToChart()){ + d_ptr->m_presenter->layout()->invalidate(); + }else{ + layout()->invalidate(); + } } } @@ -359,6 +369,9 @@ Qt::Alignment QLegend::alignment() const void QLegend::detachFromChart() { d_ptr->m_attachedToChart = false; + d_ptr->m_layout->invalidate(); + setParent(0); + } /*! @@ -366,7 +379,9 @@ void QLegend::detachFromChart() */ void QLegend::attachToChart() { - d_ptr->attachToChart(); + d_ptr->m_attachedToChart = true; + d_ptr->m_layout->invalidate(); + setParent(d_ptr->m_chart); } /*! @@ -400,24 +415,10 @@ bool QLegend::isBackgroundVisible() const /*! \internal \a event see QGraphicsWidget for details */ -void QLegend::resizeEvent(QGraphicsSceneResizeEvent *event) -{ - const QRectF& rect = QRectF(QPoint(0,0),event->newSize()); - QGraphicsWidget::resizeEvent(event); - if(d_ptr->m_rect != rect) { - d_ptr->m_rect = rect; - d_ptr->updateLayout(); - } -} - -/*! - \internal \a event see QGraphicsWidget for details - */ void QLegend::hideEvent(QHideEvent *event) { QGraphicsWidget::hideEvent(event); - setEnabled(false); - d_ptr->updateLayout(); + d_ptr->m_presenter->layout()->invalidate(); } /*! @@ -426,18 +427,7 @@ void QLegend::hideEvent(QHideEvent *event) void QLegend::showEvent(QShowEvent *event) { QGraphicsWidget::showEvent(event); - setEnabled(true); - d_ptr->updateLayout(); -} - -qreal QLegend::minWidth() const -{ - return d_ptr->m_minWidth; -} - -qreal QLegend::minHeight() const -{ - return d_ptr->m_minHeight; + d_ptr->m_presenter->layout()->invalidate(); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -445,18 +435,13 @@ qreal QLegend::minHeight() const QLegendPrivate::QLegendPrivate(ChartPresenter* presenter, QChart *chart, QLegend *q): q_ptr(q), m_presenter(presenter), + m_layout(new LegendLayout(q)), m_chart(chart), - m_markers(new QGraphicsItemGroup(q)), + m_items(new QGraphicsItemGroup(q)), m_alignment(Qt::AlignTop), m_brush(QBrush()), m_pen(QPen()), m_labelBrush(QBrush()), - m_offsetX(0), - m_offsetY(0), - m_minWidth(0), - m_minHeight(0), - m_width(0), - m_height(0), m_diameter(5), m_attachedToChart(true), m_backgroundVisible(false) @@ -471,290 +456,12 @@ QLegendPrivate::~QLegendPrivate() void QLegendPrivate::setOffset(qreal x, qreal y) { - bool scrollHorizontal = true; - switch(m_alignment) { - case Qt::AlignTop: - case Qt::AlignBottom: { - scrollHorizontal = true; - break; - } - case Qt::AlignLeft: - case Qt::AlignRight: { - scrollHorizontal = false; - break; - } - } - - // If detached, the scrolling direction is vertical instead of horizontal and vice versa. - if (!m_attachedToChart) { - scrollHorizontal = !scrollHorizontal; - } - - // Limit offset between m_minOffset and m_maxOffset - if (scrollHorizontal) { - if(m_width<=m_rect.width()) return; - - if (x != m_offsetX) { - m_offsetX = qBound(m_minOffsetX, x, m_maxOffsetX); - m_markers->setPos(-m_offsetX,m_rect.top()); - } - } else { - if(m_height<=m_rect.height()) return; - - if (y != m_offsetY) { - m_offsetY = qBound(m_minOffsetY, y, m_maxOffsetY); - m_markers->setPos(m_rect.left(),-m_offsetY); - } - } + m_layout->setOffset(x,y); } QPointF QLegendPrivate::offset() const { - return QPointF(m_offsetX,m_offsetY); -} - -void QLegendPrivate::updateLayout() -{ - if (!m_attachedToChart) { - updateDetachedLayout(); - return; - } - - m_offsetX=0; - QList items = m_markers->childItems(); - - if(items.isEmpty()) return; - - m_minWidth=0; - m_minHeight=0; - - switch(m_alignment) { - - case Qt::AlignTop: - case Qt::AlignBottom: { - QPointF point = m_rect.topLeft(); - m_width = 0; - foreach (QGraphicsItem *item, items) { - if (item->isVisible()) { - item->setPos(point.x(),m_rect.height()/2 -item->boundingRect().height()/2); - const QRectF& rect = item->boundingRect(); - qreal w = rect.width(); - m_minWidth=qMax(m_minWidth,w); - m_minHeight=qMax(m_minHeight,rect.height()); - m_width+=w; - point.setX(point.x() + w); - } - } - if(m_widthsetPos(m_rect.width()/2-m_width/2,m_rect.top()); - } - else { - m_markers->setPos(m_rect.topLeft()); - } - m_height=m_minHeight; - } - break; - case Qt::AlignLeft: - case Qt::AlignRight: { - QPointF point = m_rect.topLeft(); - m_height = 0; - foreach (QGraphicsItem *item, items) { - if (item->isVisible()) { - item->setPos(point); - const QRectF& rect = item->boundingRect(); - qreal h = rect.height(); - m_minWidth=qMax(m_minWidth,rect.width()); - m_minHeight=qMax(m_minHeight,h); - m_height+=h; - point.setY(point.y() + h); - } - } - if(m_heightsetPos(m_rect.left(),m_rect.height()/2-m_height/2); - } - else { - m_markers->setPos(m_rect.topLeft()); - } - m_width=m_minWidth; - } - break; - } - - m_minOffsetX = 0; - m_minOffsetY = 0; - m_maxOffsetX = m_width - m_rect.width(); - m_maxOffsetY = m_height - m_rect.height(); - - m_presenter->updateLayout(); -} - -void QLegendPrivate::updateDetachedLayout() -{ - // Detached layout is different. - // In detached mode legend may have multiple rows and columns, so layout calculations - // differ a log from attached mode. - // Also the scrolling logic is bit different. - m_offsetX=0; - m_offsetY=0; - QList items = m_markers->childItems(); - - if(items.isEmpty()) return; - - m_minWidth = 0; - m_minHeight = 0; - - switch (m_alignment) { - case Qt::AlignTop: { - QPointF point = m_rect.topLeft(); - m_width = 0; - m_height = 0; - for (int i=0; iisVisible()) { - const QRectF& rect = item->boundingRect(); - qreal w = rect.width(); - qreal h = rect.height(); - m_minWidth = qMax(m_minWidth,w); - m_minHeight = qMax(m_minHeight,rect.height()); - m_height = qMax(m_height,h); - item->setPos(point.x(),point.y()); - point.setX(point.x() + w); - if (point.x() + w > m_rect.topLeft().x() + m_rect.width()) { - // Next item would go off rect. - point.setX(m_rect.topLeft().x()); - point.setY(point.y() + h); - if (i+1 < items.count()) { - m_height += h; - } - } - } - } - m_markers->setPos(m_rect.topLeft()); - m_width = m_minWidth; - - m_minOffsetX = 0; - m_minOffsetY = 0; - m_maxOffsetX = m_width - m_rect.width(); - m_maxOffsetY = m_height - m_rect.height(); - } - break; - case Qt::AlignBottom: { - QPointF point = m_rect.bottomLeft(); - m_width = 0; - m_height = 0; - for (int i=0; iisVisible()) { - const QRectF& rect = item->boundingRect(); - qreal w = rect.width(); - qreal h = rect.height(); - m_minWidth = qMax(m_minWidth,w); - m_minHeight = qMax(m_minHeight,rect.height()); - m_height = qMax(m_height,h); - item->setPos(point.x(),point.y() - h); - point.setX(point.x() + w); - if (point.x() + w > m_rect.bottomLeft().x() + m_rect.width()) { - // Next item would go off rect. - point.setX(m_rect.bottomLeft().x()); - point.setY(point.y() - h); - if (i+1 < items.count()) { - m_height += h; - } - } - } - } - m_markers->setPos(m_rect.topLeft()); - m_width = m_minWidth; - - m_minOffsetX = 0; - m_minOffsetY = qMin(m_rect.topLeft().y(), m_rect.topLeft().y() - m_height + m_rect.height()); - m_maxOffsetX = m_width - m_rect.width(); - m_maxOffsetY = 0; - } - break; - case Qt::AlignLeft: { - QPointF point = m_rect.topLeft(); - m_width = 0; - m_height = 0; - qreal maxWidth = 0; - for (int i=0; iisVisible()) { - const QRectF& rect = item->boundingRect(); - qreal w = rect.width(); - qreal h = rect.height(); - m_minWidth = qMax(m_minWidth,rect.width()); - m_minHeight = qMax(m_minHeight,h); - maxWidth = qMax(maxWidth,w); - item->setPos(point.x(),point.y()); - point.setY(point.y() + h); - if (point.y() + h > m_rect.topLeft().y() + m_rect.height()) { - // Next item would go off rect. - point.setX(point.x() + maxWidth); - point.setY(m_rect.topLeft().y()); - if (i+1 < items.count()) { - m_width += maxWidth; - maxWidth = 0; - } - } - } - } - m_width += maxWidth; - m_markers->setPos(m_rect.topLeft()); - m_height = m_minHeight; - - m_minOffsetX = 0; - m_minOffsetY = 0; - m_maxOffsetX = m_width - m_rect.width(); - m_maxOffsetY = m_height - m_rect.height(); - } - break; - case Qt::AlignRight: { - QPointF point = m_rect.topRight(); - m_width = 0; - m_height = 0; - qreal maxWidth = 0; - for (int i=0; iisVisible()) { - const QRectF& rect = item->boundingRect(); - qreal w = rect.width(); - qreal h = rect.height(); - m_minWidth = qMax(m_minWidth,rect.width()); - m_minHeight = qMax(m_minHeight,h); - maxWidth = qMax(maxWidth,w); - item->setPos(point.x() - w,point.y()); - point.setY(point.y() + h); - if (point.y() + h > m_rect.topLeft().y() + m_rect.height()) { - // Next item would go off rect. - point.setX(point.x() - maxWidth); - point.setY(m_rect.topLeft().y()); - if (i+1 < items.count()) { - m_width += maxWidth; - maxWidth = 0; - } - } - } - } - m_width += maxWidth; - m_markers->setPos(m_rect.topLeft()); - m_height = m_minHeight; - - m_minOffsetX = qMin(m_rect.topLeft().x(), m_rect.topLeft().x() - m_width + m_rect.width()); - m_minOffsetY = 0; - m_maxOffsetX = 0; - m_maxOffsetY = m_height - m_rect.height(); - } - break; - default: - break; - } -} - -void QLegendPrivate::attachToChart() -{ - m_attachedToChart = true; - q_ptr->setParent(m_chart); + return m_layout->offset(); } int QLegendPrivate::roundness(qreal size) @@ -762,39 +469,17 @@ int QLegendPrivate::roundness(qreal size) return 100*m_diameter/int(size); } -void QLegendPrivate::setFont(const QFont &font) -{ - m_font = font; - QList items = m_markers->childItems(); - - foreach (QGraphicsItem *markers, items) { - LegendMarker *marker = static_cast(markers); - marker->setFont(m_font); - } - updateLayout(); -} - -void QLegendPrivate::setLabelBrush(const QBrush &brush) -{ - m_labelBrush = brush; - QList items = m_markers->childItems(); - - foreach (QGraphicsItem *markers, items) { - LegendMarker *marker = static_cast(markers); - marker->setLabelBrush(m_labelBrush); - } - updateLayout(); -} - void QLegendPrivate::handleSeriesAdded(QAbstractSeries *series, Domain *domain) { Q_UNUSED(domain) QList markers = series->d_ptr->createLegendMarker(q_ptr); + foreach(LegendMarker* marker, markers) { marker->setFont(m_font); marker->setLabelBrush(m_labelBrush); - m_markers->addToGroup(marker); + m_items->addToGroup(marker); + m_markers<)), this, SLOT(handleUpdatePieSeries())); } - updateLayout(); + q_ptr->layout()->invalidate(); } void QLegendPrivate::handleSeriesRemoved(QAbstractSeries *series) { - QList items = m_markers->childItems(); - - foreach (QGraphicsItem *markers, items) { - LegendMarker *marker = static_cast(markers); + foreach (LegendMarker *marker, m_markers) { if (marker->series() == series) { delete marker; + m_markers.removeAll(marker); } } @@ -826,7 +509,7 @@ void QLegendPrivate::handleSeriesRemoved(QAbstractSeries *series) QObject::disconnect(pieSeries, SIGNAL(removed(QList)), this, SLOT(handleUpdatePieSeries())); } - updateLayout(); + q_ptr->layout()->invalidate(); } void QLegendPrivate::handleSeriesUpdated(QAbstractSeries *series) @@ -850,19 +533,16 @@ void QLegendPrivate::handleUpdatePieSeries() void QLegendPrivate::handleSeriesVisibleChanged() { QAbstractSeries* series = qobject_cast (sender()); - QList items = m_markers->childItems(); - foreach (QGraphicsItem *markers, items) { - LegendMarker *marker = static_cast(markers); + foreach (LegendMarker* marker, m_markers) { if (marker->series() == series) { marker->setVisible(!marker->isVisible()); } } - updateLayout(); + q_ptr->layout()->invalidate(); } - #include "moc_qlegend.cpp" #include "moc_qlegend_p.cpp" diff --git a/src/legend/qlegend.h b/src/legend/qlegend.h index ace9d42..2284952 100644 --- a/src/legend/qlegend.h +++ b/src/legend/qlegend.h @@ -57,7 +57,6 @@ public: ~QLegend(); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - QRectF boundingRect() const; void setBrush(const QBrush &brush); QBrush brush() const; @@ -84,14 +83,11 @@ public: void attachToChart(); bool isAttachedToChart(); - qreal minWidth() const; - qreal minHeight() const; - void setBackgroundVisible(bool visible = true); bool isBackgroundVisible() const; + protected: - void resizeEvent(QGraphicsSceneResizeEvent *event); void hideEvent(QHideEvent *event); void showEvent(QShowEvent *event); @@ -107,6 +103,8 @@ private: QScopedPointer d_ptr; Q_DISABLE_COPY(QLegend) friend class LegendScroller; + friend class LegendLayout; + friend class ChartLayout; }; QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/legend/qlegend_p.h b/src/legend/qlegend_p.h index 4a00b7b..7964b3f 100644 --- a/src/legend/qlegend_p.h +++ b/src/legend/qlegend_p.h @@ -37,6 +37,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE class QChart; class ChartPresenter; class QAbstractSeries; +class LegendLayout; class QLegendPrivate : public QObject { @@ -47,12 +48,10 @@ public: void setOffset(qreal x, qreal y); QPointF offset() const; - void updateLayout(); - void updateDetachedLayout(); - void attachToChart(); int roundness(qreal size); - void setFont(const QFont &font); - void setLabelBrush(const QBrush &brush); + + QList markers() { return m_markers; } + QGraphicsItemGroup* items() { return m_items; } public Q_SLOTS: void handleSeriesAdded(QAbstractSeries *series, Domain *domain); @@ -64,24 +63,16 @@ public Q_SLOTS: private: QLegend *q_ptr; ChartPresenter *m_presenter; + LegendLayout *m_layout; QChart* m_chart; - QGraphicsItemGroup* m_markers; + QGraphicsItemGroup* m_items; + QList m_markers; Qt::Alignment m_alignment; QBrush m_brush; QPen m_pen; QFont m_font; QBrush m_labelBrush; - QRectF m_rect; - qreal m_offsetX; - qreal m_offsetY; - qreal m_minOffsetX; - qreal m_minOffsetY; - qreal m_maxOffsetX; - qreal m_maxOffsetY; - qreal m_minWidth; - qreal m_minHeight; - qreal m_width; - qreal m_height; + qreal m_diameter; bool m_attachedToChart; bool m_backgroundVisible; diff --git a/src/qchart.cpp b/src/qchart.cpp index 35a0940..31c1426 100644 --- a/src/qchart.cpp +++ b/src/qchart.cpp @@ -26,6 +26,7 @@ #include "qaxis.h" #include #include +#include QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -117,7 +118,8 @@ QChart::QChart(QGraphicsItem *parent, Qt::WindowFlags wFlags) : QGraphicsWidget( d_ptr->createConnections(); d_ptr->m_legend = new LegendScroller(this); d_ptr->m_presenter->setTheme(QChart::ChartThemeLight, false); - connect(d_ptr->m_presenter, SIGNAL(marginsChanged(QRectF)), this, SIGNAL(marginsChanged(QRectF))); + //connect(d_ptr->m_presenter, SIGNAL(marginsChanged(QRectF)), this, SIGNAL(marginsChanged(QRectF))); + setLayout(d_ptr->m_presenter->layout()); } /*! @@ -126,6 +128,7 @@ QChart::QChart(QGraphicsItem *parent, Qt::WindowFlags wFlags) : QGraphicsWidget( QChart::~QChart() { //delete first presenter , since this is a root of all the graphical items + setLayout(0); delete d_ptr->m_presenter; d_ptr->m_presenter=0; } @@ -170,10 +173,7 @@ void QChart::removeAllSeries() */ void QChart::setBackgroundBrush(const QBrush& brush) { - //TODO: refactor me - d_ptr->m_presenter->createChartBackgroundItem(); - d_ptr->m_presenter->m_backgroundItem->setBrush(brush); - d_ptr->m_presenter->m_backgroundItem->update(); + d_ptr->m_presenter->setBackgroundBrush(brush); } /*! @@ -181,9 +181,7 @@ void QChart::setBackgroundBrush(const QBrush& brush) */ QBrush QChart::backgroundBrush() const { - //TODO: refactor me - if (!d_ptr->m_presenter->m_backgroundItem) return QBrush(); - return (d_ptr->m_presenter->m_backgroundItem)->brush(); + return d_ptr->m_presenter->backgroundBrush(); } /*! @@ -191,10 +189,7 @@ QBrush QChart::backgroundBrush() const */ void QChart::setBackgroundPen(const QPen& pen) { - //TODO: refactor me - d_ptr->m_presenter->createChartBackgroundItem(); - d_ptr->m_presenter->m_backgroundItem->setPen(pen); - d_ptr->m_presenter->m_backgroundItem->update(); + d_ptr->m_presenter->setBackgroundPen(pen); } /*! @@ -202,9 +197,7 @@ void QChart::setBackgroundPen(const QPen& pen) */ QPen QChart::backgroundPen() const { - //TODO: refactor me - if (!d_ptr->m_presenter->m_backgroundItem) return QPen(); - return d_ptr->m_presenter->m_backgroundItem->pen(); + return d_ptr->m_presenter->backgroundPen(); } /*! @@ -212,10 +205,7 @@ QPen QChart::backgroundPen() const */ void QChart::setTitle(const QString& title) { - //TODO: refactor me - d_ptr->m_presenter->createChartTitleItem(); - d_ptr->m_presenter->m_titleItem->setText(title); - d_ptr->m_presenter->updateLayout(); + d_ptr->m_presenter->setTitle(title); } /*! @@ -223,11 +213,7 @@ void QChart::setTitle(const QString& title) */ QString QChart::title() const { - //TODO: refactor me - if (d_ptr->m_presenter->m_titleItem) - return d_ptr->m_presenter->m_titleItem->text(); - else - return QString(); + return d_ptr->m_presenter->title(); } /*! @@ -235,10 +221,7 @@ QString QChart::title() const */ void QChart::setTitleFont(const QFont& font) { - //TODO: refactor me - d_ptr->m_presenter->createChartTitleItem(); - d_ptr->m_presenter->m_titleItem->setFont(font); - d_ptr->m_presenter->updateLayout(); + d_ptr->m_presenter->setTitleFont(font); } /*! @@ -246,10 +229,7 @@ void QChart::setTitleFont(const QFont& font) */ QFont QChart::titleFont() const { - if (d_ptr->m_presenter->m_titleItem) - return d_ptr->m_presenter->m_titleItem->font(); - else - return QFont(); + return d_ptr->m_presenter->titleFont(); } /*! @@ -257,10 +237,7 @@ QFont QChart::titleFont() const */ void QChart::setTitleBrush(const QBrush &brush) { - //TODO: refactor me - d_ptr->m_presenter->createChartTitleItem(); - d_ptr->m_presenter->m_titleItem->setBrush(brush); - d_ptr->m_presenter->updateLayout(); + d_ptr->m_presenter->setTitleBrush(brush); } /*! @@ -268,9 +245,7 @@ void QChart::setTitleBrush(const QBrush &brush) */ QBrush QChart::titleBrush() const { - //TODO: refactor me - if (!d_ptr->m_presenter->m_titleItem) return QBrush(); - return d_ptr->m_presenter->m_titleItem->brush(); + return d_ptr->m_presenter->titleBrush(); } void QChart::setTheme(QChart::ChartTheme theme) @@ -364,16 +339,9 @@ QRectF QChart::margins() const return d_ptr->m_presenter->margins(); } - /*! - Resizes and updates the chart area using the \a event data + Sets animation \a options for the chart */ -void QChart::resizeEvent(QGraphicsSceneResizeEvent *event) -{ - d_ptr->m_rect = QRectF(QPoint(0,0),event->newSize()); - QGraphicsWidget::resizeEvent(event); - d_ptr->m_presenter->setGeometry(d_ptr->m_rect); -} void QChart::setAnimationOptions(AnimationOptions options) { @@ -390,7 +358,7 @@ QChart::AnimationOptions QChart::animationOptions() const */ void QChart::scrollLeft() { - d_ptr->m_presenter->scroll(-d_ptr->m_presenter->chartGeometry().width()/(axisX()->ticksCount()-1),0); + d_ptr->m_presenter->scroll(-d_ptr->m_presenter->geometry().width()/(axisX()->ticksCount()-1),0); } /*! @@ -398,7 +366,7 @@ void QChart::scrollLeft() */ void QChart::scrollRight() { - d_ptr->m_presenter->scroll(d_ptr->m_presenter->chartGeometry().width()/(axisX()->ticksCount()-1),0); + d_ptr->m_presenter->scroll(d_ptr->m_presenter->geometry().width()/(axisX()->ticksCount()-1),0); } /*! @@ -406,7 +374,7 @@ void QChart::scrollRight() */ void QChart::scrollUp() { - d_ptr->m_presenter->scroll(0,d_ptr->m_presenter->chartGeometry().width()/(axisY()->ticksCount()-1)); + d_ptr->m_presenter->scroll(0,d_ptr->m_presenter->geometry().width()/(axisY()->ticksCount()-1)); } /*! @@ -414,7 +382,7 @@ void QChart::scrollUp() */ void QChart::scrollDown() { - d_ptr->m_presenter->scroll(0,-d_ptr->m_presenter->chartGeometry().width()/(axisY()->ticksCount()-1)); + d_ptr->m_presenter->scroll(0,-d_ptr->m_presenter->geometry().width()/(axisY()->ticksCount()-1)); } /*! @@ -427,32 +395,22 @@ void QChart::scroll(const QPointF &delta) void QChart::setBackgroundVisible(bool visible) { - //TODO: refactor me - d_ptr->m_presenter->createChartBackgroundItem(); - d_ptr->m_presenter->m_backgroundItem->setVisible(visible); + d_ptr->m_presenter->setBackgroundVisible(visible); } bool QChart::isBackgroundVisible() const { - //TODO: refactor me - if (!d_ptr->m_presenter->m_backgroundItem) - return false; - - return d_ptr->m_presenter->m_backgroundItem->isVisible(); + return d_ptr->m_presenter->isBackgroundVisible(); } void QChart::setDropShadowEnabled(bool enabled) { - d_ptr->m_presenter->createChartBackgroundItem(); - d_ptr->m_presenter->m_backgroundItem->setDropShadowEnabled(enabled); + d_ptr->m_presenter->setBackgroundDropShadowEnabled(enabled); } bool QChart::isDropShadowEnabled() const { - if (!d_ptr->m_presenter->m_backgroundItem) - return false; - - return d_ptr->m_presenter->m_backgroundItem->isDropShadowEnabled(); + return d_ptr->m_presenter->isBackgroundDropShadowEnabled(); } /*! @@ -465,6 +423,11 @@ QList QChart::series() const return d_ptr->m_dataset->series(); } +void QChart::setMarginsMinimum(const QRectF& margins) +{ + d_ptr->m_presenter->setMarginsMinimum(margins); +} + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// QChartPrivate::QChartPrivate(): @@ -486,6 +449,7 @@ void QChartPrivate::createConnections() QObject::connect(m_dataset,SIGNAL(seriesRemoved(QAbstractSeries*)),m_presenter,SLOT(handleSeriesRemoved(QAbstractSeries*))); QObject::connect(m_dataset,SIGNAL(axisAdded(QAxis*,Domain*)),m_presenter,SLOT(handleAxisAdded(QAxis*,Domain*))); QObject::connect(m_dataset,SIGNAL(axisRemoved(QAxis*)),m_presenter,SLOT(handleAxisRemoved(QAxis*))); + //QObject::connect(m_presenter, SIGNAL(marginsChanged(QRectF)), q_ptr, SIGNAL(marginsChanged(QRectF))); } #include "moc_qchart.cpp" diff --git a/src/qchart.h b/src/qchart.h index 581b475..86e05dc 100644 --- a/src/qchart.h +++ b/src/qchart.h @@ -111,15 +111,14 @@ public: QAxis* axisY(QAbstractSeries* series = 0) const; QLegend* legend() const; + + void setMarginsMinimum(const QRectF& margins); QRectF margins() const; Q_SIGNALS: void marginsChanged(QRectF newMargins); protected: - void resizeEvent(QGraphicsSceneResizeEvent *event); - -protected: QScopedPointer d_ptr; friend class QLegend; friend class ChartPresenter; diff --git a/src/qchart_p.h b/src/qchart_p.h index 3fbf74b..59ee1a0 100644 --- a/src/qchart_p.h +++ b/src/qchart_p.h @@ -42,7 +42,6 @@ struct QChartPrivate { QChartPrivate(); ~QChartPrivate(); - QRectF m_rect; QLegend* m_legend; ChartDataSet *m_dataset; ChartPresenter *m_presenter; diff --git a/src/src.pro b/src/src.pro index ba6ebf9..aa91f24 100644 --- a/src/src.pro +++ b/src/src.pro @@ -43,7 +43,8 @@ SOURCES += \ $$PWD/qabstractseries.cpp \ $$PWD/chartbackground.cpp \ $$PWD/chart.cpp \ - $$PWD/scroller.cpp + $$PWD/scroller.cpp \ + $$PWD/chartlayout.cpp PRIVATE_HEADERS += \ $$PWD/chartdataset_p.h \ $$PWD/chartitem_p.h \ @@ -56,7 +57,8 @@ PRIVATE_HEADERS += \ $$PWD/qchart_p.h \ $$PWD/qchartview_p.h \ $$PWD/scroller_p.h \ - $$PWD/qabstractseries_p.h + $$PWD/qabstractseries_p.h \ + $$PWD/chartlayout_p.h PUBLIC_HEADERS += \ $$PWD/qchart.h \ $$PWD/qchartglobal.h \