##// END OF EJS Templates
Fixes detach legend layout logic
Michal Klocek -
r1536:b5727e9e0a5c
parent child
Show More
@@ -1,368 +1,372
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "legendlayout_p.h"
22 22 #include "chartpresenter_p.h"
23 23 #include "legendmarker_p.h"
24 24 #include "qlegend_p.h"
25 25
26 26 QTCOMMERCIALCHART_BEGIN_NAMESPACE
27 27
28 28 LegendLayout::LegendLayout(QLegend* legend):
29 29 m_legend(legend)
30 30 {
31 31
32 32 }
33 33
34 34 LegendLayout::~LegendLayout()
35 35 {
36 36
37 37 }
38 38
39 39 void LegendLayout::setOffset(qreal x, qreal y)
40 40 {
41 41 bool scrollHorizontal = true;
42 42 switch(m_legend->alignment()) {
43 43 case Qt::AlignTop:
44 44 case Qt::AlignBottom: {
45 45 scrollHorizontal = true;
46 46 break;
47 47 }
48 48 case Qt::AlignLeft:
49 49 case Qt::AlignRight: {
50 50 scrollHorizontal = false;
51 51 break;
52 52 }
53 53 }
54 54
55 55 // If detached, the scrolling direction is vertical instead of horizontal and vice versa.
56 56 if (!m_legend->isAttachedToChart()) {
57 57 scrollHorizontal = !scrollHorizontal;
58 58 }
59 59
60 60 QRectF boundingRect = geometry();
61 61
62 62 // Limit offset between m_minOffset and m_maxOffset
63 63 if (scrollHorizontal) {
64 64 if(m_width<=boundingRect.width()) return;
65 65
66 66 if (x != m_offsetX) {
67 67 m_offsetX = qBound(m_minOffsetX, x, m_maxOffsetX);
68 68 m_legend->d_ptr->items()->setPos(-m_offsetX,boundingRect.top());
69 69 }
70 70 }
71 71 else {
72 72 if(m_height<=boundingRect.height()) return;
73 73
74 74 if (y != m_offsetY) {
75 75 m_offsetY = qBound(m_minOffsetY, y, m_maxOffsetY);
76 76 m_legend->d_ptr->items()->setPos(boundingRect.left(),-m_offsetY);
77 77 }
78 78 }
79 79 }
80 80
81 81 QPointF LegendLayout::offset() const
82 82 {
83 83 return QPointF(m_offsetX,m_offsetY);
84 84 }
85 85
86 86 void LegendLayout::setGeometry(const QRectF& rect)
87 87 {
88 88 if (!rect.isValid()) return;
89 89
90 90 QGraphicsLayout::setGeometry(rect);
91 91
92 92 if(m_legend->isAttachedToChart()) {
93 93 setAttachedGeometry(rect);
94 94 }
95 95 else {
96 96 setDettachedGeometry(rect);
97 97 }
98 98 }
99 99
100 100 void LegendLayout::setAttachedGeometry(const QRectF& rect)
101 101 {
102 102
103 103 m_offsetX=0;
104 104 m_offsetY=0;
105 105
106 106 QSizeF size(0,0);
107 107
108 108 if( m_legend->d_ptr->markers().isEmpty()) return;
109 109
110 110 m_width=0;
111 111 m_height=0;
112 112
113 113 switch(m_legend->alignment()) {
114 114
115 115 case Qt::AlignTop:
116 116
117 117 case Qt::AlignBottom: {
118 118 QPointF point(0,0);
119 119 foreach (LegendMarker* marker, m_legend->d_ptr->markers()) {
120 120 if (marker->isVisible()) {
121 121 marker->setGeometry(QRectF(QPoint(0,0),marker->effectiveSizeHint(Qt::PreferredSize)));
122 122 marker->setPos(point.x(),rect.height()/2 - marker->boundingRect().height()/2);
123 123 const QRectF& rect = marker->boundingRect();
124 124 size = size.expandedTo(rect.size());
125 125 qreal w = rect.width();
126 126 m_width+=w;
127 127 point.setX(point.x() + w);
128 128 }
129 129 }
130 130 if(m_width<rect.width()) {
131 131 m_legend->d_ptr->items()->setPos(rect.width()/2-m_width/2,rect.top());
132 132
133 133 }
134 134 else {
135 135 m_legend->d_ptr->items()->setPos(rect.topLeft());
136 136 }
137 137 m_height=size.height();
138 138 }
139 139 break;
140 140 case Qt::AlignLeft:
141 141 case Qt::AlignRight: {
142 142 QPointF point(0,0);
143 143 foreach (LegendMarker* marker, m_legend->d_ptr->markers()) {
144 144 if (marker->isVisible()) {
145 145 marker->setGeometry(QRectF(QPoint(0,0),marker->effectiveSizeHint(Qt::PreferredSize)));
146 146 marker->setPos(point);
147 147 const QRectF& rect = marker->boundingRect();
148 148 qreal h = rect.height();
149 149 size = size.expandedTo(rect.size());
150 150 m_height+=h;
151 151 point.setY(point.y() + h);
152 152 }
153 153 }
154 154 if(m_height<rect.height()) {
155 155 m_legend->d_ptr->items()->setPos(rect.left(),rect.height()/2-m_height/2);
156 156 }
157 157 else {
158 158 m_legend->d_ptr->items()->setPos(rect.topLeft());
159 159 }
160 160 m_width=size.width();
161 161 }
162 162 break;
163 163 }
164 164
165 165 m_minOffsetX = 0;
166 166 m_minOffsetY = 0;
167 167 m_maxOffsetX = m_width - rect.width();
168 168 m_maxOffsetY = m_height - rect.height();
169 169 }
170 170
171 171 void LegendLayout::setDettachedGeometry(const QRectF& rect)
172 172 {
173 173 // Detached layout is different.
174 174 // In detached mode legend may have multiple rows and columns, so layout calculations
175 175 // differ a log from attached mode.
176 176 // Also the scrolling logic is bit different.
177 177
178 178 m_offsetX=0;
179 179 m_offsetY=0;
180 180
181 181 QSizeF size(0,0);
182 182
183 if( m_legend->d_ptr->markers().isEmpty()) return;
183 QList<LegendMarker *> markers = m_legend->d_ptr->markers();
184 184
185 QList<QGraphicsItem *> items = m_legend->d_ptr->items()->childItems();
185 if(markers.isEmpty()) return;
186 186
187 187 switch (m_legend->alignment()) {
188 188 case Qt::AlignTop: {
189 189 QPointF point = rect.topLeft();
190 190 m_width = 0;
191 191 m_height = 0;
192 for (int i=0; i<items.count(); i++) {
193 QGraphicsItem *item = items.at(i);
194 if (item->isVisible()) {
195 const QRectF& boundingRect = item->boundingRect();
192 for (int i=0; i<markers.count(); i++) {
193 LegendMarker *marker = markers.at(i);
194 if (marker->isVisible()) {
195 marker->setGeometry(QRectF(QPoint(0,0),marker->effectiveSizeHint(Qt::PreferredSize)));
196 marker->setPos(point.x(),point.y());
197 const QRectF& boundingRect = marker->boundingRect();
196 198 qreal w = boundingRect.width();
197 199 qreal h = boundingRect.height();
198 200 m_width = qMax(m_width,w);
199 201 m_height = qMax(m_height,h);
200 item->setPos(point.x(),point.y());
201 202 point.setX(point.x() + w);
202 203 if (point.x() + w > rect.topLeft().x() + rect.width()) {
203 204 // Next item would go off rect.
204 205 point.setX(rect.topLeft().x());
205 206 point.setY(point.y() + h);
206 if (i+1 < items.count()) {
207 if (i+1 < markers.count()) {
207 208 m_height += h;
208 209 }
209 210 }
210 211 }
211 212 }
212 213 m_legend->d_ptr->items()->setPos(rect.topLeft());
213 214
214 215 m_minOffsetX = 0;
215 216 m_minOffsetY = 0;
216 217 m_maxOffsetX = m_width - rect.width();
217 218 m_maxOffsetY = m_height - rect.height();
218 219 }
219 220 break;
220 221 case Qt::AlignBottom: {
221 222 QPointF point = rect.bottomLeft();
222 223 m_width = 0;
223 224 m_height = 0;
224 for (int i=0; i<items.count(); i++) {
225 QGraphicsItem *item = items.at(i);
226 if (item->isVisible()) {
227 const QRectF& boundingRect = item->boundingRect();
225 for (int i=0; i<markers.count(); i++) {
226 LegendMarker *marker = markers.at(i);
227 if (marker->isVisible()) {
228 marker->setGeometry(QRectF(QPoint(0,0),marker->effectiveSizeHint(Qt::PreferredSize)));
229 const QRectF& boundingRect = marker->boundingRect();
228 230 qreal w = boundingRect.width();
229 231 qreal h = boundingRect.height();
230 232 m_width = qMax(m_width,w);
231 233 m_height = qMax(m_height,h);
232 item->setPos(point.x(),point.y() - h);
234 marker->setPos(point.x(),point.y() - h);
233 235 point.setX(point.x() + w);
234 236 if (point.x() + w > rect.bottomLeft().x() + rect.width()) {
235 237 // Next item would go off rect.
236 238 point.setX(rect.bottomLeft().x());
237 239 point.setY(point.y() - h);
238 if (i+1 < items.count()) {
240 if (i+1 < markers.count()) {
239 241 m_height += h;
240 242 }
241 243 }
242 244 }
243 245 }
244 246 m_legend->d_ptr->items()->setPos(rect.topLeft());
245 247
246 248 m_minOffsetX = 0;
247 249 m_minOffsetY = qMin(rect.topLeft().y(), rect.topLeft().y() - m_height + rect.height());
248 250 m_maxOffsetX = m_width - rect.width();
249 251 m_maxOffsetY = 0;
250 252 }
251 253 break;
252 254 case Qt::AlignLeft: {
253 255 QPointF point = rect.topLeft();
254 256 m_width = 0;
255 257 m_height = 0;
256 258 qreal maxWidth = 0;
257 for (int i=0; i<items.count(); i++) {
258 QGraphicsItem *item = items.at(i);
259 if (item->isVisible()) {
260 const QRectF& boundingRect = item->boundingRect();
259 for (int i=0; i<markers.count(); i++) {
260 LegendMarker *marker = markers.at(i);
261 if (marker->isVisible()) {
262 marker->setGeometry(QRectF(QPoint(0,0),marker->effectiveSizeHint(Qt::PreferredSize)));
263 const QRectF& boundingRect = marker->boundingRect();
261 264 qreal w = boundingRect.width();
262 265 qreal h = boundingRect.height();
263 266 m_height = qMax(m_height,h);
264 267 maxWidth = qMax(maxWidth,w);
265 item->setPos(point.x(),point.y());
268 marker->setPos(point.x(),point.y());
266 269 point.setY(point.y() + h);
267 270 if (point.y() + h > rect.topLeft().y() + rect.height()) {
268 271 // Next item would go off rect.
269 272 point.setX(point.x() + maxWidth);
270 273 point.setY(rect.topLeft().y());
271 if (i+1 < items.count()) {
274 if (i+1 < markers.count()) {
272 275 m_width += maxWidth;
273 276 maxWidth = 0;
274 277 }
275 278 }
276 279 }
277 280 }
278 281 m_width += maxWidth;
279 282 m_legend->d_ptr->items()->setPos(rect.topLeft());
280 283
281 284 m_minOffsetX = 0;
282 285 m_minOffsetY = 0;
283 286 m_maxOffsetX = m_width - rect.width();
284 287 m_maxOffsetY = m_height - rect.height();
285 288 }
286 289 break;
287 290 case Qt::AlignRight: {
288 291 QPointF point = rect.topRight();
289 292 m_width = 0;
290 293 m_height = 0;
291 294 qreal maxWidth = 0;
292 for (int i=0; i<items.count(); i++) {
293 QGraphicsItem *item = items.at(i);
294 if (item->isVisible()) {
295 const QRectF& boundingRect = item->boundingRect();
295 for (int i=0; i<markers.count(); i++) {
296 LegendMarker *marker = markers.at(i);
297 if (marker->isVisible()) {
298 marker->setGeometry(QRectF(QPoint(0,0),marker->effectiveSizeHint(Qt::PreferredSize)));
299 const QRectF& boundingRect = marker->boundingRect();
296 300 qreal w = boundingRect.width();
297 301 qreal h = boundingRect.height();
298 302 m_height = qMax(m_height,h);
299 303 maxWidth = qMax(maxWidth,w);
300 item->setPos(point.x() - w,point.y());
304 marker->setPos(point.x() - w,point.y());
301 305 point.setY(point.y() + h);
302 306 if (point.y() + h > rect.topLeft().y() + rect.height()) {
303 307 // Next item would go off rect.
304 308 point.setX(point.x() - maxWidth);
305 309 point.setY(rect.topLeft().y());
306 if (i+1 < items.count()) {
310 if (i+1 < markers.count()) {
307 311 m_width += maxWidth;
308 312 maxWidth = 0;
309 313 }
310 314 }
311 315 }
312 316 }
313 317 m_width += maxWidth;
314 318 m_legend->d_ptr->items()->setPos(rect.topLeft());
315 319
316 320 m_minOffsetX = qMin(rect.topLeft().x(), rect.topLeft().x() - m_width + rect.width());
317 321 m_minOffsetY = 0;
318 322 m_maxOffsetX = 0;
319 323 m_maxOffsetY = m_height - rect.height();
320 324 }
321 325 break;
322 326 default:
323 327 break;
324 328 }
325 329
326 330 }
327 331
328 332 QSizeF LegendLayout::sizeHint ( Qt::SizeHint which, const QSizeF & constraint) const
329 333 {
330 334 QSizeF size(0, 0);
331 335 qreal left, top, right, bottom;
332 336 getContentsMargins(&left, &top, &right, &bottom);
333 337
334 338 if(constraint.isValid()) {
335 339 foreach(LegendMarker* marker, m_legend->d_ptr->markers()) {
336 340 size = size.expandedTo(marker->effectiveSizeHint(which));
337 341 }
338 342 size = size.boundedTo(constraint);
339 343 }
340 344 else if (constraint.width() >= 0) {
341 345 qreal width = 0;
342 346 qreal height = 0;
343 347 foreach(LegendMarker* marker, m_legend->d_ptr->markers()) {
344 348 width+=marker->effectiveSizeHint(which).width();
345 349 height=qMax(height,marker->effectiveSizeHint(which).height());
346 350 }
347 351
348 352 size = QSizeF(qMin(constraint.width(),width), height);
349 353 }
350 354 else if (constraint.height() >= 0) {
351 355 qreal width = 0;
352 356 qreal height = 0;
353 357 foreach(LegendMarker* marker, m_legend->d_ptr->markers()) {
354 358 width=qMax(width,marker->effectiveSizeHint(which).width());
355 359 height+=height,marker->effectiveSizeHint(which).height();
356 360 }
357 361 size = QSizeF(width,qMin(constraint.height(),height));
358 362 }
359 363 else {
360 364 foreach(LegendMarker* marker, m_legend->d_ptr->markers()) {
361 365 size = size.expandedTo(marker->effectiveSizeHint(which));
362 366 }
363 367 }
364 368 size += QSize(left + right, top + bottom);
365 369 return size;
366 370 }
367 371
368 372 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,233 +1,234
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "legendmarker_p.h"
22 22 #include "qxyseries.h"
23 23 #include "qxyseries_p.h"
24 24 #include "qlegend.h"
25 25 #include "qbarseries.h"
26 26 #include "qpieseries.h"
27 27 #include "qpieslice.h"
28 28 #include "qbarset.h"
29 29 #include "qbarset_p.h"
30 30 #include "qareaseries.h"
31 31 #include "qareaseries_p.h"
32 32 #include <QPainter>
33 33 #include <QGraphicsSceneEvent>
34 34 #include <QGraphicsSimpleTextItem>
35 35 #include <QDebug>
36 36
37 37 QTCOMMERCIALCHART_BEGIN_NAMESPACE
38 38
39 39 LegendMarker::LegendMarker(QAbstractSeries *series, QLegend *legend) :
40 40 QGraphicsObject(legend),
41 41 m_series(series),
42 42 m_markerRect(0,0,10.0,10.0),
43 43 m_boundingRect(0,0,0,0),
44 44 m_legend(legend),
45 45 m_textItem(new QGraphicsSimpleTextItem(this)),
46 46 m_rectItem(new QGraphicsRectItem(this)),
47 47 m_margin(2),
48 48 m_space(4)
49 49 {
50 50 //setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton);
51 51 m_rectItem->setRect(m_markerRect);
52 52 }
53 53
54 54 void LegendMarker::setPen(const QPen &pen)
55 55 {
56 56 m_rectItem->setPen(pen);
57 57 m_textItem->setPen(pen);
58 58 }
59 59
60 60 QPen LegendMarker::pen() const
61 61 {
62 62 return m_rectItem->pen();
63 63 }
64 64
65 65 void LegendMarker::setBrush(const QBrush &brush)
66 66 {
67 67 m_rectItem->setBrush(brush);
68 68 }
69 69
70 70 QBrush LegendMarker::brush() const
71 71 {
72 72 return m_rectItem->brush();
73 73 }
74 74
75 75 void LegendMarker::setFont(const QFont &font)
76 76 {
77 77 m_textItem->setFont(font);
78 updateGeometry();
78 79 }
79 80
80 81 QFont LegendMarker::font() const
81 82 {
82 83 return m_textItem->font();
83 84 }
84 85
85 86 void LegendMarker::setLabel(const QString label)
86 87 {
87 88 m_textItem->setText(label);
88 89 }
89 90
90 91 QString LegendMarker::label() const
91 92 {
92 93 return m_textItem->text();
93 94 }
94 95
95 96 QRectF LegendMarker::boundingRect() const
96 97 {
97 98 return m_boundingRect;
98 99 }
99 100
100 101 void LegendMarker::setLabelBrush(const QBrush &brush)
101 102 {
102 103 m_textItem->setBrush(brush);
103 104 }
104 105
105 106 QBrush LegendMarker::labelBrush() const
106 107 {
107 108 return m_textItem->brush();
108 109 }
109 110
110 111
111 112 void LegendMarker::setGeometry(const QRectF& rect)
112 113 {
113 114 const QRectF& textRect = m_textItem->boundingRect();
114 115
115 116 m_textItem->setPos(m_markerRect.width() + m_space + m_margin,rect.height()/2 - textRect.height()/2);
116 117 m_rectItem->setPos(m_margin,rect.height()/2 - m_markerRect.height()/2);
117 118
118 119 prepareGeometryChange();
119 120 m_boundingRect = rect;
120 121 }
121 122
122 123 void LegendMarker::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
123 124 {
124 125 Q_UNUSED(option)
125 126 Q_UNUSED(widget)
126 127 Q_UNUSED(painter)
127 128 }
128 129
129 130
130 131 QSizeF LegendMarker::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const
131 132 {
132 133 Q_UNUSED(constraint)
133 134
134 135 QFontMetrics fn(m_textItem->font());
135 136 QSizeF sh;
136 137
137 138 switch (which) {
138 139 case Qt::MinimumSize:
139 140 sh = QSizeF(fn.boundingRect("...").width(),fn.height());
140 141 break;
141 142 case Qt::PreferredSize:
142 143 sh = QSizeF(fn.boundingRect(m_textItem->text()).width() + 2*m_margin + m_space +m_markerRect.width(),qMax(m_markerRect.height()+2*m_margin,fn.height()+2*m_margin));
143 144 break;
144 145 default:
145 146 break;
146 147 }
147 148
148 149 return sh;
149 150 }
150 151
151 152 void LegendMarker::mousePressEvent(QGraphicsSceneMouseEvent *event)
152 153 {
153 154 QGraphicsObject::mousePressEvent(event);
154 155 qDebug()<<"Not implemented"; //TODO: selected signal removed for now
155 156 }
156 157
157 158 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
158 159
159 160 AreaLegendMarker::AreaLegendMarker(QAreaSeries *series,QLegend *legend) : LegendMarker(series,legend),
160 161 m_series(series)
161 162 {
162 163 //QObject::connect(this, SIGNAL(selected()), series, SIGNAL(selected()));
163 164 QObject::connect(series->d_func(),SIGNAL(updated()), this, SLOT(updated()));
164 165 QObject::connect(series, SIGNAL(nameChanged()), this, SLOT(updated()));
165 166 updated();
166 167 }
167 168
168 169 void AreaLegendMarker::updated()
169 170 {
170 171 setBrush(m_series->brush());
171 172 setLabel(m_series->name());
172 173 }
173 174
174 175 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
175 176
176 177 BarLegendMarker::BarLegendMarker(QBarSeries *barseries,QBarSet *barset, QLegend *legend) : LegendMarker(barseries,legend),
177 178 m_barset(barset)
178 179 {
179 180 //QObject::connect(this, SIGNAL(selected()),barset->d_ptr.data(), SIGNAL(selected()));
180 181 QObject::connect(barset->d_ptr.data(), SIGNAL(updatedBars()), this, SLOT(updated()));
181 182 updated();
182 183 }
183 184
184 185 void BarLegendMarker::updated()
185 186 {
186 187 setBrush(m_barset->brush());
187 188 setLabel(m_barset->label());
188 189 }
189 190
190 191 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
191 192
192 193 PieLegendMarker::PieLegendMarker(QPieSeries* series,QPieSlice *pieslice, QLegend *legend) : LegendMarker(series,legend),
193 194 m_pieslice(pieslice)
194 195 {
195 196 QObject::connect(pieslice, SIGNAL(labelChanged()), this, SLOT(updated()));
196 197 QObject::connect(pieslice, SIGNAL(brushChanged()), this, SLOT(updated()));
197 198 updated();
198 199 }
199 200
200 201 void PieLegendMarker::updated()
201 202 {
202 203 setBrush(m_pieslice->brush());
203 204 setLabel(m_pieslice->label());
204 205 }
205 206
206 207 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
207 208
208 209 XYLegendMarker::XYLegendMarker(QXYSeries *series, QLegend *legend) : LegendMarker(series,legend),
209 210 m_series(series)
210 211 {
211 212 //QObject::connect(this, SIGNAL(selected()), series, SIGNAL(selected()));
212 213 QObject::connect(series->d_func(),SIGNAL(updated()), this, SLOT(updated()));
213 214 QObject::connect(series, SIGNAL(nameChanged()), this, SLOT(updated()));
214 215 updated();
215 216 }
216 217
217 218 void XYLegendMarker::updated()
218 219 {
219 220 setLabel(m_series->name());
220 221
221 222 if(m_series->type()== QAbstractSeries::SeriesTypeScatter)
222 223 {
223 224 setBrush(m_series->brush());
224 225
225 226 }
226 227 else {
227 228 setBrush(QBrush(m_series->pen().color()));
228 229 }
229 230 }
230 231
231 232 #include "moc_legendmarker_p.cpp"
232 233
233 234 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,549 +1,550
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "qlegend.h"
22 22 #include "qlegend_p.h"
23 23 #include "qabstractseries.h"
24 24 #include "qabstractseries_p.h"
25 25 #include "qchart_p.h"
26 26 #include "legendlayout_p.h"
27 27 #include "legendmarker_p.h"
28 28 #include "qxyseries.h"
29 29 #include "qlineseries.h"
30 30 #include "qareaseries.h"
31 31 #include "qscatterseries.h"
32 32 #include "qsplineseries.h"
33 33 #include "qbarseries.h"
34 34 #include "qstackedbarseries.h"
35 35 #include "qpercentbarseries.h"
36 36 #include "qbarset.h"
37 37 #include "qpieseries.h"
38 38 #include "qpieseries_p.h"
39 39 #include "qpieslice.h"
40 40 #include "chartpresenter_p.h"
41 41 #include <QPainter>
42 42 #include <QPen>
43 43 #include <QTimer>
44 44 #include <QGraphicsLayout>
45 45 #include <QGraphicsSceneEvent>
46 46
47 47 QTCOMMERCIALCHART_BEGIN_NAMESPACE
48 48
49 49 /*!
50 50 \class QLegend
51 51 \brief Legend object
52 52 \mainclass
53 53
54 54 QLegend is a graphical object, whics displays legend of the chart. Legend state is updated by QChart, when
55 55 series have been changed. By default, legend is drawn by QChart, but user can set a new parent to legend and
56 56 handle the drawing manually.
57 57 User isn't supposed to create or delete legend objects, but can reference it via QChart class.
58 58
59 59 \image examples_percentbarchart_legend.png
60 60
61 61 \sa QChart
62 62 */
63 63 /*!
64 64 \qmlclass Legend QLegend
65 65 \brief Legend is part of QtCommercial Chart QML API.
66 66
67 67 Legend is a graphical object, whics displays legend of the chart. Legend state is updated by ChartView, when
68 68 series have been changed. Legend is used via ChartView class. For example:
69 69 \code
70 70 ChartView {
71 71 legend.visible: true
72 72 legend.alignment: Qt.AlignBottom
73 73 // Add a few series...
74 74 }
75 75 \endcode
76 76
77 77 \image examples_percentbarchart_legend.png
78 78 */
79 79
80 80 /*!
81 81 \property QLegend::alignment
82 82 \brief The alignment of the legend.
83 83
84 84 Legend paints on the defined position in the chart. The following alignments are supported:
85 85 Qt::AlignTop, Qt::AlignBottom, Qt::AlignLeft, Qt::AlignRight. If you set more than one flag the result is undefined.
86 86 */
87 87 /*!
88 88 \qmlproperty Qt.Alignment Legend::alignment
89 89 \brief The alignment of the legend.
90 90
91 91 Legend paints on the defined position in the chart. The following alignments are supported:
92 92 Qt.AlignTop, Qt.AlignBottom, Qt.AlignLeft, Qt.AlignRight. If you set more than one flag the result is undefined.
93 93 */
94 94
95 95 /*!
96 96 \property QLegend::backgroundVisible
97 97 Whether the legend background is visible or not.
98 98 */
99 99 /*!
100 100 \qmlproperty bool Legend::backgroundVisible
101 101 Whether the legend background is visible or not.
102 102 */
103 103
104 104 /*!
105 105 \property QLegend::color
106 106 The color of the legend, i.e. the background (brush) color. Note that if you change the color
107 107 of the legend, the style of the legend brush is set to Qt::SolidPattern.
108 108 */
109 109 /*!
110 110 \qmlproperty color Legend::color
111 111 The color of the legend, i.e. the background (brush) color.
112 112 */
113 113
114 114 /*!
115 115 \property QLegend::borderColor
116 116 The border color of the legend, i.e. the line color.
117 117 */
118 118 /*!
119 119 \qmlproperty color Legend::borderColor
120 120 The border color of the legend, i.e. the line color.
121 121 */
122 122
123 123 /*!
124 124 \property QLegend::font
125 125 The font of markers used by legend
126 126 */
127 127 /*!
128 128 \qmlproperty color Legend::font
129 129 The font of markers used by legend
130 130 */
131 131
132 132 /*!
133 133 \property QLegend::labelColor
134 134 The color of brush used to draw labels.
135 135 */
136 136 /*!
137 137 \qmlproperty color QLegend::labelColor
138 138 The color of brush used to draw labels.
139 139 */
140 140
141 141 /*!
142 142 \fn void QLegend::backgroundVisibleChanged(bool)
143 143 The visibility of the legend background changed to \a visible.
144 144 */
145 145
146 146 /*!
147 147 \fn void QLegend::colorChanged(QColor)
148 148 The color of the legend background changed to \a color.
149 149 */
150 150
151 151 /*!
152 152 \fn void QLegend::borderColorChanged(QColor)
153 153 The border color of the legend background changed to \a color.
154 154 */
155 155
156 156 /*!
157 157 \fn void QLegend::fontChanged(QFont)
158 158 The font of markers of the legend changed to \a font.
159 159 */
160 160
161 161 /*!
162 162 \fn void QLegend::labelBrushChanged(QBrush brush)
163 163 This signal is emitted when the brush used to draw labels has changed to \a brush.
164 164 */
165 165
166 166 /*!
167 167 \fn void QLegend::labelColorChanged(QColor color)
168 168 This signal is emitted when the color of brush used to draw labels has changed to \a color.
169 169 */
170 170
171 171 /*!
172 172 \fn qreal QLegend::minWidth() const
173 173 Returns minimum width of the legend
174 174 */
175 175
176 176 /*!
177 177 \fn qreal QLegend::minHeight() const
178 178 Returns minimum height of the legend
179 179 */
180 180
181 181 /*!
182 182 Constructs the legend object and sets the parent to \a parent
183 183 */
184 184
185 185 QLegend::QLegend(QChart *chart):QGraphicsWidget(chart),
186 186 d_ptr(new QLegendPrivate(chart->d_ptr->m_presenter,chart,this))
187 187 {
188 188 setZValue(ChartPresenter::LegendZValue);
189 189 setFlags(QGraphicsItem::ItemClipsChildrenToShape);
190 190 QObject::connect(chart->d_ptr->m_dataset,SIGNAL(seriesAdded(QAbstractSeries*,Domain*)),d_ptr.data(),SLOT(handleSeriesAdded(QAbstractSeries*,Domain*)));
191 191 QObject::connect(chart->d_ptr->m_dataset,SIGNAL(seriesRemoved(QAbstractSeries*)),d_ptr.data(),SLOT(handleSeriesRemoved(QAbstractSeries*)));
192 192 QObject::connect(chart->d_ptr->m_dataset,SIGNAL(seriesUpdated(QAbstractSeries*)),d_ptr.data(),SLOT(handleSeriesUpdated(QAbstractSeries*)));
193 193 setLayout(d_ptr->m_layout);
194 194 }
195 195
196 196 /*!
197 197 Destroys the legend object. Legend is always owned by a QChart, so an application should never call this.
198 198 */
199 199 QLegend::~QLegend()
200 200 {
201 201 }
202 202
203 203 /*!
204 204 \internal
205 205 */
206 206 void QLegend::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
207 207 {
208 208 Q_UNUSED(option)
209 209 Q_UNUSED(widget)
210 210 if(!d_ptr->m_backgroundVisible) return;
211 211
212 212 painter->setOpacity(opacity());
213 213 painter->setPen(d_ptr->m_pen);
214 214 painter->setBrush(d_ptr->m_brush);
215 215 painter->drawRoundRect(rect(),d_ptr->roundness(rect().width()),d_ptr->roundness(rect().height()));
216 216
217 217 }
218 218
219 219
220 220 /*!
221 221 Sets the \a brush of legend. Brush affects the background of legend.
222 222 */
223 223 void QLegend::setBrush(const QBrush &brush)
224 224 {
225 225 if (d_ptr->m_brush != brush) {
226 226 d_ptr->m_brush = brush;
227 227 update();
228 228 }
229 229 }
230 230
231 231 /*!
232 232 Returns the brush used by legend.
233 233 */
234 234 QBrush QLegend::brush() const
235 235 {
236 236 return d_ptr->m_brush;
237 237 }
238 238
239 239 void QLegend::setColor(QColor color)
240 240 {
241 241 QBrush b = d_ptr->m_brush;
242 242 if (b.style() != Qt::SolidPattern || b.color() != color) {
243 243 b.setStyle(Qt::SolidPattern);
244 244 b.setColor(color);
245 245 setBrush(b);
246 246 emit colorChanged(color);
247 247 }
248 248 }
249 249
250 250 QColor QLegend::color()
251 251 {
252 252 return d_ptr->m_brush.color();
253 253 }
254 254
255 255 /*!
256 256 Sets the \a pen of legend. Pen affects the legend borders.
257 257 */
258 258 void QLegend::setPen(const QPen &pen)
259 259 {
260 260 if (d_ptr->m_pen != pen) {
261 261 d_ptr->m_pen = pen;
262 262 update();
263 263 }
264 264 }
265 265
266 266 /*!
267 267 Returns the pen used by legend
268 268 */
269 269
270 270 QPen QLegend::pen() const
271 271 {
272 272 return d_ptr->m_pen;
273 273 }
274 274
275 275 void QLegend::setFont(const QFont &font)
276 276 {
277 277 if (d_ptr->m_font != font) {
278 278 d_ptr->m_font = font;
279 279
280 280 foreach (LegendMarker *marker, d_ptr->markers()) {
281 281 marker->setFont(d_ptr->m_font);
282 282 }
283 layout()->invalidate();
283 284 emit fontChanged(font);
284 285 }
285 286 }
286 287
287 288 QFont QLegend::font() const
288 289 {
289 290 return d_ptr->m_font;
290 291 }
291 292
292 293 void QLegend::setBorderColor(QColor color)
293 294 {
294 295 QPen p = d_ptr->m_pen;
295 296 if (p.color() != color) {
296 297 p.setColor(color);
297 298 setPen(p);
298 299 emit borderColorChanged(color);
299 300 }
300 301 }
301 302
302 303 QColor QLegend::borderColor()
303 304 {
304 305 return d_ptr->m_pen.color();
305 306 }
306 307
307 308 /*!
308 309 Set brush used to draw labels to \a brush.
309 310 */
310 311 void QLegend::setLabelBrush(const QBrush &brush)
311 312 {
312 313 if (d_ptr->m_labelBrush != brush) {
313 314
314 315 d_ptr->m_labelBrush = brush;
315 316
316 317 foreach (LegendMarker *marker, d_ptr->markers()) {
317 318 marker->setLabelBrush(d_ptr->m_labelBrush);
318 319 }
319 320 emit labelBrushChanged(brush);
320 321 }
321 322 }
322 323
323 324 /*!
324 325 Brush used to draw labels.
325 326 */
326 327 QBrush QLegend::labelBrush() const
327 328 {
328 329 return d_ptr->m_labelBrush;
329 330 }
330 331
331 332 void QLegend::setLabelColor(QColor color)
332 333 {
333 334 QBrush b = d_ptr->m_labelBrush;
334 335 if (b.style() != Qt::SolidPattern || b.color() != color) {
335 336 b.setStyle(Qt::SolidPattern);
336 337 b.setColor(color);
337 338 setLabelBrush(b);
338 339 emit labelColorChanged(color);
339 340 }
340 341 }
341 342
342 343 QColor QLegend::labelColor() const
343 344 {
344 345 return d_ptr->m_labelBrush.color();
345 346 }
346 347
347 348
348 349 void QLegend::setAlignment(Qt::Alignment alignment)
349 350 {
350 351 if(d_ptr->m_alignment!=alignment) {
351 352 d_ptr->m_alignment = alignment;
352 353 updateGeometry();
353 354 if(isAttachedToChart()){
354 355 d_ptr->m_presenter->layout()->invalidate();
355 356 }else{
356 357 layout()->invalidate();
357 358 }
358 359 }
359 360 }
360 361
361 362 Qt::Alignment QLegend::alignment() const
362 363 {
363 364 return d_ptr->m_alignment;
364 365 }
365 366
366 367 /*!
367 368 Detaches the legend from chart. Chart won't change layout of the legend.
368 369 */
369 370 void QLegend::detachFromChart()
370 371 {
371 372 d_ptr->m_attachedToChart = false;
372 373 d_ptr->m_layout->invalidate();
373 374 setParent(0);
374 375
375 376 }
376 377
377 378 /*!
378 379 Attaches the legend to chart. Chart may change layout of the legend.
379 380 */
380 381 void QLegend::attachToChart()
381 382 {
382 383 d_ptr->m_attachedToChart = true;
383 384 d_ptr->m_layout->invalidate();
384 385 setParent(d_ptr->m_chart);
385 386 }
386 387
387 388 /*!
388 389 Returns true, if legend is attached to chart.
389 390 */
390 391 bool QLegend::isAttachedToChart()
391 392 {
392 393 return d_ptr->m_attachedToChart;
393 394 }
394 395
395 396 /*!
396 397 Sets the visibility of legend background to \a visible
397 398 */
398 399 void QLegend::setBackgroundVisible(bool visible)
399 400 {
400 401 if(d_ptr->m_backgroundVisible != visible) {
401 402 d_ptr->m_backgroundVisible = visible;
402 403 update();
403 404 emit backgroundVisibleChanged(visible);
404 405 }
405 406 }
406 407
407 408 /*!
408 409 Returns the visibility of legend background
409 410 */
410 411 bool QLegend::isBackgroundVisible() const
411 412 {
412 413 return d_ptr->m_backgroundVisible;
413 414 }
414 415
415 416 /*!
416 417 \internal \a event see QGraphicsWidget for details
417 418 */
418 419 void QLegend::hideEvent(QHideEvent *event)
419 420 {
420 421 QGraphicsWidget::hideEvent(event);
421 422 d_ptr->m_presenter->layout()->invalidate();
422 423 }
423 424
424 425 /*!
425 426 \internal \a event see QGraphicsWidget for details
426 427 */
427 428 void QLegend::showEvent(QShowEvent *event)
428 429 {
429 430 QGraphicsWidget::showEvent(event);
430 431 d_ptr->m_presenter->layout()->invalidate();
431 432 }
432 433
433 434 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
434 435
435 436 QLegendPrivate::QLegendPrivate(ChartPresenter* presenter, QChart *chart, QLegend *q):
436 437 q_ptr(q),
437 438 m_presenter(presenter),
438 439 m_layout(new LegendLayout(q)),
439 440 m_chart(chart),
440 441 m_items(new QGraphicsItemGroup(q)),
441 442 m_alignment(Qt::AlignTop),
442 443 m_brush(QBrush()),
443 444 m_pen(QPen()),
444 445 m_labelBrush(QBrush()),
445 446 m_diameter(5),
446 447 m_attachedToChart(true),
447 448 m_backgroundVisible(false)
448 449 {
449 450
450 451 }
451 452
452 453 QLegendPrivate::~QLegendPrivate()
453 454 {
454 455
455 456 }
456 457
457 458 void QLegendPrivate::setOffset(qreal x, qreal y)
458 459 {
459 460 m_layout->setOffset(x,y);
460 461 }
461 462
462 463 QPointF QLegendPrivate::offset() const
463 464 {
464 465 return m_layout->offset();
465 466 }
466 467
467 468 int QLegendPrivate::roundness(qreal size)
468 469 {
469 470 return 100*m_diameter/int(size);
470 471 }
471 472
472 473 void QLegendPrivate::handleSeriesAdded(QAbstractSeries *series, Domain *domain)
473 474 {
474 475 Q_UNUSED(domain)
475 476
476 477 QList<LegendMarker*> markers = series->d_ptr->createLegendMarker(q_ptr);
477 478
478 479 foreach(LegendMarker* marker, markers) {
479 480 marker->setFont(m_font);
480 481 marker->setLabelBrush(m_labelBrush);
481 482 m_items->addToGroup(marker);
482 483 m_markers<<marker;
483 484 }
484 485
485 486 QObject::connect(series, SIGNAL(visibleChanged()), this, SLOT(handleSeriesVisibleChanged()));
486 487
487 488 if(series->type() == QAbstractSeries::SeriesTypePie) {
488 489 QPieSeries *pieSeries = static_cast<QPieSeries *>(series);
489 490 QObject::connect(pieSeries, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleUpdatePieSeries()));
490 491 QObject::connect(pieSeries, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleUpdatePieSeries()));
491 492 }
492 493
493 494 q_ptr->layout()->invalidate();
494 495 }
495 496
496 497 void QLegendPrivate::handleSeriesRemoved(QAbstractSeries *series)
497 498 {
498 499 foreach (LegendMarker *marker, m_markers) {
499 500 if (marker->series() == series) {
500 501 delete marker;
501 502 m_markers.removeAll(marker);
502 503 }
503 504 }
504 505
505 506 if(series->type() == QAbstractSeries::SeriesTypePie)
506 507 {
507 508 QPieSeries *pieSeries = static_cast<QPieSeries *>(series);
508 509 QObject::disconnect(pieSeries, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleUpdatePieSeries()));
509 510 QObject::disconnect(pieSeries, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleUpdatePieSeries()));
510 511 }
511 512
512 513 q_ptr->layout()->invalidate();
513 514 }
514 515
515 516 void QLegendPrivate::handleSeriesUpdated(QAbstractSeries *series)
516 517 {
517 518 // TODO: find out which markers are are added or removed. Update them
518 519 // TODO: better implementation
519 520 handleSeriesRemoved(series);
520 521 Domain domain;
521 522 handleSeriesAdded(series, &domain);
522 523 }
523 524
524 525 void QLegendPrivate::handleUpdatePieSeries()
525 526 {
526 527 //TODO: reimplement to be optimal
527 528 QPieSeries* series = qobject_cast<QPieSeries *> (sender());
528 529 Q_ASSERT(series);
529 530 handleSeriesRemoved(series);
530 531 handleSeriesAdded(series, 0);
531 532 }
532 533
533 534 void QLegendPrivate::handleSeriesVisibleChanged()
534 535 {
535 536 QAbstractSeries* series = qobject_cast<QAbstractSeries *> (sender());
536 537
537 538 foreach (LegendMarker* marker, m_markers) {
538 539 if (marker->series() == series) {
539 540 marker->setVisible(!marker->isVisible());
540 541 }
541 542 }
542 543
543 544 q_ptr->layout()->invalidate();
544 545 }
545 546
546 547 #include "moc_qlegend.cpp"
547 548 #include "moc_qlegend_p.cpp"
548 549
549 550 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now