##// END OF EJS Templates
Refactor pie (again). QPieSlice's now emit signals and no id's anymore. Just pointers in the interface.
Jani Honkonen -
r203:7350e0387b3f
parent child
Show More
@@ -0,0 +1,20
1 #include "customslice.h"
2
3 CustomSlice::CustomSlice(qreal value, QObject* parent)
4 :QPieSlice(parent)
5 {
6 setValue(value);
7 connect(this, SIGNAL(changed()), this, SLOT(updateLabel()));
8 connect(this, SIGNAL(hoverEnter()), this, SLOT(toggleExploded()));
9 connect(this, SIGNAL(hoverLeave()), this, SLOT(toggleExploded()));
10 }
11
12 void CustomSlice::updateLabel()
13 {
14 setLabel(QString::number(this->percentage()));
15 }
16
17 void CustomSlice::toggleExploded()
18 {
19 setExploded(!isExploded());
20 }
@@ -0,0 +1,15
1 #include <qpieslice.h>
2
3 QTCOMMERCIALCHART_USE_NAMESPACE
4
5 class CustomSlice : public QPieSlice
6 {
7 Q_OBJECT
8
9 public:
10 CustomSlice(qreal value, QObject* parent = 0);
11
12 public Q_SLOTS:
13 void updateLabel();
14 void toggleExploded();
15 };
@@ -0,0 +1,181
1 #include "qpieslice.h"
2
3 QTCOMMERCIALCHART_BEGIN_NAMESPACE
4
5 #define DEFAULT_PEN_COLOR Qt::black
6 #define DEFAULT_BRUSH_COLOR Qt::white
7 #define DEFAULT_LABEL_ARM_LENGTH 50
8
9 QPieSlice::QPieSlice(QObject *parent)
10 :QObject(parent),
11 m_value(0),
12 m_isLabelVisible(true),
13 m_isExploded(false),
14 m_percentage(0),
15 m_angle(0),
16 m_span(0),
17 m_pen(DEFAULT_PEN_COLOR),
18 m_brush(DEFAULT_BRUSH_COLOR),
19 m_labelPen(DEFAULT_PEN_COLOR),
20 m_labelArmLength(DEFAULT_LABEL_ARM_LENGTH)
21 {
22
23 }
24
25 QPieSlice::QPieSlice(qreal value, QString label, bool labelVisible, QObject *parent)
26 :QObject(parent),
27 m_value(value),
28 m_label(label),
29 m_isLabelVisible(labelVisible),
30 m_isExploded(false),
31 m_percentage(0),
32 m_angle(0),
33 m_span(0),
34 m_pen(DEFAULT_PEN_COLOR),
35 m_brush(DEFAULT_BRUSH_COLOR),
36 m_labelPen(DEFAULT_PEN_COLOR),
37 m_labelArmLength(DEFAULT_LABEL_ARM_LENGTH)
38 {
39
40 }
41
42 QPieSlice::~QPieSlice()
43 {
44
45 }
46
47 qreal QPieSlice::value() const
48 {
49 return m_value;
50 }
51
52 QString QPieSlice::label() const
53 {
54 return m_label;
55 }
56
57 bool QPieSlice::isLabelVisible() const
58 {
59 return m_isLabelVisible;
60 }
61
62 bool QPieSlice::isExploded() const
63 {
64 return m_isExploded;
65 }
66
67 qreal QPieSlice::percentage() const
68 {
69 return m_percentage;
70 }
71
72 qreal QPieSlice::angle() const
73 {
74 return m_angle;
75 }
76
77 qreal QPieSlice::span() const
78 {
79 return m_span;
80 }
81
82 QPen QPieSlice::pen() const
83 {
84 return m_pen;
85 }
86
87 QBrush QPieSlice::brush() const
88 {
89 return m_brush;
90 }
91
92 QPen QPieSlice::labelPen() const
93 {
94 return m_labelPen;
95 }
96
97 QFont QPieSlice::labelFont() const
98 {
99 return m_labelFont;
100 }
101
102 qreal QPieSlice::labelArmLenght() const
103 {
104 return m_labelArmLength;
105 }
106
107 void QPieSlice::setValue(qreal value)
108 {
109 if (m_value != value) {
110 m_value = value;
111 emit changed();
112 }
113 }
114
115 void QPieSlice::setLabel(QString label)
116 {
117 if (m_label != label) {
118 m_label = label;
119 emit changed();
120 }
121 }
122
123 void QPieSlice::setLabelVisible(bool visible)
124 {
125 if (m_isLabelVisible != visible) {
126 m_isLabelVisible = visible;
127 emit changed();
128 }
129 }
130
131 void QPieSlice::setExploded(bool exploded)
132 {
133 if (m_isExploded != exploded) {
134 m_isExploded = exploded;
135 emit changed();
136 }
137 }
138
139 void QPieSlice::setPen(QPen pen)
140 {
141 if (m_pen != pen) {
142 m_pen = pen;
143 emit changed();
144 }
145 }
146
147 void QPieSlice::setBrush(QBrush brush)
148 {
149 if (m_brush != brush) {
150 m_brush = brush;
151 emit changed();
152 }
153 }
154
155 void QPieSlice::setLabelFont(QFont font)
156 {
157 if (m_labelFont != font) {
158 m_labelFont = font;
159 emit changed();
160 }
161 }
162
163 void QPieSlice::setLabelPen(QPen pen)
164 {
165 if (m_labelPen != pen) {
166 m_labelPen = pen;
167 emit changed();
168 }
169 }
170
171 void QPieSlice::setLabelArmLength(qreal len)
172 {
173 if (m_labelArmLength != len) {
174 m_labelArmLength = len;
175 emit changed();
176 }
177 }
178
179 #include "moc_qpieslice.cpp"
180
181 QTCOMMERCIALCHART_END_NAMESPACE
@@ -0,0 +1,86
1 #ifndef QPIESLICE_H
2 #define QPIESLICE_H
3
4 #include <qchartglobal.h>
5 #include <QObject>
6 #include <QPen>
7 #include <QBrush>
8 #include <QFont>
9
10 QTCOMMERCIALCHART_BEGIN_NAMESPACE
11
12 class QTCOMMERCIALCHART_EXPORT QPieSlice : public QObject
13 {
14 Q_OBJECT
15
16 public:
17 QPieSlice(QObject *parent = 0);
18 QPieSlice(qreal value, QString label, bool labelVisible = true, QObject *parent = 0);
19 virtual ~QPieSlice();
20
21 // data
22 qreal value() const;
23 QString label() const;
24 bool isLabelVisible() const;
25 bool isExploded() const;
26
27 // generated data
28 qreal percentage() const;
29 qreal angle() const;
30 qreal span() const;
31
32 // customization
33 QPen pen() const;
34 QBrush brush() const;
35 QPen labelPen() const;
36 QFont labelFont() const;
37 qreal labelArmLenght() const;
38
39 Q_SIGNALS:
40 void clicked();
41 void hoverEnter();
42 void hoverLeave();
43 void changed();
44
45 public Q_SLOTS:
46
47 // data
48 void setLabel(QString label);
49 void setLabelVisible(bool visible);
50 void setValue(qreal value);
51 void setExploded(bool exploded);
52
53 // customization
54 void setPen(QPen pen);
55 void setBrush(QBrush brush);
56 void setLabelFont(QFont font);
57 void setLabelPen(QPen pen);
58 void setLabelArmLength(qreal len);
59
60 private:
61
62 // TODO: use private class
63 friend class QPieSeries;
64
65 // data
66 qreal m_value;
67 QString m_label;
68 bool m_isLabelVisible;
69 bool m_isExploded;
70
71 // generated data
72 qreal m_percentage;
73 qreal m_angle;
74 qreal m_span;
75
76 // customization
77 QPen m_pen;
78 QBrush m_brush;
79 QPen m_labelPen;
80 QFont m_labelFont;
81 qreal m_labelArmLength;
82 };
83
84 QTCOMMERCIALCHART_END_NAMESPACE
85
86 #endif // QPIESLICE_H
@@ -16,8 +16,8 MultiChartWidget::MultiChartWidget(QWidget *parent) :
16 16 QChartView *chartView1 = new QChartView();
17 17 l->addWidget(chartView1);
18 18 QPieSeries *pie = new QPieSeries();
19 pie->add(QPieSlice(1.1, "label1"));
20 pie->add(QPieSlice(1.2, "label2"));
19 pie->add(1.1, "label1");
20 pie->add(1.2, "label2");
21 21 chartView1->addSeries(pie);
22 22
23 23 // Create chart 2 and add a simple scatter series onto it
@@ -1,9 +1,10
1 1 #include <QtGui/QApplication>
2 2 #include <QMainWindow>
3 #include <cmath>
4 3 #include <qchartglobal.h>
5 4 #include <qchartview.h>
6 5 #include <qpieseries.h>
6 #include <qpieslice.h>
7 #include "customslice.h"
7 8
8 9 QTCOMMERCIALCHART_USE_NAMESPACE
9 10
@@ -11,23 +12,31 int main(int argc, char *argv[])
11 12 {
12 13 QApplication a(argc, argv);
13 14
14 // Create widget and scatter series
15 QChartView *chartWidget = new QChartView();
16 QPieSeries *series = qobject_cast<QPieSeries *>(chartWidget->createSeries(QChartSeries::SeriesTypePie));
17 Q_ASSERT(series);
18
19 // Add test data to the series
20 series->add(QPieSlice(1, "test1", true, true, QPen(Qt::red, 2), QBrush(Qt::red)));
21 series->add(QPieSlice(2, "test2"));
22 series->add(QPieSlice(3, "test3"));
23 series->add(QPieSlice(4, "test4"));
24 series->add(QPieSlice(5, "test5"));
25
26 // Use the chart widget as the central widget
27 QMainWindow w;
28 w.resize(640, 480);
29 w.setCentralWidget(chartWidget);
30 w.show();
15 QMainWindow window;
16
17 QPieSeries *series = new QPieSeries();
18 series->add(5, "Slice 1");
19 series->add(2, "Slice 2");
20 series->add(3, "Slice 3");
21 series->add(4, "Slice 4");
22 series->add(5, "Slice 5");
23 series->add(6, "Slice 6");
24 series->add(7, "Slice 7");
25 series->add(new CustomSlice(8));
26 series->enableClickExplodes(true);
27 series->enableHoverHighlight(true);
28
29 foreach (QPieSlice*s, series->slices())
30 qDebug() << s->angle() << s->span() << s->percentage();
31
32 QChartView* chartView = new QChartView(&window);
33 chartView->addSeries(series);
34 chartView->setChartTitle("simple piechart");
35 chartView->setChartTheme(QChart::ChartThemeIcy);
36
37 window.setCentralWidget(chartView);
38 window.resize(600, 600);
39 window.show();
31 40
32 41 return a.exec();
33 42 }
@@ -10,8 +10,10 QT += core gui
10 10 TARGET = piechart
11 11 TEMPLATE = app
12 12
13 SOURCES += main.cpp
13 SOURCES += main.cpp customslice.cpp
14 HEADERS += customslice.h
14 15
15 HEADERS +=
16 OBJECTS_DIR = tmp
17 MOC_DIR = tmp
16 18
17 19
@@ -10,6 +10,7
10 10 #include "qlinechartseries.h"
11 11 #include "qscatterseries.h"
12 12 #include "qpieseries.h"
13 #include "qpieslice.h"
13 14
14 15 //items
15 16 #include "axisitem_p.h"
@@ -232,11 +233,9 void ChartTheme::decorate(PiePresenter* item, QPieSeries* series, int /*count*/)
232 233 }
233 234
234 235 // finally update colors
235 foreach (QPieSliceId id, series->ids()) {
236 QPieSlice s = series->slice(id);
237 s.setPen(QPen(Qt::black)); // TODO: get from theme
238 s.setBrush(colors.takeFirst());
239 series->update(s);
236 foreach (QPieSlice* s, series->slices()) {
237 s->setPen(QPen(Qt::black)); // TODO: get from theme
238 s->setBrush(colors.takeFirst());
240 239 }
241 240 }
242 241
@@ -5,7 +5,8 SOURCES += \
5 5 $$PWD/qpieseries.cpp \
6 6 $$PWD/pieslice.cpp \
7 7 $$PWD/piepresenter.cpp \
8 $$PWD/pieslicelabel.cpp
8 $$PWD/pieslicelabel.cpp \
9 $$PWD/qpieslice.cpp
9 10
10 11 PRIVATE_HEADERS += \
11 12 $$PWD/piepresenter.h \
@@ -13,4 +14,5 PRIVATE_HEADERS += \
13 14 $$PWD/pieslicelabel.h
14 15
15 16 PUBLIC_HEADERS += \
16 $$PWD/qpieseries.h
17 $$PWD/qpieseries.h \
18 $$PWD/qpieslice.h
@@ -1,6 +1,7
1 1
2 2 #include "piepresenter.h"
3 3 #include "pieslice.h"
4 #include "qpieslice.h"
4 5 #include <QDebug>
5 6 #include <QTime>
6 7
@@ -29,140 +30,124 void PiePresenter::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *
29 30
30 31 void PiePresenter::handleSeriesChanged(const QPieSeries::ChangeSet& changeSet)
31 32 {
32 qDebug() << "PiePresenter::handleSeriesChanged()";
33 qDebug() << " added : " << changeSet.m_added;
34 qDebug() << " changed: " << changeSet.m_changed;
35 qDebug() << " removed: " << changeSet.m_removed;
33 //qDebug() << "PiePresenter::handleSeriesChanged()";
34 //qDebug() << " added : " << changeSet.added();
35 //qDebug() << " changed: " << changeSet.changed();
36 //qDebug() << " removed: " << changeSet.removed();
36 37
37 38 // ignore changeset when there are no visual slices
38 39 // changeset might not be valid about the added slices
39 40 if (m_slices.count() == 0) {
40 foreach (QPieSliceId id, m_series->m_slices.keys())
41 addSlice(id);
41 foreach (QPieSlice* s, m_series->m_slices)
42 addSlice(s);
42 43 return;
43 44 }
44 45
45 foreach (QPieSliceId id, changeSet.m_removed)
46 deleteSlice(id);
46 foreach (QPieSlice* s, changeSet.removed())
47 deleteSlice(s);
47 48
48 foreach (QPieSliceId id, changeSet.m_changed)
49 updateSlice(id);
49 foreach (QPieSlice* s, changeSet.added())
50 addSlice(s);
51 }
50 52
51 foreach (QPieSliceId id, changeSet.m_added)
52 addSlice(id);
53 void PiePresenter::handleDomainChanged(const Domain& domain)
54 {
55 // TODO
56 }
57
58 void PiePresenter::handleGeometryChanged(const QRectF& rect)
59 {
60 m_rect = rect;
61 updateGeometry();
53 62 }
54 63
55 64 void PiePresenter::updateGeometry()
56 65 {
57 66 prepareGeometryChange();
58 67
59 m_pieRect = m_rect;
68 QRectF pieRect = m_rect;
60 69
61 if (m_pieRect.width() < m_pieRect.height()) {
62 m_pieRect.setWidth(m_pieRect.width() * m_series->sizeFactor());
63 m_pieRect.setHeight(m_pieRect.width());
64 m_pieRect.moveCenter(m_rect.center());
70 if (pieRect.width() < pieRect.height()) {
71 pieRect.setWidth(pieRect.width() * m_series->sizeFactor());
72 pieRect.setHeight(pieRect.width());
73 pieRect.moveCenter(m_rect.center());
65 74 } else {
66 m_pieRect.setHeight(m_pieRect.height() * m_series->sizeFactor());
67 m_pieRect.setWidth(m_pieRect.height());
68 m_pieRect.moveCenter(m_rect.center());
75 pieRect.setHeight(pieRect.height() * m_series->sizeFactor());
76 pieRect.setWidth(pieRect.height());
77 pieRect.moveCenter(m_rect.center());
69 78 }
70 79
71 80 switch (m_series->position()) {
72 81 case QPieSeries::PiePositionTopLeft: {
73 m_pieRect.setHeight(m_pieRect.height() / 2);
74 m_pieRect.setWidth(m_pieRect.height());
75 m_pieRect.moveCenter(QPointF(m_rect.center().x() / 2, m_rect.center().y() / 2));
82 pieRect.setHeight(pieRect.height() / 2);
83 pieRect.setWidth(pieRect.height());
84 pieRect.moveCenter(QPointF(m_rect.center().x() / 2, m_rect.center().y() / 2));
76 85 break;
77 86 }
78 87 case QPieSeries::PiePositionTopRight: {
79 m_pieRect.setHeight(m_pieRect.height() / 2);
80 m_pieRect.setWidth(m_pieRect.height());
81 m_pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, m_rect.center().y() / 2));
88 pieRect.setHeight(pieRect.height() / 2);
89 pieRect.setWidth(pieRect.height());
90 pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, m_rect.center().y() / 2));
82 91 break;
83 92 }
84 93 case QPieSeries::PiePositionBottomLeft: {
85 m_pieRect.setHeight(m_pieRect.height() / 2);
86 m_pieRect.setWidth(m_pieRect.height());
87 m_pieRect.moveCenter(QPointF(m_rect.center().x() / 2, (m_rect.center().y() / 2) * 3));
94 pieRect.setHeight(pieRect.height() / 2);
95 pieRect.setWidth(pieRect.height());
96 pieRect.moveCenter(QPointF(m_rect.center().x() / 2, (m_rect.center().y() / 2) * 3));
88 97 break;
89 98 }
90 99 case QPieSeries::PiePositionBottomRight: {
91 m_pieRect.setHeight(m_pieRect.height() / 2);
92 m_pieRect.setWidth(m_pieRect.height());
93 m_pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, (m_rect.center().y() / 2) * 3));
100 pieRect.setHeight(pieRect.height() / 2);
101 pieRect.setWidth(pieRect.height());
102 pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, (m_rect.center().y() / 2) * 3));
94 103 break;
95 104 }
96 105 default:
97 106 break;
98 107 }
99 108
100 // update slice geometry
101 const qreal fullPie = 360;
102 qreal angle = 0;
103 foreach (QPieSliceId id, m_slices.keys()) {
104 qreal span = fullPie * m_series->slice(id).percentage();
105 m_slices[id]->updateGeometry(m_pieRect, angle, span);
106 angle += span;
109 if (m_pieRect != pieRect) {
110 m_pieRect = pieRect;
111 //qDebug() << "PiePresenter::updateGeometry()" << m_pieRect;
112 foreach (PieSlice* s, m_slices.values()) {
113 s->setPieRect(m_pieRect);
114 s->updateGeometry();
115 }
107 116 }
108
109 //qDebug() << "PiePresenter::updateGeometry" << m_rect << m_pieRect;
110 117 }
111 118
112 void PiePresenter::handleDomainChanged(const Domain& domain)
119 void PiePresenter::addSlice(QPieSlice* sliceData)
113 120 {
114 // TODO
115 }
121 //qDebug() << "PiePresenter::addSlice()" << sliceData;
116 122
117 void PiePresenter::handleGeometryChanged(const QRectF& rect)
118 {
119 m_rect = rect;
120 updateGeometry();
121 }
122
123 void PiePresenter::addSlice(QPieSliceId id)
124 {
125 qDebug() << "PiePresenter::addSlice()" << id;
126
127 if (m_slices.contains(id)) {
128 qWarning() << "PiePresenter::addSlice(): slice already exists!" << id;
129 updateSlice(id);
123 if (m_slices.keys().contains(sliceData)) {
124 //qWarning() << "PiePresenter::addSlice(): slice already exists!" << sliceData;
125 Q_ASSERT(0);
130 126 return;
131 127 }
132 128
133 129 // create slice
134 PieSlice *slice = new PieSlice(id, m_series, this);
135 m_slices.insert(id, slice);
136
137 updateGeometry();
130 PieSlice *slice = new PieSlice(this);
131 slice->updateData(sliceData);
132 m_slices.insert(sliceData, slice);
133
134 // connect signals
135 connect(sliceData, SIGNAL(changed()), slice, SLOT(handleSliceDataChanged()));
136 connect(slice, SIGNAL(clicked()), sliceData, SIGNAL(clicked()));
137 connect(slice, SIGNAL(hoverEnter()), sliceData, SIGNAL(hoverEnter()));
138 connect(slice, SIGNAL(hoverLeave()), sliceData, SIGNAL(hoverLeave()));
138 139 }
139 140
140 void PiePresenter::updateSlice(QPieSliceId id)
141 void PiePresenter::deleteSlice(QPieSlice* sliceData)
141 142 {
142 qDebug() << "PiePresenter::updateSlice()" << id;
143 //qDebug() << "PiePresenter::deleteSlice()" << sliceData;
143 144
144 // TODO: animation
145 if (m_slices.contains(id))
146 m_slices.value(id)->updateData();
145 if (m_slices.contains(sliceData))
146 delete m_slices.take(sliceData);
147 147 else {
148 qWarning() << "PiePresenter::updateSlice(): slice does not exist!" << id;
149 addSlice(id);
148 // nothing to remove
149 Q_ASSERT(0); // TODO: remove before release
150 150 }
151
152 updateGeometry();
153 }
154
155 void PiePresenter::deleteSlice(QPieSliceId id)
156 {
157 qDebug() << "PiePresenter::deleteSlice()" << id;
158
159 // TODO: animation
160 if (m_slices.contains(id))
161 delete m_slices.take(id);
162 else
163 qWarning() << "PiePresenter::deleteSlice(): slice does not exist!" << id;
164
165 updateGeometry();
166 151 }
167 152
168 153 #include "moc_piepresenter.cpp"
@@ -32,13 +32,12 public Q_SLOTS:
32 32 void updateGeometry();
33 33
34 34 private:
35 void addSlice(QPieSliceId id);
36 void updateSlice(QPieSliceId id);
37 void deleteSlice(QPieSliceId id);
35 void addSlice(QPieSlice* sliceData);
36 void deleteSlice(QPieSlice* sliceData);
38 37
39 38 private:
40 39 friend class PieSlice;
41 QHash<QPieSliceId, PieSlice*> m_slices;
40 QHash<QPieSlice*, PieSlice*> m_slices;
42 41 QPieSeries *m_series;
43 42 QRectF m_rect;
44 43 QRectF m_pieRect;
@@ -2,6 +2,7
2 2 #include "pieslicelabel.h"
3 3 #include "piepresenter.h"
4 4 #include "qpieseries.h"
5 #include "qpieslice.h"
5 6 #include <QPainter>
6 7 #include <QDebug>
7 8 #include <qmath.h>
@@ -20,27 +21,25 QPointF offset(qreal angle, qreal length)
20 21 return QPointF(dx, -dy);
21 22 }
22 23
23 PieSlice::PieSlice(QPieSliceId id, QPieSeries *series, QGraphicsItem* parent)
24 PieSlice::PieSlice(QGraphicsItem* parent)
24 25 :QGraphicsObject(parent),
25 m_id(id),
26 m_series(series),
27 26 m_slicelabel(new PieSliceLabel(this)),
28 m_isHovering(false)
27 m_angle(0),
28 m_span(0),
29 m_isExploded(false)
29 30 {
30 Q_ASSERT(series);
31 31 setAcceptHoverEvents(true);
32 32 setAcceptedMouseButtons(Qt::LeftButton);
33 updateData();
34 33 }
35 34
36 35 PieSlice::~PieSlice()
37 36 {
38 qDebug() << "~PieSlice()" << m_id;
37
39 38 }
40 39
41 40 QRectF PieSlice::boundingRect() const
42 41 {
43 return m_rect;
42 return m_path.boundingRect();
44 43 }
45 44
46 45 QPainterPath PieSlice::shape() const
@@ -50,50 +49,43 QPainterPath PieSlice::shape() const
50 49
51 50 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
52 51 {
53 // set hover brush
54 // TODO: what if we are using gradients...
55 QBrush brush = m_data.brush();
56 if (m_isHovering)
57 brush.setColor(brush.color().lighter());
58
59 52 painter->setRenderHint(QPainter::Antialiasing);
60 painter->setPen(m_data.pen());
61 painter->setBrush(brush);
53 painter->setPen(m_pen);
54 painter->setBrush(m_brush);
62 55 painter->drawPath(m_path);
63 56 }
64 57
65 58 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
66 59 {
67 m_isHovering = true;
68 update();
69 // TODO: emit hoverEnter()
60 emit hoverEnter();
70 61 }
71 62
72 63 void PieSlice::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
73 64 {
74 m_isHovering = false;
75 update();
76 // TODO: emit hoverLeave()
65 emit hoverLeave();
77 66 }
78 67
79 68 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/)
80 69 {
81 // TODO: emit clicked
82 // TODO: should we let the user decide if this can be exploded?
83 m_data.setExploded(!m_data.isExploded());
84 m_series->update(m_data);
70 emit clicked();
71 }
72
73 void PieSlice::setPieRect(QRectF rect)
74 {
75 m_pieRect = rect;
85 76 }
86 77
87 void PieSlice::updateGeometry(QRectF rect, qreal startAngle, qreal span)
78 void PieSlice::updateGeometry()
88 79 {
89 80 prepareGeometryChange();
90 81
91 82 // calculate center angle
92 qreal centerAngle = startAngle + (span/2);
83 qreal centerAngle = m_angle + (m_span/2);
93 84
94 85 // adjust rect for exploding
86 QRectF rect = m_pieRect;
95 87 rect.adjust(EXPLODE_OFFSET, EXPLODE_OFFSET, -EXPLODE_OFFSET ,-EXPLODE_OFFSET);
96 if (m_data.isExploded()) {
88 if (m_isExploded) {
97 89 QPointF d = offset((centerAngle), EXPLODE_OFFSET);
98 90 rect.translate(d.x(), d.y());
99 91 }
@@ -102,9 +94,9 void PieSlice::updateGeometry(QRectF rect, qreal startAngle, qreal span)
102 94 // TODO: draw the shape so that it might have a hole in the center
103 95 QPainterPath path;
104 96 path.moveTo(rect.center());
105 path.arcTo(rect, -startAngle + 90, -span);
97 path.arcTo(rect, -m_angle + 90, -m_span);
98 path.closeSubpath();
106 99 m_path = path;
107 m_rect = path.boundingRect();
108 100
109 101 // update label position
110 102 qreal radius = rect.height() / 2;
@@ -112,27 +104,36 void PieSlice::updateGeometry(QRectF rect, qreal startAngle, qreal span)
112 104
113 105 m_slicelabel->setArmStartPoint(edgeCenter);
114 106 m_slicelabel->setArmAngle(centerAngle);
115 m_slicelabel->setArmLength(50);
116 107 m_slicelabel->updateGeometry();
117 108
118 //qDebug() << "PieSlice::updateGeometry" << m_rect;
109 //qDebug() << "PieSlice::updateGeometry" << m_slicelabel->text() << boundingRect() << m_angle << m_span;
110 }
111
112 void PieSlice::handleSliceDataChanged()
113 {
114 QPieSlice *slice = qobject_cast<QPieSlice*>(sender());
115 Q_ASSERT(slice);
116 updateData(slice);
119 117 }
120 118
121 void PieSlice::updateData()
119 void PieSlice::updateData(const QPieSlice* sliceData)
122 120 {
123 if (!m_series->m_slices.contains(m_id))
124 qWarning() << "PieSlice::updateData(): cannot find slice data!" << m_id;
121 // TODO: compare what has changes to avoid unneccesary geometry updates
125 122
126 QPieSlice data = m_series->slice(m_id);
127 // TODO: find out what has changed and trigger some animation
128 m_data = data;
123 m_angle = sliceData->angle();
124 m_span = sliceData->span();
125 m_isExploded = sliceData->isExploded();
126 m_pen = sliceData->pen();
127 m_brush = sliceData->brush();
129 128
129 updateGeometry();
130 130 update();
131 131
132 m_slicelabel->setVisible(m_data.isLabelVisible());
133 m_slicelabel->setText(m_data.label());
134 //m_slicelabel->setPen(m_data.labelPen());
135 //m_slicelabel->setFont(m_data.labelFont());
132 m_slicelabel->setVisible(sliceData->isLabelVisible());
133 m_slicelabel->setText(sliceData->label());
134 m_slicelabel->setPen(sliceData->labelPen());
135 m_slicelabel->setFont(sliceData->labelFont());
136 m_slicelabel->setArmLength(sliceData->labelArmLenght());
136 137 m_slicelabel->updateGeometry(); // text size & font modifies the geometry
137 138 m_slicelabel->update();
138 139 }
@@ -12,13 +12,14
12 12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
13 13 class PiePresenter;
14 14 class PieSliceLabel;
15 class QPieSlice;
15 16
16 17 class PieSlice : public QGraphicsObject
17 18 {
18 19 Q_OBJECT
19 20
20 21 public:
21 PieSlice(QPieSliceId id, QPieSeries *series, QGraphicsItem* parent = 0);
22 PieSlice(QGraphicsItem* parent = 0);
22 23 ~PieSlice();
23 24
24 25 public: // from QGraphicsItem
@@ -31,19 +32,27 public: // from QGraphicsItem
31 32
32 33 Q_SIGNALS:
33 34 void clicked();
35 void hoverEnter();
36 void hoverLeave();
34 37
35 public:
36 void updateGeometry(QRectF rect, qreal startAngle, qreal span);
37 void updateData();
38 public Q_SLOTS:
39 void handleSliceDataChanged();
40 void setPieRect(QRectF rect);
41 void updateGeometry();
42 void updateData(const QPieSlice *sliceData);
38 43
39 44 private:
40 QPieSliceId m_id;
41 QPieSeries* m_series;
42 QPieSlice m_data;
43 45 PieSliceLabel* m_slicelabel;
46
47 QRectF m_pieRect;
44 48 QPainterPath m_path;
45 QRectF m_rect;
46 bool m_isHovering;
49
50 qreal m_angle;
51 qreal m_span;
52 bool m_isExploded;
53
54 QPen m_pen;
55 QBrush m_brush;
47 56 };
48 57
49 58 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,112 +1,147
1 1 #include "qpieseries.h"
2 #include "qpieslice.h"
2 3 #include "piepresenter.h"
3 4 #include "pieslice.h"
4 5 #include <QDebug>
5 6
6 7 QTCOMMERCIALCHART_BEGIN_NAMESPACE
7 8
8 QPieSeries::QPieSeries(QObject *parent) :
9 QChartSeries(parent),
10 m_sizeFactor(1.0),
11 m_position(PiePositionMaximized),
12 m_sliceIdSeed(0)
9 void QPieSeries::ChangeSet::appendAdded(QPieSlice* slice)
13 10 {
11 if (!m_added.contains(slice))
12 m_added << slice;
14 13 }
15 14
16 QPieSeries::~QPieSeries()
15 void QPieSeries::ChangeSet::appendChanged(QPieSlice* slice)
17 16 {
17 if (!m_changed.contains(slice))
18 m_changed << slice;
19 }
18 20
21 void QPieSeries::ChangeSet::appendRemoved(QPieSlice* slice)
22 {
23 if (!m_removed.contains(slice))
24 m_removed << slice;
19 25 }
20 26
21 bool QPieSeries::setData(QList<qreal> data)
27 QList<QPieSlice*> QPieSeries::ChangeSet::added() const
22 28 {
23 // TODO: remove this function
24 QList<QPieSlice> slices;
25 foreach (int value, data)
26 slices << QPieSlice(value, QString::number(value));
27 return set(slices);
29 return m_added;
28 30 }
29 31
30 bool QPieSeries::set(const QList<QPieSlice>& slices)
32 QList<QPieSlice*> QPieSeries::ChangeSet::changed() const
31 33 {
32 if (!slices.count())
33 return false;
34 return m_changed;
35 }
34 36
35 ChangeSet changeSet;
37 QList<QPieSlice*> QPieSeries::ChangeSet::removed() const
38 {
39 return m_removed;
40 }
36 41
37 foreach (QPieSlice s, m_slices.values())
38 changeSet.m_removed << s.id();
42 bool QPieSeries::ChangeSet::isEmpty() const
43 {
44 if (m_added.count() || m_changed.count() || m_removed.count())
45 return false;
46 return true;
47 }
39 48
40 m_slices.clear();
41 49
42 foreach (QPieSlice s, slices) {
43 s.m_id = generateSliceId();
44 m_slices.insert(s.id(), s);
45 changeSet.m_added << s.id();
46 }
50 QPieSeries::QPieSeries(QObject *parent) :
51 QChartSeries(parent),
52 m_sizeFactor(1.0),
53 m_position(PiePositionMaximized),
54 m_pieStartAngle(0),
55 m_pieSpan(360)
56 {
47 57
48 updateDerivativeData();
49 emit changed(changeSet);
58 }
50 59
60 QPieSeries::~QPieSeries()
61 {
62 // slices destroyed by parent object
63 qDebug() << "~QPieSeries";
64 }
65
66 bool QPieSeries::setData(QList<qreal> data)
67 {
68 // TODO: remove this function
69 QList<QPieSlice*> slices;
70 foreach (int value, data)
71 slices << new QPieSlice(value, QString::number(value));
72 set(slices);
51 73 return true;
52 74 }
53 75
54 bool QPieSeries::add(const QList<QPieSlice>& slices)
76 void QPieSeries::set(QList<QPieSlice*> slices)
55 77 {
56 if (!slices.count())
57 return false;
78 clear();
79 add(slices);
80 }
58 81
82 void QPieSeries::add(QList<QPieSlice*> slices)
83 {
59 84 ChangeSet changeSet;
60 foreach (QPieSlice s, slices) {
61 s.m_id = generateSliceId();
62 m_slices.insert(s.id(), s);
63 changeSet.m_added << s.id();
85 foreach (QPieSlice* s, slices) {
86 s->setParent(this);
87 m_slices << s;
88 changeSet.appendAdded(s);
64 89 }
65 90
66 91 updateDerivativeData();
67 emit changed(changeSet);
68 92
69 return true;
93 foreach (QPieSlice* s, slices) {
94 connect(s, SIGNAL(changed()), this, SLOT(sliceChanged()));
95 connect(s, SIGNAL(clicked()), this, SLOT(sliceClicked()));
96 connect(s, SIGNAL(hoverEnter()), this, SLOT(sliceHoverEnter()));
97 connect(s, SIGNAL(hoverLeave()), this, SLOT(sliceHoverLeave()));
98 }
99
100 emit changed(changeSet);
70 101 }
71 102
72 bool QPieSeries::add(const QPieSlice& slice)
103 void QPieSeries::add(QPieSlice* slice)
73 104 {
74 return add(QList<QPieSlice>() << slice);
105 add(QList<QPieSlice*>() << slice);
75 106 }
76 107
77 bool QPieSeries::update(const QPieSlice& slice)
108 QPieSlice* QPieSeries::add(qreal value, QString name)
78 109 {
79 if (!m_slices.contains(slice.id()))
80 return false; // series does not contain this slice
110 QPieSlice* slice = new QPieSlice(value, name);
111 add(slice);
112 return slice;
113 }
81 114
82 m_slices[slice.id()] = slice;
115 void QPieSeries::remove(QPieSlice* slice)
116 {
117 if (!m_slices.removeOne(slice)) {
118 Q_ASSERT(0); // TODO: remove before release
119 return;
120 }
83 121
84 122 ChangeSet changeSet;
85 changeSet.m_changed << slice.id();
86 updateDerivativeData();
123 changeSet.appendRemoved(slice);
87 124 emit changed(changeSet);
88 125
89 return true;
126 delete slice;
127 slice = NULL;
128
129 updateDerivativeData();
90 130 }
91 131
92 bool QPieSeries::remove(QPieSliceId id)
132 void QPieSeries::clear()
93 133 {
94 if (!m_slices.contains(id))
95 return false; // series does not contain this slice
96
97 m_slices.remove(id);
134 if (m_slices.count() == 0)
135 return;
98 136
99 137 ChangeSet changeSet;
100 changeSet.m_removed << id;
101 updateDerivativeData();
138 foreach (QPieSlice* s, m_slices) {
139 changeSet.appendRemoved(s);
140 m_slices.removeOne(s);
141 delete s;
142 }
102 143 emit changed(changeSet);
103
104 return true;
105 }
106
107 QPieSlice QPieSeries::slice(QPieSliceId id) const
108 {
109 return m_slices.value(id);
144 updateDerivativeData();
110 145 }
111 146
112 147 void QPieSeries::setSizeFactor(qreal factor)
@@ -128,23 +163,136 void QPieSeries::setPosition(PiePosition position)
128 163 }
129 164 }
130 165
131 QPieSliceId QPieSeries::generateSliceId()
166 void QPieSeries::setSpan(qreal startAngle, qreal span)
167 {
168 if (startAngle >= 0 && startAngle < 360 &&
169 span > 0 && span <= 360) {
170 m_pieStartAngle = startAngle;
171 m_pieSpan = span;
172 updateDerivativeData();
173 }
174 }
175
176 void QPieSeries::setLabelsVisible(bool visible)
177 {
178 foreach (QPieSlice* s, m_slices)
179 s->setLabelVisible(visible);
180 }
181
182 void QPieSeries::enableClickExplodes(bool enable)
183 {
184 if (enable)
185 connect(this, SIGNAL(clicked(QPieSlice*)), this, SLOT(toggleExploded(QPieSlice*)));
186 else
187 disconnect(this, SLOT(toggleExploded(QPieSlice*)));
188 }
189
190 void QPieSeries::enableHoverHighlight(bool enable)
191 {
192 if (enable) {
193 connect(this, SIGNAL(hoverEnter(QPieSlice*)), this, SLOT(highlightOn(QPieSlice*)));
194 connect(this, SIGNAL(hoverLeave(QPieSlice*)), this, SLOT(highlightOff(QPieSlice*)));
195 } else {
196 disconnect(this, SLOT(hoverEnter(QPieSlice*)));
197 disconnect(this, SLOT(hoverLeave(QPieSlice*)));
198 }
199 }
200
201 void QPieSeries::sliceChanged()
202 {
203 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
204 Q_ASSERT(m_slices.contains(slice));
205
206 ChangeSet changeSet;
207 changeSet.appendChanged(slice);
208 emit changed(changeSet);
209
210 updateDerivativeData();
211 }
212
213 void QPieSeries::sliceClicked()
214 {
215 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
216 Q_ASSERT(m_slices.contains(slice));
217 emit clicked(slice);
218 }
219
220 void QPieSeries::sliceHoverEnter()
221 {
222 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
223 Q_ASSERT(m_slices.contains(slice));
224 emit hoverEnter(slice);
225 }
226
227 void QPieSeries::sliceHoverLeave()
132 228 {
133 // Id is quint64 so it should be enough for us.
134 // Note that id is not unique between pie series.
135 return m_sliceIdSeed++;
229 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
230 Q_ASSERT(m_slices.contains(slice));
231 emit hoverLeave(slice);
232 }
233
234 void QPieSeries::toggleExploded(QPieSlice* slice)
235 {
236 Q_ASSERT(slice);
237 slice->setExploded(!slice->isExploded());
238 }
239
240 void QPieSeries::highlightOn(QPieSlice* slice)
241 {
242 Q_ASSERT(slice);
243 QColor c = slice->brush().color().lighter();
244 slice->setBrush(c);
245 }
246
247 void QPieSeries::highlightOff(QPieSlice* slice)
248 {
249 Q_ASSERT(slice);
250 QColor c = slice->brush().color().darker(150);
251 slice->setBrush(c);
136 252 }
137 253
138 254 void QPieSeries::updateDerivativeData()
139 255 {
140 256 m_total = 0;
141 foreach (const QPieSlice& s, m_slices.values())
142 m_total += s.value();
143 257
144 Q_ASSERT(m_total > 0); // TODO: remove this before release
258 // nothing to do?
259 if (m_slices.count() == 0)
260 return;
261
262 // calculate total
263 foreach (QPieSlice* s, m_slices)
264 m_total += s->value();
265
266 // we must have some values
267 Q_ASSERT(m_total > 0); // TODO
145 268
146 foreach (QPieSliceId id, m_slices.keys())
147 m_slices[id].m_percentage = m_slices.value(id).value() / m_total;
269 // update slice attributes
270 qreal sliceAngle = m_pieStartAngle;
271 foreach (QPieSlice* s, m_slices) {
272
273 bool changed = false;
274
275 qreal percentage = s->value() / m_total;
276 if (s->m_percentage != percentage) {
277 s->m_percentage = percentage;
278 changed = true;
279 }
280
281 qreal sliceSpan = m_pieSpan * percentage;
282 if (s->m_span != sliceSpan) {
283 s->m_span = sliceSpan;
284 changed = true;
285 }
286
287 if (s->m_angle != sliceAngle) {
288 s->m_angle = sliceAngle;
289 changed = true;
290 }
291 sliceAngle += sliceSpan;
292
293 if (changed)
294 emit s->changed();
295 }
148 296 }
149 297
150 298 #include "moc_qpieseries.cpp"
@@ -7,69 +7,13
7 7 #include <QColor>
8 8 #include <QPen>
9 9 #include <QBrush>
10 #include <QSignalMapper>
10 11
11 12 class QGraphicsObject;
12 13 QTCOMMERCIALCHART_BEGIN_NAMESPACE
13 14 class PiePresenter;
14 15 class PieSlice;
15
16 typedef quint64 QPieSliceId;
17
18 class QPieSlice
19 {
20 public:
21 QPieSlice()
22 :m_id(-1), m_value(0), m_isLabelVisible(true), m_isExploded(false), m_percentage(0) {}
23
24 QPieSlice(qreal value, QString label = QString(), bool labelVisible = true, bool exploded = false, QPen pen = QPen(), QBrush brush = QBrush())
25 :m_id(-1), m_value(value), m_label(label), m_isLabelVisible(labelVisible), m_isExploded(exploded), m_pen(pen), m_brush(brush), m_percentage(0) {}
26
27 QPieSliceId id() const { return m_id; }
28
29 void setValue(qreal value) { m_value = value; }
30 qreal value() const { return m_value; }
31
32 void setLabel(QString label) { m_label = label; }
33 QString label() const { return m_label; }
34
35 void setLabelVisible(bool visible) { m_isLabelVisible = visible; }
36 bool isLabelVisible() const { return m_isLabelVisible; }
37
38 // TODO:
39 //void setLabelPen(QPen pen) {};
40 //QPen labelPen() const {};
41 //void setLabelFont(QFont font);
42 //QFont labelFont() const;
43 //void setLabelArmLenght(qreal len) {};
44 //qreal labelArmLenght() const {};
45
46 void setExploded(bool exploded) { m_isExploded = exploded; }
47 bool isExploded() const { return m_isExploded; }
48
49 void setPen(QPen pen) { m_pen = pen; }
50 QPen pen() const { return m_pen; }
51
52 void setBrush(QBrush brush) { m_brush = brush; }
53 QBrush brush() const { return m_brush; }
54
55 qreal percentage() const { return m_percentage; }
56
57 private:
58
59 // TODO: use private class
60 friend class QPieSeries;
61
62 QPieSliceId m_id;
63 qreal m_value;
64 QString m_label;
65 bool m_isLabelVisible;
66 bool m_isExploded;
67
68 QPen m_pen;
69 QBrush m_brush;
70
71 qreal m_percentage; // generated content
72 };
16 class QPieSlice;
73 17
74 18 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QChartSeries
75 19 {
@@ -87,42 +31,48 public:
87 31 class ChangeSet
88 32 {
89 33 public:
90 QList<QPieSliceId> m_added;
91 QList<QPieSliceId> m_removed;
92 QList<QPieSliceId> m_changed;
34 void appendAdded(QPieSlice* slice);
35 void appendChanged(QPieSlice* slice);
36 void appendRemoved(QPieSlice* slice);
37
38 QList<QPieSlice*> added() const;
39 QList<QPieSlice*> changed() const;
40 QList<QPieSlice*> removed() const;
41
42 bool isEmpty() const;
43
44 private:
45 QList<QPieSlice*> m_added;
46 QList<QPieSlice*> m_changed;
47 QList<QPieSlice*> m_removed;
93 48 };
94 49
95 50 public:
96 51 QPieSeries(QObject *parent = 0);
97 ~QPieSeries();
52 virtual ~QPieSeries();
98 53
99 54 public: // from QChartSeries
100 55 QChartSeriesType type() const { return QChartSeries::SeriesTypePie; }
101 56 virtual bool setData(QList<qreal> data); // TODO: remove this
102 57
103 58 public:
104 // TODO: should we return id/bool or what?
105 // TODO: should we prefer passing a modifiable reference?
106 bool set(const QList<QPieSlice>& slices);
107 bool add(const QList<QPieSlice>& slices);
108 bool add(const QPieSlice& slice);
109 bool update(const QPieSlice& slice);
110 bool remove(QPieSliceId id);
59 void set(QList<QPieSlice*> slices);
60 void add(QList<QPieSlice*> slices);
61 void add(QPieSlice* slice);
62 QPieSlice* add(qreal value, QString name);
63 void remove(QPieSlice* slice);
64 void clear();
111 65
112 66 int count() const { return m_slices.count(); }
113 67
114 QList<QPieSlice> slices() const { return m_slices.values(); }
115 QList<QPieSliceId> ids() const { return m_slices.keys(); }
116 QPieSlice slice(QPieSliceId id) const;
68 QList<QPieSlice*> slices() const { return m_slices; }
117 69
118 // TODO: sorting?
70 // TODO: find slices?
71 // QList<QPieSlice*> findByValue(qreal value);
72 // ...
119 73
120 // TODO: convenience functions?
121 //void setValue(QPieSliceId id, qreal value);
122 //void setLabel(QPieSliceId id, QString label);
123 //void setPen(QPieSliceId id, QPen pen);
124 //void setBrush(QPieSliceId id, QBrush brush);
125 //void setExploded(QPieSliceId id, bool exploded);
74 // TODO: sorting slices?
75 // void sort(QPieSeries::SortByValue)
126 76
127 77 void setSizeFactor(qreal sizeFactor);
128 78 qreal sizeFactor() const { return m_sizeFactor; }
@@ -130,18 +80,31 public:
130 80 void setPosition(PiePosition position);
131 81 PiePosition position() const { return m_position; }
132 82
83 void setSpan(qreal startAngle, qreal span);
84
85 void setLabelsVisible(bool visible);
86 void enableClickExplodes(bool enable);
87 void enableHoverHighlight(bool enable);
88
133 89 Q_SIGNALS:
134 90 void changed(const QPieSeries::ChangeSet& changeSet);
91 void clicked(QPieSlice* slice);
92 void hoverEnter(QPieSlice* slice);
93 void hoverLeave(QPieSlice* slice);
135 94 void sizeFactorChanged();
136 95 void positionChanged();
137 96
138 // TODO:
139 //void sliceClicked(QPieSliceId id);
140 // ?? void sliceHoverEnter(QPieSliceId id);
141 // ?? void sliceHoverLeave(QPieSliceId id);
97 private Q_SLOTS: // should be private and not in the interface
98 void sliceChanged();
99 void sliceClicked();
100 void sliceHoverEnter();
101 void sliceHoverLeave();
102
103 void toggleExploded(QPieSlice* slice);
104 void highlightOn(QPieSlice* slice);
105 void highlightOff(QPieSlice* slice);
142 106
143 107 private:
144 QPieSliceId generateSliceId();
145 108 void updateDerivativeData();
146 109
147 110 private:
@@ -151,11 +114,12 private:
151 114 friend class PiePresenter;
152 115 friend class PieSlice;
153 116
154 QHash<QPieSliceId, QPieSlice> m_slices;
117 QList<QPieSlice*> m_slices;
155 118 qreal m_sizeFactor;
156 119 PiePosition m_position;
157 120 qreal m_total;
158 QPieSliceId m_sliceIdSeed;
121 qreal m_pieStartAngle;
122 qreal m_pieSpan;
159 123 };
160 124
161 125 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now