##// END OF EJS Templates
Fixed a bug with pie slice clip rect
Tero Ahola -
r1297:e9ff71cfa16b
parent child
Show More
@@ -1,220 +1,223
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2012 Digia Plc
3 ** Copyright (C) 2012 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Commercial Charts Add-on.
7 ** This file is part of the Qt Commercial Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Commercial licenses may use this file in
10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 ** accordance with the Qt Commercial License Agreement provided with the
11 ** accordance with the Qt Commercial License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #include "piesliceitem_p.h"
21 #include "piesliceitem_p.h"
22 #include "piechartitem_p.h"
22 #include "piechartitem_p.h"
23 #include "qpieseries.h"
23 #include "qpieseries.h"
24 #include "qpieslice.h"
24 #include "qpieslice.h"
25 #include "chartpresenter_p.h"
25 #include "chartpresenter_p.h"
26 #include <QPainter>
26 #include <QPainter>
27 #include <qmath.h>
27 #include <qmath.h>
28 #include <QGraphicsSceneEvent>
28 #include <QGraphicsSceneEvent>
29 #include <QTime>
29 #include <QTime>
30 #include <QDebug>
30
31
31 QTCOMMERCIALCHART_BEGIN_NAMESPACE
32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
32
33
33 #define PI 3.14159265 // TODO: is this defined in some header?
34 #define PI 3.14159265 // TODO: is this defined in some header?
34
35
35 QPointF offset(qreal angle, qreal length)
36 QPointF offset(qreal angle, qreal length)
36 {
37 {
37 qreal dx = qSin(angle*(PI/180)) * length;
38 qreal dx = qSin(angle*(PI/180)) * length;
38 qreal dy = qCos(angle*(PI/180)) * length;
39 qreal dy = qCos(angle*(PI/180)) * length;
39 return QPointF(dx, -dy);
40 return QPointF(dx, -dy);
40 }
41 }
41
42
42 PieSliceItem::PieSliceItem(QGraphicsItem* parent)
43 PieSliceItem::PieSliceItem(QGraphicsItem* parent)
43 :QGraphicsObject(parent),
44 :QGraphicsObject(parent),
44 m_hovered(false)
45 m_hovered(false)
45 {
46 {
46 setAcceptHoverEvents(true);
47 setAcceptHoverEvents(true);
47 setAcceptedMouseButtons(Qt::MouseButtonMask);
48 setAcceptedMouseButtons(Qt::MouseButtonMask);
48 setZValue(ChartPresenter::PieSeriesZValue);
49 setZValue(ChartPresenter::PieSeriesZValue);
49 }
50 }
50
51
51 PieSliceItem::~PieSliceItem()
52 PieSliceItem::~PieSliceItem()
52 {
53 {
53 // If user is hovering over the slice and it gets destroyed we do
54 // If user is hovering over the slice and it gets destroyed we do
54 // not get a hover leave event. So we must emit the signal here.
55 // not get a hover leave event. So we must emit the signal here.
55 if (m_hovered)
56 if (m_hovered)
56 emit hovered(false);
57 emit hovered(false);
57 }
58 }
58
59
59 QRectF PieSliceItem::boundingRect() const
60 QRectF PieSliceItem::boundingRect() const
60 {
61 {
61 return m_boundingRect;
62 return m_boundingRect;
62 }
63 }
63
64
64 QPainterPath PieSliceItem::shape() const
65 QPainterPath PieSliceItem::shape() const
65 {
66 {
66 // Don't include the label and label arm.
67 // Don't include the label and label arm.
67 // This is used to detect a mouse clicks. We do not want clicks from label.
68 // This is used to detect a mouse clicks. We do not want clicks from label.
68 return m_slicePath;
69 return m_slicePath;
69 }
70 }
70
71
71 void PieSliceItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
72 void PieSliceItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
72 {
73 {
73 painter->save();
74 painter->save();
74 painter->setClipRect(parentItem()->boundingRect());
75 painter->setClipRect(parentItem()->boundingRect());
75 painter->setPen(m_data.m_slicePen);
76 painter->setPen(m_data.m_slicePen);
76 painter->setBrush(m_data.m_sliceBrush);
77 painter->setBrush(m_data.m_sliceBrush);
77 painter->drawPath(m_slicePath);
78 painter->drawPath(m_slicePath);
78 painter->restore();
79 painter->restore();
79
80
80 if (m_data.m_isLabelVisible) {
81 if (m_data.m_isLabelVisible) {
82 painter->save();
81 painter->setClipRect(parentItem()->boundingRect());
83 painter->setClipRect(parentItem()->boundingRect());
82 painter->setPen(m_data.m_labelPen);
84 painter->setPen(m_data.m_labelPen);
83 painter->drawPath(m_labelArmPath);
85 painter->drawPath(m_labelArmPath);
84 // the pen color will affect the font color as well
86 // the pen color will affect the font color as well
85 painter->setFont(m_data.m_labelFont);
87 painter->setFont(m_data.m_labelFont);
86 painter->drawText(m_labelTextRect.bottomLeft(), m_data.m_labelText);
88 painter->drawText(m_labelTextRect.bottomLeft(), m_data.m_labelText);
89 painter->restore();
87 }
90 }
88 }
91 }
89
92
90 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
93 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
91 {
94 {
92 m_hovered = true;
95 m_hovered = true;
93 emit hovered(true);
96 emit hovered(true);
94 }
97 }
95
98
96 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
99 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
97 {
100 {
98 m_hovered = false;
101 m_hovered = false;
99 emit hovered(false);
102 emit hovered(false);
100 }
103 }
101
104
102 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
105 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
103 {
106 {
104 emit clicked(event->buttons());
107 emit clicked(event->buttons());
105 }
108 }
106
109
107 void PieSliceItem::setLayout(const PieSliceData &sliceData)
110 void PieSliceItem::setLayout(const PieSliceData &sliceData)
108 {
111 {
109 m_data = sliceData;
112 m_data = sliceData;
110 updateGeometry();
113 updateGeometry();
111 update();
114 update();
112 }
115 }
113
116
114 void PieSliceItem::updateGeometry()
117 void PieSliceItem::updateGeometry()
115 {
118 {
116 if (m_data.m_radius <= 0)
119 if (m_data.m_radius <= 0)
117 return;
120 return;
118
121
119 prepareGeometryChange();
122 prepareGeometryChange();
120
123
121 // update slice path
124 // update slice path
122 qreal centerAngle;
125 qreal centerAngle;
123 QPointF armStart;
126 QPointF armStart;
124 m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
127 m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
125
128
126 // update text rect
129 // update text rect
127 m_labelTextRect = labelTextRect(m_data.m_labelFont, m_data.m_labelText);
130 m_labelTextRect = labelTextRect(m_data.m_labelFont, m_data.m_labelText);
128
131
129 // update label arm path
132 // update label arm path
130 QPointF labelTextStart;
133 QPointF labelTextStart;
131 m_labelArmPath = labelArmPath(armStart, centerAngle, m_data.m_radius * m_data.m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
134 m_labelArmPath = labelArmPath(armStart, centerAngle, m_data.m_radius * m_data.m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
132
135
133 // update text position
136 // update text position
134 m_labelTextRect.moveBottomLeft(labelTextStart);
137 m_labelTextRect.moveBottomLeft(labelTextStart);
135
138
136 // update bounding rect
139 // update bounding rect
137 if (m_data.m_isLabelVisible)
140 if (m_data.m_isLabelVisible)
138 m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
141 m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
139 else
142 else
140 m_boundingRect = m_slicePath.boundingRect();
143 m_boundingRect = m_slicePath.boundingRect();
141 }
144 }
142
145
143 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
146 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
144 {
147 {
145 if (slice->isExploded()) {
148 if (slice->isExploded()) {
146 qreal centerAngle = slice->startAngle() + (slice->angleSpan()/2);
149 qreal centerAngle = slice->startAngle() + (slice->angleSpan()/2);
147 qreal len = radius * slice->explodeDistanceFactor();
150 qreal len = radius * slice->explodeDistanceFactor();
148 qreal dx = qSin(centerAngle*(PI/180)) * len;
151 qreal dx = qSin(centerAngle*(PI/180)) * len;
149 qreal dy = -qCos(centerAngle*(PI/180)) * len;
152 qreal dy = -qCos(centerAngle*(PI/180)) * len;
150 point += QPointF(dx, dy);
153 point += QPointF(dx, dy);
151 }
154 }
152 return point;
155 return point;
153 }
156 }
154
157
155 QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF* armStart)
158 QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF* armStart)
156 {
159 {
157 // calculate center angle
160 // calculate center angle
158 *centerAngle = startAngle + (angleSpan/2);
161 *centerAngle = startAngle + (angleSpan/2);
159
162
160 // calculate slice rectangle
163 // calculate slice rectangle
161 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
164 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
162
165
163 // slice path
166 // slice path
164 // TODO: draw the shape so that it might have a hole in the center
167 // TODO: draw the shape so that it might have a hole in the center
165 QPainterPath path;
168 QPainterPath path;
166 path.moveTo(rect.center());
169 path.moveTo(rect.center());
167 path.arcTo(rect, -startAngle + 90, -angleSpan);
170 path.arcTo(rect, -startAngle + 90, -angleSpan);
168 path.closeSubpath();
171 path.closeSubpath();
169
172
170 // calculate label arm start point
173 // calculate label arm start point
171 *armStart = center;
174 *armStart = center;
172 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
175 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
173
176
174 return path;
177 return path;
175 }
178 }
176
179
177 QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart)
180 QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart)
178 {
181 {
179 // prevent label arm pointing straight down because it will look bad
182 // prevent label arm pointing straight down because it will look bad
180 if (angle < 180 && angle > 170)
183 if (angle < 180 && angle > 170)
181 angle = 170;
184 angle = 170;
182 if (angle > 180 && angle < 190)
185 if (angle > 180 && angle < 190)
183 angle = 190;
186 angle = 190;
184
187
185 // line from slice to label
188 // line from slice to label
186 qreal dx = qSin(angle*(PI/180)) * length;
189 qreal dx = qSin(angle*(PI/180)) * length;
187 qreal dy = -qCos(angle*(PI/180)) * length;
190 qreal dy = -qCos(angle*(PI/180)) * length;
188 QPointF parm1 = start + QPointF(dx, dy);
191 QPointF parm1 = start + QPointF(dx, dy);
189
192
190 // line to underline the label
193 // line to underline the label
191 QPointF parm2 = parm1;
194 QPointF parm2 = parm1;
192 if (angle < 180) { // arm swings the other way on the left side
195 if (angle < 180) { // arm swings the other way on the left side
193 parm2 += QPointF(textWidth, 0);
196 parm2 += QPointF(textWidth, 0);
194 *textStart = parm1;
197 *textStart = parm1;
195 }
198 }
196 else {
199 else {
197 parm2 += QPointF(-textWidth,0);
200 parm2 += QPointF(-textWidth,0);
198 *textStart = parm2;
201 *textStart = parm2;
199 }
202 }
200
203
201 // elevate the text position a bit so that it does not hit the line
204 // elevate the text position a bit so that it does not hit the line
202 *textStart += QPointF(0, -3);
205 *textStart += QPointF(0, -3);
203
206
204 QPainterPath path;
207 QPainterPath path;
205 path.moveTo(start);
208 path.moveTo(start);
206 path.lineTo(parm1);
209 path.lineTo(parm1);
207 path.lineTo(parm2);
210 path.lineTo(parm2);
208
211
209 return path;
212 return path;
210 }
213 }
211
214
212 QRectF PieSliceItem::labelTextRect(QFont font, QString text)
215 QRectF PieSliceItem::labelTextRect(QFont font, QString text)
213 {
216 {
214 QFontMetricsF fm(font);
217 QFontMetricsF fm(font);
215 return fm.boundingRect(text);
218 return fm.boundingRect(text);
216 }
219 }
217
220
218 #include "moc_piesliceitem_p.cpp"
221 #include "moc_piesliceitem_p.cpp"
219
222
220 QTCOMMERCIALCHART_END_NAMESPACE
223 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now