##// 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
@@ -1,20 +1,21
1 TEMPLATE = subdirs
1 TEMPLATE = subdirs
2 SUBDIRS += linechart \
2 SUBDIRS += linechart \
3 zoomlinechart \
3 zoomlinechart \
4 colorlinechart \
4 colorlinechart \
5 barchart \
5 barchart \
6 stackedbarchart \
6 stackedbarchart \
7 percentbarchart \
7 percentbarchart \
8 scatter \
8 scatter \
9 piechart \
9 piechart \
10 piechartcustomization \
10 piechartdrilldown \
11 piechartdrilldown \
11 dynamiclinechart \
12 dynamiclinechart \
12 axischart \
13 axischart \
13 multichart \
14 multichart \
14 gdpbarchart \
15 gdpbarchart \
15 presenterchart \
16 presenterchart \
16 chartview \
17 chartview \
17 scatterinteractions \
18 scatterinteractions \
18 splinechart \
19 splinechart \
19 areachart \
20 areachart \
20 stackedbarchartdrilldown
21 stackedbarchartdrilldown
@@ -1,18 +1,16
1 INCLUDEPATH += $$PWD
1 INCLUDEPATH += $$PWD
2 DEPENDPATH += $$PWD
2 DEPENDPATH += $$PWD
3
3
4 SOURCES += \
4 SOURCES += \
5 $$PWD/qpieseries.cpp \
5 $$PWD/qpieseries.cpp \
6 $$PWD/pieslice.cpp \
6 $$PWD/pieslice.cpp \
7 $$PWD/piepresenter.cpp \
7 $$PWD/piepresenter.cpp \
8 $$PWD/pieslicelabel.cpp \
9 $$PWD/qpieslice.cpp
8 $$PWD/qpieslice.cpp
10
9
11 PRIVATE_HEADERS += \
10 PRIVATE_HEADERS += \
12 $$PWD/piepresenter_p.h \
11 $$PWD/piepresenter_p.h \
13 $$PWD/pieslice_p.h \
12 $$PWD/pieslice_p.h \
14 $$PWD/pieslicelabel_p.h
15
13
16 PUBLIC_HEADERS += \
14 PUBLIC_HEADERS += \
17 $$PWD/qpieseries.h \
15 $$PWD/qpieseries.h \
18 $$PWD/qpieslice.h
16 $$PWD/qpieslice.h
@@ -1,220 +1,242
1
2 #include "piepresenter_p.h"
1 #include "piepresenter_p.h"
3 #include "pieslice_p.h"
2 #include "pieslice_p.h"
4 #include "qpieslice.h"
3 #include "qpieslice.h"
5 #include "pieslicelabel_p.h"
6 #include "qpieseries.h"
4 #include "qpieseries.h"
7 #include <qmath.h>
8 #include <QDebug>
5 #include <QDebug>
9 #include <QFontMetrics>
6 #include <QPainter>
10
7
11
8
12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
13
10
14 PiePresenter::PiePresenter(QGraphicsItem *parent, QPieSeries *series)
11 PiePresenter::PiePresenter(QGraphicsItem *parent, QPieSeries *series)
15 :ChartItem(parent),
12 :ChartItem(parent),
16 m_series(series)
13 m_series(series)
17 {
14 {
18 Q_ASSERT(series);
15 Q_ASSERT(series);
19 connect(series, SIGNAL(changed(const QPieSeries::ChangeSet&)), this, SLOT(handleSeriesChanged(const QPieSeries::ChangeSet&)));
16 connect(series, SIGNAL(changed(const QPieSeries::ChangeSet&)), this, SLOT(handleSeriesChanged(const QPieSeries::ChangeSet&)));
20 connect(series, SIGNAL(sizeFactorChanged()), this, SLOT(updateGeometry()));
17 connect(series, SIGNAL(sizeFactorChanged()), this, SLOT(updateGeometry()));
21 connect(series, SIGNAL(positionChanged()), this, SLOT(updateGeometry()));
18 connect(series, SIGNAL(positionChanged()), this, SLOT(updateGeometry()));
19 connect(series, SIGNAL(sizePolicyChanged()), this, SLOT(updateGeometry()));
22
20
23 if (m_series->count()) {
21 if (m_series->count()) {
24 QPieSeries::ChangeSet changeSet;
22 QPieSeries::ChangeSet changeSet;
25 changeSet.appendAdded(m_series->m_slices);
23 changeSet.appendAdded(m_series->m_slices);
26 handleSeriesChanged(changeSet);
24 handleSeriesChanged(changeSet);
27 }
25 }
28 }
26 }
29
27
30 PiePresenter::~PiePresenter()
28 PiePresenter::~PiePresenter()
31 {
29 {
32 // slices deleted automatically through QGraphicsItem
30 // slices deleted automatically through QGraphicsItem
33 }
31 }
34
32
35 void PiePresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
33 void PiePresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
36 {
34 {
37 // TODO: paint shadows for all components
35 // TODO: paint shadows for all components
38 // - get paths from items & merge & offset and draw with shadow color?
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 void PiePresenter::handleSeriesChanged(const QPieSeries::ChangeSet& changeSet)
41 void PiePresenter::handleSeriesChanged(const QPieSeries::ChangeSet& changeSet)
42 {
42 {
43 //qDebug() << "PiePresenter::handleSeriesChanged()";
43 //qDebug() << "PiePresenter::handleSeriesChanged()";
44 //qDebug() << " added : " << changeSet.added();
44 //qDebug() << " added : " << changeSet.added();
45 //qDebug() << " changed: " << changeSet.changed();
45 //qDebug() << " changed: " << changeSet.changed();
46 //qDebug() << " removed: " << changeSet.removed();
46 //qDebug() << " removed: " << changeSet.removed();
47
47
48 foreach (QPieSlice* s, changeSet.added())
48 foreach (QPieSlice* s, changeSet.added())
49 addSlice(s);
49 addSlice(s);
50
50
51 foreach (QPieSlice* s, changeSet.changed())
51 foreach (QPieSlice* s, changeSet.changed())
52 updateSlice(s);
52 updateSlice(s);
53
53
54 foreach (QPieSlice* s, changeSet.removed())
54 foreach (QPieSlice* s, changeSet.removed())
55 deleteSlice(s);
55 deleteSlice(s);
56
56
57 // every change possibly changes the actual pie size
57 // every change possibly changes the actual pie size
58 updateGeometry();
58 updateGeometry();
59 }
59 }
60
60
61 void PiePresenter::handleDomainChanged(const Domain& domain)
61 void PiePresenter::handleDomainChanged(const Domain& domain)
62 {
62 {
63 // TODO
63 // TODO
64 }
64 }
65
65
66 void PiePresenter::handleGeometryChanged(const QRectF& rect)
66 void PiePresenter::handleGeometryChanged(const QRectF& rect)
67 {
67 {
68 m_rect = rect;
68 m_rect = rect;
69 prepareGeometryChange();
69 prepareGeometryChange();
70 updateGeometry();
70 updateGeometry();
71 }
71 }
72
72
73 void PiePresenter::updateGeometry()
73 void PiePresenter::updateGeometry()
74 {
74 {
75 if (!m_rect.isValid() || m_rect.isEmpty())
75 if (!m_rect.isValid() || m_rect.isEmpty())
76 return;
76 return;
77
77
78 // calculate maximum rectangle for pie
78 // calculate maximum rectangle for pie
79 QRectF pieRect = m_rect;
79 QRectF pieRect = m_rect;
80 if (pieRect.width() < pieRect.height()) {
80 if (pieRect.width() < pieRect.height()) {
81 pieRect.setWidth(pieRect.width() * m_series->sizeFactor());
82 pieRect.setHeight(pieRect.width());
81 pieRect.setHeight(pieRect.width());
83 pieRect.moveCenter(m_rect.center());
84 } else {
82 } else {
85 pieRect.setHeight(pieRect.height() * m_series->sizeFactor());
86 pieRect.setWidth(pieRect.height());
83 pieRect.setWidth(pieRect.height());
87 pieRect.moveCenter(m_rect.center());
88 }
84 }
89
85
90 // position the pie rectangle
86 // position the pie rectangle
91 switch (m_series->position()) {
87 QPointF center = m_rect.center(); // default position is center
92 case QPieSeries::PiePositionTopLeft: {
88 qreal dx = pieRect.width() / 2;
93 pieRect.setHeight(pieRect.height() / 2);
89 qreal dy = pieRect.height() / 2;
94 pieRect.setWidth(pieRect.height());
90 if (m_series->position() & QPieSeries::PiePositionLeft)
95 pieRect.moveCenter(QPointF(m_rect.center().x() / 2, m_rect.center().y() / 2));
91 center.setX(m_rect.left() + dx);
96 break;
92 if (m_series->position() & QPieSeries::PiePositionRight)
97 }
93 center.setX(m_rect.right() - dx);
98 case QPieSeries::PiePositionTopRight: {
94 if (m_series->position() & QPieSeries::PiePositionHCenter)
99 pieRect.setHeight(pieRect.height() / 2);
95 center.setX(m_rect.center().x());
100 pieRect.setWidth(pieRect.height());
96 if (m_series->position() & QPieSeries::PiePositionTop)
101 pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, m_rect.center().y() / 2));
97 center.setY(m_rect.top() + dy);
102 break;
98 if (m_series->position() & QPieSeries::PiePositionBottom)
103 }
99 center.setY(m_rect.bottom() - dy);
104 case QPieSeries::PiePositionBottomLeft: {
100 if (m_series->position() & QPieSeries::PiePositionVCenter)
105 pieRect.setHeight(pieRect.height() / 2);
101 center.setY(m_rect.center().y());
106 pieRect.setWidth(pieRect.height());
102 pieRect.moveCenter(center);
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 }
119
103
120 // calculate how much space we need around the pie rectangle (labels & exploding)
104 // calculate how much space we need around the pie rectangle (labels & exploding)
121 qreal delta = 0;
105 qreal delta = 0;
122 qreal pieRadius = pieRect.height() / 2;
106 qreal pieRadius = pieRect.height() / 2;
123 foreach (QPieSlice* s, m_series->m_slices) {
107 foreach (QPieSlice* s, m_series->m_slices) {
124
108
125 // calculate the farthest point in the slice from the pie center
109 bool exploded = s->isExploded();
126
110 if (m_series->sizePolicy() & QPieSeries::PieSizePolicyReserveSpaceForExploding)
127 // the arm
111 exploded = true;
128 qreal centerAngle = s->m_startAngle + (s->m_angleSpan / 2);
112
129 qreal len = pieRadius + PIESLICE_LABEL_GAP + s->labelArmLength() + s->explodeDistance();
113 bool labelVisible = s->isLabelVisible();
130 QPointF dp(qSin(centerAngle*(PI/180)) * len, -qCos(centerAngle*(PI/180)) * len);
114 if (m_series->sizePolicy() & QPieSeries::PieSizePolicyReserveSpaceForLabels)
131 QPointF p = pieRect.center() + dp;
115 labelVisible = true;
132
116
133 // the label text
117 qreal centerAngle;
134 QFontMetricsF fm(s->labelFont());
118 QPointF armStart;
135 QRectF labelRect = fm.boundingRect(s->label());
119 QRectF sliceRect = PieSlice::slicePath(center, pieRadius, s->m_startAngle, s->m_angleSpan, exploded, s->explodeDistance(), &centerAngle, &armStart).boundingRect();
136 if (centerAngle < 90 || centerAngle > 270)
120
137 p += QPointF(0, -labelRect.height());
121 if (labelVisible) {
138 if (centerAngle < 180)
122 QRectF textRect = PieSlice::labelTextRect(s->labelFont(), s->label());
139 p += QPointF(labelRect.width(), 0);
123 QPointF textStart;
140 else
124 QRectF armRect = PieSlice::labelArmPath(armStart, centerAngle, s->labelArmLength(), textRect.width(), &textStart).boundingRect();
141 p += QPointF(-labelRect.width(), 0);
125 textRect.moveBottomLeft(textStart);
142
126 sliceRect = sliceRect.united(armRect);
143 // calculate how much the radius must get smaller to fit that point in the base rectangle
127 sliceRect = sliceRect.united(textRect);
144 qreal dt = m_rect.top() - p.y();
128 }
145 if (dt > delta) delta = dt;
129
146 qreal dl = m_rect.left() - p.x();
130
147 if (dl > delta) delta = dl;
131 qreal dt = m_rect.top() - sliceRect.top();
148 qreal dr = p.x() - m_rect.right();
132 if (dt > delta)
149 if (dr > delta) delta = dr;
133 delta = dt;
150 qreal db = p.y() - m_rect.bottom();
134 qreal dl = m_rect.left() - sliceRect.left();
151 if (db > delta) delta = db;
135 if (dl > delta)
152
136 delta = dl;
153 //if (!m_rect.contains(p)) qDebug() << s->label() << dt << dl << dr << db << "delta" << delta;
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 // shrink the pie rectangle so that everything outside it fits the base rectangle
152 // shrink the pie rectangle so that everything outside it fits the base rectangle
157 pieRect.adjust(delta, delta, -delta, -delta);
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 // update slices
179 // update slices
160 if (m_pieRect != pieRect) {
180 if (m_pieRect != pieRect) {
161 m_pieRect = pieRect;
181 m_pieRect = pieRect;
162 //qDebug() << "PiePresenter::updateGeometry()" << m_rect << m_pieRect;
182 //qDebug() << "PiePresenter::updateGeometry()" << m_rect << m_pieRect;
163 foreach (PieSlice* s, m_slices.values()) {
183 foreach (PieSlice* s, m_slices.values()) {
164 s->setPieRect(m_pieRect);
184 s->setPieRect(m_pieRect);
165 s->updateGeometry();
185 s->updateGeometry();
166 s->update();
186 s->update();
167 }
187 }
168 }
188 }
189
190 update();
169 }
191 }
170
192
171 void PiePresenter::addSlice(QPieSlice* sliceData)
193 void PiePresenter::addSlice(QPieSlice* sliceData)
172 {
194 {
173 //qDebug() << "PiePresenter::addSlice()" << sliceData;
195 //qDebug() << "PiePresenter::addSlice()" << sliceData;
174
196
175 if (m_slices.keys().contains(sliceData)) {
197 if (m_slices.keys().contains(sliceData)) {
176 Q_ASSERT(0); // TODO: how to handle this nicely?
198 Q_ASSERT(0); // TODO: how to handle this nicely?
177 return;
199 return;
178 }
200 }
179
201
180 // create slice
202 // create slice
181 PieSlice *slice = new PieSlice(this);
203 PieSlice *slice = new PieSlice(this);
182 slice->setPieRect(m_pieRect);
204 slice->setPieRect(m_pieRect);
183 slice->updateData(sliceData);
205 slice->updateData(sliceData);
184 slice->updateGeometry();
206 slice->updateGeometry();
185 slice->update();
207 slice->update();
186 m_slices.insert(sliceData, slice);
208 m_slices.insert(sliceData, slice);
187
209
188 // connect signals
210 // connect signals
189 connect(slice, SIGNAL(clicked()), sliceData, SIGNAL(clicked()));
211 connect(slice, SIGNAL(clicked()), sliceData, SIGNAL(clicked()));
190 connect(slice, SIGNAL(hoverEnter()), sliceData, SIGNAL(hoverEnter()));
212 connect(slice, SIGNAL(hoverEnter()), sliceData, SIGNAL(hoverEnter()));
191 connect(slice, SIGNAL(hoverLeave()), sliceData, SIGNAL(hoverLeave()));
213 connect(slice, SIGNAL(hoverLeave()), sliceData, SIGNAL(hoverLeave()));
192 }
214 }
193
215
194 void PiePresenter::updateSlice(QPieSlice* sliceData)
216 void PiePresenter::updateSlice(QPieSlice* sliceData)
195 {
217 {
196 //qDebug() << "PiePresenter::updateSlice()" << sliceData;
218 //qDebug() << "PiePresenter::updateSlice()" << sliceData;
197
219
198 if (!m_slices.contains(sliceData)) {
220 if (!m_slices.contains(sliceData)) {
199 Q_ASSERT(0); // TODO: how to handle this nicely?
221 Q_ASSERT(0); // TODO: how to handle this nicely?
200 return;
222 return;
201 }
223 }
202
224
203 m_slices[sliceData]->updateData(sliceData);
225 m_slices[sliceData]->updateData(sliceData);
204 }
226 }
205
227
206 void PiePresenter::deleteSlice(QPieSlice* sliceData)
228 void PiePresenter::deleteSlice(QPieSlice* sliceData)
207 {
229 {
208 //qDebug() << "PiePresenter::deleteSlice()" << sliceData;
230 //qDebug() << "PiePresenter::deleteSlice()" << sliceData;
209
231
210 if (!m_slices.contains(sliceData)) {
232 if (!m_slices.contains(sliceData)) {
211 Q_ASSERT(0); // TODO: how to handle this nicely?
233 Q_ASSERT(0); // TODO: how to handle this nicely?
212 return;
234 return;
213 }
235 }
214
236
215 delete m_slices.take(sliceData);
237 delete m_slices.take(sliceData);
216 }
238 }
217
239
218 #include "moc_piepresenter_p.cpp"
240 #include "moc_piepresenter_p.cpp"
219
241
220 QTCOMMERCIALCHART_END_NAMESPACE
242 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,51 +1,52
1 #ifndef PIEPRESENTER_H
1 #ifndef PIEPRESENTER_H
2 #define PIEPRESENTER_H
2 #define PIEPRESENTER_H
3
3
4 #include "chartitem_p.h"
4 #include "chartitem_p.h"
5 #include "qpieseries.h"
5 #include "qpieseries.h"
6 #include <QSignalMapper>
6 #include <QSignalMapper>
7
7
8 class QGraphicsItem;
8 class QGraphicsItem;
9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
10 class PieSlice;
10 class PieSlice;
11
11
12 #define PI 3.14159265 // TODO: is this defined in some header?
12 #define PI 3.14159265 // TODO: is this defined in some header?
13
13
14 class PiePresenter : public QObject, public ChartItem
14 class PiePresenter : public QObject, public ChartItem
15 {
15 {
16 Q_OBJECT
16 Q_OBJECT
17
17
18 public:
18 public:
19 // TODO: use a generic data class instead of x and y
19 // TODO: use a generic data class instead of x and y
20 PiePresenter(QGraphicsItem *parent, QPieSeries *series);
20 PiePresenter(QGraphicsItem *parent, QPieSeries *series);
21 ~PiePresenter();
21 ~PiePresenter();
22
22
23 public: // from QGraphicsItem
23 public: // from QGraphicsItem
24 QRectF boundingRect() const { return m_rect; }
24 QRectF boundingRect() const { return m_rect; }
25 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
25 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
26
26
27 public:
27 public:
28 QRectF pieRect() const { return m_pieRect; }
28 QRectF pieRect() const { return m_pieRect; }
29
29
30 public Q_SLOTS:
30 public Q_SLOTS:
31 void handleSeriesChanged(const QPieSeries::ChangeSet& changeSet);
31 void handleSeriesChanged(const QPieSeries::ChangeSet& changeSet);
32 void handleDomainChanged(const Domain& domain);
32 void handleDomainChanged(const Domain& domain);
33 void handleGeometryChanged(const QRectF& rect);
33 void handleGeometryChanged(const QRectF& rect);
34 void updateGeometry();
34 void updateGeometry();
35
35
36 private:
36 private:
37 void addSlice(QPieSlice* sliceData);
37 void addSlice(QPieSlice* sliceData);
38 void updateSlice(QPieSlice* sliceData);
38 void updateSlice(QPieSlice* sliceData);
39 void deleteSlice(QPieSlice* sliceData);
39 void deleteSlice(QPieSlice* sliceData);
40
40
41 private:
41 private:
42 friend class PieSlice;
42 friend class PieSlice;
43 QHash<QPieSlice*, PieSlice*> m_slices;
43 QHash<QPieSlice*, PieSlice*> m_slices;
44 QPieSeries *m_series;
44 QPieSeries *m_series;
45 QRectF m_rect;
45 QRectF m_rect;
46 QRectF m_pieRect;
46 QRectF m_pieRect;
47 QRectF m_debugRect;
47 };
48 };
48
49
49 QTCOMMERCIALCHART_END_NAMESPACE
50 QTCOMMERCIALCHART_END_NAMESPACE
50
51
51 #endif // PIEPRESENTER_H
52 #endif // PIEPRESENTER_H
@@ -1,135 +1,201
1 #include "pieslice_p.h"
1 #include "pieslice_p.h"
2 #include "pieslicelabel_p.h"
3 #include "piepresenter_p.h"
2 #include "piepresenter_p.h"
4 #include "qpieseries.h"
3 #include "qpieseries.h"
5 #include "qpieslice.h"
4 #include "qpieslice.h"
6 #include <QPainter>
5 #include <QPainter>
7 #include <QDebug>
6 #include <QDebug>
8 #include <qmath.h>
7 #include <qmath.h>
9 #include <QGraphicsSceneEvent>
8 #include <QGraphicsSceneEvent>
10 #include <QTime>
9 #include <QTime>
11
10
12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
11 QTCOMMERCIALCHART_BEGIN_NAMESPACE
13
12
14 QPointF offset(qreal angle, qreal length)
13 QPointF offset(qreal angle, qreal length)
15 {
14 {
16 qreal dx = qSin(angle*(PI/180)) * length;
15 qreal dx = qSin(angle*(PI/180)) * length;
17 qreal dy = qCos(angle*(PI/180)) * length;
16 qreal dy = qCos(angle*(PI/180)) * length;
18 return QPointF(dx, -dy);
17 return QPointF(dx, -dy);
19 }
18 }
20
19
21 PieSlice::PieSlice(QGraphicsItem* parent)
20 PieSlice::PieSlice(QGraphicsItem* parent)
22 :QGraphicsObject(parent),
21 :QGraphicsObject(parent),
23 m_slicelabel(new PieSliceLabel(this)),
24 m_startAngle(0),
22 m_startAngle(0),
25 m_angleSpan(0),
23 m_angleSpan(0),
26 m_isExploded(false),
24 m_isExploded(false),
27 m_explodeDistance(0)
25 m_explodeDistance(0),
26 m_labelVisible(false)
28 {
27 {
29 setAcceptHoverEvents(true);
28 setAcceptHoverEvents(true);
30 setAcceptedMouseButtons(Qt::LeftButton);
29 setAcceptedMouseButtons(Qt::LeftButton);
31 }
30 }
32
31
33 PieSlice::~PieSlice()
32 PieSlice::~PieSlice()
34 {
33 {
35
34
36 }
35 }
37
36
38 QRectF PieSlice::boundingRect() const
37 QRectF PieSlice::boundingRect() const
39 {
38 {
40 return m_path.boundingRect();
39 return m_slicePath.boundingRect();
41 }
40 }
42
41
43 QPainterPath PieSlice::shape() const
42 QPainterPath PieSlice::shape() const
44 {
43 {
45 return m_path;
44 return m_slicePath;
46 }
45 }
47
46
48 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
47 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
49 {
48 {
49 painter->save();
50 painter->setPen(m_pen);
50 painter->setPen(m_pen);
51 painter->setBrush(m_brush);
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 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
66 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
56 {
67 {
57 emit hoverEnter();
68 emit hoverEnter();
58 }
69 }
59
70
60 void PieSlice::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
71 void PieSlice::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
61 {
72 {
62 emit hoverLeave();
73 emit hoverLeave();
63 }
74 }
64
75
65 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/)
76 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/)
66 {
77 {
67 emit clicked();
78 emit clicked();
68 }
79 }
69
80
70 void PieSlice::setPieRect(QRectF rect)
81 void PieSlice::setPieRect(QRectF rect)
71 {
82 {
72 m_pieRect = rect;
83 m_pieRect = rect;
73 }
84 }
74
85
75 void PieSlice::updateGeometry()
86 void PieSlice::updateGeometry()
76 {
87 {
77 if (!m_pieRect.isValid() || m_pieRect.isEmpty())
88 if (!m_pieRect.isValid() || m_pieRect.isEmpty())
78 return;
89 return;
79
90
80 prepareGeometryChange();
91 prepareGeometryChange();
81
92
82 // calculate center angle
93 // update slice path
83 qreal centerAngle = m_startAngle + (m_angleSpan/2);
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
100 // update text rect
86 QRectF rect = m_pieRect;
101 m_labelTextRect = labelTextRect(m_labelFont, m_labelText);
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 }
92
102
93 // update slice path
103 // update label arm path
94 // TODO: draw the shape so that it might have a hole in the center
104 QPointF labelTextStart;
95 QPainterPath path;
105 m_labelArmPath = labelArmPath(armStart, centerAngle, m_labelArmLength, m_labelTextRect.width(), &labelTextStart);
96 path.moveTo(rect.center());
97 path.arcTo(rect, -m_startAngle + 90, -m_angleSpan);
98 path.closeSubpath();
99 m_path = path;
100
106
101 // update label position
107 // update text position
102 qreal radius = rect.height() / 2;
108 m_labelTextRect.moveBottomLeft(labelTextStart);
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();
108
109
109 //qDebug() << "PieSlice::updateGeometry" << m_slicelabel->text() << boundingRect() << m_angle << m_span;
110 //qDebug() << "PieSlice::updateGeometry" << m_slicelabel->text() << boundingRect() << m_angle << m_span;
110 }
111 }
111
112
112 void PieSlice::updateData(const QPieSlice* sliceData)
113 void PieSlice::updateData(const QPieSlice* sliceData)
113 {
114 {
114 // TODO: compare what has changes to avoid unneccesary geometry updates
115 // TODO: compare what has changes to avoid unneccesary geometry updates
115
116
116 m_startAngle = sliceData->startAngle();
117 m_startAngle = sliceData->startAngle();
117 m_angleSpan = sliceData->m_angleSpan;
118 m_angleSpan = sliceData->m_angleSpan;
118 m_isExploded = sliceData->isExploded();
119 m_isExploded = sliceData->isExploded();
119 m_explodeDistance = sliceData->explodeDistance(); // TODO: expose to public API
120 m_explodeDistance = sliceData->explodeDistance();
120 m_pen = sliceData->pen();
121 m_pen = sliceData->pen();
121 m_brush = sliceData->brush();
122 m_brush = sliceData->brush();
122
123
123 m_slicelabel->setVisible(sliceData->isLabelVisible());
124 m_labelVisible = sliceData->isLabelVisible();
124 m_slicelabel->setText(sliceData->label());
125 m_labelText = sliceData->label();
125 m_slicelabel->setPen(sliceData->labelPen());
126 m_labelFont = sliceData->labelFont();
126 m_slicelabel->setFont(sliceData->labelFont());
127 m_labelArmLength = sliceData->labelArmLength();
127 m_slicelabel->setArmLength(sliceData->labelArmLength());
128 m_labelArmPen = sliceData->labelPen();
128
129
129 updateGeometry();
130 updateGeometry();
130 update();
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 #include "moc_pieslice_p.cpp"
199 #include "moc_pieslice_p.cpp"
134
200
135 QTCOMMERCIALCHART_END_NAMESPACE
201 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,66 +1,73
1 #ifndef PIESLICE_H
1 #ifndef PIESLICE_H
2 #define PIESLICE_H
2 #define PIESLICE_H
3
3
4 #include "qchartglobal.h"
4 #include "qchartglobal.h"
5 #include "charttheme_p.h"
5 #include "charttheme_p.h"
6 #include "qpieseries.h"
6 #include "qpieseries.h"
7 #include <QGraphicsItem>
7 #include <QGraphicsItem>
8 #include <QRectF>
8 #include <QRectF>
9 #include <QColor>
9 #include <QColor>
10 #include <QPen>
10 #include <QPen>
11
11
12 #define PIESLICE_LABEL_GAP 5
12 #define PIESLICE_LABEL_GAP 5
13
13
14 QTCOMMERCIALCHART_BEGIN_NAMESPACE
14 QTCOMMERCIALCHART_BEGIN_NAMESPACE
15 class PiePresenter;
15 class PiePresenter;
16 class PieSliceLabel;
16 class PieSliceLabel;
17 class QPieSlice;
17 class QPieSlice;
18
18
19 class PieSlice : public QGraphicsObject
19 class PieSlice : public QGraphicsObject
20 {
20 {
21 Q_OBJECT
21 Q_OBJECT
22
22
23 public:
23 public:
24 PieSlice(QGraphicsItem* parent = 0);
24 PieSlice(QGraphicsItem* parent = 0);
25 ~PieSlice();
25 ~PieSlice();
26
26
27 public: // from QGraphicsItem
27 public: // from QGraphicsItem
28 QRectF boundingRect() const;
28 QRectF boundingRect() const;
29 QPainterPath shape() const;
29 QPainterPath shape() const;
30 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
30 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
31 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
31 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
32 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
32 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
33 void mousePressEvent(QGraphicsSceneMouseEvent *event);
33 void mousePressEvent(QGraphicsSceneMouseEvent *event);
34
34
35 Q_SIGNALS:
35 Q_SIGNALS:
36 void clicked();
36 void clicked();
37 void hoverEnter();
37 void hoverEnter();
38 void hoverLeave();
38 void hoverLeave();
39
39
40 public Q_SLOTS:
40 public Q_SLOTS:
41 void setPieRect(QRectF rect);
41 void setPieRect(QRectF rect);
42 void updateGeometry();
42 void updateGeometry();
43 void updateData(const QPieSlice *sliceData);
43 void updateData(const QPieSlice *sliceData);
44
44
45 public:
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 private:
50 private:
49 PieSliceLabel* m_slicelabel;
50
51 QRectF m_pieRect;
51 QRectF m_pieRect;
52 QPainterPath m_path;
53
52
53 QPainterPath m_slicePath;
54 qreal m_startAngle;
54 qreal m_startAngle;
55 qreal m_angleSpan;
55 qreal m_angleSpan;
56
57 bool m_isExploded;
56 bool m_isExploded;
58 qreal m_explodeDistance;
57 qreal m_explodeDistance;
59
58 bool m_labelVisible;
60 QPen m_pen;
59 QPen m_pen;
61 QBrush m_brush;
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 QTCOMMERCIALCHART_END_NAMESPACE
71 QTCOMMERCIALCHART_END_NAMESPACE
65
72
66 #endif // PIESLICE_H
73 #endif // PIESLICE_H
@@ -1,481 +1,517
1 #include "qpieseries.h"
1 #include "qpieseries.h"
2 #include "qpieslice.h"
2 #include "qpieslice.h"
3 #include <QDebug>
3 #include <QDebug>
4
4
5 QTCOMMERCIALCHART_BEGIN_NAMESPACE
5 QTCOMMERCIALCHART_BEGIN_NAMESPACE
6
6
7
7
8 /*!
8 /*!
9 \class QPieSeries::ChangeSet
9 \class QPieSeries::ChangeSet
10 \brief Defines the changes in the series.
10 \brief Defines the changes in the series.
11
11
12 Contains the changes that have occurred in the series. Lists of added, changed and removed slices.
12 Contains the changes that have occurred in the series. Lists of added, changed and removed slices.
13
13
14 \sa QPieSeries::changed()
14 \sa QPieSeries::changed()
15 */
15 */
16
16
17 /*!
17 /*!
18 \internal
18 \internal
19 */
19 */
20 void QPieSeries::ChangeSet::appendAdded(QPieSlice* slice)
20 void QPieSeries::ChangeSet::appendAdded(QPieSlice* slice)
21 {
21 {
22 if (!m_added.contains(slice))
22 if (!m_added.contains(slice))
23 m_added << slice;
23 m_added << slice;
24 }
24 }
25
25
26 /*!
26 /*!
27 \internal
27 \internal
28 */
28 */
29 void QPieSeries::ChangeSet::appendAdded(QList<QPieSlice*> slices)
29 void QPieSeries::ChangeSet::appendAdded(QList<QPieSlice*> slices)
30 {
30 {
31 foreach (QPieSlice* s, slices)
31 foreach (QPieSlice* s, slices)
32 appendAdded(s);
32 appendAdded(s);
33 }
33 }
34
34
35 /*!
35 /*!
36 \internal
36 \internal
37 */
37 */
38 void QPieSeries::ChangeSet::appendChanged(QPieSlice* slice)
38 void QPieSeries::ChangeSet::appendChanged(QPieSlice* slice)
39 {
39 {
40 if (!m_changed.contains(slice))
40 if (!m_changed.contains(slice))
41 m_changed << slice;
41 m_changed << slice;
42 }
42 }
43
43
44 /*!
44 /*!
45 \internal
45 \internal
46 */
46 */
47 void QPieSeries::ChangeSet::appendRemoved(QPieSlice* slice)
47 void QPieSeries::ChangeSet::appendRemoved(QPieSlice* slice)
48 {
48 {
49 if (!m_removed.contains(slice))
49 if (!m_removed.contains(slice))
50 m_removed << slice;
50 m_removed << slice;
51 }
51 }
52
52
53 /*!
53 /*!
54 Returns a list of slices that have been added to the series.
54 Returns a list of slices that have been added to the series.
55 \sa QPieSeries::changed()
55 \sa QPieSeries::changed()
56 */
56 */
57 QList<QPieSlice*> QPieSeries::ChangeSet::added() const
57 QList<QPieSlice*> QPieSeries::ChangeSet::added() const
58 {
58 {
59 return m_added;
59 return m_added;
60 }
60 }
61
61
62 /*!
62 /*!
63 Returns a list of slices that have been changed in the series.
63 Returns a list of slices that have been changed in the series.
64 \sa QPieSeries::changed()
64 \sa QPieSeries::changed()
65 */
65 */
66 QList<QPieSlice*> QPieSeries::ChangeSet::changed() const
66 QList<QPieSlice*> QPieSeries::ChangeSet::changed() const
67 {
67 {
68 return m_changed;
68 return m_changed;
69 }
69 }
70
70
71 /*!
71 /*!
72 Returns a list of slices that have been removed from the series.
72 Returns a list of slices that have been removed from the series.
73 \sa QPieSeries::changed()
73 \sa QPieSeries::changed()
74 */
74 */
75 QList<QPieSlice*> QPieSeries::ChangeSet::removed() const
75 QList<QPieSlice*> QPieSeries::ChangeSet::removed() const
76 {
76 {
77 return m_removed;
77 return m_removed;
78 }
78 }
79
79
80
80
81 /*!
81 /*!
82 Returns true if there are no added/changed or removed slices in the change set.
82 Returns true if there are no added/changed or removed slices in the change set.
83 */
83 */
84 bool QPieSeries::ChangeSet::isEmpty() const
84 bool QPieSeries::ChangeSet::isEmpty() const
85 {
85 {
86 if (m_added.count() || m_changed.count() || m_removed.count())
86 if (m_added.count() || m_changed.count() || m_removed.count())
87 return false;
87 return false;
88 return true;
88 return true;
89 }
89 }
90
90
91 /*!
91 /*!
92 \enum QPieSeries::PiePosition
92 \enum QPieSeries::PiePosition
93
93
94 This enum describes pie position within its bounding rectangle
94 This enum describes pie position within its bounding rectangle
95
95
96 \value PiePositionMaximized
96 \value PiePositionMaximized
97 \value PiePositionTopLeft
97 \value PiePositionTopLeft
98 \value PiePositionTopRight
98 \value PiePositionTopRight
99 \value PiePositionBottomLeft
99 \value PiePositionBottomLeft
100 \value PiePositionBottomRight
100 \value PiePositionBottomRight
101 */
101 */
102
102
103 /*!
103 /*!
104 \class QPieSeries
104 \class QPieSeries
105 \brief Pie series API for QtCommercial Charts
105 \brief Pie series API for QtCommercial Charts
106
106
107 The pie series defines a pie chart which consists of pie slices which are QPieSlice objects.
107 The pie series defines a pie chart which consists of pie slices which are QPieSlice objects.
108 The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices.
108 The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices.
109 The actual slice size is determined by that relative value.
109 The actual slice size is determined by that relative value.
110
110
111 By default the pie is defined as a full pie but it can be a partial pie.
111 By default the pie is defined as a full pie but it can be a partial pie.
112 This can be done by setting a starting angle and angle span to the series.
112 This can be done by setting a starting angle and angle span to the series.
113 */
113 */
114
114
115 /*!
115 /*!
116 Constructs a series object which is a child of \a parent.
116 Constructs a series object which is a child of \a parent.
117 */
117 */
118 QPieSeries::QPieSeries(QObject *parent) :
118 QPieSeries::QPieSeries(QObject *parent) :
119 QSeries(parent),
119 QSeries(parent),
120 m_sizeFactor(1.0),
120 m_sizeFactor(1.0),
121 m_position(PiePositionMaximized),
121 m_position(PiePositionCenter),
122 m_sizePolicy(PieSizePolicyMaximized),
122 m_pieStartAngle(0),
123 m_pieStartAngle(0),
123 m_pieAngleSpan(360)
124 m_pieEndAngle(360)
124 {
125 {
125
126
126 }
127 }
127
128
128 /*!
129 /*!
129 Destroys the object. Note that adding series to QChart transfers the ownership to the chart.
130 Destroys the object. Note that adding series to QChart transfers the ownership to the chart.
130 */
131 */
131 QPieSeries::~QPieSeries()
132 QPieSeries::~QPieSeries()
132 {
133 {
133
134
134 }
135 }
135
136
136 /*!
137 /*!
137 Returns QChartSeries::SeriesTypePie.
138 Returns QChartSeries::SeriesTypePie.
138 */
139 */
139 QSeries::QSeriesType QPieSeries::type() const
140 QSeries::QSeriesType QPieSeries::type() const
140 {
141 {
141 return QSeries::SeriesTypePie;
142 return QSeries::SeriesTypePie;
142 }
143 }
143
144
144 /*!
145 /*!
145 Sets an array of \a slices to the series replacing the existing slices.
146 Sets an array of \a slices to the series replacing the existing slices.
146 Slice ownership is passed to the series.
147 Slice ownership is passed to the series.
147 */
148 */
148 void QPieSeries::replace(QList<QPieSlice*> slices)
149 void QPieSeries::replace(QList<QPieSlice*> slices)
149 {
150 {
150 clear();
151 clear();
151 add(slices);
152 add(slices);
152 }
153 }
153
154
154 /*!
155 /*!
155 Adds an array of \a slices to the series.
156 Adds an array of \a slices to the series.
156 Slice ownership is passed to the series.
157 Slice ownership is passed to the series.
157 */
158 */
158 void QPieSeries::add(QList<QPieSlice*> slices)
159 void QPieSeries::add(QList<QPieSlice*> slices)
159 {
160 {
160 ChangeSet changeSet;
161 ChangeSet changeSet;
161 foreach (QPieSlice* s, slices) {
162 foreach (QPieSlice* s, slices) {
162 s->setParent(this);
163 s->setParent(this);
163 m_slices << s;
164 m_slices << s;
164 changeSet.appendAdded(s);
165 changeSet.appendAdded(s);
165 }
166 }
166
167
167 updateDerivativeData();
168 updateDerivativeData();
168
169
169 foreach (QPieSlice* s, slices) {
170 foreach (QPieSlice* s, slices) {
170 connect(s, SIGNAL(changed()), this, SLOT(sliceChanged()));
171 connect(s, SIGNAL(changed()), this, SLOT(sliceChanged()));
171 connect(s, SIGNAL(clicked()), this, SLOT(sliceClicked()));
172 connect(s, SIGNAL(clicked()), this, SLOT(sliceClicked()));
172 connect(s, SIGNAL(hoverEnter()), this, SLOT(sliceHoverEnter()));
173 connect(s, SIGNAL(hoverEnter()), this, SLOT(sliceHoverEnter()));
173 connect(s, SIGNAL(hoverLeave()), this, SLOT(sliceHoverLeave()));
174 connect(s, SIGNAL(hoverLeave()), this, SLOT(sliceHoverLeave()));
174 }
175 }
175
176
176 emit changed(changeSet);
177 emit changed(changeSet);
177 }
178 }
178
179
179 /*!
180 /*!
180 Adds a single \a slice to the series.
181 Adds a single \a slice to the series.
181 Slice ownership is passed to the series.
182 Slice ownership is passed to the series.
182 */
183 */
183 void QPieSeries::add(QPieSlice* slice)
184 void QPieSeries::add(QPieSlice* slice)
184 {
185 {
185 add(QList<QPieSlice*>() << slice);
186 add(QList<QPieSlice*>() << slice);
186 }
187 }
187
188
188 /*!
189 /*!
189 Adds a single \a slice to the series and returns a reference to the series.
190 Adds a single \a slice to the series and returns a reference to the series.
190 Slice ownership is passed to the series.
191 Slice ownership is passed to the series.
191 */
192 */
192 QPieSeries& QPieSeries::operator << (QPieSlice* slice)
193 QPieSeries& QPieSeries::operator << (QPieSlice* slice)
193 {
194 {
194 add(slice);
195 add(slice);
195 return *this;
196 return *this;
196 }
197 }
197
198
198
199
199 /*!
200 /*!
200 Adds a single slice to the series with give \a value and \a name.
201 Adds a single slice to the series with give \a value and \a name.
201 Slice ownership is passed to the series.
202 Slice ownership is passed to the series.
202 */
203 */
203 QPieSlice* QPieSeries::add(qreal value, QString name)
204 QPieSlice* QPieSeries::add(qreal value, QString name)
204 {
205 {
205 QPieSlice* slice = new QPieSlice(value, name);
206 QPieSlice* slice = new QPieSlice(value, name);
206 add(slice);
207 add(slice);
207 return slice;
208 return slice;
208 }
209 }
209
210
210 /*!
211 /*!
211 Removes a single \a slice from the series and deletes the slice.
212 Removes a single \a slice from the series and deletes the slice.
212
213
213 Do not reference this pointer after this call.
214 Do not reference this pointer after this call.
214 */
215 */
215 void QPieSeries::remove(QPieSlice* slice)
216 void QPieSeries::remove(QPieSlice* slice)
216 {
217 {
217 if (!m_slices.removeOne(slice)) {
218 if (!m_slices.removeOne(slice)) {
218 Q_ASSERT(0); // TODO: how should this be reported?
219 Q_ASSERT(0); // TODO: how should this be reported?
219 return;
220 return;
220 }
221 }
221
222
222 ChangeSet changeSet;
223 ChangeSet changeSet;
223 changeSet.appendRemoved(slice);
224 changeSet.appendRemoved(slice);
224 emit changed(changeSet);
225 emit changed(changeSet);
225
226
226 delete slice;
227 delete slice;
227 slice = NULL;
228 slice = NULL;
228
229
229 updateDerivativeData();
230 updateDerivativeData();
230 }
231 }
231
232
232 /*!
233 /*!
233 Clears all slices from the series.
234 Clears all slices from the series.
234 */
235 */
235 void QPieSeries::clear()
236 void QPieSeries::clear()
236 {
237 {
237 if (m_slices.count() == 0)
238 if (m_slices.count() == 0)
238 return;
239 return;
239
240
240 ChangeSet changeSet;
241 ChangeSet changeSet;
241 foreach (QPieSlice* s, m_slices) {
242 foreach (QPieSlice* s, m_slices) {
242 changeSet.appendRemoved(s);
243 changeSet.appendRemoved(s);
243 m_slices.removeOne(s);
244 m_slices.removeOne(s);
244 delete s;
245 delete s;
245 }
246 }
246 emit changed(changeSet);
247 emit changed(changeSet);
247 updateDerivativeData();
248 updateDerivativeData();
248 }
249 }
249
250
250 /*!
251 /*!
251 Counts the number of the slices in this series.
252 Counts the number of the slices in this series.
252 */
253 */
253 int QPieSeries::count() const
254 int QPieSeries::count() const
254 {
255 {
255 return m_slices.count();
256 return m_slices.count();
256 }
257 }
257
258
258 /*!
259 /*!
259 Returns a list of slices that belong to this series.
260 Returns a list of slices that belong to this series.
260 */
261 */
261 QList<QPieSlice*> QPieSeries::slices() const
262 QList<QPieSlice*> QPieSeries::slices() const
262 {
263 {
263 return m_slices;
264 return m_slices;
264 }
265 }
265
266
266 /*!
267 /*!
267 Sets the size \a factor of the pie. 1.0 is the default value.
268 Sets the size \a factor of the pie. 1.0 is the default value.
268 Note that the pie will not grow beyond its absolute maximum size.
269 Note that the pie will not grow beyond its absolute maximum size.
269 In practice its use is to make the pie appear smaller.
270 In practice its use is to make the pie appear smaller.
270 \sa sizeFactor()
271 \sa sizeFactor()
271 */
272 */
272 void QPieSeries::setSizeFactor(qreal factor)
273 void QPieSeries::setSizeFactor(qreal factor)
273 {
274 {
274 if (factor < 0.0)
275 if (factor < 0.0)
275 return;
276 return;
276
277
277 if (m_sizeFactor != factor) {
278 if (m_sizeFactor != factor) {
278 m_sizeFactor = factor;
279 m_sizeFactor = factor;
279 emit sizeFactorChanged();
280 emit sizeFactorChanged();
280 }
281 }
281 }
282 }
282
283
283 /*!
284 /*!
284 Gets the size factor of the pie.
285 Gets the size factor of the pie.
285 \sa setSizeFactor()
286 \sa setSizeFactor()
286 */
287 */
287 qreal QPieSeries::sizeFactor() const
288 qreal QPieSeries::sizeFactor() const
288 {
289 {
289 return m_sizeFactor;
290 return m_sizeFactor;
290 }
291 }
291
292
292 /*!
293 /*!
293 Sets the \a position of the pie within its bounding rectangle.
294 Sets the \a position of the pie within its bounding rectangle.
294 \sa PiePosition, position()
295 \sa PiePosition, position()
295 */
296 */
296 void QPieSeries::setPosition(PiePosition position)
297 void QPieSeries::setPosition(PiePosition position)
297 {
298 {
299 // TODO: sanity check
298 if (m_position != position) {
300 if (m_position != position) {
299 m_position = position;
301 m_position = position;
300 emit positionChanged();
302 emit positionChanged();
301 }
303 }
302 }
304 }
303
305
304 /*!
306 /*!
305 Gets the position of the pie within its bounding rectangle.
307 Gets the position of the pie within its bounding rectangle.
306 \sa PiePosition, setPosition()
308 \sa PiePosition, setPosition()
307 */
309 */
308 QPieSeries::PiePosition QPieSeries::position() const
310 QPieSeries::PiePosition QPieSeries::position() const
309 {
311 {
310 return m_position;
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 &&
334 return m_sizePolicy;
322 angleSpan > 0 && angleSpan <= 360) {
335 }
336
337
338 void QPieSeries::setStartAngle(qreal startAngle)
339 {
340 if (startAngle >= 0 && startAngle <= 360 && startAngle != m_pieStartAngle && startAngle <= m_pieEndAngle) {
323 m_pieStartAngle = startAngle;
341 m_pieStartAngle = startAngle;
324 m_pieAngleSpan = angleSpan;
325 updateDerivativeData();
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 Sets the all the slice labels \a visible or invisible.
365 Sets the all the slice labels \a visible or invisible.
331
366
332 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
367 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
333 */
368 */
334 void QPieSeries::setLabelsVisible(bool visible)
369 void QPieSeries::setLabelsVisible(bool visible)
335 {
370 {
336 foreach (QPieSlice* s, m_slices)
371 foreach (QPieSlice* s, m_slices)
337 s->setLabelVisible(visible);
372 s->setLabelVisible(visible);
338 }
373 }
339
374
340 /*!
375 /*!
341 Returns the sum of all slice values in this series.
376 Returns the sum of all slice values in this series.
342
377
343 \sa QPieSlice::value(), QPieSlice::setValue()
378 \sa QPieSlice::value(), QPieSlice::setValue()
344 */
379 */
345 qreal QPieSeries::total() const
380 qreal QPieSeries::total() const
346 {
381 {
347 return m_total;
382 return m_total;
348 }
383 }
349
384
350 /*!
385 /*!
351 \fn void QPieSeries::changed(const QPieSeries::ChangeSet& changeSet)
386 \fn void QPieSeries::changed(const QPieSeries::ChangeSet& changeSet)
352
387
353 This signal emitted when something has changed in the series.
388 This signal emitted when something has changed in the series.
354 The \a changeSet contains the details of which slices have been added, changed or removed.
389 The \a changeSet contains the details of which slices have been added, changed or removed.
355
390
356 \sa QPieSeries::ChangeSet, QPieSlice::changed()
391 \sa QPieSeries::ChangeSet, QPieSlice::changed()
357 */
392 */
358
393
359 /*!
394 /*!
360 \fn void QPieSeries::clicked(QPieSlice* slice)
395 \fn void QPieSeries::clicked(QPieSlice* slice)
361
396
362 This signal is emitted when a \a slice has been clicked.
397 This signal is emitted when a \a slice has been clicked.
363
398
364 \sa QPieSlice::clicked()
399 \sa QPieSlice::clicked()
365 */
400 */
366
401
367 /*!
402 /*!
368 \fn void QPieSeries::hoverEnter(QPieSlice* slice)
403 \fn void QPieSeries::hoverEnter(QPieSlice* slice)
369
404
370 This signal is emitted when user has hovered over a \a slice.
405 This signal is emitted when user has hovered over a \a slice.
371
406
372 \sa QPieSlice::hoverEnter()
407 \sa QPieSlice::hoverEnter()
373 */
408 */
374
409
375 /*!
410 /*!
376 \fn void QPieSeries::hoverLeave(QPieSlice* slice)
411 \fn void QPieSeries::hoverLeave(QPieSlice* slice)
377
412
378 This signal is emitted when user has hovered away from a \a slice.
413 This signal is emitted when user has hovered away from a \a slice.
379
414
380 \sa QPieSlice::hoverLeave()
415 \sa QPieSlice::hoverLeave()
381 */
416 */
382
417
383 /*!
418 /*!
384 \fn void QPieSeries::sizeFactorChanged()
419 \fn void QPieSeries::sizeFactorChanged()
385
420
386 This signal is emitted when size factor has been changed.
421 This signal is emitted when size factor has been changed.
387
422
388 \sa sizeFactor(), setSizeFactor()
423 \sa sizeFactor(), setSizeFactor()
389 */
424 */
390
425
391 /*!
426 /*!
392 \fn void QPieSeries::positionChanged()
427 \fn void QPieSeries::positionChanged()
393
428
394 This signal is emitted when position of the pie has been changed.
429 This signal is emitted when position of the pie has been changed.
395
430
396 \sa position(), setPosition()
431 \sa position(), setPosition()
397 */
432 */
398
433
399 void QPieSeries::sliceChanged()
434 void QPieSeries::sliceChanged()
400 {
435 {
401 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
436 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
402 Q_ASSERT(m_slices.contains(slice));
437 Q_ASSERT(m_slices.contains(slice));
403
438
404 ChangeSet changeSet;
439 ChangeSet changeSet;
405 changeSet.appendChanged(slice);
440 changeSet.appendChanged(slice);
406 emit changed(changeSet);
441 emit changed(changeSet);
407
442
408 updateDerivativeData();
443 updateDerivativeData();
409 }
444 }
410
445
411 void QPieSeries::sliceClicked()
446 void QPieSeries::sliceClicked()
412 {
447 {
413 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
448 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
414 Q_ASSERT(m_slices.contains(slice));
449 Q_ASSERT(m_slices.contains(slice));
415 emit clicked(slice);
450 emit clicked(slice);
416 }
451 }
417
452
418 void QPieSeries::sliceHoverEnter()
453 void QPieSeries::sliceHoverEnter()
419 {
454 {
420 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
455 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
421 Q_ASSERT(m_slices.contains(slice));
456 Q_ASSERT(m_slices.contains(slice));
422 emit hoverEnter(slice);
457 emit hoverEnter(slice);
423 }
458 }
424
459
425 void QPieSeries::sliceHoverLeave()
460 void QPieSeries::sliceHoverLeave()
426 {
461 {
427 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
462 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
428 Q_ASSERT(m_slices.contains(slice));
463 Q_ASSERT(m_slices.contains(slice));
429 emit hoverLeave(slice);
464 emit hoverLeave(slice);
430 }
465 }
431
466
432 void QPieSeries::updateDerivativeData()
467 void QPieSeries::updateDerivativeData()
433 {
468 {
434 m_total = 0;
469 m_total = 0;
435
470
436 // nothing to do?
471 // nothing to do?
437 if (m_slices.count() == 0)
472 if (m_slices.count() == 0)
438 return;
473 return;
439
474
440 // calculate total
475 // calculate total
441 foreach (QPieSlice* s, m_slices)
476 foreach (QPieSlice* s, m_slices)
442 m_total += s->value();
477 m_total += s->value();
443
478
444 // we must have some values
479 // we must have some values
445 if (m_total == 0) {
480 if (m_total == 0) {
446 qDebug() << "QPieSeries::updateDerivativeData() total == 0";
481 qDebug() << "QPieSeries::updateDerivativeData() total == 0";
447 Q_ASSERT(m_total > 0); // TODO: is this the correct way to handle this?
482 Q_ASSERT(m_total > 0); // TODO: is this the correct way to handle this?
448 }
483 }
449
484
450 // update slice attributes
485 // update slice attributes
451 qreal sliceAngle = m_pieStartAngle;
486 qreal sliceAngle = m_pieStartAngle;
487 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
452 foreach (QPieSlice* s, m_slices) {
488 foreach (QPieSlice* s, m_slices) {
453
489
454 bool changed = false;
490 bool changed = false;
455
491
456 qreal percentage = s->value() / m_total;
492 qreal percentage = s->value() / m_total;
457 if (s->m_percentage != percentage) {
493 if (s->m_percentage != percentage) {
458 s->m_percentage = percentage;
494 s->m_percentage = percentage;
459 changed = true;
495 changed = true;
460 }
496 }
461
497
462 qreal sliceSpan = m_pieAngleSpan * percentage;
498 qreal sliceSpan = pieSpan * percentage;
463 if (s->m_angleSpan != sliceSpan) {
499 if (s->m_angleSpan != sliceSpan) {
464 s->m_angleSpan = sliceSpan;
500 s->m_angleSpan = sliceSpan;
465 changed = true;
501 changed = true;
466 }
502 }
467
503
468 if (s->m_startAngle != sliceAngle) {
504 if (s->m_startAngle != sliceAngle) {
469 s->m_startAngle = sliceAngle;
505 s->m_startAngle = sliceAngle;
470 changed = true;
506 changed = true;
471 }
507 }
472 sliceAngle += sliceSpan;
508 sliceAngle += sliceSpan;
473
509
474 if (changed)
510 if (changed)
475 emit s->changed();
511 emit s->changed();
476 }
512 }
477 }
513 }
478
514
479 #include "moc_qpieseries.cpp"
515 #include "moc_qpieseries.cpp"
480
516
481 QTCOMMERCIALCHART_END_NAMESPACE
517 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,127 +1,157
1 #ifndef PIESERIES_H
1 #ifndef PIESERIES_H
2 #define PIESERIES_H
2 #define PIESERIES_H
3
3
4 #include "qseries.h"
4 #include "qseries.h"
5 #include <QObject>
5 #include <QObject>
6 #include <QRectF>
6 #include <QRectF>
7 #include <QColor>
7 #include <QColor>
8 #include <QPen>
8 #include <QPen>
9 #include <QBrush>
9 #include <QBrush>
10 #include <QSignalMapper>
10 #include <QSignalMapper>
11
11
12 class QGraphicsObject;
12 class QGraphicsObject;
13 QTCOMMERCIALCHART_BEGIN_NAMESPACE
13 QTCOMMERCIALCHART_BEGIN_NAMESPACE
14 class PiePresenter;
14 class PiePresenter;
15 class PieSlice;
15 class PieSlice;
16 class QPieSlice;
16 class QPieSlice;
17
17
18 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QSeries
18 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QSeries
19 {
19 {
20 Q_OBJECT
20 Q_OBJECT
21
21
22 public:
22 public:
23 enum PiePosition {
23
24 PiePositionMaximized = 0,
24 enum PiePositionFlag {
25 PiePositionTopLeft,
25 PiePositionLeft = 0x1,
26 PiePositionTopRight,
26 PiePositionRight = 0x2,
27 PiePositionBottomLeft,
27 PiePositionHCenter = 0x4,
28 PiePositionBottomRight
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 class ChangeSet
45 class ChangeSet
32 {
46 {
33 public:
47 public:
34
48
35 // TODO: these should not really be exposed to the public API
49 // TODO: these should not really be exposed to the public API
36 void appendAdded(QPieSlice* slice);
50 void appendAdded(QPieSlice* slice);
37 void appendAdded(QList<QPieSlice*> slices);
51 void appendAdded(QList<QPieSlice*> slices);
38 void appendChanged(QPieSlice* slice);
52 void appendChanged(QPieSlice* slice);
39 void appendRemoved(QPieSlice* slice);
53 void appendRemoved(QPieSlice* slice);
40
54
41 QList<QPieSlice*> added() const;
55 QList<QPieSlice*> added() const;
42 QList<QPieSlice*> changed() const;
56 QList<QPieSlice*> changed() const;
43 QList<QPieSlice*> removed() const;
57 QList<QPieSlice*> removed() const;
44
58
45 bool isEmpty() const;
59 bool isEmpty() const;
46
60
47 private:
61 private:
48 QList<QPieSlice*> m_added;
62 QList<QPieSlice*> m_added;
49 QList<QPieSlice*> m_changed;
63 QList<QPieSlice*> m_changed;
50 QList<QPieSlice*> m_removed;
64 QList<QPieSlice*> m_removed;
51 };
65 };
52
66
53 public:
67 public:
54 QPieSeries(QObject *parent = 0);
68 QPieSeries(QObject *parent = 0);
55 virtual ~QPieSeries();
69 virtual ~QPieSeries();
56
70
57 public: // from QChartSeries
71 public: // from QChartSeries
58 QSeriesType type() const;
72 QSeriesType type() const;
59
73
60 public:
74 public:
61 void replace(QList<QPieSlice*> slices);
75
62 void add(QList<QPieSlice*> slices);
76 // slice setters
63 void add(QPieSlice* slice);
77 void add(QPieSlice* slice);
64 QPieSlice* add(qreal value, QString name);
78 void add(QList<QPieSlice*> slices);
65 QPieSeries& operator << (QPieSlice* slice);
79 void replace(QList<QPieSlice*> slices);
66 void remove(QPieSlice* slice);
80 void remove(QPieSlice* slice);
67 void clear();
81 void clear();
68
82
69 int count() const;
83 // sluce getters
70 QList<QPieSlice*> slices() const;
84 QList<QPieSlice*> slices() const;
71
85
72 void setSizeFactor(qreal sizeFactor);
86 // calculated data
73 qreal sizeFactor() const;
87 int count() const;
88 qreal total() const;
89
90 // pie customization
74 void setPosition(PiePosition position);
91 void setPosition(PiePosition position);
75 PiePosition position() const;
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 void setLabelsVisible(bool visible = true);
105 void setLabelsVisible(bool visible = true);
79
106
80 qreal total() const;
81
82 // TODO: find slices?
107 // TODO: find slices?
83 // QList<QPieSlice*> findByValue(qreal value);
108 // QList<QPieSlice*> findByValue(qreal value);
84 // ...
109 // ...
85
110
86 // TODO: sorting slices?
111 // TODO: sorting slices?
87 // void sort(QPieSeries::SortByValue|label|??)
112 // void sort(QPieSeries::SortByValue|label|??)
88
113
89 // TODO: general graphics customization
114 // TODO: general graphics customization
90 // setDrawStyle(2d|3d)
115 // setDrawStyle(2d|3d)
91 // setDropShadows(bool)
116 // setDropShadows
92
117
93 Q_SIGNALS:
118 Q_SIGNALS:
119
94 void changed(const QPieSeries::ChangeSet& changeSet);
120 void changed(const QPieSeries::ChangeSet& changeSet);
121
95 void clicked(QPieSlice* slice);
122 void clicked(QPieSlice* slice);
96 void hoverEnter(QPieSlice* slice);
123 void hoverEnter(QPieSlice* slice);
97 void hoverLeave(QPieSlice* slice);
124 void hoverLeave(QPieSlice* slice);
125
98 void sizeFactorChanged();
126 void sizeFactorChanged();
99 void positionChanged();
127 void positionChanged();
128 void sizePolicyChanged();
100
129
101 private Q_SLOTS: // TODO: should be private and not visible in the interface at all
130 private Q_SLOTS: // TODO: should be private and not visible in the interface at all
102 void sliceChanged();
131 void sliceChanged();
103 void sliceClicked();
132 void sliceClicked();
104 void sliceHoverEnter();
133 void sliceHoverEnter();
105 void sliceHoverLeave();
134 void sliceHoverLeave();
106
135
107 private:
136 private:
108 void updateDerivativeData();
137 void updateDerivativeData();
109
138
110 private:
139 private:
111 Q_DISABLE_COPY(QPieSeries)
140 Q_DISABLE_COPY(QPieSeries)
112
141
113 // TODO: use PIML
142 // TODO: use PIML
114 friend class PiePresenter;
143 friend class PiePresenter;
115 friend class PieSlice;
144 friend class PieSlice;
116
145
117 QList<QPieSlice*> m_slices;
146 QList<QPieSlice*> m_slices;
118 qreal m_sizeFactor;
147 qreal m_sizeFactor;
119 PiePosition m_position;
148 PiePosition m_position;
149 PieSizePolicy m_sizePolicy;
120 qreal m_total;
150 qreal m_total;
121 qreal m_pieStartAngle;
151 qreal m_pieStartAngle;
122 qreal m_pieAngleSpan;
152 qreal m_pieEndAngle;
123 };
153 };
124
154
125 QTCOMMERCIALCHART_END_NAMESPACE
155 QTCOMMERCIALCHART_END_NAMESPACE
126
156
127 #endif // PIESERIES_H
157 #endif // PIESERIES_H
@@ -1,97 +1,91
1 #ifndef QPIESLICE_H
1 #ifndef QPIESLICE_H
2 #define QPIESLICE_H
2 #define QPIESLICE_H
3
3
4 #include <qchartglobal.h>
4 #include <qchartglobal.h>
5 #include <QObject>
5 #include <QObject>
6 #include <QPen>
6 #include <QPen>
7 #include <QBrush>
7 #include <QBrush>
8 #include <QFont>
8 #include <QFont>
9
9
10 QTCOMMERCIALCHART_BEGIN_NAMESPACE
10 QTCOMMERCIALCHART_BEGIN_NAMESPACE
11
11
12 class QTCOMMERCIALCHART_EXPORT QPieSlice : public QObject
12 class QTCOMMERCIALCHART_EXPORT QPieSlice : public QObject
13 {
13 {
14 Q_OBJECT
14 Q_OBJECT
15 Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY changed)
15 Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY changed)
16 Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY changed)
16 Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY changed)
17
17
18 public:
18 public:
19 QPieSlice(QObject *parent = 0);
19 QPieSlice(QObject *parent = 0);
20 QPieSlice(qreal value, QString label, QObject *parent = 0);
20 QPieSlice(qreal value, QString label, QObject *parent = 0);
21 virtual ~QPieSlice();
21 virtual ~QPieSlice();
22
22
23 // data
23 // data
24 void setValue(qreal value);
24 qreal value() const;
25 qreal value() const;
26 void setLabel(QString label);
25 QString label() const;
27 QString label() const;
28 void setLabelVisible(bool visible);
26 bool isLabelVisible() const;
29 bool isLabelVisible() const;
30 void setExploded(bool exploded);
27 bool isExploded() const;
31 bool isExploded() const;
32 void setExplodeDistance(qreal distance);
28 qreal explodeDistance() const;
33 qreal explodeDistance() const;
29
34
30 // generated data
35 // generated data
31 qreal percentage() const;
36 qreal percentage() const;
32 qreal startAngle() const;
37 qreal startAngle() const;
33 qreal endAngle() const;
38 qreal endAngle() const;
34
39
35 // customization
40 // customization
41 void setPen(QPen pen);
36 QPen pen() const;
42 QPen pen() const;
43 void setBrush(QBrush brush);
37 QBrush brush() const;
44 QBrush brush() const;
45 void setLabelPen(QPen pen);
38 QPen labelPen() const;
46 QPen labelPen() const;
47 void setLabelFont(QFont font);
39 QFont labelFont() const;
48 QFont labelFont() const;
49 void setLabelArmLength(qreal len);
40 qreal labelArmLength() const;
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 Q_SIGNALS:
56 Q_SIGNALS:
43 void clicked();
57 void clicked();
44 void hoverEnter();
58 void hoverEnter();
45 void hoverLeave();
59 void hoverLeave();
46 void changed();
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 private:
62 private:
69
63
70 // TODO: use private class
64 // TODO: use private class
71 friend class QPieSeries;
65 friend class QPieSeries;
72 friend class PiePresenter;
66 friend class PiePresenter;
73 friend class PieSlice;
67 friend class PieSlice;
74
68
75 // data
69 // data
76 qreal m_value;
70 qreal m_value;
77 QString m_label;
71 QString m_label;
78 bool m_isLabelVisible;
72 bool m_isLabelVisible;
79 bool m_isExploded;
73 bool m_isExploded;
80 qreal m_explodeDistance;
74 qreal m_explodeDistance;
81
75
82 // generated data
76 // generated data
83 qreal m_percentage;
77 qreal m_percentage;
84 qreal m_startAngle;
78 qreal m_startAngle;
85 qreal m_angleSpan;
79 qreal m_angleSpan;
86
80
87 // customization
81 // customization
88 QPen m_pen;
82 QPen m_pen;
89 QBrush m_brush;
83 QBrush m_brush;
90 QPen m_labelPen;
84 QPen m_labelPen;
91 QFont m_labelFont;
85 QFont m_labelFont;
92 qreal m_labelArmLength;
86 qreal m_labelArmLength;
93 };
87 };
94
88
95 QTCOMMERCIALCHART_END_NAMESPACE
89 QTCOMMERCIALCHART_END_NAMESPACE
96
90
97 #endif // QPIESLICE_H
91 #endif // QPIESLICE_H
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now