##// END OF EJS Templates
Adaptive layout to legend. Tries to fit all items inside given maximum size
sauimone -
r626:b05202e4f2ef
parent child
Show More
@@ -5,13 +5,16
5 #include <qxyseries.h>
5 #include <qxyseries.h>
6 #include <QPainter>
6 #include <QPainter>
7 #include <QGraphicsSceneEvent>
7 #include <QGraphicsSceneEvent>
8 #include <QGraphicsSimpleTextItem>
8
9
9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
10 QTCOMMERCIALCHART_BEGIN_NAMESPACE
10
11
11 LegendMarker::LegendMarker(QSeries* series, QGraphicsItem *parent)
12 LegendMarker::LegendMarker(QSeries* series, QGraphicsItem *parent)
12 : QGraphicsObject(parent)
13 : QGraphicsObject(parent)
13 ,mBoundingRect(0,0,1,1)
14 ,mPos(0,0)
14 ,mMarkerBoundingRect(0,0,1,1)
15 ,mSize(0,0)
16 ,mBoundingRect(0,0,0,0)
17 ,mMarkerBoundingRect(0,0,0,0)
15 ,mSeries(series)
18 ,mSeries(series)
16 ,mBarset(0)
19 ,mBarset(0)
17 ,mPieslice(0)
20 ,mPieslice(0)
@@ -23,8 +26,10 LegendMarker::LegendMarker(QSeries* series, QGraphicsItem *parent)
23
26
24 LegendMarker::LegendMarker(QSeries *series, QBarSet *barset, QGraphicsItem *parent)
27 LegendMarker::LegendMarker(QSeries *series, QBarSet *barset, QGraphicsItem *parent)
25 : QGraphicsObject(parent)
28 : QGraphicsObject(parent)
26 ,mBoundingRect(0,0,1,1)
29 ,mPos(0,0)
27 ,mMarkerBoundingRect(0,0,1,1)
30 ,mSize(0,0)
31 ,mBoundingRect(0,0,0,0)
32 ,mMarkerBoundingRect(0,0,0,0)
28 ,mSeries(series)
33 ,mSeries(series)
29 ,mBarset(barset)
34 ,mBarset(barset)
30 ,mPieslice(0)
35 ,mPieslice(0)
@@ -36,8 +41,10 LegendMarker::LegendMarker(QSeries *series, QBarSet *barset, QGraphicsItem *pare
36
41
37 LegendMarker::LegendMarker(QSeries *series, QPieSlice *pieslice, QGraphicsItem *parent)
42 LegendMarker::LegendMarker(QSeries *series, QPieSlice *pieslice, QGraphicsItem *parent)
38 : QGraphicsObject(parent)
43 : QGraphicsObject(parent)
39 ,mBoundingRect(0,0,1,1)
44 ,mPos(0,0)
40 ,mMarkerBoundingRect(0,0,1,1)
45 ,mSize(0,0)
46 ,mBoundingRect(0,0,0,0)
47 ,mMarkerBoundingRect(0,0,0,0)
41 ,mSeries(series)
48 ,mSeries(series)
42 ,mBarset(0)
49 ,mBarset(0)
43 ,mPieslice(pieslice)
50 ,mPieslice(pieslice)
@@ -47,18 +54,10 LegendMarker::LegendMarker(QSeries *series, QPieSlice *pieslice, QGraphicsItem *
47 setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton);
54 setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton);
48 }
55 }
49
56
50 void LegendMarker::setBoundingRect(const QRectF rect)
57 void LegendMarker::setPos(qreal x, qreal y)
51 {
58 {
52 mBoundingRect = rect;
59 mPos = QPointF(x,y);
53 // Calculate Marker pos
60 layoutChanged();
54
55 // TODO: remove hard coding. 5 is marigin around marker
56 QSizeF markerSize(10,10);
57 qreal x = mBoundingRect.x() + 5;
58 qreal y = mBoundingRect.y() + (mBoundingRect.height() - markerSize.height())/2;
59 mMarkerBoundingRect = QRectF(x,y,markerSize.width(),markerSize.height());
60
61 mTextItem.setPos(mBoundingRect.x() + markerSize.width() + 10, y );
62 }
61 }
63
62
64 void LegendMarker::setBrush(const QBrush brush)
63 void LegendMarker::setBrush(const QBrush brush)
@@ -74,6 +73,7 QBrush LegendMarker::brush() const
74 void LegendMarker::setName(const QString name)
73 void LegendMarker::setName(const QString name)
75 {
74 {
76 mTextItem.setText(name);
75 mTextItem.setText(name);
76 layoutChanged();
77 }
77 }
78
78
79 QString LegendMarker::name() const
79 QString LegendMarker::name() const
@@ -100,6 +100,21 QRectF LegendMarker::boundingRect() const
100 return mBoundingRect;
100 return mBoundingRect;
101 }
101 }
102
102
103 void LegendMarker::layoutChanged()
104 {
105 QSizeF markerSize(10,10);
106 qreal margin = 2;
107
108 mSize.setHeight(markerSize.height() + 2 * margin);
109 mSize.setWidth(mTextItem.boundingRect().width() + markerSize.width() + 3 * margin);
110
111 mBoundingRect = QRectF(mPos.x(),mPos.y(),mSize.width(),mSize.height());
112
113 mMarkerBoundingRect = QRectF(mPos.x() + margin, mPos.y() + margin, markerSize.width(),markerSize.height());
114
115 mTextItem.setPos(mPos.x() + markerSize.width() + 2 * margin, mPos.y() + margin );
116 }
117
103 void LegendMarker::mousePressEvent(QGraphicsSceneMouseEvent *event)
118 void LegendMarker::mousePressEvent(QGraphicsSceneMouseEvent *event)
104 {
119 {
105 switch (mType)
120 switch (mType)
@@ -4,6 +4,7
4 #include "qchartglobal.h"
4 #include "qchartglobal.h"
5 #include <QGraphicsObject>
5 #include <QGraphicsObject>
6 #include <QBrush>
6 #include <QBrush>
7 #include <QGraphicsSimpleTextItem>
7
8
8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9
10
@@ -26,7 +27,8 public:
26 LegendMarker(QSeries* series, QGraphicsItem *parent = 0);
27 LegendMarker(QSeries* series, QGraphicsItem *parent = 0);
27 LegendMarker(QSeries* series, QBarSet* barset, QGraphicsItem *parent = 0);
28 LegendMarker(QSeries* series, QBarSet* barset, QGraphicsItem *parent = 0);
28 LegendMarker(QSeries* series, QPieSlice* pieslice, QGraphicsItem *parent = 0);
29 LegendMarker(QSeries* series, QPieSlice* pieslice, QGraphicsItem *parent = 0);
29 void setBoundingRect(const QRectF rect);
30
31 void setPos(qreal x, qreal y);
30
32
31 void setBrush(const QBrush brush);
33 void setBrush(const QBrush brush);
32 QBrush brush() const;
34 QBrush brush() const;
@@ -40,6 +42,8 public:
40
42
41 QRectF boundingRect() const;
43 QRectF boundingRect() const;
42
44
45 void layoutChanged();
46
43 public:
47 public:
44 // From QGraphicsObject
48 // From QGraphicsObject
45 void mousePressEvent(QGraphicsSceneMouseEvent *event);
49 void mousePressEvent(QGraphicsSceneMouseEvent *event);
@@ -53,6 +57,8 public Q_SLOTS:
53 void changed();
57 void changed();
54
58
55 private:
59 private:
60 QPointF mPos;
61 QSize mSize;
56 QRectF mBoundingRect;
62 QRectF mBoundingRect;
57 QRectF mMarkerBoundingRect;
63 QRectF mMarkerBoundingRect;
58 QBrush mBrush;
64 QBrush mBrush;
@@ -346,16 +346,10 void QChart::updateLayout()
346 }
346 }
347
347
348 // recalculate legend position
348 // recalculate legend position
349 // TODO: better layout
350 if (m_legend) {
349 if (m_legend) {
351 QRectF boundingRect(m_rect.adjusted(margin(),
350 m_legend->setMaximumSize(rect.size());
352 rect.height() + margin() + margin()/2,
351 m_legend->setPos(rect.topLeft());
353 -margin(),
352 m_legend->setPreferredLayout(QLegend::PreferredLayoutHorizontal);
354 -margin()/2 + m_legend->minimumSize().height()));
355 // m_legend->handleGeometryChanged(boundingRect);
356 QRectF br(0,0,margin(),m_rect.height());
357 m_legend->handleGeometryChanged(br);
358 m_legend->setPreferredLayout(QLegend::PreferredLayoutVertical);
359 }
353 }
360 }
354 }
361 #include "moc_qchart.cpp"
355 #include "moc_qchart.cpp"
@@ -13,6 +13,7
13 #include "qbarset.h"
13 #include "qbarset.h"
14 #include "qpieseries.h"
14 #include "qpieseries.h"
15 #include "qpieslice.h"
15 #include "qpieslice.h"
16 #include "chartpresenter_p.h"
16 #include <QPainter>
17 #include <QPainter>
17 #include <QPen>
18 #include <QPen>
18
19
@@ -22,13 +23,15 QTCOMMERCIALCHART_BEGIN_NAMESPACE
22
23
23 QLegend::QLegend(QGraphicsItem *parent)
24 QLegend::QLegend(QGraphicsItem *parent)
24 : QGraphicsObject(parent)
25 : QGraphicsObject(parent)
25 ,mBoundingRect(0,0,1,1)
26 ,mPos(0,0)
26 ,mBackgroundBrush(Qt::darkGray) // TODO: from theme?
27 ,mSize(0,0)
27 ,mMinimumSize(50,20) // TODO: magic numbers
28 ,mMinimumSize(50,20) // TODO: magic numbers
28 ,mMaximumSize(150,100)
29 ,mMaximumSize(150,100)
30 ,mBackgroundBrush(Qt::darkGray) // TODO: from theme?
29 ,mPreferredLayout(QLegend::PreferredLayoutVertical)
31 ,mPreferredLayout(QLegend::PreferredLayoutVertical)
30 {
32 {
31 setVisible(false);
33 // setVisible(false);
34 setZValue(ChartPresenter::LegendZValue);
32 }
35 }
33
36
34 void QLegend::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
37 void QLegend::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
@@ -36,13 +39,14 void QLegend::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q
36 Q_UNUSED(option)
39 Q_UNUSED(option)
37 Q_UNUSED(widget)
40 Q_UNUSED(widget)
38
41
42 painter->setOpacity(0.5);
39 painter->setBrush(mBackgroundBrush);
43 painter->setBrush(mBackgroundBrush);
40 painter->drawRect(mBoundingRect);
44 painter->drawRect(boundingRect());
41 }
45 }
42
46
43 QRectF QLegend::boundingRect() const
47 QRectF QLegend::boundingRect() const
44 {
48 {
45 return mBoundingRect;
49 return QRectF(mPos,mSize);
46 }
50 }
47
51
48 void QLegend::setBackgroundBrush(const QBrush& brush)
52 void QLegend::setBackgroundBrush(const QBrush& brush)
@@ -61,14 +65,30 void QLegend::setPreferredLayout(QLegend::PreferredLayout preferred)
61 layoutChanged();
65 layoutChanged();
62 }
66 }
63
67
64 QSizeF QLegend::minimumSize() const
68 QSizeF QLegend::maximumSize() const
65 {
69 {
66 return mMinimumSize;
70 return mMaximumSize;
67 }
71 }
68
72
69 void QLegend::setMinimumSize(const QSizeF size)
73 void QLegend::setMaximumSize(const QSizeF size)
70 {
74 {
71 mMinimumSize = size;
75 mMaximumSize = size;
76 }
77
78 void QLegend::setSize(const QSizeF size)
79 {
80 mSize = size;
81 if (mSize.width() > mMaximumSize.width()) {
82 mSize.setWidth(mMaximumSize.width());
83 }
84 if (mSize.height() > mMaximumSize.height()) {
85 mSize.setHeight(mMaximumSize.height());
86 }
87 }
88
89 void QLegend::setPos(const QPointF &pos)
90 {
91 mPos = pos;
72 }
92 }
73
93
74 void QLegend::handleSeriesAdded(QSeries* series, Domain* domain)
94 void QLegend::handleSeriesAdded(QSeries* series, Domain* domain)
@@ -96,12 +116,6 void QLegend::handleSeriesRemoved(QSeries* series)
96 layoutChanged();
116 layoutChanged();
97 }
117 }
98
118
99 void QLegend::handleGeometryChanged(const QRectF& size)
100 {
101 mBoundingRect = size;
102 layoutChanged();
103 }
104
105 void QLegend::createMarkers(QSeries *series)
119 void QLegend::createMarkers(QSeries *series)
106 {
120 {
107 switch (series->type())
121 switch (series->type())
@@ -216,38 +230,103 void QLegend::layoutChanged()
216 return;
230 return;
217 }
231 }
218
232
219 // Limit legend size to maximum.
233 // Find out widest item.
220 QSizeF size = mBoundingRect.size();
234 qreal itemMaxWidth = 0;
235 qreal itemMaxHeight = 0;
236 foreach (LegendMarker* m, mMarkers) {
237 if (m->boundingRect().width() > itemMaxWidth) {
238 itemMaxWidth = m->boundingRect().width();
239 }
240 if (m->boundingRect().height() > itemMaxHeight) {
241 itemMaxHeight = m->boundingRect().height();
242 }
243 }
244
245 int maxHorizontalItems = boundingRect().width() / itemMaxWidth;
246 int maxVerticalItems = boundingRect().height() / itemMaxHeight;
221
247
248 if (mMarkers.count() > maxHorizontalItems * maxVerticalItems) {
249 // TODO: overlapping layout
250 qDebug() << "Warning. Not enough space to layout all legend items properly.";
251 }
222
252
223 // TODO: grid layout
253 qreal margin = 5;
254 qreal totalWidth = 0;
255 qreal totalHeight = 0;
224 switch (mPreferredLayout)
256 switch (mPreferredLayout)
225 {
257 {
226 case QLegend::PreferredLayoutHorizontal: {
258 case QLegend::PreferredLayoutHorizontal: {
227
259 /*
228 qreal steps = mMarkers.count();
260 qreal xStep = mMaximumSize.width() / (mMarkers.count()+1);
229 qreal xStep = size.width() / (steps+1);
261 if (xStep > itemMaxWidth) {
230 qreal x = mBoundingRect.x() + xStep/2;
262 xStep = itemMaxWidth;
231 qreal y = mBoundingRect.y(); // Half of legend marker min size
263 }
264 qreal yStep = mMaximumSize.height() / (mMarkers.count()+1);
265 if (yStep > itemMaxHeight) {
266 yStep = itemMaxHeight;
267 }*/
268 qreal xStep = itemMaxWidth;
269 qreal yStep = itemMaxHeight;
270 qreal x = mPos.x() + margin;
271 qreal y = mPos.y() + margin;
272 int row = 1;
273 int column = 0;
274 int maxRows = 1;
275 int maxColumns = 1;
232 foreach (LegendMarker* m, mMarkers) {
276 foreach (LegendMarker* m, mMarkers) {
233 m->setBoundingRect(QRectF(x,y,xStep,size.height()/2));
277 maxRows = row;
278 m->setPos(x,y);
234 x += xStep;
279 x += xStep;
280 column++;
281 if (column > maxColumns) {
282 maxColumns = column;
283 }
284 if ((x + itemMaxWidth + margin*2) > (mPos.x() + mMaximumSize.width())) {
285 x = mPos.x() + margin;
286 y += yStep;
287 row++;
288 column = 0;
289 }
235 }
290 }
291 totalWidth = maxColumns * itemMaxWidth + margin * 2;
292 totalHeight = maxRows * itemMaxHeight + margin * 2;
236 break;
293 break;
237 }
294 }
238 case QLegend::PreferredLayoutVertical: {
295 case QLegend::PreferredLayoutVertical: {
239 // Limit markers to bounding rect size.
296 /*
240 if (size.width() > mBoundingRect.width()) {
297 qreal xStep = mMaximumSize.width() / (mMarkers.count()+1);
241 size.setWidth(mBoundingRect.width());
298 if (xStep > itemMaxWidth) {
299 xStep = itemMaxWidth;
242 }
300 }
243 qreal steps = mMarkers.count();
301 qreal yStep = mMaximumSize.height() / (mMarkers.count()+1);
244 qreal yStep = size.height() / (steps+1);
302 if (yStep > itemMaxHeight) {
245 qreal x = mBoundingRect.x();
303 yStep = itemMaxHeight;
246 qreal y = mBoundingRect.y() + yStep/2;
304 }*/
305 qreal xStep = itemMaxWidth;
306 qreal yStep = itemMaxHeight;
307 qreal x = mPos.x() + margin;
308 qreal y = mPos.y() + margin;
309 int row = 0;
310 int column = 1;
311 int maxRows = 1;
312 int maxColumns = 1;
247 foreach (LegendMarker* m, mMarkers) {
313 foreach (LegendMarker* m, mMarkers) {
248 m->setBoundingRect(QRectF(x,y,size.width(),yStep));
314 maxColumns = column;
315 m->setPos(x,y);
249 y += yStep;
316 y += yStep;
317 row++;
318 if (row > maxRows) {
319 maxRows = row;
320 }
321 if ((y + itemMaxHeight + margin*2) > (mPos.y() + mMaximumSize.height())) {
322 y = mPos.y() + margin;
323 x += xStep;
324 column++;
325 row = 0;
326 }
250 }
327 }
328 totalWidth = maxColumns * itemMaxWidth + margin * 2;
329 totalHeight = maxRows * itemMaxHeight + margin * 2;
251 break;
330 break;
252 }
331 }
253 default: {
332 default: {
@@ -255,6 +334,8 void QLegend::layoutChanged()
255 }
334 }
256 }
335 }
257
336
337 mSize.setWidth(totalWidth);
338 mSize.setHeight(totalHeight);
258 }
339 }
259
340
260 #include "moc_qlegend.cpp"
341 #include "moc_qlegend.cpp"
@@ -35,11 +35,12 public:
35
35
36 void setPreferredLayout(QLegend::PreferredLayout preferred);
36 void setPreferredLayout(QLegend::PreferredLayout preferred);
37
37
38 QSizeF minimumSize() const;
39 void setMinimumSize(const QSizeF size);
40 QSizeF maximumSize() const;
38 QSizeF maximumSize() const;
41 void setMaximumSize(const QSizeF size);
39 void setMaximumSize(const QSizeF size);
42
40
41 void setSize(const QSizeF size);
42 void setPos(const QPointF &pos);
43
43 signals:
44 signals:
44 // for interactions.
45 // for interactions.
45 void clicked(QSeries* series, Qt::MouseButton button);
46 void clicked(QSeries* series, Qt::MouseButton button);
@@ -49,12 +50,11 signals:
49 public slots:
50 public slots:
50 void handleSeriesAdded(QSeries* series,Domain* domain);
51 void handleSeriesAdded(QSeries* series,Domain* domain);
51 void handleSeriesRemoved(QSeries* series);
52 void handleSeriesRemoved(QSeries* series);
52 void handleGeometryChanged(const QRectF& size);
53
53
54 private:
54 private:
55 // PIMPL --->
55 // PIMPL --->
56 void createMarkers(QSeries* series);
56 void createMarkers(QSeries* series);
57 void appendMarkers(QXYSeries* series);
57 void appendMarkers(QXYSeries* series); // All line series are derived from QXYSeries, so this works for now
58 void appendMarkers(QBarSeries* series);
58 void appendMarkers(QBarSeries* series);
59 void appendMarkers(QPieSeries* series);
59 void appendMarkers(QPieSeries* series);
60 void deleteMarkers(QSeries* series);
60 void deleteMarkers(QSeries* series);
@@ -62,13 +62,16 private:
62 // <--- PIMPL
62 // <--- PIMPL
63
63
64
64
65 QRectF mBoundingRect;
65 // QRectF mBoundingRect;
66 QPointF mPos;
67 QSizeF mSize;
68 QSizeF mMinimumSize;
69 QSizeF mMaximumSize;
70
66 QList<QSeries*> mSeriesList;
71 QList<QSeries*> mSeriesList;
67 QList<LegendMarker*> mMarkers;
72 QList<LegendMarker*> mMarkers;
68
73
69 QBrush mBackgroundBrush;
74 QBrush mBackgroundBrush;
70 QSizeF mMinimumSize;
71 QSizeF mMaximumSize;
72 QLegend::PreferredLayout mPreferredLayout;
75 QLegend::PreferredLayout mPreferredLayout;
73 };
76 };
74
77
General Comments 0
You need to be logged in to leave comments. Login now