##// END OF EJS Templates
Refactor graphical side of pie to simplify the implementation.
Jani Honkonen -
r1074:22571433397b
parent child
Show More
@@ -251,11 +251,11 void ChartAnimator::updateLayout(XYChartItem *item, QVector<QPointF> &oldPoints,
251 QTimer::singleShot(0, animation, SLOT(start()));
251 QTimer::singleShot(0, animation, SLOT(start()));
252 }
252 }
253
253
254 void ChartAnimator::addAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData, bool isEmpty)
254 void ChartAnimator::addAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData, bool startupAnimation)
255 {
255 {
256 PieAnimation *animation = static_cast<PieAnimation *>(m_animations.value(item));
256 PieAnimation *animation = static_cast<PieAnimation *>(m_animations.value(item));
257 Q_ASSERT(animation);
257 Q_ASSERT(animation);
258 animation->addSlice(sliceItem, sliceData, isEmpty);
258 animation->addSlice(sliceItem, sliceData, startupAnimation);
259 }
259 }
260
260
261 void ChartAnimator::removeAnimation(PieChartItem *item, PieSliceItem *sliceItem)
261 void ChartAnimator::removeAnimation(PieChartItem *item, PieSliceItem *sliceItem)
@@ -265,14 +265,7 void ChartAnimator::removeAnimation(PieChartItem *item, PieSliceItem *sliceItem)
265 animation->removeSlice(sliceItem);
265 animation->removeSlice(sliceItem);
266 }
266 }
267
267
268 void ChartAnimator::updateLayout(PieChartItem *item, const PieLayout &layout)
268 void ChartAnimator::updateAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData)
269 {
270 PieAnimation *animation = static_cast<PieAnimation *>(m_animations.value(item));
271 Q_ASSERT(animation);
272 animation->updateValues(layout);
273 }
274
275 void ChartAnimator::updateLayout(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData)
276 {
269 {
277 PieAnimation *animation = static_cast<PieAnimation *>(m_animations.value(item));
270 PieAnimation *animation = static_cast<PieAnimation *>(m_animations.value(item));
278 Q_ASSERT(animation);
271 Q_ASSERT(animation);
@@ -61,8 +61,7 public:
61
61
62 void addAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData, bool isEmpty);
62 void addAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData, bool isEmpty);
63 void removeAnimation(PieChartItem *item, PieSliceItem *sliceItem);
63 void removeAnimation(PieChartItem *item, PieSliceItem *sliceItem);
64 void updateLayout(PieChartItem *item, const PieLayout &layout);
64 void updateAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData);
65 void updateLayout(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData);
66
65
67 void updateLayout(BarChartItem *item, const QVector<QRectF> &oldLayout, const QVector<QRectF> &newLayout);
66 void updateLayout(BarChartItem *item, const QVector<QRectF> &oldLayout, const QVector<QRectF> &newLayout);
68
67
@@ -36,12 +36,6 PieAnimation::~PieAnimation()
36 {
36 {
37 }
37 }
38
38
39 void PieAnimation::updateValues(const PieLayout &newValues)
40 {
41 foreach (PieSliceItem *s, newValues.keys())
42 updateValue(s, newValues.value(s));
43 }
44
45 void PieAnimation::updateValue(PieSliceItem *sliceItem, const PieSliceData &sliceData)
39 void PieAnimation::updateValue(PieSliceItem *sliceItem, const PieSliceData &sliceData)
46 {
40 {
47 PieSliceAnimation *animation = m_animations.value(sliceItem);
41 PieSliceAnimation *animation = m_animations.value(sliceItem);
@@ -55,14 +49,14 void PieAnimation::updateValue(PieSliceItem *sliceItem, const PieSliceData &slic
55 QTimer::singleShot(0, animation, SLOT(start()));
49 QTimer::singleShot(0, animation, SLOT(start()));
56 }
50 }
57
51
58 void PieAnimation::addSlice(PieSliceItem *sliceItem, const PieSliceData &sliceData, bool isEmpty)
52 void PieAnimation::addSlice(PieSliceItem *sliceItem, const PieSliceData &sliceData, bool startupAnimation)
59 {
53 {
60 PieSliceAnimation *animation = new PieSliceAnimation(sliceItem);
54 PieSliceAnimation *animation = new PieSliceAnimation(sliceItem);
61 m_animations.insert(sliceItem, animation);
55 m_animations.insert(sliceItem, animation);
62
56
63 PieSliceData startValue = sliceData;
57 PieSliceData startValue = sliceData;
64 startValue.m_radius = 0;
58 startValue.m_radius = 0;
65 if (isEmpty)
59 if (startupAnimation)
66 startValue.m_startAngle = 0;
60 startValue.m_startAngle = 0;
67 else
61 else
68 startValue.m_startAngle = sliceData.m_startAngle + (sliceData.m_angleSpan / 2);
62 startValue.m_startAngle = sliceData.m_startAngle + (sliceData.m_angleSpan / 2);
@@ -36,9 +36,8 class PieAnimation : public ChartAnimation
36 public:
36 public:
37 PieAnimation(PieChartItem *item);
37 PieAnimation(PieChartItem *item);
38 ~PieAnimation();
38 ~PieAnimation();
39 void updateValues(const PieLayout &newValues);
40 void updateValue(PieSliceItem *sliceItem, const PieSliceData &newValue);
39 void updateValue(PieSliceItem *sliceItem, const PieSliceData &newValue);
41 void addSlice(PieSliceItem *sliceItem, const PieSliceData &endValue, bool isEmpty);
40 void addSlice(PieSliceItem *sliceItem, const PieSliceData &endValue, bool startupAnimation);
42 void removeSlice(PieSliceItem *sliceItem);
41 void removeSlice(PieSliceItem *sliceItem);
43
42
44 public: // from QVariantAnimation
43 public: // from QVariantAnimation
@@ -118,9 +118,7 void PieSliceAnimation::updateCurrentValue(const QVariant &value)
118 {
118 {
119 if (state() != QAbstractAnimation::Stopped) { //workaround
119 if (state() != QAbstractAnimation::Stopped) { //workaround
120 m_currentValue = qVariantValue<PieSliceData>(value);
120 m_currentValue = qVariantValue<PieSliceData>(value);
121 m_sliceItem->setSliceData(m_currentValue);
121 m_sliceItem->setLayout(m_currentValue);
122 m_sliceItem->updateGeometry();
123 m_sliceItem->update();
124 }
122 }
125 }
123 }
126
124
@@ -40,8 +40,8 PieChartItem::PieChartItem(QPieSeries *series, ChartPresenter* presenter)
40 QPieSeriesPrivate *d = QPieSeriesPrivate::seriesData(*series);
40 QPieSeriesPrivate *d = QPieSeriesPrivate::seriesData(*series);
41 connect(d, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleSlicesAdded(QList<QPieSlice*>)));
41 connect(d, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleSlicesAdded(QList<QPieSlice*>)));
42 connect(d, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleSlicesRemoved(QList<QPieSlice*>)));
42 connect(d, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleSlicesRemoved(QList<QPieSlice*>)));
43 connect(d, SIGNAL(piePositionChanged()), this, SLOT(handlePieLayoutChanged()));
43 connect(d, SIGNAL(piePositionChanged()), this, SLOT(updateLayout()));
44 connect(d, SIGNAL(pieSizeChanged()), this, SLOT(handlePieLayoutChanged()));
44 connect(d, SIGNAL(pieSizeChanged()), this, SLOT(updateLayout()));
45
45
46 QTimer::singleShot(0, this, SLOT(initialize())); // TODO: get rid of this
46 QTimer::singleShot(0, this, SLOT(initialize())); // TODO: get rid of this
47
47
@@ -54,13 +54,11 PieChartItem::~PieChartItem()
54 // slices deleted automatically through QGraphicsItem
54 // slices deleted automatically through QGraphicsItem
55 }
55 }
56
56
57 void PieChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
57 void PieChartItem::handleGeometryChanged(const QRectF& rect)
58 {
58 {
59 Q_UNUSED(painter)
59 prepareGeometryChange();
60 // TODO: paint shadows for all components
60 m_rect = rect;
61 // - get paths from items & merge & offset and draw with shadow color?
61 updateLayout();
62 //painter->setBrush(QBrush(Qt::red));
63 //painter->drawRect(m_debugRect);
64 }
62 }
65
63
66 void PieChartItem::initialize()
64 void PieChartItem::initialize()
@@ -68,141 +66,95 void PieChartItem::initialize()
68 handleSlicesAdded(m_series->slices());
66 handleSlicesAdded(m_series->slices());
69 }
67 }
70
68
71 void PieChartItem::handleSlicesAdded(QList<QPieSlice*> slices)
69 void PieChartItem::updateLayout()
72 {
70 {
73 bool isEmpty = m_slices.isEmpty();
71 // find pie center coordinates
74
72 m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition()));
75 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
73 m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition()));
76
74
77 foreach (QPieSlice *s, slices) {
75 // find maximum radius for pie
78 PieSliceItem* item = new PieSliceItem(this);
76 m_pieRadius = m_rect.height() / 2;
79 m_slices.insert(s, item);
77 if (m_rect.width() < m_rect.height())
80 connect(s, SIGNAL(changed()), this, SLOT(handleSliceChanged()));
78 m_pieRadius = m_rect.width() / 2;
81 connect(item, SIGNAL(clicked(Qt::MouseButtons)), s, SIGNAL(clicked()));
82 connect(item, SIGNAL(hovered(bool)), s, SIGNAL(hovered(bool)));
83
79
84 PieSliceData data = sliceData(s);
80 // apply size factor
81 m_pieRadius *= m_series->pieSize();
85
82
83 // set layouts for existing slice items
84 foreach (QPieSlice* slice, m_series->slices()) {
85 PieSliceItem *sliceItem = m_sliceItems.value(slice);
86 if (sliceItem) {
87 PieSliceData sliceData = updateSliceGeometry(slice);
86 if (animator())
88 if (animator())
87 animator()->addAnimation(this, item, data, isEmpty);
89 animator()->updateAnimation(this, sliceItem, sliceData);
88 else
90 else
89 setLayout(item, data);
91 sliceItem->setLayout(sliceData);
90 }
92 }
91 }
93 }
92
94
93 void PieChartItem::handleSlicesRemoved(QList<QPieSlice*> slices)
95 update();
96 }
97
98 void PieChartItem::handleSlicesAdded(QList<QPieSlice*> slices)
94 {
99 {
95 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
100 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
96
101
97 foreach (QPieSlice *slice, slices) {
102 bool startupAnimation = m_sliceItems.isEmpty();
98
103
99 PieSliceItem *item = m_slices.value(slice);
104 foreach (QPieSlice *slice, slices) {
100 Q_ASSERT(item);
105 PieSliceItem* sliceItem = new PieSliceItem(this);
101 m_slices.remove(slice);
106 m_sliceItems.insert(slice, sliceItem);
107 connect(slice, SIGNAL(changed()), this, SLOT(handleSliceChanged()));
108 connect(sliceItem, SIGNAL(clicked(Qt::MouseButtons)), slice, SIGNAL(clicked()));
109 connect(sliceItem, SIGNAL(hovered(bool)), slice, SIGNAL(hovered(bool)));
102
110
111 PieSliceData sliceData = updateSliceGeometry(slice);
103 if (animator())
112 if (animator())
104 animator()->removeAnimation(this, item); // animator deletes the PieSliceItem
113 animator()->addAnimation(this, sliceItem, sliceData, startupAnimation);
105 else
114 else
106 delete item;
115 sliceItem->setLayout(sliceData);
107 }
116 }
108 }
117 }
109
118
110 void PieChartItem::handlePieLayoutChanged()
119 void PieChartItem::handleSlicesRemoved(QList<QPieSlice*> slices)
111 {
120 {
112 PieLayout layout = calculateLayout();
121 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
113 applyLayout(layout);
114 update();
115 }
116
122
117 void PieChartItem::handleSliceChanged()
123 foreach (QPieSlice *slice, slices) {
118 {
124 PieSliceItem *sliceItem = m_sliceItems.value(slice);
119 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
125 Q_ASSERT(sliceItem);
120 Q_ASSERT(m_slices.contains(slice));
126 m_sliceItems.remove(slice);
121 PieSliceData data = sliceData(slice);
122 updateLayout(m_slices.value(slice), data);
123 update();
124 }
125
127
126 void PieChartItem::handleDomainChanged(qreal, qreal, qreal, qreal)
128 if (animator())
127 {
129 animator()->removeAnimation(this, sliceItem); // animator deletes the PieSliceItem
128 // TODO
130 else
131 delete sliceItem;
129 }
132 }
130
131 void PieChartItem::handleGeometryChanged(const QRectF& rect)
132 {
133 prepareGeometryChange();
134 m_rect = rect;
135 handlePieLayoutChanged();
136 }
133 }
137
134
138 void PieChartItem::calculatePieLayout()
135 void PieChartItem::handleSliceChanged()
139 {
136 {
140 // find pie center coordinates
137 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
141 m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition()));
138 Q_ASSERT(m_sliceItems.contains(slice));
142 m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition()));
143
139
144 // find maximum radius for pie
140 PieSliceItem *sliceItem = m_sliceItems.value(slice);
145 m_pieRadius = m_rect.height() / 2;
141 PieSliceData sliceData = updateSliceGeometry(slice);
146 if (m_rect.width() < m_rect.height())
142 if (animator())
147 m_pieRadius = m_rect.width() / 2;
143 animator()->updateAnimation(this, sliceItem, sliceData);
144 else
145 sliceItem->setLayout(sliceData);
148
146
149 // apply size factor
147 update();
150 m_pieRadius *= m_series->pieSize();
151 }
148 }
152
149
153 PieSliceData PieChartItem::sliceData(QPieSlice *slice)
150 PieSliceData PieChartItem::updateSliceGeometry(QPieSlice *slice)
154 {
151 {
155 // TODO: This function is kid of useless now. Refactor.
152 PieSliceData &sliceData = PieSliceData::data(slice);
156 PieSliceData sliceData = PieSliceData::data(slice);
157 sliceData.m_center = PieSliceItem::sliceCenter(m_pieCenter, m_pieRadius, slice);
153 sliceData.m_center = PieSliceItem::sliceCenter(m_pieCenter, m_pieRadius, slice);
158 sliceData.m_radius = m_pieRadius;
154 sliceData.m_radius = m_pieRadius;
159 return sliceData;
155 return sliceData;
160 }
156 }
161
157
162 PieLayout PieChartItem::calculateLayout()
163 {
164 calculatePieLayout();
165 PieLayout layout;
166 foreach (QPieSlice* s, m_series->slices()) {
167 if (m_slices.contains(s)) // calculate layout only for those slices that are already visible
168 layout.insert(m_slices.value(s), sliceData(s));
169 }
170 return layout;
171 }
172
173 void PieChartItem::applyLayout(const PieLayout &layout)
174 {
175 if (animator())
176 animator()->updateLayout(this, layout);
177 else
178 setLayout(layout);
179 }
180
181 void PieChartItem::updateLayout(PieSliceItem *sliceItem, const PieSliceData &sliceData)
182 {
183 if (animator())
184 animator()->updateLayout(this, sliceItem, sliceData);
185 else
186 setLayout(sliceItem, sliceData);
187 }
188
189 void PieChartItem::setLayout(const PieLayout &layout)
190 {
191 foreach (PieSliceItem *item, layout.keys()) {
192 item->setSliceData(layout.value(item));
193 item->updateGeometry();
194 item->update();
195 }
196 }
197
198 void PieChartItem::setLayout(PieSliceItem *sliceItem, const PieSliceData &sliceData)
199 {
200 Q_ASSERT(sliceItem);
201 sliceItem->setSliceData(sliceData);
202 sliceItem->updateGeometry();
203 sliceItem->update();
204 }
205
206 #include "moc_piechartitem_p.cpp"
158 #include "moc_piechartitem_p.cpp"
207
159
208 QTCOMMERCIALCHART_END_NAMESPACE
160 QTCOMMERCIALCHART_END_NAMESPACE
@@ -30,42 +30,37 QTCOMMERCIALCHART_BEGIN_NAMESPACE
30 class QPieSlice;
30 class QPieSlice;
31 class ChartPresenter;
31 class ChartPresenter;
32
32
33 typedef QHash<PieSliceItem*, PieSliceData> PieLayout;
34
35 class PieChartItem : public ChartItem
33 class PieChartItem : public ChartItem
36 {
34 {
37 Q_OBJECT
35 Q_OBJECT
38
36
39 public:
37 public:
40 // TODO: use a generic data class instead of x and y
38 explicit PieChartItem(QPieSeries *series, ChartPresenter *presenter);
41 PieChartItem(QPieSeries *series, ChartPresenter *presenter);
42 ~PieChartItem();
39 ~PieChartItem();
43
40
44 public: // from QGraphicsItem
41 // from QGraphicsItem
45 QRectF boundingRect() const { return m_rect; }
42 QRectF boundingRect() const { return m_rect; }
46 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
43 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {}
47
44
48 public Q_SLOTS:
45 public Q_SLOTS:
46 // from Chart
47 virtual void handleGeometryChanged(const QRectF &rect);
48 // TODO: Do we have actual need for these at all? What is the use case for pie?
49 //virtual void handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY);
50 //virtual void rangeXChanged(qreal min, qreal max, int tickXCount);
51 //virtual void rangeYChanged(qreal min, qreal max, int tickYCount);
52
49 void initialize();
53 void initialize();
54 void updateLayout();
50 void handleSlicesAdded(QList<QPieSlice*> slices);
55 void handleSlicesAdded(QList<QPieSlice*> slices);
51 void handleSlicesRemoved(QList<QPieSlice*> slices);
56 void handleSlicesRemoved(QList<QPieSlice*> slices);
52 void handlePieLayoutChanged();
53 void handleSliceChanged();
57 void handleSliceChanged();
54 void handleDomainChanged(qreal, qreal, qreal, qreal);
55 void handleGeometryChanged(const QRectF& rect);
56
58
57 public:
59 private:
58 void calculatePieLayout();
60 PieSliceData updateSliceGeometry(QPieSlice *slice);
59 PieSliceData sliceData(QPieSlice *slice);
60 PieLayout calculateLayout();
61 void applyLayout(const PieLayout &layout);
62 void updateLayout(PieSliceItem *sliceItem, const PieSliceData &sliceData);
63 void setLayout(const PieLayout &layout);
64 void setLayout(PieSliceItem *sliceItem, const PieSliceData &sliceData);
65
61
66 private:
62 private:
67 friend class PieSliceItem;
63 QHash<QPieSlice*, PieSliceItem*> m_sliceItems;
68 QHash<QPieSlice*, PieSliceItem*> m_slices;
69 QPieSeries *m_series;
64 QPieSeries *m_series;
70 QRectF m_rect;
65 QRectF m_rect;
71 QPointF m_pieCenter;
66 QPointF m_pieCenter;
@@ -98,9 +98,11 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
98 emit clicked(event->buttons());
98 emit clicked(event->buttons());
99 }
99 }
100
100
101 void PieSliceItem::setSliceData(PieSliceData sliceData)
101 void PieSliceItem::setLayout(const PieSliceData &sliceData)
102 {
102 {
103 m_data = sliceData;
103 m_data = sliceData;
104 updateGeometry();
105 update();
104 }
106 }
105
107
106 void PieSliceItem::updateGeometry()
108 void PieSliceItem::updateGeometry()
@@ -45,7 +45,7 public:
45 PieSliceItem(QGraphicsItem* parent = 0);
45 PieSliceItem(QGraphicsItem* parent = 0);
46 ~PieSliceItem();
46 ~PieSliceItem();
47
47
48 public: // from QGraphicsItem
48 // from QGraphicsItem
49 QRectF boundingRect() const;
49 QRectF boundingRect() const;
50 QPainterPath shape() const;
50 QPainterPath shape() const;
51 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
51 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
@@ -53,14 +53,15 public: // from QGraphicsItem
53 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
53 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
54 void mousePressEvent(QGraphicsSceneMouseEvent *event);
54 void mousePressEvent(QGraphicsSceneMouseEvent *event);
55
55
56 void setLayout(const PieSliceData &sliceData);
57 static QPointF sliceCenter(QPointF point, qreal radius, QPieSlice *slice);
58
56 Q_SIGNALS:
59 Q_SIGNALS:
57 void clicked(Qt::MouseButtons buttons);
60 void clicked(Qt::MouseButtons buttons);
58 void hovered(bool state);
61 void hovered(bool state);
59
62
60 public:
63 private:
61 void setSliceData(PieSliceData sliceData);
62 void updateGeometry();
64 void updateGeometry();
63 static QPointF sliceCenter(QPointF point, qreal radius, QPieSlice *slice);
64 QPainterPath slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF *armStart);
65 QPainterPath slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF *armStart);
65 QPainterPath labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart);
66 QPainterPath labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart);
66 QRectF labelTextRect(QFont font, QString text);
67 QRectF labelTextRect(QFont font, QString text);
General Comments 0
You need to be logged in to leave comments. Login now