From 22571433397baf60b008157b0ffee2895eb6b12b 2012-04-20 12:59:57 From: Jani Honkonen Date: 2012-04-20 12:59:57 Subject: [PATCH] Refactor graphical side of pie to simplify the implementation. --- diff --git a/src/animations/chartanimator.cpp b/src/animations/chartanimator.cpp index 8464def..51eb5b8 100644 --- a/src/animations/chartanimator.cpp +++ b/src/animations/chartanimator.cpp @@ -251,11 +251,11 @@ void ChartAnimator::updateLayout(XYChartItem *item, QVector &oldPoints, QTimer::singleShot(0, animation, SLOT(start())); } -void ChartAnimator::addAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData, bool isEmpty) +void ChartAnimator::addAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData, bool startupAnimation) { PieAnimation *animation = static_cast(m_animations.value(item)); Q_ASSERT(animation); - animation->addSlice(sliceItem, sliceData, isEmpty); + animation->addSlice(sliceItem, sliceData, startupAnimation); } void ChartAnimator::removeAnimation(PieChartItem *item, PieSliceItem *sliceItem) @@ -265,14 +265,7 @@ void ChartAnimator::removeAnimation(PieChartItem *item, PieSliceItem *sliceItem) animation->removeSlice(sliceItem); } -void ChartAnimator::updateLayout(PieChartItem *item, const PieLayout &layout) -{ - PieAnimation *animation = static_cast(m_animations.value(item)); - Q_ASSERT(animation); - animation->updateValues(layout); -} - -void ChartAnimator::updateLayout(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData) +void ChartAnimator::updateAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData) { PieAnimation *animation = static_cast(m_animations.value(item)); Q_ASSERT(animation); diff --git a/src/animations/chartanimator_p.h b/src/animations/chartanimator_p.h index 5891b15..0e5db5f 100644 --- a/src/animations/chartanimator_p.h +++ b/src/animations/chartanimator_p.h @@ -61,8 +61,7 @@ public: void addAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData, bool isEmpty); void removeAnimation(PieChartItem *item, PieSliceItem *sliceItem); - void updateLayout(PieChartItem *item, const PieLayout &layout); - void updateLayout(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData); + void updateAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData); void updateLayout(BarChartItem *item, const QVector &oldLayout, const QVector &newLayout); diff --git a/src/animations/pieanimation.cpp b/src/animations/pieanimation.cpp index bcaf140..1eb2a53 100644 --- a/src/animations/pieanimation.cpp +++ b/src/animations/pieanimation.cpp @@ -36,12 +36,6 @@ PieAnimation::~PieAnimation() { } -void PieAnimation::updateValues(const PieLayout &newValues) -{ - foreach (PieSliceItem *s, newValues.keys()) - updateValue(s, newValues.value(s)); -} - void PieAnimation::updateValue(PieSliceItem *sliceItem, const PieSliceData &sliceData) { PieSliceAnimation *animation = m_animations.value(sliceItem); @@ -55,14 +49,14 @@ void PieAnimation::updateValue(PieSliceItem *sliceItem, const PieSliceData &slic QTimer::singleShot(0, animation, SLOT(start())); } -void PieAnimation::addSlice(PieSliceItem *sliceItem, const PieSliceData &sliceData, bool isEmpty) +void PieAnimation::addSlice(PieSliceItem *sliceItem, const PieSliceData &sliceData, bool startupAnimation) { PieSliceAnimation *animation = new PieSliceAnimation(sliceItem); m_animations.insert(sliceItem, animation); PieSliceData startValue = sliceData; startValue.m_radius = 0; - if (isEmpty) + if (startupAnimation) startValue.m_startAngle = 0; else startValue.m_startAngle = sliceData.m_startAngle + (sliceData.m_angleSpan / 2); diff --git a/src/animations/pieanimation_p.h b/src/animations/pieanimation_p.h index fe05136..a60487a 100644 --- a/src/animations/pieanimation_p.h +++ b/src/animations/pieanimation_p.h @@ -36,9 +36,8 @@ class PieAnimation : public ChartAnimation public: PieAnimation(PieChartItem *item); ~PieAnimation(); - void updateValues(const PieLayout &newValues); void updateValue(PieSliceItem *sliceItem, const PieSliceData &newValue); - void addSlice(PieSliceItem *sliceItem, const PieSliceData &endValue, bool isEmpty); + void addSlice(PieSliceItem *sliceItem, const PieSliceData &endValue, bool startupAnimation); void removeSlice(PieSliceItem *sliceItem); public: // from QVariantAnimation diff --git a/src/animations/piesliceanimation.cpp b/src/animations/piesliceanimation.cpp index 3cb0ae1..618e5d9 100644 --- a/src/animations/piesliceanimation.cpp +++ b/src/animations/piesliceanimation.cpp @@ -118,9 +118,7 @@ void PieSliceAnimation::updateCurrentValue(const QVariant &value) { if (state() != QAbstractAnimation::Stopped) { //workaround m_currentValue = qVariantValue(value); - m_sliceItem->setSliceData(m_currentValue); - m_sliceItem->updateGeometry(); - m_sliceItem->update(); + m_sliceItem->setLayout(m_currentValue); } } diff --git a/src/piechart/piechartitem.cpp b/src/piechart/piechartitem.cpp index 23c2e39..a25ffc1 100644 --- a/src/piechart/piechartitem.cpp +++ b/src/piechart/piechartitem.cpp @@ -40,8 +40,8 @@ PieChartItem::PieChartItem(QPieSeries *series, ChartPresenter* presenter) QPieSeriesPrivate *d = QPieSeriesPrivate::seriesData(*series); connect(d, SIGNAL(added(QList)), this, SLOT(handleSlicesAdded(QList))); connect(d, SIGNAL(removed(QList)), this, SLOT(handleSlicesRemoved(QList))); - connect(d, SIGNAL(piePositionChanged()), this, SLOT(handlePieLayoutChanged())); - connect(d, SIGNAL(pieSizeChanged()), this, SLOT(handlePieLayoutChanged())); + connect(d, SIGNAL(piePositionChanged()), this, SLOT(updateLayout())); + connect(d, SIGNAL(pieSizeChanged()), this, SLOT(updateLayout())); QTimer::singleShot(0, this, SLOT(initialize())); // TODO: get rid of this @@ -54,13 +54,11 @@ PieChartItem::~PieChartItem() // slices deleted automatically through QGraphicsItem } -void PieChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +void PieChartItem::handleGeometryChanged(const QRectF& rect) { - Q_UNUSED(painter) - // TODO: paint shadows for all components - // - get paths from items & merge & offset and draw with shadow color? - //painter->setBrush(QBrush(Qt::red)); - //painter->drawRect(m_debugRect); + prepareGeometryChange(); + m_rect = rect; + updateLayout(); } void PieChartItem::initialize() @@ -68,25 +66,53 @@ void PieChartItem::initialize() handleSlicesAdded(m_series->slices()); } -void PieChartItem::handleSlicesAdded(QList slices) +void PieChartItem::updateLayout() { - bool isEmpty = m_slices.isEmpty(); + // find pie center coordinates + m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition())); + m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition())); + // find maximum radius for pie + m_pieRadius = m_rect.height() / 2; + if (m_rect.width() < m_rect.height()) + m_pieRadius = m_rect.width() / 2; + + // apply size factor + m_pieRadius *= m_series->pieSize(); + + // set layouts for existing slice items + foreach (QPieSlice* slice, m_series->slices()) { + PieSliceItem *sliceItem = m_sliceItems.value(slice); + if (sliceItem) { + PieSliceData sliceData = updateSliceGeometry(slice); + if (animator()) + animator()->updateAnimation(this, sliceItem, sliceData); + else + sliceItem->setLayout(sliceData); + } + } + + update(); +} + +void PieChartItem::handleSlicesAdded(QList slices) +{ presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series)); - foreach (QPieSlice *s, slices) { - PieSliceItem* item = new PieSliceItem(this); - m_slices.insert(s, item); - connect(s, SIGNAL(changed()), this, SLOT(handleSliceChanged())); - connect(item, SIGNAL(clicked(Qt::MouseButtons)), s, SIGNAL(clicked())); - connect(item, SIGNAL(hovered(bool)), s, SIGNAL(hovered(bool))); + bool startupAnimation = m_sliceItems.isEmpty(); - PieSliceData data = sliceData(s); + foreach (QPieSlice *slice, slices) { + PieSliceItem* sliceItem = new PieSliceItem(this); + m_sliceItems.insert(slice, sliceItem); + connect(slice, SIGNAL(changed()), this, SLOT(handleSliceChanged())); + connect(sliceItem, SIGNAL(clicked(Qt::MouseButtons)), slice, SIGNAL(clicked())); + connect(sliceItem, SIGNAL(hovered(bool)), slice, SIGNAL(hovered(bool))); + PieSliceData sliceData = updateSliceGeometry(slice); if (animator()) - animator()->addAnimation(this, item, data, isEmpty); + animator()->addAnimation(this, sliceItem, sliceData, startupAnimation); else - setLayout(item, data); + sliceItem->setLayout(sliceData); } } @@ -95,114 +121,40 @@ void PieChartItem::handleSlicesRemoved(QList slices) presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series)); foreach (QPieSlice *slice, slices) { - - PieSliceItem *item = m_slices.value(slice); - Q_ASSERT(item); - m_slices.remove(slice); + PieSliceItem *sliceItem = m_sliceItems.value(slice); + Q_ASSERT(sliceItem); + m_sliceItems.remove(slice); if (animator()) - animator()->removeAnimation(this, item); // animator deletes the PieSliceItem + animator()->removeAnimation(this, sliceItem); // animator deletes the PieSliceItem else - delete item; + delete sliceItem; } } -void PieChartItem::handlePieLayoutChanged() -{ - PieLayout layout = calculateLayout(); - applyLayout(layout); - update(); -} - void PieChartItem::handleSliceChanged() { QPieSlice* slice = qobject_cast(sender()); - Q_ASSERT(m_slices.contains(slice)); - PieSliceData data = sliceData(slice); - updateLayout(m_slices.value(slice), data); - update(); -} - -void PieChartItem::handleDomainChanged(qreal, qreal, qreal, qreal) -{ - // TODO -} - -void PieChartItem::handleGeometryChanged(const QRectF& rect) -{ - prepareGeometryChange(); - m_rect = rect; - handlePieLayoutChanged(); -} - -void PieChartItem::calculatePieLayout() -{ - // find pie center coordinates - m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition())); - m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition())); + Q_ASSERT(m_sliceItems.contains(slice)); - // find maximum radius for pie - m_pieRadius = m_rect.height() / 2; - if (m_rect.width() < m_rect.height()) - m_pieRadius = m_rect.width() / 2; + PieSliceItem *sliceItem = m_sliceItems.value(slice); + PieSliceData sliceData = updateSliceGeometry(slice); + if (animator()) + animator()->updateAnimation(this, sliceItem, sliceData); + else + sliceItem->setLayout(sliceData); - // apply size factor - m_pieRadius *= m_series->pieSize(); + update(); } -PieSliceData PieChartItem::sliceData(QPieSlice *slice) +PieSliceData PieChartItem::updateSliceGeometry(QPieSlice *slice) { - // TODO: This function is kid of useless now. Refactor. - PieSliceData sliceData = PieSliceData::data(slice); + PieSliceData &sliceData = PieSliceData::data(slice); sliceData.m_center = PieSliceItem::sliceCenter(m_pieCenter, m_pieRadius, slice); sliceData.m_radius = m_pieRadius; return sliceData; } -PieLayout PieChartItem::calculateLayout() -{ - calculatePieLayout(); - PieLayout layout; - foreach (QPieSlice* s, m_series->slices()) { - if (m_slices.contains(s)) // calculate layout only for those slices that are already visible - layout.insert(m_slices.value(s), sliceData(s)); - } - return layout; -} - -void PieChartItem::applyLayout(const PieLayout &layout) -{ - if (animator()) - animator()->updateLayout(this, layout); - else - setLayout(layout); -} - -void PieChartItem::updateLayout(PieSliceItem *sliceItem, const PieSliceData &sliceData) -{ - if (animator()) - animator()->updateLayout(this, sliceItem, sliceData); - else - setLayout(sliceItem, sliceData); -} - -void PieChartItem::setLayout(const PieLayout &layout) -{ - foreach (PieSliceItem *item, layout.keys()) { - item->setSliceData(layout.value(item)); - item->updateGeometry(); - item->update(); - } -} - -void PieChartItem::setLayout(PieSliceItem *sliceItem, const PieSliceData &sliceData) -{ - Q_ASSERT(sliceItem); - sliceItem->setSliceData(sliceData); - sliceItem->updateGeometry(); - sliceItem->update(); -} - #include "moc_piechartitem_p.cpp" QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/piechart/piechartitem_p.h b/src/piechart/piechartitem_p.h index 35e9e9f..0b9cd58 100644 --- a/src/piechart/piechartitem_p.h +++ b/src/piechart/piechartitem_p.h @@ -30,42 +30,37 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE class QPieSlice; class ChartPresenter; -typedef QHash PieLayout; - class PieChartItem : public ChartItem { Q_OBJECT public: - // TODO: use a generic data class instead of x and y - PieChartItem(QPieSeries *series, ChartPresenter *presenter); + explicit PieChartItem(QPieSeries *series, ChartPresenter *presenter); ~PieChartItem(); -public: // from QGraphicsItem + // from QGraphicsItem QRectF boundingRect() const { return m_rect; } - void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {} public Q_SLOTS: + // from Chart + virtual void handleGeometryChanged(const QRectF &rect); + // TODO: Do we have actual need for these at all? What is the use case for pie? + //virtual void handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY); + //virtual void rangeXChanged(qreal min, qreal max, int tickXCount); + //virtual void rangeYChanged(qreal min, qreal max, int tickYCount); + void initialize(); + void updateLayout(); void handleSlicesAdded(QList slices); void handleSlicesRemoved(QList slices); - void handlePieLayoutChanged(); void handleSliceChanged(); - void handleDomainChanged(qreal, qreal, qreal, qreal); - void handleGeometryChanged(const QRectF& rect); -public: - void calculatePieLayout(); - PieSliceData sliceData(QPieSlice *slice); - PieLayout calculateLayout(); - void applyLayout(const PieLayout &layout); - void updateLayout(PieSliceItem *sliceItem, const PieSliceData &sliceData); - void setLayout(const PieLayout &layout); - void setLayout(PieSliceItem *sliceItem, const PieSliceData &sliceData); +private: + PieSliceData updateSliceGeometry(QPieSlice *slice); private: - friend class PieSliceItem; - QHash m_slices; + QHash m_sliceItems; QPieSeries *m_series; QRectF m_rect; QPointF m_pieCenter; diff --git a/src/piechart/piesliceitem.cpp b/src/piechart/piesliceitem.cpp index 85b7b02..f59969d 100644 --- a/src/piechart/piesliceitem.cpp +++ b/src/piechart/piesliceitem.cpp @@ -98,9 +98,11 @@ void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event) emit clicked(event->buttons()); } -void PieSliceItem::setSliceData(PieSliceData sliceData) +void PieSliceItem::setLayout(const PieSliceData &sliceData) { m_data = sliceData; + updateGeometry(); + update(); } void PieSliceItem::updateGeometry() diff --git a/src/piechart/piesliceitem_p.h b/src/piechart/piesliceitem_p.h index 0ae02f4..8e338d7 100644 --- a/src/piechart/piesliceitem_p.h +++ b/src/piechart/piesliceitem_p.h @@ -45,7 +45,7 @@ public: PieSliceItem(QGraphicsItem* parent = 0); ~PieSliceItem(); -public: // from QGraphicsItem + // from QGraphicsItem QRectF boundingRect() const; QPainterPath shape() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); @@ -53,14 +53,15 @@ public: // from QGraphicsItem void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); void mousePressEvent(QGraphicsSceneMouseEvent *event); + void setLayout(const PieSliceData &sliceData); + static QPointF sliceCenter(QPointF point, qreal radius, QPieSlice *slice); + Q_SIGNALS: void clicked(Qt::MouseButtons buttons); void hovered(bool state); -public: - void setSliceData(PieSliceData sliceData); +private: void updateGeometry(); - static QPointF sliceCenter(QPointF point, qreal radius, QPieSlice *slice); QPainterPath slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF *armStart); QPainterPath labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart); QRectF labelTextRect(QFont font, QString text);