##// END OF EJS Templates
Fixes blinking and minimal false size for legend
Michal Klocek -
r1538:8f0be28e5215
parent child
Show More
@@ -1,164 +1,166
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 "chartlayout_p.h"
22 22 #include "chartpresenter_p.h"
23 23 #include "chartaxis_p.h"
24 #include <QDebug>
24 25
25 26 QTCOMMERCIALCHART_BEGIN_NAMESPACE
26 27
27 28 ChartLayout::ChartLayout(ChartPresenter* presenter):
28 29 m_presenter(presenter),
29 30 m_marginBig(60),
30 31 m_marginSmall(20),
31 32 m_marginTiny(10),
32 33 m_chartMargins(QPointF(m_marginBig,m_marginBig),QPointF(m_marginBig,m_marginBig))
33 34 {
34 35
35 36 }
36 37
37 38 ChartLayout::~ChartLayout()
38 39 {
39 40
40 41 }
41 42
42 43 void ChartLayout::setGeometry(const QRectF& rect)
43 44 {
45
44 46 if (!rect.isValid()) return;
45 47
46 48 QGraphicsLayout::setGeometry(rect);
47 49
48 50 // check title size
49 51
50 52 QSize titleSize = QSize(0,0);
51 53
52 54 if (m_presenter->titleItem()) {
53 55 titleSize= m_presenter->titleItem()->boundingRect().size().toSize();
54 56 }
55 57
56 58 qreal axisHeight = 0;
57 59 qreal axisWidth = 0;
58 60
59 61 // check axis size
60 62
61 63 foreach (ChartAxis* axis,m_presenter->axisItems()){
62 64 if(axis->axisType() == ChartAxis::X_AXIS)
63 65 axisHeight = qMax(axis->minimumHeight(),axisHeight);
64 66 else
65 67 axisWidth = qMax(axis->minimumWidth(),axisWidth);
66 68 }
67 69
68 70 QLegend* legend = m_presenter->legend();
69 71
70 72 qreal titlePadding = m_chartMargins.top()/2;
71 73
72 74 QRectF chartMargins = m_chartMargins;
73 75
74 76 // recalculate legend position
75 77 if (legend != 0 && legend->isVisible() && legend->isAttachedToChart()) {
76 78
77 79 // Reserve some space for legend
78 80 switch (legend->alignment()) {
79 81
80 82 case Qt::AlignTop: {
81 83 QSizeF legendSize = legend->effectiveSizeHint(Qt::PreferredSize,QSizeF(rect.width(),-1));
82 84 int topMargin = 2*m_marginTiny + titleSize.height() + legendSize.height() + m_marginTiny;
83 85 chartMargins = QRect(QPoint(m_chartMargins.left(),topMargin),QPoint(m_chartMargins.right(),m_chartMargins.bottom()));
84 86 m_legendMargins = QRect(QPoint(chartMargins.left(),topMargin - (legendSize.height() + m_marginTiny)),QPoint(chartMargins.right(),rect.height()-topMargin + m_marginTiny));
85 87 titlePadding = m_marginTiny + m_marginTiny;
86 88 break;
87 89 }
88 90 case Qt::AlignBottom: {
89 91 QSizeF legendSize = legend->effectiveSizeHint(Qt::PreferredSize,QSizeF(rect.width(),-1));
90 92 int bottomMargin = m_marginTiny + m_marginSmall + legendSize.height() + m_marginTiny + axisHeight;
91 93 chartMargins = QRect(QPoint(m_chartMargins.left(),m_chartMargins.top()),QPoint(m_chartMargins.right(),bottomMargin));
92 94 m_legendMargins = QRect(QPoint(chartMargins.left(),rect.height()-bottomMargin + m_marginTiny + axisHeight),QPoint(chartMargins.right(),m_marginTiny + m_marginSmall));
93 95 titlePadding = chartMargins.top()/2;
94 96 break;
95 97 }
96 98 case Qt::AlignLeft: {
97 99 QSizeF legendSize = legend->effectiveSizeHint(Qt::PreferredSize,QSizeF(-1,rect.height()));
98 100 int leftPadding = m_marginTiny + m_marginSmall + legendSize.width() + m_marginTiny + axisWidth;
99 101 chartMargins = QRect(QPoint(leftPadding,m_chartMargins.top()),QPoint(m_chartMargins.right(),m_chartMargins.bottom()));
100 102 m_legendMargins = QRect(QPoint(m_marginTiny + m_marginSmall,chartMargins.top()),QPoint(rect.width()-leftPadding + m_marginTiny + axisWidth,chartMargins.bottom()));
101 103 titlePadding = chartMargins.top()/2;
102 104 break;
103 105 }
104 106 case Qt::AlignRight: {
105 107 QSizeF legendSize = legend->effectiveSizeHint(Qt::PreferredSize,QSizeF(-1,rect.height()));
106 108 int rightPadding = m_marginTiny + m_marginSmall + legendSize.width() + m_marginTiny;
107 109 chartMargins = QRect(QPoint(m_chartMargins.left(),m_chartMargins.top()),QPoint(rightPadding,m_chartMargins.bottom()));
108 110 m_legendMargins = QRect(QPoint(rect.width()- rightPadding+ m_marginTiny ,chartMargins.top()),QPoint(m_marginTiny + m_marginSmall,chartMargins.bottom()));
109 111 titlePadding = chartMargins.top()/2;
110 112 break;
111 113 }
112 114 default: {
113 115 break;
114 116 }
115 117 }
116 118
117 119 legend->setGeometry(rect.adjusted(m_legendMargins.left(),m_legendMargins.top(),-m_legendMargins.right(),-m_legendMargins.bottom()));
118 120 }
119 121
120 122 // recalculate title position
121 123 if (m_presenter->titleItem()) {
122 124 QPointF center = rect.center() - m_presenter->titleItem()->boundingRect().center();
123 125 m_presenter->titleItem()->setPos(center.x(),titlePadding);
124 126 }
125 127
126 128 //recalculate background gradient
127 129 if (m_presenter->backgroundItem()) {
128 130 m_presenter->backgroundItem()->setRect(rect.adjusted(m_marginTiny,m_marginTiny, -m_marginTiny, -m_marginTiny));
129 131 }
130 132
131 133 QRectF chartRect = rect.adjusted(chartMargins.left(),chartMargins.top(),-chartMargins.right(),-chartMargins.bottom());
132 134
133 135 if(m_presenter->geometry()!=chartRect && chartRect.isValid()){
134 136 m_presenter->setGeometry(chartRect);
135 137 }else if(chartRect.size().isEmpty()){
136 138 m_presenter->setGeometry(QRect(rect.width()/2,rect.height()/2,1,1));
137 139 }
138 140
139 141 }
140 142
141 143
142 144 QSizeF ChartLayout::sizeHint ( Qt::SizeHint which, const QSizeF & constraint) const
143 145 {
144 146 Q_UNUSED(constraint);
145 147 if(which == Qt::MinimumSize)
146 148 return QSize(2*(m_chartMargins.top()+m_chartMargins.bottom()),2*(m_chartMargins.top() + m_chartMargins.bottom()));
147 149 else
148 150 return QSize(-1,-1);
149 151 }
150 152
151 153 void ChartLayout::setMarginsMinimum(const QRectF& margins)
152 154 {
153 155 if(m_chartMargins != margins){
154 156 m_chartMargins = margins;
155 157 updateGeometry();
156 158 }
157 159 }
158 160
159 161 QRectF ChartLayout::margins() const
160 162 {
161 163 return m_chartMargins;
162 164 }
163 165
164 166 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,372 +1,380
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 #include <QDebug>
25 26
26 27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
27 28
28 29 LegendLayout::LegendLayout(QLegend* legend):
29 30 m_legend(legend)
30 31 {
31 32
32 33 }
33 34
34 35 LegendLayout::~LegendLayout()
35 36 {
36 37
37 38 }
38 39
39 40 void LegendLayout::setOffset(qreal x, qreal y)
40 41 {
41 42 bool scrollHorizontal = true;
42 43 switch(m_legend->alignment()) {
43 44 case Qt::AlignTop:
44 45 case Qt::AlignBottom: {
45 46 scrollHorizontal = true;
46 47 break;
47 48 }
48 49 case Qt::AlignLeft:
49 50 case Qt::AlignRight: {
50 51 scrollHorizontal = false;
51 52 break;
52 53 }
53 54 }
54 55
55 56 // If detached, the scrolling direction is vertical instead of horizontal and vice versa.
56 57 if (!m_legend->isAttachedToChart()) {
57 58 scrollHorizontal = !scrollHorizontal;
58 59 }
59 60
60 61 QRectF boundingRect = geometry();
61 62
62 63 // Limit offset between m_minOffset and m_maxOffset
63 64 if (scrollHorizontal) {
64 65 if(m_width<=boundingRect.width()) return;
65 66
66 67 if (x != m_offsetX) {
67 68 m_offsetX = qBound(m_minOffsetX, x, m_maxOffsetX);
68 69 m_legend->d_ptr->items()->setPos(-m_offsetX,boundingRect.top());
69 70 }
70 71 }
71 72 else {
72 73 if(m_height<=boundingRect.height()) return;
73 74
74 75 if (y != m_offsetY) {
75 76 m_offsetY = qBound(m_minOffsetY, y, m_maxOffsetY);
76 77 m_legend->d_ptr->items()->setPos(boundingRect.left(),-m_offsetY);
77 78 }
78 79 }
79 80 }
80 81
81 82 QPointF LegendLayout::offset() const
82 83 {
83 84 return QPointF(m_offsetX,m_offsetY);
84 85 }
85 86
86 87 void LegendLayout::setGeometry(const QRectF& rect)
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 if (!rect.isValid()) return;
102 103
103 104 m_offsetX=0;
104 105 m_offsetY=0;
105 106
106 107 QSizeF size(0,0);
107 108
108 109 if( m_legend->d_ptr->markers().isEmpty()) return;
109 110
110 111 m_width=0;
111 112 m_height=0;
112 113
113 114 switch(m_legend->alignment()) {
114 115
115 116 case Qt::AlignTop:
116 117
117 118 case Qt::AlignBottom: {
118 119 QPointF point(0,0);
119 120 foreach (LegendMarker* marker, m_legend->d_ptr->markers()) {
120 121 if (marker->isVisible()) {
121 122 marker->setGeometry(QRectF(QPoint(0,0),marker->effectiveSizeHint(Qt::PreferredSize)));
122 123 marker->setPos(point.x(),rect.height()/2 - marker->boundingRect().height()/2);
123 124 const QRectF& rect = marker->boundingRect();
124 125 size = size.expandedTo(rect.size());
125 126 qreal w = rect.width();
126 127 m_width+=w;
127 128 point.setX(point.x() + w);
128 129 }
129 130 }
130 131 if(m_width<rect.width()) {
131 132 m_legend->d_ptr->items()->setPos(rect.width()/2-m_width/2,rect.top());
132 133
133 134 }
134 135 else {
135 136 m_legend->d_ptr->items()->setPos(rect.topLeft());
136 137 }
137 138 m_height=size.height();
138 139 }
139 140 break;
140 141 case Qt::AlignLeft:
141 142 case Qt::AlignRight: {
142 143 QPointF point(0,0);
143 144 foreach (LegendMarker* marker, m_legend->d_ptr->markers()) {
144 145 if (marker->isVisible()) {
145 146 marker->setGeometry(QRectF(QPoint(0,0),marker->effectiveSizeHint(Qt::PreferredSize)));
146 147 marker->setPos(point);
147 148 const QRectF& rect = marker->boundingRect();
148 149 qreal h = rect.height();
149 150 size = size.expandedTo(rect.size());
150 151 m_height+=h;
151 152 point.setY(point.y() + h);
152 153 }
153 154 }
154 155 if(m_height<rect.height()) {
155 156 m_legend->d_ptr->items()->setPos(rect.left(),rect.height()/2-m_height/2);
156 157 }
157 158 else {
158 159 m_legend->d_ptr->items()->setPos(rect.topLeft());
159 160 }
160 161 m_width=size.width();
161 162 }
162 163 break;
163 164 }
164 165
165 166 m_minOffsetX = 0;
166 167 m_minOffsetY = 0;
167 168 m_maxOffsetX = m_width - rect.width();
168 169 m_maxOffsetY = m_height - rect.height();
169 170 }
170 171
171 172 void LegendLayout::setDettachedGeometry(const QRectF& rect)
172 173 {
174 if (!rect.isValid()) return;
175
173 176 // Detached layout is different.
174 177 // In detached mode legend may have multiple rows and columns, so layout calculations
175 178 // differ a log from attached mode.
176 179 // Also the scrolling logic is bit different.
177 180
178 181 m_offsetX=0;
179 182 m_offsetY=0;
180 183
181 184 QSizeF size(0,0);
182 185
183 186 QList<LegendMarker *> markers = m_legend->d_ptr->markers();
184 187
185 188 if(markers.isEmpty()) return;
186 189
187 190 switch (m_legend->alignment()) {
188 191 case Qt::AlignTop: {
189 192 QPointF point = rect.topLeft();
190 193 m_width = 0;
191 194 m_height = 0;
192 195 for (int i=0; i<markers.count(); i++) {
193 196 LegendMarker *marker = markers.at(i);
194 197 if (marker->isVisible()) {
195 198 marker->setGeometry(QRectF(QPoint(0,0),marker->effectiveSizeHint(Qt::PreferredSize)));
196 199 marker->setPos(point.x(),point.y());
197 200 const QRectF& boundingRect = marker->boundingRect();
198 201 qreal w = boundingRect.width();
199 202 qreal h = boundingRect.height();
200 203 m_width = qMax(m_width,w);
201 204 m_height = qMax(m_height,h);
202 205 point.setX(point.x() + w);
203 206 if (point.x() + w > rect.topLeft().x() + rect.width()) {
204 207 // Next item would go off rect.
205 208 point.setX(rect.topLeft().x());
206 209 point.setY(point.y() + h);
207 210 if (i+1 < markers.count()) {
208 211 m_height += h;
209 212 }
210 213 }
211 214 }
212 215 }
213 216 m_legend->d_ptr->items()->setPos(rect.topLeft());
214 217
215 218 m_minOffsetX = 0;
216 219 m_minOffsetY = 0;
217 220 m_maxOffsetX = m_width - rect.width();
218 221 m_maxOffsetY = m_height - rect.height();
219 222 }
220 223 break;
221 224 case Qt::AlignBottom: {
222 225 QPointF point = rect.bottomLeft();
223 226 m_width = 0;
224 227 m_height = 0;
225 228 for (int i=0; i<markers.count(); i++) {
226 229 LegendMarker *marker = markers.at(i);
227 230 if (marker->isVisible()) {
228 231 marker->setGeometry(QRectF(QPoint(0,0),marker->effectiveSizeHint(Qt::PreferredSize)));
229 232 const QRectF& boundingRect = marker->boundingRect();
230 233 qreal w = boundingRect.width();
231 234 qreal h = boundingRect.height();
232 235 m_width = qMax(m_width,w);
233 236 m_height = qMax(m_height,h);
234 237 marker->setPos(point.x(),point.y() - h);
235 238 point.setX(point.x() + w);
236 239 if (point.x() + w > rect.bottomLeft().x() + rect.width()) {
237 240 // Next item would go off rect.
238 241 point.setX(rect.bottomLeft().x());
239 242 point.setY(point.y() - h);
240 243 if (i+1 < markers.count()) {
241 244 m_height += h;
242 245 }
243 246 }
244 247 }
245 248 }
246 249 m_legend->d_ptr->items()->setPos(rect.topLeft());
247 250
248 251 m_minOffsetX = 0;
249 252 m_minOffsetY = qMin(rect.topLeft().y(), rect.topLeft().y() - m_height + rect.height());
250 253 m_maxOffsetX = m_width - rect.width();
251 254 m_maxOffsetY = 0;
252 255 }
253 256 break;
254 257 case Qt::AlignLeft: {
255 258 QPointF point = rect.topLeft();
256 259 m_width = 0;
257 260 m_height = 0;
258 261 qreal maxWidth = 0;
259 262 for (int i=0; i<markers.count(); i++) {
260 263 LegendMarker *marker = markers.at(i);
261 264 if (marker->isVisible()) {
262 265 marker->setGeometry(QRectF(QPoint(0,0),marker->effectiveSizeHint(Qt::PreferredSize)));
263 266 const QRectF& boundingRect = marker->boundingRect();
264 267 qreal w = boundingRect.width();
265 268 qreal h = boundingRect.height();
266 269 m_height = qMax(m_height,h);
267 270 maxWidth = qMax(maxWidth,w);
268 271 marker->setPos(point.x(),point.y());
269 272 point.setY(point.y() + h);
270 273 if (point.y() + h > rect.topLeft().y() + rect.height()) {
271 274 // Next item would go off rect.
272 275 point.setX(point.x() + maxWidth);
273 276 point.setY(rect.topLeft().y());
274 277 if (i+1 < markers.count()) {
275 278 m_width += maxWidth;
276 279 maxWidth = 0;
277 280 }
278 281 }
279 282 }
280 283 }
281 284 m_width += maxWidth;
282 285 m_legend->d_ptr->items()->setPos(rect.topLeft());
283 286
284 287 m_minOffsetX = 0;
285 288 m_minOffsetY = 0;
286 289 m_maxOffsetX = m_width - rect.width();
287 290 m_maxOffsetY = m_height - rect.height();
288 291 }
289 292 break;
290 293 case Qt::AlignRight: {
291 294 QPointF point = rect.topRight();
292 295 m_width = 0;
293 296 m_height = 0;
294 297 qreal maxWidth = 0;
295 298 for (int i=0; i<markers.count(); i++) {
296 299 LegendMarker *marker = markers.at(i);
297 300 if (marker->isVisible()) {
298 301 marker->setGeometry(QRectF(QPoint(0,0),marker->effectiveSizeHint(Qt::PreferredSize)));
299 302 const QRectF& boundingRect = marker->boundingRect();
300 303 qreal w = boundingRect.width();
301 304 qreal h = boundingRect.height();
302 305 m_height = qMax(m_height,h);
303 306 maxWidth = qMax(maxWidth,w);
304 307 marker->setPos(point.x() - w,point.y());
305 308 point.setY(point.y() + h);
306 309 if (point.y() + h > rect.topLeft().y() + rect.height()) {
307 310 // Next item would go off rect.
308 311 point.setX(point.x() - maxWidth);
309 312 point.setY(rect.topLeft().y());
310 313 if (i+1 < markers.count()) {
311 314 m_width += maxWidth;
312 315 maxWidth = 0;
313 316 }
314 317 }
315 318 }
316 319 }
317 320 m_width += maxWidth;
318 321 m_legend->d_ptr->items()->setPos(rect.topLeft());
319 322
320 323 m_minOffsetX = qMin(rect.topLeft().x(), rect.topLeft().x() - m_width + rect.width());
321 324 m_minOffsetY = 0;
322 325 m_maxOffsetX = 0;
323 326 m_maxOffsetY = m_height - rect.height();
324 327 }
325 328 break;
326 329 default:
327 330 break;
328 331 }
329 332
330 333 }
331 334
332 335 QSizeF LegendLayout::sizeHint ( Qt::SizeHint which, const QSizeF & constraint) const
333 336 {
334 337 QSizeF size(0, 0);
335 338 qreal left, top, right, bottom;
336 339 getContentsMargins(&left, &top, &right, &bottom);
337 340
341 if(which!=Qt::PreferredSize) return QSizeF(-1,-1);
342
338 343 if(constraint.isValid()) {
339 344 foreach(LegendMarker* marker, m_legend->d_ptr->markers()) {
340 345 size = size.expandedTo(marker->effectiveSizeHint(which));
341 346 }
342 347 size = size.boundedTo(constraint);
343 348 }
344 349 else if (constraint.width() >= 0) {
345 350 qreal width = 0;
346 351 qreal height = 0;
347 352 foreach(LegendMarker* marker, m_legend->d_ptr->markers()) {
348 353 width+=marker->effectiveSizeHint(which).width();
349 354 height=qMax(height,marker->effectiveSizeHint(which).height());
350 355 }
351 356
352 357 size = QSizeF(qMin(constraint.width(),width), height);
353 358 }
354 359 else if (constraint.height() >= 0) {
355 360 qreal width = 0;
356 361 qreal height = 0;
357 362 foreach(LegendMarker* marker, m_legend->d_ptr->markers()) {
358 363 width=qMax(width,marker->effectiveSizeHint(which).width());
359 364 height+=height,marker->effectiveSizeHint(which).height();
360 365 }
361 366 size = QSizeF(width,qMin(constraint.height(),height));
362 367 }
363 368 else {
364 369 foreach(LegendMarker* marker, m_legend->d_ptr->markers()) {
365 370 size = size.expandedTo(marker->effectiveSizeHint(which));
366 371 }
367 372 }
368 373 size += QSize(left + right, top + bottom);
374
369 375 return size;
376
377
370 378 }
371 379
372 380 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,550 +1,551
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 283 layout()->invalidate();
284 284 emit fontChanged(font);
285 285 }
286 286 }
287 287
288 288 QFont QLegend::font() const
289 289 {
290 290 return d_ptr->m_font;
291 291 }
292 292
293 293 void QLegend::setBorderColor(QColor color)
294 294 {
295 295 QPen p = d_ptr->m_pen;
296 296 if (p.color() != color) {
297 297 p.setColor(color);
298 298 setPen(p);
299 299 emit borderColorChanged(color);
300 300 }
301 301 }
302 302
303 303 QColor QLegend::borderColor()
304 304 {
305 305 return d_ptr->m_pen.color();
306 306 }
307 307
308 308 /*!
309 309 Set brush used to draw labels to \a brush.
310 310 */
311 311 void QLegend::setLabelBrush(const QBrush &brush)
312 312 {
313 313 if (d_ptr->m_labelBrush != brush) {
314 314
315 315 d_ptr->m_labelBrush = brush;
316 316
317 317 foreach (LegendMarker *marker, d_ptr->markers()) {
318 318 marker->setLabelBrush(d_ptr->m_labelBrush);
319 319 }
320 320 emit labelBrushChanged(brush);
321 321 }
322 322 }
323 323
324 324 /*!
325 325 Brush used to draw labels.
326 326 */
327 327 QBrush QLegend::labelBrush() const
328 328 {
329 329 return d_ptr->m_labelBrush;
330 330 }
331 331
332 332 void QLegend::setLabelColor(QColor color)
333 333 {
334 334 QBrush b = d_ptr->m_labelBrush;
335 335 if (b.style() != Qt::SolidPattern || b.color() != color) {
336 336 b.setStyle(Qt::SolidPattern);
337 337 b.setColor(color);
338 338 setLabelBrush(b);
339 339 emit labelColorChanged(color);
340 340 }
341 341 }
342 342
343 343 QColor QLegend::labelColor() const
344 344 {
345 345 return d_ptr->m_labelBrush.color();
346 346 }
347 347
348 348
349 349 void QLegend::setAlignment(Qt::Alignment alignment)
350 350 {
351 351 if(d_ptr->m_alignment!=alignment) {
352 352 d_ptr->m_alignment = alignment;
353 353 updateGeometry();
354 354 if(isAttachedToChart()){
355 355 d_ptr->m_presenter->layout()->invalidate();
356 356 }else{
357 357 layout()->invalidate();
358 358 }
359 359 }
360 360 }
361 361
362 362 Qt::Alignment QLegend::alignment() const
363 363 {
364 364 return d_ptr->m_alignment;
365 365 }
366 366
367 367 /*!
368 368 Detaches the legend from chart. Chart won't change layout of the legend.
369 369 */
370 370 void QLegend::detachFromChart()
371 371 {
372 372 d_ptr->m_attachedToChart = false;
373 373 d_ptr->m_layout->invalidate();
374 374 setParent(0);
375 375
376 376 }
377 377
378 378 /*!
379 379 Attaches the legend to chart. Chart may change layout of the legend.
380 380 */
381 381 void QLegend::attachToChart()
382 382 {
383 383 d_ptr->m_attachedToChart = true;
384 384 d_ptr->m_layout->invalidate();
385 385 setParent(d_ptr->m_chart);
386 386 }
387 387
388 388 /*!
389 389 Returns true, if legend is attached to chart.
390 390 */
391 391 bool QLegend::isAttachedToChart()
392 392 {
393 393 return d_ptr->m_attachedToChart;
394 394 }
395 395
396 396 /*!
397 397 Sets the visibility of legend background to \a visible
398 398 */
399 399 void QLegend::setBackgroundVisible(bool visible)
400 400 {
401 401 if(d_ptr->m_backgroundVisible != visible) {
402 402 d_ptr->m_backgroundVisible = visible;
403 403 update();
404 404 emit backgroundVisibleChanged(visible);
405 405 }
406 406 }
407 407
408 408 /*!
409 409 Returns the visibility of legend background
410 410 */
411 411 bool QLegend::isBackgroundVisible() const
412 412 {
413 413 return d_ptr->m_backgroundVisible;
414 414 }
415 415
416 416 /*!
417 417 \internal \a event see QGraphicsWidget for details
418 418 */
419 419 void QLegend::hideEvent(QHideEvent *event)
420 420 {
421 421 QGraphicsWidget::hideEvent(event);
422 422 d_ptr->m_presenter->layout()->invalidate();
423 423 }
424 424
425 425 /*!
426 426 \internal \a event see QGraphicsWidget for details
427 427 */
428 428 void QLegend::showEvent(QShowEvent *event)
429 429 {
430 430 QGraphicsWidget::showEvent(event);
431 431 d_ptr->m_presenter->layout()->invalidate();
432 432 }
433 433
434 434 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
435 435
436 436 QLegendPrivate::QLegendPrivate(ChartPresenter* presenter, QChart *chart, QLegend *q):
437 437 q_ptr(q),
438 438 m_presenter(presenter),
439 439 m_layout(new LegendLayout(q)),
440 440 m_chart(chart),
441 441 m_items(new QGraphicsItemGroup(q)),
442 442 m_alignment(Qt::AlignTop),
443 443 m_brush(QBrush()),
444 444 m_pen(QPen()),
445 445 m_labelBrush(QBrush()),
446 446 m_diameter(5),
447 447 m_attachedToChart(true),
448 448 m_backgroundVisible(false)
449 449 {
450 450
451 451 }
452 452
453 453 QLegendPrivate::~QLegendPrivate()
454 454 {
455 455
456 456 }
457 457
458 458 void QLegendPrivate::setOffset(qreal x, qreal y)
459 459 {
460 460 m_layout->setOffset(x,y);
461 461 }
462 462
463 463 QPointF QLegendPrivate::offset() const
464 464 {
465 465 return m_layout->offset();
466 466 }
467 467
468 468 int QLegendPrivate::roundness(qreal size)
469 469 {
470 470 return 100*m_diameter/int(size);
471 471 }
472 472
473 473 void QLegendPrivate::handleSeriesAdded(QAbstractSeries *series, Domain *domain)
474 474 {
475 475 Q_UNUSED(domain)
476 476
477 477 QList<LegendMarker*> markers = series->d_ptr->createLegendMarker(q_ptr);
478 478
479 479 foreach(LegendMarker* marker, markers) {
480 480 marker->setFont(m_font);
481 481 marker->setLabelBrush(m_labelBrush);
482 482 m_items->addToGroup(marker);
483 483 m_markers<<marker;
484 484 }
485 485
486 486 QObject::connect(series, SIGNAL(visibleChanged()), this, SLOT(handleSeriesVisibleChanged()));
487 487
488 488 if(series->type() == QAbstractSeries::SeriesTypePie) {
489 489 QPieSeries *pieSeries = static_cast<QPieSeries *>(series);
490 490 QObject::connect(pieSeries, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleUpdatePieSeries()));
491 491 QObject::connect(pieSeries, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleUpdatePieSeries()));
492 492 }
493 493
494 494 q_ptr->layout()->invalidate();
495 q_ptr->layout()->activate();
495 496 }
496 497
497 498 void QLegendPrivate::handleSeriesRemoved(QAbstractSeries *series)
498 499 {
499 500 foreach (LegendMarker *marker, m_markers) {
500 501 if (marker->series() == series) {
501 502 delete marker;
502 503 m_markers.removeAll(marker);
503 504 }
504 505 }
505 506
506 507 if(series->type() == QAbstractSeries::SeriesTypePie)
507 508 {
508 509 QPieSeries *pieSeries = static_cast<QPieSeries *>(series);
509 510 QObject::disconnect(pieSeries, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleUpdatePieSeries()));
510 511 QObject::disconnect(pieSeries, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleUpdatePieSeries()));
511 512 }
512 513
513 514 q_ptr->layout()->invalidate();
514 515 }
515 516
516 517 void QLegendPrivate::handleSeriesUpdated(QAbstractSeries *series)
517 518 {
518 519 // TODO: find out which markers are are added or removed. Update them
519 520 // TODO: better implementation
520 521 handleSeriesRemoved(series);
521 522 Domain domain;
522 523 handleSeriesAdded(series, &domain);
523 524 }
524 525
525 526 void QLegendPrivate::handleUpdatePieSeries()
526 527 {
527 528 //TODO: reimplement to be optimal
528 529 QPieSeries* series = qobject_cast<QPieSeries *> (sender());
529 530 Q_ASSERT(series);
530 531 handleSeriesRemoved(series);
531 532 handleSeriesAdded(series, 0);
532 533 }
533 534
534 535 void QLegendPrivate::handleSeriesVisibleChanged()
535 536 {
536 537 QAbstractSeries* series = qobject_cast<QAbstractSeries *> (sender());
537 538
538 539 foreach (LegendMarker* marker, m_markers) {
539 540 if (marker->series() == series) {
540 541 marker->setVisible(!marker->isVisible());
541 542 }
542 543 }
543 544
544 545 q_ptr->layout()->invalidate();
545 546 }
546 547
547 548 #include "moc_qlegend.cpp"
548 549 #include "moc_qlegend_p.cpp"
549 550
550 551 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now