From e561e621da223902346d192b9e4c9a1f2e89da74 2012-04-03 14:28:30 From: Michal Klocek Date: 2012-04-03 14:28:30 Subject: [PATCH] Refactor qledgend handling * rewrite some parts to fix the graphics artefacts * remove button hadnling * adds scroller * adds layout managmnet to presenter * fix issues of layout --- diff --git a/demos/chartthemes/themewidget.cpp b/demos/chartthemes/themewidget.cpp index bc3a68e..90ef4cb 100644 --- a/demos/chartthemes/themewidget.cpp +++ b/demos/chartthemes/themewidget.cpp @@ -60,6 +60,7 @@ ThemeWidget::ThemeWidget(QWidget* parent) : settingsLayout->addWidget(m_themeComboBox); settingsLayout->addWidget(new QLabel("Animation:")); settingsLayout->addWidget(m_animatedComboBox); + settingsLayout->addWidget(new QLabel("Legend:")); settingsLayout->addWidget(m_legendComboBox); settingsLayout->addWidget(m_antialiasCheckBox); settingsLayout->addStretch(); @@ -98,6 +99,7 @@ ThemeWidget::ThemeWidget(QWidget* parent) : // Set defaults m_antialiasCheckBox->setChecked(true); + updateUI(); } ThemeWidget::~ThemeWidget() @@ -164,7 +166,7 @@ QComboBox* ThemeWidget::createAnimationBox() const QComboBox* ThemeWidget::createLegendBox() const { QComboBox* legendComboBox = new QComboBox(); - legendComboBox->addItem("Legend None", -1); + legendComboBox->addItem("No Legend ", 0); legendComboBox->addItem("Legend Top", QLegend::AlignmentTop); legendComboBox->addItem("Legend Bottom", QLegend::AlignmentBottom); legendComboBox->addItem("Legend Left", QLegend::AlignmentLeft); @@ -355,17 +357,17 @@ void ThemeWidget::updateUI() chartView->chart()->setAnimationOptions(options); } - int alignment(m_legendComboBox->itemData(m_legendComboBox->currentIndex()).toInt()); - if (alignment == -1) { + QLegend::Alignments alignment(m_legendComboBox->itemData(m_legendComboBox->currentIndex()).toInt()); + + if (!alignment) { foreach (QChartView *chartView, m_charts) { - chartView->chart()->legend()->setVisible(false); + chartView->chart()->legend()->hide(); } - } else { - QLegend::Alignments legendAlignment(alignment); + } + else foreach (QChartView *chartView, m_charts) { - chartView->chart()->legend()->setAlignmnent(legendAlignment); - chartView->chart()->legend()->setVisible(true); + chartView->chart()->legend()->setAlignmnent(alignment); + chartView->chart()->legend()->show(); } - } } diff --git a/src/areachart/qareaseries.h b/src/areachart/qareaseries.h index 839ab6a..08d6f66 100644 --- a/src/areachart/qareaseries.h +++ b/src/areachart/qareaseries.h @@ -58,6 +58,7 @@ public: // from QChartSeries Q_SIGNALS: void updated(); void clicked(const QPointF &point); + void selected(); private: QBrush m_brush; diff --git a/src/axis/axisitem.cpp b/src/axis/axisitem.cpp index 8d39801..2079f98 100644 --- a/src/axis/axisitem.cpp +++ b/src/axis/axisitem.cpp @@ -283,6 +283,9 @@ void Axis::setLayout(QVector &layout) Q_ASSERT(labels.size() == ticksList.size()); Q_ASSERT(layout.size() == ticksList.size()); + qreal minWidth = 0; + qreal minHeight = 0; + switch (m_type) { case X_AXIS: @@ -296,12 +299,18 @@ void Axis::setLayout(QVector &layout) QGraphicsSimpleTextItem *labelItem = static_cast(labels.at(i)); if (!categories || i<1) { labelItem->setText(ticksList.at(i)); - QPointF center = labelItem->boundingRect().center(); + 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); } else { labelItem->setText(ticksList.at(i)); - QPointF center = labelItem->boundingRect().center(); + 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); } @@ -313,6 +322,7 @@ void Axis::setLayout(QVector &layout) lineItem = static_cast(axis.at(i+1)); lineItem->setLine(layout[i],m_rect.bottom(),layout[i],m_rect.bottom()+5); } + } break; @@ -328,14 +338,20 @@ void Axis::setLayout(QVector &layout) if (!categories || i<1) { labelItem->setText(ticksList.at(i)); - QPointF center = labelItem->boundingRect().center(); + 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() - labelItem->boundingRect().width() - label_padding , layout[i]-center.y()); + labelItem->setPos(m_rect.left() - rect.width() - label_padding , layout[i]-center.y()); } else { labelItem->setText(ticksList.at(i)); - QPointF center = labelItem->boundingRect().center(); + const QRectF& rect = labelItem->boundingRect(); + minWidth=qMax(rect.width(),minWidth); + minHeight+=rect.height(); + QPointF center = rect.center(); labelItem->setTransformOriginPoint(center.x(), center.y()); - labelItem->setPos(m_rect.left() - labelItem->boundingRect().width() - label_padding , layout[i] - (layout[i] - layout[i-1])/2 -center.y()); + labelItem->setPos(m_rect.left() - rect.width() - label_padding , layout[i] - (layout[i] - layout[i-1])/2 -center.y()); } if ((i+1)%2 && i>1) { @@ -352,7 +368,11 @@ void Axis::setLayout(QVector &layout) break; } - m_layoutVector=layout; + m_layoutVector=layout; + + presenter()->setMinimumMarginWidth(this,minWidth); + presenter()->setMinimumMarginHeight(this,minHeight); + } bool Axis::isEmpty() @@ -425,10 +445,13 @@ void Axis::handleRangeChanged(qreal min, qreal max,int tickCount) void Axis::handleGeometryChanged(const QRectF &rect) { - m_rect = rect; - if (isEmpty()) return; - QVector layout = calculateLayout(); - updateLayout(layout); + if(m_rect != rect) + { + m_rect = rect; + if (isEmpty()) return; + QVector layout = calculateLayout(); + updateLayout(layout); + } } void Axis::axisSelected() diff --git a/src/axis/axisitem_p.h b/src/axis/axisitem_p.h index 1e49797..bdcf1d1 100644 --- a/src/axis/axisitem_p.h +++ b/src/axis/axisitem_p.h @@ -21,6 +21,7 @@ #ifndef AXISITEM_H_ #define AXISITEM_H_ +#include "qchartglobal.h" #include "chart_p.h" #include @@ -100,7 +101,6 @@ private: qreal m_min; qreal m_max; int m_ticksCount; - qreal m_zoomFactor; friend class AxisAnimation; friend class AxisItem; diff --git a/src/barchart/qbarseries.h b/src/barchart/qbarseries.h index cf4744a..6f67cce 100644 --- a/src/barchart/qbarseries.h +++ b/src/barchart/qbarseries.h @@ -78,7 +78,7 @@ public: Q_SIGNALS: void clicked(QBarSet *barset, QString category, Qt::MouseButtons button); // Up to user of api, what to do with these signals - + void selected(); // void updatedBars(); void restructuredBars(); diff --git a/src/chartpresenter.cpp b/src/chartpresenter.cpp index d1f4314..509f794 100644 --- a/src/chartpresenter.cpp +++ b/src/chartpresenter.cpp @@ -19,6 +19,7 @@ ****************************************************************************/ #include "qchart.h" +#include "qchart_p.h" #include "qchartaxis.h" #include "chartpresenter_p.h" #include "chartdataset_p.h" @@ -51,10 +52,17 @@ ChartPresenter::ChartPresenter(QChart* chart,ChartDataSet* dataset):QObject(char m_animator(0), m_dataset(dataset), m_chartTheme(0), - m_rect(QRectF(QPoint(0,0),m_chart->size())), + m_chartRect(QRectF(QPoint(0,0),m_chart->size())), m_options(QChart::NoAnimation), m_themeForce(false), - m_backgroundPadding(10) + m_minLeftMargin(0), + m_minBottomMargin(0), + m_backgroundItem(0), + m_titleItem(0), + m_marginBig(60), + m_marginSmall(20), + m_marginTiny(10), + m_chartMargins(QRect(m_marginBig,m_marginBig,0,0)) { createConnections(); setTheme(QChart::ChartThemeLight, false); @@ -67,39 +75,65 @@ ChartPresenter::~ChartPresenter() void ChartPresenter::createConnections() { - QObject::connect(m_chart,SIGNAL(geometryChanged()),this,SLOT(handleGeometryChanged())); QObject::connect(m_dataset,SIGNAL(seriesAdded(QSeries*,Domain*)),this,SLOT(handleSeriesAdded(QSeries*,Domain*))); QObject::connect(m_dataset,SIGNAL(seriesRemoved(QSeries*)),this,SLOT(handleSeriesRemoved(QSeries*))); QObject::connect(m_dataset,SIGNAL(axisAdded(QChartAxis*,Domain*)),this,SLOT(handleAxisAdded(QChartAxis*,Domain*))); QObject::connect(m_dataset,SIGNAL(axisRemoved(QChartAxis*)),this,SLOT(handleAxisRemoved(QChartAxis*))); } -void ChartPresenter::handleGeometryChanged() +void ChartPresenter::setGeometry(const QRectF& rect) { - QRectF rect(QPoint(0,0),m_chart->size()); - QRectF padding = m_chart->padding(); - rect.adjust(padding.left(), padding.top(), -padding.right(), -padding.bottom()); - - //rewrite zoom stack - /* - for(int i=0;iaxisType()){ + case Axis::X_AXIS: + { + if(width>m_chartRect.width()+ m_chartMargins.left()) { + m_minLeftMargin= width - m_chartRect.width(); + updateLayout(); + } + break; + } + case Axis::Y_AXIS: + { + + if(m_minLeftMargin!=width){ + m_minLeftMargin= width; + updateLayout(); + } + break; + } + + } +} + +void ChartPresenter::setMinimumMarginHeight(Axis* axis, qreal height) +{ + switch(axis->axisType()){ + case Axis::X_AXIS: + { + if(m_minBottomMargin!=height) { + m_minBottomMargin= height; + updateLayout(); + } + break; + } + case Axis::Y_AXIS: + { + + if(height>m_chartMargins.bottom()+m_chartRect.height()){ + m_minBottomMargin= height - m_chartRect.height(); + updateLayout(); + } + break; + } + + } } void ChartPresenter::handleAxisAdded(QChartAxis* axis,Domain* domain) @@ -126,7 +160,7 @@ void ChartPresenter::handleAxisAdded(QChartAxis* axis,Domain* domain) QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&))); //initialize - item->handleGeometryChanged(m_rect); + item->handleGeometryChanged(m_chartRect); m_axisItems.insert(axis, item); } @@ -265,7 +299,7 @@ void ChartPresenter::handleSeriesAdded(QSeries* series,Domain* domain) //initialize item->handleDomainChanged(domain->minX(),domain->maxX(),domain->minY(),domain->maxY()); - if(m_rect.isValid()) item->handleGeometryChanged(m_rect); + if(m_chartRect.isValid()) item->handleGeometryChanged(m_chartRect); m_chartItems.insert(series,item); } @@ -334,23 +368,23 @@ void ChartPresenter::resetAllElements() void ChartPresenter::zoomIn() { - QRectF rect = geometry(); + QRectF rect = chartGeometry(); rect.setWidth(rect.width()/2); rect.setHeight(rect.height()/2); - rect.moveCenter(geometry().center()); + rect.moveCenter(chartGeometry().center()); zoomIn(rect); } void ChartPresenter::zoomIn(const QRectF& rect) { QRectF r = rect.normalized(); - r.translate(-m_chart->padding().topLeft()); + r.translate(-m_chartMargins.topLeft()); if(m_animator) { - QPointF point(r.center().x()/geometry().width(),r.center().y()/geometry().height()); + QPointF point(r.center().x()/chartGeometry().width(),r.center().y()/chartGeometry().height()); m_animator->setState(ChartAnimator::ZoomInState,point); } - m_dataset->zoomInDomain(r,geometry().size()); + m_dataset->zoomInDomain(r,chartGeometry().size()); if(m_animator) { m_animator->setState(ChartAnimator::ShowState); } @@ -363,9 +397,9 @@ void ChartPresenter::zoomOut() m_animator->setState(ChartAnimator::ZoomOutState); } - QSizeF size = geometry().size(); - QRectF rect = geometry(); - rect.translate(-m_chart->padding().topLeft()); + QSizeF size = chartGeometry().size(); + QRectF rect = chartGeometry(); + rect.translate(-m_chartMargins.topLeft()); m_dataset->zoomOutDomain(rect.adjusted(size.width()/4,size.height()/4,-size.width()/4,-size.height()/4),size); //m_dataset->zoomOutDomain(m_zoomStack[m_zoomIndex-1],geometry().size()); @@ -383,7 +417,7 @@ void ChartPresenter::scroll(int dx,int dy) if(dy>0) m_animator->setState(ChartAnimator::ScrollDownState,QPointF()); } - m_dataset->scrollDomain(dx,dy,geometry().size()); + m_dataset->scrollDomain(dx,dy,chartGeometry().size()); if(m_animator){ m_animator->setState(ChartAnimator::ShowState); @@ -395,6 +429,104 @@ QChart::AnimationOptions ChartPresenter::animationOptions() const return m_options; } +void ChartPresenter::updateLayout() +{ + if (!m_rect.isValid()) return; + + // recalculate title size + + QSize titleSize; + int titlePadding=0; + + if (m_titleItem) { + titleSize= m_titleItem->boundingRect().size().toSize(); + } + + //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; + + QLegend* legend = m_chart->d_ptr->m_legend; + + // recalculate legend position + if (legend->isAttachedToChart() && legend->isEnabled()) { + + QRect legendRect; + + // Reserve some space for legend + switch (legend->alignment()) { + + case QLegend::AlignmentTop: { + 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 QLegend::AlignmentBottom: { + 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 QLegend::AlignmentLeft: { + int ledgendSize = legend->minWidht(); + 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 QLegend::AlignmentRight: { + int ledgendSize = legend->minWidht(); + 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; + } + } + } + + // recalculate title position + if (m_titleItem) { + QPointF center = m_rect.center() -m_titleItem->boundingRect().center(); + m_titleItem->setPos(center.x(),titlePadding); + } + + //recalculate background gradient + if (m_backgroundItem) { + m_backgroundItem->setRect(m_rect.adjusted(m_marginTiny,m_marginTiny, -m_marginTiny, -m_marginTiny)); + } + + m_chartRect = m_rect.adjusted(m_chartMargins.left(),m_chartMargins.top(),-m_chartMargins.right(),-m_chartMargins.bottom()); + + emit geometryChanged(m_chartRect); + legend->setGeometry(m_rect.adjusted(m_legendMargins.left(),m_legendMargins.top(),-m_legendMargins.right(),-m_legendMargins.bottom())); +} + +void ChartPresenter::createChartBackgroundItem() +{ + if (!m_backgroundItem) { + m_backgroundItem = new ChartBackground(rootItem()); + m_backgroundItem->setPen(Qt::NoPen); + m_backgroundItem->setZValue(ChartPresenter::BackgroundZValue); + } +} + +void ChartPresenter::createChartTitleItem() +{ + if (!m_titleItem) { + m_titleItem = new QGraphicsSimpleTextItem(rootItem()); + m_titleItem->setZValue(ChartPresenter::BackgroundZValue); + } +} #include "moc_chartpresenter_p.cpp" diff --git a/src/chartpresenter_p.h b/src/chartpresenter_p.h index a8bcf87..338980f 100644 --- a/src/chartpresenter_p.h +++ b/src/chartpresenter_p.h @@ -22,6 +22,7 @@ #define CHARTPRESENTER_H_ #include "qchartglobal.h" +#include "chartbackground_p.h" //TODO fix me #include "qchart.h" //becouse of QChart::ChartThemeId //TODO #include "qchartaxis.h" #include @@ -55,8 +56,6 @@ public: ChartPresenter(QChart* chart,ChartDataSet *dataset); virtual ~ChartPresenter(); - int backgroundPadding() const { return m_backgroundPadding; } - QRectF geometry() const { return m_rect; } ChartAnimator* animator() const { return m_animator; } ChartTheme *chartTheme() const { return m_chartTheme; } ChartDataSet *dataSet() const { return m_dataset; } @@ -73,20 +72,32 @@ public: void zoomOut(); void scroll(int dx,int dy); -private: + void setGeometry(const QRectF& rect); + QRectF chartGeometry() const { return m_chartRect; } + + void setMinimumMarginHeight(Axis* axis, qreal height); + void setMinimumMarginWidth(Axis* axis, qreal width); + qreal minimumLeftMargin() const { return m_minLeftMargin; } + qreal minimumBottomMargin() const { return m_minBottomMargin; } + +public: //TODO: fix me void createConnections(); void resetAllElements(); + void createChartBackgroundItem(); + void createChartTitleItem(); + QRect margins() const { return m_chartMargins;} public Q_SLOTS: void handleSeriesAdded(QSeries* series,Domain* domain); void handleSeriesRemoved(QSeries* series); void handleAxisAdded(QChartAxis* axis,Domain* domain); void handleAxisRemoved(QChartAxis* axis); - void handleGeometryChanged(); + void updateLayout(); Q_SIGNALS: void geometryChanged(const QRectF& rect); + private: QChart* m_chart; ChartAnimator* m_animator; @@ -95,9 +106,19 @@ private: QMap m_chartItems; QMap m_axisItems; QRectF m_rect; + QRectF m_chartRect; QChart::AnimationOptions m_options; bool m_themeForce; - int m_backgroundPadding; + qreal m_minLeftMargin; + qreal m_minBottomMargin; +public: //TODO: fixme + ChartBackground* m_backgroundItem; + QGraphicsSimpleTextItem* m_titleItem; + int m_marginBig; + int m_marginSmall; + int m_marginTiny; + QRect m_chartMargins; + QRect m_legendMargins; }; diff --git a/src/charttheme.cpp b/src/charttheme.cpp index b76d1ab..c56a94a 100644 --- a/src/charttheme.cpp +++ b/src/charttheme.cpp @@ -176,7 +176,6 @@ void ChartTheme::decorate(QBarSeries* series, int index, bool force) takeAtPos += step; takeAtPos -= (int) takeAtPos; } - qDebug() << "pos:" << takeAtPos; if (brush == sets.at(i)->brush() || force ) sets.at(i)->setBrush(colorAt(m_seriesGradients.at(colorIndex), takeAtPos)); diff --git a/src/legendmarker.cpp b/src/legendmarker.cpp index 82da551..0418b12 100644 --- a/src/legendmarker.cpp +++ b/src/legendmarker.cpp @@ -1,25 +1,27 @@ /**************************************************************************** -** -** 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 "qchartglobal.h" + ** + ** 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 "legendmarker_p.h" +#include "qlegend.h" +#include "qbarseries.h" +#include "qpieseries.h" #include #include #include @@ -30,95 +32,61 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE -LegendMarker::LegendMarker(QSeries *series, QGraphicsItem *parent) : QGraphicsObject(parent), - m_pos(0,0), - m_size(0,0), - m_boundingRect(0,0,0,0), - m_markerBoundingRect(0,0,0,0), - m_series(series), - m_barset(0), - m_pieslice(0), - m_textItem(new QGraphicsSimpleTextItem(this)) -{ - setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton); -} - -LegendMarker::LegendMarker(QSeries *series, QBarSet *barset, QGraphicsItem *parent) : QGraphicsObject(parent), - m_pos(0,0), - m_size(0,0), - m_boundingRect(0,0,0,0), - m_markerBoundingRect(0,0,0,0), - m_series(series), - m_barset(barset), - m_pieslice(0), - m_textItem(new QGraphicsSimpleTextItem(this)) +LegendMarker::LegendMarker(QSeries* series,QLegend *legend) : QGraphicsObject(legend), +m_series(series), +m_markerRect(0,0,10.0,10.0), +m_boundingRect(0,0,0,0), +m_legend(legend), +m_textItem(new QGraphicsSimpleTextItem(this)), +m_rectItem(new QGraphicsRectItem(this)) { - setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton); -} - -LegendMarker::LegendMarker(QSeries *series, QPieSlice *pieslice, QGraphicsItem *parent) : QGraphicsObject(parent), - m_pos(0,0), - m_size(0,0), - m_boundingRect(0,0,0,0), - m_markerBoundingRect(0,0,0,0), - m_series(series), - m_barset(0), - m_pieslice(pieslice), - m_textItem(new QGraphicsSimpleTextItem(this)) -{ - setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton); -} - -void LegendMarker::setPos(qreal x, qreal y) -{ - m_pos = QPointF(x,y); - layoutChanged(); + //setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton); + m_rectItem->setRect(m_markerRect); + updateLayout(); } void LegendMarker::setPen(const QPen &pen) { - m_pen = pen; + m_textItem->setPen(pen); + updateLayout(); } QPen LegendMarker::pen() const { - return m_pen; + return m_textItem->pen(); } void LegendMarker::setBrush(const QBrush &brush) { - m_brush = brush; + m_rectItem->setBrush(brush); } QBrush LegendMarker::brush() const { - return m_brush; + return m_rectItem->brush(); } -void LegendMarker::setName(const QString name) +void LegendMarker::setLabel(const QString name) { m_textItem->setText(name); - layoutChanged(); + updateLayout(); } -QString LegendMarker::name() const +void LegendMarker::setSize(const QSize& size) { - return m_textItem->text(); + m_markerRect = QRectF(0,0,size.width(),size.height()); } -QSeries* LegendMarker::series() const +QString LegendMarker::label() const { - return m_series; + return m_textItem->text(); } void LegendMarker::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option) Q_UNUSED(widget) - - painter->setPen(m_pen); - painter->setBrush(m_brush); - painter->drawRect(m_markerBoundingRect); + Q_UNUSED(painter) } QRectF LegendMarker::boundingRect() const @@ -126,86 +94,96 @@ QRectF LegendMarker::boundingRect() const return m_boundingRect; } -void LegendMarker::layoutChanged() +void LegendMarker::updateLayout() { - QSizeF markerSize(10,10); - qreal margin = 2; - - m_size.setHeight(markerSize.height() + 2 * margin); - m_size.setWidth(m_textItem->boundingRect().width() + markerSize.width() + 3 * margin); - m_boundingRect = QRectF(m_pos.x(),m_pos.y(),m_size.width(),m_size.height()); + static const qreal margin = 2; + static const qreal space = 4; - m_markerBoundingRect = QRectF(m_pos.x() + margin, m_pos.y() + margin, markerSize.width(),markerSize.height()); + 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); - m_textItem->setPos(m_pos.x() + markerSize.width() + 2 * margin, m_pos.y() + margin); } void LegendMarker::mousePressEvent(QGraphicsSceneMouseEvent *event) { - switch (m_series->type()) { - case QSeries::SeriesTypeLine: - case QSeries::SeriesTypeArea: - case QSeries::SeriesTypeScatter: - case QSeries::SeriesTypeSpline: { - emit clicked(m_series,event->button()); - break; - } - case QSeries::SeriesTypeBar: - case QSeries::SeriesTypeStackedBar: - case QSeries::SeriesTypePercentBar: { - emit clicked(m_barset,event->button()); - break; - } - case QSeries::SeriesTypePie: { - emit clicked(m_pieslice,event->button()); - break; - } - default: { - break; - } - } + QGraphicsObject::mousePressEvent(event); + emit selected(); } -void LegendMarker::changed() +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +AreaLegendMarker::AreaLegendMarker(QAreaSeries *series,QLegend *legend) : LegendMarker(series,legend), +m_series(series) { - setPen(Qt::NoPen); - switch (m_series->type()) { - case QSeries::SeriesTypeArea: { - QAreaSeries* s = static_cast (m_series); - setBrush(s->brush()); - setName(s->name()); - break; - } - case QSeries::SeriesTypeLine: - case QSeries::SeriesTypeSpline: { - QXYSeries* s = static_cast (m_series); - setBrush(QBrush(s->pen().color(),Qt::SolidPattern)); - setName(s->name()); - break; - } - case QSeries::SeriesTypeScatter: { - QXYSeries* s = static_cast (m_series); - setBrush(s->brush()); - setName(s->name()); - break; + QObject::connect(this, SIGNAL(selected()), series, SIGNAL(selected())); + QObject::connect(series,SIGNAL(updated()), this, SLOT(updated())); + updated(); +} + +void AreaLegendMarker::updated() +{ + setBrush(m_series->brush()); + setLabel(m_series->name()); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +BarLegendMarker::BarLegendMarker(QBarSeries *series,QBarSet *barset, QLegend *legend) : LegendMarker(series,legend), +m_barset(barset) +{ + QObject::connect(this, SIGNAL(selected()),series, SIGNAL(selected())); + QObject::connect(barset, SIGNAL(valueChanged()), this, SLOT(updated())); + updated(); +} + +void BarLegendMarker::updated() +{ + setBrush(m_barset->brush()); + setLabel(m_barset->name()); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +PieLegendMarker::PieLegendMarker(QPieSeries* series,QPieSlice *pieslice, QLegend *legend) : LegendMarker(series,legend), +m_pieslice(pieslice) +{ + QObject::connect(this, SIGNAL(selected()),pieslice, SIGNAL(selected())); + QObject::connect(pieslice, SIGNAL(changed()), this, SLOT(updated())); + QObject::connect(pieslice, SIGNAL(destroyed()), this, SLOT(deleteLater())); //TODO:checkthis + updated(); +} + +void PieLegendMarker::updated() +{ + setBrush(m_pieslice->brush()); + setLabel(m_pieslice->label()); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +XYLegendMarker::XYLegendMarker(QXYSeries *series, QLegend *legend) : LegendMarker(series,legend), +m_series(series) +{ + QObject::connect(this, SIGNAL(selected()), series, SIGNAL(selected())); + QObject::connect(series,SIGNAL(updated()), this, SLOT(updated())); + updated(); +} + +void XYLegendMarker::updated() +{ + setLabel(m_series->name()); + + if(m_series->type()== QSeries::SeriesTypeScatter) + { + setBrush(m_series->brush()); + } - case QSeries::SeriesTypeBar: - case QSeries::SeriesTypeStackedBar: - case QSeries::SeriesTypePercentBar: { - setBrush(m_barset->brush()); - setName(m_barset->name()); - break; - } - case QSeries::SeriesTypePie: { - setBrush(m_pieslice->brush()); - setName(m_pieslice->label()); - break; - } - default: { - setBrush(Qt::NoBrush); - break; - } + else { + setBrush(QBrush(m_series->pen().color())); } } diff --git a/src/legendmarker_p.h b/src/legendmarker_p.h index 5b37078..ae776c1 100644 --- a/src/legendmarker_p.h +++ b/src/legendmarker_p.h @@ -30,64 +30,98 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE class QSeries; +class QAreaSeries; +class QXYSeries; class QBarSet; +class QBarSeries; class QPieSlice; +class QLegend; +class QPieSeries; -// TODO: split this to 3 different markers for series, barset and pieslice. Current implementation is easier to misuse... class LegendMarker : public QGraphicsObject { Q_OBJECT public: - LegendMarker(QSeries *series, QGraphicsItem *parent = 0); - LegendMarker(QSeries *series, QBarSet *barset, QGraphicsItem *parent = 0); - LegendMarker(QSeries *series, QPieSlice *pieslice, QGraphicsItem *parent = 0); - - void setPos(qreal x, qreal y); + explicit LegendMarker(QSeries* m_series,QLegend *parent); void setPen(const QPen &pen); QPen pen() const; - void setBrush(const QBrush &brush); QBrush brush() const; - void setName(const QString name); - QString name() const; + void setSize(const QSize& size); - QSeries* series() const; + void setLabel(const QString label); + QString label() const; + + QSeries* series() const { return m_series;} void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); QRectF boundingRect() const; - void layoutChanged(); + void updateLayout(); -public: +protected: // From QGraphicsObject void mousePressEvent(QGraphicsSceneMouseEvent *event); Q_SIGNALS: - void clicked(QSeries *series, Qt::MouseButton button); - void clicked(QBarSet *barset, Qt::MouseButton button); - void clicked(QPieSlice *pieslice, Qt::MouseButton button); + void selected(); public Q_SLOTS: - void changed(); + virtual void updated() = 0; -private: - QPointF m_pos; - QSize m_size; +protected: + QSeries* m_series; + QRectF m_markerRect; QRectF m_boundingRect; - QRectF m_markerBoundingRect; - QBrush m_brush; - QPen m_pen; + QLegend* m_legend; + QGraphicsSimpleTextItem *m_textItem; + QGraphicsRectItem *m_rectItem; - QSeries *m_series; +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class XYLegendMarker : public LegendMarker +{ +public: + XYLegendMarker(QXYSeries *series, QLegend *legend); +protected: + void updated(); +private: + QXYSeries *m_series; +}; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class AreaLegendMarker : public LegendMarker +{ +public: + AreaLegendMarker(QAreaSeries *series, QLegend *legend); +protected: + void updated(); +private: + QAreaSeries *m_series; +}; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class BarLegendMarker : public LegendMarker +{ +public: + BarLegendMarker(QBarSeries *barseires, QBarSet *barset,QLegend *legend); +protected: + void updated(); +private: QBarSet *m_barset; +}; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class PieLegendMarker : public LegendMarker +{ +public: + PieLegendMarker(QPieSeries *pieSeries, QPieSlice *pieslice, QLegend *legend); +protected: + void updated(); +private: QPieSlice *m_pieslice; - - QGraphicsSimpleTextItem *m_textItem; - }; QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/legendscrollbutton.cpp b/src/legendscrollbutton.cpp index a5de92c..3367f2f 100644 --- a/src/legendscrollbutton.cpp +++ b/src/legendscrollbutton.cpp @@ -40,7 +40,7 @@ LegendScrollButton::ScrollButtonId LegendScrollButton::id() void LegendScrollButton::mousePressEvent(QGraphicsSceneMouseEvent *event) { Q_UNUSED(event); - m_ledgend->scrollButtonClicked(this); + //m_ledgend->scrollButtonClicked(this); } diff --git a/src/piechart/qpieslice.h b/src/piechart/qpieslice.h index a82d13e..a1c4b78 100644 --- a/src/piechart/qpieslice.h +++ b/src/piechart/qpieslice.h @@ -75,6 +75,7 @@ Q_SIGNALS: void hoverEnter(); void hoverLeave(); void changed(); + void selected(); private: friend class PieSliceData; diff --git a/src/qchart.cpp b/src/qchart.cpp index 86b7bcf..c0ff856 100644 --- a/src/qchart.cpp +++ b/src/qchart.cpp @@ -66,13 +66,13 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE Constructs a chart object which is a child of a\a parent. Parameter \a wFlags is passed to the QGraphicsWidget constructor. */ QChart::QChart(QGraphicsItem *parent, Qt::WindowFlags wFlags) : QGraphicsWidget(parent,wFlags), -d_ptr(new QChartPrivate(this)) +d_ptr(new QChartPrivate()) { - //setMinimumSize(200,200); d_ptr->m_legend = new QLegend(this); d_ptr->m_dataset = new ChartDataSet(this); d_ptr->m_presenter = new ChartPresenter(this,d_ptr->m_dataset); - setMinimumSize(d_ptr->m_padding.left() * 3, d_ptr->m_padding.top() * 3); + d_ptr->m_presenter->setTheme(QChart::ChartThemeDefault,false); + //TODO:fix me setMinimumSize(d_ptr->m_padding.left() * 3, d_ptr->m_padding.top() * 3); connect(d_ptr->m_dataset,SIGNAL(seriesAdded(QSeries*,Domain*)),d_ptr->m_legend,SLOT(handleSeriesAdded(QSeries*,Domain*))); connect(d_ptr->m_dataset,SIGNAL(seriesRemoved(QSeries*)),d_ptr->m_legend,SLOT(handleSeriesRemoved(QSeries*))); } @@ -123,15 +123,15 @@ void QChart::removeAllSeries() */ void QChart::setBackgroundBrush(const QBrush& brush) { - d_ptr->createChartBackgroundItem(); - d_ptr->m_backgroundItem->setBrush(brush); - d_ptr->m_backgroundItem->update(); + d_ptr->m_presenter->createChartBackgroundItem(); + d_ptr->m_presenter->m_backgroundItem->setBrush(brush); + d_ptr->m_presenter->m_backgroundItem->update(); } QBrush QChart::backgroundBrush() const { - if (!d_ptr->m_backgroundItem) return QBrush(); - return (d_ptr->m_backgroundItem)->brush(); + if (!d_ptr->m_presenter->m_backgroundItem) return QBrush(); + return (d_ptr->m_presenter->m_backgroundItem)->brush(); } /*! @@ -139,15 +139,15 @@ QBrush QChart::backgroundBrush() const */ void QChart::setBackgroundPen(const QPen& pen) { - d_ptr->createChartBackgroundItem(); - d_ptr->m_backgroundItem->setPen(pen); - d_ptr->m_backgroundItem->update(); + d_ptr->m_presenter->createChartBackgroundItem(); + d_ptr->m_presenter->m_backgroundItem->setPen(pen); + d_ptr->m_presenter->m_backgroundItem->update(); } QPen QChart::backgroundPen() const { - if (!d_ptr->m_backgroundItem) return QPen(); - return d_ptr->m_backgroundItem->pen(); + if (!d_ptr->m_presenter->m_backgroundItem) return QPen(); + return d_ptr->m_presenter->m_backgroundItem->pen(); } /*! @@ -155,9 +155,9 @@ QPen QChart::backgroundPen() const */ void QChart::setTitle(const QString& title) { - d_ptr->createChartTitleItem(); - d_ptr->m_titleItem->setText(title); - d_ptr->updateLayout(); + d_ptr->m_presenter->createChartTitleItem(); + d_ptr->m_presenter->m_titleItem->setText(title); + d_ptr->m_presenter->updateLayout(); } /*! @@ -165,8 +165,8 @@ void QChart::setTitle(const QString& title) */ QString QChart::title() const { - if (d_ptr->m_titleItem) - return d_ptr->m_titleItem->text(); + if (d_ptr->m_presenter->m_titleItem) + return d_ptr->m_presenter->m_titleItem->text(); else return QString(); } @@ -176,9 +176,9 @@ QString QChart::title() const */ void QChart::setTitleFont(const QFont& font) { - d_ptr->createChartTitleItem(); - d_ptr->m_titleItem->setFont(font); - d_ptr->updateLayout(); + d_ptr->m_presenter->createChartTitleItem(); + d_ptr->m_presenter->m_titleItem->setFont(font); + d_ptr->m_presenter->updateLayout(); } /*! @@ -186,9 +186,9 @@ void QChart::setTitleFont(const QFont& font) */ void QChart::setTitleBrush(const QBrush &brush) { - d_ptr->createChartTitleItem(); - d_ptr->m_titleItem->setBrush(brush); - d_ptr->updateLayout(); + d_ptr->m_presenter->createChartTitleItem(); + d_ptr->m_presenter->m_titleItem->setBrush(brush); + d_ptr->m_presenter->updateLayout(); } /*! @@ -196,8 +196,8 @@ void QChart::setTitleBrush(const QBrush &brush) */ QBrush QChart::titleBrush() const { - if (!d_ptr->m_titleItem) return QBrush(); - return d_ptr->m_titleItem->brush(); + if (!d_ptr->m_presenter->m_titleItem) return QBrush(); + return d_ptr->m_presenter->m_titleItem->brush(); } /*! @@ -267,9 +267,9 @@ QLegend* QChart::legend() const return d_ptr->m_legend; } -QRect QChart::padding() const +QRect QChart::margins() const { - return d_ptr->m_padding; + return d_ptr->m_presenter->margins(); } @@ -279,9 +279,8 @@ QRect QChart::padding() const void QChart::resizeEvent(QGraphicsSceneResizeEvent *event) { d_ptr->m_rect = QRectF(QPoint(0,0),event->newSize()); - d_ptr->updateLayout(); QGraphicsWidget::resizeEvent(event); - update(); + d_ptr->m_presenter->setGeometry(d_ptr->m_rect); } /*! @@ -302,46 +301,42 @@ QChart::AnimationOptions QChart::animationOptions() const void QChart::scrollLeft() { - d_ptr->m_presenter->scroll(-d_ptr->m_presenter->geometry().width()/(axisX()->ticksCount()-1),0); + d_ptr->m_presenter->scroll(-d_ptr->m_presenter->chartGeometry().width()/(axisX()->ticksCount()-1),0); } void QChart::scrollRight() { - d_ptr->m_presenter->scroll(d_ptr->m_presenter->geometry().width()/(axisX()->ticksCount()-1),0); + d_ptr->m_presenter->scroll(d_ptr->m_presenter->chartGeometry().width()/(axisX()->ticksCount()-1),0); } void QChart::scrollUp() { - d_ptr->m_presenter->scroll(0,d_ptr->m_presenter->geometry().width()/(axisY()->ticksCount()-1)); + d_ptr->m_presenter->scroll(0,d_ptr->m_presenter->chartGeometry().width()/(axisY()->ticksCount()-1)); } void QChart::scrollDown() { - d_ptr->m_presenter->scroll(0,-d_ptr->m_presenter->geometry().width()/(axisY()->ticksCount()-1)); + d_ptr->m_presenter->scroll(0,-d_ptr->m_presenter->chartGeometry().width()/(axisY()->ticksCount()-1)); } void QChart::setBackgroundVisible(bool visible) { - d_ptr->createChartBackgroundItem(); - d_ptr->m_backgroundItem->setVisible(visible); + d_ptr->m_presenter->createChartBackgroundItem(); + d_ptr->m_presenter->m_backgroundItem->setVisible(visible); } bool QChart::isBackgroundVisible() const { - if (!d_ptr->m_backgroundItem) return false; - return d_ptr->m_backgroundItem->isVisible(); + if (!d_ptr->m_presenter->m_backgroundItem) return false; + return d_ptr->m_presenter->m_backgroundItem->isVisible(); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -QChartPrivate::QChartPrivate(QChart *parent): -q_ptr(parent), -m_backgroundItem(0), -m_titleItem(0), +QChartPrivate::QChartPrivate(): m_legend(0), m_dataset(0), -m_presenter(0), -m_padding(QRect(50,50,0,0)) +m_presenter(0) { } @@ -351,150 +346,6 @@ QChartPrivate::~QChartPrivate() } -void QChartPrivate::createChartBackgroundItem() -{ - if (!m_backgroundItem) { - m_backgroundItem = new ChartBackground(q_ptr); - m_backgroundItem->setPen(Qt::NoPen); - m_backgroundItem->setZValue(ChartPresenter::BackgroundZValue); - } -} - -void QChartPrivate::createChartTitleItem() -{ - if (!m_titleItem) { - m_titleItem = new QGraphicsSimpleTextItem(q_ptr); - m_titleItem->setZValue(ChartPresenter::BackgroundZValue); - } -} - -void QChartPrivate::updateLegendLayout() -{ - //int legendPadding = m_chart->legend()->padding(); - int legendPadding = 30; - QRectF rect = m_rect; - - if ((m_legend->attachedToChart()) && (m_legend->isVisible())) { - - // Reserve some space for legend - switch (m_legend->alignment()) { - case QLegend::AlignmentTop: { - rect.adjust(m_padding.left(), - m_padding.top() + legendPadding, - -m_padding.right(), - -m_padding.bottom()); - break; - } - case QLegend::AlignmentBottom: { - rect.adjust(m_padding.left(), - m_padding.top(), - -m_padding.right(), - -m_padding.bottom() - legendPadding); - break; - } - case QLegend::AlignmentLeft: { - rect.adjust(m_padding.left() + legendPadding, - m_padding.top(), - -m_padding.right(), - -m_padding.bottom()); - break; - } - case QLegend::AlignmentRight: { - rect.adjust(m_padding.left(), - m_padding.top(), - -m_padding.right() - legendPadding, - -m_padding.bottom()); - break; - } - default: { - rect.adjust(m_padding.left(), - m_padding.top(), - -m_padding.right(), - -m_padding.bottom()); - break; - } - } - } else { - - rect.adjust(m_padding.left(), - m_padding.top(), - -m_padding.right(), - -m_padding.bottom()); - } - - QRectF plotRect = m_rect.adjusted(m_padding.left() - ,m_padding.top() - ,-m_padding.right() - ,-m_padding.bottom()); - QRectF legendRect; - - int padding = 0; // TODO: fix this - switch (m_legend->alignment()) - { - case QLegend::AlignmentTop: { - legendRect = m_rect.adjusted(0,padding,0,-padding - plotRect.height()); - break; - } - case QLegend::AlignmentBottom: { - legendRect = m_rect.adjusted(padding,padding + plotRect.height(),-padding,0); - break; - } - case QLegend::AlignmentLeft: { - legendRect = m_rect.adjusted(0,padding,-padding - plotRect.width(),-padding); - break; - } - case QLegend::AlignmentRight: { - legendRect = m_rect.adjusted(padding + plotRect.width(),padding,0,-padding); - break; - } - default: { - legendRect = plotRect; - break; - } - } - - m_legend->setMaximumSize(legendRect.size()); - - qreal width = legendRect.width() - m_legend->size().width(); - qreal height = legendRect.height() - m_legend->size().height(); - - QPointF pos = legendRect.topLeft(); - if (width > 0) { - pos.setX(pos.x() + width/2); - } - if (height > 0) { - pos.setY(pos.y() + height/2); - } - - m_legend->setPos(pos); -} - -void QChartPrivate::updateLayout() -{ - if (!m_rect.isValid()) return; - - int padding = m_padding.top(); - int backgroundPadding = m_presenter->backgroundPadding(); - - // recalculate title position - if (m_titleItem) { - QPointF center = m_rect.center() -m_titleItem->boundingRect().center(); - m_titleItem->setPos(center.x(),m_rect.top()/2 + padding/2); - } - - //recalculate background gradient - if (m_backgroundItem) { - m_backgroundItem->setRect(m_rect.adjusted(backgroundPadding,backgroundPadding, -backgroundPadding, -backgroundPadding)); - } - - // recalculate legend position - if (m_legend) { - if ((m_legend->attachedToChart()) && (m_legend->parentObject() == q_ptr)) { - updateLegendLayout(); - } - } -} - #include "moc_qchart.cpp" QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/qchart.h b/src/qchart.h index c35213e..1172055 100644 --- a/src/qchart.h +++ b/src/qchart.h @@ -99,8 +99,7 @@ public: QChartAxis* axisY() const; QLegend* legend() const; - - QRect padding() const; + QRect margins() const; protected: void resizeEvent(QGraphicsSceneResizeEvent *event); @@ -108,6 +107,7 @@ protected: protected: QScopedPointer d_ptr; friend class QLegend; + friend class ChartPresenter; Q_DISABLE_COPY(QChart) }; diff --git a/src/qchart_p.h b/src/qchart_p.h index 7f74f3f..8ad64a7 100644 --- a/src/qchart_p.h +++ b/src/qchart_p.h @@ -30,11 +30,9 @@ #ifndef QCHART_P_H #define QCHART_P_H -#include "qchartaxis.h" #include "qlegend.h" #include "chartpresenter_p.h" #include "chartdataset_p.h" -#include "chartbackground_p.h" QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -42,22 +40,13 @@ class QChart; struct QChartPrivate { - QChartPrivate(QChart *parent); + QChartPrivate(); ~QChartPrivate(); - - void createChartBackgroundItem(); - void createChartTitleItem(); - void updateLayout(); - void updateLegendLayout(); - - QChart *q_ptr; - ChartBackground* m_backgroundItem; - QGraphicsSimpleTextItem* m_titleItem; QRectF m_rect; QLegend* m_legend; ChartDataSet *m_dataset; ChartPresenter *m_presenter; - QRect m_padding; + }; QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/qchartview.cpp b/src/qchartview.cpp index 3340368..c07ec45 100644 --- a/src/qchartview.cpp +++ b/src/qchartview.cpp @@ -116,7 +116,7 @@ void QChartView::mousePressEvent(QMouseEvent *event) { if(d_ptr->m_rubberBand && d_ptr->m_rubberBand->isEnabled() && event->button() == Qt::LeftButton) { - int padding = d_ptr->m_chart->padding().top(); + int padding = d_ptr->m_chart->margins().top(); QRect rect(padding, padding, width() - 2 * padding, height() - 2 * padding); if (rect.contains(event->pos())) { @@ -138,7 +138,7 @@ void QChartView::mousePressEvent(QMouseEvent *event) void QChartView::mouseMoveEvent(QMouseEvent *event) { if(d_ptr->m_rubberBand && d_ptr->m_rubberBand->isVisible()) { - int padding = d_ptr->m_chart->padding().top(); + int padding = d_ptr->m_chart->margins().top(); QRect rect(padding, padding, width() - 2 * padding, height() - 2 * padding); int width = event->pos().x() - d_ptr->m_rubberBandOrigin.x(); int height = event->pos().y() - d_ptr->m_rubberBandOrigin.y(); diff --git a/src/qlegend.cpp b/src/qlegend.cpp index 47c83ac..595dd79 100644 --- a/src/qlegend.cpp +++ b/src/qlegend.cpp @@ -22,7 +22,6 @@ #include "qchart_p.h" #include "qseries.h" #include "legendmarker_p.h" -#include "legendscrollbutton_p.h" #include "qxyseries.h" #include "qlineseries.h" #include "qareaseries.h" @@ -35,8 +34,10 @@ #include "qpieseries.h" #include "qpieslice.h" #include "chartpresenter_p.h" +#include "scroller_p.h" #include #include +#include #include @@ -86,45 +87,51 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE /*! Constructs the legend object and sets the parent to \a parent */ + QLegend::QLegend(QChart *chart):QGraphicsWidget(chart), m_margin(5), - m_pos(0,0), - m_minimumSize(50,20), // TODO: magic numbers - m_maximumSize(150,100), - m_size(m_minimumSize), + m_offsetX(0), + m_offsetY(0), m_brush(Qt::darkGray), // TODO: default should come from theme m_alignment(QLegend::AlignmentTop), - mFirstMarker(0), + m_markers(new QGraphicsItemGroup(this)), m_attachedToChart(true), - m_chart(chart) + m_chart(chart), + m_minWidth(0), + m_minHeight(0), + m_width(0), + m_height(0), + m_visible(false), + m_dirty(false), + m_scroller(new Scroller(this)) { - m_scrollButtonLeft = new LegendScrollButton(LegendScrollButton::ScrollButtonIdLeft, this); - m_scrollButtonRight = new LegendScrollButton(LegendScrollButton::ScrollButtonIdRight, this); - m_scrollButtonUp = new LegendScrollButton(LegendScrollButton::ScrollButtonIdUp, this); - m_scrollButtonDown = new LegendScrollButton(LegendScrollButton::ScrollButtonIdDown, this); setZValue(ChartPresenter::LegendZValue); + setFlags(QGraphicsItem::ItemClipsChildrenToShape); } /*! Paints the legend to given \a painter. Paremeters \a option and \a widget arent used. */ + void QLegend::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { - Q_UNUSED(option) - Q_UNUSED(widget) + Q_UNUSED(option) + Q_UNUSED(widget) + if(!m_visible) return; painter->setOpacity(opacity()); painter->setPen(m_pen); painter->setBrush(m_brush); -// painter->drawRect(boundingRect()); + painter->drawRect(boundingRect()); } /*! Bounding rect of legend. */ + QRectF QLegend::boundingRect() const { - return QRectF(m_pos,m_size); + return m_rect; } /*! @@ -172,11 +179,10 @@ QPen QLegend::pen() const */ void QLegend::setAlignmnent(QLegend::Alignments alignment) { -// if (!m_attachedToChart) { + if(m_alignment!=alignment && m_attachedToChart) { m_alignment = alignment; updateLayout(); - m_chart->resize(m_chart->size()); -// } + } } /*! @@ -188,56 +194,6 @@ QLegend::Alignments QLegend::alignment() const } /*! - Returns the maximum size of legend. -*/ -QSizeF QLegend::maximumSize() const -{ - return m_maximumSize; -} - -/*! - Sets the maximum \a size for legend. The legend can't grow bigger than this size. If there are - more series than legend can fit to this size, scroll buttons are displayed. -*/ -void QLegend::setMaximumSize(const QSizeF size) -{ - m_maximumSize = size; - updateLayout(); -} - -/*! - Returns the current size of legend. -*/ -QSizeF QLegend::size() const -{ - return m_size; -} - -/*! - Sets the \a size of legend. If size is bigger than maximum size of legend, the legend is resized to the maximum size. - \sa setMmaximumSize() -*/ -void QLegend::setSize(const QSizeF size) -{ - m_size = size; - if (m_size.width() > m_maximumSize.width()) { - m_size.setWidth(m_maximumSize.width()); - } - if (m_size.height() > m_maximumSize.height()) { - m_size.setHeight(m_maximumSize.height()); - } -} - -/*! - Sets position of legend to \a pos -*/ -void QLegend::setPos(const QPointF &pos) -{ - m_pos = pos; - updateLayout(); -} - -/*! \internal \a series \a domain Should be called when series is added to chart. */ void QLegend::handleSeriesAdded(QSeries *series, Domain *domain) @@ -293,7 +249,11 @@ void QLegend::handleSeriesAdded(QSeries *series, Domain *domain) } } - updateLayout(); + // wait for all series added + if(!m_dirty){ + QTimer::singleShot(0,this,SLOT(updateLayout())); + m_dirty=true; + } } /*! @@ -330,17 +290,10 @@ void QLegend::handleSeriesRemoved(QSeries *series) void QLegend::handleAdded(QList slices) { QPieSeries* series = static_cast (sender()); - foreach(QPieSlice* s, slices) { - LegendMarker* marker = new LegendMarker(series, s, this); - marker->setName(s->label()); - marker->setBrush(s->brush()); - connect(marker, SIGNAL(clicked(QPieSlice*,Qt::MouseButton)), - this, SIGNAL(clicked(QPieSlice*,Qt::MouseButton))); - connect(s, SIGNAL(changed()), marker, SLOT(changed())); - connect(s, SIGNAL(destroyed()), marker, SLOT(deleteLater())); + foreach(QPieSlice* slice, slices) { + PieLegendMarker* marker = new PieLegendMarker(series,slice, this); connect(marker, SIGNAL(destroyed()), this, SLOT(handleMarkerDestroyed())); - m_markers.append(marker); - childItems().append(marker); + m_markers->addToGroup(marker); } updateLayout(); } @@ -361,36 +314,8 @@ void QLegend::handleRemoved(QList slices) void QLegend::handleMarkerDestroyed() { LegendMarker* m = static_cast (sender()); - m_markers.removeOne(m); - updateLayout(); -} - -/*! - \internal \a event Handles clicked signals from scroll buttons -*/ -void QLegend::scrollButtonClicked(LegendScrollButton *scrollButton) -{ - Q_ASSERT(scrollButton); - - switch (scrollButton->id()) { - case LegendScrollButton::ScrollButtonIdLeft: - case LegendScrollButton::ScrollButtonIdUp: { - // Lower limit is same in these cases - mFirstMarker--; - checkFirstMarkerBounds(); - break; - } - case LegendScrollButton::ScrollButtonIdRight: - case LegendScrollButton::ScrollButtonIdDown: { - mFirstMarker++; - checkFirstMarkerBounds(); - break; - } - default: { - break; - } - } - updateLayout(); + delete m; + // updateLayout(); } /*! @@ -412,7 +337,7 @@ void QLegend::attachToChart() /*! Returns true, if legend is attached to chart. */ -bool QLegend::attachedToChart() +bool QLegend::isAttachedToChart() { return m_attachedToChart; } @@ -422,13 +347,9 @@ bool QLegend::attachedToChart() */ void QLegend::appendMarkers(QAreaSeries* series) { - LegendMarker* marker = new LegendMarker(series,this); - connect(marker, SIGNAL(clicked(QSeries *, Qt::MouseButton)), this, SIGNAL(clicked(QSeries *, Qt::MouseButton))); + AreaLegendMarker* marker = new AreaLegendMarker(series,this); connect(marker, SIGNAL(destroyed()), this, SLOT(handleMarkerDestroyed())); - connect(series,SIGNAL(updated()),marker,SLOT(changed())); - marker->changed(); - m_markers.append(marker); - childItems().append(marker); + m_markers->addToGroup(marker); } /*! @@ -436,13 +357,9 @@ void QLegend::appendMarkers(QAreaSeries* series) */ void QLegend::appendMarkers(QXYSeries* series) { - LegendMarker* marker = new LegendMarker(series,this); - connect(marker, SIGNAL(clicked(QSeries *, Qt::MouseButton)), this, SIGNAL(clicked(QSeries *, Qt::MouseButton))); + XYLegendMarker* marker = new XYLegendMarker(series,this); connect(marker, SIGNAL(destroyed()), this, SLOT(handleMarkerDestroyed())); - connect(series,SIGNAL(updated()),marker,SLOT(changed())); - marker->changed(); - m_markers.append(marker); - childItems().append(marker); + m_markers->addToGroup(marker); } /*! @@ -451,14 +368,9 @@ void QLegend::appendMarkers(QXYSeries* series) void QLegend::appendMarkers(QBarSeries *series) { foreach(QBarSet* set, series->barSets()) { - LegendMarker* marker = new LegendMarker(series, set, this); - connect(marker, SIGNAL(clicked(QBarSet *, Qt::MouseButton)), - this, SIGNAL(clicked(QBarSet *, Qt::MouseButton))); - connect(set, SIGNAL(valueChanged()), marker, SLOT(changed())); + BarLegendMarker* marker = new BarLegendMarker(series,set, this); connect(marker, SIGNAL(destroyed()), this, SLOT(handleMarkerDestroyed())); - marker->changed(); - m_markers.append(marker); - childItems().append(marker); + m_markers->addToGroup(marker); } } @@ -468,15 +380,9 @@ void QLegend::appendMarkers(QBarSeries *series) void QLegend::appendMarkers(QPieSeries *series) { foreach(QPieSlice* slice, series->slices()) { - LegendMarker* marker = new LegendMarker(series, slice, this); - connect(marker, SIGNAL(clicked(QPieSlice *, Qt::MouseButton)), - this, SIGNAL(clicked(QPieSlice *, Qt::MouseButton))); - connect(slice, SIGNAL(changed()), marker, SLOT(changed())); - connect(slice, SIGNAL(destroyed()), marker, SLOT(deleteLater())); + PieLegendMarker* marker = new PieLegendMarker(series,slice, this); connect(marker, SIGNAL(destroyed()), this, SLOT(handleMarkerDestroyed())); - marker->changed(); - m_markers.append(marker); - childItems().append(marker); + m_markers->addToGroup(marker); } } @@ -486,10 +392,13 @@ void QLegend::appendMarkers(QPieSeries *series) void QLegend::deleteMarkers(QSeries *series) { // Search all markers that belong to given series and delete them. - foreach (LegendMarker *m, m_markers) { - if (m->series() == series) { - m_markers.removeOne(m); - delete m; + + QList items = m_markers->childItems(); + + foreach (QGraphicsItem *m, items) { + LegendMarker *marker = static_cast(m); + if (marker->series() == series) { + delete marker; } } } @@ -499,251 +408,154 @@ void QLegend::deleteMarkers(QSeries *series) If items don't fit, sets the visibility of scroll buttons accordingly. Causes legend to be resized. */ -void QLegend::updateLayout() -{ - // Calculate layout for markers and text - if (m_markers.count() <= 0) { - // Nothing to do - return; - } - checkFirstMarkerBounds(); +void QLegend::setOffset(const QPointF& point) +{ - switch (m_alignment) - { - // Both cases organise items horizontally - case QLegend::AlignmentBottom: - case QLegend::AlignmentTop: { - layoutHorizontal(); - break; - } - // Both cases organize items vertically - case QLegend::AlignmentLeft: - case QLegend::AlignmentRight: { - layoutVertical(); - break; - } - default: { - break; - } - } + switch(m_alignment) { -} + case AlignmentTop: + case AlignmentBottom: { + if(m_width<=m_rect.width()) return; -/*! - \internal Organizes markers horizontally. - Causes legend to be resized. -*/ -void QLegend::layoutHorizontal() -{ - // Find out widest item. - QSizeF markerMaxSize = maximumMarkerSize(); - // Use max height as scroll button size - rescaleScrollButtons(QSize(markerMaxSize.height() ,markerMaxSize.height())); - - qreal totalWidth = 0; - qreal totalHeight = 0; - - qreal xStep = markerMaxSize.width(); - qreal x = m_pos.x() + m_margin; - qreal y = m_pos.y() + m_margin; - int column = 0; - int maxColumns = 1; - qreal scrollButtonWidth = 0; - - // Set correct visibility for scroll scrollbuttons - if (scrollButtonsVisible()) { - m_scrollButtonLeft->setVisible(true); - m_scrollButtonRight->setVisible(true); - // scrollbuttons visible, so add their width to total width - totalWidth += (m_scrollButtonLeft->boundingRect().width() + m_margin) * 2; - scrollButtonWidth = m_scrollButtonLeft->boundingRect().width() + m_margin; - // start position changes by scrollbutton width - x += scrollButtonWidth; - } else { - m_scrollButtonLeft->setVisible(false); - m_scrollButtonRight->setVisible(false); - } - m_scrollButtonUp->setVisible(false); - m_scrollButtonDown->setVisible(false); - - for (int i=0; i < m_markers.count(); i++) { - LegendMarker *m = m_markers.at(i); - if (i < mFirstMarker) { - // Markers before first are not visible. - m->setVisible(false); - } else { - if ((x + xStep + scrollButtonWidth + m_margin) > (m_pos.x() + m_maximumSize.width())) { - // This marker would go outside legend rect. - m->setVisible(false); - } else { - // This marker is ok - m->setVisible(true); - m->setPos(x, y); - x += xStep; - column++; + if (point.x() != m_offsetX) { + m_offsetX = qBound(0.0, point.x(), m_width - m_rect.width()); + m_markers->setPos(-m_offsetX,m_rect.top()); } + break; } - maxColumns = column; - } - - m_scrollButtonLeft->setPos(m_pos.x() + m_margin, y); - m_scrollButtonRight->setPos(x + m_margin, y); + case AlignmentLeft: + case AlignmentRight: { - totalWidth += maxColumns * markerMaxSize.width() + m_margin * 2; - totalHeight = markerMaxSize.height() + m_margin * 2; + if(m_height<=m_rect.height()) return; - m_size.setWidth(totalWidth); - m_size.setHeight(totalHeight); -} - -/*! - \internal Organizes markers vertically. - Causes legend to be resized. -*/ -void QLegend::layoutVertical() -{ - // Find out widest item. - QSizeF markerMaxSize = maximumMarkerSize(); - // Use max height as scroll button size - rescaleScrollButtons(QSize(markerMaxSize.height() ,markerMaxSize.height())); - - qreal totalWidth = 0; - qreal totalHeight = 0; - - qreal yStep = markerMaxSize.height(); - qreal x = m_pos.x() + m_margin; - qreal y = m_pos.y() + m_margin; - int row = 1; - int maxRows = 1; - qreal scrollButtonHeight = 0; - - // Set correct visibility for scroll scrollbuttons - if (scrollButtonsVisible()) { - m_scrollButtonUp->setVisible(true); - m_scrollButtonDown->setVisible(true); - totalHeight += (m_scrollButtonUp->boundingRect().height() + m_margin) * 2; // scrollbuttons visible, so add their height to total height - scrollButtonHeight = m_scrollButtonUp->boundingRect().height(); - y += scrollButtonHeight + m_margin; // start position changes by scrollbutton height - } else { - m_scrollButtonUp->setVisible(false); - m_scrollButtonDown->setVisible(false); - } - m_scrollButtonLeft->setVisible(false); - m_scrollButtonRight->setVisible(false); - - for (int i=0; i < m_markers.count(); i++) { - LegendMarker* m = m_markers.at(i); - if (i < mFirstMarker) { - // Markers before first are not visible. - m->setVisible(false); - } else { - if ((y + yStep + scrollButtonHeight) > (m_pos.y() + m_maximumSize.height())) { - // This marker would go outside legend rect. - m->setVisible(false); - } else { - // This marker is ok - m->setVisible(true); - m->setPos(x, y); - y += yStep; - row++; + if (point.y() != m_offsetY) { + m_offsetY = qBound(0.0, point.y(), m_height - m_rect.height()); + m_markers->setPos(m_rect.left(),-m_offsetY); } + break; } - maxRows = row; } +} - m_scrollButtonUp->setPos(m_pos.x() + m_margin, m_pos.y() + m_margin); - m_scrollButtonDown->setPos(m_pos.x() + m_margin, y + m_margin); - - totalWidth += markerMaxSize.width() + m_margin * 2; - totalHeight = maxRows * markerMaxSize.height() + m_margin * 4 + scrollButtonHeight; // TODO: check this - - m_size.setWidth(totalWidth); - m_size.setHeight(totalHeight); +QPointF QLegend::offset() const +{ + return QPointF(m_offsetX,m_offsetY); } -/*! - \internal Sets the size of scroll buttons to \a size -*/ -void QLegend::rescaleScrollButtons(const QSize &size) +// this function runs first to set min max values +void QLegend::updateLayout() { - QPolygonF left; - left << QPointF(size.width(), 0) << QPointF(0, size.height() / 2) << QPointF(size.width(), size.height()); - QPolygonF right; - right << QPointF(0, 0) << QPointF(size.width(), size.height() / 2) << QPointF(0, size.height()); - QPolygonF up; - up << QPointF(0, size.height()) << QPointF(size.width() / 2,0) << QPointF(size.width(), size.height()); - QPolygonF down; - down << QPointF(0, 0) << QPointF(size.width() / 2, size.height()) << QPointF(size.width(), 0); + m_dirty=false; + m_offsetX=0; + QList items = m_markers->childItems(); + + if(items.isEmpty()) return; + + m_minWidth=0; + m_minHeight=0; + + switch(m_alignment) { + + case AlignmentTop: + case AlignmentBottom: { + QPointF point = m_rect.topLeft(); + m_width = 0; + foreach (QGraphicsItem *item, items) { + 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 AlignmentLeft: + case AlignmentRight:{ + QPointF point = m_rect.topLeft(); + m_height = 0; + foreach (QGraphicsItem *item, items) { + 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_scrollButtonLeft->setPolygon(left); - m_scrollButtonRight->setPolygon(right); - m_scrollButtonUp->setPolygon(up); - m_scrollButtonDown->setPolygon(down); + m_chart->d_ptr->m_presenter->updateLayout(); //TODO fixme; } -/*! - \internal Finds out maximum size of single marker. Marker sizes depend on series names. -*/ -QSizeF QLegend::maximumMarkerSize() -{ - QSizeF max(0,0); - foreach (LegendMarker* m, m_markers) { - if (m->boundingRect().width() > max.width()) - max.setWidth(m->boundingRect().width()); - if (m->boundingRect().height() > max.height()) - max.setHeight(m->boundingRect().height()); +void QLegend::setBackgroundVisible(bool visible) +{ + if(m_visible!=visible) + { + m_visible=visible; + update(); } - return max; } -/*! - \internal Checks that first marker is in acceptable bounds. Bounds range from 0 to (maximum number of markers - visible markers) - If scrollbuttons are visible, they affect the number of visible markers. -*/ -void QLegend::checkFirstMarkerBounds() -{ - if ((m_alignment == QLegend::AlignmentLeft) || (m_alignment == QLegend::AlignmentRight)) { - // Bounds limited by height. - int max; - if (scrollButtonsVisible()) { - max = (m_maximumSize.height() - m_scrollButtonLeft->boundingRect().height() * 2 - m_margin * 4) / maximumMarkerSize().height(); - } else { - max = m_maximumSize.height() / maximumMarkerSize().height(); - } - - if (mFirstMarker > m_markers.count() - max) - mFirstMarker = m_markers.count() - max; - } else { - // Bounds limited by width - int max; - if (scrollButtonsVisible()) { - max = (m_maximumSize.width() - m_scrollButtonLeft->boundingRect().width() * 2 - m_margin*4) / maximumMarkerSize().width(); - } else { - max = m_maximumSize.width() / maximumMarkerSize().width(); - } +bool QLegend::isBackgroundVisible() const +{ + return m_visible; +} - if (mFirstMarker > m_markers.count() - max) - mFirstMarker = m_markers.count() - max; +void QLegend::resizeEvent(QGraphicsSceneResizeEvent *event) +{ + const QRectF& rect = QRectF(QPoint(0,0),event->newSize()); + QGraphicsWidget::resizeEvent(event); + if(m_rect != rect){ + m_rect = rect; + updateLayout(); } +} - if (mFirstMarker < 0) - mFirstMarker = 0; +void QLegend::hideEvent(QHideEvent *event) +{ + QGraphicsWidget::hideEvent(event); + setEnabled(false); + updateLayout(); } -/*! - \internal Helper function. Visibility of scroll buttons isn't quite obvious, so helper function clarifies the logic. -*/ -bool QLegend::scrollButtonsVisible() +void QLegend::showEvent(QShowEvent *event) { - // Just a helper to clarify, what the magic below means :) - if ((m_alignment == QLegend::AlignmentTop) || (m_alignment == QLegend::AlignmentBottom)) { - return (maximumMarkerSize().width() * m_markers.count() + m_margin * 2 > m_maximumSize.width()); - } else if ((m_alignment == QLegend::AlignmentLeft) || (m_alignment == QLegend::AlignmentRight)) { - return (maximumMarkerSize().height() * m_markers.count() + m_margin * 2 > m_maximumSize.height()); - } + QGraphicsWidget::showEvent(event); + setEnabled(true); + updateLayout(); +} - return (maximumMarkerSize().height() * m_markers.count() + m_margin * 2 > m_maximumSize.height()); +void QLegend::mousePressEvent(QGraphicsSceneMouseEvent* event) +{ + //Q_UNUSED(event); + m_scroller->mousePressEvent(event); +} +void QLegend::mouseMoveEvent(QGraphicsSceneMouseEvent* event) +{ + //Q_UNUSED(event); + m_scroller->mouseMoveEvent(event); +} +void QLegend::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) +{ + //Q_UNUSED(event); + m_scroller->mouseReleaseEvent(event); } #include "moc_qlegend.cpp" diff --git a/src/qlegend.h b/src/qlegend.h index dd1af1d..8fc17b9 100644 --- a/src/qlegend.h +++ b/src/qlegend.h @@ -39,6 +39,7 @@ class QAreaSeries; class LegendScrollButton; class QSeries; class QChart; +class Scroller; class QTCOMMERCIALCHART_EXPORT QLegend : public QGraphicsWidget { @@ -71,25 +72,27 @@ public: void setAlignmnent(QLegend::Alignments alignment); QLegend::Alignments alignment() const; - QSizeF maximumSize() const; - void setMaximumSize(const QSizeF size); - - QSizeF size() const; - void setSize(const QSizeF size); - void setPos(const QPointF &pos); - - void scrollButtonClicked(LegendScrollButton *scrollButton); void detachFromChart(); void attachToChart(); - bool attachedToChart(); + bool isAttachedToChart(); + + qreal minWidht() const { return m_minWidth;} + qreal minHeight() const { return m_minHeight;} -Q_SIGNALS: - // for interactions. - void clicked(QSeries *series, Qt::MouseButton button); - void clicked(QBarSet *barset, Qt::MouseButton button); - void clicked(QPieSlice *slice, Qt::MouseButton button); - void legendGeometryChanged(); + void setBackgroundVisible(bool visible); + bool isBackgroundVisible() const; + + void setOffset(const QPointF& point); + QPointF offset() const; + +protected: + void resizeEvent(QGraphicsSceneResizeEvent *event); + void hideEvent(QHideEvent *event); + void showEvent(QShowEvent *event); + void mousePressEvent(QGraphicsSceneMouseEvent* event); + void mouseMoveEvent(QGraphicsSceneMouseEvent* event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent* event); public Q_SLOTS: // PIMPL ---> @@ -108,36 +111,39 @@ private: void appendMarkers(QBarSeries *series); void appendMarkers(QPieSeries *series); void deleteMarkers(QSeries *series); + + + + +private Q_SLOTS: void updateLayout(); - void layoutHorizontal(); - void layoutVertical(); - void rescaleScrollButtons(const QSize &size); - QSizeF maximumMarkerSize(); - void checkFirstMarkerBounds(); - bool scrollButtonsVisible(); + void scroll(); +private: qreal m_margin; - QPointF m_pos; - QSizeF m_minimumSize; - QSizeF m_maximumSize; - QSizeF m_size; - QList m_markers; + QRectF m_rect; + qreal m_offsetX; + qreal m_offsetY; + + //QList m_markers; QBrush m_brush; QPen m_pen; QLegend::Alignments m_alignment; + QGraphicsItemGroup* m_markers; - int mFirstMarker; - - LegendScrollButton *m_scrollButtonLeft; - LegendScrollButton *m_scrollButtonRight; - LegendScrollButton *m_scrollButtonUp; - LegendScrollButton *m_scrollButtonDown; bool m_attachedToChart; QChart *m_chart; + qreal m_minWidth; + qreal m_minHeight; + qreal m_width; + qreal m_height; + bool m_visible; + bool m_dirty; + Scroller* m_scroller; friend class QChart; // <--- PIMPL }; diff --git a/src/scroller.cpp b/src/scroller.cpp new file mode 100644 index 0000000..2b8e04a --- /dev/null +++ b/src/scroller.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** +** +** 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 "scroller_p.h" +#include "qlegend.h" +#include + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +Scroller::Scroller(QLegend* legend): +m_ticker(this), +m_state(Idle), +m_moveThreshold(10), +m_timeTreshold(50), +m_legend(legend) +{ + +} + +Scroller::~Scroller() +{ +} + +void Scroller::mousePressEvent(QGraphicsSceneMouseEvent* event) +{ + if (event->button() == Qt::LeftButton) { + + switch (m_state) { + case Idle: + { + m_state = Pressed; + m_offset = offset(); + m_press = event->pos(); + m_timeStamp = QTime::currentTime(); + event->accept(); + break; + } + case Scroll: + { + m_state = Stop; + m_speed = QPoint(0, 0); + m_offset = offset(); + m_press = event->pos(); + event->accept(); + break; + } + case Pressed: + case Move: + case Stop: + qWarning() << __FUNCTION__<<"Scroller unexpected state" << m_state; + event->ignore(); + break; + } + } +} + +void Scroller::mouseMoveEvent(QGraphicsSceneMouseEvent* event) +{ + QPointF delta = event->pos() - m_press; + + switch (m_state) { + case Pressed: + case Stop: + { + if (qAbs(delta.x()) > m_moveThreshold || qAbs(delta.y()) > m_moveThreshold) { + m_state = Move; + m_timeStamp = QTime::currentTime(); + m_distance = QPointF(0, 0); + m_press = event->pos(); + event->accept(); + break; + } + else { + event->ignore(); + break; + } + } + case Move: + { + setOffset(m_offset - delta); + calculateSpeed(event->pos()); + event->accept(); + break; + } + case Idle: + case Scroll: + qWarning() << __FUNCTION__<<"Scroller unexpected state" << m_state; + event->ignore(); + break; + } + +} + +void Scroller::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) +{ + if (event->button() == Qt::LeftButton) { + + switch (m_state) { + + case Scroll: + m_state = Stop; + m_speed = QPointF(0, 0); + m_offset = offset(); + event->accept(); + break; + case Pressed: + { + m_state = Idle; + //if (m_timeStamp.elapsed() < m_clickedPressDelay) { + + //emit clicked(m_offset.toPoint()); + //} + event->accept(); + break; + } + case Move: + { + calculateSpeed(event->pos()); + m_offset = offset(); + m_press = event->pos(); + if (m_speed == QPointF(0, 0)) { + m_state = Idle; + } + else { + m_speed /= 4; + m_state = Scroll; + m_ticker.start(20); + } + event->accept(); + break; + } + + case Stop: + case Idle: + qWarning() << __FUNCTION__<<"Scroller unexpected state" << m_state; + event->ignore(); + break; + + } + } +} + +void Scroller::scrollTick() +{ + switch (m_state) { + case Scroll: + { + lowerSpeed(m_speed); + setOffset(m_offset - m_speed); + m_offset = offset(); + if (m_speed == QPointF(0, 0)) { + m_state = Idle; + m_ticker.stop(); + } + break; + } + case Stop: + m_ticker.stop(); + break; + case Idle: + case Move: + case Pressed: + qWarning() << __FUNCTION__<<"Scroller unexpected state" << m_state; + m_ticker.stop(); + break; + + } +} + +void Scroller::lowerSpeed(QPointF& speed, qreal maxSpeed) +{ + qreal x = qBound(-maxSpeed, speed.x(), maxSpeed); + qreal y = qBound(-maxSpeed, speed.y(), maxSpeed); + + x = (x == 0) ? x : + (x > 0) ? qMax(qreal(0), x - m_fraction.x()) : qMin(qreal(0), x + m_fraction.x()); + y = (y == 0) ? y : + (y > 0) ? qMax(qreal(0), y - m_fraction.y()) : qMin(qreal(0), y + m_fraction.y()); + speed.setX(x); + speed.setY(y); +} + +void Scroller::calculateSpeed(const QPointF& position) +{ + if (m_timeStamp.elapsed() > m_timeTreshold) { + + QPointF distance = position - m_press; + + m_timeStamp = QTime::currentTime(); + m_speed = distance - m_distance; + m_distance = distance; + + qreal fraction = qMax(qAbs(m_speed.x()), qAbs(m_speed.y())); + + if (fraction != 0) { + m_fraction.setX(qAbs(m_speed.x() / fraction)); + m_fraction.setY(qAbs(m_speed.y() / fraction)); + } + else { + m_fraction.setX(1); + m_fraction.setY(1); + } + } +} + +void Scroller::setOffset(const QPointF& point) +{ + m_legend->setOffset(point); +} + +QPointF Scroller::offset() const +{ + return m_legend->offset(); +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +ScrollTicker::ScrollTicker(Scroller *scroller,QObject* parent):QObject(parent), + m_scroller(scroller) +{ + +} + +void ScrollTicker::start(int interval) +{ + if (!m_timer.isActive()){ + m_timer.start(interval, this); + } +} + +void ScrollTicker::stop() +{ + m_timer.stop(); +} + +void ScrollTicker::timerEvent(QTimerEvent *event) +{ + Q_UNUSED(event); + m_scroller->scrollTick(); +} + +QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/scroller_p.h b/src/scroller_p.h new file mode 100644 index 0000000..8700127 --- /dev/null +++ b/src/scroller_p.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** 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 SCROLLER_P_H_ +#define SCROLLER_P_H_ + +#include "qchartglobal.h" +#include +#include +#include + +class QGraphicsSceneMouseEvent; + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +class Scroller; +class QLegend; + +class ScrollTicker : public QObject +{ +public: + ScrollTicker(Scroller *scroller,QObject *parent=0); + void start(int interval); + void stop(); +protected: + void timerEvent(QTimerEvent *event); + +private: + QBasicTimer m_timer; + Scroller *m_scroller; +}; + +class Scroller +{ +public: + enum State { + Idle, + Pressed, + Move, + Scroll, + Stop + }; + + explicit Scroller(QLegend* legend); + virtual ~Scroller(); + + virtual void setOffset(const QPointF& point); + virtual QPointF offset() const; + +public: + void scrollTick(); + + +public: + void mousePressEvent(QGraphicsSceneMouseEvent* event); + void mouseMoveEvent(QGraphicsSceneMouseEvent* event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent* event); + +private: + void calculateSpeed(const QPointF& position); + void lowerSpeed(QPointF& speed,qreal maxSpeed=100); + +private: + ScrollTicker m_ticker; + State m_state; + QTime m_timeStamp; + QPointF m_press; + QPointF m_offset; + QPointF m_speed; + QPointF m_distance; + QPointF m_fraction; + int m_moveThreshold; + int m_timeTreshold; + QLegend* m_legend; + + +}; + +QTCOMMERCIALCHART_END_NAMESPACE + +#endif /* SCROLLER_P_H_ */ diff --git a/src/src.pro b/src/src.pro index 02d782a..27d0065 100644 --- a/src/src.pro +++ b/src/src.pro @@ -19,7 +19,8 @@ SOURCES += \ $$PWD/legendmarker.cpp \ $$PWD/legendscrollbutton.cpp \ $$PWD/chartbackground.cpp \ - $$PWD/chart.cpp + $$PWD/chart.cpp \ + $$PWD/scroller.cpp PRIVATE_HEADERS += \ $$PWD/chartdataset_p.h \ $$PWD/chartitem_p.h \ @@ -32,7 +33,8 @@ PRIVATE_HEADERS += \ $$PWD/chart_p.h \ $$PWD/chartconfig_p.h \ $$PWD/qchart_p.h \ - $$PWD/qchartview_p.h + $$PWD/qchartview_p.h \ + $$PWD/scroller_p.h PUBLIC_HEADERS += \ $$PWD/qchart.h \ $$PWD/qchartglobal.h \ diff --git a/src/xychart/qxyseries.h b/src/xychart/qxyseries.h index ef1c3e5..5814c69 100644 --- a/src/xychart/qxyseries.h +++ b/src/xychart/qxyseries.h @@ -75,6 +75,7 @@ private Q_SLOTS: Q_SIGNALS: void clicked(const QPointF &point); + void selected(); void updated(); void pointReplaced(int index); void pointRemoved(int index); @@ -87,7 +88,7 @@ protected: QPen m_pen; QBrush m_brush; - int m_mapX; + int m_mapX; int m_mapY; int m_mapFirst; int m_mapCount; diff --git a/test/auto/qchartview/tst_qchartview.cpp b/test/auto/qchartview/tst_qchartview.cpp index cd40346..682ff71 100644 --- a/test/auto/qchartview/tst_qchartview.cpp +++ b/test/auto/qchartview/tst_qchartview.cpp @@ -131,7 +131,7 @@ void tst_QChartView::rubberBand() QFETCH(int, maxY); m_view->setRubberBand(rubberBand); - QRect padding = m_view->chart()->padding(); + QRect padding = m_view->chart()->margins(); QCOMPARE(m_view->rubberBand(), rubberBand); QLineSeries* line = new QLineSeries(); @@ -186,7 +186,7 @@ void tst_QChartView::keys() QFETCH(int, Xcount); QFETCH(int, Ycount); - QRect padding = m_view->chart()->padding(); + QRect padding = m_view->chart()->margins(); QLineSeries* line = new QLineSeries(); *line << QPointF(0, 0) << QPointF(100, 100);