##// 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 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 256 PieAnimation *animation = static_cast<PieAnimation *>(m_animations.value(item));
257 257 Q_ASSERT(animation);
258 animation->addSlice(sliceItem, sliceData, isEmpty);
258 animation->addSlice(sliceItem, sliceData, startupAnimation);
259 259 }
260 260
261 261 void ChartAnimator::removeAnimation(PieChartItem *item, PieSliceItem *sliceItem)
@@ -265,14 +265,7 void ChartAnimator::removeAnimation(PieChartItem *item, PieSliceItem *sliceItem)
265 265 animation->removeSlice(sliceItem);
266 266 }
267 267
268 void ChartAnimator::updateLayout(PieChartItem *item, const PieLayout &layout)
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)
268 void ChartAnimator::updateAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData)
276 269 {
277 270 PieAnimation *animation = static_cast<PieAnimation *>(m_animations.value(item));
278 271 Q_ASSERT(animation);
@@ -61,8 +61,7 public:
61 61
62 62 void addAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData, bool isEmpty);
63 63 void removeAnimation(PieChartItem *item, PieSliceItem *sliceItem);
64 void updateLayout(PieChartItem *item, const PieLayout &layout);
65 void updateLayout(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData);
64 void updateAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData);
66 65
67 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 39 void PieAnimation::updateValue(PieSliceItem *sliceItem, const PieSliceData &sliceData)
46 40 {
47 41 PieSliceAnimation *animation = m_animations.value(sliceItem);
@@ -55,14 +49,14 void PieAnimation::updateValue(PieSliceItem *sliceItem, const PieSliceData &slic
55 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 54 PieSliceAnimation *animation = new PieSliceAnimation(sliceItem);
61 55 m_animations.insert(sliceItem, animation);
62 56
63 57 PieSliceData startValue = sliceData;
64 58 startValue.m_radius = 0;
65 if (isEmpty)
59 if (startupAnimation)
66 60 startValue.m_startAngle = 0;
67 61 else
68 62 startValue.m_startAngle = sliceData.m_startAngle + (sliceData.m_angleSpan / 2);
@@ -36,9 +36,8 class PieAnimation : public ChartAnimation
36 36 public:
37 37 PieAnimation(PieChartItem *item);
38 38 ~PieAnimation();
39 void updateValues(const PieLayout &newValues);
40 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 41 void removeSlice(PieSliceItem *sliceItem);
43 42
44 43 public: // from QVariantAnimation
@@ -118,9 +118,7 void PieSliceAnimation::updateCurrentValue(const QVariant &value)
118 118 {
119 119 if (state() != QAbstractAnimation::Stopped) { //workaround
120 120 m_currentValue = qVariantValue<PieSliceData>(value);
121 m_sliceItem->setSliceData(m_currentValue);
122 m_sliceItem->updateGeometry();
123 m_sliceItem->update();
121 m_sliceItem->setLayout(m_currentValue);
124 122 }
125 123 }
126 124
@@ -40,8 +40,8 PieChartItem::PieChartItem(QPieSeries *series, ChartPresenter* presenter)
40 40 QPieSeriesPrivate *d = QPieSeriesPrivate::seriesData(*series);
41 41 connect(d, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleSlicesAdded(QList<QPieSlice*>)));
42 42 connect(d, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleSlicesRemoved(QList<QPieSlice*>)));
43 connect(d, SIGNAL(piePositionChanged()), this, SLOT(handlePieLayoutChanged()));
44 connect(d, SIGNAL(pieSizeChanged()), this, SLOT(handlePieLayoutChanged()));
43 connect(d, SIGNAL(piePositionChanged()), this, SLOT(updateLayout()));
44 connect(d, SIGNAL(pieSizeChanged()), this, SLOT(updateLayout()));
45 45
46 46 QTimer::singleShot(0, this, SLOT(initialize())); // TODO: get rid of this
47 47
@@ -54,13 +54,11 PieChartItem::~PieChartItem()
54 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)
60 // TODO: paint shadows for all components
61 // - get paths from items & merge & offset and draw with shadow color?
62 //painter->setBrush(QBrush(Qt::red));
63 //painter->drawRect(m_debugRect);
59 prepareGeometryChange();
60 m_rect = rect;
61 updateLayout();
64 62 }
65 63
66 64 void PieChartItem::initialize()
@@ -68,25 +66,53 void PieChartItem::initialize()
68 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
72 m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition()));
73 m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition()));
74 74
75 // find maximum radius for pie
76 m_pieRadius = m_rect.height() / 2;
77 if (m_rect.width() < m_rect.height())
78 m_pieRadius = m_rect.width() / 2;
79
80 // apply size factor
81 m_pieRadius *= m_series->pieSize();
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);
88 if (animator())
89 animator()->updateAnimation(this, sliceItem, sliceData);
90 else
91 sliceItem->setLayout(sliceData);
92 }
93 }
94
95 update();
96 }
97
98 void PieChartItem::handleSlicesAdded(QList<QPieSlice*> slices)
99 {
75 100 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
76 101
77 foreach (QPieSlice *s, slices) {
78 PieSliceItem* item = new PieSliceItem(this);
79 m_slices.insert(s, item);
80 connect(s, SIGNAL(changed()), this, SLOT(handleSliceChanged()));
81 connect(item, SIGNAL(clicked(Qt::MouseButtons)), s, SIGNAL(clicked()));
82 connect(item, SIGNAL(hovered(bool)), s, SIGNAL(hovered(bool)));
102 bool startupAnimation = m_sliceItems.isEmpty();
83 103
84 PieSliceData data = sliceData(s);
104 foreach (QPieSlice *slice, slices) {
105 PieSliceItem* sliceItem = new PieSliceItem(this);
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)));
85 110
111 PieSliceData sliceData = updateSliceGeometry(slice);
86 112 if (animator())
87 animator()->addAnimation(this, item, data, isEmpty);
113 animator()->addAnimation(this, sliceItem, sliceData, startupAnimation);
88 114 else
89 setLayout(item, data);
115 sliceItem->setLayout(sliceData);
90 116 }
91 117 }
92 118
@@ -95,114 +121,40 void PieChartItem::handleSlicesRemoved(QList<QPieSlice*> slices)
95 121 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
96 122
97 123 foreach (QPieSlice *slice, slices) {
98
99 PieSliceItem *item = m_slices.value(slice);
100 Q_ASSERT(item);
101 m_slices.remove(slice);
124 PieSliceItem *sliceItem = m_sliceItems.value(slice);
125 Q_ASSERT(sliceItem);
126 m_sliceItems.remove(slice);
102 127
103 128 if (animator())
104 animator()->removeAnimation(this, item); // animator deletes the PieSliceItem
129 animator()->removeAnimation(this, sliceItem); // animator deletes the PieSliceItem
105 130 else
106 delete item;
131 delete sliceItem;
107 132 }
108 133 }
109 134
110 void PieChartItem::handlePieLayoutChanged()
111 {
112 PieLayout layout = calculateLayout();
113 applyLayout(layout);
114 update();
115 }
116
117 135 void PieChartItem::handleSliceChanged()
118 136 {
119 137 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
120 Q_ASSERT(m_slices.contains(slice));
121 PieSliceData data = sliceData(slice);
122 updateLayout(m_slices.value(slice), data);
123 update();
124 }
125
126 void PieChartItem::handleDomainChanged(qreal, qreal, qreal, qreal)
127 {
128 // TODO
129 }
130
131 void PieChartItem::handleGeometryChanged(const QRectF& rect)
132 {
133 prepareGeometryChange();
134 m_rect = rect;
135 handlePieLayoutChanged();
136 }
137
138 void PieChartItem::calculatePieLayout()
139 {
140 // find pie center coordinates
141 m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition()));
142 m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition()));
138 Q_ASSERT(m_sliceItems.contains(slice));
143 139
144 // find maximum radius for pie
145 m_pieRadius = m_rect.height() / 2;
146 if (m_rect.width() < m_rect.height())
147 m_pieRadius = m_rect.width() / 2;
140 PieSliceItem *sliceItem = m_sliceItems.value(slice);
141 PieSliceData sliceData = updateSliceGeometry(slice);
142 if (animator())
143 animator()->updateAnimation(this, sliceItem, sliceData);
144 else
145 sliceItem->setLayout(sliceData);
148 146
149 // apply size factor
150 m_pieRadius *= m_series->pieSize();
147 update();
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.
156 PieSliceData sliceData = PieSliceData::data(slice);
152 PieSliceData &sliceData = PieSliceData::data(slice);
157 153 sliceData.m_center = PieSliceItem::sliceCenter(m_pieCenter, m_pieRadius, slice);
158 154 sliceData.m_radius = m_pieRadius;
159 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 158 #include "moc_piechartitem_p.cpp"
207 159
208 160 QTCOMMERCIALCHART_END_NAMESPACE
@@ -30,42 +30,37 QTCOMMERCIALCHART_BEGIN_NAMESPACE
30 30 class QPieSlice;
31 31 class ChartPresenter;
32 32
33 typedef QHash<PieSliceItem*, PieSliceData> PieLayout;
34
35 33 class PieChartItem : public ChartItem
36 34 {
37 35 Q_OBJECT
38 36
39 37 public:
40 // TODO: use a generic data class instead of x and y
41 PieChartItem(QPieSeries *series, ChartPresenter *presenter);
38 explicit PieChartItem(QPieSeries *series, ChartPresenter *presenter);
42 39 ~PieChartItem();
43 40
44 public: // from QGraphicsItem
41 // from QGraphicsItem
45 42 QRectF boundingRect() const { return m_rect; }
46 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
43 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {}
47 44
48 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 53 void initialize();
54 void updateLayout();
50 55 void handleSlicesAdded(QList<QPieSlice*> slices);
51 56 void handleSlicesRemoved(QList<QPieSlice*> slices);
52 void handlePieLayoutChanged();
53 57 void handleSliceChanged();
54 void handleDomainChanged(qreal, qreal, qreal, qreal);
55 void handleGeometryChanged(const QRectF& rect);
56 58
57 public:
58 void calculatePieLayout();
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);
59 private:
60 PieSliceData updateSliceGeometry(QPieSlice *slice);
65 61
66 62 private:
67 friend class PieSliceItem;
68 QHash<QPieSlice*, PieSliceItem*> m_slices;
63 QHash<QPieSlice*, PieSliceItem*> m_sliceItems;
69 64 QPieSeries *m_series;
70 65 QRectF m_rect;
71 66 QPointF m_pieCenter;
@@ -98,9 +98,11 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
98 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 103 m_data = sliceData;
104 updateGeometry();
105 update();
104 106 }
105 107
106 108 void PieSliceItem::updateGeometry()
@@ -45,7 +45,7 public:
45 45 PieSliceItem(QGraphicsItem* parent = 0);
46 46 ~PieSliceItem();
47 47
48 public: // from QGraphicsItem
48 // from QGraphicsItem
49 49 QRectF boundingRect() const;
50 50 QPainterPath shape() const;
51 51 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
@@ -53,14 +53,15 public: // from QGraphicsItem
53 53 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
54 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 59 Q_SIGNALS:
57 60 void clicked(Qt::MouseButtons buttons);
58 61 void hovered(bool state);
59 62
60 public:
61 void setSliceData(PieSliceData sliceData);
63 private:
62 64 void updateGeometry();
63 static QPointF sliceCenter(QPointF point, qreal radius, QPieSlice *slice);
64 65 QPainterPath slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF *armStart);
65 66 QPainterPath labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart);
66 67 QRectF labelTextRect(QFont font, QString text);
General Comments 0
You need to be logged in to leave comments. Login now