##// END OF EJS Templates
Added a pie chart customization example and refactoring the pie interface.
Jani Honkonen -
r437:8d9e377a1065
parent child
Show More
@@ -0,0 +1,224
1 #include <QtGui/QApplication>
2 #include <QMainWindow>
3 #include <qchartglobal.h>
4 #include <qchartview.h>
5 #include <qpieseries.h>
6 #include <qpieslice.h>
7 #include <QGridLayout>
8 #include <QFormLayout>
9 #include <QComboBox>
10 #include <QSpinBox>
11 #include <QCheckBox>
12 #include <QGroupBox>
13 #include <QLabel>
14
15 QTCOMMERCIALCHART_USE_NAMESPACE
16
17 Q_DECLARE_METATYPE(QPieSeries::PiePosition)
18
19 class CustomSlice : public QPieSlice
20 {
21 Q_OBJECT
22 public:
23 CustomSlice(qreal value, QString label)
24 :QPieSlice(value, label)
25 {
26 connect(this, SIGNAL(hoverEnter()), this, SLOT(handleHoverEnter()));
27 connect(this, SIGNAL(hoverLeave()), this, SLOT(handleHoverLeave()));
28 }
29
30 public Q_SLOTS:
31
32 void handleHoverEnter()
33 {
34 QBrush brush = this->brush();
35 m_originalBrush = brush;
36 brush.setColor(brush.color().lighter());
37 setBrush(brush);
38 }
39
40 void handleHoverLeave()
41 {
42 setBrush(m_originalBrush);
43 }
44
45 private:
46 QBrush m_originalBrush;
47 };
48
49 class MainWidget : public QWidget
50 {
51 Q_OBJECT
52
53 public:
54 explicit MainWidget(QWidget* parent = 0)
55 :QWidget(parent)
56 {
57 m_chartView = new QChartView();
58 m_chartView->setChartTitle("Piechart customization");
59 //m_chartView->setRenderHint(QPainter::Antialiasing);
60
61 m_series = new QPieSeries();
62 *m_series << new CustomSlice(10.0, "Slice 1");
63 *m_series << new CustomSlice(20.0, "Slice 2");
64 *m_series << new CustomSlice(30.0, "Slice 3");
65 *m_series << new CustomSlice(40.0, "Slice 4");
66 *m_series << new CustomSlice(50.0, "Slice 5");
67 m_chartView->addSeries(m_series);
68
69 m_vPosition = new QComboBox();
70 m_vPosition->addItem("Top", QPieSeries::PiePositionTop);
71 m_vPosition->addItem("Bottom", QPieSeries::PiePositionBottom);
72 m_vPosition->addItem("Center", QPieSeries::PiePositionVCenter);
73
74 m_hPosition = new QComboBox();
75 m_hPosition->addItem("Left", QPieSeries::PiePositionLeft);
76 m_hPosition->addItem("Right", QPieSeries::PiePositionRight);
77 m_hPosition->addItem("Center", QPieSeries::PiePositionHCenter);
78
79 m_sizePolicy = new QComboBox();
80 m_sizePolicy->addItem("Maximized", QPieSeries::PieSizePolicyMaximized);
81 m_sizePolicy->addItem("Space for labels", QPieSeries::PieSizePolicyReserveSpaceForLabels);
82 m_sizePolicy->addItem("Space for exploding", QPieSeries::PieSizePolicyReserveSpaceForExploding);
83 m_sizePolicy->addItem("Space for all", QPieSeries::PieSizePolicyReserveSpaceForAll);
84
85 m_sizeFactor = new QDoubleSpinBox();
86 m_sizeFactor->setMinimum(0.0);
87 m_sizeFactor->setMaximum(1.0);
88 m_sizeFactor->setValue(m_series->sizeFactor());
89 m_sizeFactor->setSingleStep(0.1);
90
91 m_startAngle = new QDoubleSpinBox();
92 m_startAngle->setMinimum(0.0);
93 m_startAngle->setMaximum(360);
94 m_startAngle->setValue(m_series->startAngle());
95 m_startAngle->setSingleStep(1);
96
97 m_endAngle = new QDoubleSpinBox();
98 m_endAngle->setMinimum(0.0);
99 m_endAngle->setMaximum(360);
100 m_endAngle->setValue(m_series->endAngle());
101 m_endAngle->setSingleStep(1);
102
103 QFormLayout* seriesSettingsLayout = new QFormLayout();
104 seriesSettingsLayout->addRow("Vertical position", m_vPosition);
105 seriesSettingsLayout->addRow("Horizontal position", m_hPosition);
106 seriesSettingsLayout->addRow("Size policy", m_sizePolicy);
107 seriesSettingsLayout->addRow("Size factor", m_sizeFactor);
108 seriesSettingsLayout->addRow("Start angle", m_startAngle);
109 seriesSettingsLayout->addRow("End angle", m_endAngle);
110 QGroupBox* seriesSettings = new QGroupBox("Series");
111 seriesSettings->setLayout(seriesSettingsLayout);
112
113 m_sliceName = new QLabel("<click a slice>");
114 m_sliceValue = new QDoubleSpinBox();
115 m_sliceValue->setMaximum(1000);
116 m_sliceLabelVisible = new QCheckBox();
117 m_sliceExploded = new QCheckBox();
118
119 QFormLayout* sliceSettingsLayout = new QFormLayout();
120 sliceSettingsLayout->addRow("Selected", m_sliceName);
121 sliceSettingsLayout->addRow("Value", m_sliceValue);
122 sliceSettingsLayout->addRow("Label visible", m_sliceLabelVisible);
123 sliceSettingsLayout->addRow("Exploded", m_sliceExploded);
124 QGroupBox* sliceSettings = new QGroupBox("Slice");
125 sliceSettings->setLayout(sliceSettingsLayout);
126
127 QGridLayout* baseLayout = new QGridLayout();
128 baseLayout->addWidget(seriesSettings, 0, 0);
129 baseLayout->addWidget(sliceSettings, 1, 0);
130 baseLayout->addWidget(m_chartView, 0, 1, 2, 1);
131 setLayout(baseLayout);
132
133 connect(m_vPosition, SIGNAL(currentIndexChanged(int)), this, SLOT(updateSerieSettings()));
134 connect(m_hPosition, SIGNAL(currentIndexChanged(int)), this, SLOT(updateSerieSettings()));
135 connect(m_sizePolicy, SIGNAL(currentIndexChanged(int)), this, SLOT(updateSerieSettings()));
136 connect(m_sizeFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
137 connect(m_startAngle, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
138 connect(m_endAngle, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
139
140 connect(m_sliceValue, SIGNAL(valueChanged(double)), this, SLOT(updateSliceSettings()));
141 connect(m_sliceLabelVisible, SIGNAL(toggled(bool)), this, SLOT(updateSliceSettings()));
142 connect(m_sliceExploded, SIGNAL(toggled(bool)), this, SLOT(updateSliceSettings()));
143
144 connect(m_series, SIGNAL(clicked(QPieSlice*)), this, SLOT(handleSliceClicked(QPieSlice*)));
145
146 updateSerieSettings();
147 }
148
149 public Q_SLOTS:
150
151 void updateSerieSettings()
152 {
153 QPieSeries::PiePosition vPos(m_vPosition->itemData(m_vPosition->currentIndex()).toInt());
154 QPieSeries::PiePosition hPos(m_hPosition->itemData(m_hPosition->currentIndex()).toInt());
155 m_series->setPosition(vPos | hPos);
156
157 QPieSeries::PieSizePolicy policy(m_sizePolicy->itemData(m_sizePolicy->currentIndex()).toInt());
158 m_series->setSizePolicy(policy);
159
160 m_series->setSizeFactor(m_sizeFactor->value());
161
162 m_series->setStartAngle(m_startAngle->value());
163 m_series->setEndAngle(m_endAngle->value());
164 }
165
166 void updateSliceSettings()
167 {
168 m_slice->setValue(m_sliceValue->value());
169 m_slice->setLabelVisible(m_sliceLabelVisible->isChecked());
170 m_slice->setExploded(m_sliceExploded->isChecked());
171 }
172
173 void handleSliceClicked(QPieSlice* slice)
174 {
175 m_slice = slice;
176 m_sliceName->setText(slice->label());
177
178 m_sliceValue->blockSignals(true);
179 m_sliceValue->setValue(slice->value());
180 m_sliceValue->blockSignals(false);
181
182 m_sliceLabelVisible->blockSignals(true);
183 m_sliceLabelVisible->setChecked(slice->isLabelVisible());
184 m_sliceLabelVisible->blockSignals(false);
185
186 m_sliceExploded->blockSignals(true);
187 m_sliceExploded->setChecked(slice->isExploded());
188 m_sliceExploded->blockSignals(false);
189 }
190
191 private:
192 QChartView* m_chartView;
193 QPieSeries* m_series;
194 QPieSlice* m_slice;
195
196 QComboBox* m_vPosition;
197 QComboBox* m_hPosition;
198 QComboBox* m_sizePolicy;
199 QDoubleSpinBox* m_sizeFactor;
200 QDoubleSpinBox* m_startAngle;
201 QDoubleSpinBox* m_endAngle;
202
203 QLabel* m_sliceName;
204 QDoubleSpinBox* m_sliceValue;
205 QCheckBox* m_sliceLabelVisible;
206 QCheckBox* m_sliceExploded;
207 };
208
209 int main(int argc, char *argv[])
210 {
211 QApplication a(argc, argv);
212
213 QMainWindow window;
214
215 MainWidget* widget = new MainWidget();
216
217 window.setCentralWidget(widget);
218 window.resize(900, 600);
219 window.show();
220
221 return a.exec();
222 }
223
224 #include "main.moc"
@@ -0,0 +1,8
1 !include( ../example.pri ) {
2 error( "Couldn't find the example.pri file!" )
3 }
4 TARGET = piechartcustomization
5 SOURCES += main.cpp
6 HEADERS +=
7
8
@@ -7,6 +7,7 SUBDIRS += linechart \
7 7 percentbarchart \
8 8 scatter \
9 9 piechart \
10 piechartcustomization \
10 11 piechartdrilldown \
11 12 dynamiclinechart \
12 13 axischart \
@@ -5,13 +5,11 SOURCES += \
5 5 $$PWD/qpieseries.cpp \
6 6 $$PWD/pieslice.cpp \
7 7 $$PWD/piepresenter.cpp \
8 $$PWD/pieslicelabel.cpp \
9 8 $$PWD/qpieslice.cpp
10 9
11 10 PRIVATE_HEADERS += \
12 11 $$PWD/piepresenter_p.h \
13 12 $$PWD/pieslice_p.h \
14 $$PWD/pieslicelabel_p.h
15 13
16 14 PUBLIC_HEADERS += \
17 15 $$PWD/qpieseries.h \
@@ -1,12 +1,9
1
2 1 #include "piepresenter_p.h"
3 2 #include "pieslice_p.h"
4 3 #include "qpieslice.h"
5 #include "pieslicelabel_p.h"
6 4 #include "qpieseries.h"
7 #include <qmath.h>
8 5 #include <QDebug>
9 #include <QFontMetrics>
6 #include <QPainter>
10 7
11 8
12 9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
@@ -19,6 +16,7 PiePresenter::PiePresenter(QGraphicsItem *parent, QPieSeries *series)
19 16 connect(series, SIGNAL(changed(const QPieSeries::ChangeSet&)), this, SLOT(handleSeriesChanged(const QPieSeries::ChangeSet&)));
20 17 connect(series, SIGNAL(sizeFactorChanged()), this, SLOT(updateGeometry()));
21 18 connect(series, SIGNAL(positionChanged()), this, SLOT(updateGeometry()));
19 connect(series, SIGNAL(sizePolicyChanged()), this, SLOT(updateGeometry()));
22 20
23 21 if (m_series->count()) {
24 22 QPieSeries::ChangeSet changeSet;
@@ -36,6 +34,8 void PiePresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QW
36 34 {
37 35 // TODO: paint shadows for all components
38 36 // - get paths from items & merge & offset and draw with shadow color?
37 //painter->setBrush(QBrush(Qt::red));
38 //painter->drawRect(m_debugRect);
39 39 }
40 40
41 41 void PiePresenter::handleSeriesChanged(const QPieSeries::ChangeSet& changeSet)
@@ -78,84 +78,104 void PiePresenter::updateGeometry()
78 78 // calculate maximum rectangle for pie
79 79 QRectF pieRect = m_rect;
80 80 if (pieRect.width() < pieRect.height()) {
81 pieRect.setWidth(pieRect.width() * m_series->sizeFactor());
82 81 pieRect.setHeight(pieRect.width());
83 pieRect.moveCenter(m_rect.center());
84 82 } else {
85 pieRect.setHeight(pieRect.height() * m_series->sizeFactor());
86 83 pieRect.setWidth(pieRect.height());
87 pieRect.moveCenter(m_rect.center());
88 84 }
89 85
90 86 // position the pie rectangle
91 switch (m_series->position()) {
92 case QPieSeries::PiePositionTopLeft: {
93 pieRect.setHeight(pieRect.height() / 2);
94 pieRect.setWidth(pieRect.height());
95 pieRect.moveCenter(QPointF(m_rect.center().x() / 2, m_rect.center().y() / 2));
96 break;
97 }
98 case QPieSeries::PiePositionTopRight: {
99 pieRect.setHeight(pieRect.height() / 2);
100 pieRect.setWidth(pieRect.height());
101 pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, m_rect.center().y() / 2));
102 break;
103 }
104 case QPieSeries::PiePositionBottomLeft: {
105 pieRect.setHeight(pieRect.height() / 2);
106 pieRect.setWidth(pieRect.height());
107 pieRect.moveCenter(QPointF(m_rect.center().x() / 2, (m_rect.center().y() / 2) * 3));
108 break;
109 }
110 case QPieSeries::PiePositionBottomRight: {
111 pieRect.setHeight(pieRect.height() / 2);
112 pieRect.setWidth(pieRect.height());
113 pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, (m_rect.center().y() / 2) * 3));
114 break;
115 }
116 default:
117 break;
118 }
87 QPointF center = m_rect.center(); // default position is center
88 qreal dx = pieRect.width() / 2;
89 qreal dy = pieRect.height() / 2;
90 if (m_series->position() & QPieSeries::PiePositionLeft)
91 center.setX(m_rect.left() + dx);
92 if (m_series->position() & QPieSeries::PiePositionRight)
93 center.setX(m_rect.right() - dx);
94 if (m_series->position() & QPieSeries::PiePositionHCenter)
95 center.setX(m_rect.center().x());
96 if (m_series->position() & QPieSeries::PiePositionTop)
97 center.setY(m_rect.top() + dy);
98 if (m_series->position() & QPieSeries::PiePositionBottom)
99 center.setY(m_rect.bottom() - dy);
100 if (m_series->position() & QPieSeries::PiePositionVCenter)
101 center.setY(m_rect.center().y());
102 pieRect.moveCenter(center);
119 103
120 104 // calculate how much space we need around the pie rectangle (labels & exploding)
121 105 qreal delta = 0;
122 106 qreal pieRadius = pieRect.height() / 2;
123 107 foreach (QPieSlice* s, m_series->m_slices) {
124 108
125 // calculate the farthest point in the slice from the pie center
126
127 // the arm
128 qreal centerAngle = s->m_startAngle + (s->m_angleSpan / 2);
129 qreal len = pieRadius + PIESLICE_LABEL_GAP + s->labelArmLength() + s->explodeDistance();
130 QPointF dp(qSin(centerAngle*(PI/180)) * len, -qCos(centerAngle*(PI/180)) * len);
131 QPointF p = pieRect.center() + dp;
132
133 // the label text
134 QFontMetricsF fm(s->labelFont());
135 QRectF labelRect = fm.boundingRect(s->label());
136 if (centerAngle < 90 || centerAngle > 270)
137 p += QPointF(0, -labelRect.height());
138 if (centerAngle < 180)
139 p += QPointF(labelRect.width(), 0);
140 else
141 p += QPointF(-labelRect.width(), 0);
142
143 // calculate how much the radius must get smaller to fit that point in the base rectangle
144 qreal dt = m_rect.top() - p.y();
145 if (dt > delta) delta = dt;
146 qreal dl = m_rect.left() - p.x();
147 if (dl > delta) delta = dl;
148 qreal dr = p.x() - m_rect.right();
149 if (dr > delta) delta = dr;
150 qreal db = p.y() - m_rect.bottom();
151 if (db > delta) delta = db;
152
153 //if (!m_rect.contains(p)) qDebug() << s->label() << dt << dl << dr << db << "delta" << delta;
109 bool exploded = s->isExploded();
110 if (m_series->sizePolicy() & QPieSeries::PieSizePolicyReserveSpaceForExploding)
111 exploded = true;
112
113 bool labelVisible = s->isLabelVisible();
114 if (m_series->sizePolicy() & QPieSeries::PieSizePolicyReserveSpaceForLabels)
115 labelVisible = true;
116
117 qreal centerAngle;
118 QPointF armStart;
119 QRectF sliceRect = PieSlice::slicePath(center, pieRadius, s->m_startAngle, s->m_angleSpan, exploded, s->explodeDistance(), &centerAngle, &armStart).boundingRect();
120
121 if (labelVisible) {
122 QRectF textRect = PieSlice::labelTextRect(s->labelFont(), s->label());
123 QPointF textStart;
124 QRectF armRect = PieSlice::labelArmPath(armStart, centerAngle, s->labelArmLength(), textRect.width(), &textStart).boundingRect();
125 textRect.moveBottomLeft(textStart);
126 sliceRect = sliceRect.united(armRect);
127 sliceRect = sliceRect.united(textRect);
128 }
129
130
131 qreal dt = m_rect.top() - sliceRect.top();
132 if (dt > delta)
133 delta = dt;
134 qreal dl = m_rect.left() - sliceRect.left();
135 if (dl > delta)
136 delta = dl;
137 qreal dr = sliceRect.right() - m_rect.right();
138 if (dr > delta)
139 delta = dr;
140 qreal db = sliceRect.bottom() - m_rect.bottom();
141 if (db > delta)
142 delta = db;
143
144 /*
145 if (s->label() == "Slice 5") {
146 m_debugRect = sliceRect;
147 qDebug() << "dt:" << dt << ", dl:" << dl << ", dr:" << dr << ", db:" << db << ", delta:" << delta;
148 }
149 */
154 150 }
155 151
156 152 // shrink the pie rectangle so that everything outside it fits the base rectangle
157 153 pieRect.adjust(delta, delta, -delta, -delta);
158 154
155 /*
156 // apply size factor (range 0.0 ... 1.0)
157 pieRect.setWidth(pieRect.width() * m_series->sizeFactor());
158 pieRect.setHeight(pieRect.height() * m_series->sizeFactor());
159
160 // position the pie rectangle (again)
161 center = m_rect.center(); // default position is center
162 dx = pieRect.width() / 2;
163 dy = pieRect.height() / 2;
164 if (m_series->position() & QPieSeries::PiePositionLeft)
165 center.setX(m_rect.left() + dx);
166 if (m_series->position() & QPieSeries::PiePositionRight)
167 center.setX(m_rect.right() - dx);
168 if (m_series->position() & QPieSeries::PiePositionHCenter)
169 center.setX(m_rect.center().x());
170 if (m_series->position() & QPieSeries::PiePositionTop)
171 center.setY(m_rect.top() + dy);
172 if (m_series->position() & QPieSeries::PiePositionBottom)
173 center.setY(m_rect.bottom() - dy);
174 if (m_series->position() & QPieSeries::PiePositionVCenter)
175 center.setY(m_rect.center().y());
176 pieRect.moveCenter(center);
177 */
178
159 179 // update slices
160 180 if (m_pieRect != pieRect) {
161 181 m_pieRect = pieRect;
@@ -166,6 +186,8 void PiePresenter::updateGeometry()
166 186 s->update();
167 187 }
168 188 }
189
190 update();
169 191 }
170 192
171 193 void PiePresenter::addSlice(QPieSlice* sliceData)
@@ -44,6 +44,7 private:
44 44 QPieSeries *m_series;
45 45 QRectF m_rect;
46 46 QRectF m_pieRect;
47 QRectF m_debugRect;
47 48 };
48 49
49 50 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,5 +1,4
1 1 #include "pieslice_p.h"
2 #include "pieslicelabel_p.h"
3 2 #include "piepresenter_p.h"
4 3 #include "qpieseries.h"
5 4 #include "qpieslice.h"
@@ -20,11 +19,11 QPointF offset(qreal angle, qreal length)
20 19
21 20 PieSlice::PieSlice(QGraphicsItem* parent)
22 21 :QGraphicsObject(parent),
23 m_slicelabel(new PieSliceLabel(this)),
24 22 m_startAngle(0),
25 23 m_angleSpan(0),
26 24 m_isExploded(false),
27 m_explodeDistance(0)
25 m_explodeDistance(0),
26 m_labelVisible(false)
28 27 {
29 28 setAcceptHoverEvents(true);
30 29 setAcceptedMouseButtons(Qt::LeftButton);
@@ -37,19 +36,31 PieSlice::~PieSlice()
37 36
38 37 QRectF PieSlice::boundingRect() const
39 38 {
40 return m_path.boundingRect();
39 return m_slicePath.boundingRect();
41 40 }
42 41
43 42 QPainterPath PieSlice::shape() const
44 43 {
45 return m_path;
44 return m_slicePath;
46 45 }
47 46
48 47 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
49 48 {
49 painter->save();
50 50 painter->setPen(m_pen);
51 51 painter->setBrush(m_brush);
52 painter->drawPath(m_path);
52 painter->drawPath(m_slicePath);
53 painter->restore();
54
55 if (m_labelVisible) {
56 painter->save();
57 painter->setPen(m_labelArmPen);
58 painter->drawPath(m_labelArmPath);
59 painter->restore();
60
61 painter->setFont(m_labelFont);
62 painter->drawText(m_labelTextRect.bottomLeft(), m_labelText);
63 }
53 64 }
54 65
55 66 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
@@ -79,32 +90,22 void PieSlice::updateGeometry()
79 90
80 91 prepareGeometryChange();
81 92
82 // calculate center angle
83 qreal centerAngle = m_startAngle + (m_angleSpan/2);
93 // update slice path
94 QPointF center = m_pieRect.center();
95 qreal radius = m_pieRect.height() / 2;
96 qreal centerAngle;
97 QPointF armStart;
98 m_slicePath = slicePath(center, radius, m_startAngle, m_angleSpan, m_isExploded, m_explodeDistance, &centerAngle, &armStart);
84 99
85 // adjust rect for exploding
86 QRectF rect = m_pieRect;
87 if (m_isExploded) {
88 qreal dx = qSin(centerAngle*(PI/180)) * m_explodeDistance;
89 qreal dy = -qCos(centerAngle*(PI/180)) * m_explodeDistance;
90 rect.translate(dx, dy);
91 }
100 // update text rect
101 m_labelTextRect = labelTextRect(m_labelFont, m_labelText);
92 102
93 // update slice path
94 // TODO: draw the shape so that it might have a hole in the center
95 QPainterPath path;
96 path.moveTo(rect.center());
97 path.arcTo(rect, -m_startAngle + 90, -m_angleSpan);
98 path.closeSubpath();
99 m_path = path;
103 // update label arm path
104 QPointF labelTextStart;
105 m_labelArmPath = labelArmPath(armStart, centerAngle, m_labelArmLength, m_labelTextRect.width(), &labelTextStart);
100 106
101 // update label position
102 qreal radius = rect.height() / 2;
103 QPointF edgeCenter = rect.center() + offset(centerAngle, radius + PIESLICE_LABEL_GAP);
104 m_slicelabel->setArmStartPoint(edgeCenter);
105 m_slicelabel->setArmAngle(centerAngle);
106 m_slicelabel->updateGeometry();
107 m_slicelabel->update();
107 // update text position
108 m_labelTextRect.moveBottomLeft(labelTextStart);
108 109
109 110 //qDebug() << "PieSlice::updateGeometry" << m_slicelabel->text() << boundingRect() << m_angle << m_span;
110 111 }
@@ -116,20 +117,85 void PieSlice::updateData(const QPieSlice* sliceData)
116 117 m_startAngle = sliceData->startAngle();
117 118 m_angleSpan = sliceData->m_angleSpan;
118 119 m_isExploded = sliceData->isExploded();
119 m_explodeDistance = sliceData->explodeDistance(); // TODO: expose to public API
120 m_explodeDistance = sliceData->explodeDistance();
120 121 m_pen = sliceData->pen();
121 122 m_brush = sliceData->brush();
122 123
123 m_slicelabel->setVisible(sliceData->isLabelVisible());
124 m_slicelabel->setText(sliceData->label());
125 m_slicelabel->setPen(sliceData->labelPen());
126 m_slicelabel->setFont(sliceData->labelFont());
127 m_slicelabel->setArmLength(sliceData->labelArmLength());
124 m_labelVisible = sliceData->isLabelVisible();
125 m_labelText = sliceData->label();
126 m_labelFont = sliceData->labelFont();
127 m_labelArmLength = sliceData->labelArmLength();
128 m_labelArmPen = sliceData->labelPen();
128 129
129 130 updateGeometry();
130 131 update();
131 132 }
132 133
134 QPainterPath PieSlice::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, bool exploded, qreal explodeDistance, qreal* centerAngle, QPointF* armStart)
135 {
136 // calculate center angle
137 *centerAngle = startAngle + (angleSpan/2);
138
139 // calculate slice rectangle
140 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
141
142 // adjust rect for exploding
143 if (exploded) {
144 qreal dx = qSin(*centerAngle*(PI/180)) * explodeDistance;
145 qreal dy = -qCos(*centerAngle*(PI/180)) * explodeDistance;
146 rect.translate(dx, dy);
147 }
148
149 // slice path
150 // TODO: draw the shape so that it might have a hole in the center
151 QPainterPath path;
152 path.moveTo(rect.center());
153 path.arcTo(rect, -startAngle + 90, -angleSpan);
154 path.closeSubpath();
155
156 // calculate label arm start point
157 *armStart = center;
158 if (exploded)
159 *armStart += offset(*centerAngle, explodeDistance + radius + PIESLICE_LABEL_GAP);
160 else
161 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
162
163 return path;
164 }
165
166 QPainterPath PieSlice::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF* textStart)
167 {
168 qreal dx = qSin(angle*(PI/180)) * length;
169 qreal dy = -qCos(angle*(PI/180)) * length;
170 QPointF parm1 = start + QPointF(dx, dy);
171
172 QPointF parm2 = parm1;
173 if (angle < 180) { // arm swings the other way on the left side
174 parm2 += QPointF(textWidth, 0);
175 *textStart = parm1;
176 }
177 else {
178 parm2 += QPointF(-textWidth,0);
179 *textStart = parm2;
180 }
181
182 // elevate the text position a bit so that it does not hit the line
183 *textStart += QPointF(0, -5);
184
185 QPainterPath path;
186 path.moveTo(start);
187 path.lineTo(parm1);
188 path.lineTo(parm2);
189
190 return path;
191 }
192
193 QRectF PieSlice::labelTextRect(QFont font, QString text)
194 {
195 QFontMetricsF fm(font);
196 return fm.boundingRect(text);
197 }
198
133 199 #include "moc_pieslice_p.cpp"
134 200
135 201 QTCOMMERCIALCHART_END_NAMESPACE
@@ -43,22 +43,29 public Q_SLOTS:
43 43 void updateData(const QPieSlice *sliceData);
44 44
45 45 public:
46 PieSliceLabel* label() { return m_slicelabel; }
46 static QPainterPath slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, bool exploded, qreal explodeDistance, qreal* centerAngle, QPointF* armStart);
47 static QPainterPath labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF* textStart);
48 static QRectF labelTextRect(QFont font, QString text);
47 49
48 50 private:
49 PieSliceLabel* m_slicelabel;
50
51 51 QRectF m_pieRect;
52 QPainterPath m_path;
53 52
53 QPainterPath m_slicePath;
54 54 qreal m_startAngle;
55 55 qreal m_angleSpan;
56
57 56 bool m_isExploded;
58 57 qreal m_explodeDistance;
59
58 bool m_labelVisible;
60 59 QPen m_pen;
61 60 QBrush m_brush;
61
62 QPainterPath m_labelArmPath;
63 qreal m_labelArmLength;
64 QPen m_labelArmPen;
65
66 QRectF m_labelTextRect;
67 QFont m_labelFont;
68 QString m_labelText;
62 69 };
63 70
64 71 QTCOMMERCIALCHART_END_NAMESPACE
@@ -118,9 +118,10 bool QPieSeries::ChangeSet::isEmpty() const
118 118 QPieSeries::QPieSeries(QObject *parent) :
119 119 QSeries(parent),
120 120 m_sizeFactor(1.0),
121 m_position(PiePositionMaximized),
121 m_position(PiePositionCenter),
122 m_sizePolicy(PieSizePolicyMaximized),
122 123 m_pieStartAngle(0),
123 m_pieAngleSpan(360)
124 m_pieEndAngle(360)
124 125 {
125 126
126 127 }
@@ -295,6 +296,7 qreal QPieSeries::sizeFactor() const
295 296 */
296 297 void QPieSeries::setPosition(PiePosition position)
297 298 {
299 // TODO: sanity check
298 300 if (m_position != position) {
299 301 m_position = position;
300 302 emit positionChanged();
@@ -310,22 +312,55 QPieSeries::PiePosition QPieSeries::position() const
310 312 return m_position;
311 313 }
312 314
313
314 315 /*!
315 Sets the \a startAngle and \a angleSpan of this series.
316 Sets the \a sizePolicy of the pie.
317 \sa PieSizePolicy, sizePolicy()
318 */
319 void QPieSeries::setSizePolicy(PieSizePolicy sizePolicy)
320 {
321 // TODO: sanity check
322 if (m_sizePolicy != sizePolicy) {
323 m_sizePolicy = sizePolicy;
324 emit sizePolicyChanged();
325 }
326 }
316 327
317 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
328 /*!
329 Gets the size policy of the pie.
330 \sa PieSizePolicy, setSizePolicy()
318 331 */
319 void QPieSeries::setSpan(qreal startAngle, qreal angleSpan)
332 QPieSeries::PieSizePolicy QPieSeries::sizePolicy() const
320 333 {
321 if (startAngle >= 0 && startAngle < 360 &&
322 angleSpan > 0 && angleSpan <= 360) {
334 return m_sizePolicy;
335 }
336
337
338 void QPieSeries::setStartAngle(qreal startAngle)
339 {
340 if (startAngle >= 0 && startAngle <= 360 && startAngle != m_pieStartAngle && startAngle <= m_pieEndAngle) {
323 341 m_pieStartAngle = startAngle;
324 m_pieAngleSpan = angleSpan;
325 342 updateDerivativeData();
326 343 }
327 344 }
328 345
346 qreal QPieSeries::startAngle() const
347 {
348 return m_pieStartAngle;
349 }
350
351 void QPieSeries::setEndAngle(qreal endAngle)
352 {
353 if (endAngle >= 0 && endAngle <= 360 && endAngle != m_pieEndAngle && endAngle >= m_pieStartAngle) {
354 m_pieEndAngle = endAngle;
355 updateDerivativeData();
356 }
357 }
358
359 qreal QPieSeries::endAngle() const
360 {
361 return m_pieEndAngle;
362 }
363
329 364 /*!
330 365 Sets the all the slice labels \a visible or invisible.
331 366
@@ -449,6 +484,7 void QPieSeries::updateDerivativeData()
449 484
450 485 // update slice attributes
451 486 qreal sliceAngle = m_pieStartAngle;
487 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
452 488 foreach (QPieSlice* s, m_slices) {
453 489
454 490 bool changed = false;
@@ -459,7 +495,7 void QPieSeries::updateDerivativeData()
459 495 changed = true;
460 496 }
461 497
462 qreal sliceSpan = m_pieAngleSpan * percentage;
498 qreal sliceSpan = pieSpan * percentage;
463 499 if (s->m_angleSpan != sliceSpan) {
464 500 s->m_angleSpan = sliceSpan;
465 501 changed = true;
@@ -20,14 +20,28 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QSeries
20 20 Q_OBJECT
21 21
22 22 public:
23 enum PiePosition {
24 PiePositionMaximized = 0,
25 PiePositionTopLeft,
26 PiePositionTopRight,
27 PiePositionBottomLeft,
28 PiePositionBottomRight
23
24 enum PiePositionFlag {
25 PiePositionLeft = 0x1,
26 PiePositionRight = 0x2,
27 PiePositionHCenter = 0x4,
28 PiePositionTop = 0x10,
29 PiePositionBottom = 0x20,
30 PiePositionVCenter = 0x40,
31 PiePositionCenter = PiePositionHCenter | PiePositionVCenter
32 };
33
34 Q_DECLARE_FLAGS(PiePosition, PiePositionFlag)
35
36 enum PieSizePolicyFlag {
37 PieSizePolicyMaximized = 0,
38 PieSizePolicyReserveSpaceForLabels = 0x1,
39 PieSizePolicyReserveSpaceForExploding = 0x2,
40 PieSizePolicyReserveSpaceForAll = PieSizePolicyReserveSpaceForLabels | PieSizePolicyReserveSpaceForExploding
29 41 };
30 42
43 Q_DECLARE_FLAGS(PieSizePolicy, PieSizePolicyFlag)
44
31 45 class ChangeSet
32 46 {
33 47 public:
@@ -58,27 +72,38 public: // from QChartSeries
58 72 QSeriesType type() const;
59 73
60 74 public:
61 void replace(QList<QPieSlice*> slices);
62 void add(QList<QPieSlice*> slices);
75
76 // slice setters
63 77 void add(QPieSlice* slice);
64 QPieSlice* add(qreal value, QString name);
65 QPieSeries& operator << (QPieSlice* slice);
78 void add(QList<QPieSlice*> slices);
79 void replace(QList<QPieSlice*> slices);
66 80 void remove(QPieSlice* slice);
67 81 void clear();
68 82
69 int count() const;
83 // sluce getters
70 84 QList<QPieSlice*> slices() const;
71 85
72 void setSizeFactor(qreal sizeFactor);
73 qreal sizeFactor() const;
86 // calculated data
87 int count() const;
88 qreal total() const;
89
90 // pie customization
74 91 void setPosition(PiePosition position);
75 92 PiePosition position() const;
76 void setSpan(qreal startAngle, qreal angleSpan);
93 void setSizePolicy(PieSizePolicy policy);
94 PieSizePolicy sizePolicy() const;
95 void setSizeFactor(qreal sizeFactor);
96 qreal sizeFactor() const;
97 void setStartAngle(qreal startAngle);
98 qreal startAngle() const;
99 void setEndAngle(qreal endAngle);
100 qreal endAngle() const;
77 101
102 // convenience function
103 QPieSeries& operator << (QPieSlice* slice);
104 QPieSlice* add(qreal value, QString name);
78 105 void setLabelsVisible(bool visible = true);
79 106
80 qreal total() const;
81
82 107 // TODO: find slices?
83 108 // QList<QPieSlice*> findByValue(qreal value);
84 109 // ...
@@ -88,15 +113,19 public:
88 113
89 114 // TODO: general graphics customization
90 115 // setDrawStyle(2d|3d)
91 // setDropShadows(bool)
116 // setDropShadows
92 117
93 118 Q_SIGNALS:
119
94 120 void changed(const QPieSeries::ChangeSet& changeSet);
121
95 122 void clicked(QPieSlice* slice);
96 123 void hoverEnter(QPieSlice* slice);
97 124 void hoverLeave(QPieSlice* slice);
125
98 126 void sizeFactorChanged();
99 127 void positionChanged();
128 void sizePolicyChanged();
100 129
101 130 private Q_SLOTS: // TODO: should be private and not visible in the interface at all
102 131 void sliceChanged();
@@ -117,9 +146,10 private:
117 146 QList<QPieSlice*> m_slices;
118 147 qreal m_sizeFactor;
119 148 PiePosition m_position;
149 PieSizePolicy m_sizePolicy;
120 150 qreal m_total;
121 151 qreal m_pieStartAngle;
122 qreal m_pieAngleSpan;
152 qreal m_pieEndAngle;
123 153 };
124 154
125 155 QTCOMMERCIALCHART_END_NAMESPACE
@@ -21,10 +21,15 public:
21 21 virtual ~QPieSlice();
22 22
23 23 // data
24 void setValue(qreal value);
24 25 qreal value() const;
26 void setLabel(QString label);
25 27 QString label() const;
28 void setLabelVisible(bool visible);
26 29 bool isLabelVisible() const;
30 void setExploded(bool exploded);
27 31 bool isExploded() const;
32 void setExplodeDistance(qreal distance);
28 33 qreal explodeDistance() const;
29 34
30 35 // generated data
@@ -33,38 +38,27 public:
33 38 qreal endAngle() const;
34 39
35 40 // customization
41 void setPen(QPen pen);
36 42 QPen pen() const;
43 void setBrush(QBrush brush);
37 44 QBrush brush() const;
45 void setLabelPen(QPen pen);
38 46 QPen labelPen() const;
47 void setLabelFont(QFont font);
39 48 QFont labelFont() const;
49 void setLabelArmLength(qreal len);
40 50 qreal labelArmLength() const;
41 51
52 // TODO: label position in general
53 // setLabelFlags(inside|outside|labelArmOn|labelArmOff|???)
54 // setLabelOrientation(horizontal|vertical|same as slice center angle|???)
55
42 56 Q_SIGNALS:
43 57 void clicked();
44 58 void hoverEnter();
45 59 void hoverLeave();
46 60 void changed();
47 61
48 public Q_SLOTS:
49
50 // data
51 void setLabel(QString label);
52 void setLabelVisible(bool visible);
53 void setValue(qreal value);
54 void setExploded(bool exploded);
55 void setExplodeDistance(qreal distance);
56
57 // customization
58 void setPen(QPen pen);
59 void setBrush(QBrush brush);
60 void setLabelFont(QFont font);
61 void setLabelPen(QPen pen);
62 void setLabelArmLength(qreal len);
63
64 // TODO: label position in general
65 // setLabelFlags(inside|outside|labelArmOn|labelArmOff|???)
66 // setLabelOrientation(horizontal|vertical|same as slice center angle|???)
67
68 62 private:
69 63
70 64 // TODO: use private class
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now