##// END OF EJS Templates
Minor fix.
Marek Rosa -
r1694:8ec588a26fd8
parent child
Show More
@@ -1,249 +1,250
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 #include <QDebug>
31
31
32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33
33
34 QPointF offset(qreal angle, qreal length)
34 QPointF offset(qreal angle, qreal length)
35 {
35 {
36 qreal dx = qSin(angle*(M_PI/180)) * length;
36 qreal dx = qSin(angle*(M_PI/180)) * length;
37 qreal dy = qCos(angle*(M_PI/180)) * length;
37 qreal dy = qCos(angle*(M_PI/180)) * length;
38 return QPointF(dx, -dy);
38 return QPointF(dx, -dy);
39 }
39 }
40
40
41 PieSliceItem::PieSliceItem(QGraphicsItem* parent)
41 PieSliceItem::PieSliceItem(QGraphicsItem* parent)
42 :QGraphicsObject(parent),
42 :QGraphicsObject(parent),
43 m_hovered(false)
43 m_hovered(false)
44 {
44 {
45 setAcceptHoverEvents(true);
45 setAcceptHoverEvents(true);
46 setAcceptedMouseButtons(Qt::MouseButtonMask);
46 setAcceptedMouseButtons(Qt::MouseButtonMask);
47 setZValue(ChartPresenter::PieSeriesZValue);
47 setZValue(ChartPresenter::PieSeriesZValue);
48 }
48 }
49
49
50 PieSliceItem::~PieSliceItem()
50 PieSliceItem::~PieSliceItem()
51 {
51 {
52 // If user is hovering over the slice and it gets destroyed we do
52 // If user is hovering over the slice and it gets destroyed we do
53 // not get a hover leave event. So we must emit the signal here.
53 // not get a hover leave event. So we must emit the signal here.
54 if (m_hovered)
54 if (m_hovered)
55 emit hovered(false);
55 emit hovered(false);
56 }
56 }
57
57
58 QRectF PieSliceItem::boundingRect() const
58 QRectF PieSliceItem::boundingRect() const
59 {
59 {
60 return m_boundingRect;
60 return m_boundingRect;
61 }
61 }
62
62
63 QPainterPath PieSliceItem::shape() const
63 QPainterPath PieSliceItem::shape() const
64 {
64 {
65 // Don't include the label and label arm.
65 // Don't include the label and label arm.
66 // This is used to detect a mouse clicks. We do not want clicks from label.
66 // This is used to detect a mouse clicks. We do not want clicks from label.
67 return m_slicePath;
67 return m_slicePath;
68 }
68 }
69
69
70 void PieSliceItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
70 void PieSliceItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
71 {
71 {
72 painter->save();
72 painter->save();
73 painter->setClipRect(parentItem()->boundingRect());
73 painter->setClipRect(parentItem()->boundingRect());
74 painter->setPen(m_data.m_slicePen);
74 painter->setPen(m_data.m_slicePen);
75 painter->setBrush(m_data.m_sliceBrush);
75 painter->setBrush(m_data.m_sliceBrush);
76 painter->drawPath(m_slicePath);
76 painter->drawPath(m_slicePath);
77 painter->restore();
77 painter->restore();
78
78
79 if (m_data.m_isLabelVisible) {
79 if (m_data.m_isLabelVisible) {
80 painter->save();
80 painter->save();
81
81
82 // Pen for label arm not defined in the QPieSeries api, let's use brush's color instead
82 // Pen for label arm not defined in the QPieSeries api, let's use brush's color instead
83 // Also, the drawText actually uses the pen color for the text color (unlike QGraphicsSimpleTextItem)
83 // Also, the drawText actually uses the pen color for the text color (unlike QGraphicsSimpleTextItem)
84 painter->setPen(m_data.m_labelBrush.color());
84 painter->setPen(m_data.m_labelBrush.color());
85 painter->setBrush(m_data.m_labelBrush);
85 painter->setBrush(m_data.m_labelBrush);
86 painter->setFont(m_data.m_labelFont);
86 painter->setFont(m_data.m_labelFont);
87 if (m_data.m_donut) {
87 if (m_data.m_donut) {
88 painter->translate(m_labelTextRect.center());
88 painter->translate(m_labelTextRect.center());
89 painter->rotate(m_data.m_startAngle + m_data.m_angleSpan / 2);
89 painter->rotate(m_data.m_startAngle + m_data.m_angleSpan / 2);
90 painter->drawText(-m_labelTextRect.width() / 2, -m_labelTextRect.height() / 2, m_labelTextRect.width(), m_labelTextRect.height(), Qt::AlignCenter, m_data.m_labelText);
90 painter->drawText(-m_labelTextRect.width() / 2, -m_labelTextRect.height() / 2, m_labelTextRect.width(), m_labelTextRect.height(), Qt::AlignCenter, m_data.m_labelText);
91 }else if (m_data.m_labelPosition == QPieSlice::LabelOutside) {
91 }else if (m_data.m_labelPosition == QPieSlice::LabelOutside) {
92 painter->setClipRect(parentItem()->boundingRect());
92 painter->setClipRect(parentItem()->boundingRect());
93 painter->strokePath(m_labelArmPath, m_data.m_labelBrush.color());
93 painter->strokePath(m_labelArmPath, m_data.m_labelBrush.color());
94 painter->drawText(m_labelTextRect, Qt::AlignCenter, m_data.m_labelText);
94 } else { // QPieSlice::LabelInside
95 } else { // QPieSlice::LabelInside
95 painter->setClipPath(m_slicePath);
96 painter->setClipPath(m_slicePath);
96 painter->drawText(m_labelTextRect, Qt::AlignCenter, m_data.m_labelText);
97 painter->drawText(m_labelTextRect, Qt::AlignCenter, m_data.m_labelText);
97 }
98 }
98
99
99 painter->restore();
100 painter->restore();
100 }
101 }
101 }
102 }
102
103
103 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
104 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
104 {
105 {
105 m_hovered = true;
106 m_hovered = true;
106 emit hovered(true);
107 emit hovered(true);
107 }
108 }
108
109
109 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
110 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
110 {
111 {
111 m_hovered = false;
112 m_hovered = false;
112 emit hovered(false);
113 emit hovered(false);
113 }
114 }
114
115
115 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
116 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
116 {
117 {
117 emit clicked(event->buttons());
118 emit clicked(event->buttons());
118 }
119 }
119
120
120 void PieSliceItem::setLayout(const PieSliceData &sliceData)
121 void PieSliceItem::setLayout(const PieSliceData &sliceData)
121 {
122 {
122 m_data = sliceData;
123 m_data = sliceData;
123 updateGeometry();
124 updateGeometry();
124 update();
125 update();
125 }
126 }
126
127
127 void PieSliceItem::updateGeometry()
128 void PieSliceItem::updateGeometry()
128 {
129 {
129 if (m_data.m_radius <= 0)
130 if (m_data.m_radius <= 0)
130 return;
131 return;
131
132
132 prepareGeometryChange();
133 prepareGeometryChange();
133
134
134 // slice path
135 // slice path
135 qreal centerAngle;
136 qreal centerAngle;
136 QPointF armStart;
137 QPointF armStart;
137 m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
138 m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
138
139
139 // text rect
140 // text rect
140 QFontMetricsF fm(m_data.m_labelFont);
141 QFontMetricsF fm(m_data.m_labelFont);
141 m_labelTextRect = QRectF(0, 0, fm.width(m_data.m_labelText), fm.height());
142 m_labelTextRect = QRectF(0, 0, fm.width(m_data.m_labelText), fm.height());
142
143
143 // label arm path
144 // label arm path
144 QPointF labelTextStart;
145 QPointF labelTextStart;
145 m_labelArmPath = labelArmPath(armStart, centerAngle, m_data.m_radius * m_data.m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
146 m_labelArmPath = labelArmPath(armStart, centerAngle, m_data.m_radius * m_data.m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
146
147
147 // text position
148 // text position
148 if (m_data.m_donut) {
149 if (m_data.m_donut) {
149 QPointF donutCenter = m_data.m_center + offset(centerAngle, m_data.m_innerRadius + (m_data.m_radius - m_data.m_innerRadius) / 2);
150 QPointF donutCenter = m_data.m_center + offset(centerAngle, m_data.m_innerRadius + (m_data.m_radius - m_data.m_innerRadius) / 2);
150 m_labelTextRect.moveCenter(donutCenter);
151 m_labelTextRect.moveCenter(donutCenter);
151 } else if (m_data.m_labelPosition == QPieSlice::LabelOutside) {
152 } else if (m_data.m_labelPosition == QPieSlice::LabelOutside) {
152 m_labelTextRect.moveBottomLeft(labelTextStart);
153 m_labelTextRect.moveBottomLeft(labelTextStart);
153 } else {// QPieSlice::LabelInside
154 } else {// QPieSlice::LabelInside
154 QPointF sliceCenter = m_data.m_center + offset(centerAngle, m_data.m_radius / 2);
155 QPointF sliceCenter = m_data.m_center + offset(centerAngle, m_data.m_radius / 2);
155 m_labelTextRect.moveCenter(sliceCenter);
156 m_labelTextRect.moveCenter(sliceCenter);
156 }
157 }
157
158
158 // bounding rect
159 // bounding rect
159 if (m_data.m_isLabelVisible)
160 if (m_data.m_isLabelVisible)
160 m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
161 m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
161 else
162 else
162 m_boundingRect = m_slicePath.boundingRect();
163 m_boundingRect = m_slicePath.boundingRect();
163 }
164 }
164
165
165 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
166 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
166 {
167 {
167 if (slice->isExploded()) {
168 if (slice->isExploded()) {
168 qreal centerAngle = slice->startAngle() + (slice->angleSpan()/2);
169 qreal centerAngle = slice->startAngle() + (slice->angleSpan()/2);
169 qreal len = radius * slice->explodeDistanceFactor();
170 qreal len = radius * slice->explodeDistanceFactor();
170 point += offset(centerAngle, len);
171 point += offset(centerAngle, len);
171 }
172 }
172 return point;
173 return point;
173 }
174 }
174
175
175 QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF* armStart)
176 QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF* armStart)
176 {
177 {
177 // calculate center angle
178 // calculate center angle
178 *centerAngle = startAngle + (angleSpan/2);
179 *centerAngle = startAngle + (angleSpan/2);
179
180
180 // calculate slice rectangle
181 // calculate slice rectangle
181 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
182 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
182
183
183 // slice path
184 // slice path
184 QPainterPath path;
185 QPainterPath path;
185 if (m_data.m_donut) {
186 if (m_data.m_donut) {
186 QRectF insideRect(center.x() - m_data.m_innerRadius, center.y()-m_data.m_innerRadius, m_data.m_innerRadius*2, m_data.m_innerRadius*2);
187 QRectF insideRect(center.x() - m_data.m_innerRadius, center.y()-m_data.m_innerRadius, m_data.m_innerRadius*2, m_data.m_innerRadius*2);
187 path.arcMoveTo(rect, -startAngle + 90);
188 path.arcMoveTo(rect, -startAngle + 90);
188 path.arcTo(rect, -startAngle + 90, -angleSpan);
189 path.arcTo(rect, -startAngle + 90, -angleSpan);
189 path.arcTo(insideRect, -startAngle + 90 - angleSpan, angleSpan);
190 path.arcTo(insideRect, -startAngle + 90 - angleSpan, angleSpan);
190 path.closeSubpath();
191 path.closeSubpath();
191 } else {
192 } else {
192 path.moveTo(rect.center());
193 path.moveTo(rect.center());
193 path.arcTo(rect, -startAngle + 90, -angleSpan);
194 path.arcTo(rect, -startAngle + 90, -angleSpan);
194 path.closeSubpath();
195 path.closeSubpath();
195 }
196 }
196
197
197 // calculate label arm start point
198 // calculate label arm start point
198 *armStart = center;
199 *armStart = center;
199 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
200 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
200
201
201 return path;
202 return path;
202 }
203 }
203
204
204 QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart)
205 QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart)
205 {
206 {
206 // Normalize the angle to 0-360 range
207 // Normalize the angle to 0-360 range
207 // NOTE: We are using int here on purpose. Depenging on platform and hardware
208 // NOTE: We are using int here on purpose. Depenging on platform and hardware
208 // qreal can be a double, float or something the user gives to the Qt configure
209 // qreal can be a double, float or something the user gives to the Qt configure
209 // (QT_COORD_TYPE). Compilers do not seem to support modulo for double or float
210 // (QT_COORD_TYPE). Compilers do not seem to support modulo for double or float
210 // but there are fmod() and fmodf() functions for that. So instead of some #ifdef
211 // but there are fmod() and fmodf() functions for that. So instead of some #ifdef
211 // that might break we just use int. Precision for this is just fine for our needs.
212 // that might break we just use int. Precision for this is just fine for our needs.
212 int normalized = angle * 10.0;
213 int normalized = angle * 10.0;
213 normalized = normalized % 3600;
214 normalized = normalized % 3600;
214 if (normalized < 0)
215 if (normalized < 0)
215 normalized += 3600;
216 normalized += 3600;
216 angle = (qreal) normalized / 10.0;
217 angle = (qreal) normalized / 10.0;
217
218
218 // prevent label arm pointing straight down because it will look bad
219 // prevent label arm pointing straight down because it will look bad
219 if (angle < 180 && angle > 170)
220 if (angle < 180 && angle > 170)
220 angle = 170;
221 angle = 170;
221 if (angle > 180 && angle < 190)
222 if (angle > 180 && angle < 190)
222 angle = 190;
223 angle = 190;
223
224
224 // line from slice to label
225 // line from slice to label
225 QPointF parm1 = start + offset(angle, length);
226 QPointF parm1 = start + offset(angle, length);
226
227
227 // line to underline the label
228 // line to underline the label
228 QPointF parm2 = parm1;
229 QPointF parm2 = parm1;
229 if (angle < 180) { // arm swings the other way on the left side
230 if (angle < 180) { // arm swings the other way on the left side
230 parm2 += QPointF(textWidth, 0);
231 parm2 += QPointF(textWidth, 0);
231 *textStart = parm1;
232 *textStart = parm1;
232 }
233 }
233 else {
234 else {
234 parm2 += QPointF(-textWidth,0);
235 parm2 += QPointF(-textWidth,0);
235 *textStart = parm2;
236 *textStart = parm2;
236 }
237 }
237
238
238 QPainterPath path;
239 QPainterPath path;
239 path.moveTo(start);
240 path.moveTo(start);
240 path.lineTo(parm1);
241 path.lineTo(parm1);
241 path.lineTo(parm2);
242 path.lineTo(parm2);
242
243
243 return path;
244 return path;
244 }
245 }
245
246
246 #include "moc_piesliceitem_p.cpp"
247 #include "moc_piesliceitem_p.cpp"
247
248
248 QTCOMMERCIALCHART_END_NAMESPACE
249 QTCOMMERCIALCHART_END_NAMESPACE
249
250
General Comments 0
You need to be logged in to leave comments. Login now