##// END OF EJS Templates
Removed hack from QCustomPlot, moved to QCustomPlotVect class.
jeandet -
r7:6e23aedd1ca8 default
parent child
Show More
This diff has been collapsed as it changes many lines, (619 lines changed) Show them Hide them
@@ -0,0 +1,619
1 #include "qcustomplotvect.h"
2 #include <QVector>
3 #include <QVectorIterator>
4 QCustomPlotVect::QCustomPlotVect(QWidget *parent)
5 :QCustomPlot(parent)
6 {
7
8 }
9
10 QCustomPlotVect::~QCustomPlotVect()
11 {
12
13 }
14
15 QCPGraphVect *QCustomPlotVect::addGraph(QCPAxis *keyAxis, QCPAxis *valueAxis)
16 {
17 if (!keyAxis) keyAxis = xAxis;
18 if (!valueAxis) valueAxis = yAxis;
19 if (!keyAxis || !valueAxis)
20 {
21 qDebug() << Q_FUNC_INFO << "can't use default QCustomPlot xAxis or yAxis, because at least one is invalid (has been deleted)";
22 return 0;
23 }
24 if (keyAxis->parentPlot() != this || valueAxis->parentPlot() != this)
25 {
26 qDebug() << Q_FUNC_INFO << "passed keyAxis or valueAxis doesn't have this QCustomPlot as parent";
27 return 0;
28 }
29
30 QCPGraphVect *newGraph = new QCPGraphVect(keyAxis, valueAxis);
31 if (addPlottable(newGraph))
32 {
33 newGraph->setName(QLatin1String("Graph ")+QString::number(mGraphs.size()));
34 return newGraph;
35 } else
36 {
37 delete newGraph;
38 return 0;
39 }
40 }
41
42
43 QCPGraphVect::QCPGraphVect(QCPAxis *keyAxis, QCPAxis *valueAxis)
44 :QCPGraph(keyAxis,valueAxis)
45 {
46 mData = new QVector<QCPData>();
47 }
48
49 QCPGraphVect::~QCPGraphVect()
50 {
51
52 }
53
54 void QCPGraphVect::setData(QVector<QCPData> *data)
55 {
56 if(data!=mData)
57 {
58 delete this->mData;
59 this->mData = data;
60 }
61 }
62
63 void QCPGraphVect::draw(QCPPainter *painter)
64 {
65 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
66 int test = mKeyAxis.data()->range().size();
67 test = mData->count();
68 if (mKeyAxis.data()->range().size() <= 0 || mData->isEmpty()) return;
69 if (mLineStyle == lsNone && mScatterStyle.isNone()) return;
70
71 // allocate line and (if necessary) point vectors:
72 QVector<QPointF> *lineData = new QVector<QPointF>;
73 QVector<QCPData> *scatterData = 0;
74 if (!mScatterStyle.isNone())
75 scatterData = new QVector<QCPData>;
76
77 // fill vectors with data appropriate to plot style:
78 getPlotData(lineData, scatterData);
79
80 // check data validity if flag set:
81 #ifdef QCUSTOMPLOT_CHECK_DATA
82 QCPDataMap::const_iterator it;
83 for (it = mData->constBegin(); it != mData->constEnd(); ++it)
84 {
85 if (QCP::isInvalidData(it.value().key, it.value().value) ||
86 QCP::isInvalidData(it.value().keyErrorPlus, it.value().keyErrorMinus) ||
87 QCP::isInvalidData(it.value().valueErrorPlus, it.value().valueErrorPlus))
88 qDebug() << Q_FUNC_INFO << "Data point at" << it.key() << "invalid." << "Plottable name:" << name();
89 }
90 #endif
91
92 // draw fill of graph:
93 drawFill(painter, lineData);
94
95 // draw line:
96 if (mLineStyle == lsImpulse)
97 drawImpulsePlot(painter, lineData);
98 else if (mLineStyle != lsNone)
99 drawLinePlot(painter, lineData); // also step plots can be drawn as a line plot
100
101 // draw scatters:
102 if (scatterData)
103 drawScatterPlot(painter, scatterData);
104
105 // free allocated line and point vectors:
106 delete lineData;
107 if (scatterData)
108 delete scatterData;
109 }
110
111 void QCPGraphVect::getPlotData(QVector<QPointF> *lineData, QVector<QCPData> *scatterData) const
112 {
113 switch(mLineStyle)
114 {
115 case lsNone: getScatterPlotData(scatterData); break;
116 case lsLine: getLinePlotData(lineData, scatterData); break;
117 case lsStepLeft: getStepLeftPlotData(lineData, scatterData); break;
118 case lsStepRight: getStepRightPlotData(lineData, scatterData); break;
119 case lsStepCenter: getStepCenterPlotData(lineData, scatterData); break;
120 case lsImpulse: getImpulsePlotData(lineData, scatterData); break;
121 }
122 }
123
124 void QCPGraphVect::getLinePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const
125 {
126 QCPAxis *keyAxis = mKeyAxis.data();
127 QCPAxis *valueAxis = mValueAxis.data();
128 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
129 if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as linePixelData"; return; }
130
131 QVector<QCPData> lineData;
132 getPreparedData(&lineData, scatterData);
133 linePixelData->reserve(lineData.size()+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill
134 linePixelData->resize(lineData.size());
135
136 // transform lineData points to pixels:
137 if (keyAxis->orientation() == Qt::Vertical)
138 {
139 for (int i=0; i<lineData.size(); ++i)
140 {
141 (*linePixelData)[i].setX(valueAxis->coordToPixel(lineData.at(i).value));
142 (*linePixelData)[i].setY(keyAxis->coordToPixel(lineData.at(i).key));
143 }
144 } else // key axis is horizontal
145 {
146 for (int i=0; i<lineData.size(); ++i)
147 {
148 (*linePixelData)[i].setX(keyAxis->coordToPixel(lineData.at(i).key));
149 (*linePixelData)[i].setY(valueAxis->coordToPixel(lineData.at(i).value));
150 }
151 }
152 }
153
154 QCPRange QCPGraphVect::getKeyRange(bool &foundRange, QCPAbstractPlottable::SignDomain inSignDomain, bool includeErrors) const
155 {
156
157 QCPRange range;
158 bool haveLower = false;
159 bool haveUpper = false;
160
161 double current, currentErrorMinus, currentErrorPlus;
162
163 if (inSignDomain == sdBoth) // range may be anywhere
164 {
165 QVector<QCPData>::const_iterator it = mData->constBegin();
166 while (it != mData->constEnd())
167 {
168 current = (*it).key;
169 currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0);
170 currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0);
171 if (current-currentErrorMinus < range.lower || !haveLower)
172 {
173 range.lower = current-currentErrorMinus;
174 haveLower = true;
175 }
176 if (current+currentErrorPlus > range.upper || !haveUpper)
177 {
178 range.upper = current+currentErrorPlus;
179 haveUpper = true;
180 }
181 ++it;
182 }
183 } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain
184 {
185 QVector<QCPData>::const_iterator it = mData->constBegin();
186 while (it != mData->constEnd())
187 {
188 current = (*it).key;
189 currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0);
190 currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0);
191 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0)
192 {
193 range.lower = current-currentErrorMinus;
194 haveLower = true;
195 }
196 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0)
197 {
198 range.upper = current+currentErrorPlus;
199 haveUpper = true;
200 }
201 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point.
202 {
203 if ((current < range.lower || !haveLower) && current < 0)
204 {
205 range.lower = current;
206 haveLower = true;
207 }
208 if ((current > range.upper || !haveUpper) && current < 0)
209 {
210 range.upper = current;
211 haveUpper = true;
212 }
213 }
214 ++it;
215 }
216 } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain
217 {
218 QVector<QCPData>::const_iterator it = mData->constBegin();
219 while (it != mData->constEnd())
220 {
221 current = (*it).key;
222 currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0);
223 currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0);
224 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0)
225 {
226 range.lower = current-currentErrorMinus;
227 haveLower = true;
228 }
229 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0)
230 {
231 range.upper = current+currentErrorPlus;
232 haveUpper = true;
233 }
234 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point.
235 {
236 if ((current < range.lower || !haveLower) && current > 0)
237 {
238 range.lower = current;
239 haveLower = true;
240 }
241 if ((current > range.upper || !haveUpper) && current > 0)
242 {
243 range.upper = current;
244 haveUpper = true;
245 }
246 }
247 ++it;
248 }
249 }
250
251 foundRange = haveLower && haveUpper;
252 return range;
253 }
254
255 QCPRange QCPGraphVect::getValueRange(bool &foundRange, QCPAbstractPlottable::SignDomain inSignDomain, bool includeErrors) const
256 {
257 QCPRange range;
258 bool haveLower = false;
259 bool haveUpper = false;
260
261 double current, currentErrorMinus, currentErrorPlus;
262
263 if (inSignDomain == sdBoth) // range may be anywhere
264 {
265 QVector<QCPData>::const_iterator it = mData->constBegin();
266 while (it != mData->constEnd())
267 {
268 current = (*it).value;
269 currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0);
270 currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0);
271 if (current-currentErrorMinus < range.lower || !haveLower)
272 {
273 range.lower = current-currentErrorMinus;
274 haveLower = true;
275 }
276 if (current+currentErrorPlus > range.upper || !haveUpper)
277 {
278 range.upper = current+currentErrorPlus;
279 haveUpper = true;
280 }
281 ++it;
282 }
283 } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain
284 {
285 QVector<QCPData>::const_iterator it = mData->constBegin();
286 while (it != mData->constEnd())
287 {
288 current = (*it).value;
289 currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0);
290 currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0);
291 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0)
292 {
293 range.lower = current-currentErrorMinus;
294 haveLower = true;
295 }
296 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0)
297 {
298 range.upper = current+currentErrorPlus;
299 haveUpper = true;
300 }
301 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point.
302 {
303 if ((current < range.lower || !haveLower) && current < 0)
304 {
305 range.lower = current;
306 haveLower = true;
307 }
308 if ((current > range.upper || !haveUpper) && current < 0)
309 {
310 range.upper = current;
311 haveUpper = true;
312 }
313 }
314 ++it;
315 }
316 } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain
317 {
318 QVector<QCPData>::const_iterator it = mData->constBegin();
319 while (it != mData->constEnd())
320 {
321 current = (*it).value;
322 currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0);
323 currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0);
324 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0)
325 {
326 range.lower = current-currentErrorMinus;
327 haveLower = true;
328 }
329 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0)
330 {
331 range.upper = current+currentErrorPlus;
332 haveUpper = true;
333 }
334 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point.
335 {
336 if ((current < range.lower || !haveLower) && current > 0)
337 {
338 range.lower = current;
339 haveLower = true;
340 }
341 if ((current > range.upper || !haveUpper) && current > 0)
342 {
343 range.upper = current;
344 haveUpper = true;
345 }
346 }
347 ++it;
348 }
349 }
350
351 foundRange = haveLower && haveUpper;
352 return range;
353 }
354
355 void QCPGraphVect::getPreparedData(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const
356 {
357 QCPAxis *keyAxis = mKeyAxis.data();
358 QCPAxis *valueAxis = mValueAxis.data();
359 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
360 // get visible data range:
361 QVector<QCPData>::const_iterator lower, upper; // note that upper is the actual upper point, and not 1 step after the upper point
362 getVisibleDataBounds(lower, upper);
363 if (lower == mData->constEnd() || upper == mData->constEnd())
364 return;
365
366 // count points in visible range, taking into account that we only need to count to the limit maxCount if using adaptive sampling:
367 int maxCount = std::numeric_limits<int>::max();
368 if (mAdaptiveSampling)
369 {
370 int keyPixelSpan = qAbs(keyAxis->coordToPixel((*lower).key)-keyAxis->coordToPixel((*upper).key));
371 maxCount = 2*keyPixelSpan+2;
372 }
373 int dataCount = countDataInBounds(lower, upper, maxCount);
374
375 if (mAdaptiveSampling && dataCount >= maxCount) // use adaptive sampling only if there are at least two points per pixel on average
376 {
377 if (lineData)
378 {
379 QVector<QCPData>::const_iterator it = lower;
380 QVector<QCPData>::const_iterator upperEnd = upper+1;
381 double minValue = (*it).value;
382 double maxValue = (*it).value;
383 QVector<QCPData>::const_iterator currentIntervalFirstPoint = it;
384 int reversedFactor = keyAxis->rangeReversed() != (keyAxis->orientation()==Qt::Vertical) ? -1 : 1; // is used to calculate keyEpsilon pixel into the correct direction
385 int reversedRound = keyAxis->rangeReversed() != (keyAxis->orientation()==Qt::Vertical) ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey
386 double currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*lower).key)+reversedRound));
387 double lastIntervalEndKey = currentIntervalStartKey;
388 double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates
389 bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes)
390 int intervalDataCount = 1;
391 ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect
392 while (it != upperEnd)
393 {
394 if ((*it).key < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this cluster if necessary
395 {
396 if ((*it).value < minValue)
397 minValue = (*it).value;
398 else if ((*it).value > maxValue)
399 maxValue = (*it).value;
400 ++intervalDataCount;
401 } else // new pixel interval started
402 {
403 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster
404 {
405 if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point is further away, so first point of this cluster must be at a real data point
406 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.2, (*currentIntervalFirstPoint).value));
407 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue));
408 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue));
409 if ((*it).key > currentIntervalStartKey+keyEpsilon*2) // new pixel started further away from previous cluster, so make sure the last point of the cluster is at a real data point
410 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.8, (*(it-1)).value));
411 } else
412 lineData->append(QCPData((*currentIntervalFirstPoint).key, (*currentIntervalFirstPoint).value));
413 lastIntervalEndKey = (*(it-1)).key;
414 minValue = (*it).value;
415 maxValue = (*it).value;
416 currentIntervalFirstPoint = it;
417 currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*it).key)+reversedRound));
418 if (keyEpsilonVariable)
419 keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor));
420 intervalDataCount = 1;
421 }
422 ++it;
423 }
424 // handle last interval:
425 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster
426 {
427 if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point wasn't a cluster, so first point of this cluster must be at a real data point
428 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.2, (*currentIntervalFirstPoint).value));
429 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue));
430 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue));
431 } else
432 lineData->append(QCPData((*currentIntervalFirstPoint).key, (*currentIntervalFirstPoint).value));
433 }
434
435 if (scatterData)
436 {
437 double valueMaxRange = valueAxis->range().upper;
438 double valueMinRange = valueAxis->range().lower;
439 QVector<QCPData>::const_iterator it = lower;
440 QVector<QCPData>::const_iterator upperEnd = upper+1;
441 double minValue = (*it).value;
442 double maxValue = (*it).value;
443 QVector<QCPData>::const_iterator minValueIt = it;
444 QVector<QCPData>::const_iterator maxValueIt = it;
445 QVector<QCPData>::const_iterator currentIntervalStart = it;
446 int reversedFactor = keyAxis->rangeReversed() ? -1 : 1; // is used to calculate keyEpsilon pixel into the correct direction
447 int reversedRound = keyAxis->rangeReversed() ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey
448 double currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*lower).key)+reversedRound));
449 double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates
450 bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes)
451 int intervalDataCount = 1;
452 ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect
453 while (it != upperEnd)
454 {
455 if ((*it).key < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this pixel if necessary
456 {
457 if ((*it).value < minValue && (*it).value > valueMinRange && (*it).value < valueMaxRange)
458 {
459 minValue = (*it).value;
460 minValueIt = it;
461 } else if ((*it).value > maxValue && (*it).value > valueMinRange && (*it).value < valueMaxRange)
462 {
463 maxValue = (*it).value;
464 maxValueIt = it;
465 }
466 ++intervalDataCount;
467 } else // new pixel started
468 {
469 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them
470 {
471 // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot):
472 double valuePixelSpan = qAbs(valueAxis->coordToPixel(minValue)-valueAxis->coordToPixel(maxValue));
473 int dataModulo = qMax(1, qRound(intervalDataCount/(valuePixelSpan/4.0))); // approximately every 4 value pixels one data point on average
474 QVector<QCPData>::const_iterator intervalIt = currentIntervalStart;
475 int c = 0;
476 while (intervalIt != it)
477 {
478 if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && (*intervalIt).value > valueMinRange && (*intervalIt).value < valueMaxRange)
479 scatterData->append((*intervalIt));
480 ++c;
481 ++intervalIt;
482 }
483 } else if ((*currentIntervalStart).value > valueMinRange && (*currentIntervalStart).value < valueMaxRange)
484 scatterData->append((*currentIntervalStart));
485 minValue = (*it).value;
486 maxValue = (*it).value;
487 currentIntervalStart = it;
488 currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*it).key)+reversedRound));
489 if (keyEpsilonVariable)
490 keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor));
491 intervalDataCount = 1;
492 }
493 ++it;
494 }
495 // handle last interval:
496 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them
497 {
498 // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot):
499 double valuePixelSpan = qAbs(valueAxis->coordToPixel(minValue)-valueAxis->coordToPixel(maxValue));
500 int dataModulo = qMax(1, qRound(intervalDataCount/(valuePixelSpan/4.0))); // approximately every 4 value pixels one data point on average
501 QVector<QCPData>::const_iterator intervalIt = currentIntervalStart;
502 int c = 0;
503 while (intervalIt != it)
504 {
505 if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && (*intervalIt).value > valueMinRange && (*intervalIt).value < valueMaxRange)
506 scatterData->append((*intervalIt));
507 ++c;
508 ++intervalIt;
509 }
510 } else if ((*currentIntervalStart).value > valueMinRange && (*currentIntervalStart).value < valueMaxRange)
511 scatterData->append(*currentIntervalStart);
512 }
513 } else // don't use adaptive sampling algorithm, transfer points one-to-one from the map into the output parameters
514 {
515 QVector<QCPData> *dataVector = 0;
516 if (lineData)
517 {
518 dataVector = lineData;
519 }
520 else if (scatterData)
521 dataVector = scatterData;
522 if (dataVector)
523 {
524 QVector<QCPData>::const_iterator it = lower;
525 QVector<QCPData>::const_iterator upperEnd = upper+1;
526 dataVector->reserve(dataCount+2); // +2 for possible fill end points
527 while (it != upperEnd)
528 {
529 dataVector->append(*it);
530 ++it;
531 }
532 }
533 if (lineData && scatterData)
534 *scatterData = *dataVector;
535 }
536 }
537
538 QVector<QCPData>::const_iterator __lowerBoundDico_vect(QVector<QCPData>* vector,double key)
539 {
540 int DX=vector->size()/2;
541 int pos=DX;
542 // double test=(*vector)[vector->length()-1].key;
543 if(key>((*vector)[vector->length()-1].key))
544 return vector->constEnd();
545 if(key<((*vector)[0].key))
546 return vector->constBegin();
547 while (DX>1)
548 {
549 DX=DX/2;
550 if((*vector)[pos].key > key)
551 {
552 pos-=DX;
553 }
554 else
555 {
556 pos+=DX;
557 }
558 }
559 if((*vector)[pos].key >= key)
560 return vector->constBegin()+pos;
561 return vector->constBegin()+pos+1;
562 }
563
564
565 QVector<QCPData>::const_iterator __upperBoundDico_vect(QVector<QCPData>* vector,double key)
566 {
567 int DX=vector->size()/2;
568 int pos=DX;
569 if(key>((*vector)[vector->length()-1].key))
570 return vector->constEnd();
571 if(key<((*vector)[0].key))
572 return vector->constBegin();
573 while (DX>1)
574 {
575 DX=DX/2;
576 if((*vector)[pos].key > key)
577 {
578 pos-=DX;
579 }
580 else
581 {
582 pos+=DX;
583 }
584 }
585 return vector->constBegin()+pos+1;
586 }
587
588
589 void QCPGraphVect::getVisibleDataBounds(QVector<QCPData>::const_iterator &lower, QVector<QCPData>::const_iterator &upper) const
590 {
591 if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
592 if (mData->isEmpty())
593 {
594 lower = mData->constEnd();
595 upper = mData->constEnd();
596 return;
597 }
598 QVector<QCPData>::const_iterator lbound = __lowerBoundDico_vect(mData,mKeyAxis.data()->range().lower);
599 QVector<QCPData>::const_iterator ubound = __upperBoundDico_vect(mData,mKeyAxis.data()->range().upper);
600 bool lowoutlier = lbound != mData->constBegin(); // indicates whether there exist points below axis range
601 bool highoutlier = ubound != mData->constEnd(); // indicates whether there exist points above axis range
602
603 lower = (lowoutlier ? lbound-1 : lbound); // data point range that will be actually drawn
604 upper = (highoutlier ? ubound : ubound-1); // data point range that will be actually drawn
605 }
606
607 int QCPGraphVect::countDataInBounds(const QVector<QCPData>::const_iterator &lower, const QVector<QCPData>::const_iterator &upper, int maxCount) const
608 {
609 if (upper == mData->constEnd() && lower == mData->constEnd())
610 return 0;
611 QVector<QCPData>::const_iterator it = lower;
612 int count = 1;
613 while (it != upper && count < maxCount)
614 {
615 ++it;
616 ++count;
617 }
618 return count;
619 }
@@ -0,0 +1,38
1 #ifndef QCUSTOMPLOTVECT_H
2 #define QCUSTOMPLOTVECT_H
3
4 #include <QWidget>
5 #include <qcustomplot.h>
6
7 class QCPGraphVect : public QCPGraph
8 {
9 Q_OBJECT
10 public:
11 explicit QCPGraphVect(QCPAxis *keyAxis, QCPAxis *valueAxis);
12 ~QCPGraphVect();
13 QVector<QCPData> *data() const { return mData; }
14 void setData(QVector<QCPData> *data);
15 protected:
16 QVector<QCPData>* mData;
17 virtual void draw(QCPPainter *painter);
18 virtual QCPRange getKeyRange(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const; // overloads base class interface
19 virtual QCPRange getValueRange(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const;
20 void getPreparedData(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const;
21 void getVisibleDataBounds(QVector<QCPData>::const_iterator &lower, QVector<QCPData>::const_iterator &upper) const;
22 int countDataInBounds(const QVector<QCPData>::const_iterator &lower, const QVector<QCPData>::const_iterator &upper, int maxCount) const;
23
24 void getPlotData(QVector<QPointF> *lineData, QVector<QCPData> *scatterData) const;
25 void getLinePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const;
26 };
27
28 class QCustomPlotVect : public QCustomPlot
29 {
30 Q_OBJECT
31 public:
32 QCustomPlotVect(QWidget *parent = 0);
33 ~QCustomPlotVect();
34 QCPGraphVect *addGraph(QCPAxis *keyAxis=0, QCPAxis *valueAxis=0);
35 protected:
36 };
37
38 #endif // QCUSTOMPLOTVECT_H
@@ -30,9 +30,7 SOURCES += src/main.cpp\
30 30 src/mainwindow.cpp \
31 31 src/SocExplorerPlot.cpp \
32 32 src/QCustomPlot/qcustomplot.cpp \
33 src/folderview.cpp \
34 33 src/toolbarcontainer.cpp \
35 src/folderlistwidget.cpp \
36 34 src/Core/abstractfileloader.cpp \
37 35 src/Core/filedownloader.cpp \
38 36 src/Core/filedownloadertask.cpp \
@@ -52,14 +50,13 SOURCES += src/main.cpp\
52 50 src/Core/Widgets/PyWdgt/pythonqtscriptingconsoledandd.cpp \
53 51 src/QCustomPlot/qcpdocumentobject.cpp \
54 52 src/Core/Widgets/filebrowser.cpp \
55 src/Core/Widgets/filesystemmodel.cpp
53 src/Core/Widgets/filesystemmodel.cpp \
54 src/Core/Widgets/qcustomplotvect.cpp
56 55
57 56 HEADERS += src/mainwindow.h \
58 57 src/SocExplorerPlot.h \
59 58 src/QCustomPlot/qcustomplot.h \
60 src/folderview.h \
61 59 src/toolbarcontainer.h \
62 src/folderlistwidget.h \
63 60 src/Core/abstractfileloader.h \
64 61 src/Core/filedownloader.h \
65 62 src/Core/filedownloadertask.h \
@@ -81,10 +78,10 HEADERS += src/mainwindow.h \
81 78 src/Core/pyqlop.h \
82 79 src/QCustomPlot/qcpdocumentobject.h \
83 80 src/Core/Widgets/filebrowser.h \
84 src/Core/Widgets/filesystemmodel.h
81 src/Core/Widgets/filesystemmodel.h \
82 src/Core/Widgets/qcustomplotvect.h
85 83
86 84 FORMS += src/mainwindow.ui \
87 src/folderview.ui \
88 85 src/Core/Widgets/downloadhistory.ui \
89 86 src/Core/Widgets/downloadhistoryelement.ui \
90 87 src/Cassini/cassinidatadownloader.ui \
@@ -55,7 +55,7 void CassiniTools::makePlot()
55 55 plot->setXaxisTickLabelType(QCPAxis::ltDateTime);
56 56 plot->setXaxisDateTimeFormat("hh:mm:ss.zzz");
57 57 plot->setContextMenuPolicy(Qt::ActionsContextMenu);
58 QAction* action=new QAction("export view",_self);
58 SocExplorerPlotActions* action=new SocExplorerPlotActions("export view",plot->PID(),_self);
59 59 plot->addAction(action);
60 60 QObject::connect(action,SIGNAL(triggered()),_self,SLOT(export_view()));
61 61 }
@@ -104,15 +104,11 void CassiniTools::plot_TAB_File(const Q
104 104 plotFile(fileName);
105 105 }
106 106
107 void CassiniTools::export_view()
107 void CassiniTools::export_view(int PID)
108 108 {
109 SocExplorerPlot* plot = QLopPlots::getPlot(m_defaultPlot);
109 SocExplorerPlot* plot = QLopPlots::getPlot(PID);
110 110 if(plot==NULL)
111 {
112 makePlot();
113 plot = QLopPlots::getPlot(m_defaultPlot);
114 }
115 if(plot)
111 return;
116 112 {
117 113 QString fileName = QFileDialog::getSaveFileName();
118 114 }
@@ -31,7 +31,7 public:
31 31 static void plotFile(const QString &File);
32 32 public slots:
33 33 void plot_TAB_File(const QString& fileName);
34 void export_view();
34 void export_view(int PID);
35 35 private slots:
36 36 void dataReady(QLopDataList data);
37 37 };
@@ -2,7 +2,6
2 2 #define CASSINITOOLSGUI_H
3 3
4 4 #include <QWidget>
5 #include <folderview.h>
6 5 #include <filebrowser.h>
7 6
8 7 namespace Ui {
@@ -79,6 +79,7 int QLopPlots::addPlot()
79 79 if(pid!=-1)
80 80 {
81 81 SocExplorerPlot* plot=new SocExplorerPlot();
82 plot->setPID(pid);
82 83 m_plots->insert(pid,plot);
83 84 QDockWidget* dock = new QDockWidget();
84 85 dock->setWidget(plot);
@@ -4629,7 +4629,7 void PythonQtWrapper_QCPGraph::setErrorP
4629 4629
4630 4630 void PythonQtWrapper_QCPGraph::setUseFastVectors(QCPGraph* theWrappedObject, bool useFastVectors)
4631 4631 {
4632 ( theWrappedObject->setUseFastVectors(useFastVectors));
4632 // ( theWrappedObject->setUseFastVectors(useFastVectors));
4633 4633 }
4634 4634
4635 4635 QPointF PythonQtWrapper_QCPGraph::upperFillBasePoint(QCPGraph* theWrappedObject, double upperKey) const
@@ -4639,7 +4639,7 QPointF PythonQtWrapper_QCPGraph::upper
4639 4639
4640 4640 bool PythonQtWrapper_QCPGraph::useFastVectors(QCPGraph* theWrappedObject) const
4641 4641 {
4642 return ( theWrappedObject->useFastVectors());
4642 return true;//( theWrappedObject->useFastVectors());
4643 4643 }
4644 4644
4645 4645
This diff has been collapsed as it changes many lines, (19433 lines changed) Show them Hide them
@@ -48,12 +48,12
48 48 Creates a new QCPPainter instance and sets default values
49 49 */
50 50 QCPPainter::QCPPainter() :
51 QPainter(),
52 mModes(pmDefault),
53 mIsAntialiasing(false)
54 {
55 // don't setRenderHint(QPainter::NonCosmeticDefautPen) here, because painter isn't active yet and
56 // a call to begin() will follow
51 QPainter(),
52 mModes(pmDefault),
53 mIsAntialiasing(false)
54 {
55 // don't setRenderHint(QPainter::NonCosmeticDefautPen) here, because painter isn't active yet and
56 // a call to begin() will follow
57 57 }
58 58
59 59 /*!
@@ -63,13 +63,13 QCPPainter::QCPPainter() :
63 63 Like \ref begin, this method sets QPainter::NonCosmeticDefaultPen in Qt versions before Qt5.
64 64 */
65 65 QCPPainter::QCPPainter(QPaintDevice *device) :
66 QPainter(device),
67 mModes(pmDefault),
68 mIsAntialiasing(false)
66 QPainter(device),
67 mModes(pmDefault),
68 mIsAntialiasing(false)
69 69 {
70 70 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) // before Qt5, default pens used to be cosmetic if NonCosmeticDefaultPen flag isn't set. So we set it to get consistency across Qt versions.
71 if (isActive())
72 setRenderHint(QPainter::NonCosmeticDefaultPen);
71 if (isActive())
72 setRenderHint(QPainter::NonCosmeticDefaultPen);
73 73 #endif
74 74 }
75 75
@@ -85,9 +85,9 QCPPainter::~QCPPainter()
85 85 */
86 86 void QCPPainter::setPen(const QPen &pen)
87 87 {
88 QPainter::setPen(pen);
89 if (mModes.testFlag(pmNonCosmetic))
90 makeNonCosmetic();
88 QPainter::setPen(pen);
89 if (mModes.testFlag(pmNonCosmetic))
90 makeNonCosmetic();
91 91 }
92 92
93 93 /*! \overload
@@ -99,9 +99,9 void QCPPainter::setPen(const QPen &pen)
99 99 */
100 100 void QCPPainter::setPen(const QColor &color)
101 101 {
102 QPainter::setPen(color);
103 if (mModes.testFlag(pmNonCosmetic))
104 makeNonCosmetic();
102 QPainter::setPen(color);
103 if (mModes.testFlag(pmNonCosmetic))
104 makeNonCosmetic();
105 105 }
106 106
107 107 /*! \overload
@@ -113,9 +113,9 void QCPPainter::setPen(const QColor &co
113 113 */
114 114 void QCPPainter::setPen(Qt::PenStyle penStyle)
115 115 {
116 QPainter::setPen(penStyle);
117 if (mModes.testFlag(pmNonCosmetic))
118 makeNonCosmetic();
116 QPainter::setPen(penStyle);
117 if (mModes.testFlag(pmNonCosmetic))
118 makeNonCosmetic();
119 119 }
120 120
121 121 /*! \overload
@@ -128,10 +128,10 void QCPPainter::setPen(Qt::PenStyle pen
128 128 */
129 129 void QCPPainter::drawLine(const QLineF &line)
130 130 {
131 if (mIsAntialiasing || mModes.testFlag(pmVectorized))
132 QPainter::drawLine(line);
133 else
134 QPainter::drawLine(line.toLine());
131 if (mIsAntialiasing || mModes.testFlag(pmVectorized))
132 QPainter::drawLine(line);
133 else
134 QPainter::drawLine(line.toLine());
135 135 }
136 136
137 137 /*!
@@ -142,16 +142,16 void QCPPainter::drawLine(const QLineF &
142 142 */
143 143 void QCPPainter::setAntialiasing(bool enabled)
144 144 {
145 setRenderHint(QPainter::Antialiasing, enabled);
146 if (mIsAntialiasing != enabled)
147 {
148 mIsAntialiasing = enabled;
149 if (!mModes.testFlag(pmVectorized)) // antialiasing half-pixel shift only needed for rasterized outputs
150 {
151 if (mIsAntialiasing)
152 translate(0.5, 0.5);
153 else
154 translate(-0.5, -0.5);
145 setRenderHint(QPainter::Antialiasing, enabled);
146 if (mIsAntialiasing != enabled)
147 {
148 mIsAntialiasing = enabled;
149 if (!mModes.testFlag(pmVectorized)) // antialiasing half-pixel shift only needed for rasterized outputs
150 {
151 if (mIsAntialiasing)
152 translate(0.5, 0.5);
153 else
154 translate(-0.5, -0.5);
155 155 }
156 156 }
157 157 }
@@ -162,7 +162,7 void QCPPainter::setAntialiasing(bool en
162 162 */
163 163 void QCPPainter::setModes(QCPPainter::PainterModes modes)
164 164 {
165 mModes = modes;
165 mModes = modes;
166 166 }
167 167
168 168 /*!
@@ -178,12 +178,12 void QCPPainter::setModes(QCPPainter::Pa
178 178 */
179 179 bool QCPPainter::begin(QPaintDevice *device)
180 180 {
181 bool result = QPainter::begin(device);
181 bool result = QPainter::begin(device);
182 182 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) // before Qt5, default pens used to be cosmetic if NonCosmeticDefaultPen flag isn't set. So we set it to get consistency across Qt versions.
183 if (result)
184 setRenderHint(QPainter::NonCosmeticDefaultPen);
183 if (result)
184 setRenderHint(QPainter::NonCosmeticDefaultPen);
185 185 #endif
186 return result;
186 return result;
187 187 }
188 188
189 189 /*! \overload
@@ -193,10 +193,10 bool QCPPainter::begin(QPaintDevice *dev
193 193 */
194 194 void QCPPainter::setMode(QCPPainter::PainterMode mode, bool enabled)
195 195 {
196 if (!enabled && mModes.testFlag(mode))
197 mModes &= ~mode;
198 else if (enabled && !mModes.testFlag(mode))
199 mModes |= mode;
196 if (!enabled && mModes.testFlag(mode))
197 mModes &= ~mode;
198 else if (enabled && !mModes.testFlag(mode))
199 mModes |= mode;
200 200 }
201 201
202 202 /*!
@@ -209,8 +209,8 void QCPPainter::setMode(QCPPainter::Pai
209 209 */
210 210 void QCPPainter::save()
211 211 {
212 mAntialiasingStack.push(mIsAntialiasing);
213 QPainter::save();
212 mAntialiasingStack.push(mIsAntialiasing);
213 QPainter::save();
214 214 }
215 215
216 216 /*!
@@ -223,11 +223,11 void QCPPainter::save()
223 223 */
224 224 void QCPPainter::restore()
225 225 {
226 if (!mAntialiasingStack.isEmpty())
227 mIsAntialiasing = mAntialiasingStack.pop();
228 else
229 qDebug() << Q_FUNC_INFO << "Unbalanced save/restore";
230 QPainter::restore();
226 if (!mAntialiasingStack.isEmpty())
227 mIsAntialiasing = mAntialiasingStack.pop();
228 else
229 qDebug() << Q_FUNC_INFO << "Unbalanced save/restore";
230 QPainter::restore();
231 231 }
232 232
233 233 /*!
@@ -236,11 +236,11 void QCPPainter::restore()
236 236 */
237 237 void QCPPainter::makeNonCosmetic()
238 238 {
239 if (qFuzzyIsNull(pen().widthF()))
240 {
241 QPen p = pen();
242 p.setWidth(1);
243 QPainter::setPen(p);
239 if (qFuzzyIsNull(pen().widthF()))
240 {
241 QPen p = pen();
242 p.setWidth(1);
243 QPainter::setPen(p);
244 244 }
245 245 }
246 246
@@ -340,11 +340,11 void QCPPainter::makeNonCosmetic()
340 340 from the plottable that uses this scatter style.
341 341 */
342 342 QCPScatterStyle::QCPScatterStyle() :
343 mSize(6),
344 mShape(ssNone),
345 mPen(Qt::NoPen),
346 mBrush(Qt::NoBrush),
347 mPenDefined(false)
343 mSize(6),
344 mShape(ssNone),
345 mPen(Qt::NoPen),
346 mBrush(Qt::NoBrush),
347 mPenDefined(false)
348 348 {
349 349 }
350 350
@@ -356,11 +356,11 QCPScatterStyle::QCPScatterStyle() :
356 356 from the plottable that uses this scatter style.
357 357 */
358 358 QCPScatterStyle::QCPScatterStyle(ScatterShape shape, double size) :
359 mSize(size),
360 mShape(shape),
361 mPen(Qt::NoPen),
362 mBrush(Qt::NoBrush),
363 mPenDefined(false)
359 mSize(size),
360 mShape(shape),
361 mPen(Qt::NoPen),
362 mBrush(Qt::NoBrush),
363 mPenDefined(false)
364 364 {
365 365 }
366 366
@@ -369,11 +369,11 QCPScatterStyle::QCPScatterStyle(Scatter
369 369 and size to \a size. No brush is defined, i.e. the scatter point will not be filled.
370 370 */
371 371 QCPScatterStyle::QCPScatterStyle(ScatterShape shape, const QColor &color, double size) :
372 mSize(size),
373 mShape(shape),
374 mPen(QPen(color)),
375 mBrush(Qt::NoBrush),
376 mPenDefined(true)
372 mSize(size),
373 mShape(shape),
374 mPen(QPen(color)),
375 mBrush(Qt::NoBrush),
376 mPenDefined(true)
377 377 {
378 378 }
379 379
@@ -382,11 +382,11 QCPScatterStyle::QCPScatterStyle(Scatter
382 382 the brush color to \a fill (with a solid pattern), and size to \a size.
383 383 */
384 384 QCPScatterStyle::QCPScatterStyle(ScatterShape shape, const QColor &color, const QColor &fill, double size) :
385 mSize(size),
386 mShape(shape),
387 mPen(QPen(color)),
388 mBrush(QBrush(fill)),
389 mPenDefined(true)
385 mSize(size),
386 mShape(shape),
387 mPen(QPen(color)),
388 mBrush(QBrush(fill)),
389 mPenDefined(true)
390 390 {
391 391 }
392 392
@@ -406,11 +406,11 QCPScatterStyle::QCPScatterStyle(Scatter
406 406 wanted.
407 407 */
408 408 QCPScatterStyle::QCPScatterStyle(ScatterShape shape, const QPen &pen, const QBrush &brush, double size) :
409 mSize(size),
410 mShape(shape),
411 mPen(pen),
412 mBrush(brush),
413 mPenDefined(pen.style() != Qt::NoPen)
409 mSize(size),
410 mShape(shape),
411 mPen(pen),
412 mBrush(brush),
413 mPenDefined(pen.style() != Qt::NoPen)
414 414 {
415 415 }
416 416
@@ -419,12 +419,12 QCPScatterStyle::QCPScatterStyle(Scatter
419 419 is set to \ref ssPixmap.
420 420 */
421 421 QCPScatterStyle::QCPScatterStyle(const QPixmap &pixmap) :
422 mSize(5),
423 mShape(ssPixmap),
424 mPen(Qt::NoPen),
425 mBrush(Qt::NoBrush),
426 mPixmap(pixmap),
427 mPenDefined(false)
422 mSize(5),
423 mShape(ssPixmap),
424 mPen(Qt::NoPen),
425 mBrush(Qt::NoBrush),
426 mPixmap(pixmap),
427 mPenDefined(false)
428 428 {
429 429 }
430 430
@@ -438,12 +438,12 QCPScatterStyle::QCPScatterStyle(const Q
438 438 natural size by default. To double the size of the path for example, set \a size to 12.
439 439 */
440 440 QCPScatterStyle::QCPScatterStyle(const QPainterPath &customPath, const QPen &pen, const QBrush &brush, double size) :
441 mSize(size),
442 mShape(ssCustom),
443 mPen(pen),
444 mBrush(brush),
445 mCustomPath(customPath),
446 mPenDefined(pen.style() != Qt::NoPen)
441 mSize(size),
442 mShape(ssCustom),
443 mPen(pen),
444 mBrush(brush),
445 mCustomPath(customPath),
446 mPenDefined(pen.style() != Qt::NoPen)
447 447 {
448 448 }
449 449
@@ -454,7 +454,7 QCPScatterStyle::QCPScatterStyle(const Q
454 454 */
455 455 void QCPScatterStyle::setSize(double size)
456 456 {
457 mSize = size;
457 mSize = size;
458 458 }
459 459
460 460 /*!
@@ -467,7 +467,7 void QCPScatterStyle::setSize(double siz
467 467 */
468 468 void QCPScatterStyle::setShape(QCPScatterStyle::ScatterShape shape)
469 469 {
470 mShape = shape;
470 mShape = shape;
471 471 }
472 472
473 473 /*!
@@ -480,8 +480,8 void QCPScatterStyle::setShape(QCPScatte
480 480 */
481 481 void QCPScatterStyle::setPen(const QPen &pen)
482 482 {
483 mPenDefined = true;
484 mPen = pen;
483 mPenDefined = true;
484 mPen = pen;
485 485 }
486 486
487 487 /*!
@@ -492,7 +492,7 void QCPScatterStyle::setPen(const QPen
492 492 */
493 493 void QCPScatterStyle::setBrush(const QBrush &brush)
494 494 {
495 mBrush = brush;
495 mBrush = brush;
496 496 }
497 497
498 498 /*!
@@ -504,8 +504,8 void QCPScatterStyle::setBrush(const QBr
504 504 */
505 505 void QCPScatterStyle::setPixmap(const QPixmap &pixmap)
506 506 {
507 setShape(ssPixmap);
508 mPixmap = pixmap;
507 setShape(ssPixmap);
508 mPixmap = pixmap;
509 509 }
510 510
511 511 /*!
@@ -515,8 +515,8 void QCPScatterStyle::setPixmap(const QP
515 515 */
516 516 void QCPScatterStyle::setCustomPath(const QPainterPath &customPath)
517 517 {
518 setShape(ssCustom);
519 mCustomPath = customPath;
518 setShape(ssCustom);
519 mCustomPath = customPath;
520 520 }
521 521
522 522 /*!
@@ -530,8 +530,8 void QCPScatterStyle::setCustomPath(cons
530 530 */
531 531 void QCPScatterStyle::applyTo(QCPPainter *painter, const QPen &defaultPen) const
532 532 {
533 painter->setPen(mPenDefined ? mPen : defaultPen);
534 painter->setBrush(mBrush);
533 painter->setPen(mPenDefined ? mPen : defaultPen);
534 painter->setBrush(mBrush);
535 535 }
536 536
537 537 /*!
@@ -544,7 +544,7 void QCPScatterStyle::applyTo(QCPPainter
544 544 */
545 545 void QCPScatterStyle::drawShape(QCPPainter *painter, QPointF pos) const
546 546 {
547 drawShape(painter, pos.x(), pos.y());
547 drawShape(painter, pos.x(), pos.y());
548 548 }
549 549
550 550 /*! \overload
@@ -552,125 +552,125 void QCPScatterStyle::drawShape(QCPPaint
552 552 */
553 553 void QCPScatterStyle::drawShape(QCPPainter *painter, double x, double y) const
554 554 {
555 double w = mSize/2.0;
556 switch (mShape)
555 double w = mSize/2.0;
556 switch (mShape)
557 557 {
558 558 case ssNone: break;
559 559 case ssDot:
560 {
560 {
561 561 painter->drawLine(QPointF(x, y), QPointF(x+0.0001, y));
562 562 break;
563 }
563 }
564 564 case ssCross:
565 {
565 {
566 566 painter->drawLine(QLineF(x-w, y-w, x+w, y+w));
567 567 painter->drawLine(QLineF(x-w, y+w, x+w, y-w));
568 568 break;
569 }
569 }
570 570 case ssPlus:
571 {
571 {
572 572 painter->drawLine(QLineF(x-w, y, x+w, y));
573 573 painter->drawLine(QLineF( x, y+w, x, y-w));
574 574 break;
575 }
575 }
576 576 case ssCircle:
577 {
577 {
578 578 painter->drawEllipse(QPointF(x , y), w, w);
579 579 break;
580 }
580 }
581 581 case ssDisc:
582 {
582 {
583 583 QBrush b = painter->brush();
584 584 painter->setBrush(painter->pen().color());
585 585 painter->drawEllipse(QPointF(x , y), w, w);
586 586 painter->setBrush(b);
587 587 break;
588 }
588 }
589 589 case ssSquare:
590 {
590 {
591 591 painter->drawRect(QRectF(x-w, y-w, mSize, mSize));
592 592 break;
593 }
593 }
594 594 case ssDiamond:
595 {
595 {
596 596 painter->drawLine(QLineF(x-w, y, x, y-w));
597 597 painter->drawLine(QLineF( x, y-w, x+w, y));
598 598 painter->drawLine(QLineF(x+w, y, x, y+w));
599 599 painter->drawLine(QLineF( x, y+w, x-w, y));
600 600 break;
601 }
601 }
602 602 case ssStar:
603 {
603 {
604 604 painter->drawLine(QLineF(x-w, y, x+w, y));
605 605 painter->drawLine(QLineF( x, y+w, x, y-w));
606 606 painter->drawLine(QLineF(x-w*0.707, y-w*0.707, x+w*0.707, y+w*0.707));
607 607 painter->drawLine(QLineF(x-w*0.707, y+w*0.707, x+w*0.707, y-w*0.707));
608 608 break;
609 }
609 }
610 610 case ssTriangle:
611 {
611 {
612 612 painter->drawLine(QLineF(x-w, y+0.755*w, x+w, y+0.755*w));
613 613 painter->drawLine(QLineF(x+w, y+0.755*w, x, y-0.977*w));
614 614 painter->drawLine(QLineF( x, y-0.977*w, x-w, y+0.755*w));
615 615 break;
616 }
616 }
617 617 case ssTriangleInverted:
618 {
618 {
619 619 painter->drawLine(QLineF(x-w, y-0.755*w, x+w, y-0.755*w));
620 620 painter->drawLine(QLineF(x+w, y-0.755*w, x, y+0.977*w));
621 621 painter->drawLine(QLineF( x, y+0.977*w, x-w, y-0.755*w));
622 622 break;
623 }
623 }
624 624 case ssCrossSquare:
625 {
625 {
626 626 painter->drawLine(QLineF(x-w, y-w, x+w*0.95, y+w*0.95));
627 627 painter->drawLine(QLineF(x-w, y+w*0.95, x+w*0.95, y-w));
628 628 painter->drawRect(QRectF(x-w, y-w, mSize, mSize));
629 629 break;
630 }
630 }
631 631 case ssPlusSquare:
632 {
632 {
633 633 painter->drawLine(QLineF(x-w, y, x+w*0.95, y));
634 634 painter->drawLine(QLineF( x, y+w, x, y-w));
635 635 painter->drawRect(QRectF(x-w, y-w, mSize, mSize));
636 636 break;
637 }
637 }
638 638 case ssCrossCircle:
639 {
639 {
640 640 painter->drawLine(QLineF(x-w*0.707, y-w*0.707, x+w*0.670, y+w*0.670));
641 641 painter->drawLine(QLineF(x-w*0.707, y+w*0.670, x+w*0.670, y-w*0.707));
642 642 painter->drawEllipse(QPointF(x, y), w, w);
643 643 break;
644 }
644 }
645 645 case ssPlusCircle:
646 {
646 {
647 647 painter->drawLine(QLineF(x-w, y, x+w, y));
648 648 painter->drawLine(QLineF( x, y+w, x, y-w));
649 649 painter->drawEllipse(QPointF(x, y), w, w);
650 650 break;
651 }
651 }
652 652 case ssPeace:
653 {
653 {
654 654 painter->drawLine(QLineF(x, y-w, x, y+w));
655 655 painter->drawLine(QLineF(x, y, x-w*0.707, y+w*0.707));
656 656 painter->drawLine(QLineF(x, y, x+w*0.707, y+w*0.707));
657 657 painter->drawEllipse(QPointF(x, y), w, w);
658 658 break;
659 }
659 }
660 660 case ssPixmap:
661 {
661 {
662 662 painter->drawPixmap(x-mPixmap.width()*0.5, y-mPixmap.height()*0.5, mPixmap);
663 663 break;
664 }
664 }
665 665 case ssCustom:
666 {
666 {
667 667 QTransform oldTransform = painter->transform();
668 668 painter->translate(x, y);
669 669 painter->scale(mSize/6.0, mSize/6.0);
670 670 painter->drawPath(mCustomPath);
671 671 painter->setTransform(oldTransform);
672 672 break;
673 }
673 }
674 674 }
675 675 }
676 676
@@ -748,28 +748,28 void QCPScatterStyle::drawShape(QCPPaint
748 748 This check is only performed by \ref QCustomPlot::addLayer.
749 749 */
750 750 QCPLayer::QCPLayer(QCustomPlot *parentPlot, const QString &layerName) :
751 QObject(parentPlot),
752 mParentPlot(parentPlot),
753 mName(layerName),
754 mIndex(-1), // will be set to a proper value by the QCustomPlot layer creation function
755 mVisible(true)
756 {
757 // Note: no need to make sure layerName is unique, because layer
758 // management is done with QCustomPlot functions.
751 QObject(parentPlot),
752 mParentPlot(parentPlot),
753 mName(layerName),
754 mIndex(-1), // will be set to a proper value by the QCustomPlot layer creation function
755 mVisible(true)
756 {
757 // Note: no need to make sure layerName is unique, because layer
758 // management is done with QCustomPlot functions.
759 759 }
760 760
761 761 QCPLayer::~QCPLayer()
762 762 {
763 // If child layerables are still on this layer, detach them, so they don't try to reach back to this
764 // then invalid layer once they get deleted/moved themselves. This only happens when layers are deleted
765 // directly, like in the QCustomPlot destructor. (The regular layer removal procedure for the user is to
766 // call QCustomPlot::removeLayer, which moves all layerables off this layer before deleting it.)
767
768 while (!mChildren.isEmpty())
769 mChildren.last()->setLayer(0); // removes itself from mChildren via removeChild()
770
771 if (mParentPlot->currentLayer() == this)
772 qDebug() << Q_FUNC_INFO << "The parent plot's mCurrentLayer will be a dangling pointer. Should have been set to a valid layer or 0 beforehand.";
763 // If child layerables are still on this layer, detach them, so they don't try to reach back to this
764 // then invalid layer once they get deleted/moved themselves. This only happens when layers are deleted
765 // directly, like in the QCustomPlot destructor. (The regular layer removal procedure for the user is to
766 // call QCustomPlot::removeLayer, which moves all layerables off this layer before deleting it.)
767
768 while (!mChildren.isEmpty())
769 mChildren.last()->setLayer(0); // removes itself from mChildren via removeChild()
770
771 if (mParentPlot->currentLayer() == this)
772 qDebug() << Q_FUNC_INFO << "The parent plot's mCurrentLayer will be a dangling pointer. Should have been set to a valid layer or 0 beforehand.";
773 773 }
774 774
775 775 /*!
@@ -782,7 +782,7 QCPLayer::~QCPLayer()
782 782 */
783 783 void QCPLayer::setVisible(bool visible)
784 784 {
785 mVisible = visible;
785 mVisible = visible;
786 786 }
787 787
788 788 /*! \internal
@@ -797,14 +797,14 void QCPLayer::setVisible(bool visible)
797 797 */
798 798 void QCPLayer::addChild(QCPLayerable *layerable, bool prepend)
799 799 {
800 if (!mChildren.contains(layerable))
801 {
802 if (prepend)
803 mChildren.prepend(layerable);
804 else
805 mChildren.append(layerable);
806 } else
807 qDebug() << Q_FUNC_INFO << "layerable is already child of this layer" << reinterpret_cast<quintptr>(layerable);
800 if (!mChildren.contains(layerable))
801 {
802 if (prepend)
803 mChildren.prepend(layerable);
804 else
805 mChildren.append(layerable);
806 } else
807 qDebug() << Q_FUNC_INFO << "layerable is already child of this layer" << reinterpret_cast<quintptr>(layerable);
808 808 }
809 809
810 810 /*! \internal
@@ -818,8 +818,8 void QCPLayer::addChild(QCPLayerable *la
818 818 */
819 819 void QCPLayer::removeChild(QCPLayerable *layerable)
820 820 {
821 if (!mChildren.removeOne(layerable))
822 qDebug() << Q_FUNC_INFO << "layerable is not child of this layer" << reinterpret_cast<quintptr>(layerable);
821 if (!mChildren.removeOne(layerable))
822 qDebug() << Q_FUNC_INFO << "layerable is not child of this layer" << reinterpret_cast<quintptr>(layerable);
823 823 }
824 824
825 825
@@ -929,28 +929,28 void QCPLayer::removeChild(QCPLayerable
929 929 not become the QObject-parent (for memory management) of this layerable, \a plot does.
930 930 */
931 931 QCPLayerable::QCPLayerable(QCustomPlot *plot, QString targetLayer, QCPLayerable *parentLayerable) :
932 QObject(plot),
933 mVisible(true),
934 mParentPlot(plot),
935 mParentLayerable(parentLayerable),
936 mLayer(0),
937 mAntialiased(true)
938 {
939 if (mParentPlot)
940 {
941 if (targetLayer.isEmpty())
942 setLayer(mParentPlot->currentLayer());
943 else if (!setLayer(targetLayer))
944 qDebug() << Q_FUNC_INFO << "setting QCPlayerable initial layer to" << targetLayer << "failed.";
932 QObject(plot),
933 mVisible(true),
934 mParentPlot(plot),
935 mParentLayerable(parentLayerable),
936 mLayer(0),
937 mAntialiased(true)
938 {
939 if (mParentPlot)
940 {
941 if (targetLayer.isEmpty())
942 setLayer(mParentPlot->currentLayer());
943 else if (!setLayer(targetLayer))
944 qDebug() << Q_FUNC_INFO << "setting QCPlayerable initial layer to" << targetLayer << "failed.";
945 945 }
946 946 }
947 947
948 948 QCPLayerable::~QCPLayerable()
949 949 {
950 if (mLayer)
951 {
952 mLayer->removeChild(this);
953 mLayer = 0;
950 if (mLayer)
951 {
952 mLayer->removeChild(this);
953 mLayer = 0;
954 954 }
955 955 }
956 956
@@ -961,7 +961,7 QCPLayerable::~QCPLayerable()
961 961 */
962 962 void QCPLayerable::setVisible(bool on)
963 963 {
964 mVisible = on;
964 mVisible = on;
965 965 }
966 966
967 967 /*!
@@ -972,7 +972,7 void QCPLayerable::setVisible(bool on)
972 972 */
973 973 bool QCPLayerable::setLayer(QCPLayer *layer)
974 974 {
975 return moveToLayer(layer, false);
975 return moveToLayer(layer, false);
976 976 }
977 977
978 978 /*! \overload
@@ -982,18 +982,18 bool QCPLayerable::setLayer(QCPLayer *la
982 982 */
983 983 bool QCPLayerable::setLayer(const QString &layerName)
984 984 {
985 if (!mParentPlot)
986 {
987 qDebug() << Q_FUNC_INFO << "no parent QCustomPlot set";
988 return false;
989 }
990 if (QCPLayer *layer = mParentPlot->layer(layerName))
991 {
992 return setLayer(layer);
993 } else
994 {
995 qDebug() << Q_FUNC_INFO << "there is no layer with name" << layerName;
996 return false;
985 if (!mParentPlot)
986 {
987 qDebug() << Q_FUNC_INFO << "no parent QCustomPlot set";
988 return false;
989 }
990 if (QCPLayer *layer = mParentPlot->layer(layerName))
991 {
992 return setLayer(layer);
993 } else
994 {
995 qDebug() << Q_FUNC_INFO << "there is no layer with name" << layerName;
996 return false;
997 997 }
998 998 }
999 999
@@ -1005,7 +1005,7 bool QCPLayerable::setLayer(const QStrin
1005 1005 */
1006 1006 void QCPLayerable::setAntialiased(bool enabled)
1007 1007 {
1008 mAntialiased = enabled;
1008 mAntialiased = enabled;
1009 1009 }
1010 1010
1011 1011 /*!
@@ -1023,7 +1023,7 void QCPLayerable::setAntialiased(bool e
1023 1023 */
1024 1024 bool QCPLayerable::realVisibility() const
1025 1025 {
1026 return mVisible && (!mLayer || mLayer->visible()) && (!mParentLayerable || mParentLayerable.data()->realVisibility());
1026 return mVisible && (!mLayer || mLayer->visible()) && (!mParentLayerable || mParentLayerable.data()->realVisibility());
1027 1027 }
1028 1028
1029 1029 /*!
@@ -1062,10 +1062,10 bool QCPLayerable::realVisibility() cons
1062 1062 */
1063 1063 double QCPLayerable::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
1064 1064 {
1065 Q_UNUSED(pos)
1066 Q_UNUSED(onlySelectable)
1067 Q_UNUSED(details)
1068 return -1.0;
1065 Q_UNUSED(pos)
1066 Q_UNUSED(onlySelectable)
1067 Q_UNUSED(details)
1068 return -1.0;
1069 1069 }
1070 1070
1071 1071 /*! \internal
@@ -1087,17 +1087,17 double QCPLayerable::selectTest(const QP
1087 1087 */
1088 1088 void QCPLayerable::initializeParentPlot(QCustomPlot *parentPlot)
1089 1089 {
1090 if (mParentPlot)
1091 {
1092 qDebug() << Q_FUNC_INFO << "called with mParentPlot already initialized";
1093 return;
1094 }
1095
1096 if (!parentPlot)
1097 qDebug() << Q_FUNC_INFO << "called with parentPlot zero";
1098
1099 mParentPlot = parentPlot;
1100 parentPlotInitialized(mParentPlot);
1090 if (mParentPlot)
1091 {
1092 qDebug() << Q_FUNC_INFO << "called with mParentPlot already initialized";
1093 return;
1094 }
1095
1096 if (!parentPlot)
1097 qDebug() << Q_FUNC_INFO << "called with parentPlot zero";
1098
1099 mParentPlot = parentPlot;
1100 parentPlotInitialized(mParentPlot);
1101 1101 }
1102 1102
1103 1103 /*! \internal
@@ -1113,7 +1113,7 void QCPLayerable::initializeParentPlot(
1113 1113 */
1114 1114 void QCPLayerable::setParentLayerable(QCPLayerable *parentLayerable)
1115 1115 {
1116 mParentLayerable = parentLayerable;
1116 mParentLayerable = parentLayerable;
1117 1117 }
1118 1118
1119 1119 /*! \internal
@@ -1126,26 +1126,26 void QCPLayerable::setParentLayerable(QC
1126 1126 */
1127 1127 bool QCPLayerable::moveToLayer(QCPLayer *layer, bool prepend)
1128 1128 {
1129 if (layer && !mParentPlot)
1130 {
1131 qDebug() << Q_FUNC_INFO << "no parent QCustomPlot set";
1132 return false;
1133 }
1134 if (layer && layer->parentPlot() != mParentPlot)
1135 {
1136 qDebug() << Q_FUNC_INFO << "layer" << layer->name() << "is not in same QCustomPlot as this layerable";
1137 return false;
1138 }
1139
1140 QCPLayer *oldLayer = mLayer;
1141 if (mLayer)
1142 mLayer->removeChild(this);
1143 mLayer = layer;
1144 if (mLayer)
1145 mLayer->addChild(this, prepend);
1146 if (mLayer != oldLayer)
1147 emit layerChanged(mLayer);
1148 return true;
1129 if (layer && !mParentPlot)
1130 {
1131 qDebug() << Q_FUNC_INFO << "no parent QCustomPlot set";
1132 return false;
1133 }
1134 if (layer && layer->parentPlot() != mParentPlot)
1135 {
1136 qDebug() << Q_FUNC_INFO << "layer" << layer->name() << "is not in same QCustomPlot as this layerable";
1137 return false;
1138 }
1139
1140 QCPLayer *oldLayer = mLayer;
1141 if (mLayer)
1142 mLayer->removeChild(this);
1143 mLayer = layer;
1144 if (mLayer)
1145 mLayer->addChild(this, prepend);
1146 if (mLayer != oldLayer)
1147 emit layerChanged(mLayer);
1148 return true;
1149 1149 }
1150 1150
1151 1151 /*! \internal
@@ -1157,12 +1157,12 bool QCPLayerable::moveToLayer(QCPLayer
1157 1157 */
1158 1158 void QCPLayerable::applyAntialiasingHint(QCPPainter *painter, bool localAntialiased, QCP::AntialiasedElement overrideElement) const
1159 1159 {
1160 if (mParentPlot && mParentPlot->notAntialiasedElements().testFlag(overrideElement))
1161 painter->setAntialiasing(false);
1162 else if (mParentPlot && mParentPlot->antialiasedElements().testFlag(overrideElement))
1163 painter->setAntialiasing(true);
1164 else
1165 painter->setAntialiasing(localAntialiased);
1160 if (mParentPlot && mParentPlot->notAntialiasedElements().testFlag(overrideElement))
1161 painter->setAntialiasing(false);
1162 else if (mParentPlot && mParentPlot->antialiasedElements().testFlag(overrideElement))
1163 painter->setAntialiasing(true);
1164 else
1165 painter->setAntialiasing(localAntialiased);
1166 1166 }
1167 1167
1168 1168 /*! \internal
@@ -1183,7 +1183,7 void QCPLayerable::applyAntialiasingHint
1183 1183 */
1184 1184 void QCPLayerable::parentPlotInitialized(QCustomPlot *parentPlot)
1185 1185 {
1186 Q_UNUSED(parentPlot)
1186 Q_UNUSED(parentPlot)
1187 1187 }
1188 1188
1189 1189 /*! \internal
@@ -1199,7 +1199,7 void QCPLayerable::parentPlotInitialized
1199 1199 */
1200 1200 QCP::Interaction QCPLayerable::selectionCategory() const
1201 1201 {
1202 return QCP::iSelectOther;
1202 return QCP::iSelectOther;
1203 1203 }
1204 1204
1205 1205 /*! \internal
@@ -1213,10 +1213,10 QCP::Interaction QCPLayerable::selection
1213 1213 */
1214 1214 QRect QCPLayerable::clipRect() const
1215 1215 {
1216 if (mParentPlot)
1217 return mParentPlot->viewport();
1218 else
1219 return QRect();
1216 if (mParentPlot)
1217 return mParentPlot->viewport();
1218 else
1219 return QRect();
1220 1220 }
1221 1221
1222 1222 /*! \internal
@@ -1249,10 +1249,10 QRect QCPLayerable::clipRect() const
1249 1249 */
1250 1250 void QCPLayerable::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged)
1251 1251 {
1252 Q_UNUSED(event)
1253 Q_UNUSED(additive)
1254 Q_UNUSED(details)
1255 Q_UNUSED(selectionStateChanged)
1252 Q_UNUSED(event)
1253 Q_UNUSED(additive)
1254 Q_UNUSED(details)
1255 Q_UNUSED(selectionStateChanged)
1256 1256 }
1257 1257
1258 1258 /*! \internal
@@ -1269,7 +1269,7 void QCPLayerable::selectEvent(QMouseEve
1269 1269 */
1270 1270 void QCPLayerable::deselectEvent(bool *selectionStateChanged)
1271 1271 {
1272 Q_UNUSED(selectionStateChanged)
1272 Q_UNUSED(selectionStateChanged)
1273 1273 }
1274 1274
1275 1275
@@ -1307,8 +1307,8 const double QCPRange::maxRange = 1e250;
1307 1307 Constructs a range with \a lower and \a upper set to zero.
1308 1308 */
1309 1309 QCPRange::QCPRange() :
1310 lower(0),
1311 upper(0)
1310 lower(0),
1311 upper(0)
1312 1312 {
1313 1313 }
1314 1314
@@ -1316,10 +1316,10 QCPRange::QCPRange() :
1316 1316 Constructs a range with the specified \a lower and \a upper values.
1317 1317 */
1318 1318 QCPRange::QCPRange(double lower, double upper) :
1319 lower(lower),
1320 upper(upper)
1321 {
1322 normalize();
1319 lower(lower),
1320 upper(upper)
1321 {
1322 normalize();
1323 1323 }
1324 1324
1325 1325 /*!
@@ -1327,7 +1327,7 QCPRange::QCPRange(double lower, double
1327 1327 */
1328 1328 double QCPRange::size() const
1329 1329 {
1330 return upper-lower;
1330 return upper-lower;
1331 1331 }
1332 1332
1333 1333 /*!
@@ -1335,7 +1335,7 double QCPRange::size() const
1335 1335 */
1336 1336 double QCPRange::center() const
1337 1337 {
1338 return (upper+lower)*0.5;
1338 return (upper+lower)*0.5;
1339 1339 }
1340 1340
1341 1341 /*!
@@ -1344,8 +1344,8 double QCPRange::center() const
1344 1344 */
1345 1345 void QCPRange::normalize()
1346 1346 {
1347 if (lower > upper)
1348 qSwap(lower, upper);
1347 if (lower > upper)
1348 qSwap(lower, upper);
1349 1349 }
1350 1350
1351 1351 /*!
@@ -1358,10 +1358,10 void QCPRange::normalize()
1358 1358 */
1359 1359 void QCPRange::expand(const QCPRange &otherRange)
1360 1360 {
1361 if (lower > otherRange.lower)
1362 lower = otherRange.lower;
1363 if (upper < otherRange.upper)
1364 upper = otherRange.upper;
1361 if (lower > otherRange.lower)
1362 lower = otherRange.lower;
1363 if (upper < otherRange.upper)
1364 upper = otherRange.upper;
1365 1365 }
1366 1366
1367 1367
@@ -1373,9 +1373,9 void QCPRange::expand(const QCPRange &ot
1373 1373 */
1374 1374 QCPRange QCPRange::expanded(const QCPRange &otherRange) const
1375 1375 {
1376 QCPRange result = *this;
1377 result.expand(otherRange);
1378 return result;
1376 QCPRange result = *this;
1377 result.expand(otherRange);
1378 return result;
1379 1379 }
1380 1380
1381 1381 /*!
@@ -1392,47 +1392,47 QCPRange QCPRange::expanded(const QCPRan
1392 1392 */
1393 1393 QCPRange QCPRange::sanitizedForLogScale() const
1394 1394 {
1395 double rangeFac = 1e-3;
1396 QCPRange sanitizedRange(lower, upper);
1397 sanitizedRange.normalize();
1398 // can't have range spanning negative and positive values in log plot, so change range to fix it
1399 //if (qFuzzyCompare(sanitizedRange.lower+1, 1) && !qFuzzyCompare(sanitizedRange.upper+1, 1))
1400 if (sanitizedRange.lower == 0.0 && sanitizedRange.upper != 0.0)
1401 {
1402 // case lower is 0
1403 if (rangeFac < sanitizedRange.upper*rangeFac)
1404 sanitizedRange.lower = rangeFac;
1405 else
1406 sanitizedRange.lower = sanitizedRange.upper*rangeFac;
1395 double rangeFac = 1e-3;
1396 QCPRange sanitizedRange(lower, upper);
1397 sanitizedRange.normalize();
1398 // can't have range spanning negative and positive values in log plot, so change range to fix it
1399 //if (qFuzzyCompare(sanitizedRange.lower+1, 1) && !qFuzzyCompare(sanitizedRange.upper+1, 1))
1400 if (sanitizedRange.lower == 0.0 && sanitizedRange.upper != 0.0)
1401 {
1402 // case lower is 0
1403 if (rangeFac < sanitizedRange.upper*rangeFac)
1404 sanitizedRange.lower = rangeFac;
1405 else
1406 sanitizedRange.lower = sanitizedRange.upper*rangeFac;
1407 1407 } //else if (!qFuzzyCompare(lower+1, 1) && qFuzzyCompare(upper+1, 1))
1408 else if (sanitizedRange.lower != 0.0 && sanitizedRange.upper == 0.0)
1409 {
1410 // case upper is 0
1411 if (-rangeFac > sanitizedRange.lower*rangeFac)
1412 sanitizedRange.upper = -rangeFac;
1413 else
1414 sanitizedRange.upper = sanitizedRange.lower*rangeFac;
1408 else if (sanitizedRange.lower != 0.0 && sanitizedRange.upper == 0.0)
1409 {
1410 // case upper is 0
1411 if (-rangeFac > sanitizedRange.lower*rangeFac)
1412 sanitizedRange.upper = -rangeFac;
1413 else
1414 sanitizedRange.upper = sanitizedRange.lower*rangeFac;
1415 1415 } else if (sanitizedRange.lower < 0 && sanitizedRange.upper > 0)
1416 1416 {
1417 // find out whether negative or positive interval is wider to decide which sign domain will be chosen
1418 if (-sanitizedRange.lower > sanitizedRange.upper)
1419 {
1420 // negative is wider, do same as in case upper is 0
1421 if (-rangeFac > sanitizedRange.lower*rangeFac)
1422 sanitizedRange.upper = -rangeFac;
1423 else
1424 sanitizedRange.upper = sanitizedRange.lower*rangeFac;
1417 // find out whether negative or positive interval is wider to decide which sign domain will be chosen
1418 if (-sanitizedRange.lower > sanitizedRange.upper)
1419 {
1420 // negative is wider, do same as in case upper is 0
1421 if (-rangeFac > sanitizedRange.lower*rangeFac)
1422 sanitizedRange.upper = -rangeFac;
1423 else
1424 sanitizedRange.upper = sanitizedRange.lower*rangeFac;
1425 1425 } else
1426 1426 {
1427 // positive is wider, do same as in case lower is 0
1428 if (rangeFac < sanitizedRange.upper*rangeFac)
1429 sanitizedRange.lower = rangeFac;
1430 else
1431 sanitizedRange.lower = sanitizedRange.upper*rangeFac;
1432 }
1433 }
1434 // due to normalization, case lower>0 && upper<0 should never occur, because that implies upper<lower
1435 return sanitizedRange;
1427 // positive is wider, do same as in case lower is 0
1428 if (rangeFac < sanitizedRange.upper*rangeFac)
1429 sanitizedRange.lower = rangeFac;
1430 else
1431 sanitizedRange.lower = sanitizedRange.upper*rangeFac;
1432 }
1433 }
1434 // due to normalization, case lower>0 && upper<0 should never occur, because that implies upper<lower
1435 return sanitizedRange;
1436 1436 }
1437 1437
1438 1438 /*!
@@ -1441,9 +1441,9 QCPRange QCPRange::sanitizedForLogScale(
1441 1441 */
1442 1442 QCPRange QCPRange::sanitizedForLinScale() const
1443 1443 {
1444 QCPRange sanitizedRange(lower, upper);
1445 sanitizedRange.normalize();
1446 return sanitizedRange;
1444 QCPRange sanitizedRange(lower, upper);
1445 sanitizedRange.normalize();
1446 return sanitizedRange;
1447 1447 }
1448 1448
1449 1449 /*!
@@ -1451,7 +1451,7 QCPRange QCPRange::sanitizedForLinScale(
1451 1451 */
1452 1452 bool QCPRange::contains(double value) const
1453 1453 {
1454 return value >= lower && value <= upper;
1454 return value >= lower && value <= upper;
1455 1455 }
1456 1456
1457 1457 /*!
@@ -1464,17 +1464,17 bool QCPRange::contains(double value) co
1464 1464 */
1465 1465 bool QCPRange::validRange(double lower, double upper)
1466 1466 {
1467 /*
1467 /*
1468 1468 return (lower > -maxRange &&
1469 1469 upper < maxRange &&
1470 1470 qAbs(lower-upper) > minRange &&
1471 1471 (lower < -minRange || lower > minRange) &&
1472 1472 (upper < -minRange || upper > minRange));
1473 1473 */
1474 return (lower > -maxRange &&
1475 upper < maxRange &&
1476 qAbs(lower-upper) > minRange &&
1477 qAbs(lower-upper) < maxRange);
1474 return (lower > -maxRange &&
1475 upper < maxRange &&
1476 qAbs(lower-upper) > minRange &&
1477 qAbs(lower-upper) < maxRange);
1478 1478 }
1479 1479
1480 1480 /*!
@@ -1488,7 +1488,7 bool QCPRange::validRange(double lower,
1488 1488 */
1489 1489 bool QCPRange::validRange(const QCPRange &range)
1490 1490 {
1491 /*
1491 /*
1492 1492 return (range.lower > -maxRange &&
1493 1493 range.upper < maxRange &&
1494 1494 qAbs(range.lower-range.upper) > minRange &&
@@ -1496,10 +1496,10 bool QCPRange::validRange(const QCPRange
1496 1496 (range.lower < -minRange || range.lower > minRange) &&
1497 1497 (range.upper < -minRange || range.upper > minRange));
1498 1498 */
1499 return (range.lower > -maxRange &&
1500 range.upper < maxRange &&
1501 qAbs(range.lower-range.upper) > minRange &&
1502 qAbs(range.lower-range.upper) < maxRange);
1499 return (range.lower > -maxRange &&
1500 range.upper < maxRange &&
1501 qAbs(range.lower-range.upper) > minRange &&
1502 qAbs(range.lower-range.upper) < maxRange);
1503 1503 }
1504 1504
1505 1505
@@ -1557,18 +1557,18 bool QCPRange::validRange(const QCPRange
1557 1557 Creates a new QCPMarginGroup instance in \a parentPlot.
1558 1558 */
1559 1559 QCPMarginGroup::QCPMarginGroup(QCustomPlot *parentPlot) :
1560 QObject(parentPlot),
1561 mParentPlot(parentPlot)
1562 {
1563 mChildren.insert(QCP::msLeft, QList<QCPLayoutElement*>());
1564 mChildren.insert(QCP::msRight, QList<QCPLayoutElement*>());
1565 mChildren.insert(QCP::msTop, QList<QCPLayoutElement*>());
1566 mChildren.insert(QCP::msBottom, QList<QCPLayoutElement*>());
1560 QObject(parentPlot),
1561 mParentPlot(parentPlot)
1562 {
1563 mChildren.insert(QCP::msLeft, QList<QCPLayoutElement*>());
1564 mChildren.insert(QCP::msRight, QList<QCPLayoutElement*>());
1565 mChildren.insert(QCP::msTop, QList<QCPLayoutElement*>());
1566 mChildren.insert(QCP::msBottom, QList<QCPLayoutElement*>());
1567 1567 }
1568 1568
1569 1569 QCPMarginGroup::~QCPMarginGroup()
1570 1570 {
1571 clear();
1571 clear();
1572 1572 }
1573 1573
1574 1574 /*!
@@ -1577,14 +1577,14 QCPMarginGroup::~QCPMarginGroup()
1577 1577 */
1578 1578 bool QCPMarginGroup::isEmpty() const
1579 1579 {
1580 QHashIterator<QCP::MarginSide, QList<QCPLayoutElement*> > it(mChildren);
1581 while (it.hasNext())
1582 {
1583 it.next();
1584 if (!it.value().isEmpty())
1585 return false;
1586 }
1587 return true;
1580 QHashIterator<QCP::MarginSide, QList<QCPLayoutElement*> > it(mChildren);
1581 while (it.hasNext())
1582 {
1583 it.next();
1584 if (!it.value().isEmpty())
1585 return false;
1586 }
1587 return true;
1588 1588 }
1589 1589
1590 1590 /*!
@@ -1593,14 +1593,14 bool QCPMarginGroup::isEmpty() const
1593 1593 */
1594 1594 void QCPMarginGroup::clear()
1595 1595 {
1596 // make all children remove themselves from this margin group:
1597 QHashIterator<QCP::MarginSide, QList<QCPLayoutElement*> > it(mChildren);
1598 while (it.hasNext())
1599 {
1600 it.next();
1601 const QList<QCPLayoutElement*> elements = it.value();
1602 for (int i=elements.size()-1; i>=0; --i)
1603 elements.at(i)->setMarginGroup(it.key(), 0); // removes itself from mChildren via removeChild
1596 // make all children remove themselves from this margin group:
1597 QHashIterator<QCP::MarginSide, QList<QCPLayoutElement*> > it(mChildren);
1598 while (it.hasNext())
1599 {
1600 it.next();
1601 const QList<QCPLayoutElement*> elements = it.value();
1602 for (int i=elements.size()-1; i>=0; --i)
1603 elements.at(i)->setMarginGroup(it.key(), 0); // removes itself from mChildren via removeChild
1604 1604 }
1605 1605 }
1606 1606
@@ -1616,18 +1616,18 void QCPMarginGroup::clear()
1616 1616 */
1617 1617 int QCPMarginGroup::commonMargin(QCP::MarginSide side) const
1618 1618 {
1619 // query all automatic margins of the layout elements in this margin group side and find maximum:
1620 int result = 0;
1621 const QList<QCPLayoutElement*> elements = mChildren.value(side);
1622 for (int i=0; i<elements.size(); ++i)
1623 {
1624 if (!elements.at(i)->autoMargins().testFlag(side))
1625 continue;
1626 int m = qMax(elements.at(i)->calculateAutoMargin(side), QCP::getMarginValue(elements.at(i)->minimumMargins(), side));
1627 if (m > result)
1628 result = m;
1629 }
1630 return result;
1619 // query all automatic margins of the layout elements in this margin group side and find maximum:
1620 int result = 0;
1621 const QList<QCPLayoutElement*> elements = mChildren.value(side);
1622 for (int i=0; i<elements.size(); ++i)
1623 {
1624 if (!elements.at(i)->autoMargins().testFlag(side))
1625 continue;
1626 int m = qMax(elements.at(i)->calculateAutoMargin(side), QCP::getMarginValue(elements.at(i)->minimumMargins(), side));
1627 if (m > result)
1628 result = m;
1629 }
1630 return result;
1631 1631 }
1632 1632
1633 1633 /*! \internal
@@ -1638,10 +1638,10 int QCPMarginGroup::commonMargin(QCP::Ma
1638 1638 */
1639 1639 void QCPMarginGroup::addChild(QCP::MarginSide side, QCPLayoutElement *element)
1640 1640 {
1641 if (!mChildren[side].contains(element))
1642 mChildren[side].append(element);
1643 else
1644 qDebug() << Q_FUNC_INFO << "element is already child of this margin group side" << reinterpret_cast<quintptr>(element);
1641 if (!mChildren[side].contains(element))
1642 mChildren[side].append(element);
1643 else
1644 qDebug() << Q_FUNC_INFO << "element is already child of this margin group side" << reinterpret_cast<quintptr>(element);
1645 1645 }
1646 1646
1647 1647 /*! \internal
@@ -1652,8 +1652,8 void QCPMarginGroup::addChild(QCP::Margi
1652 1652 */
1653 1653 void QCPMarginGroup::removeChild(QCP::MarginSide side, QCPLayoutElement *element)
1654 1654 {
1655 if (!mChildren[side].removeOne(element))
1656 qDebug() << Q_FUNC_INFO << "element is not child of this margin group side" << reinterpret_cast<quintptr>(element);
1655 if (!mChildren[side].removeOne(element))
1656 qDebug() << Q_FUNC_INFO << "element is not child of this margin group side" << reinterpret_cast<quintptr>(element);
1657 1657 }
1658 1658
1659 1659
@@ -1742,24 +1742,24 void QCPMarginGroup::removeChild(QCP::Ma
1742 1742 Creates an instance of QCPLayoutElement and sets default values.
1743 1743 */
1744 1744 QCPLayoutElement::QCPLayoutElement(QCustomPlot *parentPlot) :
1745 QCPLayerable(parentPlot), // parenthood is changed as soon as layout element gets inserted into a layout (except for top level layout)
1746 mParentLayout(0),
1747 mMinimumSize(),
1748 mMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX),
1749 mRect(0, 0, 0, 0),
1750 mOuterRect(0, 0, 0, 0),
1751 mMargins(0, 0, 0, 0),
1752 mMinimumMargins(0, 0, 0, 0),
1753 mAutoMargins(QCP::msAll)
1745 QCPLayerable(parentPlot), // parenthood is changed as soon as layout element gets inserted into a layout (except for top level layout)
1746 mParentLayout(0),
1747 mMinimumSize(),
1748 mMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX),
1749 mRect(0, 0, 0, 0),
1750 mOuterRect(0, 0, 0, 0),
1751 mMargins(0, 0, 0, 0),
1752 mMinimumMargins(0, 0, 0, 0),
1753 mAutoMargins(QCP::msAll)
1754 1754 {
1755 1755 }
1756 1756
1757 1757 QCPLayoutElement::~QCPLayoutElement()
1758 1758 {
1759 setMarginGroup(QCP::msAll, 0); // unregister at margin groups, if there are any
1760 // unregister at layout:
1761 if (qobject_cast<QCPLayout*>(mParentLayout)) // the qobject_cast is just a safeguard in case the layout forgets to call clear() in its dtor and this dtor is called by QObject dtor
1762 mParentLayout->take(this);
1759 setMarginGroup(QCP::msAll, 0); // unregister at margin groups, if there are any
1760 // unregister at layout:
1761 if (qobject_cast<QCPLayout*>(mParentLayout)) // the qobject_cast is just a safeguard in case the layout forgets to call clear() in its dtor and this dtor is called by QObject dtor
1762 mParentLayout->take(this);
1763 1763 }
1764 1764
1765 1765 /*!
@@ -1775,10 +1775,10 QCPLayoutElement::~QCPLayoutElement()
1775 1775 */
1776 1776 void QCPLayoutElement::setOuterRect(const QRect &rect)
1777 1777 {
1778 if (mOuterRect != rect)
1779 {
1780 mOuterRect = rect;
1781 mRect = mOuterRect.adjusted(mMargins.left(), mMargins.top(), -mMargins.right(), -mMargins.bottom());
1778 if (mOuterRect != rect)
1779 {
1780 mOuterRect = rect;
1781 mRect = mOuterRect.adjusted(mMargins.left(), mMargins.top(), -mMargins.right(), -mMargins.bottom());
1782 1782 }
1783 1783 }
1784 1784
@@ -1795,10 +1795,10 void QCPLayoutElement::setOuterRect(cons
1795 1795 */
1796 1796 void QCPLayoutElement::setMargins(const QMargins &margins)
1797 1797 {
1798 if (mMargins != margins)
1799 {
1800 mMargins = margins;
1801 mRect = mOuterRect.adjusted(mMargins.left(), mMargins.top(), -mMargins.right(), -mMargins.bottom());
1798 if (mMargins != margins)
1799 {
1800 mMargins = margins;
1801 mRect = mOuterRect.adjusted(mMargins.left(), mMargins.top(), -mMargins.right(), -mMargins.bottom());
1802 1802 }
1803 1803 }
1804 1804
@@ -1813,9 +1813,9 void QCPLayoutElement::setMargins(const
1813 1813 */
1814 1814 void QCPLayoutElement::setMinimumMargins(const QMargins &margins)
1815 1815 {
1816 if (mMinimumMargins != margins)
1817 {
1818 mMinimumMargins = margins;
1816 if (mMinimumMargins != margins)
1817 {
1818 mMinimumMargins = margins;
1819 1819 }
1820 1820 }
1821 1821
@@ -1831,7 +1831,7 void QCPLayoutElement::setMinimumMargins
1831 1831 */
1832 1832 void QCPLayoutElement::setAutoMargins(QCP::MarginSides sides)
1833 1833 {
1834 mAutoMargins = sides;
1834 mAutoMargins = sides;
1835 1835 }
1836 1836
1837 1837 /*!
@@ -1845,11 +1845,11 void QCPLayoutElement::setAutoMargins(QC
1845 1845 */
1846 1846 void QCPLayoutElement::setMinimumSize(const QSize &size)
1847 1847 {
1848 if (mMinimumSize != size)
1849 {
1850 mMinimumSize = size;
1851 if (mParentLayout)
1852 mParentLayout->sizeConstraintsChanged();
1848 if (mMinimumSize != size)
1849 {
1850 mMinimumSize = size;
1851 if (mParentLayout)
1852 mParentLayout->sizeConstraintsChanged();
1853 1853 }
1854 1854 }
1855 1855
@@ -1859,7 +1859,7 void QCPLayoutElement::setMinimumSize(co
1859 1859 */
1860 1860 void QCPLayoutElement::setMinimumSize(int width, int height)
1861 1861 {
1862 setMinimumSize(QSize(width, height));
1862 setMinimumSize(QSize(width, height));
1863 1863 }
1864 1864
1865 1865 /*!
@@ -1868,11 +1868,11 void QCPLayoutElement::setMinimumSize(in
1868 1868 */
1869 1869 void QCPLayoutElement::setMaximumSize(const QSize &size)
1870 1870 {
1871 if (mMaximumSize != size)
1872 {
1873 mMaximumSize = size;
1874 if (mParentLayout)
1875 mParentLayout->sizeConstraintsChanged();
1871 if (mMaximumSize != size)
1872 {
1873 mMaximumSize = size;
1874 if (mParentLayout)
1875 mParentLayout->sizeConstraintsChanged();
1876 1876 }
1877 1877 }
1878 1878
@@ -1882,7 +1882,7 void QCPLayoutElement::setMaximumSize(co
1882 1882 */
1883 1883 void QCPLayoutElement::setMaximumSize(int width, int height)
1884 1884 {
1885 setMaximumSize(QSize(width, height));
1885 setMaximumSize(QSize(width, height));
1886 1886 }
1887 1887
1888 1888 /*!
@@ -1898,28 +1898,28 void QCPLayoutElement::setMaximumSize(in
1898 1898 */
1899 1899 void QCPLayoutElement::setMarginGroup(QCP::MarginSides sides, QCPMarginGroup *group)
1900 1900 {
1901 QVector<QCP::MarginSide> sideVector;
1902 if (sides.testFlag(QCP::msLeft)) sideVector.append(QCP::msLeft);
1903 if (sides.testFlag(QCP::msRight)) sideVector.append(QCP::msRight);
1904 if (sides.testFlag(QCP::msTop)) sideVector.append(QCP::msTop);
1905 if (sides.testFlag(QCP::msBottom)) sideVector.append(QCP::msBottom);
1906
1907 for (int i=0; i<sideVector.size(); ++i)
1908 {
1909 QCP::MarginSide side = sideVector.at(i);
1910 if (marginGroup(side) != group)
1911 {
1912 QCPMarginGroup *oldGroup = marginGroup(side);
1913 if (oldGroup) // unregister at old group
1914 oldGroup->removeChild(side, this);
1915
1916 if (!group) // if setting to 0, remove hash entry. Else set hash entry to new group and register there
1917 {
1918 mMarginGroups.remove(side);
1901 QVector<QCP::MarginSide> sideVector;
1902 if (sides.testFlag(QCP::msLeft)) sideVector.append(QCP::msLeft);
1903 if (sides.testFlag(QCP::msRight)) sideVector.append(QCP::msRight);
1904 if (sides.testFlag(QCP::msTop)) sideVector.append(QCP::msTop);
1905 if (sides.testFlag(QCP::msBottom)) sideVector.append(QCP::msBottom);
1906
1907 for (int i=0; i<sideVector.size(); ++i)
1908 {
1909 QCP::MarginSide side = sideVector.at(i);
1910 if (marginGroup(side) != group)
1911 {
1912 QCPMarginGroup *oldGroup = marginGroup(side);
1913 if (oldGroup) // unregister at old group
1914 oldGroup->removeChild(side, this);
1915
1916 if (!group) // if setting to 0, remove hash entry. Else set hash entry to new group and register there
1917 {
1918 mMarginGroups.remove(side);
1919 1919 } else // setting to a new group
1920 1920 {
1921 mMarginGroups[side] = group;
1922 group->addChild(side, this);
1921 mMarginGroups[side] = group;
1922 group->addChild(side, this);
1923 1923 }
1924 1924 }
1925 1925 }
@@ -1939,26 +1939,26 void QCPLayoutElement::setMarginGroup(QC
1939 1939 */
1940 1940 void QCPLayoutElement::update(UpdatePhase phase)
1941 1941 {
1942 if (phase == upMargins)
1943 {
1944 if (mAutoMargins != QCP::msNone)
1945 {
1946 // set the margins of this layout element according to automatic margin calculation, either directly or via a margin group:
1947 QMargins newMargins = mMargins;
1948 foreach (QCP::MarginSide side, QList<QCP::MarginSide>() << QCP::msLeft << QCP::msRight << QCP::msTop << QCP::msBottom)
1949 {
1950 if (mAutoMargins.testFlag(side)) // this side's margin shall be calculated automatically
1942 if (phase == upMargins)
1943 {
1944 if (mAutoMargins != QCP::msNone)
1945 {
1946 // set the margins of this layout element according to automatic margin calculation, either directly or via a margin group:
1947 QMargins newMargins = mMargins;
1948 foreach (QCP::MarginSide side, QList<QCP::MarginSide>() << QCP::msLeft << QCP::msRight << QCP::msTop << QCP::msBottom)
1949 {
1950 if (mAutoMargins.testFlag(side)) // this side's margin shall be calculated automatically
1951 1951 {
1952 if (mMarginGroups.contains(side))
1953 QCP::setMarginValue(newMargins, side, mMarginGroups[side]->commonMargin(side)); // this side is part of a margin group, so get the margin value from that group
1954 else
1955 QCP::setMarginValue(newMargins, side, calculateAutoMargin(side)); // this side is not part of a group, so calculate the value directly
1956 // apply minimum margin restrictions:
1957 if (QCP::getMarginValue(newMargins, side) < QCP::getMarginValue(mMinimumMargins, side))
1958 QCP::setMarginValue(newMargins, side, QCP::getMarginValue(mMinimumMargins, side));
1952 if (mMarginGroups.contains(side))
1953 QCP::setMarginValue(newMargins, side, mMarginGroups[side]->commonMargin(side)); // this side is part of a margin group, so get the margin value from that group
1954 else
1955 QCP::setMarginValue(newMargins, side, calculateAutoMargin(side)); // this side is not part of a group, so calculate the value directly
1956 // apply minimum margin restrictions:
1957 if (QCP::getMarginValue(newMargins, side) < QCP::getMarginValue(mMinimumMargins, side))
1958 QCP::setMarginValue(newMargins, side, QCP::getMarginValue(mMinimumMargins, side));
1959 1959 }
1960 1960 }
1961 setMargins(newMargins);
1961 setMargins(newMargins);
1962 1962 }
1963 1963 }
1964 1964 }
@@ -1972,7 +1972,7 void QCPLayoutElement::update(UpdatePhas
1972 1972 */
1973 1973 QSize QCPLayoutElement::minimumSizeHint() const
1974 1974 {
1975 return mMinimumSize;
1975 return mMinimumSize;
1976 1976 }
1977 1977
1978 1978 /*!
@@ -1984,7 +1984,7 QSize QCPLayoutElement::minimumSizeHint(
1984 1984 */
1985 1985 QSize QCPLayoutElement::maximumSizeHint() const
1986 1986 {
1987 return mMaximumSize;
1987 return mMaximumSize;
1988 1988 }
1989 1989
1990 1990 /*!
@@ -1996,8 +1996,8 QSize QCPLayoutElement::maximumSizeHint(
1996 1996 */
1997 1997 QList<QCPLayoutElement*> QCPLayoutElement::elements(bool recursive) const
1998 1998 {
1999 Q_UNUSED(recursive)
2000 return QList<QCPLayoutElement*>();
1999 Q_UNUSED(recursive)
2000 return QList<QCPLayoutElement*>();
2001 2001 }
2002 2002
2003 2003 /*!
@@ -2013,22 +2013,22 QList<QCPLayoutElement*> QCPLayoutElemen
2013 2013 */
2014 2014 double QCPLayoutElement::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
2015 2015 {
2016 Q_UNUSED(details)
2017
2018 if (onlySelectable)
2019 return -1;
2020
2021 if (QRectF(mOuterRect).contains(pos))
2022 {
2023 if (mParentPlot)
2024 return mParentPlot->selectionTolerance()*0.99;
2025 else
2026 {
2027 qDebug() << Q_FUNC_INFO << "parent plot not defined";
2028 return -1;
2029 }
2030 } else
2031 return -1;
2016 Q_UNUSED(details)
2017
2018 if (onlySelectable)
2019 return -1;
2020
2021 if (QRectF(mOuterRect).contains(pos))
2022 {
2023 if (mParentPlot)
2024 return mParentPlot->selectionTolerance()*0.99;
2025 else
2026 {
2027 qDebug() << Q_FUNC_INFO << "parent plot not defined";
2028 return -1;
2029 }
2030 } else
2031 return -1;
2032 2032 }
2033 2033
2034 2034 /*! \internal
@@ -2038,10 +2038,10 double QCPLayoutElement::selectTest(cons
2038 2038 */
2039 2039 void QCPLayoutElement::parentPlotInitialized(QCustomPlot *parentPlot)
2040 2040 {
2041 foreach (QCPLayoutElement* el, elements(false))
2042 {
2043 if (!el->parentPlot())
2044 el->initializeParentPlot(parentPlot);
2041 foreach (QCPLayoutElement* el, elements(false))
2042 {
2043 if (!el->parentPlot())
2044 el->initializeParentPlot(parentPlot);
2045 2045 }
2046 2046 }
2047 2047
@@ -2056,7 +2056,7 void QCPLayoutElement::parentPlotInitial
2056 2056 */
2057 2057 int QCPLayoutElement::calculateAutoMargin(QCP::MarginSide side)
2058 2058 {
2059 return qMax(QCP::getMarginValue(mMargins, side), QCP::getMarginValue(mMinimumMargins, side));
2059 return qMax(QCP::getMarginValue(mMargins, side), QCP::getMarginValue(mMinimumMargins, side));
2060 2060 }
2061 2061
2062 2062 ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -2150,40 +2150,40 QCPLayout::QCPLayout()
2150 2150 */
2151 2151 void QCPLayout::update(UpdatePhase phase)
2152 2152 {
2153 QCPLayoutElement::update(phase);
2154
2155 // set child element rects according to layout:
2156 if (phase == upLayout)
2157 updateLayout();
2158
2159 // propagate update call to child elements:
2160 const int elCount = elementCount();
2161 for (int i=0; i<elCount; ++i)
2162 {
2163 if (QCPLayoutElement *el = elementAt(i))
2164 el->update(phase);
2153 QCPLayoutElement::update(phase);
2154
2155 // set child element rects according to layout:
2156 if (phase == upLayout)
2157 updateLayout();
2158
2159 // propagate update call to child elements:
2160 const int elCount = elementCount();
2161 for (int i=0; i<elCount; ++i)
2162 {
2163 if (QCPLayoutElement *el = elementAt(i))
2164 el->update(phase);
2165 2165 }
2166 2166 }
2167 2167
2168 2168 /* inherits documentation from base class */
2169 2169 QList<QCPLayoutElement*> QCPLayout::elements(bool recursive) const
2170 2170 {
2171 const int c = elementCount();
2172 QList<QCPLayoutElement*> result;
2171 const int c = elementCount();
2172 QList<QCPLayoutElement*> result;
2173 2173 #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
2174 result.reserve(c);
2174 result.reserve(c);
2175 2175 #endif
2176 for (int i=0; i<c; ++i)
2177 result.append(elementAt(i));
2178 if (recursive)
2179 {
2180 for (int i=0; i<c; ++i)
2181 {
2182 if (result.at(i))
2183 result << result.at(i)->elements(recursive);
2184 }
2185 }
2186 return result;
2176 for (int i=0; i<c; ++i)
2177 result.append(elementAt(i));
2178 if (recursive)
2179 {
2180 for (int i=0; i<c; ++i)
2181 {
2182 if (result.at(i))
2183 result << result.at(i)->elements(recursive);
2184 }
2185 }
2186 return result;
2187 2187 }
2188 2188
2189 2189 /*!
@@ -2208,12 +2208,12 void QCPLayout::simplify()
2208 2208 */
2209 2209 bool QCPLayout::removeAt(int index)
2210 2210 {
2211 if (QCPLayoutElement *el = takeAt(index))
2212 {
2213 delete el;
2214 return true;
2215 } else
2216 return false;
2211 if (QCPLayoutElement *el = takeAt(index))
2212 {
2213 delete el;
2214 return true;
2215 } else
2216 return false;
2217 2217 }
2218 2218
2219 2219 /*!
@@ -2227,12 +2227,12 bool QCPLayout::removeAt(int index)
2227 2227 */
2228 2228 bool QCPLayout::remove(QCPLayoutElement *element)
2229 2229 {
2230 if (take(element))
2231 {
2232 delete element;
2233 return true;
2234 } else
2235 return false;
2230 if (take(element))
2231 {
2232 delete element;
2233 return true;
2234 } else
2235 return false;
2236 2236 }
2237 2237
2238 2238 /*!
@@ -2242,12 +2242,12 bool QCPLayout::remove(QCPLayoutElement
2242 2242 */
2243 2243 void QCPLayout::clear()
2244 2244 {
2245 for (int i=elementCount()-1; i>=0; --i)
2246 {
2247 if (elementAt(i))
2248 removeAt(i);
2249 }
2250 simplify();
2245 for (int i=elementCount()-1; i>=0; --i)
2246 {
2247 if (elementAt(i))
2248 removeAt(i);
2249 }
2250 simplify();
2251 2251 }
2252 2252
2253 2253 /*!
@@ -2260,10 +2260,10 void QCPLayout::clear()
2260 2260 */
2261 2261 void QCPLayout::sizeConstraintsChanged() const
2262 2262 {
2263 if (QWidget *w = qobject_cast<QWidget*>(parent()))
2264 w->updateGeometry();
2265 else if (QCPLayout *l = qobject_cast<QCPLayout*>(parent()))
2266 l->sizeConstraintsChanged();
2263 if (QWidget *w = qobject_cast<QWidget*>(parent()))
2264 w->updateGeometry();
2265 else if (QCPLayout *l = qobject_cast<QCPLayout*>(parent()))
2266 l->sizeConstraintsChanged();
2267 2267 }
2268 2268
2269 2269 /*! \internal
@@ -2297,15 +2297,15 void QCPLayout::updateLayout()
2297 2297 */
2298 2298 void QCPLayout::adoptElement(QCPLayoutElement *el)
2299 2299 {
2300 if (el)
2301 {
2302 el->mParentLayout = this;
2303 el->setParentLayerable(this);
2304 el->setParent(this);
2305 if (!el->parentPlot())
2306 el->initializeParentPlot(mParentPlot);
2307 } else
2308 qDebug() << Q_FUNC_INFO << "Null element passed";
2300 if (el)
2301 {
2302 el->mParentLayout = this;
2303 el->setParentLayerable(this);
2304 el->setParent(this);
2305 if (!el->parentPlot())
2306 el->initializeParentPlot(mParentPlot);
2307 } else
2308 qDebug() << Q_FUNC_INFO << "Null element passed";
2309 2309 }
2310 2310
2311 2311 /*! \internal
@@ -2320,14 +2320,14 void QCPLayout::adoptElement(QCPLayoutEl
2320 2320 */
2321 2321 void QCPLayout::releaseElement(QCPLayoutElement *el)
2322 2322 {
2323 if (el)
2324 {
2325 el->mParentLayout = 0;
2326 el->setParentLayerable(0);
2327 el->setParent(mParentPlot);
2328 // Note: Don't initializeParentPlot(0) here, because layout element will stay in same parent plot
2329 } else
2330 qDebug() << Q_FUNC_INFO << "Null element passed";
2323 if (el)
2324 {
2325 el->mParentLayout = 0;
2326 el->setParentLayerable(0);
2327 el->setParent(mParentPlot);
2328 // Note: Don't initializeParentPlot(0) here, because layout element will stay in same parent plot
2329 } else
2330 qDebug() << Q_FUNC_INFO << "Null element passed";
2331 2331 }
2332 2332
2333 2333 /*! \internal
@@ -2361,115 +2361,115 void QCPLayout::releaseElement(QCPLayout
2361 2361 */
2362 2362 QVector<int> QCPLayout::getSectionSizes(QVector<int> maxSizes, QVector<int> minSizes, QVector<double> stretchFactors, int totalSize) const
2363 2363 {
2364 if (maxSizes.size() != minSizes.size() || minSizes.size() != stretchFactors.size())
2365 {
2366 qDebug() << Q_FUNC_INFO << "Passed vector sizes aren't equal:" << maxSizes << minSizes << stretchFactors;
2367 return QVector<int>();
2368 }
2369 if (stretchFactors.isEmpty())
2370 return QVector<int>();
2371 int sectionCount = stretchFactors.size();
2372 QVector<double> sectionSizes(sectionCount);
2373 // if provided total size is forced smaller than total minimum size, ignore minimum sizes (squeeze sections):
2374 int minSizeSum = 0;
2375 for (int i=0; i<sectionCount; ++i)
2376 minSizeSum += minSizes.at(i);
2377 if (totalSize < minSizeSum)
2378 {
2379 // new stretch factors are minimum sizes and minimum sizes are set to zero:
2380 for (int i=0; i<sectionCount; ++i)
2381 {
2382 stretchFactors[i] = minSizes.at(i);
2383 minSizes[i] = 0;
2384 }
2385 }
2386
2387 QList<int> minimumLockedSections;
2388 QList<int> unfinishedSections;
2389 for (int i=0; i<sectionCount; ++i)
2390 unfinishedSections.append(i);
2391 double freeSize = totalSize;
2392
2393 int outerIterations = 0;
2394 while (!unfinishedSections.isEmpty() && outerIterations < sectionCount*2) // the iteration check ist just a failsafe in case something really strange happens
2395 {
2396 ++outerIterations;
2397 int innerIterations = 0;
2398 while (!unfinishedSections.isEmpty() && innerIterations < sectionCount*2) // the iteration check ist just a failsafe in case something really strange happens
2399 {
2400 ++innerIterations;
2401 // find section that hits its maximum next:
2402 int nextId = -1;
2403 double nextMax = 1e12;
2404 for (int i=0; i<unfinishedSections.size(); ++i)
2405 {
2406 int secId = unfinishedSections.at(i);
2407 double hitsMaxAt = (maxSizes.at(secId)-sectionSizes.at(secId))/stretchFactors.at(secId);
2408 if (hitsMaxAt < nextMax)
2364 if (maxSizes.size() != minSizes.size() || minSizes.size() != stretchFactors.size())
2365 {
2366 qDebug() << Q_FUNC_INFO << "Passed vector sizes aren't equal:" << maxSizes << minSizes << stretchFactors;
2367 return QVector<int>();
2368 }
2369 if (stretchFactors.isEmpty())
2370 return QVector<int>();
2371 int sectionCount = stretchFactors.size();
2372 QVector<double> sectionSizes(sectionCount);
2373 // if provided total size is forced smaller than total minimum size, ignore minimum sizes (squeeze sections):
2374 int minSizeSum = 0;
2375 for (int i=0; i<sectionCount; ++i)
2376 minSizeSum += minSizes.at(i);
2377 if (totalSize < minSizeSum)
2378 {
2379 // new stretch factors are minimum sizes and minimum sizes are set to zero:
2380 for (int i=0; i<sectionCount; ++i)
2381 {
2382 stretchFactors[i] = minSizes.at(i);
2383 minSizes[i] = 0;
2384 }
2385 }
2386
2387 QList<int> minimumLockedSections;
2388 QList<int> unfinishedSections;
2389 for (int i=0; i<sectionCount; ++i)
2390 unfinishedSections.append(i);
2391 double freeSize = totalSize;
2392
2393 int outerIterations = 0;
2394 while (!unfinishedSections.isEmpty() && outerIterations < sectionCount*2) // the iteration check ist just a failsafe in case something really strange happens
2395 {
2396 ++outerIterations;
2397 int innerIterations = 0;
2398 while (!unfinishedSections.isEmpty() && innerIterations < sectionCount*2) // the iteration check ist just a failsafe in case something really strange happens
2399 {
2400 ++innerIterations;
2401 // find section that hits its maximum next:
2402 int nextId = -1;
2403 double nextMax = 1e12;
2404 for (int i=0; i<unfinishedSections.size(); ++i)
2405 {
2406 int secId = unfinishedSections.at(i);
2407 double hitsMaxAt = (maxSizes.at(secId)-sectionSizes.at(secId))/stretchFactors.at(secId);
2408 if (hitsMaxAt < nextMax)
2409 2409 {
2410 nextMax = hitsMaxAt;
2411 nextId = secId;
2410 nextMax = hitsMaxAt;
2411 nextId = secId;
2412 2412 }
2413 2413 }
2414 // check if that maximum is actually within the bounds of the total size (i.e. can we stretch all remaining sections so far that the found section
2415 // actually hits its maximum, without exceeding the total size when we add up all sections)
2416 double stretchFactorSum = 0;
2417 for (int i=0; i<unfinishedSections.size(); ++i)
2418 stretchFactorSum += stretchFactors.at(unfinishedSections.at(i));
2419 double nextMaxLimit = freeSize/stretchFactorSum;
2420 if (nextMax < nextMaxLimit) // next maximum is actually hit, move forward to that point and fix the size of that section
2421 {
2422 for (int i=0; i<unfinishedSections.size(); ++i)
2414 // check if that maximum is actually within the bounds of the total size (i.e. can we stretch all remaining sections so far that the found section
2415 // actually hits its maximum, without exceeding the total size when we add up all sections)
2416 double stretchFactorSum = 0;
2417 for (int i=0; i<unfinishedSections.size(); ++i)
2418 stretchFactorSum += stretchFactors.at(unfinishedSections.at(i));
2419 double nextMaxLimit = freeSize/stretchFactorSum;
2420 if (nextMax < nextMaxLimit) // next maximum is actually hit, move forward to that point and fix the size of that section
2421 {
2422 for (int i=0; i<unfinishedSections.size(); ++i)
2423 2423 {
2424 sectionSizes[unfinishedSections.at(i)] += nextMax*stretchFactors.at(unfinishedSections.at(i)); // increment all sections
2425 freeSize -= nextMax*stretchFactors.at(unfinishedSections.at(i));
2424 sectionSizes[unfinishedSections.at(i)] += nextMax*stretchFactors.at(unfinishedSections.at(i)); // increment all sections
2425 freeSize -= nextMax*stretchFactors.at(unfinishedSections.at(i));
2426 2426 }
2427 unfinishedSections.removeOne(nextId); // exclude the section that is now at maximum from further changes
2427 unfinishedSections.removeOne(nextId); // exclude the section that is now at maximum from further changes
2428 2428 } else // next maximum isn't hit, just distribute rest of free space on remaining sections
2429 2429 {
2430 for (int i=0; i<unfinishedSections.size(); ++i)
2431 sectionSizes[unfinishedSections.at(i)] += nextMaxLimit*stretchFactors.at(unfinishedSections.at(i)); // increment all sections
2432 unfinishedSections.clear();
2433 }
2434 }
2435 if (innerIterations == sectionCount*2)
2436 qDebug() << Q_FUNC_INFO << "Exceeded maximum expected inner iteration count, layouting aborted. Input was:" << maxSizes << minSizes << stretchFactors << totalSize;
2437
2438 // now check whether the resulting section sizes violate minimum restrictions:
2439 bool foundMinimumViolation = false;
2440 for (int i=0; i<sectionSizes.size(); ++i)
2441 {
2442 if (minimumLockedSections.contains(i))
2443 continue;
2444 if (sectionSizes.at(i) < minSizes.at(i)) // section violates minimum
2445 {
2446 sectionSizes[i] = minSizes.at(i); // set it to minimum
2447 foundMinimumViolation = true; // make sure we repeat the whole optimization process
2448 minimumLockedSections.append(i);
2449 }
2450 }
2451 if (foundMinimumViolation)
2452 {
2453 freeSize = totalSize;
2454 for (int i=0; i<sectionCount; ++i)
2455 {
2456 if (!minimumLockedSections.contains(i)) // only put sections that haven't hit their minimum back into the pool
2457 unfinishedSections.append(i);
2458 else
2459 freeSize -= sectionSizes.at(i); // remove size of minimum locked sections from available space in next round
2460 }
2461 // reset all section sizes to zero that are in unfinished sections (all others have been set to their minimum):
2462 for (int i=0; i<unfinishedSections.size(); ++i)
2463 sectionSizes[unfinishedSections.at(i)] = 0;
2464 }
2465 }
2466 if (outerIterations == sectionCount*2)
2467 qDebug() << Q_FUNC_INFO << "Exceeded maximum expected outer iteration count, layouting aborted. Input was:" << maxSizes << minSizes << stretchFactors << totalSize;
2468
2469 QVector<int> result(sectionCount);
2470 for (int i=0; i<sectionCount; ++i)
2471 result[i] = qRound(sectionSizes.at(i));
2472 return result;
2430 for (int i=0; i<unfinishedSections.size(); ++i)
2431 sectionSizes[unfinishedSections.at(i)] += nextMaxLimit*stretchFactors.at(unfinishedSections.at(i)); // increment all sections
2432 unfinishedSections.clear();
2433 }
2434 }
2435 if (innerIterations == sectionCount*2)
2436 qDebug() << Q_FUNC_INFO << "Exceeded maximum expected inner iteration count, layouting aborted. Input was:" << maxSizes << minSizes << stretchFactors << totalSize;
2437
2438 // now check whether the resulting section sizes violate minimum restrictions:
2439 bool foundMinimumViolation = false;
2440 for (int i=0; i<sectionSizes.size(); ++i)
2441 {
2442 if (minimumLockedSections.contains(i))
2443 continue;
2444 if (sectionSizes.at(i) < minSizes.at(i)) // section violates minimum
2445 {
2446 sectionSizes[i] = minSizes.at(i); // set it to minimum
2447 foundMinimumViolation = true; // make sure we repeat the whole optimization process
2448 minimumLockedSections.append(i);
2449 }
2450 }
2451 if (foundMinimumViolation)
2452 {
2453 freeSize = totalSize;
2454 for (int i=0; i<sectionCount; ++i)
2455 {
2456 if (!minimumLockedSections.contains(i)) // only put sections that haven't hit their minimum back into the pool
2457 unfinishedSections.append(i);
2458 else
2459 freeSize -= sectionSizes.at(i); // remove size of minimum locked sections from available space in next round
2460 }
2461 // reset all section sizes to zero that are in unfinished sections (all others have been set to their minimum):
2462 for (int i=0; i<unfinishedSections.size(); ++i)
2463 sectionSizes[unfinishedSections.at(i)] = 0;
2464 }
2465 }
2466 if (outerIterations == sectionCount*2)
2467 qDebug() << Q_FUNC_INFO << "Exceeded maximum expected outer iteration count, layouting aborted. Input was:" << maxSizes << minSizes << stretchFactors << totalSize;
2468
2469 QVector<int> result(sectionCount);
2470 for (int i=0; i<sectionCount; ++i)
2471 result[i] = qRound(sectionSizes.at(i));
2472 return result;
2473 2473 }
2474 2474
2475 2475
@@ -2497,16 +2497,16 QVector<int> QCPLayout::getSectionSizes(
2497 2497 Creates an instance of QCPLayoutGrid and sets default values.
2498 2498 */
2499 2499 QCPLayoutGrid::QCPLayoutGrid() :
2500 mColumnSpacing(5),
2501 mRowSpacing(5)
2500 mColumnSpacing(5),
2501 mRowSpacing(5)
2502 2502 {
2503 2503 }
2504 2504
2505 2505 QCPLayoutGrid::~QCPLayoutGrid()
2506 2506 {
2507 // clear all child layout elements. This is important because only the specific layouts know how
2508 // to handle removing elements (clear calls virtual removeAt method to do that).
2509 clear();
2507 // clear all child layout elements. This is important because only the specific layouts know how
2508 // to handle removing elements (clear calls virtual removeAt method to do that).
2509 clear();
2510 2510 }
2511 2511
2512 2512 /*!
@@ -2519,19 +2519,19 QCPLayoutGrid::~QCPLayoutGrid()
2519 2519 */
2520 2520 QCPLayoutElement *QCPLayoutGrid::element(int row, int column) const
2521 2521 {
2522 if (row >= 0 && row < mElements.size())
2523 {
2524 if (column >= 0 && column < mElements.first().size())
2525 {
2526 if (QCPLayoutElement *result = mElements.at(row).at(column))
2527 return result;
2528 else
2529 qDebug() << Q_FUNC_INFO << "Requested cell is empty. Row:" << row << "Column:" << column;
2522 if (row >= 0 && row < mElements.size())
2523 {
2524 if (column >= 0 && column < mElements.first().size())
2525 {
2526 if (QCPLayoutElement *result = mElements.at(row).at(column))
2527 return result;
2528 else
2529 qDebug() << Q_FUNC_INFO << "Requested cell is empty. Row:" << row << "Column:" << column;
2530 2530 } else
2531 qDebug() << Q_FUNC_INFO << "Invalid column. Row:" << row << "Column:" << column;
2532 } else
2533 qDebug() << Q_FUNC_INFO << "Invalid row. Row:" << row << "Column:" << column;
2534 return 0;
2531 qDebug() << Q_FUNC_INFO << "Invalid column. Row:" << row << "Column:" << column;
2532 } else
2533 qDebug() << Q_FUNC_INFO << "Invalid row. Row:" << row << "Column:" << column;
2534 return 0;
2535 2535 }
2536 2536
2537 2537 /*!
@@ -2541,7 +2541,7 QCPLayoutElement *QCPLayoutGrid::element
2541 2541 */
2542 2542 int QCPLayoutGrid::rowCount() const
2543 2543 {
2544 return mElements.size();
2544 return mElements.size();
2545 2545 }
2546 2546
2547 2547 /*!
@@ -2551,10 +2551,10 int QCPLayoutGrid::rowCount() const
2551 2551 */
2552 2552 int QCPLayoutGrid::columnCount() const
2553 2553 {
2554 if (mElements.size() > 0)
2555 return mElements.first().size();
2556 else
2557 return 0;
2554 if (mElements.size() > 0)
2555 return mElements.first().size();
2556 else
2557 return 0;
2558 2558 }
2559 2559
2560 2560 /*!
@@ -2569,21 +2569,21 int QCPLayoutGrid::columnCount() const
2569 2569 */
2570 2570 bool QCPLayoutGrid::addElement(int row, int column, QCPLayoutElement *element)
2571 2571 {
2572 if (element)
2573 {
2574 if (!hasElement(row, column))
2575 {
2576 if (element->layout()) // remove from old layout first
2577 element->layout()->take(element);
2578 expandTo(row+1, column+1);
2579 mElements[row][column] = element;
2580 adoptElement(element);
2581 return true;
2572 if (element)
2573 {
2574 if (!hasElement(row, column))
2575 {
2576 if (element->layout()) // remove from old layout first
2577 element->layout()->take(element);
2578 expandTo(row+1, column+1);
2579 mElements[row][column] = element;
2580 adoptElement(element);
2581 return true;
2582 2582 } else
2583 qDebug() << Q_FUNC_INFO << "There is already an element in the specified row/column:" << row << column;
2584 } else
2585 qDebug() << Q_FUNC_INFO << "Can't add null element to row/column:" << row << column;
2586 return false;
2583 qDebug() << Q_FUNC_INFO << "There is already an element in the specified row/column:" << row << column;
2584 } else
2585 qDebug() << Q_FUNC_INFO << "Can't add null element to row/column:" << row << column;
2586 return false;
2587 2587 }
2588 2588
2589 2589 /*!
@@ -2594,10 +2594,10 bool QCPLayoutGrid::addElement(int row,
2594 2594 */
2595 2595 bool QCPLayoutGrid::hasElement(int row, int column)
2596 2596 {
2597 if (row >= 0 && row < rowCount() && column >= 0 && column < columnCount())
2598 return mElements.at(row).at(column);
2599 else
2600 return false;
2597 if (row >= 0 && row < rowCount() && column >= 0 && column < columnCount())
2598 return mElements.at(row).at(column);
2599 else
2600 return false;
2601 2601 }
2602 2602
2603 2603 /*!
@@ -2613,14 +2613,14 bool QCPLayoutGrid::hasElement(int row,
2613 2613 */
2614 2614 void QCPLayoutGrid::setColumnStretchFactor(int column, double factor)
2615 2615 {
2616 if (column >= 0 && column < columnCount())
2617 {
2618 if (factor > 0)
2619 mColumnStretchFactors[column] = factor;
2620 else
2621 qDebug() << Q_FUNC_INFO << "Invalid stretch factor, must be positive:" << factor;
2622 } else
2623 qDebug() << Q_FUNC_INFO << "Invalid column:" << column;
2616 if (column >= 0 && column < columnCount())
2617 {
2618 if (factor > 0)
2619 mColumnStretchFactors[column] = factor;
2620 else
2621 qDebug() << Q_FUNC_INFO << "Invalid stretch factor, must be positive:" << factor;
2622 } else
2623 qDebug() << Q_FUNC_INFO << "Invalid column:" << column;
2624 2624 }
2625 2625
2626 2626 /*!
@@ -2636,19 +2636,19 void QCPLayoutGrid::setColumnStretchFact
2636 2636 */
2637 2637 void QCPLayoutGrid::setColumnStretchFactors(const QList<double> &factors)
2638 2638 {
2639 if (factors.size() == mColumnStretchFactors.size())
2640 {
2641 mColumnStretchFactors = factors;
2642 for (int i=0; i<mColumnStretchFactors.size(); ++i)
2643 {
2644 if (mColumnStretchFactors.at(i) <= 0)
2645 {
2646 qDebug() << Q_FUNC_INFO << "Invalid stretch factor, must be positive:" << mColumnStretchFactors.at(i);
2647 mColumnStretchFactors[i] = 1;
2648 }
2649 }
2650 } else
2651 qDebug() << Q_FUNC_INFO << "Column count not equal to passed stretch factor count:" << factors;
2639 if (factors.size() == mColumnStretchFactors.size())
2640 {
2641 mColumnStretchFactors = factors;
2642 for (int i=0; i<mColumnStretchFactors.size(); ++i)
2643 {
2644 if (mColumnStretchFactors.at(i) <= 0)
2645 {
2646 qDebug() << Q_FUNC_INFO << "Invalid stretch factor, must be positive:" << mColumnStretchFactors.at(i);
2647 mColumnStretchFactors[i] = 1;
2648 }
2649 }
2650 } else
2651 qDebug() << Q_FUNC_INFO << "Column count not equal to passed stretch factor count:" << factors;
2652 2652 }
2653 2653
2654 2654 /*!
@@ -2664,14 +2664,14 void QCPLayoutGrid::setColumnStretchFact
2664 2664 */
2665 2665 void QCPLayoutGrid::setRowStretchFactor(int row, double factor)
2666 2666 {
2667 if (row >= 0 && row < rowCount())
2668 {
2669 if (factor > 0)
2670 mRowStretchFactors[row] = factor;
2671 else
2672 qDebug() << Q_FUNC_INFO << "Invalid stretch factor, must be positive:" << factor;
2673 } else
2674 qDebug() << Q_FUNC_INFO << "Invalid row:" << row;
2667 if (row >= 0 && row < rowCount())
2668 {
2669 if (factor > 0)
2670 mRowStretchFactors[row] = factor;
2671 else
2672 qDebug() << Q_FUNC_INFO << "Invalid stretch factor, must be positive:" << factor;
2673 } else
2674 qDebug() << Q_FUNC_INFO << "Invalid row:" << row;
2675 2675 }
2676 2676
2677 2677 /*!
@@ -2687,19 +2687,19 void QCPLayoutGrid::setRowStretchFactor(
2687 2687 */
2688 2688 void QCPLayoutGrid::setRowStretchFactors(const QList<double> &factors)
2689 2689 {
2690 if (factors.size() == mRowStretchFactors.size())
2691 {
2692 mRowStretchFactors = factors;
2693 for (int i=0; i<mRowStretchFactors.size(); ++i)
2694 {
2695 if (mRowStretchFactors.at(i) <= 0)
2696 {
2697 qDebug() << Q_FUNC_INFO << "Invalid stretch factor, must be positive:" << mRowStretchFactors.at(i);
2698 mRowStretchFactors[i] = 1;
2699 }
2700 }
2701 } else
2702 qDebug() << Q_FUNC_INFO << "Row count not equal to passed stretch factor count:" << factors;
2690 if (factors.size() == mRowStretchFactors.size())
2691 {
2692 mRowStretchFactors = factors;
2693 for (int i=0; i<mRowStretchFactors.size(); ++i)
2694 {
2695 if (mRowStretchFactors.at(i) <= 0)
2696 {
2697 qDebug() << Q_FUNC_INFO << "Invalid stretch factor, must be positive:" << mRowStretchFactors.at(i);
2698 mRowStretchFactors[i] = 1;
2699 }
2700 }
2701 } else
2702 qDebug() << Q_FUNC_INFO << "Row count not equal to passed stretch factor count:" << factors;
2703 2703 }
2704 2704
2705 2705 /*!
@@ -2709,7 +2709,7 void QCPLayoutGrid::setRowStretchFactors
2709 2709 */
2710 2710 void QCPLayoutGrid::setColumnSpacing(int pixels)
2711 2711 {
2712 mColumnSpacing = pixels;
2712 mColumnSpacing = pixels;
2713 2713 }
2714 2714
2715 2715 /*!
@@ -2719,7 +2719,7 void QCPLayoutGrid::setColumnSpacing(int
2719 2719 */
2720 2720 void QCPLayoutGrid::setRowSpacing(int pixels)
2721 2721 {
2722 mRowSpacing = pixels;
2722 mRowSpacing = pixels;
2723 2723 }
2724 2724
2725 2725 /*!
@@ -2738,21 +2738,21 void QCPLayoutGrid::setRowSpacing(int pi
2738 2738 */
2739 2739 void QCPLayoutGrid::expandTo(int newRowCount, int newColumnCount)
2740 2740 {
2741 // add rows as necessary:
2742 while (rowCount() < newRowCount)
2743 {
2744 mElements.append(QList<QCPLayoutElement*>());
2745 mRowStretchFactors.append(1);
2746 }
2747 // go through rows and expand columns as necessary:
2748 int newColCount = qMax(columnCount(), newColumnCount);
2749 for (int i=0; i<rowCount(); ++i)
2750 {
2751 while (mElements.at(i).size() < newColCount)
2752 mElements[i].append(0);
2753 }
2754 while (mColumnStretchFactors.size() < newColCount)
2755 mColumnStretchFactors.append(1);
2741 // add rows as necessary:
2742 while (rowCount() < newRowCount)
2743 {
2744 mElements.append(QList<QCPLayoutElement*>());
2745 mRowStretchFactors.append(1);
2746 }
2747 // go through rows and expand columns as necessary:
2748 int newColCount = qMax(columnCount(), newColumnCount);
2749 for (int i=0; i<rowCount(); ++i)
2750 {
2751 while (mElements.at(i).size() < newColCount)
2752 mElements[i].append(0);
2753 }
2754 while (mColumnStretchFactors.size() < newColCount)
2755 mColumnStretchFactors.append(1);
2756 2756 }
2757 2757
2758 2758 /*!
@@ -2763,22 +2763,22 void QCPLayoutGrid::expandTo(int newRowC
2763 2763 */
2764 2764 void QCPLayoutGrid::insertRow(int newIndex)
2765 2765 {
2766 if (mElements.isEmpty() || mElements.first().isEmpty()) // if grid is completely empty, add first cell
2767 {
2768 expandTo(1, 1);
2769 return;
2770 }
2771
2772 if (newIndex < 0)
2773 newIndex = 0;
2774 if (newIndex > rowCount())
2775 newIndex = rowCount();
2776
2777 mRowStretchFactors.insert(newIndex, 1);
2778 QList<QCPLayoutElement*> newRow;
2779 for (int col=0; col<columnCount(); ++col)
2780 newRow.append((QCPLayoutElement*)0);
2781 mElements.insert(newIndex, newRow);
2766 if (mElements.isEmpty() || mElements.first().isEmpty()) // if grid is completely empty, add first cell
2767 {
2768 expandTo(1, 1);
2769 return;
2770 }
2771
2772 if (newIndex < 0)
2773 newIndex = 0;
2774 if (newIndex > rowCount())
2775 newIndex = rowCount();
2776
2777 mRowStretchFactors.insert(newIndex, 1);
2778 QList<QCPLayoutElement*> newRow;
2779 for (int col=0; col<columnCount(); ++col)
2780 newRow.append((QCPLayoutElement*)0);
2781 mElements.insert(newIndex, newRow);
2782 2782 }
2783 2783
2784 2784 /*!
@@ -2789,47 +2789,47 void QCPLayoutGrid::insertRow(int newInd
2789 2789 */
2790 2790 void QCPLayoutGrid::insertColumn(int newIndex)
2791 2791 {
2792 if (mElements.isEmpty() || mElements.first().isEmpty()) // if grid is completely empty, add first cell
2793 {
2794 expandTo(1, 1);
2795 return;
2796 }
2797
2798 if (newIndex < 0)
2799 newIndex = 0;
2800 if (newIndex > columnCount())
2801 newIndex = columnCount();
2802
2803 mColumnStretchFactors.insert(newIndex, 1);
2804 for (int row=0; row<rowCount(); ++row)
2805 mElements[row].insert(newIndex, (QCPLayoutElement*)0);
2792 if (mElements.isEmpty() || mElements.first().isEmpty()) // if grid is completely empty, add first cell
2793 {
2794 expandTo(1, 1);
2795 return;
2796 }
2797
2798 if (newIndex < 0)
2799 newIndex = 0;
2800 if (newIndex > columnCount())
2801 newIndex = columnCount();
2802
2803 mColumnStretchFactors.insert(newIndex, 1);
2804 for (int row=0; row<rowCount(); ++row)
2805 mElements[row].insert(newIndex, (QCPLayoutElement*)0);
2806 2806 }
2807 2807
2808 2808 /* inherits documentation from base class */
2809 2809 void QCPLayoutGrid::updateLayout()
2810 2810 {
2811 QVector<int> minColWidths, minRowHeights, maxColWidths, maxRowHeights;
2812 getMinimumRowColSizes(&minColWidths, &minRowHeights);
2813 getMaximumRowColSizes(&maxColWidths, &maxRowHeights);
2814
2815 int totalRowSpacing = (rowCount()-1) * mRowSpacing;
2816 int totalColSpacing = (columnCount()-1) * mColumnSpacing;
2817 QVector<int> colWidths = getSectionSizes(maxColWidths, minColWidths, mColumnStretchFactors.toVector(), mRect.width()-totalColSpacing);
2818 QVector<int> rowHeights = getSectionSizes(maxRowHeights, minRowHeights, mRowStretchFactors.toVector(), mRect.height()-totalRowSpacing);
2819
2820 // go through cells and set rects accordingly:
2821 int yOffset = mRect.top();
2822 for (int row=0; row<rowCount(); ++row)
2823 {
2824 if (row > 0)
2825 yOffset += rowHeights.at(row-1)+mRowSpacing;
2826 int xOffset = mRect.left();
2827 for (int col=0; col<columnCount(); ++col)
2828 {
2829 if (col > 0)
2830 xOffset += colWidths.at(col-1)+mColumnSpacing;
2831 if (mElements.at(row).at(col))
2832 mElements.at(row).at(col)->setOuterRect(QRect(xOffset, yOffset, colWidths.at(col), rowHeights.at(row)));
2811 QVector<int> minColWidths, minRowHeights, maxColWidths, maxRowHeights;
2812 getMinimumRowColSizes(&minColWidths, &minRowHeights);
2813 getMaximumRowColSizes(&maxColWidths, &maxRowHeights);
2814
2815 int totalRowSpacing = (rowCount()-1) * mRowSpacing;
2816 int totalColSpacing = (columnCount()-1) * mColumnSpacing;
2817 QVector<int> colWidths = getSectionSizes(maxColWidths, minColWidths, mColumnStretchFactors.toVector(), mRect.width()-totalColSpacing);
2818 QVector<int> rowHeights = getSectionSizes(maxRowHeights, minRowHeights, mRowStretchFactors.toVector(), mRect.height()-totalRowSpacing);
2819
2820 // go through cells and set rects accordingly:
2821 int yOffset = mRect.top();
2822 for (int row=0; row<rowCount(); ++row)
2823 {
2824 if (row > 0)
2825 yOffset += rowHeights.at(row-1)+mRowSpacing;
2826 int xOffset = mRect.left();
2827 for (int col=0; col<columnCount(); ++col)
2828 {
2829 if (col > 0)
2830 xOffset += colWidths.at(col-1)+mColumnSpacing;
2831 if (mElements.at(row).at(col))
2832 mElements.at(row).at(col)->setOuterRect(QRect(xOffset, yOffset, colWidths.at(col), rowHeights.at(row)));
2833 2833 }
2834 2834 }
2835 2835 }
@@ -2837,78 +2837,78 void QCPLayoutGrid::updateLayout()
2837 2837 /* inherits documentation from base class */
2838 2838 int QCPLayoutGrid::elementCount() const
2839 2839 {
2840 return rowCount()*columnCount();
2840 return rowCount()*columnCount();
2841 2841 }
2842 2842
2843 2843 /* inherits documentation from base class */
2844 2844 QCPLayoutElement *QCPLayoutGrid::elementAt(int index) const
2845 2845 {
2846 if (index >= 0 && index < elementCount())
2847 return mElements.at(index / columnCount()).at(index % columnCount());
2848 else
2849 return 0;
2846 if (index >= 0 && index < elementCount())
2847 return mElements.at(index / columnCount()).at(index % columnCount());
2848 else
2849 return 0;
2850 2850 }
2851 2851
2852 2852 /* inherits documentation from base class */
2853 2853 QCPLayoutElement *QCPLayoutGrid::takeAt(int index)
2854 2854 {
2855 if (QCPLayoutElement *el = elementAt(index))
2856 {
2857 releaseElement(el);
2858 mElements[index / columnCount()][index % columnCount()] = 0;
2859 return el;
2860 } else
2861 {
2862 qDebug() << Q_FUNC_INFO << "Attempt to take invalid index:" << index;
2863 return 0;
2855 if (QCPLayoutElement *el = elementAt(index))
2856 {
2857 releaseElement(el);
2858 mElements[index / columnCount()][index % columnCount()] = 0;
2859 return el;
2860 } else
2861 {
2862 qDebug() << Q_FUNC_INFO << "Attempt to take invalid index:" << index;
2863 return 0;
2864 2864 }
2865 2865 }
2866 2866
2867 2867 /* inherits documentation from base class */
2868 2868 bool QCPLayoutGrid::take(QCPLayoutElement *element)
2869 2869 {
2870 if (element)
2871 {
2872 for (int i=0; i<elementCount(); ++i)
2873 {
2874 if (elementAt(i) == element)
2875 {
2876 takeAt(i);
2877 return true;
2878 }
2879 }
2880 qDebug() << Q_FUNC_INFO << "Element not in this layout, couldn't take";
2881 } else
2882 qDebug() << Q_FUNC_INFO << "Can't take null element";
2883 return false;
2870 if (element)
2871 {
2872 for (int i=0; i<elementCount(); ++i)
2873 {
2874 if (elementAt(i) == element)
2875 {
2876 takeAt(i);
2877 return true;
2878 }
2879 }
2880 qDebug() << Q_FUNC_INFO << "Element not in this layout, couldn't take";
2881 } else
2882 qDebug() << Q_FUNC_INFO << "Can't take null element";
2883 return false;
2884 2884 }
2885 2885
2886 2886 /* inherits documentation from base class */
2887 2887 QList<QCPLayoutElement*> QCPLayoutGrid::elements(bool recursive) const
2888 2888 {
2889 QList<QCPLayoutElement*> result;
2890 int colC = columnCount();
2891 int rowC = rowCount();
2889 QList<QCPLayoutElement*> result;
2890 int colC = columnCount();
2891 int rowC = rowCount();
2892 2892 #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
2893 result.reserve(colC*rowC);
2893 result.reserve(colC*rowC);
2894 2894 #endif
2895 for (int row=0; row<rowC; ++row)
2896 {
2897 for (int col=0; col<colC; ++col)
2898 {
2899 result.append(mElements.at(row).at(col));
2900 }
2901 }
2902 if (recursive)
2903 {
2904 int c = result.size();
2905 for (int i=0; i<c; ++i)
2906 {
2907 if (result.at(i))
2908 result << result.at(i)->elements(recursive);
2909 }
2910 }
2911 return result;
2895 for (int row=0; row<rowC; ++row)
2896 {
2897 for (int col=0; col<colC; ++col)
2898 {
2899 result.append(mElements.at(row).at(col));
2900 }
2901 }
2902 if (recursive)
2903 {
2904 int c = result.size();
2905 for (int i=0; i<c; ++i)
2906 {
2907 if (result.at(i))
2908 result << result.at(i)->elements(recursive);
2909 }
2910 }
2911 return result;
2912 2912 }
2913 2913
2914 2914 /*!
@@ -2916,44 +2916,44 QList<QCPLayoutElement*> QCPLayoutGrid::
2916 2916 */
2917 2917 void QCPLayoutGrid::simplify()
2918 2918 {
2919 // remove rows with only empty cells:
2920 for (int row=rowCount()-1; row>=0; --row)
2921 {
2922 bool hasElements = false;
2923 for (int col=0; col<columnCount(); ++col)
2924 {
2925 if (mElements.at(row).at(col))
2926 {
2927 hasElements = true;
2928 break;
2929 }
2930 }
2931 if (!hasElements)
2932 {
2933 mRowStretchFactors.removeAt(row);
2934 mElements.removeAt(row);
2935 if (mElements.isEmpty()) // removed last element, also remove stretch factor (wouldn't happen below because also columnCount changed to 0 now)
2936 mColumnStretchFactors.clear();
2937 }
2938 }
2939
2940 // remove columns with only empty cells:
2941 for (int col=columnCount()-1; col>=0; --col)
2942 {
2943 bool hasElements = false;
2944 for (int row=0; row<rowCount(); ++row)
2945 {
2946 if (mElements.at(row).at(col))
2947 {
2948 hasElements = true;
2949 break;
2950 }
2951 }
2952 if (!hasElements)
2953 {
2954 mColumnStretchFactors.removeAt(col);
2955 for (int row=0; row<rowCount(); ++row)
2956 mElements[row].removeAt(col);
2919 // remove rows with only empty cells:
2920 for (int row=rowCount()-1; row>=0; --row)
2921 {
2922 bool hasElements = false;
2923 for (int col=0; col<columnCount(); ++col)
2924 {
2925 if (mElements.at(row).at(col))
2926 {
2927 hasElements = true;
2928 break;
2929 }
2930 }
2931 if (!hasElements)
2932 {
2933 mRowStretchFactors.removeAt(row);
2934 mElements.removeAt(row);
2935 if (mElements.isEmpty()) // removed last element, also remove stretch factor (wouldn't happen below because also columnCount changed to 0 now)
2936 mColumnStretchFactors.clear();
2937 }
2938 }
2939
2940 // remove columns with only empty cells:
2941 for (int col=columnCount()-1; col>=0; --col)
2942 {
2943 bool hasElements = false;
2944 for (int row=0; row<rowCount(); ++row)
2945 {
2946 if (mElements.at(row).at(col))
2947 {
2948 hasElements = true;
2949 break;
2950 }
2951 }
2952 if (!hasElements)
2953 {
2954 mColumnStretchFactors.removeAt(col);
2955 for (int row=0; row<rowCount(); ++row)
2956 mElements[row].removeAt(col);
2957 2957 }
2958 2958 }
2959 2959 }
@@ -2961,32 +2961,32 void QCPLayoutGrid::simplify()
2961 2961 /* inherits documentation from base class */
2962 2962 QSize QCPLayoutGrid::minimumSizeHint() const
2963 2963 {
2964 QVector<int> minColWidths, minRowHeights;
2965 getMinimumRowColSizes(&minColWidths, &minRowHeights);
2966 QSize result(0, 0);
2967 for (int i=0; i<minColWidths.size(); ++i)
2968 result.rwidth() += minColWidths.at(i);
2969 for (int i=0; i<minRowHeights.size(); ++i)
2970 result.rheight() += minRowHeights.at(i);
2971 result.rwidth() += qMax(0, columnCount()-1) * mColumnSpacing + mMargins.left() + mMargins.right();
2972 result.rheight() += qMax(0, rowCount()-1) * mRowSpacing + mMargins.top() + mMargins.bottom();
2973 return result;
2964 QVector<int> minColWidths, minRowHeights;
2965 getMinimumRowColSizes(&minColWidths, &minRowHeights);
2966 QSize result(0, 0);
2967 for (int i=0; i<minColWidths.size(); ++i)
2968 result.rwidth() += minColWidths.at(i);
2969 for (int i=0; i<minRowHeights.size(); ++i)
2970 result.rheight() += minRowHeights.at(i);
2971 result.rwidth() += qMax(0, columnCount()-1) * mColumnSpacing + mMargins.left() + mMargins.right();
2972 result.rheight() += qMax(0, rowCount()-1) * mRowSpacing + mMargins.top() + mMargins.bottom();
2973 return result;
2974 2974 }
2975 2975
2976 2976 /* inherits documentation from base class */
2977 2977 QSize QCPLayoutGrid::maximumSizeHint() const
2978 2978 {
2979 QVector<int> maxColWidths, maxRowHeights;
2980 getMaximumRowColSizes(&maxColWidths, &maxRowHeights);
2981
2982 QSize result(0, 0);
2983 for (int i=0; i<maxColWidths.size(); ++i)
2984 result.setWidth(qMin(result.width()+maxColWidths.at(i), QWIDGETSIZE_MAX));
2985 for (int i=0; i<maxRowHeights.size(); ++i)
2986 result.setHeight(qMin(result.height()+maxRowHeights.at(i), QWIDGETSIZE_MAX));
2987 result.rwidth() += qMax(0, columnCount()-1) * mColumnSpacing + mMargins.left() + mMargins.right();
2988 result.rheight() += qMax(0, rowCount()-1) * mRowSpacing + mMargins.top() + mMargins.bottom();
2989 return result;
2979 QVector<int> maxColWidths, maxRowHeights;
2980 getMaximumRowColSizes(&maxColWidths, &maxRowHeights);
2981
2982 QSize result(0, 0);
2983 for (int i=0; i<maxColWidths.size(); ++i)
2984 result.setWidth(qMin(result.width()+maxColWidths.at(i), QWIDGETSIZE_MAX));
2985 for (int i=0; i<maxRowHeights.size(); ++i)
2986 result.setHeight(qMin(result.height()+maxRowHeights.at(i), QWIDGETSIZE_MAX));
2987 result.rwidth() += qMax(0, columnCount()-1) * mColumnSpacing + mMargins.left() + mMargins.right();
2988 result.rheight() += qMax(0, rowCount()-1) * mRowSpacing + mMargins.top() + mMargins.bottom();
2989 return result;
2990 2990 }
2991 2991
2992 2992 /*! \internal
@@ -3003,21 +3003,21 QSize QCPLayoutGrid::maximumSizeHint() c
3003 3003 */
3004 3004 void QCPLayoutGrid::getMinimumRowColSizes(QVector<int> *minColWidths, QVector<int> *minRowHeights) const
3005 3005 {
3006 *minColWidths = QVector<int>(columnCount(), 0);
3007 *minRowHeights = QVector<int>(rowCount(), 0);
3008 for (int row=0; row<rowCount(); ++row)
3009 {
3010 for (int col=0; col<columnCount(); ++col)
3011 {
3012 if (mElements.at(row).at(col))
3013 {
3014 QSize minHint = mElements.at(row).at(col)->minimumSizeHint();
3015 QSize min = mElements.at(row).at(col)->minimumSize();
3016 QSize final(min.width() > 0 ? min.width() : minHint.width(), min.height() > 0 ? min.height() : minHint.height());
3017 if (minColWidths->at(col) < final.width())
3018 (*minColWidths)[col] = final.width();
3019 if (minRowHeights->at(row) < final.height())
3020 (*minRowHeights)[row] = final.height();
3006 *minColWidths = QVector<int>(columnCount(), 0);
3007 *minRowHeights = QVector<int>(rowCount(), 0);
3008 for (int row=0; row<rowCount(); ++row)
3009 {
3010 for (int col=0; col<columnCount(); ++col)
3011 {
3012 if (mElements.at(row).at(col))
3013 {
3014 QSize minHint = mElements.at(row).at(col)->minimumSizeHint();
3015 QSize min = mElements.at(row).at(col)->minimumSize();
3016 QSize final(min.width() > 0 ? min.width() : minHint.width(), min.height() > 0 ? min.height() : minHint.height());
3017 if (minColWidths->at(col) < final.width())
3018 (*minColWidths)[col] = final.width();
3019 if (minRowHeights->at(row) < final.height())
3020 (*minRowHeights)[row] = final.height();
3021 3021 }
3022 3022 }
3023 3023 }
@@ -3037,21 +3037,21 void QCPLayoutGrid::getMinimumRowColSize
3037 3037 */
3038 3038 void QCPLayoutGrid::getMaximumRowColSizes(QVector<int> *maxColWidths, QVector<int> *maxRowHeights) const
3039 3039 {
3040 *maxColWidths = QVector<int>(columnCount(), QWIDGETSIZE_MAX);
3041 *maxRowHeights = QVector<int>(rowCount(), QWIDGETSIZE_MAX);
3042 for (int row=0; row<rowCount(); ++row)
3043 {
3044 for (int col=0; col<columnCount(); ++col)
3045 {
3046 if (mElements.at(row).at(col))
3047 {
3048 QSize maxHint = mElements.at(row).at(col)->maximumSizeHint();
3049 QSize max = mElements.at(row).at(col)->maximumSize();
3050 QSize final(max.width() < QWIDGETSIZE_MAX ? max.width() : maxHint.width(), max.height() < QWIDGETSIZE_MAX ? max.height() : maxHint.height());
3051 if (maxColWidths->at(col) > final.width())
3052 (*maxColWidths)[col] = final.width();
3053 if (maxRowHeights->at(row) > final.height())
3054 (*maxRowHeights)[row] = final.height();
3040 *maxColWidths = QVector<int>(columnCount(), QWIDGETSIZE_MAX);
3041 *maxRowHeights = QVector<int>(rowCount(), QWIDGETSIZE_MAX);
3042 for (int row=0; row<rowCount(); ++row)
3043 {
3044 for (int col=0; col<columnCount(); ++col)
3045 {
3046 if (mElements.at(row).at(col))
3047 {
3048 QSize maxHint = mElements.at(row).at(col)->maximumSizeHint();
3049 QSize max = mElements.at(row).at(col)->maximumSize();
3050 QSize final(max.width() < QWIDGETSIZE_MAX ? max.width() : maxHint.width(), max.height() < QWIDGETSIZE_MAX ? max.height() : maxHint.height());
3051 if (maxColWidths->at(col) > final.width())
3052 (*maxColWidths)[col] = final.width();
3053 if (maxRowHeights->at(row) > final.height())
3054 (*maxRowHeights)[row] = final.height();
3055 3055 }
3056 3056 }
3057 3057 }
@@ -3098,9 +3098,9 QCPLayoutInset::QCPLayoutInset()
3098 3098
3099 3099 QCPLayoutInset::~QCPLayoutInset()
3100 3100 {
3101 // clear all child layout elements. This is important because only the specific layouts know how
3102 // to handle removing elements (clear calls virtual removeAt method to do that).
3103 clear();
3101 // clear all child layout elements. This is important because only the specific layouts know how
3102 // to handle removing elements (clear calls virtual removeAt method to do that).
3103 clear();
3104 3104 }
3105 3105
3106 3106 /*!
@@ -3108,12 +3108,12 QCPLayoutInset::~QCPLayoutInset()
3108 3108 */
3109 3109 QCPLayoutInset::InsetPlacement QCPLayoutInset::insetPlacement(int index) const
3110 3110 {
3111 if (elementAt(index))
3112 return mInsetPlacement.at(index);
3113 else
3114 {
3115 qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
3116 return ipFree;
3111 if (elementAt(index))
3112 return mInsetPlacement.at(index);
3113 else
3114 {
3115 qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
3116 return ipFree;
3117 3117 }
3118 3118 }
3119 3119
@@ -3123,12 +3123,12 QCPLayoutInset::InsetPlacement QCPLayout
3123 3123 */
3124 3124 Qt::Alignment QCPLayoutInset::insetAlignment(int index) const
3125 3125 {
3126 if (elementAt(index))
3127 return mInsetAlignment.at(index);
3128 else
3129 {
3130 qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
3131 return 0;
3126 if (elementAt(index))
3127 return mInsetAlignment.at(index);
3128 else
3129 {
3130 qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
3131 return 0;
3132 3132 }
3133 3133 }
3134 3134
@@ -3138,12 +3138,12 Qt::Alignment QCPLayoutInset::insetAlign
3138 3138 */
3139 3139 QRectF QCPLayoutInset::insetRect(int index) const
3140 3140 {
3141 if (elementAt(index))
3142 return mInsetRect.at(index);
3143 else
3144 {
3145 qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
3146 return QRectF();
3141 if (elementAt(index))
3142 return mInsetRect.at(index);
3143 else
3144 {
3145 qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
3146 return QRectF();
3147 3147 }
3148 3148 }
3149 3149
@@ -3154,10 +3154,10 QRectF QCPLayoutInset::insetRect(int ind
3154 3154 */
3155 3155 void QCPLayoutInset::setInsetPlacement(int index, QCPLayoutInset::InsetPlacement placement)
3156 3156 {
3157 if (elementAt(index))
3158 mInsetPlacement[index] = placement;
3159 else
3160 qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
3157 if (elementAt(index))
3158 mInsetPlacement[index] = placement;
3159 else
3160 qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
3161 3161 }
3162 3162
3163 3163 /*!
@@ -3170,10 +3170,10 void QCPLayoutInset::setInsetPlacement(i
3170 3170 */
3171 3171 void QCPLayoutInset::setInsetAlignment(int index, Qt::Alignment alignment)
3172 3172 {
3173 if (elementAt(index))
3174 mInsetAlignment[index] = alignment;
3175 else
3176 qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
3173 if (elementAt(index))
3174 mInsetAlignment[index] = alignment;
3175 else
3176 qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
3177 3177 }
3178 3178
3179 3179 /*!
@@ -3189,104 +3189,104 void QCPLayoutInset::setInsetAlignment(i
3189 3189 */
3190 3190 void QCPLayoutInset::setInsetRect(int index, const QRectF &rect)
3191 3191 {
3192 if (elementAt(index))
3193 mInsetRect[index] = rect;
3194 else
3195 qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
3192 if (elementAt(index))
3193 mInsetRect[index] = rect;
3194 else
3195 qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
3196 3196 }
3197 3197
3198 3198 /* inherits documentation from base class */
3199 3199 void QCPLayoutInset::updateLayout()
3200 3200 {
3201 for (int i=0; i<mElements.size(); ++i)
3202 {
3203 QRect insetRect;
3204 QSize finalMinSize, finalMaxSize;
3205 QSize minSizeHint = mElements.at(i)->minimumSizeHint();
3206 QSize maxSizeHint = mElements.at(i)->maximumSizeHint();
3207 finalMinSize.setWidth(mElements.at(i)->minimumSize().width() > 0 ? mElements.at(i)->minimumSize().width() : minSizeHint.width());
3208 finalMinSize.setHeight(mElements.at(i)->minimumSize().height() > 0 ? mElements.at(i)->minimumSize().height() : minSizeHint.height());
3209 finalMaxSize.setWidth(mElements.at(i)->maximumSize().width() < QWIDGETSIZE_MAX ? mElements.at(i)->maximumSize().width() : maxSizeHint.width());
3210 finalMaxSize.setHeight(mElements.at(i)->maximumSize().height() < QWIDGETSIZE_MAX ? mElements.at(i)->maximumSize().height() : maxSizeHint.height());
3211 if (mInsetPlacement.at(i) == ipFree)
3212 {
3213 insetRect = QRect(rect().x()+rect().width()*mInsetRect.at(i).x(),
3214 rect().y()+rect().height()*mInsetRect.at(i).y(),
3215 rect().width()*mInsetRect.at(i).width(),
3216 rect().height()*mInsetRect.at(i).height());
3217 if (insetRect.size().width() < finalMinSize.width())
3218 insetRect.setWidth(finalMinSize.width());
3219 if (insetRect.size().height() < finalMinSize.height())
3220 insetRect.setHeight(finalMinSize.height());
3221 if (insetRect.size().width() > finalMaxSize.width())
3222 insetRect.setWidth(finalMaxSize.width());
3223 if (insetRect.size().height() > finalMaxSize.height())
3224 insetRect.setHeight(finalMaxSize.height());
3201 for (int i=0; i<mElements.size(); ++i)
3202 {
3203 QRect insetRect;
3204 QSize finalMinSize, finalMaxSize;
3205 QSize minSizeHint = mElements.at(i)->minimumSizeHint();
3206 QSize maxSizeHint = mElements.at(i)->maximumSizeHint();
3207 finalMinSize.setWidth(mElements.at(i)->minimumSize().width() > 0 ? mElements.at(i)->minimumSize().width() : minSizeHint.width());
3208 finalMinSize.setHeight(mElements.at(i)->minimumSize().height() > 0 ? mElements.at(i)->minimumSize().height() : minSizeHint.height());
3209 finalMaxSize.setWidth(mElements.at(i)->maximumSize().width() < QWIDGETSIZE_MAX ? mElements.at(i)->maximumSize().width() : maxSizeHint.width());
3210 finalMaxSize.setHeight(mElements.at(i)->maximumSize().height() < QWIDGETSIZE_MAX ? mElements.at(i)->maximumSize().height() : maxSizeHint.height());
3211 if (mInsetPlacement.at(i) == ipFree)
3212 {
3213 insetRect = QRect(rect().x()+rect().width()*mInsetRect.at(i).x(),
3214 rect().y()+rect().height()*mInsetRect.at(i).y(),
3215 rect().width()*mInsetRect.at(i).width(),
3216 rect().height()*mInsetRect.at(i).height());
3217 if (insetRect.size().width() < finalMinSize.width())
3218 insetRect.setWidth(finalMinSize.width());
3219 if (insetRect.size().height() < finalMinSize.height())
3220 insetRect.setHeight(finalMinSize.height());
3221 if (insetRect.size().width() > finalMaxSize.width())
3222 insetRect.setWidth(finalMaxSize.width());
3223 if (insetRect.size().height() > finalMaxSize.height())
3224 insetRect.setHeight(finalMaxSize.height());
3225 3225 } else if (mInsetPlacement.at(i) == ipBorderAligned)
3226 3226 {
3227 insetRect.setSize(finalMinSize);
3228 Qt::Alignment al = mInsetAlignment.at(i);
3229 if (al.testFlag(Qt::AlignLeft)) insetRect.moveLeft(rect().x());
3230 else if (al.testFlag(Qt::AlignRight)) insetRect.moveRight(rect().x()+rect().width());
3231 else insetRect.moveLeft(rect().x()+rect().width()*0.5-finalMinSize.width()*0.5); // default to Qt::AlignHCenter
3232 if (al.testFlag(Qt::AlignTop)) insetRect.moveTop(rect().y());
3233 else if (al.testFlag(Qt::AlignBottom)) insetRect.moveBottom(rect().y()+rect().height());
3234 else insetRect.moveTop(rect().y()+rect().height()*0.5-finalMinSize.height()*0.5); // default to Qt::AlignVCenter
3235 }
3236 mElements.at(i)->setOuterRect(insetRect);
3227 insetRect.setSize(finalMinSize);
3228 Qt::Alignment al = mInsetAlignment.at(i);
3229 if (al.testFlag(Qt::AlignLeft)) insetRect.moveLeft(rect().x());
3230 else if (al.testFlag(Qt::AlignRight)) insetRect.moveRight(rect().x()+rect().width());
3231 else insetRect.moveLeft(rect().x()+rect().width()*0.5-finalMinSize.width()*0.5); // default to Qt::AlignHCenter
3232 if (al.testFlag(Qt::AlignTop)) insetRect.moveTop(rect().y());
3233 else if (al.testFlag(Qt::AlignBottom)) insetRect.moveBottom(rect().y()+rect().height());
3234 else insetRect.moveTop(rect().y()+rect().height()*0.5-finalMinSize.height()*0.5); // default to Qt::AlignVCenter
3235 }
3236 mElements.at(i)->setOuterRect(insetRect);
3237 3237 }
3238 3238 }
3239 3239
3240 3240 /* inherits documentation from base class */
3241 3241 int QCPLayoutInset::elementCount() const
3242 3242 {
3243 return mElements.size();
3243 return mElements.size();
3244 3244 }
3245 3245
3246 3246 /* inherits documentation from base class */
3247 3247 QCPLayoutElement *QCPLayoutInset::elementAt(int index) const
3248 3248 {
3249 if (index >= 0 && index < mElements.size())
3250 return mElements.at(index);
3251 else
3252 return 0;
3249 if (index >= 0 && index < mElements.size())
3250 return mElements.at(index);
3251 else
3252 return 0;
3253 3253 }
3254 3254
3255 3255 /* inherits documentation from base class */
3256 3256 QCPLayoutElement *QCPLayoutInset::takeAt(int index)
3257 3257 {
3258 if (QCPLayoutElement *el = elementAt(index))
3259 {
3260 releaseElement(el);
3261 mElements.removeAt(index);
3262 mInsetPlacement.removeAt(index);
3263 mInsetAlignment.removeAt(index);
3264 mInsetRect.removeAt(index);
3265 return el;
3266 } else
3267 {
3268 qDebug() << Q_FUNC_INFO << "Attempt to take invalid index:" << index;
3269 return 0;
3258 if (QCPLayoutElement *el = elementAt(index))
3259 {
3260 releaseElement(el);
3261 mElements.removeAt(index);
3262 mInsetPlacement.removeAt(index);
3263 mInsetAlignment.removeAt(index);
3264 mInsetRect.removeAt(index);
3265 return el;
3266 } else
3267 {
3268 qDebug() << Q_FUNC_INFO << "Attempt to take invalid index:" << index;
3269 return 0;
3270 3270 }
3271 3271 }
3272 3272
3273 3273 /* inherits documentation from base class */
3274 3274 bool QCPLayoutInset::take(QCPLayoutElement *element)
3275 3275 {
3276 if (element)
3277 {
3278 for (int i=0; i<elementCount(); ++i)
3279 {
3280 if (elementAt(i) == element)
3281 {
3282 takeAt(i);
3283 return true;
3284 }
3285 }
3286 qDebug() << Q_FUNC_INFO << "Element not in this layout, couldn't take";
3287 } else
3288 qDebug() << Q_FUNC_INFO << "Can't take null element";
3289 return false;
3276 if (element)
3277 {
3278 for (int i=0; i<elementCount(); ++i)
3279 {
3280 if (elementAt(i) == element)
3281 {
3282 takeAt(i);
3283 return true;
3284 }
3285 }
3286 qDebug() << Q_FUNC_INFO << "Element not in this layout, couldn't take";
3287 } else
3288 qDebug() << Q_FUNC_INFO << "Can't take null element";
3289 return false;
3290 3290 }
3291 3291
3292 3292 /*!
@@ -3300,18 +3300,18 bool QCPLayoutInset::take(QCPLayoutEleme
3300 3300 */
3301 3301 double QCPLayoutInset::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
3302 3302 {
3303 Q_UNUSED(details)
3304 if (onlySelectable)
3303 Q_UNUSED(details)
3304 if (onlySelectable)
3305 return -1;
3306
3307 for (int i=0; i<mElements.size(); ++i)
3308 {
3309 // inset layout shall only return positive selectTest, if actually an inset object is at pos
3310 // else it would block the entire underlying QCPAxisRect with its surface.
3311 if (mElements.at(i)->realVisibility() && mElements.at(i)->selectTest(pos, onlySelectable) >= 0)
3312 return mParentPlot->selectionTolerance()*0.99;
3313 }
3305 3314 return -1;
3306
3307 for (int i=0; i<mElements.size(); ++i)
3308 {
3309 // inset layout shall only return positive selectTest, if actually an inset object is at pos
3310 // else it would block the entire underlying QCPAxisRect with its surface.
3311 if (mElements.at(i)->realVisibility() && mElements.at(i)->selectTest(pos, onlySelectable) >= 0)
3312 return mParentPlot->selectionTolerance()*0.99;
3313 }
3314 return -1;
3315 3315 }
3316 3316
3317 3317 /*!
@@ -3327,17 +3327,17 double QCPLayoutInset::selectTest(const
3327 3327 */
3328 3328 void QCPLayoutInset::addElement(QCPLayoutElement *element, Qt::Alignment alignment)
3329 3329 {
3330 if (element)
3331 {
3332 if (element->layout()) // remove from old layout first
3333 element->layout()->take(element);
3334 mElements.append(element);
3335 mInsetPlacement.append(ipBorderAligned);
3336 mInsetAlignment.append(alignment);
3337 mInsetRect.append(QRectF(0.6, 0.6, 0.4, 0.4));
3338 adoptElement(element);
3339 } else
3340 qDebug() << Q_FUNC_INFO << "Can't add null element";
3330 if (element)
3331 {
3332 if (element->layout()) // remove from old layout first
3333 element->layout()->take(element);
3334 mElements.append(element);
3335 mInsetPlacement.append(ipBorderAligned);
3336 mInsetAlignment.append(alignment);
3337 mInsetRect.append(QRectF(0.6, 0.6, 0.4, 0.4));
3338 adoptElement(element);
3339 } else
3340 qDebug() << Q_FUNC_INFO << "Can't add null element";
3341 3341 }
3342 3342
3343 3343 /*!
@@ -3353,17 +3353,17 void QCPLayoutInset::addElement(QCPLayou
3353 3353 */
3354 3354 void QCPLayoutInset::addElement(QCPLayoutElement *element, const QRectF &rect)
3355 3355 {
3356 if (element)
3357 {
3358 if (element->layout()) // remove from old layout first
3359 element->layout()->take(element);
3360 mElements.append(element);
3361 mInsetPlacement.append(ipFree);
3362 mInsetAlignment.append(Qt::AlignRight|Qt::AlignTop);
3363 mInsetRect.append(rect);
3364 adoptElement(element);
3365 } else
3366 qDebug() << Q_FUNC_INFO << "Can't add null element";
3356 if (element)
3357 {
3358 if (element->layout()) // remove from old layout first
3359 element->layout()->take(element);
3360 mElements.append(element);
3361 mInsetPlacement.append(ipFree);
3362 mInsetAlignment.append(Qt::AlignRight|Qt::AlignTop);
3363 mInsetRect.append(rect);
3364 adoptElement(element);
3365 } else
3366 qDebug() << Q_FUNC_INFO << "Can't add null element";
3367 3367 }
3368 3368
3369 3369
@@ -3395,10 +3395,10 void QCPLayoutInset::addElement(QCPLayou
3395 3395 Creates a QCPLineEnding instance with default values (style \ref esNone).
3396 3396 */
3397 3397 QCPLineEnding::QCPLineEnding() :
3398 mStyle(esNone),
3399 mWidth(8),
3400 mLength(10),
3401 mInverted(false)
3398 mStyle(esNone),
3399 mWidth(8),
3400 mLength(10),
3401 mInverted(false)
3402 3402 {
3403 3403 }
3404 3404
@@ -3406,10 +3406,10 QCPLineEnding::QCPLineEnding() :
3406 3406 Creates a QCPLineEnding instance with the specified values.
3407 3407 */
3408 3408 QCPLineEnding::QCPLineEnding(QCPLineEnding::EndingStyle style, double width, double length, bool inverted) :
3409 mStyle(style),
3410 mWidth(width),
3411 mLength(length),
3412 mInverted(inverted)
3409 mStyle(style),
3410 mWidth(width),
3411 mLength(length),
3412 mInverted(inverted)
3413 3413 {
3414 3414 }
3415 3415
@@ -3418,7 +3418,7 QCPLineEnding::QCPLineEnding(QCPLineEndi
3418 3418 */
3419 3419 void QCPLineEnding::setStyle(QCPLineEnding::EndingStyle style)
3420 3420 {
3421 mStyle = style;
3421 mStyle = style;
3422 3422 }
3423 3423
3424 3424 /*!
@@ -3429,7 +3429,7 void QCPLineEnding::setStyle(QCPLineEndi
3429 3429 */
3430 3430 void QCPLineEnding::setWidth(double width)
3431 3431 {
3432 mWidth = width;
3432 mWidth = width;
3433 3433 }
3434 3434
3435 3435 /*!
@@ -3440,7 +3440,7 void QCPLineEnding::setWidth(double widt
3440 3440 */
3441 3441 void QCPLineEnding::setLength(double length)
3442 3442 {
3443 mLength = length;
3443 mLength = length;
3444 3444 }
3445 3445
3446 3446 /*!
@@ -3453,7 +3453,7 void QCPLineEnding::setLength(double len
3453 3453 */
3454 3454 void QCPLineEnding::setInverted(bool inverted)
3455 3455 {
3456 mInverted = inverted;
3456 mInverted = inverted;
3457 3457 }
3458 3458
3459 3459 /*! \internal
@@ -3467,26 +3467,26 void QCPLineEnding::setInverted(bool inv
3467 3467 */
3468 3468 double QCPLineEnding::boundingDistance() const
3469 3469 {
3470 switch (mStyle)
3470 switch (mStyle)
3471 3471 {
3472 3472 case esNone:
3473 return 0;
3474
3473 return 0;
3474
3475 3475 case esFlatArrow:
3476 3476 case esSpikeArrow:
3477 3477 case esLineArrow:
3478 3478 case esSkewedBar:
3479 return qSqrt(mWidth*mWidth+mLength*mLength); // items that have width and length
3480
3479 return qSqrt(mWidth*mWidth+mLength*mLength); // items that have width and length
3480
3481 3481 case esDisc:
3482 3482 case esSquare:
3483 3483 case esDiamond:
3484 3484 case esBar:
3485 3485 case esHalfBar:
3486 return mWidth*1.42; // items that only have a width -> width*sqrt(2)
3487
3488 }
3489 return 0;
3486 return mWidth*1.42; // items that only have a width -> width*sqrt(2)
3487
3488 }
3489 return 0;
3490 3490 }
3491 3491
3492 3492 /*!
@@ -3502,27 +3502,27 double QCPLineEnding::boundingDistance()
3502 3502 */
3503 3503 double QCPLineEnding::realLength() const
3504 3504 {
3505 switch (mStyle)
3505 switch (mStyle)
3506 3506 {
3507 3507 case esNone:
3508 3508 case esLineArrow:
3509 3509 case esSkewedBar:
3510 3510 case esBar:
3511 3511 case esHalfBar:
3512 return 0;
3513
3512 return 0;
3513
3514 3514 case esFlatArrow:
3515 return mLength;
3516
3515 return mLength;
3516
3517 3517 case esDisc:
3518 3518 case esSquare:
3519 3519 case esDiamond:
3520 return mWidth*0.5;
3521
3520 return mWidth*0.5;
3521
3522 3522 case esSpikeArrow:
3523 return mLength*0.8;
3524 }
3525 return 0;
3523 return mLength*0.8;
3524 }
3525 return 0;
3526 3526 }
3527 3527
3528 3528 /*! \internal
@@ -3532,26 +3532,26 double QCPLineEnding::realLength() const
3532 3532 */
3533 3533 void QCPLineEnding::draw(QCPPainter *painter, const QVector2D &pos, const QVector2D &dir) const
3534 3534 {
3535 if (mStyle == esNone)
3536 return;
3537
3538 QVector2D lengthVec(dir.normalized());
3539 if (lengthVec.isNull())
3540 lengthVec = QVector2D(1, 0);
3541 QVector2D widthVec(-lengthVec.y(), lengthVec.x());
3542 lengthVec *= (float)(mLength*(mInverted ? -1 : 1));
3543 widthVec *= (float)(mWidth*0.5*(mInverted ? -1 : 1));
3544
3545 QPen penBackup = painter->pen();
3546 QBrush brushBackup = painter->brush();
3547 QPen miterPen = penBackup;
3548 miterPen.setJoinStyle(Qt::MiterJoin); // to make arrow heads spikey
3549 QBrush brush(painter->pen().color(), Qt::SolidPattern);
3550 switch (mStyle)
3535 if (mStyle == esNone)
3536 return;
3537
3538 QVector2D lengthVec(dir.normalized());
3539 if (lengthVec.isNull())
3540 lengthVec = QVector2D(1, 0);
3541 QVector2D widthVec(-lengthVec.y(), lengthVec.x());
3542 lengthVec *= (float)(mLength*(mInverted ? -1 : 1));
3543 widthVec *= (float)(mWidth*0.5*(mInverted ? -1 : 1));
3544
3545 QPen penBackup = painter->pen();
3546 QBrush brushBackup = painter->brush();
3547 QPen miterPen = penBackup;
3548 miterPen.setJoinStyle(Qt::MiterJoin); // to make arrow heads spikey
3549 QBrush brush(painter->pen().color(), Qt::SolidPattern);
3550 switch (mStyle)
3551 3551 {
3552 3552 case esNone: break;
3553 3553 case esFlatArrow:
3554 {
3554 {
3555 3555 QPointF points[3] = {pos.toPointF(),
3556 3556 (pos-lengthVec+widthVec).toPointF(),
3557 3557 (pos-lengthVec-widthVec).toPointF()
@@ -3562,9 +3562,9 void QCPLineEnding::draw(QCPPainter *pai
3562 3562 painter->setBrush(brushBackup);
3563 3563 painter->setPen(penBackup);
3564 3564 break;
3565 }
3565 }
3566 3566 case esSpikeArrow:
3567 {
3567 {
3568 3568 QPointF points[4] = {pos.toPointF(),
3569 3569 (pos-lengthVec+widthVec).toPointF(),
3570 3570 (pos-lengthVec*0.8f).toPointF(),
@@ -3576,9 +3576,9 void QCPLineEnding::draw(QCPPainter *pai
3576 3576 painter->setBrush(brushBackup);
3577 3577 painter->setPen(penBackup);
3578 3578 break;
3579 }
3579 }
3580 3580 case esLineArrow:
3581 {
3581 {
3582 3582 QPointF points[3] = {(pos-lengthVec+widthVec).toPointF(),
3583 3583 pos.toPointF(),
3584 3584 (pos-lengthVec-widthVec).toPointF()
@@ -3587,16 +3587,16 void QCPLineEnding::draw(QCPPainter *pai
3587 3587 painter->drawPolyline(points, 3);
3588 3588 painter->setPen(penBackup);
3589 3589 break;
3590 }
3590 }
3591 3591 case esDisc:
3592 {
3592 {
3593 3593 painter->setBrush(brush);
3594 3594 painter->drawEllipse(pos.toPointF(), mWidth*0.5, mWidth*0.5);
3595 3595 painter->setBrush(brushBackup);
3596 3596 break;
3597 }
3597 }
3598 3598 case esSquare:
3599 {
3599 {
3600 3600 QVector2D widthVecPerp(-widthVec.y(), widthVec.x());
3601 3601 QPointF points[4] = {(pos-widthVecPerp+widthVec).toPointF(),
3602 3602 (pos-widthVecPerp-widthVec).toPointF(),
@@ -3609,9 +3609,9 void QCPLineEnding::draw(QCPPainter *pai
3609 3609 painter->setBrush(brushBackup);
3610 3610 painter->setPen(penBackup);
3611 3611 break;
3612 }
3612 }
3613 3613 case esDiamond:
3614 {
3614 {
3615 3615 QVector2D widthVecPerp(-widthVec.y(), widthVec.x());
3616 3616 QPointF points[4] = {(pos-widthVecPerp).toPointF(),
3617 3617 (pos-widthVec).toPointF(),
@@ -3624,32 +3624,32 void QCPLineEnding::draw(QCPPainter *pai
3624 3624 painter->setBrush(brushBackup);
3625 3625 painter->setPen(penBackup);
3626 3626 break;
3627 }
3627 }
3628 3628 case esBar:
3629 {
3629 {
3630 3630 painter->drawLine((pos+widthVec).toPointF(), (pos-widthVec).toPointF());
3631 3631 break;
3632 }
3632 }
3633 3633 case esHalfBar:
3634 {
3634 {
3635 3635 painter->drawLine((pos+widthVec).toPointF(), pos.toPointF());
3636 3636 break;
3637 }
3637 }
3638 3638 case esSkewedBar:
3639 {
3639 {
3640 3640 if (qFuzzyIsNull(painter->pen().widthF()) && !painter->modes().testFlag(QCPPainter::pmNonCosmetic))
3641 {
3641 {
3642 3642 // if drawing with cosmetic pen (perfectly thin stroke, happens only in vector exports), draw bar exactly on tip of line
3643 3643 painter->drawLine((pos+widthVec+lengthVec*0.2f*(mInverted?-1:1)).toPointF(),
3644 3644 (pos-widthVec-lengthVec*0.2f*(mInverted?-1:1)).toPointF());
3645 } else
3646 {
3645 } else
3646 {
3647 3647 // if drawing with thick (non-cosmetic) pen, shift bar a little in line direction to prevent line from sticking through bar slightly
3648 3648 painter->drawLine((pos+widthVec+lengthVec*0.2f*(mInverted?-1:1)+dir.normalized()*qMax(1.0f, (float)painter->pen().widthF())*0.5f).toPointF(),
3649 3649 (pos-widthVec-lengthVec*0.2f*(mInverted?-1:1)+dir.normalized()*qMax(1.0f, (float)painter->pen().widthF())*0.5f).toPointF());
3650 }
3651 break;
3652 }
3650 }
3651 break;
3652 }
3653 3653 }
3654 3654 }
3655 3655
@@ -3660,7 +3660,7 void QCPLineEnding::draw(QCPPainter *pai
3660 3660 */
3661 3661 void QCPLineEnding::draw(QCPPainter *painter, const QVector2D &pos, double angle) const
3662 3662 {
3663 draw(painter, pos, QVector2D(qCos(angle), qSin(angle)));
3663 draw(painter, pos, QVector2D(qCos(angle), qSin(angle)));
3664 3664 }
3665 3665
3666 3666
@@ -3687,18 +3687,18 void QCPLineEnding::draw(QCPPainter *pai
3687 3687 You shouldn't instantiate grids on their own, since every QCPAxis brings its own QCPGrid.
3688 3688 */
3689 3689 QCPGrid::QCPGrid(QCPAxis *parentAxis) :
3690 QCPLayerable(parentAxis->parentPlot(), QString(), parentAxis),
3691 mParentAxis(parentAxis)
3692 {
3693 // warning: this is called in QCPAxis constructor, so parentAxis members should not be accessed/called
3694 setParent(parentAxis);
3695 setPen(QPen(QColor(200,200,200), 0, Qt::DotLine));
3696 setSubGridPen(QPen(QColor(220,220,220), 0, Qt::DotLine));
3697 setZeroLinePen(QPen(QColor(200,200,200), 0, Qt::SolidLine));
3698 setSubGridVisible(false);
3699 setAntialiased(false);
3700 setAntialiasedSubGrid(false);
3701 setAntialiasedZeroLine(false);
3690 QCPLayerable(parentAxis->parentPlot(), QString(), parentAxis),
3691 mParentAxis(parentAxis)
3692 {
3693 // warning: this is called in QCPAxis constructor, so parentAxis members should not be accessed/called
3694 setParent(parentAxis);
3695 setPen(QPen(QColor(200,200,200), 0, Qt::DotLine));
3696 setSubGridPen(QPen(QColor(220,220,220), 0, Qt::DotLine));
3697 setZeroLinePen(QPen(QColor(200,200,200), 0, Qt::SolidLine));
3698 setSubGridVisible(false);
3699 setAntialiased(false);
3700 setAntialiasedSubGrid(false);
3701 setAntialiasedZeroLine(false);
3702 3702 }
3703 3703
3704 3704 /*!
@@ -3708,7 +3708,7 QCPGrid::QCPGrid(QCPAxis *parentAxis) :
3708 3708 */
3709 3709 void QCPGrid::setSubGridVisible(bool visible)
3710 3710 {
3711 mSubGridVisible = visible;
3711 mSubGridVisible = visible;
3712 3712 }
3713 3713
3714 3714 /*!
@@ -3716,7 +3716,7 void QCPGrid::setSubGridVisible(bool vis
3716 3716 */
3717 3717 void QCPGrid::setAntialiasedSubGrid(bool enabled)
3718 3718 {
3719 mAntialiasedSubGrid = enabled;
3719 mAntialiasedSubGrid = enabled;
3720 3720 }
3721 3721
3722 3722 /*!
@@ -3724,7 +3724,7 void QCPGrid::setAntialiasedSubGrid(bool
3724 3724 */
3725 3725 void QCPGrid::setAntialiasedZeroLine(bool enabled)
3726 3726 {
3727 mAntialiasedZeroLine = enabled;
3727 mAntialiasedZeroLine = enabled;
3728 3728 }
3729 3729
3730 3730 /*!
@@ -3732,7 +3732,7 void QCPGrid::setAntialiasedZeroLine(boo
3732 3732 */
3733 3733 void QCPGrid::setPen(const QPen &pen)
3734 3734 {
3735 mPen = pen;
3735 mPen = pen;
3736 3736 }
3737 3737
3738 3738 /*!
@@ -3740,7 +3740,7 void QCPGrid::setPen(const QPen &pen)
3740 3740 */
3741 3741 void QCPGrid::setSubGridPen(const QPen &pen)
3742 3742 {
3743 mSubGridPen = pen;
3743 mSubGridPen = pen;
3744 3744 }
3745 3745
3746 3746 /*!
@@ -3751,7 +3751,7 void QCPGrid::setSubGridPen(const QPen &
3751 3751 */
3752 3752 void QCPGrid::setZeroLinePen(const QPen &pen)
3753 3753 {
3754 mZeroLinePen = pen;
3754 mZeroLinePen = pen;
3755 3755 }
3756 3756
3757 3757 /*! \internal
@@ -3769,7 +3769,7 void QCPGrid::setZeroLinePen(const QPen
3769 3769 */
3770 3770 void QCPGrid::applyDefaultAntialiasingHint(QCPPainter *painter) const
3771 3771 {
3772 applyAntialiasingHint(painter, mAntialiased, QCP::aeGrid);
3772 applyAntialiasingHint(painter, mAntialiased, QCP::aeGrid);
3773 3773 }
3774 3774
3775 3775 /*! \internal
@@ -3779,11 +3779,11 void QCPGrid::applyDefaultAntialiasingHi
3779 3779 */
3780 3780 void QCPGrid::draw(QCPPainter *painter)
3781 3781 {
3782 if (!mParentAxis) { qDebug() << Q_FUNC_INFO << "invalid parent axis"; return; }
3783
3784 if (mSubGridVisible)
3785 drawSubGridLines(painter);
3786 drawGridLines(painter);
3782 if (!mParentAxis) { qDebug() << Q_FUNC_INFO << "invalid parent axis"; return; }
3783
3784 if (mSubGridVisible)
3785 drawSubGridLines(painter);
3786 drawGridLines(painter);
3787 3787 }
3788 3788
3789 3789 /*! \internal
@@ -3794,68 +3794,68 void QCPGrid::draw(QCPPainter *painter)
3794 3794 */
3795 3795 void QCPGrid::drawGridLines(QCPPainter *painter) const
3796 3796 {
3797 if (!mParentAxis) { qDebug() << Q_FUNC_INFO << "invalid parent axis"; return; }
3798
3799 int lowTick = mParentAxis->mLowestVisibleTick;
3800 int highTick = mParentAxis->mHighestVisibleTick;
3801 double t; // helper variable, result of coordinate-to-pixel transforms
3802 if (mParentAxis->orientation() == Qt::Horizontal)
3803 {
3804 // draw zeroline:
3805 int zeroLineIndex = -1;
3806 if (mZeroLinePen.style() != Qt::NoPen && mParentAxis->mRange.lower < 0 && mParentAxis->mRange.upper > 0)
3807 {
3808 applyAntialiasingHint(painter, mAntialiasedZeroLine, QCP::aeZeroLine);
3809 painter->setPen(mZeroLinePen);
3810 double epsilon = mParentAxis->range().size()*1E-6; // for comparing double to zero
3811 for (int i=lowTick; i <= highTick; ++i)
3812 {
3813 if (qAbs(mParentAxis->mTickVector.at(i)) < epsilon)
3797 if (!mParentAxis) { qDebug() << Q_FUNC_INFO << "invalid parent axis"; return; }
3798
3799 int lowTick = mParentAxis->mLowestVisibleTick;
3800 int highTick = mParentAxis->mHighestVisibleTick;
3801 double t; // helper variable, result of coordinate-to-pixel transforms
3802 if (mParentAxis->orientation() == Qt::Horizontal)
3803 {
3804 // draw zeroline:
3805 int zeroLineIndex = -1;
3806 if (mZeroLinePen.style() != Qt::NoPen && mParentAxis->mRange.lower < 0 && mParentAxis->mRange.upper > 0)
3807 {
3808 applyAntialiasingHint(painter, mAntialiasedZeroLine, QCP::aeZeroLine);
3809 painter->setPen(mZeroLinePen);
3810 double epsilon = mParentAxis->range().size()*1E-6; // for comparing double to zero
3811 for (int i=lowTick; i <= highTick; ++i)
3812 {
3813 if (qAbs(mParentAxis->mTickVector.at(i)) < epsilon)
3814 3814 {
3815 zeroLineIndex = i;
3816 t = mParentAxis->coordToPixel(mParentAxis->mTickVector.at(i)); // x
3817 painter->drawLine(QLineF(t, mParentAxis->mAxisRect->bottom(), t, mParentAxis->mAxisRect->top()));
3818 break;
3815 zeroLineIndex = i;
3816 t = mParentAxis->coordToPixel(mParentAxis->mTickVector.at(i)); // x
3817 painter->drawLine(QLineF(t, mParentAxis->mAxisRect->bottom(), t, mParentAxis->mAxisRect->top()));
3818 break;
3819 3819 }
3820 3820 }
3821 3821 }
3822 // draw grid lines:
3823 applyDefaultAntialiasingHint(painter);
3824 painter->setPen(mPen);
3825 for (int i=lowTick; i <= highTick; ++i)
3826 {
3827 if (i == zeroLineIndex) continue; // don't draw a gridline on top of the zeroline
3828 t = mParentAxis->coordToPixel(mParentAxis->mTickVector.at(i)); // x
3829 painter->drawLine(QLineF(t, mParentAxis->mAxisRect->bottom(), t, mParentAxis->mAxisRect->top()));
3830 }
3831 } else
3832 {
3833 // draw zeroline:
3834 int zeroLineIndex = -1;
3835 if (mZeroLinePen.style() != Qt::NoPen && mParentAxis->mRange.lower < 0 && mParentAxis->mRange.upper > 0)
3836 {
3837 applyAntialiasingHint(painter, mAntialiasedZeroLine, QCP::aeZeroLine);
3838 painter->setPen(mZeroLinePen);
3839 double epsilon = mParentAxis->mRange.size()*1E-6; // for comparing double to zero
3840 for (int i=lowTick; i <= highTick; ++i)
3841 {
3842 if (qAbs(mParentAxis->mTickVector.at(i)) < epsilon)
3822 // draw grid lines:
3823 applyDefaultAntialiasingHint(painter);
3824 painter->setPen(mPen);
3825 for (int i=lowTick; i <= highTick; ++i)
3826 {
3827 if (i == zeroLineIndex) continue; // don't draw a gridline on top of the zeroline
3828 t = mParentAxis->coordToPixel(mParentAxis->mTickVector.at(i)); // x
3829 painter->drawLine(QLineF(t, mParentAxis->mAxisRect->bottom(), t, mParentAxis->mAxisRect->top()));
3830 }
3831 } else
3832 {
3833 // draw zeroline:
3834 int zeroLineIndex = -1;
3835 if (mZeroLinePen.style() != Qt::NoPen && mParentAxis->mRange.lower < 0 && mParentAxis->mRange.upper > 0)
3836 {
3837 applyAntialiasingHint(painter, mAntialiasedZeroLine, QCP::aeZeroLine);
3838 painter->setPen(mZeroLinePen);
3839 double epsilon = mParentAxis->mRange.size()*1E-6; // for comparing double to zero
3840 for (int i=lowTick; i <= highTick; ++i)
3841 {
3842 if (qAbs(mParentAxis->mTickVector.at(i)) < epsilon)
3843 3843 {
3844 zeroLineIndex = i;
3845 t = mParentAxis->coordToPixel(mParentAxis->mTickVector.at(i)); // y
3846 painter->drawLine(QLineF(mParentAxis->mAxisRect->left(), t, mParentAxis->mAxisRect->right(), t));
3847 break;
3844 zeroLineIndex = i;
3845 t = mParentAxis->coordToPixel(mParentAxis->mTickVector.at(i)); // y
3846 painter->drawLine(QLineF(mParentAxis->mAxisRect->left(), t, mParentAxis->mAxisRect->right(), t));
3847 break;
3848 3848 }
3849 3849 }
3850 3850 }
3851 // draw grid lines:
3852 applyDefaultAntialiasingHint(painter);
3853 painter->setPen(mPen);
3854 for (int i=lowTick; i <= highTick; ++i)
3855 {
3856 if (i == zeroLineIndex) continue; // don't draw a gridline on top of the zeroline
3857 t = mParentAxis->coordToPixel(mParentAxis->mTickVector.at(i)); // y
3858 painter->drawLine(QLineF(mParentAxis->mAxisRect->left(), t, mParentAxis->mAxisRect->right(), t));
3851 // draw grid lines:
3852 applyDefaultAntialiasingHint(painter);
3853 painter->setPen(mPen);
3854 for (int i=lowTick; i <= highTick; ++i)
3855 {
3856 if (i == zeroLineIndex) continue; // don't draw a gridline on top of the zeroline
3857 t = mParentAxis->coordToPixel(mParentAxis->mTickVector.at(i)); // y
3858 painter->drawLine(QLineF(mParentAxis->mAxisRect->left(), t, mParentAxis->mAxisRect->right(), t));
3859 3859 }
3860 3860 }
3861 3861 }
@@ -3868,24 +3868,24 void QCPGrid::drawGridLines(QCPPainter *
3868 3868 */
3869 3869 void QCPGrid::drawSubGridLines(QCPPainter *painter) const
3870 3870 {
3871 if (!mParentAxis) { qDebug() << Q_FUNC_INFO << "invalid parent axis"; return; }
3872
3873 applyAntialiasingHint(painter, mAntialiasedSubGrid, QCP::aeSubGrid);
3874 double t; // helper variable, result of coordinate-to-pixel transforms
3875 painter->setPen(mSubGridPen);
3876 if (mParentAxis->orientation() == Qt::Horizontal)
3877 {
3878 for (int i=0; i<mParentAxis->mSubTickVector.size(); ++i)
3879 {
3880 t = mParentAxis->coordToPixel(mParentAxis->mSubTickVector.at(i)); // x
3881 painter->drawLine(QLineF(t, mParentAxis->mAxisRect->bottom(), t, mParentAxis->mAxisRect->top()));
3882 }
3883 } else
3884 {
3885 for (int i=0; i<mParentAxis->mSubTickVector.size(); ++i)
3886 {
3887 t = mParentAxis->coordToPixel(mParentAxis->mSubTickVector.at(i)); // y
3888 painter->drawLine(QLineF(mParentAxis->mAxisRect->left(), t, mParentAxis->mAxisRect->right(), t));
3871 if (!mParentAxis) { qDebug() << Q_FUNC_INFO << "invalid parent axis"; return; }
3872
3873 applyAntialiasingHint(painter, mAntialiasedSubGrid, QCP::aeSubGrid);
3874 double t; // helper variable, result of coordinate-to-pixel transforms
3875 painter->setPen(mSubGridPen);
3876 if (mParentAxis->orientation() == Qt::Horizontal)
3877 {
3878 for (int i=0; i<mParentAxis->mSubTickVector.size(); ++i)
3879 {
3880 t = mParentAxis->coordToPixel(mParentAxis->mSubTickVector.at(i)); // x
3881 painter->drawLine(QLineF(t, mParentAxis->mAxisRect->bottom(), t, mParentAxis->mAxisRect->top()));
3882 }
3883 } else
3884 {
3885 for (int i=0; i<mParentAxis->mSubTickVector.size(); ++i)
3886 {
3887 t = mParentAxis->coordToPixel(mParentAxis->mSubTickVector.at(i)); // y
3888 painter->drawLine(QLineF(mParentAxis->mAxisRect->left(), t, mParentAxis->mAxisRect->right(), t));
3889 3889 }
3890 3890 }
3891 3891 }
@@ -3994,167 +3994,167 void QCPGrid::drawSubGridLines(QCPPainte
3994 3994 create them manually and then inject them also via \ref QCPAxisRect::addAxis.
3995 3995 */
3996 3996 QCPAxis::QCPAxis(QCPAxisRect *parent, AxisType type) :
3997 QCPLayerable(parent->parentPlot(), QString(), parent),
3998 // axis base:
3999 mAxisType(type),
4000 mAxisRect(parent),
4001 mPadding(5),
4002 mOrientation(orientation(type)),
4003 mSelectableParts(spAxis | spTickLabels | spAxisLabel),
4004 mSelectedParts(spNone),
4005 mBasePen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)),
4006 mSelectedBasePen(QPen(Qt::blue, 2)),
4007 // axis label:
4008 mLabel(),
4009 mLabelFont(mParentPlot->font()),
4010 mSelectedLabelFont(QFont(mLabelFont.family(), mLabelFont.pointSize(), QFont::Bold)),
4011 mLabelColor(Qt::black),
4012 mSelectedLabelColor(Qt::blue),
4013 // tick labels:
4014 mTickLabels(true),
4015 mAutoTickLabels(true),
4016 mTickLabelType(ltNumber),
4017 mTickLabelFont(mParentPlot->font()),
4018 mSelectedTickLabelFont(QFont(mTickLabelFont.family(), mTickLabelFont.pointSize(), QFont::Bold)),
4019 mTickLabelColor(Qt::black),
4020 mSelectedTickLabelColor(Qt::blue),
4021 mDateTimeFormat(QLatin1String("hh:mm:ss\ndd.MM.yy")),
4022 mDateTimeSpec(Qt::LocalTime),
4023 mNumberPrecision(6),
4024 mNumberFormatChar('g'),
4025 mNumberBeautifulPowers(true),
4026 // ticks and subticks:
4027 mTicks(true),
4028 mTickStep(1),
4029 mSubTickCount(4),
4030 mAutoTickCount(6),
4031 mAutoTicks(true),
4032 mAutoTickStep(true),
4033 mAutoSubTicks(true),
4034 mTickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)),
4035 mSelectedTickPen(QPen(Qt::blue, 2)),
4036 mSubTickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)),
4037 mSelectedSubTickPen(QPen(Qt::blue, 2)),
4038 // scale and range:
4039 mRange(0, 5),
4040 mRangeReversed(false),
4041 mScaleType(stLinear),
4042 mScaleLogBase(10),
4043 mScaleLogBaseLogInv(1.0/qLn(mScaleLogBase)),
4044 // internal members:
4045 mGrid(new QCPGrid(this)),
4046 mAxisPainter(new QCPAxisPainterPrivate(parent->parentPlot())),
4047 mLowestVisibleTick(0),
4048 mHighestVisibleTick(-1),
4049 mCachedMarginValid(false),
4050 mCachedMargin(0)
4051 {
4052 mGrid->setVisible(false);
4053 setAntialiased(false);
4054 setLayer(mParentPlot->currentLayer()); // it's actually on that layer already, but we want it in front of the grid, so we place it on there again
4055
4056 if (type == atTop)
4057 {
4058 setTickLabelPadding(3);
4059 setLabelPadding(6);
3997 QCPLayerable(parent->parentPlot(), QString(), parent),
3998 // axis base:
3999 mAxisType(type),
4000 mAxisRect(parent),
4001 mPadding(5),
4002 mOrientation(orientation(type)),
4003 mSelectableParts(spAxis | spTickLabels | spAxisLabel),
4004 mSelectedParts(spNone),
4005 mBasePen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)),
4006 mSelectedBasePen(QPen(Qt::blue, 2)),
4007 // axis label:
4008 mLabel(),
4009 mLabelFont(mParentPlot->font()),
4010 mSelectedLabelFont(QFont(mLabelFont.family(), mLabelFont.pointSize(), QFont::Bold)),
4011 mLabelColor(Qt::black),
4012 mSelectedLabelColor(Qt::blue),
4013 // tick labels:
4014 mTickLabels(true),
4015 mAutoTickLabels(true),
4016 mTickLabelType(ltNumber),
4017 mTickLabelFont(mParentPlot->font()),
4018 mSelectedTickLabelFont(QFont(mTickLabelFont.family(), mTickLabelFont.pointSize(), QFont::Bold)),
4019 mTickLabelColor(Qt::black),
4020 mSelectedTickLabelColor(Qt::blue),
4021 mDateTimeFormat(QLatin1String("hh:mm:ss\ndd.MM.yy")),
4022 mDateTimeSpec(Qt::LocalTime),
4023 mNumberPrecision(6),
4024 mNumberFormatChar('g'),
4025 mNumberBeautifulPowers(true),
4026 // ticks and subticks:
4027 mTicks(true),
4028 mTickStep(1),
4029 mSubTickCount(4),
4030 mAutoTickCount(6),
4031 mAutoTicks(true),
4032 mAutoTickStep(true),
4033 mAutoSubTicks(true),
4034 mTickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)),
4035 mSelectedTickPen(QPen(Qt::blue, 2)),
4036 mSubTickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)),
4037 mSelectedSubTickPen(QPen(Qt::blue, 2)),
4038 // scale and range:
4039 mRange(0, 5),
4040 mRangeReversed(false),
4041 mScaleType(stLinear),
4042 mScaleLogBase(10),
4043 mScaleLogBaseLogInv(1.0/qLn(mScaleLogBase)),
4044 // internal members:
4045 mGrid(new QCPGrid(this)),
4046 mAxisPainter(new QCPAxisPainterPrivate(parent->parentPlot())),
4047 mLowestVisibleTick(0),
4048 mHighestVisibleTick(-1),
4049 mCachedMarginValid(false),
4050 mCachedMargin(0)
4051 {
4052 mGrid->setVisible(false);
4053 setAntialiased(false);
4054 setLayer(mParentPlot->currentLayer()); // it's actually on that layer already, but we want it in front of the grid, so we place it on there again
4055
4056 if (type == atTop)
4057 {
4058 setTickLabelPadding(3);
4059 setLabelPadding(6);
4060 4060 } else if (type == atRight)
4061 4061 {
4062 setTickLabelPadding(7);
4063 setLabelPadding(12);
4062 setTickLabelPadding(7);
4063 setLabelPadding(12);
4064 4064 } else if (type == atBottom)
4065 4065 {
4066 setTickLabelPadding(3);
4067 setLabelPadding(3);
4066 setTickLabelPadding(3);
4067 setLabelPadding(3);
4068 4068 } else if (type == atLeft)
4069 4069 {
4070 setTickLabelPadding(5);
4071 setLabelPadding(10);
4070 setTickLabelPadding(5);
4071 setLabelPadding(10);
4072 4072 }
4073 4073 }
4074 4074
4075 4075 QCPAxis::~QCPAxis()
4076 4076 {
4077 delete mAxisPainter;
4077 delete mAxisPainter;
4078 4078 }
4079 4079
4080 4080 /* No documentation as it is a property getter */
4081 4081 int QCPAxis::tickLabelPadding() const
4082 4082 {
4083 return mAxisPainter->tickLabelPadding;
4083 return mAxisPainter->tickLabelPadding;
4084 4084 }
4085 4085
4086 4086 /* No documentation as it is a property getter */
4087 4087 double QCPAxis::tickLabelRotation() const
4088 4088 {
4089 return mAxisPainter->tickLabelRotation;
4089 return mAxisPainter->tickLabelRotation;
4090 4090 }
4091 4091
4092 4092 /* No documentation as it is a property getter */
4093 4093 QCPAxis::LabelSide QCPAxis::tickLabelSide() const
4094 4094 {
4095 return mAxisPainter->tickLabelSide;
4095 return mAxisPainter->tickLabelSide;
4096 4096 }
4097 4097
4098 4098 /* No documentation as it is a property getter */
4099 4099 QString QCPAxis::numberFormat() const
4100 4100 {
4101 QString result;
4102 result.append(mNumberFormatChar);
4103 if (mNumberBeautifulPowers)
4104 {
4105 result.append(QLatin1Char('b'));
4106 if (mAxisPainter->numberMultiplyCross)
4107 result.append(QLatin1Char('c'));
4108 }
4109 return result;
4101 QString result;
4102 result.append(mNumberFormatChar);
4103 if (mNumberBeautifulPowers)
4104 {
4105 result.append(QLatin1Char('b'));
4106 if (mAxisPainter->numberMultiplyCross)
4107 result.append(QLatin1Char('c'));
4108 }
4109 return result;
4110 4110 }
4111 4111
4112 4112 /* No documentation as it is a property getter */
4113 4113 int QCPAxis::tickLengthIn() const
4114 4114 {
4115 return mAxisPainter->tickLengthIn;
4115 return mAxisPainter->tickLengthIn;
4116 4116 }
4117 4117
4118 4118 /* No documentation as it is a property getter */
4119 4119 int QCPAxis::tickLengthOut() const
4120 4120 {
4121 return mAxisPainter->tickLengthOut;
4121 return mAxisPainter->tickLengthOut;
4122 4122 }
4123 4123
4124 4124 /* No documentation as it is a property getter */
4125 4125 int QCPAxis::subTickLengthIn() const
4126 4126 {
4127 return mAxisPainter->subTickLengthIn;
4127 return mAxisPainter->subTickLengthIn;
4128 4128 }
4129 4129
4130 4130 /* No documentation as it is a property getter */
4131 4131 int QCPAxis::subTickLengthOut() const
4132 4132 {
4133 return mAxisPainter->subTickLengthOut;
4133 return mAxisPainter->subTickLengthOut;
4134 4134 }
4135 4135
4136 4136 /* No documentation as it is a property getter */
4137 4137 int QCPAxis::labelPadding() const
4138 4138 {
4139 return mAxisPainter->labelPadding;
4139 return mAxisPainter->labelPadding;
4140 4140 }
4141 4141
4142 4142 /* No documentation as it is a property getter */
4143 4143 int QCPAxis::offset() const
4144 4144 {
4145 return mAxisPainter->offset;
4145 return mAxisPainter->offset;
4146 4146 }
4147 4147
4148 4148 /* No documentation as it is a property getter */
4149 4149 QCPLineEnding QCPAxis::lowerEnding() const
4150 4150 {
4151 return mAxisPainter->lowerEnding;
4151 return mAxisPainter->lowerEnding;
4152 4152 }
4153 4153
4154 4154 /* No documentation as it is a property getter */
4155 4155 QCPLineEnding QCPAxis::upperEnding() const
4156 4156 {
4157 return mAxisPainter->upperEnding;
4157 return mAxisPainter->upperEnding;
4158 4158 }
4159 4159
4160 4160 /*!
@@ -4172,13 +4172,13 QCPLineEnding QCPAxis::upperEnding() con
4172 4172 */
4173 4173 void QCPAxis::setScaleType(QCPAxis::ScaleType type)
4174 4174 {
4175 if (mScaleType != type)
4176 {
4177 mScaleType = type;
4178 if (mScaleType == stLogarithmic)
4179 setRange(mRange.sanitizedForLogScale());
4180 mCachedMarginValid = false;
4181 emit scaleTypeChanged(mScaleType);
4175 if (mScaleType != type)
4176 {
4177 mScaleType = type;
4178 if (mScaleType == stLogarithmic)
4179 setRange(mRange.sanitizedForLogScale());
4180 mCachedMarginValid = false;
4181 emit scaleTypeChanged(mScaleType);
4182 4182 }
4183 4183 }
4184 4184
@@ -4191,13 +4191,13 void QCPAxis::setScaleType(QCPAxis::Scal
4191 4191 */
4192 4192 void QCPAxis::setScaleLogBase(double base)
4193 4193 {
4194 if (base > 1)
4195 {
4196 mScaleLogBase = base;
4197 mScaleLogBaseLogInv = 1.0/qLn(mScaleLogBase); // buffer for faster baseLog() calculation
4198 mCachedMarginValid = false;
4199 } else
4200 qDebug() << Q_FUNC_INFO << "Invalid logarithmic scale base (must be greater 1):" << base;
4194 if (base > 1)
4195 {
4196 mScaleLogBase = base;
4197 mScaleLogBaseLogInv = 1.0/qLn(mScaleLogBase); // buffer for faster baseLog() calculation
4198 mCachedMarginValid = false;
4199 } else
4200 qDebug() << Q_FUNC_INFO << "Invalid logarithmic scale base (must be greater 1):" << base;
4201 4201 }
4202 4202
4203 4203 /*!
@@ -4210,21 +4210,21 void QCPAxis::setScaleLogBase(double bas
4210 4210 */
4211 4211 void QCPAxis::setRange(const QCPRange &range)
4212 4212 {
4213 if (range.lower == mRange.lower && range.upper == mRange.upper)
4214 return;
4215
4216 if (!QCPRange::validRange(range)) return;
4217 QCPRange oldRange = mRange;
4218 if (mScaleType == stLogarithmic)
4219 {
4220 mRange = range.sanitizedForLogScale();
4221 } else
4222 {
4223 mRange = range.sanitizedForLinScale();
4224 }
4225 mCachedMarginValid = false;
4226 emit rangeChanged(mRange);
4227 emit rangeChanged(mRange, oldRange);
4213 if (range.lower == mRange.lower && range.upper == mRange.upper)
4214 return;
4215
4216 if (!QCPRange::validRange(range)) return;
4217 QCPRange oldRange = mRange;
4218 if (mScaleType == stLogarithmic)
4219 {
4220 mRange = range.sanitizedForLogScale();
4221 } else
4222 {
4223 mRange = range.sanitizedForLinScale();
4224 }
4225 mCachedMarginValid = false;
4226 emit rangeChanged(mRange);
4227 emit rangeChanged(mRange, oldRange);
4228 4228 }
4229 4229
4230 4230 /*!
@@ -4239,10 +4239,10 void QCPAxis::setRange(const QCPRange &r
4239 4239 */
4240 4240 void QCPAxis::setSelectableParts(const SelectableParts &selectable)
4241 4241 {
4242 if (mSelectableParts != selectable)
4243 {
4244 mSelectableParts = selectable;
4245 emit selectableChanged(mSelectableParts);
4242 if (mSelectableParts != selectable)
4243 {
4244 mSelectableParts = selectable;
4245 emit selectableChanged(mSelectableParts);
4246 4246 }
4247 4247 }
4248 4248
@@ -4263,10 +4263,10 void QCPAxis::setSelectableParts(const S
4263 4263 */
4264 4264 void QCPAxis::setSelectedParts(const SelectableParts &selected)
4265 4265 {
4266 if (mSelectedParts != selected)
4267 {
4268 mSelectedParts = selected;
4269 emit selectionChanged(mSelectedParts);
4266 if (mSelectedParts != selected)
4267 {
4268 mSelectedParts = selected;
4269 emit selectionChanged(mSelectedParts);
4270 4270 }
4271 4271 }
4272 4272
@@ -4281,23 +4281,23 void QCPAxis::setSelectedParts(const Sel
4281 4281 */
4282 4282 void QCPAxis::setRange(double lower, double upper)
4283 4283 {
4284 if (lower == mRange.lower && upper == mRange.upper)
4285 return;
4286
4287 if (!QCPRange::validRange(lower, upper)) return;
4288 QCPRange oldRange = mRange;
4289 mRange.lower = lower;
4290 mRange.upper = upper;
4291 if (mScaleType == stLogarithmic)
4292 {
4293 mRange = mRange.sanitizedForLogScale();
4294 } else
4295 {
4296 mRange = mRange.sanitizedForLinScale();
4297 }
4298 mCachedMarginValid = false;
4299 emit rangeChanged(mRange);
4300 emit rangeChanged(mRange, oldRange);
4284 if (lower == mRange.lower && upper == mRange.upper)
4285 return;
4286
4287 if (!QCPRange::validRange(lower, upper)) return;
4288 QCPRange oldRange = mRange;
4289 mRange.lower = lower;
4290 mRange.upper = upper;
4291 if (mScaleType == stLogarithmic)
4292 {
4293 mRange = mRange.sanitizedForLogScale();
4294 } else
4295 {
4296 mRange = mRange.sanitizedForLinScale();
4297 }
4298 mCachedMarginValid = false;
4299 emit rangeChanged(mRange);
4300 emit rangeChanged(mRange, oldRange);
4301 4301 }
4302 4302
4303 4303 /*!
@@ -4313,12 +4313,12 void QCPAxis::setRange(double lower, dou
4313 4313 */
4314 4314 void QCPAxis::setRange(double position, double size, Qt::AlignmentFlag alignment)
4315 4315 {
4316 if (alignment == Qt::AlignLeft)
4317 setRange(position, position+size);
4318 else if (alignment == Qt::AlignRight)
4319 setRange(position-size, position);
4320 else // alignment == Qt::AlignCenter
4321 setRange(position-size/2.0, position+size/2.0);
4316 if (alignment == Qt::AlignLeft)
4317 setRange(position, position+size);
4318 else if (alignment == Qt::AlignRight)
4319 setRange(position-size, position);
4320 else // alignment == Qt::AlignCenter
4321 setRange(position-size/2.0, position+size/2.0);
4322 4322 }
4323 4323
4324 4324 /*!
@@ -4327,21 +4327,21 void QCPAxis::setRange(double position,
4327 4327 */
4328 4328 void QCPAxis::setRangeLower(double lower)
4329 4329 {
4330 if (mRange.lower == lower)
4331 return;
4332
4333 QCPRange oldRange = mRange;
4334 mRange.lower = lower;
4335 if (mScaleType == stLogarithmic)
4336 {
4337 mRange = mRange.sanitizedForLogScale();
4338 } else
4339 {
4340 mRange = mRange.sanitizedForLinScale();
4341 }
4342 mCachedMarginValid = false;
4343 emit rangeChanged(mRange);
4344 emit rangeChanged(mRange, oldRange);
4330 if (mRange.lower == lower)
4331 return;
4332
4333 QCPRange oldRange = mRange;
4334 mRange.lower = lower;
4335 if (mScaleType == stLogarithmic)
4336 {
4337 mRange = mRange.sanitizedForLogScale();
4338 } else
4339 {
4340 mRange = mRange.sanitizedForLinScale();
4341 }
4342 mCachedMarginValid = false;
4343 emit rangeChanged(mRange);
4344 emit rangeChanged(mRange, oldRange);
4345 4345 }
4346 4346
4347 4347 /*!
@@ -4350,21 +4350,21 void QCPAxis::setRangeLower(double lower
4350 4350 */
4351 4351 void QCPAxis::setRangeUpper(double upper)
4352 4352 {
4353 if (mRange.upper == upper)
4354 return;
4355
4356 QCPRange oldRange = mRange;
4357 mRange.upper = upper;
4358 if (mScaleType == stLogarithmic)
4359 {
4360 mRange = mRange.sanitizedForLogScale();
4361 } else
4362 {
4363 mRange = mRange.sanitizedForLinScale();
4364 }
4365 mCachedMarginValid = false;
4366 emit rangeChanged(mRange);
4367 emit rangeChanged(mRange, oldRange);
4353 if (mRange.upper == upper)
4354 return;
4355
4356 QCPRange oldRange = mRange;
4357 mRange.upper = upper;
4358 if (mScaleType == stLogarithmic)
4359 {
4360 mRange = mRange.sanitizedForLogScale();
4361 } else
4362 {
4363 mRange = mRange.sanitizedForLinScale();
4364 }
4365 mCachedMarginValid = false;
4366 emit rangeChanged(mRange);
4367 emit rangeChanged(mRange, oldRange);
4368 4368 }
4369 4369
4370 4370 /*!
@@ -4378,10 +4378,10 void QCPAxis::setRangeUpper(double upper
4378 4378 */
4379 4379 void QCPAxis::setRangeReversed(bool reversed)
4380 4380 {
4381 if (mRangeReversed != reversed)
4382 {
4383 mRangeReversed = reversed;
4384 mCachedMarginValid = false;
4381 if (mRangeReversed != reversed)
4382 {
4383 mRangeReversed = reversed;
4384 mCachedMarginValid = false;
4385 4385 }
4386 4386 }
4387 4387
@@ -4402,10 +4402,10 void QCPAxis::setRangeReversed(bool reve
4402 4402 */
4403 4403 void QCPAxis::setAutoTicks(bool on)
4404 4404 {
4405 if (mAutoTicks != on)
4406 {
4407 mAutoTicks = on;
4408 mCachedMarginValid = false;
4405 if (mAutoTicks != on)
4406 {
4407 mAutoTicks = on;
4408 mCachedMarginValid = false;
4409 4409 }
4410 4410 }
4411 4411
@@ -4422,14 +4422,14 void QCPAxis::setAutoTicks(bool on)
4422 4422 */
4423 4423 void QCPAxis::setAutoTickCount(int approximateCount)
4424 4424 {
4425 if (mAutoTickCount != approximateCount)
4426 {
4427 if (approximateCount > 0)
4428 {
4429 mAutoTickCount = approximateCount;
4430 mCachedMarginValid = false;
4425 if (mAutoTickCount != approximateCount)
4426 {
4427 if (approximateCount > 0)
4428 {
4429 mAutoTickCount = approximateCount;
4430 mCachedMarginValid = false;
4431 4431 } else
4432 qDebug() << Q_FUNC_INFO << "approximateCount must be greater than zero:" << approximateCount;
4432 qDebug() << Q_FUNC_INFO << "approximateCount must be greater than zero:" << approximateCount;
4433 4433 }
4434 4434 }
4435 4435
@@ -4450,10 +4450,10 void QCPAxis::setAutoTickCount(int appro
4450 4450 */
4451 4451 void QCPAxis::setAutoTickLabels(bool on)
4452 4452 {
4453 if (mAutoTickLabels != on)
4454 {
4455 mAutoTickLabels = on;
4456 mCachedMarginValid = false;
4453 if (mAutoTickLabels != on)
4454 {
4455 mAutoTickLabels = on;
4456 mCachedMarginValid = false;
4457 4457 }
4458 4458 }
4459 4459
@@ -4471,10 +4471,10 void QCPAxis::setAutoTickLabels(bool on)
4471 4471 */
4472 4472 void QCPAxis::setAutoTickStep(bool on)
4473 4473 {
4474 if (mAutoTickStep != on)
4475 {
4476 mAutoTickStep = on;
4477 mCachedMarginValid = false;
4474 if (mAutoTickStep != on)
4475 {
4476 mAutoTickStep = on;
4477 mCachedMarginValid = false;
4478 4478 }
4479 4479 }
4480 4480
@@ -4489,10 +4489,10 void QCPAxis::setAutoTickStep(bool on)
4489 4489 */
4490 4490 void QCPAxis::setAutoSubTicks(bool on)
4491 4491 {
4492 if (mAutoSubTicks != on)
4493 {
4494 mAutoSubTicks = on;
4495 mCachedMarginValid = false;
4492 if (mAutoSubTicks != on)
4493 {
4494 mAutoSubTicks = on;
4495 mCachedMarginValid = false;
4496 4496 }
4497 4497 }
4498 4498
@@ -4504,10 +4504,10 void QCPAxis::setAutoSubTicks(bool on)
4504 4504 */
4505 4505 void QCPAxis::setTicks(bool show)
4506 4506 {
4507 if (mTicks != show)
4508 {
4509 mTicks = show;
4510 mCachedMarginValid = false;
4507 if (mTicks != show)
4508 {
4509 mTicks = show;
4510 mCachedMarginValid = false;
4511 4511 }
4512 4512 }
4513 4513
@@ -4516,10 +4516,10 void QCPAxis::setTicks(bool show)
4516 4516 */
4517 4517 void QCPAxis::setTickLabels(bool show)
4518 4518 {
4519 if (mTickLabels != show)
4520 {
4521 mTickLabels = show;
4522 mCachedMarginValid = false;
4519 if (mTickLabels != show)
4520 {
4521 mTickLabels = show;
4522 mCachedMarginValid = false;
4523 4523 }
4524 4524 }
4525 4525
@@ -4529,10 +4529,10 void QCPAxis::setTickLabels(bool show)
4529 4529 */
4530 4530 void QCPAxis::setTickLabelPadding(int padding)
4531 4531 {
4532 if (mAxisPainter->tickLabelPadding != padding)
4533 {
4534 mAxisPainter->tickLabelPadding = padding;
4535 mCachedMarginValid = false;
4532 if (mAxisPainter->tickLabelPadding != padding)
4533 {
4534 mAxisPainter->tickLabelPadding = padding;
4535 mCachedMarginValid = false;
4536 4536 }
4537 4537 }
4538 4538
@@ -4559,10 +4559,10 void QCPAxis::setTickLabelPadding(int pa
4559 4559 */
4560 4560 void QCPAxis::setTickLabelType(LabelType type)
4561 4561 {
4562 if (mTickLabelType != type)
4563 {
4564 mTickLabelType = type;
4565 mCachedMarginValid = false;
4562 if (mTickLabelType != type)
4563 {
4564 mTickLabelType = type;
4565 mCachedMarginValid = false;
4566 4566 }
4567 4567 }
4568 4568
@@ -4573,10 +4573,10 void QCPAxis::setTickLabelType(LabelType
4573 4573 */
4574 4574 void QCPAxis::setTickLabelFont(const QFont &font)
4575 4575 {
4576 if (font != mTickLabelFont)
4577 {
4578 mTickLabelFont = font;
4579 mCachedMarginValid = false;
4576 if (font != mTickLabelFont)
4577 {
4578 mTickLabelFont = font;
4579 mCachedMarginValid = false;
4580 4580 }
4581 4581 }
4582 4582
@@ -4587,10 +4587,10 void QCPAxis::setTickLabelFont(const QFo
4587 4587 */
4588 4588 void QCPAxis::setTickLabelColor(const QColor &color)
4589 4589 {
4590 if (color != mTickLabelColor)
4591 {
4592 mTickLabelColor = color;
4593 mCachedMarginValid = false;
4590 if (color != mTickLabelColor)
4591 {
4592 mTickLabelColor = color;
4593 mCachedMarginValid = false;
4594 4594 }
4595 4595 }
4596 4596
@@ -4605,10 +4605,10 void QCPAxis::setTickLabelColor(const QC
4605 4605 */
4606 4606 void QCPAxis::setTickLabelRotation(double degrees)
4607 4607 {
4608 if (!qFuzzyIsNull(degrees-mAxisPainter->tickLabelRotation))
4609 {
4610 mAxisPainter->tickLabelRotation = qBound(-90.0, degrees, 90.0);
4611 mCachedMarginValid = false;
4608 if (!qFuzzyIsNull(degrees-mAxisPainter->tickLabelRotation))
4609 {
4610 mAxisPainter->tickLabelRotation = qBound(-90.0, degrees, 90.0);
4611 mCachedMarginValid = false;
4612 4612 }
4613 4613 }
4614 4614
@@ -4621,8 +4621,8 void QCPAxis::setTickLabelRotation(doubl
4621 4621 */
4622 4622 void QCPAxis::setTickLabelSide(LabelSide side)
4623 4623 {
4624 mAxisPainter->tickLabelSide = side;
4625 mCachedMarginValid = false;
4624 mAxisPainter->tickLabelSide = side;
4625 mCachedMarginValid = false;
4626 4626 }
4627 4627
4628 4628 /*!
@@ -4635,10 +4635,10 void QCPAxis::setTickLabelSide(LabelSide
4635 4635 */
4636 4636 void QCPAxis::setDateTimeFormat(const QString &format)
4637 4637 {
4638 if (mDateTimeFormat != format)
4639 {
4640 mDateTimeFormat = format;
4641 mCachedMarginValid = false;
4638 if (mDateTimeFormat != format)
4639 {
4640 mDateTimeFormat = format;
4641 mCachedMarginValid = false;
4642 4642 }
4643 4643 }
4644 4644
@@ -4654,7 +4654,7 void QCPAxis::setDateTimeFormat(const QS
4654 4654 */
4655 4655 void QCPAxis::setDateTimeSpec(const Qt::TimeSpec &timeSpec)
4656 4656 {
4657 mDateTimeSpec = timeSpec;
4657 mDateTimeSpec = timeSpec;
4658 4658 }
4659 4659
4660 4660 /*!
@@ -4695,56 +4695,56 void QCPAxis::setDateTimeSpec(const Qt::
4695 4695 */
4696 4696 void QCPAxis::setNumberFormat(const QString &formatCode)
4697 4697 {
4698 if (formatCode.isEmpty())
4699 {
4700 qDebug() << Q_FUNC_INFO << "Passed formatCode is empty";
4701 return;
4702 }
4703 mCachedMarginValid = false;
4704
4705 // interpret first char as number format char:
4706 QString allowedFormatChars(QLatin1String("eEfgG"));
4707 if (allowedFormatChars.contains(formatCode.at(0)))
4708 {
4709 mNumberFormatChar = QLatin1Char(formatCode.at(0).toLatin1());
4710 } else
4711 {
4712 qDebug() << Q_FUNC_INFO << "Invalid number format code (first char not in 'eEfgG'):" << formatCode;
4713 return;
4714 }
4715 if (formatCode.length() < 2)
4716 {
4717 mNumberBeautifulPowers = false;
4718 mAxisPainter->numberMultiplyCross = false;
4719 return;
4720 }
4721
4722 // interpret second char as indicator for beautiful decimal powers:
4723 if (formatCode.at(1) == QLatin1Char('b') && (mNumberFormatChar == QLatin1Char('e') || mNumberFormatChar == QLatin1Char('g')))
4724 {
4725 mNumberBeautifulPowers = true;
4726 } else
4727 {
4728 qDebug() << Q_FUNC_INFO << "Invalid number format code (second char not 'b' or first char neither 'e' nor 'g'):" << formatCode;
4729 return;
4730 }
4731 if (formatCode.length() < 3)
4732 {
4733 mAxisPainter->numberMultiplyCross = false;
4734 return;
4735 }
4736
4737 // interpret third char as indicator for dot or cross multiplication symbol:
4738 if (formatCode.at(2) == QLatin1Char('c'))
4739 {
4740 mAxisPainter->numberMultiplyCross = true;
4698 if (formatCode.isEmpty())
4699 {
4700 qDebug() << Q_FUNC_INFO << "Passed formatCode is empty";
4701 return;
4702 }
4703 mCachedMarginValid = false;
4704
4705 // interpret first char as number format char:
4706 QString allowedFormatChars(QLatin1String("eEfgG"));
4707 if (allowedFormatChars.contains(formatCode.at(0)))
4708 {
4709 mNumberFormatChar = QLatin1Char(formatCode.at(0).toLatin1());
4710 } else
4711 {
4712 qDebug() << Q_FUNC_INFO << "Invalid number format code (first char not in 'eEfgG'):" << formatCode;
4713 return;
4714 }
4715 if (formatCode.length() < 2)
4716 {
4717 mNumberBeautifulPowers = false;
4718 mAxisPainter->numberMultiplyCross = false;
4719 return;
4720 }
4721
4722 // interpret second char as indicator for beautiful decimal powers:
4723 if (formatCode.at(1) == QLatin1Char('b') && (mNumberFormatChar == QLatin1Char('e') || mNumberFormatChar == QLatin1Char('g')))
4724 {
4725 mNumberBeautifulPowers = true;
4726 } else
4727 {
4728 qDebug() << Q_FUNC_INFO << "Invalid number format code (second char not 'b' or first char neither 'e' nor 'g'):" << formatCode;
4729 return;
4730 }
4731 if (formatCode.length() < 3)
4732 {
4733 mAxisPainter->numberMultiplyCross = false;
4734 return;
4735 }
4736
4737 // interpret third char as indicator for dot or cross multiplication symbol:
4738 if (formatCode.at(2) == QLatin1Char('c'))
4739 {
4740 mAxisPainter->numberMultiplyCross = true;
4741 4741 } else if (formatCode.at(2) == QLatin1Char('d'))
4742 4742 {
4743 mAxisPainter->numberMultiplyCross = false;
4744 } else
4745 {
4746 qDebug() << Q_FUNC_INFO << "Invalid number format code (third char neither 'c' nor 'd'):" << formatCode;
4747 return;
4743 mAxisPainter->numberMultiplyCross = false;
4744 } else
4745 {
4746 qDebug() << Q_FUNC_INFO << "Invalid number format code (third char neither 'c' nor 'd'):" << formatCode;
4747 return;
4748 4748 }
4749 4749 }
4750 4750
@@ -4761,10 +4761,10 void QCPAxis::setNumberFormat(const QStr
4761 4761 */
4762 4762 void QCPAxis::setNumberPrecision(int precision)
4763 4763 {
4764 if (mNumberPrecision != precision)
4765 {
4766 mNumberPrecision = precision;
4767 mCachedMarginValid = false;
4764 if (mNumberPrecision != precision)
4765 {
4766 mNumberPrecision = precision;
4767 mCachedMarginValid = false;
4768 4768 }
4769 4769 }
4770 4770
@@ -4775,10 +4775,10 void QCPAxis::setNumberPrecision(int pre
4775 4775 */
4776 4776 void QCPAxis::setTickStep(double step)
4777 4777 {
4778 if (mTickStep != step)
4779 {
4780 mTickStep = step;
4781 mCachedMarginValid = false;
4778 if (mTickStep != step)
4779 {
4780 mTickStep = step;
4781 mCachedMarginValid = false;
4782 4782 }
4783 4783 }
4784 4784
@@ -4797,9 +4797,9 void QCPAxis::setTickStep(double step)
4797 4797 */
4798 4798 void QCPAxis::setTickVector(const QVector<double> &vec)
4799 4799 {
4800 // don't check whether mTickVector != vec here, because it takes longer than we would save
4801 mTickVector = vec;
4802 mCachedMarginValid = false;
4800 // don't check whether mTickVector != vec here, because it takes longer than we would save
4801 mTickVector = vec;
4802 mCachedMarginValid = false;
4803 4803 }
4804 4804
4805 4805 /*!
@@ -4815,9 +4815,9 void QCPAxis::setTickVector(const QVecto
4815 4815 */
4816 4816 void QCPAxis::setTickVectorLabels(const QVector<QString> &vec)
4817 4817 {
4818 // don't check whether mTickVectorLabels != vec here, because it takes longer than we would save
4819 mTickVectorLabels = vec;
4820 mCachedMarginValid = false;
4818 // don't check whether mTickVectorLabels != vec here, because it takes longer than we would save
4819 mTickVectorLabels = vec;
4820 mCachedMarginValid = false;
4821 4821 }
4822 4822
4823 4823 /*!
@@ -4830,8 +4830,8 void QCPAxis::setTickVectorLabels(const
4830 4830 */
4831 4831 void QCPAxis::setTickLength(int inside, int outside)
4832 4832 {
4833 setTickLengthIn(inside);
4834 setTickLengthOut(outside);
4833 setTickLengthIn(inside);
4834 setTickLengthOut(outside);
4835 4835 }
4836 4836
4837 4837 /*!
@@ -4842,9 +4842,9 void QCPAxis::setTickLength(int inside,
4842 4842 */
4843 4843 void QCPAxis::setTickLengthIn(int inside)
4844 4844 {
4845 if (mAxisPainter->tickLengthIn != inside)
4846 {
4847 mAxisPainter->tickLengthIn = inside;
4845 if (mAxisPainter->tickLengthIn != inside)
4846 {
4847 mAxisPainter->tickLengthIn = inside;
4848 4848 }
4849 4849 }
4850 4850
@@ -4857,10 +4857,10 void QCPAxis::setTickLengthIn(int inside
4857 4857 */
4858 4858 void QCPAxis::setTickLengthOut(int outside)
4859 4859 {
4860 if (mAxisPainter->tickLengthOut != outside)
4861 {
4862 mAxisPainter->tickLengthOut = outside;
4863 mCachedMarginValid = false; // only outside tick length can change margin
4860 if (mAxisPainter->tickLengthOut != outside)
4861 {
4862 mAxisPainter->tickLengthOut = outside;
4863 mCachedMarginValid = false; // only outside tick length can change margin
4864 4864 }
4865 4865 }
4866 4866
@@ -4877,7 +4877,7 void QCPAxis::setTickLengthOut(int outsi
4877 4877 */
4878 4878 void QCPAxis::setSubTickCount(int count)
4879 4879 {
4880 mSubTickCount = count;
4880 mSubTickCount = count;
4881 4881 }
4882 4882
4883 4883 /*!
@@ -4890,8 +4890,8 void QCPAxis::setSubTickCount(int count)
4890 4890 */
4891 4891 void QCPAxis::setSubTickLength(int inside, int outside)
4892 4892 {
4893 setSubTickLengthIn(inside);
4894 setSubTickLengthOut(outside);
4893 setSubTickLengthIn(inside);
4894 setSubTickLengthOut(outside);
4895 4895 }
4896 4896
4897 4897 /*!
@@ -4902,9 +4902,9 void QCPAxis::setSubTickLength(int insid
4902 4902 */
4903 4903 void QCPAxis::setSubTickLengthIn(int inside)
4904 4904 {
4905 if (mAxisPainter->subTickLengthIn != inside)
4906 {
4907 mAxisPainter->subTickLengthIn = inside;
4905 if (mAxisPainter->subTickLengthIn != inside)
4906 {
4907 mAxisPainter->subTickLengthIn = inside;
4908 4908 }
4909 4909 }
4910 4910
@@ -4917,10 +4917,10 void QCPAxis::setSubTickLengthIn(int ins
4917 4917 */
4918 4918 void QCPAxis::setSubTickLengthOut(int outside)
4919 4919 {
4920 if (mAxisPainter->subTickLengthOut != outside)
4921 {
4922 mAxisPainter->subTickLengthOut = outside;
4923 mCachedMarginValid = false; // only outside tick length can change margin
4920 if (mAxisPainter->subTickLengthOut != outside)
4921 {
4922 mAxisPainter->subTickLengthOut = outside;
4923 mCachedMarginValid = false; // only outside tick length can change margin
4924 4924 }
4925 4925 }
4926 4926
@@ -4931,7 +4931,7 void QCPAxis::setSubTickLengthOut(int ou
4931 4931 */
4932 4932 void QCPAxis::setBasePen(const QPen &pen)
4933 4933 {
4934 mBasePen = pen;
4934 mBasePen = pen;
4935 4935 }
4936 4936
4937 4937 /*!
@@ -4941,7 +4941,7 void QCPAxis::setBasePen(const QPen &pen
4941 4941 */
4942 4942 void QCPAxis::setTickPen(const QPen &pen)
4943 4943 {
4944 mTickPen = pen;
4944 mTickPen = pen;
4945 4945 }
4946 4946
4947 4947 /*!
@@ -4951,7 +4951,7 void QCPAxis::setTickPen(const QPen &pen
4951 4951 */
4952 4952 void QCPAxis::setSubTickPen(const QPen &pen)
4953 4953 {
4954 mSubTickPen = pen;
4954 mSubTickPen = pen;
4955 4955 }
4956 4956
4957 4957 /*!
@@ -4961,10 +4961,10 void QCPAxis::setSubTickPen(const QPen &
4961 4961 */
4962 4962 void QCPAxis::setLabelFont(const QFont &font)
4963 4963 {
4964 if (mLabelFont != font)
4965 {
4966 mLabelFont = font;
4967 mCachedMarginValid = false;
4964 if (mLabelFont != font)
4965 {
4966 mLabelFont = font;
4967 mCachedMarginValid = false;
4968 4968 }
4969 4969 }
4970 4970
@@ -4975,7 +4975,7 void QCPAxis::setLabelFont(const QFont &
4975 4975 */
4976 4976 void QCPAxis::setLabelColor(const QColor &color)
4977 4977 {
4978 mLabelColor = color;
4978 mLabelColor = color;
4979 4979 }
4980 4980
4981 4981 /*!
@@ -4984,10 +4984,10 void QCPAxis::setLabelColor(const QColor
4984 4984 */
4985 4985 void QCPAxis::setLabel(const QString &str)
4986 4986 {
4987 if (mLabel != str)
4988 {
4989 mLabel = str;
4990 mCachedMarginValid = false;
4987 if (mLabel != str)
4988 {
4989 mLabel = str;
4990 mCachedMarginValid = false;
4991 4991 }
4992 4992 }
4993 4993
@@ -4998,10 +4998,10 void QCPAxis::setLabel(const QString &st
4998 4998 */
4999 4999 void QCPAxis::setLabelPadding(int padding)
5000 5000 {
5001 if (mAxisPainter->labelPadding != padding)
5002 {
5003 mAxisPainter->labelPadding = padding;
5004 mCachedMarginValid = false;
5001 if (mAxisPainter->labelPadding != padding)
5002 {
5003 mAxisPainter->labelPadding = padding;
5004 mCachedMarginValid = false;
5005 5005 }
5006 5006 }
5007 5007
@@ -5017,10 +5017,10 void QCPAxis::setLabelPadding(int paddin
5017 5017 */
5018 5018 void QCPAxis::setPadding(int padding)
5019 5019 {
5020 if (mPadding != padding)
5021 {
5022 mPadding = padding;
5023 mCachedMarginValid = false;
5020 if (mPadding != padding)
5021 {
5022 mPadding = padding;
5023 mCachedMarginValid = false;
5024 5024 }
5025 5025 }
5026 5026
@@ -5034,7 +5034,7 void QCPAxis::setPadding(int padding)
5034 5034 */
5035 5035 void QCPAxis::setOffset(int offset)
5036 5036 {
5037 mAxisPainter->offset = offset;
5037 mAxisPainter->offset = offset;
5038 5038 }
5039 5039
5040 5040 /*!
@@ -5044,10 +5044,10 void QCPAxis::setOffset(int offset)
5044 5044 */
5045 5045 void QCPAxis::setSelectedTickLabelFont(const QFont &font)
5046 5046 {
5047 if (font != mSelectedTickLabelFont)
5048 {
5049 mSelectedTickLabelFont = font;
5050 // don't set mCachedMarginValid to false here because margin calculation is always done with non-selected fonts
5047 if (font != mSelectedTickLabelFont)
5048 {
5049 mSelectedTickLabelFont = font;
5050 // don't set mCachedMarginValid to false here because margin calculation is always done with non-selected fonts
5051 5051 }
5052 5052 }
5053 5053
@@ -5058,8 +5058,8 void QCPAxis::setSelectedTickLabelFont(c
5058 5058 */
5059 5059 void QCPAxis::setSelectedLabelFont(const QFont &font)
5060 5060 {
5061 mSelectedLabelFont = font;
5062 // don't set mCachedMarginValid to false here because margin calculation is always done with non-selected fonts
5061 mSelectedLabelFont = font;
5062 // don't set mCachedMarginValid to false here because margin calculation is always done with non-selected fonts
5063 5063 }
5064 5064
5065 5065 /*!
@@ -5069,9 +5069,9 void QCPAxis::setSelectedLabelFont(const
5069 5069 */
5070 5070 void QCPAxis::setSelectedTickLabelColor(const QColor &color)
5071 5071 {
5072 if (color != mSelectedTickLabelColor)
5073 {
5074 mSelectedTickLabelColor = color;
5072 if (color != mSelectedTickLabelColor)
5073 {
5074 mSelectedTickLabelColor = color;
5075 5075 }
5076 5076 }
5077 5077
@@ -5082,7 +5082,7 void QCPAxis::setSelectedTickLabelColor(
5082 5082 */
5083 5083 void QCPAxis::setSelectedLabelColor(const QColor &color)
5084 5084 {
5085 mSelectedLabelColor = color;
5085 mSelectedLabelColor = color;
5086 5086 }
5087 5087
5088 5088 /*!
@@ -5092,7 +5092,7 void QCPAxis::setSelectedLabelColor(cons
5092 5092 */
5093 5093 void QCPAxis::setSelectedBasePen(const QPen &pen)
5094 5094 {
5095 mSelectedBasePen = pen;
5095 mSelectedBasePen = pen;
5096 5096 }
5097 5097
5098 5098 /*!
@@ -5102,7 +5102,7 void QCPAxis::setSelectedBasePen(const Q
5102 5102 */
5103 5103 void QCPAxis::setSelectedTickPen(const QPen &pen)
5104 5104 {
5105 mSelectedTickPen = pen;
5105 mSelectedTickPen = pen;
5106 5106 }
5107 5107
5108 5108 /*!
@@ -5112,7 +5112,7 void QCPAxis::setSelectedTickPen(const Q
5112 5112 */
5113 5113 void QCPAxis::setSelectedSubTickPen(const QPen &pen)
5114 5114 {
5115 mSelectedSubTickPen = pen;
5115 mSelectedSubTickPen = pen;
5116 5116 }
5117 5117
5118 5118 /*!
@@ -5127,7 +5127,7 void QCPAxis::setSelectedSubTickPen(cons
5127 5127 */
5128 5128 void QCPAxis::setLowerEnding(const QCPLineEnding &ending)
5129 5129 {
5130 mAxisPainter->lowerEnding = ending;
5130 mAxisPainter->lowerEnding = ending;
5131 5131 }
5132 5132
5133 5133 /*!
@@ -5142,7 +5142,7 void QCPAxis::setLowerEnding(const QCPLi
5142 5142 */
5143 5143 void QCPAxis::setUpperEnding(const QCPLineEnding &ending)
5144 5144 {
5145 mAxisPainter->upperEnding = ending;
5145 mAxisPainter->upperEnding = ending;
5146 5146 }
5147 5147
5148 5148 /*!
@@ -5154,19 +5154,19 void QCPAxis::setUpperEnding(const QCPLi
5154 5154 */
5155 5155 void QCPAxis::moveRange(double diff)
5156 5156 {
5157 QCPRange oldRange = mRange;
5158 if (mScaleType == stLinear)
5159 {
5160 mRange.lower += diff;
5161 mRange.upper += diff;
5157 QCPRange oldRange = mRange;
5158 if (mScaleType == stLinear)
5159 {
5160 mRange.lower += diff;
5161 mRange.upper += diff;
5162 5162 } else // mScaleType == stLogarithmic
5163 5163 {
5164 mRange.lower *= diff;
5165 mRange.upper *= diff;
5166 }
5167 mCachedMarginValid = false;
5168 emit rangeChanged(mRange);
5169 emit rangeChanged(mRange, oldRange);
5164 mRange.lower *= diff;
5165 mRange.upper *= diff;
5166 }
5167 mCachedMarginValid = false;
5168 emit rangeChanged(mRange);
5169 emit rangeChanged(mRange, oldRange);
5170 5170 }
5171 5171
5172 5172 /*!
@@ -5177,29 +5177,29 void QCPAxis::moveRange(double diff)
5177 5177 */
5178 5178 void QCPAxis::scaleRange(double factor, double center)
5179 5179 {
5180 QCPRange oldRange = mRange;
5181 if (mScaleType == stLinear)
5182 {
5183 QCPRange newRange;
5184 newRange.lower = (mRange.lower-center)*factor + center;
5185 newRange.upper = (mRange.upper-center)*factor + center;
5186 if (QCPRange::validRange(newRange))
5187 mRange = newRange.sanitizedForLinScale();
5180 QCPRange oldRange = mRange;
5181 if (mScaleType == stLinear)
5182 {
5183 QCPRange newRange;
5184 newRange.lower = (mRange.lower-center)*factor + center;
5185 newRange.upper = (mRange.upper-center)*factor + center;
5186 if (QCPRange::validRange(newRange))
5187 mRange = newRange.sanitizedForLinScale();
5188 5188 } else // mScaleType == stLogarithmic
5189 5189 {
5190 if ((mRange.upper < 0 && center < 0) || (mRange.upper > 0 && center > 0)) // make sure center has same sign as range
5191 {
5192 QCPRange newRange;
5193 newRange.lower = qPow(mRange.lower/center, factor)*center;
5194 newRange.upper = qPow(mRange.upper/center, factor)*center;
5195 if (QCPRange::validRange(newRange))
5196 mRange = newRange.sanitizedForLogScale();
5190 if ((mRange.upper < 0 && center < 0) || (mRange.upper > 0 && center > 0)) // make sure center has same sign as range
5191 {
5192 QCPRange newRange;
5193 newRange.lower = qPow(mRange.lower/center, factor)*center;
5194 newRange.upper = qPow(mRange.upper/center, factor)*center;
5195 if (QCPRange::validRange(newRange))
5196 mRange = newRange.sanitizedForLogScale();
5197 5197 } else
5198 qDebug() << Q_FUNC_INFO << "Center of scaling operation doesn't lie in same logarithmic sign domain as range:" << center;
5199 }
5200 mCachedMarginValid = false;
5201 emit rangeChanged(mRange);
5202 emit rangeChanged(mRange, oldRange);
5198 qDebug() << Q_FUNC_INFO << "Center of scaling operation doesn't lie in same logarithmic sign domain as range:" << center;
5199 }
5200 mCachedMarginValid = false;
5201 emit rangeChanged(mRange);
5202 emit rangeChanged(mRange, oldRange);
5203 5203 }
5204 5204
5205 5205 /*!
@@ -5217,20 +5217,20 void QCPAxis::scaleRange(double factor,
5217 5217 */
5218 5218 void QCPAxis::setScaleRatio(const QCPAxis *otherAxis, double ratio)
5219 5219 {
5220 int otherPixelSize, ownPixelSize;
5221
5222 if (otherAxis->orientation() == Qt::Horizontal)
5223 otherPixelSize = otherAxis->axisRect()->width();
5224 else
5225 otherPixelSize = otherAxis->axisRect()->height();
5226
5227 if (orientation() == Qt::Horizontal)
5228 ownPixelSize = axisRect()->width();
5229 else
5230 ownPixelSize = axisRect()->height();
5231
5232 double newRangeSize = ratio*otherAxis->range().size()*ownPixelSize/(double)otherPixelSize;
5233 setRange(range().center(), newRangeSize, Qt::AlignCenter);
5220 int otherPixelSize, ownPixelSize;
5221
5222 if (otherAxis->orientation() == Qt::Horizontal)
5223 otherPixelSize = otherAxis->axisRect()->width();
5224 else
5225 otherPixelSize = otherAxis->axisRect()->height();
5226
5227 if (orientation() == Qt::Horizontal)
5228 ownPixelSize = axisRect()->width();
5229 else
5230 ownPixelSize = axisRect()->height();
5231
5232 double newRangeSize = ratio*otherAxis->range().size()*ownPixelSize/(double)otherPixelSize;
5233 setRange(range().center(), newRangeSize, Qt::AlignCenter);
5234 5234 }
5235 5235
5236 5236 /*!
@@ -5241,47 +5241,47 void QCPAxis::setScaleRatio(const QCPAxi
5241 5241 */
5242 5242 void QCPAxis::rescale(bool onlyVisiblePlottables)
5243 5243 {
5244 QList<QCPAbstractPlottable*> p = plottables();
5245 QCPRange newRange;
5246 bool haveRange = false;
5247 for (int i=0; i<p.size(); ++i)
5248 {
5249 if (!p.at(i)->realVisibility() && onlyVisiblePlottables)
5250 continue;
5251 QCPRange plottableRange;
5252 bool currentFoundRange;
5253 QCPAbstractPlottable::SignDomain signDomain = QCPAbstractPlottable::sdBoth;
5254 if (mScaleType == stLogarithmic)
5255 signDomain = (mRange.upper < 0 ? QCPAbstractPlottable::sdNegative : QCPAbstractPlottable::sdPositive);
5256 if (p.at(i)->keyAxis() == this)
5257 plottableRange = p.at(i)->getKeyRange(currentFoundRange, signDomain);
5258 else
5259 plottableRange = p.at(i)->getValueRange(currentFoundRange, signDomain);
5260 if (currentFoundRange)
5261 {
5262 if (!haveRange)
5263 newRange = plottableRange;
5264 else
5265 newRange.expand(plottableRange);
5266 haveRange = true;
5267 }
5268 }
5269 if (haveRange)
5270 {
5271 if (!QCPRange::validRange(newRange)) // likely due to range being zero (plottable has only constant data in this axis dimension), shift current range to at least center the plottable
5272 {
5273 double center = (newRange.lower+newRange.upper)*0.5; // upper and lower should be equal anyway, but just to make sure, incase validRange returned false for other reason
5274 if (mScaleType == stLinear)
5275 {
5276 newRange.lower = center-mRange.size()/2.0;
5277 newRange.upper = center+mRange.size()/2.0;
5244 QList<QCPAbstractPlottable*> p = plottables();
5245 QCPRange newRange;
5246 bool haveRange = false;
5247 for (int i=0; i<p.size(); ++i)
5248 {
5249 if (!p.at(i)->realVisibility() && onlyVisiblePlottables)
5250 continue;
5251 QCPRange plottableRange;
5252 bool currentFoundRange;
5253 QCPAbstractPlottable::SignDomain signDomain = QCPAbstractPlottable::sdBoth;
5254 if (mScaleType == stLogarithmic)
5255 signDomain = (mRange.upper < 0 ? QCPAbstractPlottable::sdNegative : QCPAbstractPlottable::sdPositive);
5256 if (p.at(i)->keyAxis() == this)
5257 plottableRange = p.at(i)->getKeyRange(currentFoundRange, signDomain);
5258 else
5259 plottableRange = p.at(i)->getValueRange(currentFoundRange, signDomain);
5260 if (currentFoundRange)
5261 {
5262 if (!haveRange)
5263 newRange = plottableRange;
5264 else
5265 newRange.expand(plottableRange);
5266 haveRange = true;
5267 }
5268 }
5269 if (haveRange)
5270 {
5271 if (!QCPRange::validRange(newRange)) // likely due to range being zero (plottable has only constant data in this axis dimension), shift current range to at least center the plottable
5272 {
5273 double center = (newRange.lower+newRange.upper)*0.5; // upper and lower should be equal anyway, but just to make sure, incase validRange returned false for other reason
5274 if (mScaleType == stLinear)
5275 {
5276 newRange.lower = center-mRange.size()/2.0;
5277 newRange.upper = center+mRange.size()/2.0;
5278 5278 } else // mScaleType == stLogarithmic
5279 5279 {
5280 newRange.lower = center/qSqrt(mRange.upper/mRange.lower);
5281 newRange.upper = center*qSqrt(mRange.upper/mRange.lower);
5282 }
5283 }
5284 setRange(newRange);
5280 newRange.lower = center/qSqrt(mRange.upper/mRange.lower);
5281 newRange.upper = center*qSqrt(mRange.upper/mRange.lower);
5282 }
5283 }
5284 setRange(newRange);
5285 5285 }
5286 5286 }
5287 5287
@@ -5290,35 +5290,35 void QCPAxis::rescale(bool onlyVisiblePl
5290 5290 */
5291 5291 double QCPAxis::pixelToCoord(double value) const
5292 5292 {
5293 if (orientation() == Qt::Horizontal)
5294 {
5295 if (mScaleType == stLinear)
5296 {
5297 if (!mRangeReversed)
5298 return (value-mAxisRect->left())/(double)mAxisRect->width()*mRange.size()+mRange.lower;
5299 else
5300 return -(value-mAxisRect->left())/(double)mAxisRect->width()*mRange.size()+mRange.upper;
5293 if (orientation() == Qt::Horizontal)
5294 {
5295 if (mScaleType == stLinear)
5296 {
5297 if (!mRangeReversed)
5298 return (value-mAxisRect->left())/(double)mAxisRect->width()*mRange.size()+mRange.lower;
5299 else
5300 return -(value-mAxisRect->left())/(double)mAxisRect->width()*mRange.size()+mRange.upper;
5301 5301 } else // mScaleType == stLogarithmic
5302 5302 {
5303 if (!mRangeReversed)
5304 return qPow(mRange.upper/mRange.lower, (value-mAxisRect->left())/(double)mAxisRect->width())*mRange.lower;
5305 else
5306 return qPow(mRange.upper/mRange.lower, (mAxisRect->left()-value)/(double)mAxisRect->width())*mRange.upper;
5303 if (!mRangeReversed)
5304 return qPow(mRange.upper/mRange.lower, (value-mAxisRect->left())/(double)mAxisRect->width())*mRange.lower;
5305 else
5306 return qPow(mRange.upper/mRange.lower, (mAxisRect->left()-value)/(double)mAxisRect->width())*mRange.upper;
5307 5307 }
5308 5308 } else // orientation() == Qt::Vertical
5309 5309 {
5310 if (mScaleType == stLinear)
5311 {
5312 if (!mRangeReversed)
5313 return (mAxisRect->bottom()-value)/(double)mAxisRect->height()*mRange.size()+mRange.lower;
5314 else
5315 return -(mAxisRect->bottom()-value)/(double)mAxisRect->height()*mRange.size()+mRange.upper;
5310 if (mScaleType == stLinear)
5311 {
5312 if (!mRangeReversed)
5313 return (mAxisRect->bottom()-value)/(double)mAxisRect->height()*mRange.size()+mRange.lower;
5314 else
5315 return -(mAxisRect->bottom()-value)/(double)mAxisRect->height()*mRange.size()+mRange.upper;
5316 5316 } else // mScaleType == stLogarithmic
5317 5317 {
5318 if (!mRangeReversed)
5319 return qPow(mRange.upper/mRange.lower, (mAxisRect->bottom()-value)/(double)mAxisRect->height())*mRange.lower;
5320 else
5321 return qPow(mRange.upper/mRange.lower, (value-mAxisRect->bottom())/(double)mAxisRect->height())*mRange.upper;
5318 if (!mRangeReversed)
5319 return qPow(mRange.upper/mRange.lower, (mAxisRect->bottom()-value)/(double)mAxisRect->height())*mRange.lower;
5320 else
5321 return qPow(mRange.upper/mRange.lower, (value-mAxisRect->bottom())/(double)mAxisRect->height())*mRange.upper;
5322 5322 }
5323 5323 }
5324 5324 }
@@ -5328,48 +5328,48 double QCPAxis::pixelToCoord(double valu
5328 5328 */
5329 5329 double QCPAxis::coordToPixel(double value) const
5330 5330 {
5331 if (orientation() == Qt::Horizontal)
5332 {
5333 if (mScaleType == stLinear)
5334 {
5335 if (!mRangeReversed)
5336 return (value-mRange.lower)/mRange.size()*mAxisRect->width()+mAxisRect->left();
5337 else
5338 return (mRange.upper-value)/mRange.size()*mAxisRect->width()+mAxisRect->left();
5331 if (orientation() == Qt::Horizontal)
5332 {
5333 if (mScaleType == stLinear)
5334 {
5335 if (!mRangeReversed)
5336 return (value-mRange.lower)/mRange.size()*mAxisRect->width()+mAxisRect->left();
5337 else
5338 return (mRange.upper-value)/mRange.size()*mAxisRect->width()+mAxisRect->left();
5339 5339 } else // mScaleType == stLogarithmic
5340 5340 {
5341 if (value >= 0 && mRange.upper < 0) // invalid value for logarithmic scale, just draw it outside visible range
5342 return !mRangeReversed ? mAxisRect->right()+200 : mAxisRect->left()-200;
5343 else if (value <= 0 && mRange.upper > 0) // invalid value for logarithmic scale, just draw it outside visible range
5344 return !mRangeReversed ? mAxisRect->left()-200 : mAxisRect->right()+200;
5345 else
5346 {
5347 if (!mRangeReversed)
5348 return baseLog(value/mRange.lower)/baseLog(mRange.upper/mRange.lower)*mAxisRect->width()+mAxisRect->left();
5349 else
5350 return baseLog(mRange.upper/value)/baseLog(mRange.upper/mRange.lower)*mAxisRect->width()+mAxisRect->left();
5341 if (value >= 0 && mRange.upper < 0) // invalid value for logarithmic scale, just draw it outside visible range
5342 return !mRangeReversed ? mAxisRect->right()+200 : mAxisRect->left()-200;
5343 else if (value <= 0 && mRange.upper > 0) // invalid value for logarithmic scale, just draw it outside visible range
5344 return !mRangeReversed ? mAxisRect->left()-200 : mAxisRect->right()+200;
5345 else
5346 {
5347 if (!mRangeReversed)
5348 return baseLog(value/mRange.lower)/baseLog(mRange.upper/mRange.lower)*mAxisRect->width()+mAxisRect->left();
5349 else
5350 return baseLog(mRange.upper/value)/baseLog(mRange.upper/mRange.lower)*mAxisRect->width()+mAxisRect->left();
5351 5351 }
5352 5352 }
5353 5353 } else // orientation() == Qt::Vertical
5354 5354 {
5355 if (mScaleType == stLinear)
5356 {
5357 if (!mRangeReversed)
5358 return mAxisRect->bottom()-(value-mRange.lower)/mRange.size()*mAxisRect->height();
5359 else
5360 return mAxisRect->bottom()-(mRange.upper-value)/mRange.size()*mAxisRect->height();
5355 if (mScaleType == stLinear)
5356 {
5357 if (!mRangeReversed)
5358 return mAxisRect->bottom()-(value-mRange.lower)/mRange.size()*mAxisRect->height();
5359 else
5360 return mAxisRect->bottom()-(mRange.upper-value)/mRange.size()*mAxisRect->height();
5361 5361 } else // mScaleType == stLogarithmic
5362 5362 {
5363 if (value >= 0 && mRange.upper < 0) // invalid value for logarithmic scale, just draw it outside visible range
5364 return !mRangeReversed ? mAxisRect->top()-200 : mAxisRect->bottom()+200;
5365 else if (value <= 0 && mRange.upper > 0) // invalid value for logarithmic scale, just draw it outside visible range
5366 return !mRangeReversed ? mAxisRect->bottom()+200 : mAxisRect->top()-200;
5367 else
5368 {
5369 if (!mRangeReversed)
5370 return mAxisRect->bottom()-baseLog(value/mRange.lower)/baseLog(mRange.upper/mRange.lower)*mAxisRect->height();
5371 else
5372 return mAxisRect->bottom()-baseLog(mRange.upper/value)/baseLog(mRange.upper/mRange.lower)*mAxisRect->height();
5363 if (value >= 0 && mRange.upper < 0) // invalid value for logarithmic scale, just draw it outside visible range
5364 return !mRangeReversed ? mAxisRect->top()-200 : mAxisRect->bottom()+200;
5365 else if (value <= 0 && mRange.upper > 0) // invalid value for logarithmic scale, just draw it outside visible range
5366 return !mRangeReversed ? mAxisRect->bottom()+200 : mAxisRect->top()-200;
5367 else
5368 {
5369 if (!mRangeReversed)
5370 return mAxisRect->bottom()-baseLog(value/mRange.lower)/baseLog(mRange.upper/mRange.lower)*mAxisRect->height();
5371 else
5372 return mAxisRect->bottom()-baseLog(mRange.upper/value)/baseLog(mRange.upper/mRange.lower)*mAxisRect->height();
5373 5373 }
5374 5374 }
5375 5375 }
@@ -5386,30 +5386,30 double QCPAxis::coordToPixel(double valu
5386 5386 */
5387 5387 QCPAxis::SelectablePart QCPAxis::getPartAt(const QPointF &pos) const
5388 5388 {
5389 if (!mVisible)
5390 return spNone;
5391
5392 if (mAxisPainter->axisSelectionBox().contains(pos.toPoint()))
5393 return spAxis;
5394 else if (mAxisPainter->tickLabelsSelectionBox().contains(pos.toPoint()))
5395 return spTickLabels;
5396 else if (mAxisPainter->labelSelectionBox().contains(pos.toPoint()))
5397 return spAxisLabel;
5398 else
5399 return spNone;
5389 if (!mVisible)
5390 return spNone;
5391
5392 if (mAxisPainter->axisSelectionBox().contains(pos.toPoint()))
5393 return spAxis;
5394 else if (mAxisPainter->tickLabelsSelectionBox().contains(pos.toPoint()))
5395 return spTickLabels;
5396 else if (mAxisPainter->labelSelectionBox().contains(pos.toPoint()))
5397 return spAxisLabel;
5398 else
5399 return spNone;
5400 5400 }
5401 5401
5402 5402 /* inherits documentation from base class */
5403 5403 double QCPAxis::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
5404 5404 {
5405 if (!mParentPlot) return -1;
5406 SelectablePart part = getPartAt(pos);
5407 if ((onlySelectable && !mSelectableParts.testFlag(part)) || part == spNone)
5408 return -1;
5409
5410 if (details)
5411 details->setValue(part);
5412 return mParentPlot->selectionTolerance()*0.99;
5405 if (!mParentPlot) return -1;
5406 SelectablePart part = getPartAt(pos);
5407 if ((onlySelectable && !mSelectableParts.testFlag(part)) || part == spNone)
5408 return -1;
5409
5410 if (details)
5411 details->setValue(part);
5412 return mParentPlot->selectionTolerance()*0.99;
5413 5413 }
5414 5414
5415 5415 /*!
@@ -5421,15 +5421,15 double QCPAxis::selectTest(const QPointF
5421 5421 */
5422 5422 QList<QCPAbstractPlottable*> QCPAxis::plottables() const
5423 5423 {
5424 QList<QCPAbstractPlottable*> result;
5425 if (!mParentPlot) return result;
5426
5427 for (int i=0; i<mParentPlot->mPlottables.size(); ++i)
5428 {
5429 if (mParentPlot->mPlottables.at(i)->keyAxis() == this ||mParentPlot->mPlottables.at(i)->valueAxis() == this)
5430 result.append(mParentPlot->mPlottables.at(i));
5431 }
5432 return result;
5424 QList<QCPAbstractPlottable*> result;
5425 if (!mParentPlot) return result;
5426
5427 for (int i=0; i<mParentPlot->mPlottables.size(); ++i)
5428 {
5429 if (mParentPlot->mPlottables.at(i)->keyAxis() == this ||mParentPlot->mPlottables.at(i)->valueAxis() == this)
5430 result.append(mParentPlot->mPlottables.at(i));
5431 }
5432 return result;
5433 5433 }
5434 5434
5435 5435 /*!
@@ -5439,15 +5439,15 QList<QCPAbstractPlottable*> QCPAxis::pl
5439 5439 */
5440 5440 QList<QCPGraph*> QCPAxis::graphs() const
5441 5441 {
5442 QList<QCPGraph*> result;
5443 if (!mParentPlot) return result;
5444
5445 for (int i=0; i<mParentPlot->mGraphs.size(); ++i)
5446 {
5447 if (mParentPlot->mGraphs.at(i)->keyAxis() == this || mParentPlot->mGraphs.at(i)->valueAxis() == this)
5448 result.append(mParentPlot->mGraphs.at(i));
5449 }
5450 return result;
5442 QList<QCPGraph*> result;
5443 if (!mParentPlot) return result;
5444
5445 for (int i=0; i<mParentPlot->mGraphs.size(); ++i)
5446 {
5447 if (mParentPlot->mGraphs.at(i)->keyAxis() == this || mParentPlot->mGraphs.at(i)->valueAxis() == this)
5448 result.append(mParentPlot->mGraphs.at(i));
5449 }
5450 return result;
5451 5451 }
5452 5452
5453 5453 /*!
@@ -5458,22 +5458,22 QList<QCPGraph*> QCPAxis::graphs() const
5458 5458 */
5459 5459 QList<QCPAbstractItem*> QCPAxis::items() const
5460 5460 {
5461 QList<QCPAbstractItem*> result;
5462 if (!mParentPlot) return result;
5463
5464 for (int itemId=0; itemId<mParentPlot->mItems.size(); ++itemId)
5465 {
5466 QList<QCPItemPosition*> positions = mParentPlot->mItems.at(itemId)->positions();
5467 for (int posId=0; posId<positions.size(); ++posId)
5468 {
5469 if (positions.at(posId)->keyAxis() == this || positions.at(posId)->valueAxis() == this)
5470 {
5471 result.append(mParentPlot->mItems.at(itemId));
5472 break;
5473 }
5474 }
5475 }
5476 return result;
5461 QList<QCPAbstractItem*> result;
5462 if (!mParentPlot) return result;
5463
5464 for (int itemId=0; itemId<mParentPlot->mItems.size(); ++itemId)
5465 {
5466 QList<QCPItemPosition*> positions = mParentPlot->mItems.at(itemId)->positions();
5467 for (int posId=0; posId<positions.size(); ++posId)
5468 {
5469 if (positions.at(posId)->keyAxis() == this || positions.at(posId)->valueAxis() == this)
5470 {
5471 result.append(mParentPlot->mItems.at(itemId));
5472 break;
5473 }
5474 }
5475 }
5476 return result;
5477 5477 }
5478 5478
5479 5479 /*!
@@ -5482,7 +5482,7 QList<QCPAbstractItem*> QCPAxis::items()
5482 5482 */
5483 5483 QCPAxis::AxisType QCPAxis::marginSideToAxisType(QCP::MarginSide side)
5484 5484 {
5485 switch (side)
5485 switch (side)
5486 5486 {
5487 5487 case QCP::msLeft: return atLeft;
5488 5488 case QCP::msRight: return atRight;
@@ -5490,8 +5490,8 QCPAxis::AxisType QCPAxis::marginSideToA
5490 5490 case QCP::msBottom: return atBottom;
5491 5491 default: break;
5492 5492 }
5493 qDebug() << Q_FUNC_INFO << "Invalid margin side passed:" << (int)side;
5494 return atLeft;
5493 qDebug() << Q_FUNC_INFO << "Invalid margin side passed:" << (int)side;
5494 return atLeft;
5495 5495 }
5496 5496
5497 5497 /*!
@@ -5499,7 +5499,7 QCPAxis::AxisType QCPAxis::marginSideToA
5499 5499 */
5500 5500 QCPAxis::AxisType QCPAxis::opposite(QCPAxis::AxisType type)
5501 5501 {
5502 switch (type)
5502 switch (type)
5503 5503 {
5504 5504 case atLeft: return atRight; break;
5505 5505 case atRight: return atLeft; break;
@@ -5518,85 +5518,85 QCPAxis::AxisType QCPAxis::opposite(QCPA
5518 5518 */
5519 5519 void QCPAxis::setupTickVectors()
5520 5520 {
5521 if (!mParentPlot) return;
5522 if ((!mTicks && !mTickLabels && !mGrid->visible()) || mRange.size() <= 0) return;
5523
5524 // fill tick vectors, either by auto generating or by notifying user to fill the vectors himself
5525 if (mAutoTicks)
5526 {
5527 generateAutoTicks();
5528 } else
5529 {
5530 emit ticksRequest();
5531 }
5532
5533 visibleTickBounds(mLowestVisibleTick, mHighestVisibleTick);
5534 if (mTickVector.isEmpty())
5535 {
5536 mSubTickVector.clear();
5537 return;
5538 }
5539
5540 // generate subticks between ticks:
5541 mSubTickVector.resize((mTickVector.size()-1)*mSubTickCount);
5542 if (mSubTickCount > 0)
5543 {
5544 double subTickStep = 0;
5545 double subTickPosition = 0;
5546 int subTickIndex = 0;
5547 bool done = false;
5548 int lowTick = mLowestVisibleTick > 0 ? mLowestVisibleTick-1 : mLowestVisibleTick;
5549 int highTick = mHighestVisibleTick < mTickVector.size()-1 ? mHighestVisibleTick+1 : mHighestVisibleTick;
5550 for (int i=lowTick+1; i<=highTick; ++i)
5551 {
5552 subTickStep = (mTickVector.at(i)-mTickVector.at(i-1))/(double)(mSubTickCount+1);
5553 for (int k=1; k<=mSubTickCount; ++k)
5554 {
5555 subTickPosition = mTickVector.at(i-1) + k*subTickStep;
5556 if (subTickPosition < mRange.lower)
5557 continue;
5558 if (subTickPosition > mRange.upper)
5521 if (!mParentPlot) return;
5522 if ((!mTicks && !mTickLabels && !mGrid->visible()) || mRange.size() <= 0) return;
5523
5524 // fill tick vectors, either by auto generating or by notifying user to fill the vectors himself
5525 if (mAutoTicks)
5526 {
5527 generateAutoTicks();
5528 } else
5529 {
5530 emit ticksRequest();
5531 }
5532
5533 visibleTickBounds(mLowestVisibleTick, mHighestVisibleTick);
5534 if (mTickVector.isEmpty())
5535 {
5536 mSubTickVector.clear();
5537 return;
5538 }
5539
5540 // generate subticks between ticks:
5541 mSubTickVector.resize((mTickVector.size()-1)*mSubTickCount);
5542 if (mSubTickCount > 0)
5543 {
5544 double subTickStep = 0;
5545 double subTickPosition = 0;
5546 int subTickIndex = 0;
5547 bool done = false;
5548 int lowTick = mLowestVisibleTick > 0 ? mLowestVisibleTick-1 : mLowestVisibleTick;
5549 int highTick = mHighestVisibleTick < mTickVector.size()-1 ? mHighestVisibleTick+1 : mHighestVisibleTick;
5550 for (int i=lowTick+1; i<=highTick; ++i)
5551 {
5552 subTickStep = (mTickVector.at(i)-mTickVector.at(i-1))/(double)(mSubTickCount+1);
5553 for (int k=1; k<=mSubTickCount; ++k)
5554 {
5555 subTickPosition = mTickVector.at(i-1) + k*subTickStep;
5556 if (subTickPosition < mRange.lower)
5557 continue;
5558 if (subTickPosition > mRange.upper)
5559 5559 {
5560 done = true;
5561 break;
5560 done = true;
5561 break;
5562 5562 }
5563 mSubTickVector[subTickIndex] = subTickPosition;
5564 subTickIndex++;
5565 }
5566 if (done) break;
5567 }
5568 mSubTickVector.resize(subTickIndex);
5569 }
5570
5571 // generate tick labels according to tick positions:
5572 if (mAutoTickLabels)
5573 {
5574 int vecsize = mTickVector.size();
5575 mTickVectorLabels.resize(vecsize);
5576 if (mTickLabelType == ltNumber)
5577 {
5578 for (int i=mLowestVisibleTick; i<=mHighestVisibleTick; ++i)
5579 mTickVectorLabels[i] = mParentPlot->locale().toString(mTickVector.at(i), mNumberFormatChar.toLatin1(), mNumberPrecision);
5563 mSubTickVector[subTickIndex] = subTickPosition;
5564 subTickIndex++;
5565 }
5566 if (done) break;
5567 }
5568 mSubTickVector.resize(subTickIndex);
5569 }
5570
5571 // generate tick labels according to tick positions:
5572 if (mAutoTickLabels)
5573 {
5574 int vecsize = mTickVector.size();
5575 mTickVectorLabels.resize(vecsize);
5576 if (mTickLabelType == ltNumber)
5577 {
5578 for (int i=mLowestVisibleTick; i<=mHighestVisibleTick; ++i)
5579 mTickVectorLabels[i] = mParentPlot->locale().toString(mTickVector.at(i), mNumberFormatChar.toLatin1(), mNumberPrecision);
5580 5580 } else if (mTickLabelType == ltDateTime)
5581 5581 {
5582 for (int i=mLowestVisibleTick; i<=mHighestVisibleTick; ++i)
5582 for (int i=mLowestVisibleTick; i<=mHighestVisibleTick; ++i)
5583 5583 {
5584 5584 #if QT_VERSION < QT_VERSION_CHECK(4, 7, 0) // use fromMSecsSinceEpoch function if available, to gain sub-second accuracy on tick labels (e.g. for format "hh:mm:ss:zzz")
5585 mTickVectorLabels[i] = mParentPlot->locale().toString(QDateTime::fromTime_t(mTickVector.at(i)).toTimeSpec(mDateTimeSpec), mDateTimeFormat);
5585 mTickVectorLabels[i] = mParentPlot->locale().toString(QDateTime::fromTime_t(mTickVector.at(i)).toTimeSpec(mDateTimeSpec), mDateTimeFormat);
5586 5586 #else
5587 mTickVectorLabels[i] = mParentPlot->locale().toString(QDateTime::fromMSecsSinceEpoch(mTickVector.at(i)*1000).toTimeSpec(mDateTimeSpec), mDateTimeFormat);
5587 mTickVectorLabels[i] = mParentPlot->locale().toString(QDateTime::fromMSecsSinceEpoch(mTickVector.at(i)*1000).toTimeSpec(mDateTimeSpec), mDateTimeFormat);
5588 5588 #endif
5589 5589 }
5590 5590 }
5591 5591 } else // mAutoTickLabels == false
5592 5592 {
5593 if (mAutoTicks) // ticks generated automatically, but not ticklabels, so emit ticksRequest here for labels
5594 {
5595 emit ticksRequest();
5596 }
5597 // make sure provided tick label vector has correct (minimal) length:
5598 if (mTickVectorLabels.size() < mTickVector.size())
5599 mTickVectorLabels.resize(mTickVector.size());
5593 if (mAutoTicks) // ticks generated automatically, but not ticklabels, so emit ticksRequest here for labels
5594 {
5595 emit ticksRequest();
5596 }
5597 // make sure provided tick label vector has correct (minimal) length:
5598 if (mTickVectorLabels.size() < mTickVector.size())
5599 mTickVectorLabels.resize(mTickVector.size());
5600 5600 }
5601 5601 }
5602 5602
@@ -5611,63 +5611,63 void QCPAxis::setupTickVectors()
5611 5611 */
5612 5612 void QCPAxis::generateAutoTicks()
5613 5613 {
5614 if (mScaleType == stLinear)
5615 {
5616 if (mAutoTickStep)
5617 {
5618 // Generate tick positions according to linear scaling:
5619 mTickStep = mRange.size()/(double)(mAutoTickCount+1e-10); // mAutoTickCount ticks on average, the small addition is to prevent jitter on exact integers
5620 double magnitudeFactor = qPow(10.0, qFloor(qLn(mTickStep)/qLn(10.0))); // get magnitude factor e.g. 0.01, 1, 10, 1000 etc.
5621 double tickStepMantissa = mTickStep/magnitudeFactor;
5622 if (tickStepMantissa < 5)
5623 {
5624 // round digit after decimal point to 0.5
5625 mTickStep = (int)(tickStepMantissa*2)/2.0*magnitudeFactor;
5614 if (mScaleType == stLinear)
5615 {
5616 if (mAutoTickStep)
5617 {
5618 // Generate tick positions according to linear scaling:
5619 mTickStep = mRange.size()/(double)(mAutoTickCount+1e-10); // mAutoTickCount ticks on average, the small addition is to prevent jitter on exact integers
5620 double magnitudeFactor = qPow(10.0, qFloor(qLn(mTickStep)/qLn(10.0))); // get magnitude factor e.g. 0.01, 1, 10, 1000 etc.
5621 double tickStepMantissa = mTickStep/magnitudeFactor;
5622 if (tickStepMantissa < 5)
5623 {
5624 // round digit after decimal point to 0.5
5625 mTickStep = (int)(tickStepMantissa*2)/2.0*magnitudeFactor;
5626 5626 } else
5627 5627 {
5628 // round to first digit in multiples of 2
5629 mTickStep = (int)(tickStepMantissa/2.0)*2.0*magnitudeFactor;
5630 }
5631 }
5632 if (mAutoSubTicks)
5633 mSubTickCount = calculateAutoSubTickCount(mTickStep);
5634 // Generate tick positions according to mTickStep:
5635 qint64 firstStep = floor(mRange.lower/mTickStep); // do not use qFloor here, or we'll lose 64 bit precision
5636 qint64 lastStep = ceil(mRange.upper/mTickStep); // do not use qCeil here, or we'll lose 64 bit precision
5637 int tickcount = lastStep-firstStep+1;
5638 if (tickcount < 0) tickcount = 0;
5639 mTickVector.resize(tickcount);
5640 for (int i=0; i<tickcount; ++i)
5641 mTickVector[i] = (firstStep+i)*mTickStep;
5628 // round to first digit in multiples of 2
5629 mTickStep = (int)(tickStepMantissa/2.0)*2.0*magnitudeFactor;
5630 }
5631 }
5632 if (mAutoSubTicks)
5633 mSubTickCount = calculateAutoSubTickCount(mTickStep);
5634 // Generate tick positions according to mTickStep:
5635 qint64 firstStep = floor(mRange.lower/mTickStep); // do not use qFloor here, or we'll lose 64 bit precision
5636 qint64 lastStep = ceil(mRange.upper/mTickStep); // do not use qCeil here, or we'll lose 64 bit precision
5637 int tickcount = lastStep-firstStep+1;
5638 if (tickcount < 0) tickcount = 0;
5639 mTickVector.resize(tickcount);
5640 for (int i=0; i<tickcount; ++i)
5641 mTickVector[i] = (firstStep+i)*mTickStep;
5642 5642 } else // mScaleType == stLogarithmic
5643 5643 {
5644 // Generate tick positions according to logbase scaling:
5645 if (mRange.lower > 0 && mRange.upper > 0) // positive range
5646 {
5647 double lowerMag = basePow(qFloor(baseLog(mRange.lower)));
5648 double currentMag = lowerMag;
5649 mTickVector.clear();
5650 mTickVector.append(currentMag);
5651 while (currentMag < mRange.upper && currentMag > 0) // currentMag might be zero for ranges ~1e-300, just cancel in that case
5652 {
5653 currentMag *= mScaleLogBase;
5654 mTickVector.append(currentMag);
5644 // Generate tick positions according to logbase scaling:
5645 if (mRange.lower > 0 && mRange.upper > 0) // positive range
5646 {
5647 double lowerMag = basePow(qFloor(baseLog(mRange.lower)));
5648 double currentMag = lowerMag;
5649 mTickVector.clear();
5650 mTickVector.append(currentMag);
5651 while (currentMag < mRange.upper && currentMag > 0) // currentMag might be zero for ranges ~1e-300, just cancel in that case
5652 {
5653 currentMag *= mScaleLogBase;
5654 mTickVector.append(currentMag);
5655 5655 }
5656 5656 } else if (mRange.lower < 0 && mRange.upper < 0) // negative range
5657 5657 {
5658 double lowerMag = -basePow(qCeil(baseLog(-mRange.lower)));
5659 double currentMag = lowerMag;
5660 mTickVector.clear();
5661 mTickVector.append(currentMag);
5662 while (currentMag < mRange.upper && currentMag < 0) // currentMag might be zero for ranges ~1e-300, just cancel in that case
5663 {
5664 currentMag /= mScaleLogBase;
5665 mTickVector.append(currentMag);
5658 double lowerMag = -basePow(qCeil(baseLog(-mRange.lower)));
5659 double currentMag = lowerMag;
5660 mTickVector.clear();
5661 mTickVector.append(currentMag);
5662 while (currentMag < mRange.upper && currentMag < 0) // currentMag might be zero for ranges ~1e-300, just cancel in that case
5663 {
5664 currentMag /= mScaleLogBase;
5665 mTickVector.append(currentMag);
5666 5666 }
5667 5667 } else // invalid range for logarithmic scale, because lower and upper have different sign
5668 5668 {
5669 mTickVector.clear();
5670 qDebug() << Q_FUNC_INFO << "Invalid range for logarithmic plot: " << mRange.lower << "-" << mRange.upper;
5669 mTickVector.clear();
5670 qDebug() << Q_FUNC_INFO << "Invalid range for logarithmic plot: " << mRange.lower << "-" << mRange.upper;
5671 5671 }
5672 5672 }
5673 5673 }
@@ -5687,25 +5687,25 void QCPAxis::generateAutoTicks()
5687 5687 */
5688 5688 int QCPAxis::calculateAutoSubTickCount(double tickStep) const
5689 5689 {
5690 int result = mSubTickCount; // default to current setting, if no proper value can be found
5691
5692 // get mantissa of tickstep:
5693 double magnitudeFactor = qPow(10.0, qFloor(qLn(tickStep)/qLn(10.0))); // get magnitude factor e.g. 0.01, 1, 10, 1000 etc.
5694 double tickStepMantissa = tickStep/magnitudeFactor;
5695
5696 // separate integer and fractional part of mantissa:
5697 double epsilon = 0.01;
5698 double intPartf;
5699 int intPart;
5700 double fracPart = modf(tickStepMantissa, &intPartf);
5701 intPart = intPartf;
5702
5703 // handle cases with (almost) integer mantissa:
5704 if (fracPart < epsilon || 1.0-fracPart < epsilon)
5705 {
5706 if (1.0-fracPart < epsilon)
5707 ++intPart;
5708 switch (intPart)
5690 int result = mSubTickCount; // default to current setting, if no proper value can be found
5691
5692 // get mantissa of tickstep:
5693 double magnitudeFactor = qPow(10.0, qFloor(qLn(tickStep)/qLn(10.0))); // get magnitude factor e.g. 0.01, 1, 10, 1000 etc.
5694 double tickStepMantissa = tickStep/magnitudeFactor;
5695
5696 // separate integer and fractional part of mantissa:
5697 double epsilon = 0.01;
5698 double intPartf;
5699 int intPart;
5700 double fracPart = modf(tickStepMantissa, &intPartf);
5701 intPart = intPartf;
5702
5703 // handle cases with (almost) integer mantissa:
5704 if (fracPart < epsilon || 1.0-fracPart < epsilon)
5705 {
5706 if (1.0-fracPart < epsilon)
5707 ++intPart;
5708 switch (intPart)
5709 5709 {
5710 5710 case 1: result = 4; break; // 1.0 -> 0.2 substep
5711 5711 case 2: result = 3; break; // 2.0 -> 0.5 substep
@@ -5719,10 +5719,10 int QCPAxis::calculateAutoSubTickCount(d
5719 5719 }
5720 5720 } else
5721 5721 {
5722 // handle cases with significantly fractional mantissa:
5723 if (qAbs(fracPart-0.5) < epsilon) // *.5 mantissa
5724 {
5725 switch (intPart)
5722 // handle cases with significantly fractional mantissa:
5723 if (qAbs(fracPart-0.5) < epsilon) // *.5 mantissa
5724 {
5725 switch (intPart)
5726 5726 {
5727 5727 case 1: result = 2; break; // 1.5 -> 0.5 substep
5728 5728 case 2: result = 4; break; // 2.5 -> 0.5 substep
@@ -5735,33 +5735,33 int QCPAxis::calculateAutoSubTickCount(d
5735 5735 case 9: result = 4; break; // 9.5 -> 1.9 substep
5736 5736 }
5737 5737 }
5738 // if mantissa fraction isnt 0.0 or 0.5, don't bother finding good sub tick marks, leave default
5739 }
5740
5741 return result;
5738 // if mantissa fraction isnt 0.0 or 0.5, don't bother finding good sub tick marks, leave default
5739 }
5740
5741 return result;
5742 5742 }
5743 5743
5744 5744 /* inherits documentation from base class */
5745 5745 void QCPAxis::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged)
5746 5746 {
5747 Q_UNUSED(event)
5748 SelectablePart part = details.value<SelectablePart>();
5749 if (mSelectableParts.testFlag(part))
5750 {
5751 SelectableParts selBefore = mSelectedParts;
5752 setSelectedParts(additive ? mSelectedParts^part : part);
5753 if (selectionStateChanged)
5754 *selectionStateChanged = mSelectedParts != selBefore;
5747 Q_UNUSED(event)
5748 SelectablePart part = details.value<SelectablePart>();
5749 if (mSelectableParts.testFlag(part))
5750 {
5751 SelectableParts selBefore = mSelectedParts;
5752 setSelectedParts(additive ? mSelectedParts^part : part);
5753 if (selectionStateChanged)
5754 *selectionStateChanged = mSelectedParts != selBefore;
5755 5755 }
5756 5756 }
5757 5757
5758 5758 /* inherits documentation from base class */
5759 5759 void QCPAxis::deselectEvent(bool *selectionStateChanged)
5760 5760 {
5761 SelectableParts selBefore = mSelectedParts;
5762 setSelectedParts(mSelectedParts & ~mSelectableParts);
5763 if (selectionStateChanged)
5764 *selectionStateChanged = mSelectedParts != selBefore;
5761 SelectableParts selBefore = mSelectedParts;
5762 setSelectedParts(mSelectedParts & ~mSelectableParts);
5763 if (selectionStateChanged)
5764 *selectionStateChanged = mSelectedParts != selBefore;
5765 5765 }
5766 5766
5767 5767 /*! \internal
@@ -5779,7 +5779,7 void QCPAxis::deselectEvent(bool *select
5779 5779 */
5780 5780 void QCPAxis::applyDefaultAntialiasingHint(QCPPainter *painter) const
5781 5781 {
5782 applyAntialiasingHint(painter, mAntialiased, QCP::aeAxes);
5782 applyAntialiasingHint(painter, mAntialiased, QCP::aeAxes);
5783 5783 }
5784 5784
5785 5785 /*! \internal
@@ -5789,51 +5789,51 void QCPAxis::applyDefaultAntialiasingHi
5789 5789 */
5790 5790 void QCPAxis::draw(QCPPainter *painter)
5791 5791 {
5792 const int lowTick = mLowestVisibleTick;
5793 const int highTick = mHighestVisibleTick;
5794 QVector<double> subTickPositions; // the final coordToPixel transformed vector passed to QCPAxisPainter
5795 QVector<double> tickPositions; // the final coordToPixel transformed vector passed to QCPAxisPainter
5796 QVector<QString> tickLabels; // the final vector passed to QCPAxisPainter
5797 tickPositions.reserve(highTick-lowTick+1);
5798 tickLabels.reserve(highTick-lowTick+1);
5799 subTickPositions.reserve(mSubTickVector.size());
5800
5801 if (mTicks)
5802 {
5803 for (int i=lowTick; i<=highTick; ++i)
5804 {
5805 tickPositions.append(coordToPixel(mTickVector.at(i)));
5806 if (mTickLabels)
5807 tickLabels.append(mTickVectorLabels.at(i));
5808 }
5809
5810 if (mSubTickCount > 0)
5811 {
5812 const int subTickCount = mSubTickVector.size();
5813 for (int i=0; i<subTickCount; ++i) // no need to check bounds because subticks are always only created inside current mRange
5814 subTickPositions.append(coordToPixel(mSubTickVector.at(i)));
5815 }
5816 }
5817 // transfer all properties of this axis to QCPAxisPainterPrivate which it needs to draw the axis.
5818 // Note that some axis painter properties are already set by direct feed-through with QCPAxis setters
5819 mAxisPainter->type = mAxisType;
5820 mAxisPainter->basePen = getBasePen();
5821 mAxisPainter->labelFont = getLabelFont();
5822 mAxisPainter->labelColor = getLabelColor();
5823 mAxisPainter->label = mLabel;
5824 mAxisPainter->substituteExponent = mAutoTickLabels && mNumberBeautifulPowers && mTickLabelType == ltNumber;
5825 mAxisPainter->tickPen = getTickPen();
5826 mAxisPainter->subTickPen = getSubTickPen();
5827 mAxisPainter->tickLabelFont = getTickLabelFont();
5828 mAxisPainter->tickLabelColor = getTickLabelColor();
5829 mAxisPainter->axisRect = mAxisRect->rect();
5830 mAxisPainter->viewportRect = mParentPlot->viewport();
5831 mAxisPainter->abbreviateDecimalPowers = mScaleType == stLogarithmic;
5832 mAxisPainter->reversedEndings = mRangeReversed;
5833 mAxisPainter->tickPositions = tickPositions;
5834 mAxisPainter->tickLabels = tickLabels;
5835 mAxisPainter->subTickPositions = subTickPositions;
5836 mAxisPainter->draw(painter);
5792 const int lowTick = mLowestVisibleTick;
5793 const int highTick = mHighestVisibleTick;
5794 QVector<double> subTickPositions; // the final coordToPixel transformed vector passed to QCPAxisPainter
5795 QVector<double> tickPositions; // the final coordToPixel transformed vector passed to QCPAxisPainter
5796 QVector<QString> tickLabels; // the final vector passed to QCPAxisPainter
5797 tickPositions.reserve(highTick-lowTick+1);
5798 tickLabels.reserve(highTick-lowTick+1);
5799 subTickPositions.reserve(mSubTickVector.size());
5800
5801 if (mTicks)
5802 {
5803 for (int i=lowTick; i<=highTick; ++i)
5804 {
5805 tickPositions.append(coordToPixel(mTickVector.at(i)));
5806 if (mTickLabels)
5807 tickLabels.append(mTickVectorLabels.at(i));
5808 }
5809
5810 if (mSubTickCount > 0)
5811 {
5812 const int subTickCount = mSubTickVector.size();
5813 for (int i=0; i<subTickCount; ++i) // no need to check bounds because subticks are always only created inside current mRange
5814 subTickPositions.append(coordToPixel(mSubTickVector.at(i)));
5815 }
5816 }
5817 // transfer all properties of this axis to QCPAxisPainterPrivate which it needs to draw the axis.
5818 // Note that some axis painter properties are already set by direct feed-through with QCPAxis setters
5819 mAxisPainter->type = mAxisType;
5820 mAxisPainter->basePen = getBasePen();
5821 mAxisPainter->labelFont = getLabelFont();
5822 mAxisPainter->labelColor = getLabelColor();
5823 mAxisPainter->label = mLabel;
5824 mAxisPainter->substituteExponent = mAutoTickLabels && mNumberBeautifulPowers && mTickLabelType == ltNumber;
5825 mAxisPainter->tickPen = getTickPen();
5826 mAxisPainter->subTickPen = getSubTickPen();
5827 mAxisPainter->tickLabelFont = getTickLabelFont();
5828 mAxisPainter->tickLabelColor = getTickLabelColor();
5829 mAxisPainter->axisRect = mAxisRect->rect();
5830 mAxisPainter->viewportRect = mParentPlot->viewport();
5831 mAxisPainter->abbreviateDecimalPowers = mScaleType == stLogarithmic;
5832 mAxisPainter->reversedEndings = mRangeReversed;
5833 mAxisPainter->tickPositions = tickPositions;
5834 mAxisPainter->tickLabels = tickLabels;
5835 mAxisPainter->subTickPositions = subTickPositions;
5836 mAxisPainter->draw(painter);
5837 5837 }
5838 5838
5839 5839 /*! \internal
@@ -5854,34 +5854,34 void QCPAxis::draw(QCPPainter *painter)
5854 5854 */
5855 5855 void QCPAxis::visibleTickBounds(int &lowIndex, int &highIndex) const
5856 5856 {
5857 bool lowFound = false;
5858 bool highFound = false;
5859 lowIndex = 0;
5860 highIndex = -1;
5861
5862 for (int i=0; i < mTickVector.size(); ++i)
5863 {
5864 if (mTickVector.at(i) >= mRange.lower)
5865 {
5866 lowFound = true;
5867 lowIndex = i;
5868 break;
5869 }
5870 }
5871 for (int i=mTickVector.size()-1; i >= 0; --i)
5872 {
5873 if (mTickVector.at(i) <= mRange.upper)
5874 {
5875 highFound = true;
5876 highIndex = i;
5877 break;
5878 }
5879 }
5880
5881 if (!lowFound && highFound)
5882 lowIndex = highIndex+1;
5883 else if (lowFound && !highFound)
5884 highIndex = lowIndex-1;
5857 bool lowFound = false;
5858 bool highFound = false;
5859 lowIndex = 0;
5860 highIndex = -1;
5861
5862 for (int i=0; i < mTickVector.size(); ++i)
5863 {
5864 if (mTickVector.at(i) >= mRange.lower)
5865 {
5866 lowFound = true;
5867 lowIndex = i;
5868 break;
5869 }
5870 }
5871 for (int i=mTickVector.size()-1; i >= 0; --i)
5872 {
5873 if (mTickVector.at(i) <= mRange.upper)
5874 {
5875 highFound = true;
5876 highIndex = i;
5877 break;
5878 }
5879 }
5880
5881 if (!lowFound && highFound)
5882 lowIndex = highIndex+1;
5883 else if (lowFound && !highFound)
5884 highIndex = lowIndex-1;
5885 5885 }
5886 5886
5887 5887 /*! \internal
@@ -5894,7 +5894,7 void QCPAxis::visibleTickBounds(int &low
5894 5894 */
5895 5895 double QCPAxis::baseLog(double value) const
5896 5896 {
5897 return qLn(value)*mScaleLogBaseLogInv;
5897 return qLn(value)*mScaleLogBaseLogInv;
5898 5898 }
5899 5899
5900 5900 /*! \internal
@@ -5906,7 +5906,7 double QCPAxis::baseLog(double value) co
5906 5906 */
5907 5907 double QCPAxis::basePow(double value) const
5908 5908 {
5909 return qPow(mScaleLogBase, value);
5909 return qPow(mScaleLogBase, value);
5910 5910 }
5911 5911
5912 5912 /*! \internal
@@ -5916,7 +5916,7 double QCPAxis::basePow(double value) co
5916 5916 */
5917 5917 QPen QCPAxis::getBasePen() const
5918 5918 {
5919 return mSelectedParts.testFlag(spAxis) ? mSelectedBasePen : mBasePen;
5919 return mSelectedParts.testFlag(spAxis) ? mSelectedBasePen : mBasePen;
5920 5920 }
5921 5921
5922 5922 /*! \internal
@@ -5926,7 +5926,7 QPen QCPAxis::getBasePen() const
5926 5926 */
5927 5927 QPen QCPAxis::getTickPen() const
5928 5928 {
5929 return mSelectedParts.testFlag(spAxis) ? mSelectedTickPen : mTickPen;
5929 return mSelectedParts.testFlag(spAxis) ? mSelectedTickPen : mTickPen;
5930 5930 }
5931 5931
5932 5932 /*! \internal
@@ -5936,7 +5936,7 QPen QCPAxis::getTickPen() const
5936 5936 */
5937 5937 QPen QCPAxis::getSubTickPen() const
5938 5938 {
5939 return mSelectedParts.testFlag(spAxis) ? mSelectedSubTickPen : mSubTickPen;
5939 return mSelectedParts.testFlag(spAxis) ? mSelectedSubTickPen : mSubTickPen;
5940 5940 }
5941 5941
5942 5942 /*! \internal
@@ -5946,7 +5946,7 QPen QCPAxis::getSubTickPen() const
5946 5946 */
5947 5947 QFont QCPAxis::getTickLabelFont() const
5948 5948 {
5949 return mSelectedParts.testFlag(spTickLabels) ? mSelectedTickLabelFont : mTickLabelFont;
5949 return mSelectedParts.testFlag(spTickLabels) ? mSelectedTickLabelFont : mTickLabelFont;
5950 5950 }
5951 5951
5952 5952 /*! \internal
@@ -5956,7 +5956,7 QFont QCPAxis::getTickLabelFont() const
5956 5956 */
5957 5957 QFont QCPAxis::getLabelFont() const
5958 5958 {
5959 return mSelectedParts.testFlag(spAxisLabel) ? mSelectedLabelFont : mLabelFont;
5959 return mSelectedParts.testFlag(spAxisLabel) ? mSelectedLabelFont : mLabelFont;
5960 5960 }
5961 5961
5962 5962 /*! \internal
@@ -5966,7 +5966,7 QFont QCPAxis::getLabelFont() const
5966 5966 */
5967 5967 QColor QCPAxis::getTickLabelColor() const
5968 5968 {
5969 return mSelectedParts.testFlag(spTickLabels) ? mSelectedTickLabelColor : mTickLabelColor;
5969 return mSelectedParts.testFlag(spTickLabels) ? mSelectedTickLabelColor : mTickLabelColor;
5970 5970 }
5971 5971
5972 5972 /*! \internal
@@ -5976,7 +5976,7 QColor QCPAxis::getTickLabelColor() cons
5976 5976 */
5977 5977 QColor QCPAxis::getLabelColor() const
5978 5978 {
5979 return mSelectedParts.testFlag(spAxisLabel) ? mSelectedLabelColor : mLabelColor;
5979 return mSelectedParts.testFlag(spAxisLabel) ? mSelectedLabelColor : mLabelColor;
5980 5980 }
5981 5981
5982 5982 /*! \internal
@@ -5995,52 +5995,52 QColor QCPAxis::getLabelColor() const
5995 5995 */
5996 5996 int QCPAxis::calculateMargin()
5997 5997 {
5998 if (!mVisible) // if not visible, directly return 0, don't cache 0 because we can't react to setVisible in QCPAxis
5999 return 0;
6000
6001 if (mCachedMarginValid)
6002 return mCachedMargin;
6003
6004 // run through similar steps as QCPAxis::draw, and caluclate margin needed to fit axis and its labels
6005 int margin = 0;
6006
6007 int lowTick, highTick;
6008 visibleTickBounds(lowTick, highTick);
6009 QVector<double> tickPositions; // the final coordToPixel transformed vector passed to QCPAxisPainter
6010 QVector<QString> tickLabels; // the final vector passed to QCPAxisPainter
6011 tickPositions.reserve(highTick-lowTick+1);
6012 tickLabels.reserve(highTick-lowTick+1);
6013 if (mTicks)
6014 {
6015 for (int i=lowTick; i<=highTick; ++i)
6016 {
6017 tickPositions.append(coordToPixel(mTickVector.at(i)));
6018 if (mTickLabels)
6019 tickLabels.append(mTickVectorLabels.at(i));
6020 }
6021 }
6022 // transfer all properties of this axis to QCPAxisPainterPrivate which it needs to calculate the size.
6023 // Note that some axis painter properties are already set by direct feed-through with QCPAxis setters
6024 mAxisPainter->type = mAxisType;
6025 mAxisPainter->labelFont = getLabelFont();
6026 mAxisPainter->label = mLabel;
6027 mAxisPainter->tickLabelFont = mTickLabelFont;
6028 mAxisPainter->axisRect = mAxisRect->rect();
6029 mAxisPainter->viewportRect = mParentPlot->viewport();
6030 mAxisPainter->tickPositions = tickPositions;
6031 mAxisPainter->tickLabels = tickLabels;
6032 margin += mAxisPainter->size();
6033 margin += mPadding;
6034
6035 mCachedMargin = margin;
6036 mCachedMarginValid = true;
6037 return margin;
5998 if (!mVisible) // if not visible, directly return 0, don't cache 0 because we can't react to setVisible in QCPAxis
5999 return 0;
6000
6001 if (mCachedMarginValid)
6002 return mCachedMargin;
6003
6004 // run through similar steps as QCPAxis::draw, and caluclate margin needed to fit axis and its labels
6005 int margin = 0;
6006
6007 int lowTick, highTick;
6008 visibleTickBounds(lowTick, highTick);
6009 QVector<double> tickPositions; // the final coordToPixel transformed vector passed to QCPAxisPainter
6010 QVector<QString> tickLabels; // the final vector passed to QCPAxisPainter
6011 tickPositions.reserve(highTick-lowTick+1);
6012 tickLabels.reserve(highTick-lowTick+1);
6013 if (mTicks)
6014 {
6015 for (int i=lowTick; i<=highTick; ++i)
6016 {
6017 tickPositions.append(coordToPixel(mTickVector.at(i)));
6018 if (mTickLabels)
6019 tickLabels.append(mTickVectorLabels.at(i));
6020 }
6021 }
6022 // transfer all properties of this axis to QCPAxisPainterPrivate which it needs to calculate the size.
6023 // Note that some axis painter properties are already set by direct feed-through with QCPAxis setters
6024 mAxisPainter->type = mAxisType;
6025 mAxisPainter->labelFont = getLabelFont();
6026 mAxisPainter->label = mLabel;
6027 mAxisPainter->tickLabelFont = mTickLabelFont;
6028 mAxisPainter->axisRect = mAxisRect->rect();
6029 mAxisPainter->viewportRect = mParentPlot->viewport();
6030 mAxisPainter->tickPositions = tickPositions;
6031 mAxisPainter->tickLabels = tickLabels;
6032 margin += mAxisPainter->size();
6033 margin += mPadding;
6034
6035 mCachedMargin = margin;
6036 mCachedMarginValid = true;
6037 return margin;
6038 6038 }
6039 6039
6040 6040 /* inherits documentation from base class */
6041 6041 QCP::Interaction QCPAxis::selectionCategory() const
6042 6042 {
6043 return QCP::iSelectAxes;
6043 return QCP::iSelectAxes;
6044 6044 }
6045 6045
6046 6046
@@ -6065,27 +6065,27 QCP::Interaction QCPAxis::selectionCateg
6065 6065 redraw, to utilize the caching mechanisms.
6066 6066 */
6067 6067 QCPAxisPainterPrivate::QCPAxisPainterPrivate(QCustomPlot *parentPlot) :
6068 type(QCPAxis::atLeft),
6069 basePen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)),
6070 lowerEnding(QCPLineEnding::esNone),
6071 upperEnding(QCPLineEnding::esNone),
6072 labelPadding(0),
6073 tickLabelPadding(0),
6074 tickLabelRotation(0),
6075 tickLabelSide(QCPAxis::lsOutside),
6076 substituteExponent(true),
6077 numberMultiplyCross(false),
6078 tickLengthIn(5),
6079 tickLengthOut(0),
6080 subTickLengthIn(2),
6081 subTickLengthOut(0),
6082 tickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)),
6083 subTickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)),
6084 offset(0),
6085 abbreviateDecimalPowers(false),
6086 reversedEndings(false),
6087 mParentPlot(parentPlot),
6088 mLabelCache(16) // cache at most 16 (tick) labels
6068 type(QCPAxis::atLeft),
6069 basePen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)),
6070 lowerEnding(QCPLineEnding::esNone),
6071 upperEnding(QCPLineEnding::esNone),
6072 labelPadding(0),
6073 tickLabelPadding(0),
6074 tickLabelRotation(0),
6075 tickLabelSide(QCPAxis::lsOutside),
6076 substituteExponent(true),
6077 numberMultiplyCross(false),
6078 tickLengthIn(5),
6079 tickLengthOut(0),
6080 subTickLengthIn(2),
6081 subTickLengthOut(0),
6082 tickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)),
6083 subTickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)),
6084 offset(0),
6085 abbreviateDecimalPowers(false),
6086 reversedEndings(false),
6087 mParentPlot(parentPlot),
6088 mLabelCache(16) // cache at most 16 (tick) labels
6089 6089 {
6090 6090 }
6091 6091
@@ -6102,15 +6102,15 QCPAxisPainterPrivate::~QCPAxisPainterPr
6102 6102 */
6103 6103 void QCPAxisPainterPrivate::draw(QCPPainter *painter)
6104 6104 {
6105 QByteArray newHash = generateLabelParameterHash();
6106 if (newHash != mLabelParameterHash)
6107 {
6108 mLabelCache.clear();
6109 mLabelParameterHash = newHash;
6110 }
6111
6112 QPoint origin;
6113 switch (type)
6105 QByteArray newHash = generateLabelParameterHash();
6106 if (newHash != mLabelParameterHash)
6107 {
6108 mLabelCache.clear();
6109 mLabelParameterHash = newHash;
6110 }
6111
6112 QPoint origin;
6113 switch (type)
6114 6114 {
6115 6115 case QCPAxis::atLeft: origin = axisRect.bottomLeft() +QPoint(-offset, 0); break;
6116 6116 case QCPAxis::atRight: origin = axisRect.bottomRight()+QPoint(+offset, 0); break;
@@ -6118,175 +6118,175 void QCPAxisPainterPrivate::draw(QCPPain
6118 6118 case QCPAxis::atBottom: origin = axisRect.bottomLeft() +QPoint(0, +offset); break;
6119 6119 }
6120 6120
6121 double xCor = 0, yCor = 0; // paint system correction, for pixel exact matches (affects baselines and ticks of top/right axes)
6122 switch (type)
6121 double xCor = 0, yCor = 0; // paint system correction, for pixel exact matches (affects baselines and ticks of top/right axes)
6122 switch (type)
6123 6123 {
6124 6124 case QCPAxis::atTop: yCor = -1; break;
6125 6125 case QCPAxis::atRight: xCor = 1; break;
6126 6126 default: break;
6127 6127 }
6128 6128
6129 int margin = 0;
6130 // draw baseline:
6131 QLineF baseLine;
6132 painter->setPen(basePen);
6133 if (QCPAxis::orientation(type) == Qt::Horizontal)
6134 baseLine.setPoints(origin+QPointF(xCor, yCor), origin+QPointF(axisRect.width()+xCor, yCor));
6135 else
6136 baseLine.setPoints(origin+QPointF(xCor, yCor), origin+QPointF(xCor, -axisRect.height()+yCor));
6137 if (reversedEndings)
6138 baseLine = QLineF(baseLine.p2(), baseLine.p1()); // won't make a difference for line itself, but for line endings later
6139 painter->drawLine(baseLine);
6140
6141 // draw ticks:
6142 if (!tickPositions.isEmpty())
6143 {
6144 painter->setPen(tickPen);
6145 int tickDir = (type == QCPAxis::atBottom || type == QCPAxis::atRight) ? -1 : 1; // direction of ticks ("inward" is right for left axis and left for right axis)
6146 if (QCPAxis::orientation(type) == Qt::Horizontal)
6147 {
6148 for (int i=0; i<tickPositions.size(); ++i)
6149 painter->drawLine(QLineF(tickPositions.at(i)+xCor, origin.y()-tickLengthOut*tickDir+yCor, tickPositions.at(i)+xCor, origin.y()+tickLengthIn*tickDir+yCor));
6129 int margin = 0;
6130 // draw baseline:
6131 QLineF baseLine;
6132 painter->setPen(basePen);
6133 if (QCPAxis::orientation(type) == Qt::Horizontal)
6134 baseLine.setPoints(origin+QPointF(xCor, yCor), origin+QPointF(axisRect.width()+xCor, yCor));
6135 else
6136 baseLine.setPoints(origin+QPointF(xCor, yCor), origin+QPointF(xCor, -axisRect.height()+yCor));
6137 if (reversedEndings)
6138 baseLine = QLineF(baseLine.p2(), baseLine.p1()); // won't make a difference for line itself, but for line endings later
6139 painter->drawLine(baseLine);
6140
6141 // draw ticks:
6142 if (!tickPositions.isEmpty())
6143 {
6144 painter->setPen(tickPen);
6145 int tickDir = (type == QCPAxis::atBottom || type == QCPAxis::atRight) ? -1 : 1; // direction of ticks ("inward" is right for left axis and left for right axis)
6146 if (QCPAxis::orientation(type) == Qt::Horizontal)
6147 {
6148 for (int i=0; i<tickPositions.size(); ++i)
6149 painter->drawLine(QLineF(tickPositions.at(i)+xCor, origin.y()-tickLengthOut*tickDir+yCor, tickPositions.at(i)+xCor, origin.y()+tickLengthIn*tickDir+yCor));
6150 6150 } else
6151 6151 {
6152 for (int i=0; i<tickPositions.size(); ++i)
6153 painter->drawLine(QLineF(origin.x()-tickLengthOut*tickDir+xCor, tickPositions.at(i)+yCor, origin.x()+tickLengthIn*tickDir+xCor, tickPositions.at(i)+yCor));
6154 }
6155 }
6156
6157 // draw subticks:
6158 if (!subTickPositions.isEmpty())
6159 {
6160 painter->setPen(subTickPen);
6161 // direction of ticks ("inward" is right for left axis and left for right axis)
6162 int tickDir = (type == QCPAxis::atBottom || type == QCPAxis::atRight) ? -1 : 1;
6163 if (QCPAxis::orientation(type) == Qt::Horizontal)
6164 {
6165 for (int i=0; i<subTickPositions.size(); ++i)
6166 painter->drawLine(QLineF(subTickPositions.at(i)+xCor, origin.y()-subTickLengthOut*tickDir+yCor, subTickPositions.at(i)+xCor, origin.y()+subTickLengthIn*tickDir+yCor));
6152 for (int i=0; i<tickPositions.size(); ++i)
6153 painter->drawLine(QLineF(origin.x()-tickLengthOut*tickDir+xCor, tickPositions.at(i)+yCor, origin.x()+tickLengthIn*tickDir+xCor, tickPositions.at(i)+yCor));
6154 }
6155 }
6156
6157 // draw subticks:
6158 if (!subTickPositions.isEmpty())
6159 {
6160 painter->setPen(subTickPen);
6161 // direction of ticks ("inward" is right for left axis and left for right axis)
6162 int tickDir = (type == QCPAxis::atBottom || type == QCPAxis::atRight) ? -1 : 1;
6163 if (QCPAxis::orientation(type) == Qt::Horizontal)
6164 {
6165 for (int i=0; i<subTickPositions.size(); ++i)
6166 painter->drawLine(QLineF(subTickPositions.at(i)+xCor, origin.y()-subTickLengthOut*tickDir+yCor, subTickPositions.at(i)+xCor, origin.y()+subTickLengthIn*tickDir+yCor));
6167 6167 } else
6168 6168 {
6169 for (int i=0; i<subTickPositions.size(); ++i)
6170 painter->drawLine(QLineF(origin.x()-subTickLengthOut*tickDir+xCor, subTickPositions.at(i)+yCor, origin.x()+subTickLengthIn*tickDir+xCor, subTickPositions.at(i)+yCor));
6171 }
6172 }
6173 margin += qMax(0, qMax(tickLengthOut, subTickLengthOut));
6174
6175 // draw axis base endings:
6176 bool antialiasingBackup = painter->antialiasing();
6177 painter->setAntialiasing(true); // always want endings to be antialiased, even if base and ticks themselves aren't
6178 painter->setBrush(QBrush(basePen.color()));
6179 QVector2D baseLineVector(baseLine.dx(), baseLine.dy());
6180 if (lowerEnding.style() != QCPLineEnding::esNone)
6181 lowerEnding.draw(painter, QVector2D(baseLine.p1())-baseLineVector.normalized()*lowerEnding.realLength()*(lowerEnding.inverted()?-1:1), -baseLineVector);
6182 if (upperEnding.style() != QCPLineEnding::esNone)
6183 upperEnding.draw(painter, QVector2D(baseLine.p2())+baseLineVector.normalized()*upperEnding.realLength()*(upperEnding.inverted()?-1:1), baseLineVector);
6184 painter->setAntialiasing(antialiasingBackup);
6185
6186 // tick labels:
6187 QRect oldClipRect;
6188 if (tickLabelSide == QCPAxis::lsInside) // if using inside labels, clip them to the axis rect
6189 {
6190 oldClipRect = painter->clipRegion().boundingRect();
6191 painter->setClipRect(axisRect);
6192 }
6193 QSize tickLabelsSize(0, 0); // size of largest tick label, for offset calculation of axis label
6194 if (!tickLabels.isEmpty())
6195 {
6196 if (tickLabelSide == QCPAxis::lsOutside)
6197 margin += tickLabelPadding;
6198 painter->setFont(tickLabelFont);
6199 painter->setPen(QPen(tickLabelColor));
6200 const int maxLabelIndex = qMin(tickPositions.size(), tickLabels.size());
6201 int distanceToAxis = margin;
6202 if (tickLabelSide == QCPAxis::lsInside)
6203 distanceToAxis = -(qMax(tickLengthIn, subTickLengthIn)+tickLabelPadding);
6204 for (int i=0; i<maxLabelIndex; ++i)
6205 placeTickLabel(painter, tickPositions.at(i), distanceToAxis, tickLabels.at(i), &tickLabelsSize);
6206 if (tickLabelSide == QCPAxis::lsOutside)
6207 margin += (QCPAxis::orientation(type) == Qt::Horizontal) ? tickLabelsSize.height() : tickLabelsSize.width();
6208 }
6209 if (tickLabelSide == QCPAxis::lsInside)
6210 painter->setClipRect(oldClipRect);
6211
6212 // axis label:
6213 QRect labelBounds;
6214 if (!label.isEmpty())
6215 {
6216 margin += labelPadding;
6217 painter->setFont(labelFont);
6218 painter->setPen(QPen(labelColor));
6219 labelBounds = painter->fontMetrics().boundingRect(0, 0, 0, 0, Qt::TextDontClip, label);
6220 if (type == QCPAxis::atLeft)
6221 {
6222 QTransform oldTransform = painter->transform();
6223 painter->translate((origin.x()-margin-labelBounds.height()), origin.y());
6224 painter->rotate(-90);
6225 painter->drawText(0, 0, axisRect.height(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, label);
6226 painter->setTransform(oldTransform);
6227 }
6228 else if (type == QCPAxis::atRight)
6229 {
6230 QTransform oldTransform = painter->transform();
6231 painter->translate((origin.x()+margin+labelBounds.height()), origin.y()-axisRect.height());
6232 painter->rotate(90);
6233 painter->drawText(0, 0, axisRect.height(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, label);
6234 painter->setTransform(oldTransform);
6235 }
6236 else if (type == QCPAxis::atTop)
6237 painter->drawText(origin.x(), origin.y()-margin-labelBounds.height(), axisRect.width(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, label);
6238 else if (type == QCPAxis::atBottom)
6239 painter->drawText(origin.x(), origin.y()+margin, axisRect.width(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, label);
6240 }
6241
6242 // set selection boxes:
6243 int selectionTolerance = 0;
6244 if (mParentPlot)
6245 selectionTolerance = mParentPlot->selectionTolerance();
6246 else
6247 qDebug() << Q_FUNC_INFO << "mParentPlot is null";
6248 int selAxisOutSize = qMax(qMax(tickLengthOut, subTickLengthOut), selectionTolerance);
6249 int selAxisInSize = selectionTolerance;
6250 int selTickLabelSize;
6251 int selTickLabelOffset;
6252 if (tickLabelSide == QCPAxis::lsOutside)
6253 {
6254 selTickLabelSize = (QCPAxis::orientation(type) == Qt::Horizontal ? tickLabelsSize.height() : tickLabelsSize.width());
6255 selTickLabelOffset = qMax(tickLengthOut, subTickLengthOut)+tickLabelPadding;
6256 } else
6257 {
6258 selTickLabelSize = -(QCPAxis::orientation(type) == Qt::Horizontal ? tickLabelsSize.height() : tickLabelsSize.width());
6259 selTickLabelOffset = -(qMax(tickLengthIn, subTickLengthIn)+tickLabelPadding);
6260 }
6261 int selLabelSize = labelBounds.height();
6262 int selLabelOffset = qMax(tickLengthOut, subTickLengthOut)+(!tickLabels.isEmpty() && tickLabelSide == QCPAxis::lsOutside ? tickLabelPadding+selTickLabelSize : 0)+labelPadding;
6263 if (type == QCPAxis::atLeft)
6264 {
6265 mAxisSelectionBox.setCoords(origin.x()-selAxisOutSize, axisRect.top(), origin.x()+selAxisInSize, axisRect.bottom());
6266 mTickLabelsSelectionBox.setCoords(origin.x()-selTickLabelOffset-selTickLabelSize, axisRect.top(), origin.x()-selTickLabelOffset, axisRect.bottom());
6267 mLabelSelectionBox.setCoords(origin.x()-selLabelOffset-selLabelSize, axisRect.top(), origin.x()-selLabelOffset, axisRect.bottom());
6169 for (int i=0; i<subTickPositions.size(); ++i)
6170 painter->drawLine(QLineF(origin.x()-subTickLengthOut*tickDir+xCor, subTickPositions.at(i)+yCor, origin.x()+subTickLengthIn*tickDir+xCor, subTickPositions.at(i)+yCor));
6171 }
6172 }
6173 margin += qMax(0, qMax(tickLengthOut, subTickLengthOut));
6174
6175 // draw axis base endings:
6176 bool antialiasingBackup = painter->antialiasing();
6177 painter->setAntialiasing(true); // always want endings to be antialiased, even if base and ticks themselves aren't
6178 painter->setBrush(QBrush(basePen.color()));
6179 QVector2D baseLineVector(baseLine.dx(), baseLine.dy());
6180 if (lowerEnding.style() != QCPLineEnding::esNone)
6181 lowerEnding.draw(painter, QVector2D(baseLine.p1())-baseLineVector.normalized()*lowerEnding.realLength()*(lowerEnding.inverted()?-1:1), -baseLineVector);
6182 if (upperEnding.style() != QCPLineEnding::esNone)
6183 upperEnding.draw(painter, QVector2D(baseLine.p2())+baseLineVector.normalized()*upperEnding.realLength()*(upperEnding.inverted()?-1:1), baseLineVector);
6184 painter->setAntialiasing(antialiasingBackup);
6185
6186 // tick labels:
6187 QRect oldClipRect;
6188 if (tickLabelSide == QCPAxis::lsInside) // if using inside labels, clip them to the axis rect
6189 {
6190 oldClipRect = painter->clipRegion().boundingRect();
6191 painter->setClipRect(axisRect);
6192 }
6193 QSize tickLabelsSize(0, 0); // size of largest tick label, for offset calculation of axis label
6194 if (!tickLabels.isEmpty())
6195 {
6196 if (tickLabelSide == QCPAxis::lsOutside)
6197 margin += tickLabelPadding;
6198 painter->setFont(tickLabelFont);
6199 painter->setPen(QPen(tickLabelColor));
6200 const int maxLabelIndex = qMin(tickPositions.size(), tickLabels.size());
6201 int distanceToAxis = margin;
6202 if (tickLabelSide == QCPAxis::lsInside)
6203 distanceToAxis = -(qMax(tickLengthIn, subTickLengthIn)+tickLabelPadding);
6204 for (int i=0; i<maxLabelIndex; ++i)
6205 placeTickLabel(painter, tickPositions.at(i), distanceToAxis, tickLabels.at(i), &tickLabelsSize);
6206 if (tickLabelSide == QCPAxis::lsOutside)
6207 margin += (QCPAxis::orientation(type) == Qt::Horizontal) ? tickLabelsSize.height() : tickLabelsSize.width();
6208 }
6209 if (tickLabelSide == QCPAxis::lsInside)
6210 painter->setClipRect(oldClipRect);
6211
6212 // axis label:
6213 QRect labelBounds;
6214 if (!label.isEmpty())
6215 {
6216 margin += labelPadding;
6217 painter->setFont(labelFont);
6218 painter->setPen(QPen(labelColor));
6219 labelBounds = painter->fontMetrics().boundingRect(0, 0, 0, 0, Qt::TextDontClip, label);
6220 if (type == QCPAxis::atLeft)
6221 {
6222 QTransform oldTransform = painter->transform();
6223 painter->translate((origin.x()-margin-labelBounds.height()), origin.y());
6224 painter->rotate(-90);
6225 painter->drawText(0, 0, axisRect.height(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, label);
6226 painter->setTransform(oldTransform);
6227 }
6228 else if (type == QCPAxis::atRight)
6229 {
6230 QTransform oldTransform = painter->transform();
6231 painter->translate((origin.x()+margin+labelBounds.height()), origin.y()-axisRect.height());
6232 painter->rotate(90);
6233 painter->drawText(0, 0, axisRect.height(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, label);
6234 painter->setTransform(oldTransform);
6235 }
6236 else if (type == QCPAxis::atTop)
6237 painter->drawText(origin.x(), origin.y()-margin-labelBounds.height(), axisRect.width(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, label);
6238 else if (type == QCPAxis::atBottom)
6239 painter->drawText(origin.x(), origin.y()+margin, axisRect.width(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, label);
6240 }
6241
6242 // set selection boxes:
6243 int selectionTolerance = 0;
6244 if (mParentPlot)
6245 selectionTolerance = mParentPlot->selectionTolerance();
6246 else
6247 qDebug() << Q_FUNC_INFO << "mParentPlot is null";
6248 int selAxisOutSize = qMax(qMax(tickLengthOut, subTickLengthOut), selectionTolerance);
6249 int selAxisInSize = selectionTolerance;
6250 int selTickLabelSize;
6251 int selTickLabelOffset;
6252 if (tickLabelSide == QCPAxis::lsOutside)
6253 {
6254 selTickLabelSize = (QCPAxis::orientation(type) == Qt::Horizontal ? tickLabelsSize.height() : tickLabelsSize.width());
6255 selTickLabelOffset = qMax(tickLengthOut, subTickLengthOut)+tickLabelPadding;
6256 } else
6257 {
6258 selTickLabelSize = -(QCPAxis::orientation(type) == Qt::Horizontal ? tickLabelsSize.height() : tickLabelsSize.width());
6259 selTickLabelOffset = -(qMax(tickLengthIn, subTickLengthIn)+tickLabelPadding);
6260 }
6261 int selLabelSize = labelBounds.height();
6262 int selLabelOffset = qMax(tickLengthOut, subTickLengthOut)+(!tickLabels.isEmpty() && tickLabelSide == QCPAxis::lsOutside ? tickLabelPadding+selTickLabelSize : 0)+labelPadding;
6263 if (type == QCPAxis::atLeft)
6264 {
6265 mAxisSelectionBox.setCoords(origin.x()-selAxisOutSize, axisRect.top(), origin.x()+selAxisInSize, axisRect.bottom());
6266 mTickLabelsSelectionBox.setCoords(origin.x()-selTickLabelOffset-selTickLabelSize, axisRect.top(), origin.x()-selTickLabelOffset, axisRect.bottom());
6267 mLabelSelectionBox.setCoords(origin.x()-selLabelOffset-selLabelSize, axisRect.top(), origin.x()-selLabelOffset, axisRect.bottom());
6268 6268 } else if (type == QCPAxis::atRight)
6269 6269 {
6270 mAxisSelectionBox.setCoords(origin.x()-selAxisInSize, axisRect.top(), origin.x()+selAxisOutSize, axisRect.bottom());
6271 mTickLabelsSelectionBox.setCoords(origin.x()+selTickLabelOffset+selTickLabelSize, axisRect.top(), origin.x()+selTickLabelOffset, axisRect.bottom());
6272 mLabelSelectionBox.setCoords(origin.x()+selLabelOffset+selLabelSize, axisRect.top(), origin.x()+selLabelOffset, axisRect.bottom());
6270 mAxisSelectionBox.setCoords(origin.x()-selAxisInSize, axisRect.top(), origin.x()+selAxisOutSize, axisRect.bottom());
6271 mTickLabelsSelectionBox.setCoords(origin.x()+selTickLabelOffset+selTickLabelSize, axisRect.top(), origin.x()+selTickLabelOffset, axisRect.bottom());
6272 mLabelSelectionBox.setCoords(origin.x()+selLabelOffset+selLabelSize, axisRect.top(), origin.x()+selLabelOffset, axisRect.bottom());
6273 6273 } else if (type == QCPAxis::atTop)
6274 6274 {
6275 mAxisSelectionBox.setCoords(axisRect.left(), origin.y()-selAxisOutSize, axisRect.right(), origin.y()+selAxisInSize);
6276 mTickLabelsSelectionBox.setCoords(axisRect.left(), origin.y()-selTickLabelOffset-selTickLabelSize, axisRect.right(), origin.y()-selTickLabelOffset);
6277 mLabelSelectionBox.setCoords(axisRect.left(), origin.y()-selLabelOffset-selLabelSize, axisRect.right(), origin.y()-selLabelOffset);
6275 mAxisSelectionBox.setCoords(axisRect.left(), origin.y()-selAxisOutSize, axisRect.right(), origin.y()+selAxisInSize);
6276 mTickLabelsSelectionBox.setCoords(axisRect.left(), origin.y()-selTickLabelOffset-selTickLabelSize, axisRect.right(), origin.y()-selTickLabelOffset);
6277 mLabelSelectionBox.setCoords(axisRect.left(), origin.y()-selLabelOffset-selLabelSize, axisRect.right(), origin.y()-selLabelOffset);
6278 6278 } else if (type == QCPAxis::atBottom)
6279 6279 {
6280 mAxisSelectionBox.setCoords(axisRect.left(), origin.y()-selAxisInSize, axisRect.right(), origin.y()+selAxisOutSize);
6281 mTickLabelsSelectionBox.setCoords(axisRect.left(), origin.y()+selTickLabelOffset+selTickLabelSize, axisRect.right(), origin.y()+selTickLabelOffset);
6282 mLabelSelectionBox.setCoords(axisRect.left(), origin.y()+selLabelOffset+selLabelSize, axisRect.right(), origin.y()+selLabelOffset);
6283 }
6284 mAxisSelectionBox = mAxisSelectionBox.normalized();
6285 mTickLabelsSelectionBox = mTickLabelsSelectionBox.normalized();
6286 mLabelSelectionBox = mLabelSelectionBox.normalized();
6287 // draw hitboxes for debug purposes:
6288 //painter->setBrush(Qt::NoBrush);
6289 //painter->drawRects(QVector<QRect>() << mAxisSelectionBox << mTickLabelsSelectionBox << mLabelSelectionBox);
6280 mAxisSelectionBox.setCoords(axisRect.left(), origin.y()-selAxisInSize, axisRect.right(), origin.y()+selAxisOutSize);
6281 mTickLabelsSelectionBox.setCoords(axisRect.left(), origin.y()+selTickLabelOffset+selTickLabelSize, axisRect.right(), origin.y()+selTickLabelOffset);
6282 mLabelSelectionBox.setCoords(axisRect.left(), origin.y()+selLabelOffset+selLabelSize, axisRect.right(), origin.y()+selLabelOffset);
6283 }
6284 mAxisSelectionBox = mAxisSelectionBox.normalized();
6285 mTickLabelsSelectionBox = mTickLabelsSelectionBox.normalized();
6286 mLabelSelectionBox = mLabelSelectionBox.normalized();
6287 // draw hitboxes for debug purposes:
6288 //painter->setBrush(Qt::NoBrush);
6289 //painter->drawRects(QVector<QRect>() << mAxisSelectionBox << mTickLabelsSelectionBox << mLabelSelectionBox);
6290 6290 }
6291 6291
6292 6292 /*! \internal
@@ -6296,35 +6296,35 void QCPAxisPainterPrivate::draw(QCPPain
6296 6296 */
6297 6297 int QCPAxisPainterPrivate::size() const
6298 6298 {
6299 int result = 0;
6300
6301 // get length of tick marks pointing outwards:
6302 if (!tickPositions.isEmpty())
6303 result += qMax(0, qMax(tickLengthOut, subTickLengthOut));
6304
6305 // calculate size of tick labels:
6306 if (tickLabelSide == QCPAxis::lsOutside)
6307 {
6308 QSize tickLabelsSize(0, 0);
6309 if (!tickLabels.isEmpty())
6310 {
6311 for (int i=0; i<tickLabels.size(); ++i)
6312 getMaxTickLabelSize(tickLabelFont, tickLabels.at(i), &tickLabelsSize);
6313 result += QCPAxis::orientation(type) == Qt::Horizontal ? tickLabelsSize.height() : tickLabelsSize.width();
6314 result += tickLabelPadding;
6315 }
6316 }
6317
6318 // calculate size of axis label (only height needed, because left/right labels are rotated by 90 degrees):
6319 if (!label.isEmpty())
6320 {
6321 QFontMetrics fontMetrics(labelFont);
6322 QRect bounds;
6323 bounds = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip | Qt::AlignHCenter | Qt::AlignVCenter, label);
6324 result += bounds.height() + labelPadding;
6325 }
6326
6327 return result;
6299 int result = 0;
6300
6301 // get length of tick marks pointing outwards:
6302 if (!tickPositions.isEmpty())
6303 result += qMax(0, qMax(tickLengthOut, subTickLengthOut));
6304
6305 // calculate size of tick labels:
6306 if (tickLabelSide == QCPAxis::lsOutside)
6307 {
6308 QSize tickLabelsSize(0, 0);
6309 if (!tickLabels.isEmpty())
6310 {
6311 for (int i=0; i<tickLabels.size(); ++i)
6312 getMaxTickLabelSize(tickLabelFont, tickLabels.at(i), &tickLabelsSize);
6313 result += QCPAxis::orientation(type) == Qt::Horizontal ? tickLabelsSize.height() : tickLabelsSize.width();
6314 result += tickLabelPadding;
6315 }
6316 }
6317
6318 // calculate size of axis label (only height needed, because left/right labels are rotated by 90 degrees):
6319 if (!label.isEmpty())
6320 {
6321 QFontMetrics fontMetrics(labelFont);
6322 QRect bounds;
6323 bounds = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip | Qt::AlignHCenter | Qt::AlignVCenter, label);
6324 result += bounds.height() + labelPadding;
6325 }
6326
6327 return result;
6328 6328 }
6329 6329
6330 6330 /*! \internal
@@ -6335,7 +6335,7 int QCPAxisPainterPrivate::size() const
6335 6335 */
6336 6336 void QCPAxisPainterPrivate::clearCache()
6337 6337 {
6338 mLabelCache.clear();
6338 mLabelCache.clear();
6339 6339 }
6340 6340
6341 6341 /*! \internal
@@ -6347,14 +6347,14 void QCPAxisPainterPrivate::clearCache()
6347 6347 */
6348 6348 QByteArray QCPAxisPainterPrivate::generateLabelParameterHash() const
6349 6349 {
6350 QByteArray result;
6351 result.append(QByteArray::number(tickLabelRotation));
6352 result.append(QByteArray::number((int)tickLabelSide));
6353 result.append(QByteArray::number((int)substituteExponent));
6354 result.append(QByteArray::number((int)numberMultiplyCross));
6355 result.append(tickLabelColor.name().toLatin1()+QByteArray::number(tickLabelColor.alpha(), 16));
6356 result.append(tickLabelFont.toString().toLatin1());
6357 return result;
6350 QByteArray result;
6351 result.append(QByteArray::number(tickLabelRotation));
6352 result.append(QByteArray::number((int)tickLabelSide));
6353 result.append(QByteArray::number((int)substituteExponent));
6354 result.append(QByteArray::number((int)numberMultiplyCross));
6355 result.append(tickLabelColor.name().toLatin1()+QByteArray::number(tickLabelColor.alpha(), 16));
6356 result.append(tickLabelFont.toString().toLatin1());
6357 return result;
6358 6358 }
6359 6359
6360 6360 /*! \internal
@@ -6378,78 +6378,78 QByteArray QCPAxisPainterPrivate::genera
6378 6378 */
6379 6379 void QCPAxisPainterPrivate::placeTickLabel(QCPPainter *painter, double position, int distanceToAxis, const QString &text, QSize *tickLabelsSize)
6380 6380 {
6381 // warning: if you change anything here, also adapt getMaxTickLabelSize() accordingly!
6382 if (text.isEmpty()) return;
6383 QSize finalSize;
6384 QPointF labelAnchor;
6385 switch (type)
6381 // warning: if you change anything here, also adapt getMaxTickLabelSize() accordingly!
6382 if (text.isEmpty()) return;
6383 QSize finalSize;
6384 QPointF labelAnchor;
6385 switch (type)
6386 6386 {
6387 6387 case QCPAxis::atLeft: labelAnchor = QPointF(axisRect.left()-distanceToAxis-offset, position); break;
6388 6388 case QCPAxis::atRight: labelAnchor = QPointF(axisRect.right()+distanceToAxis+offset, position); break;
6389 6389 case QCPAxis::atTop: labelAnchor = QPointF(position, axisRect.top()-distanceToAxis-offset); break;
6390 6390 case QCPAxis::atBottom: labelAnchor = QPointF(position, axisRect.bottom()+distanceToAxis+offset); break;
6391 6391 }
6392 if (mParentPlot->plottingHints().testFlag(QCP::phCacheLabels) && !painter->modes().testFlag(QCPPainter::pmNoCaching)) // label caching enabled
6393 {
6394 if (!mLabelCache.contains(text)) // no cached label exists, create it
6395 {
6396 CachedLabel *newCachedLabel = new CachedLabel;
6397 TickLabelData labelData = getTickLabelData(painter->font(), text);
6398 newCachedLabel->offset = getTickLabelDrawOffset(labelData)+labelData.rotatedTotalBounds.topLeft();
6399 newCachedLabel->pixmap = QPixmap(labelData.rotatedTotalBounds.size());
6400 newCachedLabel->pixmap.fill(Qt::transparent);
6401 QCPPainter cachePainter(&newCachedLabel->pixmap);
6402 cachePainter.setPen(painter->pen());
6403 drawTickLabel(&cachePainter, -labelData.rotatedTotalBounds.topLeft().x(), -labelData.rotatedTotalBounds.topLeft().y(), labelData);
6404 mLabelCache.insert(text, newCachedLabel, 1);
6405 }
6406 // draw cached label:
6407 const CachedLabel *cachedLabel = mLabelCache.object(text);
6408 // if label would be partly clipped by widget border on sides, don't draw it (only for outside tick labels):
6409 if (tickLabelSide == QCPAxis::lsOutside)
6410 {
6411 if (QCPAxis::orientation(type) == Qt::Horizontal)
6412 {
6413 if (labelAnchor.x()+cachedLabel->offset.x()+cachedLabel->pixmap.width() > viewportRect.right() ||
6414 labelAnchor.x()+cachedLabel->offset.x() < viewportRect.left())
6415 return;
6392 if (mParentPlot->plottingHints().testFlag(QCP::phCacheLabels) && !painter->modes().testFlag(QCPPainter::pmNoCaching)) // label caching enabled
6393 {
6394 if (!mLabelCache.contains(text)) // no cached label exists, create it
6395 {
6396 CachedLabel *newCachedLabel = new CachedLabel;
6397 TickLabelData labelData = getTickLabelData(painter->font(), text);
6398 newCachedLabel->offset = getTickLabelDrawOffset(labelData)+labelData.rotatedTotalBounds.topLeft();
6399 newCachedLabel->pixmap = QPixmap(labelData.rotatedTotalBounds.size());
6400 newCachedLabel->pixmap.fill(Qt::transparent);
6401 QCPPainter cachePainter(&newCachedLabel->pixmap);
6402 cachePainter.setPen(painter->pen());
6403 drawTickLabel(&cachePainter, -labelData.rotatedTotalBounds.topLeft().x(), -labelData.rotatedTotalBounds.topLeft().y(), labelData);
6404 mLabelCache.insert(text, newCachedLabel, 1);
6405 }
6406 // draw cached label:
6407 const CachedLabel *cachedLabel = mLabelCache.object(text);
6408 // if label would be partly clipped by widget border on sides, don't draw it (only for outside tick labels):
6409 if (tickLabelSide == QCPAxis::lsOutside)
6410 {
6411 if (QCPAxis::orientation(type) == Qt::Horizontal)
6412 {
6413 if (labelAnchor.x()+cachedLabel->offset.x()+cachedLabel->pixmap.width() > viewportRect.right() ||
6414 labelAnchor.x()+cachedLabel->offset.x() < viewportRect.left())
6415 return;
6416 6416 } else
6417 6417 {
6418 if (labelAnchor.y()+cachedLabel->offset.y()+cachedLabel->pixmap.height() >viewportRect.bottom() ||
6419 labelAnchor.y()+cachedLabel->offset.y() < viewportRect.top())
6420 return;
6421 }
6422 }
6423 painter->drawPixmap(labelAnchor+cachedLabel->offset, cachedLabel->pixmap);
6424 finalSize = cachedLabel->pixmap.size();
6418 if (labelAnchor.y()+cachedLabel->offset.y()+cachedLabel->pixmap.height() >viewportRect.bottom() ||
6419 labelAnchor.y()+cachedLabel->offset.y() < viewportRect.top())
6420 return;
6421 }
6422 }
6423 painter->drawPixmap(labelAnchor+cachedLabel->offset, cachedLabel->pixmap);
6424 finalSize = cachedLabel->pixmap.size();
6425 6425 } else // label caching disabled, draw text directly on surface:
6426 6426 {
6427 TickLabelData labelData = getTickLabelData(painter->font(), text);
6428 QPointF finalPosition = labelAnchor + getTickLabelDrawOffset(labelData);
6429 // if label would be partly clipped by widget border on sides, don't draw it (only for outside tick labels):
6430 if (tickLabelSide == QCPAxis::lsOutside)
6431 {
6432 if (QCPAxis::orientation(type) == Qt::Horizontal)
6433 {
6434 if (finalPosition.x()+(labelData.rotatedTotalBounds.width()+labelData.rotatedTotalBounds.left()) > viewportRect.right() ||
6435 finalPosition.x()+labelData.rotatedTotalBounds.left() < viewportRect.left())
6436 return;
6427 TickLabelData labelData = getTickLabelData(painter->font(), text);
6428 QPointF finalPosition = labelAnchor + getTickLabelDrawOffset(labelData);
6429 // if label would be partly clipped by widget border on sides, don't draw it (only for outside tick labels):
6430 if (tickLabelSide == QCPAxis::lsOutside)
6431 {
6432 if (QCPAxis::orientation(type) == Qt::Horizontal)
6433 {
6434 if (finalPosition.x()+(labelData.rotatedTotalBounds.width()+labelData.rotatedTotalBounds.left()) > viewportRect.right() ||
6435 finalPosition.x()+labelData.rotatedTotalBounds.left() < viewportRect.left())
6436 return;
6437 6437 } else
6438 6438 {
6439 if (finalPosition.y()+(labelData.rotatedTotalBounds.height()+labelData.rotatedTotalBounds.top()) > viewportRect.bottom() ||
6440 finalPosition.y()+labelData.rotatedTotalBounds.top() < viewportRect.top())
6441 return;
6442 }
6443 }
6444 drawTickLabel(painter, finalPosition.x(), finalPosition.y(), labelData);
6445 finalSize = labelData.rotatedTotalBounds.size();
6446 }
6447
6448 // expand passed tickLabelsSize if current tick label is larger:
6449 if (finalSize.width() > tickLabelsSize->width())
6450 tickLabelsSize->setWidth(finalSize.width());
6451 if (finalSize.height() > tickLabelsSize->height())
6452 tickLabelsSize->setHeight(finalSize.height());
6439 if (finalPosition.y()+(labelData.rotatedTotalBounds.height()+labelData.rotatedTotalBounds.top()) > viewportRect.bottom() ||
6440 finalPosition.y()+labelData.rotatedTotalBounds.top() < viewportRect.top())
6441 return;
6442 }
6443 }
6444 drawTickLabel(painter, finalPosition.x(), finalPosition.y(), labelData);
6445 finalSize = labelData.rotatedTotalBounds.size();
6446 }
6447
6448 // expand passed tickLabelsSize if current tick label is larger:
6449 if (finalSize.width() > tickLabelsSize->width())
6450 tickLabelsSize->setWidth(finalSize.width());
6451 if (finalSize.height() > tickLabelsSize->height())
6452 tickLabelsSize->setHeight(finalSize.height());
6453 6453 }
6454 6454
6455 6455 /*! \internal
@@ -6463,31 +6463,31 void QCPAxisPainterPrivate::placeTickLab
6463 6463 */
6464 6464 void QCPAxisPainterPrivate::drawTickLabel(QCPPainter *painter, double x, double y, const TickLabelData &labelData) const
6465 6465 {
6466 // backup painter settings that we're about to change:
6467 QTransform oldTransform = painter->transform();
6468 QFont oldFont = painter->font();
6469
6470 // transform painter to position/rotation:
6471 painter->translate(x, y);
6472 if (!qFuzzyIsNull(tickLabelRotation))
6473 painter->rotate(tickLabelRotation);
6474
6475 // draw text:
6476 if (!labelData.expPart.isEmpty()) // indicator that beautiful powers must be used
6477 {
6478 painter->setFont(labelData.baseFont);
6479 painter->drawText(0, 0, 0, 0, Qt::TextDontClip, labelData.basePart);
6480 painter->setFont(labelData.expFont);
6481 painter->drawText(labelData.baseBounds.width()+1, 0, labelData.expBounds.width(), labelData.expBounds.height(), Qt::TextDontClip, labelData.expPart);
6482 } else
6483 {
6484 painter->setFont(labelData.baseFont);
6485 painter->drawText(0, 0, labelData.totalBounds.width(), labelData.totalBounds.height(), Qt::TextDontClip | Qt::AlignHCenter, labelData.basePart);
6486 }
6487
6488 // reset painter settings to what it was before:
6489 painter->setTransform(oldTransform);
6490 painter->setFont(oldFont);
6466 // backup painter settings that we're about to change:
6467 QTransform oldTransform = painter->transform();
6468 QFont oldFont = painter->font();
6469
6470 // transform painter to position/rotation:
6471 painter->translate(x, y);
6472 if (!qFuzzyIsNull(tickLabelRotation))
6473 painter->rotate(tickLabelRotation);
6474
6475 // draw text:
6476 if (!labelData.expPart.isEmpty()) // indicator that beautiful powers must be used
6477 {
6478 painter->setFont(labelData.baseFont);
6479 painter->drawText(0, 0, 0, 0, Qt::TextDontClip, labelData.basePart);
6480 painter->setFont(labelData.expFont);
6481 painter->drawText(labelData.baseBounds.width()+1, 0, labelData.expBounds.width(), labelData.expBounds.height(), Qt::TextDontClip, labelData.expPart);
6482 } else
6483 {
6484 painter->setFont(labelData.baseFont);
6485 painter->drawText(0, 0, labelData.totalBounds.width(), labelData.totalBounds.height(), Qt::TextDontClip | Qt::AlignHCenter, labelData.basePart);
6486 }
6487
6488 // reset painter settings to what it was before:
6489 painter->setTransform(oldTransform);
6490 painter->setFont(oldFont);
6491 6491 }
6492 6492
6493 6493 /*! \internal
@@ -6500,61 +6500,61 void QCPAxisPainterPrivate::drawTickLabe
6500 6500 */
6501 6501 QCPAxisPainterPrivate::TickLabelData QCPAxisPainterPrivate::getTickLabelData(const QFont &font, const QString &text) const
6502 6502 {
6503 TickLabelData result;
6504
6505 // determine whether beautiful decimal powers should be used
6506 bool useBeautifulPowers = false;
6507 int ePos = -1;
6508 if (substituteExponent)
6509 {
6510 ePos = text.indexOf(QLatin1Char('e'));
6511 if (ePos > -1)
6512 useBeautifulPowers = true;
6513 }
6514
6515 // calculate text bounding rects and do string preparation for beautiful decimal powers:
6516 result.baseFont = font;
6517 if (result.baseFont.pointSizeF() > 0) // On some rare systems, this sometimes is initialized with -1 (Qt bug?), so we check here before possibly setting a negative value in the next line
6518 result.baseFont.setPointSizeF(result.baseFont.pointSizeF()+0.05); // QFontMetrics.boundingRect has a bug for exact point sizes that make the results oscillate due to internal rounding
6519 if (useBeautifulPowers)
6520 {
6521 // split text into parts of number/symbol that will be drawn normally and part that will be drawn as exponent:
6522 result.basePart = text.left(ePos);
6523 // in log scaling, we want to turn "1*10^n" into "10^n", else add multiplication sign and decimal base:
6524 if (abbreviateDecimalPowers && result.basePart == QLatin1String("1"))
6525 result.basePart = QLatin1String("10");
6526 else
6527 result.basePart += (numberMultiplyCross ? QString(QChar(215)) : QString(QChar(183))) + QLatin1String("10");
6528 result.expPart = text.mid(ePos+1);
6529 // clip "+" and leading zeros off expPart:
6530 while (result.expPart.length() > 2 && result.expPart.at(1) == QLatin1Char('0')) // length > 2 so we leave one zero when numberFormatChar is 'e'
6531 result.expPart.remove(1, 1);
6532 if (!result.expPart.isEmpty() && result.expPart.at(0) == QLatin1Char('+'))
6533 result.expPart.remove(0, 1);
6534 // prepare smaller font for exponent:
6535 result.expFont = font;
6536 result.expFont.setPointSize(result.expFont.pointSize()*0.75);
6537 // calculate bounding rects of base part, exponent part and total one:
6538 result.baseBounds = QFontMetrics(result.baseFont).boundingRect(0, 0, 0, 0, Qt::TextDontClip, result.basePart);
6539 result.expBounds = QFontMetrics(result.expFont).boundingRect(0, 0, 0, 0, Qt::TextDontClip, result.expPart);
6540 result.totalBounds = result.baseBounds.adjusted(0, 0, result.expBounds.width()+2, 0); // +2 consists of the 1 pixel spacing between base and exponent (see drawTickLabel) and an extra pixel to include AA
6503 TickLabelData result;
6504
6505 // determine whether beautiful decimal powers should be used
6506 bool useBeautifulPowers = false;
6507 int ePos = -1;
6508 if (substituteExponent)
6509 {
6510 ePos = text.indexOf(QLatin1Char('e'));
6511 if (ePos > -1)
6512 useBeautifulPowers = true;
6513 }
6514
6515 // calculate text bounding rects and do string preparation for beautiful decimal powers:
6516 result.baseFont = font;
6517 if (result.baseFont.pointSizeF() > 0) // On some rare systems, this sometimes is initialized with -1 (Qt bug?), so we check here before possibly setting a negative value in the next line
6518 result.baseFont.setPointSizeF(result.baseFont.pointSizeF()+0.05); // QFontMetrics.boundingRect has a bug for exact point sizes that make the results oscillate due to internal rounding
6519 if (useBeautifulPowers)
6520 {
6521 // split text into parts of number/symbol that will be drawn normally and part that will be drawn as exponent:
6522 result.basePart = text.left(ePos);
6523 // in log scaling, we want to turn "1*10^n" into "10^n", else add multiplication sign and decimal base:
6524 if (abbreviateDecimalPowers && result.basePart == QLatin1String("1"))
6525 result.basePart = QLatin1String("10");
6526 else
6527 result.basePart += (numberMultiplyCross ? QString(QChar(215)) : QString(QChar(183))) + QLatin1String("10");
6528 result.expPart = text.mid(ePos+1);
6529 // clip "+" and leading zeros off expPart:
6530 while (result.expPart.length() > 2 && result.expPart.at(1) == QLatin1Char('0')) // length > 2 so we leave one zero when numberFormatChar is 'e'
6531 result.expPart.remove(1, 1);
6532 if (!result.expPart.isEmpty() && result.expPart.at(0) == QLatin1Char('+'))
6533 result.expPart.remove(0, 1);
6534 // prepare smaller font for exponent:
6535 result.expFont = font;
6536 result.expFont.setPointSize(result.expFont.pointSize()*0.75);
6537 // calculate bounding rects of base part, exponent part and total one:
6538 result.baseBounds = QFontMetrics(result.baseFont).boundingRect(0, 0, 0, 0, Qt::TextDontClip, result.basePart);
6539 result.expBounds = QFontMetrics(result.expFont).boundingRect(0, 0, 0, 0, Qt::TextDontClip, result.expPart);
6540 result.totalBounds = result.baseBounds.adjusted(0, 0, result.expBounds.width()+2, 0); // +2 consists of the 1 pixel spacing between base and exponent (see drawTickLabel) and an extra pixel to include AA
6541 6541 } else // useBeautifulPowers == false
6542 6542 {
6543 result.basePart = text;
6544 result.totalBounds = QFontMetrics(result.baseFont).boundingRect(0, 0, 0, 0, Qt::TextDontClip | Qt::AlignHCenter, result.basePart);
6545 }
6546 result.totalBounds.moveTopLeft(QPoint(0, 0)); // want bounding box aligned top left at origin, independent of how it was created, to make further processing simpler
6547
6548 // calculate possibly different bounding rect after rotation:
6549 result.rotatedTotalBounds = result.totalBounds;
6550 if (!qFuzzyIsNull(tickLabelRotation))
6551 {
6552 QTransform transform;
6553 transform.rotate(tickLabelRotation);
6554 result.rotatedTotalBounds = transform.mapRect(result.rotatedTotalBounds);
6555 }
6556
6557 return result;
6543 result.basePart = text;
6544 result.totalBounds = QFontMetrics(result.baseFont).boundingRect(0, 0, 0, 0, Qt::TextDontClip | Qt::AlignHCenter, result.basePart);
6545 }
6546 result.totalBounds.moveTopLeft(QPoint(0, 0)); // want bounding box aligned top left at origin, independent of how it was created, to make further processing simpler
6547
6548 // calculate possibly different bounding rect after rotation:
6549 result.rotatedTotalBounds = result.totalBounds;
6550 if (!qFuzzyIsNull(tickLabelRotation))
6551 {
6552 QTransform transform;
6553 transform.rotate(tickLabelRotation);
6554 result.rotatedTotalBounds = transform.mapRect(result.rotatedTotalBounds);
6555 }
6556
6557 return result;
6558 6558 }
6559 6559
6560 6560 /*! \internal
@@ -6569,7 +6569,7 QCPAxisPainterPrivate::TickLabelData QCP
6569 6569 */
6570 6570 QPointF QCPAxisPainterPrivate::getTickLabelDrawOffset(const TickLabelData &labelData) const
6571 6571 {
6572 /*
6572 /*
6573 6573 calculate label offset from base point at tick (non-trivial, for best visual appearance): short
6574 6574 explanation for bottom axis: The anchor, i.e. the point in the label that is placed
6575 6575 horizontally under the corresponding tick is always on the label side that is closer to the
@@ -6579,85 +6579,85 QPointF QCPAxisPainterPrivate::getTickLa
6579 6579 time, a 45 degree rotated text will "point toward" its tick, as is typical for rotated tick
6580 6580 labels.
6581 6581 */
6582 bool doRotation = !qFuzzyIsNull(tickLabelRotation);
6583 bool flip = qFuzzyCompare(qAbs(tickLabelRotation), 90.0); // perfect +/-90 degree flip. Indicates vertical label centering on vertical axes.
6584 double radians = tickLabelRotation/180.0*M_PI;
6585 int x=0, y=0;
6586 if ((type == QCPAxis::atLeft && tickLabelSide == QCPAxis::lsOutside) || (type == QCPAxis::atRight && tickLabelSide == QCPAxis::lsInside)) // Anchor at right side of tick label
6587 {
6588 if (doRotation)
6589 {
6590 if (tickLabelRotation > 0)
6591 {
6592 x = -qCos(radians)*labelData.totalBounds.width();
6593 y = flip ? -labelData.totalBounds.width()/2.0 : -qSin(radians)*labelData.totalBounds.width()-qCos(radians)*labelData.totalBounds.height()/2.0;
6582 bool doRotation = !qFuzzyIsNull(tickLabelRotation);
6583 bool flip = qFuzzyCompare(qAbs(tickLabelRotation), 90.0); // perfect +/-90 degree flip. Indicates vertical label centering on vertical axes.
6584 double radians = tickLabelRotation/180.0*M_PI;
6585 int x=0, y=0;
6586 if ((type == QCPAxis::atLeft && tickLabelSide == QCPAxis::lsOutside) || (type == QCPAxis::atRight && tickLabelSide == QCPAxis::lsInside)) // Anchor at right side of tick label
6587 {
6588 if (doRotation)
6589 {
6590 if (tickLabelRotation > 0)
6591 {
6592 x = -qCos(radians)*labelData.totalBounds.width();
6593 y = flip ? -labelData.totalBounds.width()/2.0 : -qSin(radians)*labelData.totalBounds.width()-qCos(radians)*labelData.totalBounds.height()/2.0;
6594 6594 } else
6595 6595 {
6596 x = -qCos(-radians)*labelData.totalBounds.width()-qSin(-radians)*labelData.totalBounds.height();
6597 y = flip ? +labelData.totalBounds.width()/2.0 : +qSin(-radians)*labelData.totalBounds.width()-qCos(-radians)*labelData.totalBounds.height()/2.0;
6596 x = -qCos(-radians)*labelData.totalBounds.width()-qSin(-radians)*labelData.totalBounds.height();
6597 y = flip ? +labelData.totalBounds.width()/2.0 : +qSin(-radians)*labelData.totalBounds.width()-qCos(-radians)*labelData.totalBounds.height()/2.0;
6598 6598 }
6599 6599 } else
6600 6600 {
6601 x = -labelData.totalBounds.width();
6602 y = -labelData.totalBounds.height()/2.0;
6601 x = -labelData.totalBounds.width();
6602 y = -labelData.totalBounds.height()/2.0;
6603 6603 }
6604 6604 } else if ((type == QCPAxis::atRight && tickLabelSide == QCPAxis::lsOutside) || (type == QCPAxis::atLeft && tickLabelSide == QCPAxis::lsInside)) // Anchor at left side of tick label
6605 6605 {
6606 if (doRotation)
6607 {
6608 if (tickLabelRotation > 0)
6609 {
6610 x = +qSin(radians)*labelData.totalBounds.height();
6611 y = flip ? -labelData.totalBounds.width()/2.0 : -qCos(radians)*labelData.totalBounds.height()/2.0;
6606 if (doRotation)
6607 {
6608 if (tickLabelRotation > 0)
6609 {
6610 x = +qSin(radians)*labelData.totalBounds.height();
6611 y = flip ? -labelData.totalBounds.width()/2.0 : -qCos(radians)*labelData.totalBounds.height()/2.0;
6612 6612 } else
6613 6613 {
6614 x = 0;
6615 y = flip ? +labelData.totalBounds.width()/2.0 : -qCos(-radians)*labelData.totalBounds.height()/2.0;
6614 x = 0;
6615 y = flip ? +labelData.totalBounds.width()/2.0 : -qCos(-radians)*labelData.totalBounds.height()/2.0;
6616 6616 }
6617 6617 } else
6618 6618 {
6619 x = 0;
6620 y = -labelData.totalBounds.height()/2.0;
6619 x = 0;
6620 y = -labelData.totalBounds.height()/2.0;
6621 6621 }
6622 6622 } else if ((type == QCPAxis::atTop && tickLabelSide == QCPAxis::lsOutside) || (type == QCPAxis::atBottom && tickLabelSide == QCPAxis::lsInside)) // Anchor at bottom side of tick label
6623 6623 {
6624 if (doRotation)
6625 {
6626 if (tickLabelRotation > 0)
6627 {
6628 x = -qCos(radians)*labelData.totalBounds.width()+qSin(radians)*labelData.totalBounds.height()/2.0;
6629 y = -qSin(radians)*labelData.totalBounds.width()-qCos(radians)*labelData.totalBounds.height();
6624 if (doRotation)
6625 {
6626 if (tickLabelRotation > 0)
6627 {
6628 x = -qCos(radians)*labelData.totalBounds.width()+qSin(radians)*labelData.totalBounds.height()/2.0;
6629 y = -qSin(radians)*labelData.totalBounds.width()-qCos(radians)*labelData.totalBounds.height();
6630 6630 } else
6631 6631 {
6632 x = -qSin(-radians)*labelData.totalBounds.height()/2.0;
6633 y = -qCos(-radians)*labelData.totalBounds.height();
6632 x = -qSin(-radians)*labelData.totalBounds.height()/2.0;
6633 y = -qCos(-radians)*labelData.totalBounds.height();
6634 6634 }
6635 6635 } else
6636 6636 {
6637 x = -labelData.totalBounds.width()/2.0;
6638 y = -labelData.totalBounds.height();
6637 x = -labelData.totalBounds.width()/2.0;
6638 y = -labelData.totalBounds.height();
6639 6639 }
6640 6640 } else if ((type == QCPAxis::atBottom && tickLabelSide == QCPAxis::lsOutside) || (type == QCPAxis::atTop && tickLabelSide == QCPAxis::lsInside)) // Anchor at top side of tick label
6641 6641 {
6642 if (doRotation)
6643 {
6644 if (tickLabelRotation > 0)
6645 {
6646 x = +qSin(radians)*labelData.totalBounds.height()/2.0;
6647 y = 0;
6642 if (doRotation)
6643 {
6644 if (tickLabelRotation > 0)
6645 {
6646 x = +qSin(radians)*labelData.totalBounds.height()/2.0;
6647 y = 0;
6648 6648 } else
6649 6649 {
6650 x = -qCos(-radians)*labelData.totalBounds.width()-qSin(-radians)*labelData.totalBounds.height()/2.0;
6651 y = +qSin(-radians)*labelData.totalBounds.width();
6650 x = -qCos(-radians)*labelData.totalBounds.width()-qSin(-radians)*labelData.totalBounds.height()/2.0;
6651 y = +qSin(-radians)*labelData.totalBounds.width();
6652 6652 }
6653 6653 } else
6654 6654 {
6655 x = -labelData.totalBounds.width()/2.0;
6656 y = 0;
6657 }
6658 }
6659
6660 return QPointF(x, y);
6655 x = -labelData.totalBounds.width()/2.0;
6656 y = 0;
6657 }
6658 }
6659
6660 return QPointF(x, y);
6661 6661 }
6662 6662
6663 6663 /*! \internal
@@ -6669,23 +6669,23 QPointF QCPAxisPainterPrivate::getTickLa
6669 6669 */
6670 6670 void QCPAxisPainterPrivate::getMaxTickLabelSize(const QFont &font, const QString &text, QSize *tickLabelsSize) const
6671 6671 {
6672 // note: this function must return the same tick label sizes as the placeTickLabel function.
6673 QSize finalSize;
6674 if (mParentPlot->plottingHints().testFlag(QCP::phCacheLabels) && mLabelCache.contains(text)) // label caching enabled and have cached label
6675 {
6676 const CachedLabel *cachedLabel = mLabelCache.object(text);
6677 finalSize = cachedLabel->pixmap.size();
6672 // note: this function must return the same tick label sizes as the placeTickLabel function.
6673 QSize finalSize;
6674 if (mParentPlot->plottingHints().testFlag(QCP::phCacheLabels) && mLabelCache.contains(text)) // label caching enabled and have cached label
6675 {
6676 const CachedLabel *cachedLabel = mLabelCache.object(text);
6677 finalSize = cachedLabel->pixmap.size();
6678 6678 } else // label caching disabled or no label with this text cached:
6679 6679 {
6680 TickLabelData labelData = getTickLabelData(font, text);
6681 finalSize = labelData.rotatedTotalBounds.size();
6682 }
6683
6684 // expand passed tickLabelsSize if current tick label is larger:
6685 if (finalSize.width() > tickLabelsSize->width())
6686 tickLabelsSize->setWidth(finalSize.width());
6687 if (finalSize.height() > tickLabelsSize->height())
6688 tickLabelsSize->setHeight(finalSize.height());
6680 TickLabelData labelData = getTickLabelData(font, text);
6681 finalSize = labelData.rotatedTotalBounds.size();
6682 }
6683
6684 // expand passed tickLabelsSize if current tick label is larger:
6685 if (finalSize.width() > tickLabelsSize->width())
6686 tickLabelsSize->setWidth(finalSize.width());
6687 if (finalSize.height() > tickLabelsSize->height())
6688 tickLabelsSize->setHeight(finalSize.height());
6689 6689 }
6690 6690
6691 6691
@@ -6838,24 +6838,24 void QCPAxisPainterPrivate::getMaxTickLa
6838 6838 You probably want one of the subclasses like \ref QCPGraph or \ref QCPCurve instead.
6839 6839 */
6840 6840 QCPAbstractPlottable::QCPAbstractPlottable(QCPAxis *keyAxis, QCPAxis *valueAxis) :
6841 QCPLayerable(keyAxis->parentPlot(), QString(), keyAxis->axisRect()),
6842 mName(),
6843 mAntialiasedFill(true),
6844 mAntialiasedScatters(true),
6845 mAntialiasedErrorBars(false),
6846 mPen(Qt::black),
6847 mSelectedPen(Qt::black),
6848 mBrush(Qt::NoBrush),
6849 mSelectedBrush(Qt::NoBrush),
6850 mKeyAxis(keyAxis),
6851 mValueAxis(valueAxis),
6852 mSelectable(true),
6853 mSelected(false)
6854 {
6855 if (keyAxis->parentPlot() != valueAxis->parentPlot())
6856 qDebug() << Q_FUNC_INFO << "Parent plot of keyAxis is not the same as that of valueAxis.";
6857 if (keyAxis->orientation() == valueAxis->orientation())
6858 qDebug() << Q_FUNC_INFO << "keyAxis and valueAxis must be orthogonal to each other.";
6841 QCPLayerable(keyAxis->parentPlot(), QString(), keyAxis->axisRect()),
6842 mName(),
6843 mAntialiasedFill(true),
6844 mAntialiasedScatters(true),
6845 mAntialiasedErrorBars(false),
6846 mPen(Qt::black),
6847 mSelectedPen(Qt::black),
6848 mBrush(Qt::NoBrush),
6849 mSelectedBrush(Qt::NoBrush),
6850 mKeyAxis(keyAxis),
6851 mValueAxis(valueAxis),
6852 mSelectable(true),
6853 mSelected(false)
6854 {
6855 if (keyAxis->parentPlot() != valueAxis->parentPlot())
6856 qDebug() << Q_FUNC_INFO << "Parent plot of keyAxis is not the same as that of valueAxis.";
6857 if (keyAxis->orientation() == valueAxis->orientation())
6858 qDebug() << Q_FUNC_INFO << "keyAxis and valueAxis must be orthogonal to each other.";
6859 6859 }
6860 6860
6861 6861 /*!
@@ -6864,7 +6864,7 QCPAbstractPlottable::QCPAbstractPlottab
6864 6864 */
6865 6865 void QCPAbstractPlottable::setName(const QString &name)
6866 6866 {
6867 mName = name;
6867 mName = name;
6868 6868 }
6869 6869
6870 6870 /*!
@@ -6875,7 +6875,7 void QCPAbstractPlottable::setName(const
6875 6875 */
6876 6876 void QCPAbstractPlottable::setAntialiasedFill(bool enabled)
6877 6877 {
6878 mAntialiasedFill = enabled;
6878 mAntialiasedFill = enabled;
6879 6879 }
6880 6880
6881 6881 /*!
@@ -6886,7 +6886,7 void QCPAbstractPlottable::setAntialiase
6886 6886 */
6887 6887 void QCPAbstractPlottable::setAntialiasedScatters(bool enabled)
6888 6888 {
6889 mAntialiasedScatters = enabled;
6889 mAntialiasedScatters = enabled;
6890 6890 }
6891 6891
6892 6892 /*!
@@ -6897,7 +6897,7 void QCPAbstractPlottable::setAntialiase
6897 6897 */
6898 6898 void QCPAbstractPlottable::setAntialiasedErrorBars(bool enabled)
6899 6899 {
6900 mAntialiasedErrorBars = enabled;
6900 mAntialiasedErrorBars = enabled;
6901 6901 }
6902 6902
6903 6903
@@ -6912,7 +6912,7 void QCPAbstractPlottable::setAntialiase
6912 6912 */
6913 6913 void QCPAbstractPlottable::setPen(const QPen &pen)
6914 6914 {
6915 mPen = pen;
6915 mPen = pen;
6916 6916 }
6917 6917
6918 6918 /*!
@@ -6923,7 +6923,7 void QCPAbstractPlottable::setPen(const
6923 6923 */
6924 6924 void QCPAbstractPlottable::setSelectedPen(const QPen &pen)
6925 6925 {
6926 mSelectedPen = pen;
6926 mSelectedPen = pen;
6927 6927 }
6928 6928
6929 6929 /*!
@@ -6937,7 +6937,7 void QCPAbstractPlottable::setSelectedPe
6937 6937 */
6938 6938 void QCPAbstractPlottable::setBrush(const QBrush &brush)
6939 6939 {
6940 mBrush = brush;
6940 mBrush = brush;
6941 6941 }
6942 6942
6943 6943 /*!
@@ -6948,7 +6948,7 void QCPAbstractPlottable::setBrush(cons
6948 6948 */
6949 6949 void QCPAbstractPlottable::setSelectedBrush(const QBrush &brush)
6950 6950 {
6951 mSelectedBrush = brush;
6951 mSelectedBrush = brush;
6952 6952 }
6953 6953
6954 6954 /*!
@@ -6964,7 +6964,7 void QCPAbstractPlottable::setSelectedBr
6964 6964 */
6965 6965 void QCPAbstractPlottable::setKeyAxis(QCPAxis *axis)
6966 6966 {
6967 mKeyAxis = axis;
6967 mKeyAxis = axis;
6968 6968 }
6969 6969
6970 6970 /*!
@@ -6980,7 +6980,7 void QCPAbstractPlottable::setKeyAxis(QC
6980 6980 */
6981 6981 void QCPAbstractPlottable::setValueAxis(QCPAxis *axis)
6982 6982 {
6983 mValueAxis = axis;
6983 mValueAxis = axis;
6984 6984 }
6985 6985
6986 6986 /*!
@@ -6994,10 +6994,10 void QCPAbstractPlottable::setValueAxis(
6994 6994 */
6995 6995 void QCPAbstractPlottable::setSelectable(bool selectable)
6996 6996 {
6997 if (mSelectable != selectable)
6998 {
6999 mSelectable = selectable;
7000 emit selectableChanged(mSelectable);
6997 if (mSelectable != selectable)
6998 {
6999 mSelectable = selectable;
7000 emit selectableChanged(mSelectable);
7001 7001 }
7002 7002 }
7003 7003
@@ -7017,10 +7017,10 void QCPAbstractPlottable::setSelectable
7017 7017 */
7018 7018 void QCPAbstractPlottable::setSelected(bool selected)
7019 7019 {
7020 if (mSelected != selected)
7021 {
7022 mSelected = selected;
7023 emit selectionChanged(mSelected);
7020 if (mSelected != selected)
7021 {
7022 mSelected = selected;
7023 emit selectionChanged(mSelected);
7024 7024 }
7025 7025 }
7026 7026
@@ -7039,8 +7039,8 void QCPAbstractPlottable::setSelected(b
7039 7039 */
7040 7040 void QCPAbstractPlottable::rescaleAxes(bool onlyEnlarge) const
7041 7041 {
7042 rescaleKeyAxis(onlyEnlarge);
7043 rescaleValueAxis(onlyEnlarge);
7042 rescaleKeyAxis(onlyEnlarge);
7043 rescaleValueAxis(onlyEnlarge);
7044 7044 }
7045 7045
7046 7046 /*!
@@ -7050,33 +7050,33 void QCPAbstractPlottable::rescaleAxes(b
7050 7050 */
7051 7051 void QCPAbstractPlottable::rescaleKeyAxis(bool onlyEnlarge) const
7052 7052 {
7053 QCPAxis *keyAxis = mKeyAxis.data();
7054 if (!keyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
7055
7056 SignDomain signDomain = sdBoth;
7057 if (keyAxis->scaleType() == QCPAxis::stLogarithmic)
7058 signDomain = (keyAxis->range().upper < 0 ? sdNegative : sdPositive);
7059
7060 bool foundRange;
7061 QCPRange newRange = getKeyRange(foundRange, signDomain);
7062 if (foundRange)
7063 {
7064 if (onlyEnlarge)
7065 newRange.expand(keyAxis->range());
7066 if (!QCPRange::validRange(newRange)) // likely due to range being zero (plottable has only constant data in this axis dimension), shift current range to at least center the plottable
7067 {
7068 double center = (newRange.lower+newRange.upper)*0.5; // upper and lower should be equal anyway, but just to make sure, incase validRange returned false for other reason
7069 if (keyAxis->scaleType() == QCPAxis::stLinear)
7070 {
7071 newRange.lower = center-keyAxis->range().size()/2.0;
7072 newRange.upper = center+keyAxis->range().size()/2.0;
7053 QCPAxis *keyAxis = mKeyAxis.data();
7054 if (!keyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
7055
7056 SignDomain signDomain = sdBoth;
7057 if (keyAxis->scaleType() == QCPAxis::stLogarithmic)
7058 signDomain = (keyAxis->range().upper < 0 ? sdNegative : sdPositive);
7059
7060 bool foundRange;
7061 QCPRange newRange = getKeyRange(foundRange, signDomain);
7062 if (foundRange)
7063 {
7064 if (onlyEnlarge)
7065 newRange.expand(keyAxis->range());
7066 if (!QCPRange::validRange(newRange)) // likely due to range being zero (plottable has only constant data in this axis dimension), shift current range to at least center the plottable
7067 {
7068 double center = (newRange.lower+newRange.upper)*0.5; // upper and lower should be equal anyway, but just to make sure, incase validRange returned false for other reason
7069 if (keyAxis->scaleType() == QCPAxis::stLinear)
7070 {
7071 newRange.lower = center-keyAxis->range().size()/2.0;
7072 newRange.upper = center+keyAxis->range().size()/2.0;
7073 7073 } else // scaleType() == stLogarithmic
7074 7074 {
7075 newRange.lower = center/qSqrt(keyAxis->range().upper/keyAxis->range().lower);
7076 newRange.upper = center*qSqrt(keyAxis->range().upper/keyAxis->range().lower);
7077 }
7078 }
7079 keyAxis->setRange(newRange);
7075 newRange.lower = center/qSqrt(keyAxis->range().upper/keyAxis->range().lower);
7076 newRange.upper = center*qSqrt(keyAxis->range().upper/keyAxis->range().lower);
7077 }
7078 }
7079 keyAxis->setRange(newRange);
7080 7080 }
7081 7081 }
7082 7082
@@ -7090,33 +7090,33 void QCPAbstractPlottable::rescaleKeyAxi
7090 7090 */
7091 7091 void QCPAbstractPlottable::rescaleValueAxis(bool onlyEnlarge) const
7092 7092 {
7093 QCPAxis *valueAxis = mValueAxis.data();
7094 if (!valueAxis) { qDebug() << Q_FUNC_INFO << "invalid value axis"; return; }
7095
7096 SignDomain signDomain = sdBoth;
7097 if (valueAxis->scaleType() == QCPAxis::stLogarithmic)
7098 signDomain = (valueAxis->range().upper < 0 ? sdNegative : sdPositive);
7099
7100 bool foundRange;
7101 QCPRange newRange = getValueRange(foundRange, signDomain);
7102 if (foundRange)
7103 {
7104 if (onlyEnlarge)
7105 newRange.expand(valueAxis->range());
7106 if (!QCPRange::validRange(newRange)) // likely due to range being zero (plottable has only constant data in this axis dimension), shift current range to at least center the plottable
7107 {
7108 double center = (newRange.lower+newRange.upper)*0.5; // upper and lower should be equal anyway, but just to make sure, incase validRange returned false for other reason
7109 if (valueAxis->scaleType() == QCPAxis::stLinear)
7110 {
7111 newRange.lower = center-valueAxis->range().size()/2.0;
7112 newRange.upper = center+valueAxis->range().size()/2.0;
7093 QCPAxis *valueAxis = mValueAxis.data();
7094 if (!valueAxis) { qDebug() << Q_FUNC_INFO << "invalid value axis"; return; }
7095
7096 SignDomain signDomain = sdBoth;
7097 if (valueAxis->scaleType() == QCPAxis::stLogarithmic)
7098 signDomain = (valueAxis->range().upper < 0 ? sdNegative : sdPositive);
7099
7100 bool foundRange;
7101 QCPRange newRange = getValueRange(foundRange, signDomain);
7102 if (foundRange)
7103 {
7104 if (onlyEnlarge)
7105 newRange.expand(valueAxis->range());
7106 if (!QCPRange::validRange(newRange)) // likely due to range being zero (plottable has only constant data in this axis dimension), shift current range to at least center the plottable
7107 {
7108 double center = (newRange.lower+newRange.upper)*0.5; // upper and lower should be equal anyway, but just to make sure, incase validRange returned false for other reason
7109 if (valueAxis->scaleType() == QCPAxis::stLinear)
7110 {
7111 newRange.lower = center-valueAxis->range().size()/2.0;
7112 newRange.upper = center+valueAxis->range().size()/2.0;
7113 7113 } else // scaleType() == stLogarithmic
7114 7114 {
7115 newRange.lower = center/qSqrt(valueAxis->range().upper/valueAxis->range().lower);
7116 newRange.upper = center*qSqrt(valueAxis->range().upper/valueAxis->range().lower);
7117 }
7118 }
7119 valueAxis->setRange(newRange);
7115 newRange.lower = center/qSqrt(valueAxis->range().upper/valueAxis->range().lower);
7116 newRange.upper = center*qSqrt(valueAxis->range().upper/valueAxis->range().lower);
7117 }
7118 }
7119 valueAxis->setRange(newRange);
7120 7120 }
7121 7121 }
7122 7122
@@ -7134,15 +7134,15 void QCPAbstractPlottable::rescaleValueA
7134 7134 */
7135 7135 bool QCPAbstractPlottable::addToLegend()
7136 7136 {
7137 if (!mParentPlot || !mParentPlot->legend)
7138 return false;
7139
7140 if (!mParentPlot->legend->hasItemWithPlottable(this))
7141 {
7142 mParentPlot->legend->addItem(new QCPPlottableLegendItem(mParentPlot->legend, this));
7143 return true;
7144 } else
7145 return false;
7137 if (!mParentPlot || !mParentPlot->legend)
7138 return false;
7139
7140 if (!mParentPlot->legend->hasItemWithPlottable(this))
7141 {
7142 mParentPlot->legend->addItem(new QCPPlottableLegendItem(mParentPlot->legend, this));
7143 return true;
7144 } else
7145 return false;
7146 7146 }
7147 7147
7148 7148 /*!
@@ -7157,28 +7157,28 bool QCPAbstractPlottable::addToLegend()
7157 7157 */
7158 7158 bool QCPAbstractPlottable::removeFromLegend() const
7159 7159 {
7160 if (!mParentPlot->legend)
7161 return false;
7162
7163 if (QCPPlottableLegendItem *lip = mParentPlot->legend->itemWithPlottable(this))
7164 return mParentPlot->legend->removeItem(lip);
7165 else
7166 return false;
7160 if (!mParentPlot->legend)
7161 return false;
7162
7163 if (QCPPlottableLegendItem *lip = mParentPlot->legend->itemWithPlottable(this))
7164 return mParentPlot->legend->removeItem(lip);
7165 else
7166 return false;
7167 7167 }
7168 7168
7169 7169 /* inherits documentation from base class */
7170 7170 QRect QCPAbstractPlottable::clipRect() const
7171 7171 {
7172 if (mKeyAxis && mValueAxis)
7173 return mKeyAxis.data()->axisRect()->rect() & mValueAxis.data()->axisRect()->rect();
7174 else
7175 return QRect();
7172 if (mKeyAxis && mValueAxis)
7173 return mKeyAxis.data()->axisRect()->rect() & mValueAxis.data()->axisRect()->rect();
7174 else
7175 return QRect();
7176 7176 }
7177 7177
7178 7178 /* inherits documentation from base class */
7179 7179 QCP::Interaction QCPAbstractPlottable::selectionCategory() const
7180 7180 {
7181 return QCP::iSelectPlottables;
7181 return QCP::iSelectPlottables;
7182 7182 }
7183 7183
7184 7184 /*! \internal
@@ -7193,18 +7193,18 QCP::Interaction QCPAbstractPlottable::s
7193 7193 */
7194 7194 void QCPAbstractPlottable::coordsToPixels(double key, double value, double &x, double &y) const
7195 7195 {
7196 QCPAxis *keyAxis = mKeyAxis.data();
7197 QCPAxis *valueAxis = mValueAxis.data();
7198 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
7199
7200 if (keyAxis->orientation() == Qt::Horizontal)
7201 {
7202 x = keyAxis->coordToPixel(key);
7203 y = valueAxis->coordToPixel(value);
7204 } else
7205 {
7206 y = keyAxis->coordToPixel(key);
7207 x = valueAxis->coordToPixel(value);
7196 QCPAxis *keyAxis = mKeyAxis.data();
7197 QCPAxis *valueAxis = mValueAxis.data();
7198 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
7199
7200 if (keyAxis->orientation() == Qt::Horizontal)
7201 {
7202 x = keyAxis->coordToPixel(key);
7203 y = valueAxis->coordToPixel(value);
7204 } else
7205 {
7206 y = keyAxis->coordToPixel(key);
7207 x = valueAxis->coordToPixel(value);
7208 7208 }
7209 7209 }
7210 7210
@@ -7215,14 +7215,14 void QCPAbstractPlottable::coordsToPixel
7215 7215 */
7216 7216 const QPointF QCPAbstractPlottable::coordsToPixels(double key, double value) const
7217 7217 {
7218 QCPAxis *keyAxis = mKeyAxis.data();
7219 QCPAxis *valueAxis = mValueAxis.data();
7220 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return QPointF(); }
7221
7222 if (keyAxis->orientation() == Qt::Horizontal)
7223 return QPointF(keyAxis->coordToPixel(key), valueAxis->coordToPixel(value));
7224 else
7225 return QPointF(valueAxis->coordToPixel(value), keyAxis->coordToPixel(key));
7218 QCPAxis *keyAxis = mKeyAxis.data();
7219 QCPAxis *valueAxis = mValueAxis.data();
7220 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return QPointF(); }
7221
7222 if (keyAxis->orientation() == Qt::Horizontal)
7223 return QPointF(keyAxis->coordToPixel(key), valueAxis->coordToPixel(value));
7224 else
7225 return QPointF(valueAxis->coordToPixel(value), keyAxis->coordToPixel(key));
7226 7226 }
7227 7227
7228 7228 /*! \internal
@@ -7237,18 +7237,18 const QPointF QCPAbstractPlottable::coor
7237 7237 */
7238 7238 void QCPAbstractPlottable::pixelsToCoords(double x, double y, double &key, double &value) const
7239 7239 {
7240 QCPAxis *keyAxis = mKeyAxis.data();
7241 QCPAxis *valueAxis = mValueAxis.data();
7242 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
7243
7244 if (keyAxis->orientation() == Qt::Horizontal)
7245 {
7246 key = keyAxis->pixelToCoord(x);
7247 value = valueAxis->pixelToCoord(y);
7248 } else
7249 {
7250 key = keyAxis->pixelToCoord(y);
7251 value = valueAxis->pixelToCoord(x);
7240 QCPAxis *keyAxis = mKeyAxis.data();
7241 QCPAxis *valueAxis = mValueAxis.data();
7242 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
7243
7244 if (keyAxis->orientation() == Qt::Horizontal)
7245 {
7246 key = keyAxis->pixelToCoord(x);
7247 value = valueAxis->pixelToCoord(y);
7248 } else
7249 {
7250 key = keyAxis->pixelToCoord(y);
7251 value = valueAxis->pixelToCoord(x);
7252 7252 }
7253 7253 }
7254 7254
@@ -7259,7 +7259,7 void QCPAbstractPlottable::pixelsToCoord
7259 7259 */
7260 7260 void QCPAbstractPlottable::pixelsToCoords(const QPointF &pixelPos, double &key, double &value) const
7261 7261 {
7262 pixelsToCoords(pixelPos.x(), pixelPos.y(), key, value);
7262 pixelsToCoords(pixelPos.x(), pixelPos.y(), key, value);
7263 7263 }
7264 7264
7265 7265 /*! \internal
@@ -7269,7 +7269,7 void QCPAbstractPlottable::pixelsToCoord
7269 7269 */
7270 7270 QPen QCPAbstractPlottable::mainPen() const
7271 7271 {
7272 return mSelected ? mSelectedPen : mPen;
7272 return mSelected ? mSelectedPen : mPen;
7273 7273 }
7274 7274
7275 7275 /*! \internal
@@ -7279,7 +7279,7 QPen QCPAbstractPlottable::mainPen() con
7279 7279 */
7280 7280 QBrush QCPAbstractPlottable::mainBrush() const
7281 7281 {
7282 return mSelected ? mSelectedBrush : mBrush;
7282 return mSelected ? mSelectedBrush : mBrush;
7283 7283 }
7284 7284
7285 7285 /*! \internal
@@ -7297,7 +7297,7 QBrush QCPAbstractPlottable::mainBrush()
7297 7297 */
7298 7298 void QCPAbstractPlottable::applyDefaultAntialiasingHint(QCPPainter *painter) const
7299 7299 {
7300 applyAntialiasingHint(painter, mAntialiased, QCP::aePlottables);
7300 applyAntialiasingHint(painter, mAntialiased, QCP::aePlottables);
7301 7301 }
7302 7302
7303 7303 /*! \internal
@@ -7313,7 +7313,7 void QCPAbstractPlottable::applyDefaultA
7313 7313 */
7314 7314 void QCPAbstractPlottable::applyFillAntialiasingHint(QCPPainter *painter) const
7315 7315 {
7316 applyAntialiasingHint(painter, mAntialiasedFill, QCP::aeFills);
7316 applyAntialiasingHint(painter, mAntialiasedFill, QCP::aeFills);
7317 7317 }
7318 7318
7319 7319 /*! \internal
@@ -7329,7 +7329,7 void QCPAbstractPlottable::applyFillAnti
7329 7329 */
7330 7330 void QCPAbstractPlottable::applyScattersAntialiasingHint(QCPPainter *painter) const
7331 7331 {
7332 applyAntialiasingHint(painter, mAntialiasedScatters, QCP::aeScatters);
7332 applyAntialiasingHint(painter, mAntialiasedScatters, QCP::aeScatters);
7333 7333 }
7334 7334
7335 7335 /*! \internal
@@ -7345,7 +7345,7 void QCPAbstractPlottable::applyScatters
7345 7345 */
7346 7346 void QCPAbstractPlottable::applyErrorBarsAntialiasingHint(QCPPainter *painter) const
7347 7347 {
7348 applyAntialiasingHint(painter, mAntialiasedErrorBars, QCP::aeErrorBars);
7348 applyAntialiasingHint(painter, mAntialiasedErrorBars, QCP::aeErrorBars);
7349 7349 }
7350 7350
7351 7351 /*! \internal
@@ -7360,48 +7360,48 void QCPAbstractPlottable::applyErrorBar
7360 7360 */
7361 7361 double QCPAbstractPlottable::distSqrToLine(const QPointF &start, const QPointF &end, const QPointF &point) const
7362 7362 {
7363 QVector2D a(start);
7364 QVector2D b(end);
7365 QVector2D p(point);
7366 QVector2D v(b-a);
7367
7368 double vLengthSqr = v.lengthSquared();
7369 if (!qFuzzyIsNull(vLengthSqr))
7370 {
7371 double mu = QVector2D::dotProduct(p-a, v)/vLengthSqr;
7372 if (mu < 0)
7363 QVector2D a(start);
7364 QVector2D b(end);
7365 QVector2D p(point);
7366 QVector2D v(b-a);
7367
7368 double vLengthSqr = v.lengthSquared();
7369 if (!qFuzzyIsNull(vLengthSqr))
7370 {
7371 double mu = QVector2D::dotProduct(p-a, v)/vLengthSqr;
7372 if (mu < 0)
7373 return (a-p).lengthSquared();
7374 else if (mu > 1)
7375 return (b-p).lengthSquared();
7376 else
7377 return ((a + mu*v)-p).lengthSquared();
7378 } else
7373 7379 return (a-p).lengthSquared();
7374 else if (mu > 1)
7375 return (b-p).lengthSquared();
7376 else
7377 return ((a + mu*v)-p).lengthSquared();
7378 } else
7379 return (a-p).lengthSquared();
7380 7380 }
7381 7381
7382 7382 /* inherits documentation from base class */
7383 7383 void QCPAbstractPlottable::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged)
7384 7384 {
7385 Q_UNUSED(event)
7386 Q_UNUSED(details)
7387 if (mSelectable)
7388 {
7389 bool selBefore = mSelected;
7390 setSelected(additive ? !mSelected : true);
7391 if (selectionStateChanged)
7392 *selectionStateChanged = mSelected != selBefore;
7385 Q_UNUSED(event)
7386 Q_UNUSED(details)
7387 if (mSelectable)
7388 {
7389 bool selBefore = mSelected;
7390 setSelected(additive ? !mSelected : true);
7391 if (selectionStateChanged)
7392 *selectionStateChanged = mSelected != selBefore;
7393 7393 }
7394 7394 }
7395 7395
7396 7396 /* inherits documentation from base class */
7397 7397 void QCPAbstractPlottable::deselectEvent(bool *selectionStateChanged)
7398 7398 {
7399 if (mSelectable)
7400 {
7401 bool selBefore = mSelected;
7402 setSelected(false);
7403 if (selectionStateChanged)
7404 *selectionStateChanged = mSelected != selBefore;
7399 if (mSelectable)
7400 {
7401 bool selBefore = mSelected;
7402 setSelected(false);
7403 if (selectionStateChanged)
7404 *selectionStateChanged = mSelected != selBefore;
7405 7405 }
7406 7406 }
7407 7407
@@ -7451,25 +7451,25 void QCPAbstractPlottable::deselectEvent
7451 7451 explained in the subclassing section of the QCPAbstractItem documentation.
7452 7452 */
7453 7453 QCPItemAnchor::QCPItemAnchor(QCustomPlot *parentPlot, QCPAbstractItem *parentItem, const QString name, int anchorId) :
7454 mName(name),
7455 mParentPlot(parentPlot),
7456 mParentItem(parentItem),
7457 mAnchorId(anchorId)
7454 mName(name),
7455 mParentPlot(parentPlot),
7456 mParentItem(parentItem),
7457 mAnchorId(anchorId)
7458 7458 {
7459 7459 }
7460 7460
7461 7461 QCPItemAnchor::~QCPItemAnchor()
7462 7462 {
7463 // unregister as parent at children:
7464 foreach (QCPItemPosition *child, mChildrenX.toList())
7465 {
7466 if (child->parentAnchorX() == this)
7467 child->setParentAnchorX(0); // this acts back on this anchor and child removes itself from mChildrenX
7468 }
7469 foreach (QCPItemPosition *child, mChildrenY.toList())
7470 {
7471 if (child->parentAnchorY() == this)
7472 child->setParentAnchorY(0); // this acts back on this anchor and child removes itself from mChildrenY
7463 // unregister as parent at children:
7464 foreach (QCPItemPosition *child, mChildrenX.toList())
7465 {
7466 if (child->parentAnchorX() == this)
7467 child->setParentAnchorX(0); // this acts back on this anchor and child removes itself from mChildrenX
7468 }
7469 foreach (QCPItemPosition *child, mChildrenY.toList())
7470 {
7471 if (child->parentAnchorY() == this)
7472 child->setParentAnchorY(0); // this acts back on this anchor and child removes itself from mChildrenY
7473 7473 }
7474 7474 }
7475 7475
@@ -7481,20 +7481,20 QCPItemAnchor::~QCPItemAnchor()
7481 7481 */
7482 7482 QPointF QCPItemAnchor::pixelPoint() const
7483 7483 {
7484 if (mParentItem)
7485 {
7486 if (mAnchorId > -1)
7487 {
7488 return mParentItem->anchorPixelPoint(mAnchorId);
7484 if (mParentItem)
7485 {
7486 if (mAnchorId > -1)
7487 {
7488 return mParentItem->anchorPixelPoint(mAnchorId);
7489 7489 } else
7490 7490 {
7491 qDebug() << Q_FUNC_INFO << "no valid anchor id set:" << mAnchorId;
7492 return QPointF();
7493 }
7494 } else
7495 {
7496 qDebug() << Q_FUNC_INFO << "no parent item set";
7497 return QPointF();
7491 qDebug() << Q_FUNC_INFO << "no valid anchor id set:" << mAnchorId;
7492 return QPointF();
7493 }
7494 } else
7495 {
7496 qDebug() << Q_FUNC_INFO << "no parent item set";
7497 return QPointF();
7498 7498 }
7499 7499 }
7500 7500
@@ -7508,10 +7508,10 QPointF QCPItemAnchor::pixelPoint() cons
7508 7508 */
7509 7509 void QCPItemAnchor::addChildX(QCPItemPosition *pos)
7510 7510 {
7511 if (!mChildrenX.contains(pos))
7512 mChildrenX.insert(pos);
7513 else
7514 qDebug() << Q_FUNC_INFO << "provided pos is child already" << reinterpret_cast<quintptr>(pos);
7511 if (!mChildrenX.contains(pos))
7512 mChildrenX.insert(pos);
7513 else
7514 qDebug() << Q_FUNC_INFO << "provided pos is child already" << reinterpret_cast<quintptr>(pos);
7515 7515 }
7516 7516
7517 7517 /*! \internal
@@ -7522,8 +7522,8 void QCPItemAnchor::addChildX(QCPItemPos
7522 7522 */
7523 7523 void QCPItemAnchor::removeChildX(QCPItemPosition *pos)
7524 7524 {
7525 if (!mChildrenX.remove(pos))
7526 qDebug() << Q_FUNC_INFO << "provided pos isn't child" << reinterpret_cast<quintptr>(pos);
7525 if (!mChildrenX.remove(pos))
7526 qDebug() << Q_FUNC_INFO << "provided pos isn't child" << reinterpret_cast<quintptr>(pos);
7527 7527 }
7528 7528
7529 7529 /*! \internal
@@ -7536,10 +7536,10 void QCPItemAnchor::removeChildX(QCPItem
7536 7536 */
7537 7537 void QCPItemAnchor::addChildY(QCPItemPosition *pos)
7538 7538 {
7539 if (!mChildrenY.contains(pos))
7540 mChildrenY.insert(pos);
7541 else
7542 qDebug() << Q_FUNC_INFO << "provided pos is child already" << reinterpret_cast<quintptr>(pos);
7539 if (!mChildrenY.contains(pos))
7540 mChildrenY.insert(pos);
7541 else
7542 qDebug() << Q_FUNC_INFO << "provided pos is child already" << reinterpret_cast<quintptr>(pos);
7543 7543 }
7544 7544
7545 7545 /*! \internal
@@ -7550,8 +7550,8 void QCPItemAnchor::addChildY(QCPItemPos
7550 7550 */
7551 7551 void QCPItemAnchor::removeChildY(QCPItemPosition *pos)
7552 7552 {
7553 if (!mChildrenY.remove(pos))
7554 qDebug() << Q_FUNC_INFO << "provided pos isn't child" << reinterpret_cast<quintptr>(pos);
7553 if (!mChildrenY.remove(pos))
7554 qDebug() << Q_FUNC_INFO << "provided pos isn't child" << reinterpret_cast<quintptr>(pos);
7555 7555 }
7556 7556
7557 7557
@@ -7624,42 +7624,42 void QCPItemAnchor::removeChildY(QCPItem
7624 7624 explained in the subclassing section of the QCPAbstractItem documentation.
7625 7625 */
7626 7626 QCPItemPosition::QCPItemPosition(QCustomPlot *parentPlot, QCPAbstractItem *parentItem, const QString name) :
7627 QCPItemAnchor(parentPlot, parentItem, name),
7628 mPositionTypeX(ptAbsolute),
7629 mPositionTypeY(ptAbsolute),
7630 mKey(0),
7631 mValue(0),
7632 mParentAnchorX(0),
7633 mParentAnchorY(0)
7627 QCPItemAnchor(parentPlot, parentItem, name),
7628 mPositionTypeX(ptAbsolute),
7629 mPositionTypeY(ptAbsolute),
7630 mKey(0),
7631 mValue(0),
7632 mParentAnchorX(0),
7633 mParentAnchorY(0)
7634 7634 {
7635 7635 }
7636 7636
7637 7637 QCPItemPosition::~QCPItemPosition()
7638 7638 {
7639 // unregister as parent at children:
7640 // Note: this is done in ~QCPItemAnchor again, but it's important QCPItemPosition does it itself, because only then
7641 // the setParentAnchor(0) call the correct QCPItemPosition::pixelPoint function instead of QCPItemAnchor::pixelPoint
7642 foreach (QCPItemPosition *child, mChildrenX.toList())
7643 {
7644 if (child->parentAnchorX() == this)
7645 child->setParentAnchorX(0); // this acts back on this anchor and child removes itself from mChildrenX
7646 }
7647 foreach (QCPItemPosition *child, mChildrenY.toList())
7648 {
7649 if (child->parentAnchorY() == this)
7650 child->setParentAnchorY(0); // this acts back on this anchor and child removes itself from mChildrenY
7651 }
7652 // unregister as child in parent:
7653 if (mParentAnchorX)
7654 mParentAnchorX->removeChildX(this);
7655 if (mParentAnchorY)
7656 mParentAnchorY->removeChildY(this);
7639 // unregister as parent at children:
7640 // Note: this is done in ~QCPItemAnchor again, but it's important QCPItemPosition does it itself, because only then
7641 // the setParentAnchor(0) call the correct QCPItemPosition::pixelPoint function instead of QCPItemAnchor::pixelPoint
7642 foreach (QCPItemPosition *child, mChildrenX.toList())
7643 {
7644 if (child->parentAnchorX() == this)
7645 child->setParentAnchorX(0); // this acts back on this anchor and child removes itself from mChildrenX
7646 }
7647 foreach (QCPItemPosition *child, mChildrenY.toList())
7648 {
7649 if (child->parentAnchorY() == this)
7650 child->setParentAnchorY(0); // this acts back on this anchor and child removes itself from mChildrenY
7651 }
7652 // unregister as child in parent:
7653 if (mParentAnchorX)
7654 mParentAnchorX->removeChildX(this);
7655 if (mParentAnchorY)
7656 mParentAnchorY->removeChildY(this);
7657 7657 }
7658 7658
7659 7659 /* can't make this a header inline function, because QPointer breaks with forward declared types, see QTBUG-29588 */
7660 7660 QCPAxisRect *QCPItemPosition::axisRect() const
7661 7661 {
7662 return mAxisRect.data();
7662 return mAxisRect.data();
7663 7663 }
7664 7664
7665 7665 /*!
@@ -7689,8 +7689,8 QCPAxisRect *QCPItemPosition::axisRect()
7689 7689 */
7690 7690 void QCPItemPosition::setType(QCPItemPosition::PositionType type)
7691 7691 {
7692 setTypeX(type);
7693 setTypeY(type);
7692 setTypeX(type);
7693 setTypeY(type);
7694 7694 }
7695 7695
7696 7696 /*!
@@ -7702,24 +7702,24 void QCPItemPosition::setType(QCPItemPos
7702 7702 */
7703 7703 void QCPItemPosition::setTypeX(QCPItemPosition::PositionType type)
7704 7704 {
7705 if (mPositionTypeX != type)
7706 {
7707 // if switching from or to coordinate type that isn't valid (e.g. because axes or axis rect
7708 // were deleted), don't try to recover the pixelPoint() because it would output a qDebug warning.
7709 bool retainPixelPosition = true;
7710 if ((mPositionTypeX == ptPlotCoords || type == ptPlotCoords) && (!mKeyAxis || !mValueAxis))
7711 retainPixelPosition = false;
7712 if ((mPositionTypeX == ptAxisRectRatio || type == ptAxisRectRatio) && (!mAxisRect))
7713 retainPixelPosition = false;
7714
7715 QPointF pixel;
7716 if (retainPixelPosition)
7717 pixel = pixelPoint();
7718
7719 mPositionTypeX = type;
7720
7721 if (retainPixelPosition)
7722 setPixelPoint(pixel);
7705 if (mPositionTypeX != type)
7706 {
7707 // if switching from or to coordinate type that isn't valid (e.g. because axes or axis rect
7708 // were deleted), don't try to recover the pixelPoint() because it would output a qDebug warning.
7709 bool retainPixelPosition = true;
7710 if ((mPositionTypeX == ptPlotCoords || type == ptPlotCoords) && (!mKeyAxis || !mValueAxis))
7711 retainPixelPosition = false;
7712 if ((mPositionTypeX == ptAxisRectRatio || type == ptAxisRectRatio) && (!mAxisRect))
7713 retainPixelPosition = false;
7714
7715 QPointF pixel;
7716 if (retainPixelPosition)
7717 pixel = pixelPoint();
7718
7719 mPositionTypeX = type;
7720
7721 if (retainPixelPosition)
7722 setPixelPoint(pixel);
7723 7723 }
7724 7724 }
7725 7725
@@ -7732,24 +7732,24 void QCPItemPosition::setTypeX(QCPItemPo
7732 7732 */
7733 7733 void QCPItemPosition::setTypeY(QCPItemPosition::PositionType type)
7734 7734 {
7735 if (mPositionTypeY != type)
7736 {
7737 // if switching from or to coordinate type that isn't valid (e.g. because axes or axis rect
7738 // were deleted), don't try to recover the pixelPoint() because it would output a qDebug warning.
7739 bool retainPixelPosition = true;
7740 if ((mPositionTypeY == ptPlotCoords || type == ptPlotCoords) && (!mKeyAxis || !mValueAxis))
7741 retainPixelPosition = false;
7742 if ((mPositionTypeY == ptAxisRectRatio || type == ptAxisRectRatio) && (!mAxisRect))
7743 retainPixelPosition = false;
7744
7745 QPointF pixel;
7746 if (retainPixelPosition)
7747 pixel = pixelPoint();
7748
7749 mPositionTypeY = type;
7750
7751 if (retainPixelPosition)
7752 setPixelPoint(pixel);
7735 if (mPositionTypeY != type)
7736 {
7737 // if switching from or to coordinate type that isn't valid (e.g. because axes or axis rect
7738 // were deleted), don't try to recover the pixelPoint() because it would output a qDebug warning.
7739 bool retainPixelPosition = true;
7740 if ((mPositionTypeY == ptPlotCoords || type == ptPlotCoords) && (!mKeyAxis || !mValueAxis))
7741 retainPixelPosition = false;
7742 if ((mPositionTypeY == ptAxisRectRatio || type == ptAxisRectRatio) && (!mAxisRect))
7743 retainPixelPosition = false;
7744
7745 QPointF pixel;
7746 if (retainPixelPosition)
7747 pixel = pixelPoint();
7748
7749 mPositionTypeY = type;
7750
7751 if (retainPixelPosition)
7752 setPixelPoint(pixel);
7753 7753 }
7754 7754 }
7755 7755
@@ -7773,9 +7773,9 void QCPItemPosition::setTypeY(QCPItemPo
7773 7773 */
7774 7774 bool QCPItemPosition::setParentAnchor(QCPItemAnchor *parentAnchor, bool keepPixelPosition)
7775 7775 {
7776 bool successX = setParentAnchorX(parentAnchor, keepPixelPosition);
7777 bool successY = setParentAnchorY(parentAnchor, keepPixelPosition);
7778 return successX && successY;
7776 bool successX = setParentAnchorX(parentAnchor, keepPixelPosition);
7777 bool successY = setParentAnchorY(parentAnchor, keepPixelPosition);
7778 return successX && successY;
7779 7779 }
7780 7780
7781 7781 /*!
@@ -7787,60 +7787,60 bool QCPItemPosition::setParentAnchor(QC
7787 7787 */
7788 7788 bool QCPItemPosition::setParentAnchorX(QCPItemAnchor *parentAnchor, bool keepPixelPosition)
7789 7789 {
7790 // make sure self is not assigned as parent:
7791 if (parentAnchor == this)
7792 {
7793 qDebug() << Q_FUNC_INFO << "can't set self as parent anchor" << reinterpret_cast<quintptr>(parentAnchor);
7794 return false;
7795 }
7796 // make sure no recursive parent-child-relationships are created:
7797 QCPItemAnchor *currentParent = parentAnchor;
7798 while (currentParent)
7799 {
7800 if (QCPItemPosition *currentParentPos = currentParent->toQCPItemPosition())
7801 {
7802 // is a QCPItemPosition, might have further parent, so keep iterating
7803 if (currentParentPos == this)
7804 {
7805 qDebug() << Q_FUNC_INFO << "can't create recursive parent-child-relationship" << reinterpret_cast<quintptr>(parentAnchor);
7806 return false;
7807 }
7808 currentParent = currentParentPos->parentAnchorX();
7790 // make sure self is not assigned as parent:
7791 if (parentAnchor == this)
7792 {
7793 qDebug() << Q_FUNC_INFO << "can't set self as parent anchor" << reinterpret_cast<quintptr>(parentAnchor);
7794 return false;
7795 }
7796 // make sure no recursive parent-child-relationships are created:
7797 QCPItemAnchor *currentParent = parentAnchor;
7798 while (currentParent)
7799 {
7800 if (QCPItemPosition *currentParentPos = currentParent->toQCPItemPosition())
7801 {
7802 // is a QCPItemPosition, might have further parent, so keep iterating
7803 if (currentParentPos == this)
7804 {
7805 qDebug() << Q_FUNC_INFO << "can't create recursive parent-child-relationship" << reinterpret_cast<quintptr>(parentAnchor);
7806 return false;
7807 }
7808 currentParent = currentParentPos->parentAnchorX();
7809 7809 } else
7810 7810 {
7811 // is a QCPItemAnchor, can't have further parent. Now make sure the parent items aren't the
7812 // same, to prevent a position being child of an anchor which itself depends on the position,
7813 // because they're both on the same item:
7814 if (currentParent->mParentItem == mParentItem)
7815 {
7816 qDebug() << Q_FUNC_INFO << "can't set parent to be an anchor which itself depends on this position" << reinterpret_cast<quintptr>(parentAnchor);
7817 return false;
7818 }
7819 break;
7820 }
7821 }
7822
7823 // if previously no parent set and PosType is still ptPlotCoords, set to ptAbsolute:
7824 if (!mParentAnchorX && mPositionTypeX == ptPlotCoords)
7825 setTypeX(ptAbsolute);
7826
7827 // save pixel position:
7828 QPointF pixelP;
7829 if (keepPixelPosition)
7830 pixelP = pixelPoint();
7831 // unregister at current parent anchor:
7832 if (mParentAnchorX)
7833 mParentAnchorX->removeChildX(this);
7834 // register at new parent anchor:
7835 if (parentAnchor)
7836 parentAnchor->addChildX(this);
7837 mParentAnchorX = parentAnchor;
7838 // restore pixel position under new parent:
7839 if (keepPixelPosition)
7840 setPixelPoint(pixelP);
7841 else
7842 setCoords(0, coords().y());
7843 return true;
7811 // is a QCPItemAnchor, can't have further parent. Now make sure the parent items aren't the
7812 // same, to prevent a position being child of an anchor which itself depends on the position,
7813 // because they're both on the same item:
7814 if (currentParent->mParentItem == mParentItem)
7815 {
7816 qDebug() << Q_FUNC_INFO << "can't set parent to be an anchor which itself depends on this position" << reinterpret_cast<quintptr>(parentAnchor);
7817 return false;
7818 }
7819 break;
7820 }
7821 }
7822
7823 // if previously no parent set and PosType is still ptPlotCoords, set to ptAbsolute:
7824 if (!mParentAnchorX && mPositionTypeX == ptPlotCoords)
7825 setTypeX(ptAbsolute);
7826
7827 // save pixel position:
7828 QPointF pixelP;
7829 if (keepPixelPosition)
7830 pixelP = pixelPoint();
7831 // unregister at current parent anchor:
7832 if (mParentAnchorX)
7833 mParentAnchorX->removeChildX(this);
7834 // register at new parent anchor:
7835 if (parentAnchor)
7836 parentAnchor->addChildX(this);
7837 mParentAnchorX = parentAnchor;
7838 // restore pixel position under new parent:
7839 if (keepPixelPosition)
7840 setPixelPoint(pixelP);
7841 else
7842 setCoords(0, coords().y());
7843 return true;
7844 7844 }
7845 7845
7846 7846 /*!
@@ -7852,60 +7852,60 bool QCPItemPosition::setParentAnchorX(Q
7852 7852 */
7853 7853 bool QCPItemPosition::setParentAnchorY(QCPItemAnchor *parentAnchor, bool keepPixelPosition)
7854 7854 {
7855 // make sure self is not assigned as parent:
7856 if (parentAnchor == this)
7857 {
7858 qDebug() << Q_FUNC_INFO << "can't set self as parent anchor" << reinterpret_cast<quintptr>(parentAnchor);
7859 return false;
7860 }
7861 // make sure no recursive parent-child-relationships are created:
7862 QCPItemAnchor *currentParent = parentAnchor;
7863 while (currentParent)
7864 {
7865 if (QCPItemPosition *currentParentPos = currentParent->toQCPItemPosition())
7866 {
7867 // is a QCPItemPosition, might have further parent, so keep iterating
7868 if (currentParentPos == this)
7869 {
7870 qDebug() << Q_FUNC_INFO << "can't create recursive parent-child-relationship" << reinterpret_cast<quintptr>(parentAnchor);
7871 return false;
7872 }
7873 currentParent = currentParentPos->parentAnchorY();
7855 // make sure self is not assigned as parent:
7856 if (parentAnchor == this)
7857 {
7858 qDebug() << Q_FUNC_INFO << "can't set self as parent anchor" << reinterpret_cast<quintptr>(parentAnchor);
7859 return false;
7860 }
7861 // make sure no recursive parent-child-relationships are created:
7862 QCPItemAnchor *currentParent = parentAnchor;
7863 while (currentParent)
7864 {
7865 if (QCPItemPosition *currentParentPos = currentParent->toQCPItemPosition())
7866 {
7867 // is a QCPItemPosition, might have further parent, so keep iterating
7868 if (currentParentPos == this)
7869 {
7870 qDebug() << Q_FUNC_INFO << "can't create recursive parent-child-relationship" << reinterpret_cast<quintptr>(parentAnchor);
7871 return false;
7872 }
7873 currentParent = currentParentPos->parentAnchorY();
7874 7874 } else
7875 7875 {
7876 // is a QCPItemAnchor, can't have further parent. Now make sure the parent items aren't the
7877 // same, to prevent a position being child of an anchor which itself depends on the position,
7878 // because they're both on the same item:
7879 if (currentParent->mParentItem == mParentItem)
7880 {
7881 qDebug() << Q_FUNC_INFO << "can't set parent to be an anchor which itself depends on this position" << reinterpret_cast<quintptr>(parentAnchor);
7882 return false;
7883 }
7884 break;
7885 }
7886 }
7887
7888 // if previously no parent set and PosType is still ptPlotCoords, set to ptAbsolute:
7889 if (!mParentAnchorY && mPositionTypeY == ptPlotCoords)
7890 setTypeY(ptAbsolute);
7891
7892 // save pixel position:
7893 QPointF pixelP;
7894 if (keepPixelPosition)
7895 pixelP = pixelPoint();
7896 // unregister at current parent anchor:
7897 if (mParentAnchorY)
7898 mParentAnchorY->removeChildY(this);
7899 // register at new parent anchor:
7900 if (parentAnchor)
7901 parentAnchor->addChildY(this);
7902 mParentAnchorY = parentAnchor;
7903 // restore pixel position under new parent:
7904 if (keepPixelPosition)
7905 setPixelPoint(pixelP);
7906 else
7907 setCoords(coords().x(), 0);
7908 return true;
7876 // is a QCPItemAnchor, can't have further parent. Now make sure the parent items aren't the
7877 // same, to prevent a position being child of an anchor which itself depends on the position,
7878 // because they're both on the same item:
7879 if (currentParent->mParentItem == mParentItem)
7880 {
7881 qDebug() << Q_FUNC_INFO << "can't set parent to be an anchor which itself depends on this position" << reinterpret_cast<quintptr>(parentAnchor);
7882 return false;
7883 }
7884 break;
7885 }
7886 }
7887
7888 // if previously no parent set and PosType is still ptPlotCoords, set to ptAbsolute:
7889 if (!mParentAnchorY && mPositionTypeY == ptPlotCoords)
7890 setTypeY(ptAbsolute);
7891
7892 // save pixel position:
7893 QPointF pixelP;
7894 if (keepPixelPosition)
7895 pixelP = pixelPoint();
7896 // unregister at current parent anchor:
7897 if (mParentAnchorY)
7898 mParentAnchorY->removeChildY(this);
7899 // register at new parent anchor:
7900 if (parentAnchor)
7901 parentAnchor->addChildY(this);
7902 mParentAnchorY = parentAnchor;
7903 // restore pixel position under new parent:
7904 if (keepPixelPosition)
7905 setPixelPoint(pixelP);
7906 else
7907 setCoords(coords().x(), 0);
7908 return true;
7909 7909 }
7910 7910
7911 7911 /*!
@@ -7927,8 +7927,8 bool QCPItemPosition::setParentAnchorY(Q
7927 7927 */
7928 7928 void QCPItemPosition::setCoords(double key, double value)
7929 7929 {
7930 mKey = key;
7931 mValue = value;
7930 mKey = key;
7931 mValue = value;
7932 7932 }
7933 7933
7934 7934 /*! \overload
@@ -7938,7 +7938,7 void QCPItemPosition::setCoords(double k
7938 7938 */
7939 7939 void QCPItemPosition::setCoords(const QPointF &pos)
7940 7940 {
7941 setCoords(pos.x(), pos.y());
7941 setCoords(pos.x(), pos.y());
7942 7942 }
7943 7943
7944 7944 /*!
@@ -7949,97 +7949,97 void QCPItemPosition::setCoords(const QP
7949 7949 */
7950 7950 QPointF QCPItemPosition::pixelPoint() const
7951 7951 {
7952 QPointF result;
7953
7954 // determine X:
7955 switch (mPositionTypeX)
7952 QPointF result;
7953
7954 // determine X:
7955 switch (mPositionTypeX)
7956 7956 {
7957 7957 case ptAbsolute:
7958 {
7958 {
7959 7959 result.rx() = mKey;
7960 7960 if (mParentAnchorX)
7961 result.rx() += mParentAnchorX->pixelPoint().x();
7962 break;
7963 }
7961 result.rx() += mParentAnchorX->pixelPoint().x();
7962 break;
7963 }
7964 7964 case ptViewportRatio:
7965 {
7965 {
7966 7966 result.rx() = mKey*mParentPlot->viewport().width();
7967 7967 if (mParentAnchorX)
7968 result.rx() += mParentAnchorX->pixelPoint().x();
7968 result.rx() += mParentAnchorX->pixelPoint().x();
7969 7969 else
7970 result.rx() += mParentPlot->viewport().left();
7971 break;
7972 }
7970 result.rx() += mParentPlot->viewport().left();
7971 break;
7972 }
7973 7973 case ptAxisRectRatio:
7974 {
7974 {
7975 7975 if (mAxisRect)
7976 {
7976 {
7977 7977 result.rx() = mKey*mAxisRect.data()->width();
7978 7978 if (mParentAnchorX)
7979 result.rx() += mParentAnchorX->pixelPoint().x();
7979 result.rx() += mParentAnchorX->pixelPoint().x();
7980 7980 else
7981 result.rx() += mAxisRect.data()->left();
7982 } else
7983 qDebug() << Q_FUNC_INFO << "Item position type x is ptAxisRectRatio, but no axis rect was defined";
7984 break;
7985 }
7981 result.rx() += mAxisRect.data()->left();
7982 } else
7983 qDebug() << Q_FUNC_INFO << "Item position type x is ptAxisRectRatio, but no axis rect was defined";
7984 break;
7985 }
7986 7986 case ptPlotCoords:
7987 {
7987 {
7988 7988 if (mKeyAxis && mKeyAxis.data()->orientation() == Qt::Horizontal)
7989 result.rx() = mKeyAxis.data()->coordToPixel(mKey);
7989 result.rx() = mKeyAxis.data()->coordToPixel(mKey);
7990 7990 else if (mValueAxis && mValueAxis.data()->orientation() == Qt::Horizontal)
7991 result.rx() = mValueAxis.data()->coordToPixel(mValue);
7991 result.rx() = mValueAxis.data()->coordToPixel(mValue);
7992 7992 else
7993 qDebug() << Q_FUNC_INFO << "Item position type x is ptPlotCoords, but no axes were defined";
7994 break;
7995 }
7996 }
7997
7998 // determine Y:
7999 switch (mPositionTypeY)
7993 qDebug() << Q_FUNC_INFO << "Item position type x is ptPlotCoords, but no axes were defined";
7994 break;
7995 }
7996 }
7997
7998 // determine Y:
7999 switch (mPositionTypeY)
8000 8000 {
8001 8001 case ptAbsolute:
8002 {
8002 {
8003 8003 result.ry() = mValue;
8004 8004 if (mParentAnchorY)
8005 result.ry() += mParentAnchorY->pixelPoint().y();
8006 break;
8007 }
8005 result.ry() += mParentAnchorY->pixelPoint().y();
8006 break;
8007 }
8008 8008 case ptViewportRatio:
8009 {
8009 {
8010 8010 result.ry() = mValue*mParentPlot->viewport().height();
8011 8011 if (mParentAnchorY)
8012 result.ry() += mParentAnchorY->pixelPoint().y();
8012 result.ry() += mParentAnchorY->pixelPoint().y();
8013 8013 else
8014 result.ry() += mParentPlot->viewport().top();
8015 break;
8016 }
8014 result.ry() += mParentPlot->viewport().top();
8015 break;
8016 }
8017 8017 case ptAxisRectRatio:
8018 {
8018 {
8019 8019 if (mAxisRect)
8020 {
8020 {
8021 8021 result.ry() = mValue*mAxisRect.data()->height();
8022 8022 if (mParentAnchorY)
8023 result.ry() += mParentAnchorY->pixelPoint().y();
8023 result.ry() += mParentAnchorY->pixelPoint().y();
8024 8024 else
8025 result.ry() += mAxisRect.data()->top();
8026 } else
8027 qDebug() << Q_FUNC_INFO << "Item position type y is ptAxisRectRatio, but no axis rect was defined";
8028 break;
8029 }
8025 result.ry() += mAxisRect.data()->top();
8026 } else
8027 qDebug() << Q_FUNC_INFO << "Item position type y is ptAxisRectRatio, but no axis rect was defined";
8028 break;
8029 }
8030 8030 case ptPlotCoords:
8031 {
8031 {
8032 8032 if (mKeyAxis && mKeyAxis.data()->orientation() == Qt::Vertical)
8033 result.ry() = mKeyAxis.data()->coordToPixel(mKey);
8033 result.ry() = mKeyAxis.data()->coordToPixel(mKey);
8034 8034 else if (mValueAxis && mValueAxis.data()->orientation() == Qt::Vertical)
8035 result.ry() = mValueAxis.data()->coordToPixel(mValue);
8035 result.ry() = mValueAxis.data()->coordToPixel(mValue);
8036 8036 else
8037 qDebug() << Q_FUNC_INFO << "Item position type y is ptPlotCoords, but no axes were defined";
8038 break;
8039 }
8040 }
8041
8042 return result;
8037 qDebug() << Q_FUNC_INFO << "Item position type y is ptPlotCoords, but no axes were defined";
8038 break;
8039 }
8040 }
8041
8042 return result;
8043 8043 }
8044 8044
8045 8045 /*!
@@ -8049,8 +8049,8 QPointF QCPItemPosition::pixelPoint() co
8049 8049 */
8050 8050 void QCPItemPosition::setAxes(QCPAxis *keyAxis, QCPAxis *valueAxis)
8051 8051 {
8052 mKeyAxis = keyAxis;
8053 mValueAxis = valueAxis;
8052 mKeyAxis = keyAxis;
8053 mValueAxis = valueAxis;
8054 8054 }
8055 8055
8056 8056 /*!
@@ -8060,7 +8060,7 void QCPItemPosition::setAxes(QCPAxis *k
8060 8060 */
8061 8061 void QCPItemPosition::setAxisRect(QCPAxisRect *axisRect)
8062 8062 {
8063 mAxisRect = axisRect;
8063 mAxisRect = axisRect;
8064 8064 }
8065 8065
8066 8066 /*!
@@ -8075,94 +8075,94 void QCPItemPosition::setAxisRect(QCPAxi
8075 8075 */
8076 8076 void QCPItemPosition::setPixelPoint(const QPointF &pixelPoint)
8077 8077 {
8078 double x = pixelPoint.x();
8079 double y = pixelPoint.y();
8080
8081 switch (mPositionTypeX)
8078 double x = pixelPoint.x();
8079 double y = pixelPoint.y();
8080
8081 switch (mPositionTypeX)
8082 8082 {
8083 8083 case ptAbsolute:
8084 {
8084 {
8085 8085 if (mParentAnchorX)
8086 x -= mParentAnchorX->pixelPoint().x();
8087 break;
8088 }
8086 x -= mParentAnchorX->pixelPoint().x();
8087 break;
8088 }
8089 8089 case ptViewportRatio:
8090 {
8090 {
8091 8091 if (mParentAnchorX)
8092 x -= mParentAnchorX->pixelPoint().x();
8092 x -= mParentAnchorX->pixelPoint().x();
8093 8093 else
8094 x -= mParentPlot->viewport().left();
8094 x -= mParentPlot->viewport().left();
8095 8095 x /= (double)mParentPlot->viewport().width();
8096 8096 break;
8097 }
8097 }
8098 8098 case ptAxisRectRatio:
8099 {
8099 {
8100 8100 if (mAxisRect)
8101 {
8101 {
8102 8102 if (mParentAnchorX)
8103 x -= mParentAnchorX->pixelPoint().x();
8103 x -= mParentAnchorX->pixelPoint().x();
8104 8104 else
8105 x -= mAxisRect.data()->left();
8105 x -= mAxisRect.data()->left();
8106 8106 x /= (double)mAxisRect.data()->width();
8107 } else
8108 qDebug() << Q_FUNC_INFO << "Item position type x is ptAxisRectRatio, but no axis rect was defined";
8109 break;
8110 }
8107 } else
8108 qDebug() << Q_FUNC_INFO << "Item position type x is ptAxisRectRatio, but no axis rect was defined";
8109 break;
8110 }
8111 8111 case ptPlotCoords:
8112 {
8112 {
8113 8113 if (mKeyAxis && mKeyAxis.data()->orientation() == Qt::Horizontal)
8114 x = mKeyAxis.data()->pixelToCoord(x);
8114 x = mKeyAxis.data()->pixelToCoord(x);
8115 8115 else if (mValueAxis && mValueAxis.data()->orientation() == Qt::Horizontal)
8116 y = mValueAxis.data()->pixelToCoord(x);
8116 y = mValueAxis.data()->pixelToCoord(x);
8117 8117 else
8118 qDebug() << Q_FUNC_INFO << "Item position type x is ptPlotCoords, but no axes were defined";
8119 break;
8120 }
8121 }
8122
8123 switch (mPositionTypeY)
8118 qDebug() << Q_FUNC_INFO << "Item position type x is ptPlotCoords, but no axes were defined";
8119 break;
8120 }
8121 }
8122
8123 switch (mPositionTypeY)
8124 8124 {
8125 8125 case ptAbsolute:
8126 {
8126 {
8127 8127 if (mParentAnchorY)
8128 y -= mParentAnchorY->pixelPoint().y();
8129 break;
8130 }
8128 y -= mParentAnchorY->pixelPoint().y();
8129 break;
8130 }
8131 8131 case ptViewportRatio:
8132 {
8132 {
8133 8133 if (mParentAnchorY)
8134 y -= mParentAnchorY->pixelPoint().y();
8134 y -= mParentAnchorY->pixelPoint().y();
8135 8135 else
8136 y -= mParentPlot->viewport().top();
8136 y -= mParentPlot->viewport().top();
8137 8137 y /= (double)mParentPlot->viewport().height();
8138 8138 break;
8139 }
8139 }
8140 8140 case ptAxisRectRatio:
8141 {
8141 {
8142 8142 if (mAxisRect)
8143 {
8143 {
8144 8144 if (mParentAnchorY)
8145 y -= mParentAnchorY->pixelPoint().y();
8145 y -= mParentAnchorY->pixelPoint().y();
8146 8146 else
8147 y -= mAxisRect.data()->top();
8147 y -= mAxisRect.data()->top();
8148 8148 y /= (double)mAxisRect.data()->height();
8149 } else
8150 qDebug() << Q_FUNC_INFO << "Item position type y is ptAxisRectRatio, but no axis rect was defined";
8151 break;
8152 }
8149 } else
8150 qDebug() << Q_FUNC_INFO << "Item position type y is ptAxisRectRatio, but no axis rect was defined";
8151 break;
8152 }
8153 8153 case ptPlotCoords:
8154 {
8154 {
8155 8155 if (mKeyAxis && mKeyAxis.data()->orientation() == Qt::Vertical)
8156 x = mKeyAxis.data()->pixelToCoord(y);
8156 x = mKeyAxis.data()->pixelToCoord(y);
8157 8157 else if (mValueAxis && mValueAxis.data()->orientation() == Qt::Vertical)
8158 y = mValueAxis.data()->pixelToCoord(y);
8158 y = mValueAxis.data()->pixelToCoord(y);
8159 8159 else
8160 qDebug() << Q_FUNC_INFO << "Item position type y is ptPlotCoords, but no axes were defined";
8161 break;
8162 }
8163 }
8164
8165 setCoords(x, y);
8160 qDebug() << Q_FUNC_INFO << "Item position type y is ptPlotCoords, but no axes were defined";
8161 break;
8162 }
8163 }
8164
8165 setCoords(x, y);
8166 8166 }
8167 8167
8168 8168
@@ -8353,29 +8353,29 void QCPItemPosition::setPixelPoint(cons
8353 8353 Base class constructor which initializes base class members.
8354 8354 */
8355 8355 QCPAbstractItem::QCPAbstractItem(QCustomPlot *parentPlot) :
8356 QCPLayerable(parentPlot),
8357 mClipToAxisRect(false),
8358 mSelectable(true),
8359 mSelected(false)
8360 {
8361 QList<QCPAxisRect*> rects = parentPlot->axisRects();
8362 if (rects.size() > 0)
8363 {
8364 setClipToAxisRect(true);
8365 setClipAxisRect(rects.first());
8356 QCPLayerable(parentPlot),
8357 mClipToAxisRect(false),
8358 mSelectable(true),
8359 mSelected(false)
8360 {
8361 QList<QCPAxisRect*> rects = parentPlot->axisRects();
8362 if (rects.size() > 0)
8363 {
8364 setClipToAxisRect(true);
8365 setClipAxisRect(rects.first());
8366 8366 }
8367 8367 }
8368 8368
8369 8369 QCPAbstractItem::~QCPAbstractItem()
8370 8370 {
8371 // don't delete mPositions because every position is also an anchor and thus in mAnchors
8372 qDeleteAll(mAnchors);
8371 // don't delete mPositions because every position is also an anchor and thus in mAnchors
8372 qDeleteAll(mAnchors);
8373 8373 }
8374 8374
8375 8375 /* can't make this a header inline function, because QPointer breaks with forward declared types, see QTBUG-29588 */
8376 8376 QCPAxisRect *QCPAbstractItem::clipAxisRect() const
8377 8377 {
8378 return mClipAxisRect.data();
8378 return mClipAxisRect.data();
8379 8379 }
8380 8380
8381 8381 /*!
@@ -8386,9 +8386,9 QCPAxisRect *QCPAbstractItem::clipAxisRe
8386 8386 */
8387 8387 void QCPAbstractItem::setClipToAxisRect(bool clip)
8388 8388 {
8389 mClipToAxisRect = clip;
8390 if (mClipToAxisRect)
8391 setParentLayerable(mClipAxisRect.data());
8389 mClipToAxisRect = clip;
8390 if (mClipToAxisRect)
8391 setParentLayerable(mClipAxisRect.data());
8392 8392 }
8393 8393
8394 8394 /*!
@@ -8399,9 +8399,9 void QCPAbstractItem::setClipToAxisRect(
8399 8399 */
8400 8400 void QCPAbstractItem::setClipAxisRect(QCPAxisRect *rect)
8401 8401 {
8402 mClipAxisRect = rect;
8403 if (mClipToAxisRect)
8404 setParentLayerable(mClipAxisRect.data());
8402 mClipAxisRect = rect;
8403 if (mClipToAxisRect)
8404 setParentLayerable(mClipAxisRect.data());
8405 8405 }
8406 8406
8407 8407 /*!
@@ -8415,10 +8415,10 void QCPAbstractItem::setClipAxisRect(QC
8415 8415 */
8416 8416 void QCPAbstractItem::setSelectable(bool selectable)
8417 8417 {
8418 if (mSelectable != selectable)
8419 {
8420 mSelectable = selectable;
8421 emit selectableChanged(mSelectable);
8418 if (mSelectable != selectable)
8419 {
8420 mSelectable = selectable;
8421 emit selectableChanged(mSelectable);
8422 8422 }
8423 8423 }
8424 8424
@@ -8438,10 +8438,10 void QCPAbstractItem::setSelectable(bool
8438 8438 */
8439 8439 void QCPAbstractItem::setSelected(bool selected)
8440 8440 {
8441 if (mSelected != selected)
8442 {
8443 mSelected = selected;
8444 emit selectionChanged(mSelected);
8441 if (mSelected != selected)
8442 {
8443 mSelected = selected;
8444 emit selectionChanged(mSelected);
8445 8445 }
8446 8446 }
8447 8447
@@ -8457,13 +8457,13 void QCPAbstractItem::setSelected(bool s
8457 8457 */
8458 8458 QCPItemPosition *QCPAbstractItem::position(const QString &name) const
8459 8459 {
8460 for (int i=0; i<mPositions.size(); ++i)
8461 {
8462 if (mPositions.at(i)->name() == name)
8463 return mPositions.at(i);
8464 }
8465 qDebug() << Q_FUNC_INFO << "position with name not found:" << name;
8466 return 0;
8460 for (int i=0; i<mPositions.size(); ++i)
8461 {
8462 if (mPositions.at(i)->name() == name)
8463 return mPositions.at(i);
8464 }
8465 qDebug() << Q_FUNC_INFO << "position with name not found:" << name;
8466 return 0;
8467 8467 }
8468 8468
8469 8469 /*!
@@ -8478,13 +8478,13 QCPItemPosition *QCPAbstractItem::positi
8478 8478 */
8479 8479 QCPItemAnchor *QCPAbstractItem::anchor(const QString &name) const
8480 8480 {
8481 for (int i=0; i<mAnchors.size(); ++i)
8482 {
8483 if (mAnchors.at(i)->name() == name)
8484 return mAnchors.at(i);
8485 }
8486 qDebug() << Q_FUNC_INFO << "anchor with name not found:" << name;
8487 return 0;
8481 for (int i=0; i<mAnchors.size(); ++i)
8482 {
8483 if (mAnchors.at(i)->name() == name)
8484 return mAnchors.at(i);
8485 }
8486 qDebug() << Q_FUNC_INFO << "anchor with name not found:" << name;
8487 return 0;
8488 8488 }
8489 8489
8490 8490 /*!
@@ -8497,12 +8497,12 QCPItemAnchor *QCPAbstractItem::anchor(c
8497 8497 */
8498 8498 bool QCPAbstractItem::hasAnchor(const QString &name) const
8499 8499 {
8500 for (int i=0; i<mAnchors.size(); ++i)
8501 {
8502 if (mAnchors.at(i)->name() == name)
8503 return true;
8504 }
8505 return false;
8500 for (int i=0; i<mAnchors.size(); ++i)
8501 {
8502 if (mAnchors.at(i)->name() == name)
8503 return true;
8504 }
8505 return false;
8506 8506 }
8507 8507
8508 8508 /*! \internal
@@ -8516,10 +8516,10 bool QCPAbstractItem::hasAnchor(const QS
8516 8516 */
8517 8517 QRect QCPAbstractItem::clipRect() const
8518 8518 {
8519 if (mClipToAxisRect && mClipAxisRect)
8520 return mClipAxisRect.data()->rect();
8521 else
8522 return mParentPlot->viewport();
8519 if (mClipToAxisRect && mClipAxisRect)
8520 return mClipAxisRect.data()->rect();
8521 else
8522 return mParentPlot->viewport();
8523 8523 }
8524 8524
8525 8525 /*! \internal
@@ -8537,7 +8537,7 QRect QCPAbstractItem::clipRect() const
8537 8537 */
8538 8538 void QCPAbstractItem::applyDefaultAntialiasingHint(QCPPainter *painter) const
8539 8539 {
8540 applyAntialiasingHint(painter, mAntialiased, QCP::aeItems);
8540 applyAntialiasingHint(painter, mAntialiased, QCP::aeItems);
8541 8541 }
8542 8542
8543 8543 /*! \internal
@@ -8554,23 +8554,23 void QCPAbstractItem::applyDefaultAntial
8554 8554 */
8555 8555 double QCPAbstractItem::distSqrToLine(const QPointF &start, const QPointF &end, const QPointF &point) const
8556 8556 {
8557 QVector2D a(start);
8558 QVector2D b(end);
8559 QVector2D p(point);
8560 QVector2D v(b-a);
8561
8562 double vLengthSqr = v.lengthSquared();
8563 if (!qFuzzyIsNull(vLengthSqr))
8564 {
8565 double mu = QVector2D::dotProduct(p-a, v)/vLengthSqr;
8566 if (mu < 0)
8557 QVector2D a(start);
8558 QVector2D b(end);
8559 QVector2D p(point);
8560 QVector2D v(b-a);
8561
8562 double vLengthSqr = v.lengthSquared();
8563 if (!qFuzzyIsNull(vLengthSqr))
8564 {
8565 double mu = QVector2D::dotProduct(p-a, v)/vLengthSqr;
8566 if (mu < 0)
8567 return (a-p).lengthSquared();
8568 else if (mu > 1)
8569 return (b-p).lengthSquared();
8570 else
8571 return ((a + mu*v)-p).lengthSquared();
8572 } else
8567 8573 return (a-p).lengthSquared();
8568 else if (mu > 1)
8569 return (b-p).lengthSquared();
8570 else
8571 return ((a + mu*v)-p).lengthSquared();
8572 } else
8573 return (a-p).lengthSquared();
8574 8574 }
8575 8575
8576 8576 /*! \internal
@@ -8592,28 +8592,28 double QCPAbstractItem::distSqrToLine(co
8592 8592 */
8593 8593 double QCPAbstractItem::rectSelectTest(const QRectF &rect, const QPointF &pos, bool filledRect) const
8594 8594 {
8595 double result = -1;
8596
8597 // distance to border:
8598 QList<QLineF> lines;
8599 lines << QLineF(rect.topLeft(), rect.topRight()) << QLineF(rect.bottomLeft(), rect.bottomRight())
8600 << QLineF(rect.topLeft(), rect.bottomLeft()) << QLineF(rect.topRight(), rect.bottomRight());
8601 double minDistSqr = std::numeric_limits<double>::max();
8602 for (int i=0; i<lines.size(); ++i)
8603 {
8604 double distSqr = distSqrToLine(lines.at(i).p1(), lines.at(i).p2(), pos);
8605 if (distSqr < minDistSqr)
8606 minDistSqr = distSqr;
8607 }
8608 result = qSqrt(minDistSqr);
8609
8610 // filled rect, allow click inside to count as hit:
8611 if (filledRect && result > mParentPlot->selectionTolerance()*0.99)
8612 {
8613 if (rect.contains(pos))
8614 result = mParentPlot->selectionTolerance()*0.99;
8615 }
8616 return result;
8595 double result = -1;
8596
8597 // distance to border:
8598 QList<QLineF> lines;
8599 lines << QLineF(rect.topLeft(), rect.topRight()) << QLineF(rect.bottomLeft(), rect.bottomRight())
8600 << QLineF(rect.topLeft(), rect.bottomLeft()) << QLineF(rect.topRight(), rect.bottomRight());
8601 double minDistSqr = std::numeric_limits<double>::max();
8602 for (int i=0; i<lines.size(); ++i)
8603 {
8604 double distSqr = distSqrToLine(lines.at(i).p1(), lines.at(i).p2(), pos);
8605 if (distSqr < minDistSqr)
8606 minDistSqr = distSqr;
8607 }
8608 result = qSqrt(minDistSqr);
8609
8610 // filled rect, allow click inside to count as hit:
8611 if (filledRect && result > mParentPlot->selectionTolerance()*0.99)
8612 {
8613 if (rect.contains(pos))
8614 result = mParentPlot->selectionTolerance()*0.99;
8615 }
8616 return result;
8617 8617 }
8618 8618
8619 8619 /*! \internal
@@ -8628,8 +8628,8 double QCPAbstractItem::rectSelectTest(c
8628 8628 */
8629 8629 QPointF QCPAbstractItem::anchorPixelPoint(int anchorId) const
8630 8630 {
8631 qDebug() << Q_FUNC_INFO << "called on item which shouldn't have any anchors (this method not reimplemented). anchorId" << anchorId;
8632 return QPointF();
8631 qDebug() << Q_FUNC_INFO << "called on item which shouldn't have any anchors (this method not reimplemented). anchorId" << anchorId;
8632 return QPointF();
8633 8633 }
8634 8634
8635 8635 /*! \internal
@@ -8648,17 +8648,17 QPointF QCPAbstractItem::anchorPixelPoin
8648 8648 */
8649 8649 QCPItemPosition *QCPAbstractItem::createPosition(const QString &name)
8650 8650 {
8651 if (hasAnchor(name))
8652 qDebug() << Q_FUNC_INFO << "anchor/position with name exists already:" << name;
8653 QCPItemPosition *newPosition = new QCPItemPosition(mParentPlot, this, name);
8654 mPositions.append(newPosition);
8655 mAnchors.append(newPosition); // every position is also an anchor
8656 newPosition->setAxes(mParentPlot->xAxis, mParentPlot->yAxis);
8657 newPosition->setType(QCPItemPosition::ptPlotCoords);
8658 if (mParentPlot->axisRect())
8659 newPosition->setAxisRect(mParentPlot->axisRect());
8660 newPosition->setCoords(0, 0);
8661 return newPosition;
8651 if (hasAnchor(name))
8652 qDebug() << Q_FUNC_INFO << "anchor/position with name exists already:" << name;
8653 QCPItemPosition *newPosition = new QCPItemPosition(mParentPlot, this, name);
8654 mPositions.append(newPosition);
8655 mAnchors.append(newPosition); // every position is also an anchor
8656 newPosition->setAxes(mParentPlot->xAxis, mParentPlot->yAxis);
8657 newPosition->setType(QCPItemPosition::ptPlotCoords);
8658 if (mParentPlot->axisRect())
8659 newPosition->setAxisRect(mParentPlot->axisRect());
8660 newPosition->setCoords(0, 0);
8661 return newPosition;
8662 8662 }
8663 8663
8664 8664 /*! \internal
@@ -8682,43 +8682,43 QCPItemPosition *QCPAbstractItem::create
8682 8682 */
8683 8683 QCPItemAnchor *QCPAbstractItem::createAnchor(const QString &name, int anchorId)
8684 8684 {
8685 if (hasAnchor(name))
8686 qDebug() << Q_FUNC_INFO << "anchor/position with name exists already:" << name;
8687 QCPItemAnchor *newAnchor = new QCPItemAnchor(mParentPlot, this, name, anchorId);
8688 mAnchors.append(newAnchor);
8689 return newAnchor;
8685 if (hasAnchor(name))
8686 qDebug() << Q_FUNC_INFO << "anchor/position with name exists already:" << name;
8687 QCPItemAnchor *newAnchor = new QCPItemAnchor(mParentPlot, this, name, anchorId);
8688 mAnchors.append(newAnchor);
8689 return newAnchor;
8690 8690 }
8691 8691
8692 8692 /* inherits documentation from base class */
8693 8693 void QCPAbstractItem::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged)
8694 8694 {
8695 Q_UNUSED(event)
8696 Q_UNUSED(details)
8697 if (mSelectable)
8698 {
8699 bool selBefore = mSelected;
8700 setSelected(additive ? !mSelected : true);
8701 if (selectionStateChanged)
8702 *selectionStateChanged = mSelected != selBefore;
8695 Q_UNUSED(event)
8696 Q_UNUSED(details)
8697 if (mSelectable)
8698 {
8699 bool selBefore = mSelected;
8700 setSelected(additive ? !mSelected : true);
8701 if (selectionStateChanged)
8702 *selectionStateChanged = mSelected != selBefore;
8703 8703 }
8704 8704 }
8705 8705
8706 8706 /* inherits documentation from base class */
8707 8707 void QCPAbstractItem::deselectEvent(bool *selectionStateChanged)
8708 8708 {
8709 if (mSelectable)
8710 {
8711 bool selBefore = mSelected;
8712 setSelected(false);
8713 if (selectionStateChanged)
8714 *selectionStateChanged = mSelected != selBefore;
8709 if (mSelectable)
8710 {
8711 bool selBefore = mSelected;
8712 setSelected(false);
8713 if (selectionStateChanged)
8714 *selectionStateChanged = mSelected != selBefore;
8715 8715 }
8716 8716 }
8717 8717
8718 8718 /* inherits documentation from base class */
8719 8719 QCP::Interaction QCPAbstractItem::selectionCategory() const
8720 8720 {
8721 return QCP::iSelectItems;
8721 return QCP::iSelectItems;
8722 8722 }
8723 8723
8724 8724
@@ -9032,91 +9032,91 QCP::Interaction QCPAbstractItem::select
9032 9032 Constructs a QCustomPlot and sets reasonable default values.
9033 9033 */
9034 9034 QCustomPlot::QCustomPlot(QWidget *parent) :
9035 QWidget(parent),
9036 xAxis(0),
9037 yAxis(0),
9038 xAxis2(0),
9039 yAxis2(0),
9040 legend(0),
9041 mPlotLayout(0),
9042 mAutoAddPlottableToLegend(true),
9043 mAntialiasedElements(QCP::aeNone),
9044 mNotAntialiasedElements(QCP::aeNone),
9045 mInteractions(0),
9046 mSelectionTolerance(8),
9047 mNoAntialiasingOnDrag(false),
9048 mBackgroundBrush(Qt::white, Qt::SolidPattern),
9049 mBackgroundScaled(true),
9050 mBackgroundScaledMode(Qt::KeepAspectRatioByExpanding),
9051 mCurrentLayer(0),
9052 mPlottingHints(QCP::phCacheLabels|QCP::phForceRepaint),
9053 mMultiSelectModifier(Qt::ControlModifier),
9054 mPaintBuffer(size()),
9055 mMouseEventElement(0),
9056 mReplotting(false)
9057 {
9058 setAttribute(Qt::WA_NoMousePropagation);
9059 setAttribute(Qt::WA_OpaquePaintEvent);
9060 setMouseTracking(true);
9061 QLocale currentLocale = locale();
9062 currentLocale.setNumberOptions(QLocale::OmitGroupSeparator);
9063 setLocale(currentLocale);
9064
9065 // create initial layers:
9066 mLayers.append(new QCPLayer(this, QLatin1String("background")));
9067 mLayers.append(new QCPLayer(this, QLatin1String("grid")));
9068 mLayers.append(new QCPLayer(this, QLatin1String("main")));
9069 mLayers.append(new QCPLayer(this, QLatin1String("axes")));
9070 mLayers.append(new QCPLayer(this, QLatin1String("legend")));
9071 updateLayerIndices();
9072 setCurrentLayer(QLatin1String("main"));
9073
9074 // create initial layout, axis rect and legend:
9075 mPlotLayout = new QCPLayoutGrid;
9076 mPlotLayout->initializeParentPlot(this);
9077 mPlotLayout->setParent(this); // important because if parent is QWidget, QCPLayout::sizeConstraintsChanged will call QWidget::updateGeometry
9078 mPlotLayout->setLayer(QLatin1String("main"));
9079 QCPAxisRect *defaultAxisRect = new QCPAxisRect(this, true);
9080 mPlotLayout->addElement(0, 0, defaultAxisRect);
9081 xAxis = defaultAxisRect->axis(QCPAxis::atBottom);
9082 yAxis = defaultAxisRect->axis(QCPAxis::atLeft);
9083 xAxis2 = defaultAxisRect->axis(QCPAxis::atTop);
9084 yAxis2 = defaultAxisRect->axis(QCPAxis::atRight);
9085 legend = new QCPLegend;
9086 legend->setVisible(false);
9087 defaultAxisRect->insetLayout()->addElement(legend, Qt::AlignRight|Qt::AlignTop);
9088 defaultAxisRect->insetLayout()->setMargins(QMargins(12, 12, 12, 12));
9089
9090 defaultAxisRect->setLayer(QLatin1String("background"));
9091 xAxis->setLayer(QLatin1String("axes"));
9092 yAxis->setLayer(QLatin1String("axes"));
9093 xAxis2->setLayer(QLatin1String("axes"));
9094 yAxis2->setLayer(QLatin1String("axes"));
9095 xAxis->grid()->setLayer(QLatin1String("grid"));
9096 yAxis->grid()->setLayer(QLatin1String("grid"));
9097 xAxis2->grid()->setLayer(QLatin1String("grid"));
9098 yAxis2->grid()->setLayer(QLatin1String("grid"));
9099 legend->setLayer(QLatin1String("legend"));
9100
9101 setViewport(rect()); // needs to be called after mPlotLayout has been created
9102
9103 replot();
9035 QWidget(parent),
9036 xAxis(0),
9037 yAxis(0),
9038 xAxis2(0),
9039 yAxis2(0),
9040 legend(0),
9041 mPlotLayout(0),
9042 mAutoAddPlottableToLegend(true),
9043 mAntialiasedElements(QCP::aeNone),
9044 mNotAntialiasedElements(QCP::aeNone),
9045 mInteractions(0),
9046 mSelectionTolerance(8),
9047 mNoAntialiasingOnDrag(false),
9048 mBackgroundBrush(Qt::white, Qt::SolidPattern),
9049 mBackgroundScaled(true),
9050 mBackgroundScaledMode(Qt::KeepAspectRatioByExpanding),
9051 mCurrentLayer(0),
9052 mPlottingHints(QCP::phCacheLabels|QCP::phForceRepaint),
9053 mMultiSelectModifier(Qt::ControlModifier),
9054 mPaintBuffer(size()),
9055 mMouseEventElement(0),
9056 mReplotting(false)
9057 {
9058 setAttribute(Qt::WA_NoMousePropagation);
9059 setAttribute(Qt::WA_OpaquePaintEvent);
9060 setMouseTracking(true);
9061 QLocale currentLocale = locale();
9062 currentLocale.setNumberOptions(QLocale::OmitGroupSeparator);
9063 setLocale(currentLocale);
9064
9065 // create initial layers:
9066 mLayers.append(new QCPLayer(this, QLatin1String("background")));
9067 mLayers.append(new QCPLayer(this, QLatin1String("grid")));
9068 mLayers.append(new QCPLayer(this, QLatin1String("main")));
9069 mLayers.append(new QCPLayer(this, QLatin1String("axes")));
9070 mLayers.append(new QCPLayer(this, QLatin1String("legend")));
9071 updateLayerIndices();
9072 setCurrentLayer(QLatin1String("main"));
9073
9074 // create initial layout, axis rect and legend:
9075 mPlotLayout = new QCPLayoutGrid;
9076 mPlotLayout->initializeParentPlot(this);
9077 mPlotLayout->setParent(this); // important because if parent is QWidget, QCPLayout::sizeConstraintsChanged will call QWidget::updateGeometry
9078 mPlotLayout->setLayer(QLatin1String("main"));
9079 QCPAxisRect *defaultAxisRect = new QCPAxisRect(this, true);
9080 mPlotLayout->addElement(0, 0, defaultAxisRect);
9081 xAxis = defaultAxisRect->axis(QCPAxis::atBottom);
9082 yAxis = defaultAxisRect->axis(QCPAxis::atLeft);
9083 xAxis2 = defaultAxisRect->axis(QCPAxis::atTop);
9084 yAxis2 = defaultAxisRect->axis(QCPAxis::atRight);
9085 legend = new QCPLegend;
9086 legend->setVisible(false);
9087 defaultAxisRect->insetLayout()->addElement(legend, Qt::AlignRight|Qt::AlignTop);
9088 defaultAxisRect->insetLayout()->setMargins(QMargins(12, 12, 12, 12));
9089
9090 defaultAxisRect->setLayer(QLatin1String("background"));
9091 xAxis->setLayer(QLatin1String("axes"));
9092 yAxis->setLayer(QLatin1String("axes"));
9093 xAxis2->setLayer(QLatin1String("axes"));
9094 yAxis2->setLayer(QLatin1String("axes"));
9095 xAxis->grid()->setLayer(QLatin1String("grid"));
9096 yAxis->grid()->setLayer(QLatin1String("grid"));
9097 xAxis2->grid()->setLayer(QLatin1String("grid"));
9098 yAxis2->grid()->setLayer(QLatin1String("grid"));
9099 legend->setLayer(QLatin1String("legend"));
9100
9101 setViewport(rect()); // needs to be called after mPlotLayout has been created
9102
9103 replot();
9104 9104 }
9105 9105
9106 9106 QCustomPlot::~QCustomPlot()
9107 9107 {
9108 clearPlottables();
9109 clearItems();
9110
9111 if (mPlotLayout)
9112 {
9113 delete mPlotLayout;
9114 mPlotLayout = 0;
9115 }
9116
9117 mCurrentLayer = 0;
9118 qDeleteAll(mLayers); // don't use removeLayer, because it would prevent the last layer to be removed
9119 mLayers.clear();
9108 clearPlottables();
9109 clearItems();
9110
9111 if (mPlotLayout)
9112 {
9113 delete mPlotLayout;
9114 mPlotLayout = 0;
9115 }
9116
9117 mCurrentLayer = 0;
9118 qDeleteAll(mLayers); // don't use removeLayer, because it would prevent the last layer to be removed
9119 mLayers.clear();
9120 9120 }
9121 9121
9122 9122 /*!
@@ -9138,11 +9138,11 QCustomPlot::~QCustomPlot()
9138 9138 */
9139 9139 void QCustomPlot::setAntialiasedElements(const QCP::AntialiasedElements &antialiasedElements)
9140 9140 {
9141 mAntialiasedElements = antialiasedElements;
9142
9143 // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously:
9144 if ((mNotAntialiasedElements & mAntialiasedElements) != 0)
9145 mNotAntialiasedElements |= ~mAntialiasedElements;
9141 mAntialiasedElements = antialiasedElements;
9142
9143 // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously:
9144 if ((mNotAntialiasedElements & mAntialiasedElements) != 0)
9145 mNotAntialiasedElements |= ~mAntialiasedElements;
9146 9146 }
9147 9147
9148 9148 /*!
@@ -9154,14 +9154,14 void QCustomPlot::setAntialiasedElements
9154 9154 */
9155 9155 void QCustomPlot::setAntialiasedElement(QCP::AntialiasedElement antialiasedElement, bool enabled)
9156 9156 {
9157 if (!enabled && mAntialiasedElements.testFlag(antialiasedElement))
9158 mAntialiasedElements &= ~antialiasedElement;
9159 else if (enabled && !mAntialiasedElements.testFlag(antialiasedElement))
9160 mAntialiasedElements |= antialiasedElement;
9161
9162 // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously:
9163 if ((mNotAntialiasedElements & mAntialiasedElements) != 0)
9164 mNotAntialiasedElements |= ~mAntialiasedElements;
9157 if (!enabled && mAntialiasedElements.testFlag(antialiasedElement))
9158 mAntialiasedElements &= ~antialiasedElement;
9159 else if (enabled && !mAntialiasedElements.testFlag(antialiasedElement))
9160 mAntialiasedElements |= antialiasedElement;
9161
9162 // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously:
9163 if ((mNotAntialiasedElements & mAntialiasedElements) != 0)
9164 mNotAntialiasedElements |= ~mAntialiasedElements;
9165 9165 }
9166 9166
9167 9167 /*!
@@ -9184,11 +9184,11 void QCustomPlot::setAntialiasedElement(
9184 9184 */
9185 9185 void QCustomPlot::setNotAntialiasedElements(const QCP::AntialiasedElements &notAntialiasedElements)
9186 9186 {
9187 mNotAntialiasedElements = notAntialiasedElements;
9188
9189 // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously:
9190 if ((mNotAntialiasedElements & mAntialiasedElements) != 0)
9191 mAntialiasedElements |= ~mNotAntialiasedElements;
9187 mNotAntialiasedElements = notAntialiasedElements;
9188
9189 // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously:
9190 if ((mNotAntialiasedElements & mAntialiasedElements) != 0)
9191 mAntialiasedElements |= ~mNotAntialiasedElements;
9192 9192 }
9193 9193
9194 9194 /*!
@@ -9200,14 +9200,14 void QCustomPlot::setNotAntialiasedEleme
9200 9200 */
9201 9201 void QCustomPlot::setNotAntialiasedElement(QCP::AntialiasedElement notAntialiasedElement, bool enabled)
9202 9202 {
9203 if (!enabled && mNotAntialiasedElements.testFlag(notAntialiasedElement))
9204 mNotAntialiasedElements &= ~notAntialiasedElement;
9205 else if (enabled && !mNotAntialiasedElements.testFlag(notAntialiasedElement))
9206 mNotAntialiasedElements |= notAntialiasedElement;
9207
9208 // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously:
9209 if ((mNotAntialiasedElements & mAntialiasedElements) != 0)
9210 mAntialiasedElements |= ~mNotAntialiasedElements;
9203 if (!enabled && mNotAntialiasedElements.testFlag(notAntialiasedElement))
9204 mNotAntialiasedElements &= ~notAntialiasedElement;
9205 else if (enabled && !mNotAntialiasedElements.testFlag(notAntialiasedElement))
9206 mNotAntialiasedElements |= notAntialiasedElement;
9207
9208 // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously:
9209 if ((mNotAntialiasedElements & mAntialiasedElements) != 0)
9210 mAntialiasedElements |= ~mNotAntialiasedElements;
9211 9211 }
9212 9212
9213 9213 /*!
@@ -9218,7 +9218,7 void QCustomPlot::setNotAntialiasedEleme
9218 9218 */
9219 9219 void QCustomPlot::setAutoAddPlottableToLegend(bool on)
9220 9220 {
9221 mAutoAddPlottableToLegend = on;
9221 mAutoAddPlottableToLegend = on;
9222 9222 }
9223 9223
9224 9224 /*!
@@ -9277,7 +9277,7 void QCustomPlot::setAutoAddPlottableToL
9277 9277 */
9278 9278 void QCustomPlot::setInteractions(const QCP::Interactions &interactions)
9279 9279 {
9280 mInteractions = interactions;
9280 mInteractions = interactions;
9281 9281 }
9282 9282
9283 9283 /*!
@@ -9289,10 +9289,10 void QCustomPlot::setInteractions(const
9289 9289 */
9290 9290 void QCustomPlot::setInteraction(const QCP::Interaction &interaction, bool enabled)
9291 9291 {
9292 if (!enabled && mInteractions.testFlag(interaction))
9293 mInteractions &= ~interaction;
9294 else if (enabled && !mInteractions.testFlag(interaction))
9295 mInteractions |= interaction;
9292 if (!enabled && mInteractions.testFlag(interaction))
9293 mInteractions &= ~interaction;
9294 else if (enabled && !mInteractions.testFlag(interaction))
9295 mInteractions |= interaction;
9296 9296 }
9297 9297
9298 9298 /*!
@@ -9310,7 +9310,7 void QCustomPlot::setInteraction(const Q
9310 9310 */
9311 9311 void QCustomPlot::setSelectionTolerance(int pixels)
9312 9312 {
9313 mSelectionTolerance = pixels;
9313 mSelectionTolerance = pixels;
9314 9314 }
9315 9315
9316 9316 /*!
@@ -9324,7 +9324,7 void QCustomPlot::setSelectionTolerance(
9324 9324 */
9325 9325 void QCustomPlot::setNoAntialiasingOnDrag(bool enabled)
9326 9326 {
9327 mNoAntialiasingOnDrag = enabled;
9327 mNoAntialiasingOnDrag = enabled;
9328 9328 }
9329 9329
9330 9330 /*!
@@ -9334,7 +9334,7 void QCustomPlot::setNoAntialiasingOnDra
9334 9334 */
9335 9335 void QCustomPlot::setPlottingHints(const QCP::PlottingHints &hints)
9336 9336 {
9337 mPlottingHints = hints;
9337 mPlottingHints = hints;
9338 9338 }
9339 9339
9340 9340 /*!
@@ -9344,14 +9344,14 void QCustomPlot::setPlottingHints(const
9344 9344 */
9345 9345 void QCustomPlot::setPlottingHint(QCP::PlottingHint hint, bool enabled)
9346 9346 {
9347 QCP::PlottingHints newHints = mPlottingHints;
9348 if (!enabled)
9349 newHints &= ~hint;
9350 else
9351 newHints |= hint;
9352
9353 if (newHints != mPlottingHints)
9354 setPlottingHints(newHints);
9347 QCP::PlottingHints newHints = mPlottingHints;
9348 if (!enabled)
9349 newHints &= ~hint;
9350 else
9351 newHints |= hint;
9352
9353 if (newHints != mPlottingHints)
9354 setPlottingHints(newHints);
9355 9355 }
9356 9356
9357 9357 /*!
@@ -9366,9 +9366,8 void QCustomPlot::setPlottingHint(QCP::P
9366 9366 */
9367 9367 void QCustomPlot::setMultiSelectModifier(Qt::KeyboardModifier modifier)
9368 9368 {
9369 mMultiSelectModifier = modifier;
9370 }
9371
9369 mMultiSelectModifier = modifier;
9370 }
9372 9371
9373 9372 /*!
9374 9373 Sets the viewport of this QCustomPlot. The Viewport is the area that the top level layout
@@ -9379,9 +9378,9 void QCustomPlot::setMultiSelectModifier
9379 9378 */
9380 9379 void QCustomPlot::setViewport(const QRect &rect)
9381 9380 {
9382 mViewport = rect;
9383 if (mPlotLayout)
9384 mPlotLayout->setOuterRect(mViewport);
9381 mViewport = rect;
9382 if (mPlotLayout)
9383 mPlotLayout->setOuterRect(mViewport);
9385 9384 }
9386 9385
9387 9386 /*!
@@ -9401,8 +9400,8 void QCustomPlot::setViewport(const QRec
9401 9400 */
9402 9401 void QCustomPlot::setBackground(const QPixmap &pm)
9403 9402 {
9404 mBackgroundPixmap = pm;
9405 mScaledBackgroundPixmap = QPixmap();
9403 mBackgroundPixmap = pm;
9404 mScaledBackgroundPixmap = QPixmap();
9406 9405 }
9407 9406
9408 9407 /*!
@@ -9420,7 +9419,7 void QCustomPlot::setBackground(const QP
9420 9419 */
9421 9420 void QCustomPlot::setBackground(const QBrush &brush)
9422 9421 {
9423 mBackgroundBrush = brush;
9422 mBackgroundBrush = brush;
9424 9423 }
9425 9424
9426 9425 /*! \overload
@@ -9432,10 +9431,10 void QCustomPlot::setBackground(const QB
9432 9431 */
9433 9432 void QCustomPlot::setBackground(const QPixmap &pm, bool scaled, Qt::AspectRatioMode mode)
9434 9433 {
9435 mBackgroundPixmap = pm;
9436 mScaledBackgroundPixmap = QPixmap();
9437 mBackgroundScaled = scaled;
9438 mBackgroundScaledMode = mode;
9434 mBackgroundPixmap = pm;
9435 mScaledBackgroundPixmap = QPixmap();
9436 mBackgroundScaled = scaled;
9437 mBackgroundScaledMode = mode;
9439 9438 }
9440 9439
9441 9440 /*!
@@ -9450,7 +9449,7 void QCustomPlot::setBackground(const QP
9450 9449 */
9451 9450 void QCustomPlot::setBackgroundScaled(bool scaled)
9452 9451 {
9453 mBackgroundScaled = scaled;
9452 mBackgroundScaled = scaled;
9454 9453 }
9455 9454
9456 9455 /*!
@@ -9461,7 +9460,7 void QCustomPlot::setBackgroundScaled(bo
9461 9460 */
9462 9461 void QCustomPlot::setBackgroundScaledMode(Qt::AspectRatioMode mode)
9463 9462 {
9464 mBackgroundScaledMode = mode;
9463 mBackgroundScaledMode = mode;
9465 9464 }
9466 9465
9467 9466 /*!
@@ -9474,13 +9473,13 void QCustomPlot::setBackgroundScaledMod
9474 9473 */
9475 9474 QCPAbstractPlottable *QCustomPlot::plottable(int index)
9476 9475 {
9477 if (index >= 0 && index < mPlottables.size())
9478 {
9479 return mPlottables.at(index);
9480 } else
9481 {
9482 qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
9483 return 0;
9476 if (index >= 0 && index < mPlottables.size())
9477 {
9478 return mPlottables.at(index);
9479 } else
9480 {
9481 qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
9482 return 0;
9484 9483 }
9485 9484 }
9486 9485
@@ -9493,11 +9492,11 QCPAbstractPlottable *QCustomPlot::plott
9493 9492 */
9494 9493 QCPAbstractPlottable *QCustomPlot::plottable()
9495 9494 {
9496 if (!mPlottables.isEmpty())
9497 {
9498 return mPlottables.last();
9499 } else
9500 return 0;
9495 if (!mPlottables.isEmpty())
9496 {
9497 return mPlottables.last();
9498 } else
9499 return 0;
9501 9500 }
9502 9501
9503 9502 /*!
@@ -9512,27 +9511,27 QCPAbstractPlottable *QCustomPlot::plott
9512 9511 */
9513 9512 bool QCustomPlot::addPlottable(QCPAbstractPlottable *plottable)
9514 9513 {
9515 if (mPlottables.contains(plottable))
9516 {
9517 qDebug() << Q_FUNC_INFO << "plottable already added to this QCustomPlot:" << reinterpret_cast<quintptr>(plottable);
9518 return false;
9519 }
9520 if (plottable->parentPlot() != this)
9521 {
9522 qDebug() << Q_FUNC_INFO << "plottable not created with this QCustomPlot as parent:" << reinterpret_cast<quintptr>(plottable);
9523 return false;
9524 }
9525
9526 mPlottables.append(plottable);
9527 // possibly add plottable to legend:
9528 if (mAutoAddPlottableToLegend)
9529 plottable->addToLegend();
9530 // special handling for QCPGraphs to maintain the simple graph interface:
9531 if (QCPGraph *graph = qobject_cast<QCPGraph*>(plottable))
9532 mGraphs.append(graph);
9533 if (!plottable->layer()) // usually the layer is already set in the constructor of the plottable (via QCPLayerable constructor)
9534 plottable->setLayer(currentLayer());
9535 return true;
9514 if (mPlottables.contains(plottable))
9515 {
9516 qDebug() << Q_FUNC_INFO << "plottable already added to this QCustomPlot:" << reinterpret_cast<quintptr>(plottable);
9517 return false;
9518 }
9519 if (plottable->parentPlot() != this)
9520 {
9521 qDebug() << Q_FUNC_INFO << "plottable not created with this QCustomPlot as parent:" << reinterpret_cast<quintptr>(plottable);
9522 return false;
9523 }
9524
9525 mPlottables.append(plottable);
9526 // possibly add plottable to legend:
9527 if (mAutoAddPlottableToLegend)
9528 plottable->addToLegend();
9529 // special handling for QCPGraphs to maintain the simple graph interface:
9530 if (QCPGraph *graph = qobject_cast<QCPGraph*>(plottable))
9531 mGraphs.append(graph);
9532 if (!plottable->layer()) // usually the layer is already set in the constructor of the plottable (via QCPLayerable constructor)
9533 plottable->setLayer(currentLayer());
9534 return true;
9536 9535 }
9537 9536
9538 9537 /*!
@@ -9544,21 +9543,21 bool QCustomPlot::addPlottable(QCPAbstra
9544 9543 */
9545 9544 bool QCustomPlot::removePlottable(QCPAbstractPlottable *plottable)
9546 9545 {
9547 if (!mPlottables.contains(plottable))
9548 {
9549 qDebug() << Q_FUNC_INFO << "plottable not in list:" << reinterpret_cast<quintptr>(plottable);
9550 return false;
9551 }
9552
9553 // remove plottable from legend:
9554 plottable->removeFromLegend();
9555 // special handling for QCPGraphs to maintain the simple graph interface:
9556 if (QCPGraph *graph = qobject_cast<QCPGraph*>(plottable))
9557 mGraphs.removeOne(graph);
9558 // remove plottable:
9559 delete plottable;
9560 mPlottables.removeOne(plottable);
9561 return true;
9546 if (!mPlottables.contains(plottable))
9547 {
9548 qDebug() << Q_FUNC_INFO << "plottable not in list:" << reinterpret_cast<quintptr>(plottable);
9549 return false;
9550 }
9551
9552 // remove plottable from legend:
9553 plottable->removeFromLegend();
9554 // special handling for QCPGraphs to maintain the simple graph interface:
9555 if (QCPGraph *graph = qobject_cast<QCPGraph*>(plottable))
9556 mGraphs.removeOne(graph);
9557 // remove plottable:
9558 delete plottable;
9559 mPlottables.removeOne(plottable);
9560 return true;
9562 9561 }
9563 9562
9564 9563 /*! \overload
@@ -9567,12 +9566,12 bool QCustomPlot::removePlottable(QCPAbs
9567 9566 */
9568 9567 bool QCustomPlot::removePlottable(int index)
9569 9568 {
9570 if (index >= 0 && index < mPlottables.size())
9571 return removePlottable(mPlottables[index]);
9572 else
9573 {
9574 qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
9575 return false;
9569 if (index >= 0 && index < mPlottables.size())
9570 return removePlottable(mPlottables[index]);
9571 else
9572 {
9573 qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
9574 return false;
9576 9575 }
9577 9576 }
9578 9577
@@ -9585,10 +9584,10 bool QCustomPlot::removePlottable(int in
9585 9584 */
9586 9585 int QCustomPlot::clearPlottables()
9587 9586 {
9588 int c = mPlottables.size();
9589 for (int i=c-1; i >= 0; --i)
9590 removePlottable(mPlottables[i]);
9591 return c;
9587 int c = mPlottables.size();
9588 for (int i=c-1; i >= 0; --i)
9589 removePlottable(mPlottables[i]);
9590 return c;
9592 9591 }
9593 9592
9594 9593 /*!
@@ -9598,7 +9597,7 int QCustomPlot::clearPlottables()
9598 9597 */
9599 9598 int QCustomPlot::plottableCount() const
9600 9599 {
9601 return mPlottables.size();
9600 return mPlottables.size();
9602 9601 }
9603 9602
9604 9603 /*!
@@ -9610,13 +9609,13 int QCustomPlot::plottableCount() const
9610 9609 */
9611 9610 QList<QCPAbstractPlottable*> QCustomPlot::selectedPlottables() const
9612 9611 {
9613 QList<QCPAbstractPlottable*> result;
9614 foreach (QCPAbstractPlottable *plottable, mPlottables)
9615 {
9616 if (plottable->selected())
9617 result.append(plottable);
9618 }
9619 return result;
9612 QList<QCPAbstractPlottable*> result;
9613 foreach (QCPAbstractPlottable *plottable, mPlottables)
9614 {
9615 if (plottable->selected())
9616 result.append(plottable);
9617 }
9618 return result;
9620 9619 }
9621 9620
9622 9621 /*!
@@ -9633,25 +9632,25 QList<QCPAbstractPlottable*> QCustomPlot
9633 9632 */
9634 9633 QCPAbstractPlottable *QCustomPlot::plottableAt(const QPointF &pos, bool onlySelectable) const
9635 9634 {
9636 QCPAbstractPlottable *resultPlottable = 0;
9637 double resultDistance = mSelectionTolerance; // only regard clicks with distances smaller than mSelectionTolerance as selections, so initialize with that value
9638
9639 foreach (QCPAbstractPlottable *plottable, mPlottables)
9640 {
9641 if (onlySelectable && !plottable->selectable()) // we could have also passed onlySelectable to the selectTest function, but checking here is faster, because we have access to QCPabstractPlottable::selectable
9642 continue;
9643 if ((plottable->keyAxis()->axisRect()->rect() & plottable->valueAxis()->axisRect()->rect()).contains(pos.toPoint())) // only consider clicks inside the rect that is spanned by the plottable's key/value axes
9644 {
9645 double currentDistance = plottable->selectTest(pos, false);
9646 if (currentDistance >= 0 && currentDistance < resultDistance)
9647 {
9648 resultPlottable = plottable;
9649 resultDistance = currentDistance;
9650 }
9651 }
9652 }
9653
9654 return resultPlottable;
9635 QCPAbstractPlottable *resultPlottable = 0;
9636 double resultDistance = mSelectionTolerance; // only regard clicks with distances smaller than mSelectionTolerance as selections, so initialize with that value
9637
9638 foreach (QCPAbstractPlottable *plottable, mPlottables)
9639 {
9640 if (onlySelectable && !plottable->selectable()) // we could have also passed onlySelectable to the selectTest function, but checking here is faster, because we have access to QCPabstractPlottable::selectable
9641 continue;
9642 if ((plottable->keyAxis()->axisRect()->rect() & plottable->valueAxis()->axisRect()->rect()).contains(pos.toPoint())) // only consider clicks inside the rect that is spanned by the plottable's key/value axes
9643 {
9644 double currentDistance = plottable->selectTest(pos, false);
9645 if (currentDistance >= 0 && currentDistance < resultDistance)
9646 {
9647 resultPlottable = plottable;
9648 resultDistance = currentDistance;
9649 }
9650 }
9651 }
9652
9653 return resultPlottable;
9655 9654 }
9656 9655
9657 9656 /*!
@@ -9661,7 +9660,7 QCPAbstractPlottable *QCustomPlot::plott
9661 9660 */
9662 9661 bool QCustomPlot::hasPlottable(QCPAbstractPlottable *plottable) const
9663 9662 {
9664 return mPlottables.contains(plottable);
9663 return mPlottables.contains(plottable);
9665 9664 }
9666 9665
9667 9666 /*!
@@ -9674,13 +9673,13 bool QCustomPlot::hasPlottable(QCPAbstra
9674 9673 */
9675 9674 QCPGraph *QCustomPlot::graph(int index) const
9676 9675 {
9677 if (index >= 0 && index < mGraphs.size())
9678 {
9679 return mGraphs.at(index);
9680 } else
9681 {
9682 qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
9683 return 0;
9676 if (index >= 0 && index < mGraphs.size())
9677 {
9678 return mGraphs.at(index);
9679 } else
9680 {
9681 qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
9682 return 0;
9684 9683 }
9685 9684 }
9686 9685
@@ -9693,11 +9692,11 QCPGraph *QCustomPlot::graph(int index)
9693 9692 */
9694 9693 QCPGraph *QCustomPlot::graph() const
9695 9694 {
9696 if (!mGraphs.isEmpty())
9697 {
9698 return mGraphs.last();
9699 } else
9700 return 0;
9695 if (!mGraphs.isEmpty())
9696 {
9697 return mGraphs.last();
9698 } else
9699 return 0;
9701 9700 }
9702 9701
9703 9702 /*!
@@ -9714,28 +9713,28 QCPGraph *QCustomPlot::graph() const
9714 9713 */
9715 9714 QCPGraph *QCustomPlot::addGraph(QCPAxis *keyAxis, QCPAxis *valueAxis)
9716 9715 {
9717 if (!keyAxis) keyAxis = xAxis;
9718 if (!valueAxis) valueAxis = yAxis;
9719 if (!keyAxis || !valueAxis)
9720 {
9721 qDebug() << Q_FUNC_INFO << "can't use default QCustomPlot xAxis or yAxis, because at least one is invalid (has been deleted)";
9722 return 0;
9723 }
9724 if (keyAxis->parentPlot() != this || valueAxis->parentPlot() != this)
9725 {
9726 qDebug() << Q_FUNC_INFO << "passed keyAxis or valueAxis doesn't have this QCustomPlot as parent";
9727 return 0;
9728 }
9729
9730 QCPGraph *newGraph = new QCPGraph(keyAxis, valueAxis);
9731 if (addPlottable(newGraph))
9732 {
9733 newGraph->setName(QLatin1String("Graph ")+QString::number(mGraphs.size()));
9734 return newGraph;
9735 } else
9736 {
9737 delete newGraph;
9738 return 0;
9716 if (!keyAxis) keyAxis = xAxis;
9717 if (!valueAxis) valueAxis = yAxis;
9718 if (!keyAxis || !valueAxis)
9719 {
9720 qDebug() << Q_FUNC_INFO << "can't use default QCustomPlot xAxis or yAxis, because at least one is invalid (has been deleted)";
9721 return 0;
9722 }
9723 if (keyAxis->parentPlot() != this || valueAxis->parentPlot() != this)
9724 {
9725 qDebug() << Q_FUNC_INFO << "passed keyAxis or valueAxis doesn't have this QCustomPlot as parent";
9726 return 0;
9727 }
9728
9729 QCPGraph *newGraph = new QCPGraph(keyAxis, valueAxis);
9730 if (addPlottable(newGraph))
9731 {
9732 newGraph->setName(QLatin1String("Graph ")+QString::number(mGraphs.size()));
9733 return newGraph;
9734 } else
9735 {
9736 delete newGraph;
9737 return 0;
9739 9738 }
9740 9739 }
9741 9740
@@ -9750,7 +9749,7 QCPGraph *QCustomPlot::addGraph(QCPAxis
9750 9749 */
9751 9750 bool QCustomPlot::removeGraph(QCPGraph *graph)
9752 9751 {
9753 return removePlottable(graph);
9752 return removePlottable(graph);
9754 9753 }
9755 9754
9756 9755 /*! \overload
@@ -9759,10 +9758,10 bool QCustomPlot::removeGraph(QCPGraph *
9759 9758 */
9760 9759 bool QCustomPlot::removeGraph(int index)
9761 9760 {
9762 if (index >= 0 && index < mGraphs.size())
9763 return removeGraph(mGraphs[index]);
9764 else
9765 return false;
9761 if (index >= 0 && index < mGraphs.size())
9762 return removeGraph(mGraphs[index]);
9763 else
9764 return false;
9766 9765 }
9767 9766
9768 9767 /*!
@@ -9774,10 +9773,10 bool QCustomPlot::removeGraph(int index)
9774 9773 */
9775 9774 int QCustomPlot::clearGraphs()
9776 9775 {
9777 int c = mGraphs.size();
9778 for (int i=c-1; i >= 0; --i)
9779 removeGraph(mGraphs[i]);
9780 return c;
9776 int c = mGraphs.size();
9777 for (int i=c-1; i >= 0; --i)
9778 removeGraph(mGraphs[i]);
9779 return c;
9781 9780 }
9782 9781
9783 9782 /*!
@@ -9787,7 +9786,7 int QCustomPlot::clearGraphs()
9787 9786 */
9788 9787 int QCustomPlot::graphCount() const
9789 9788 {
9790 return mGraphs.size();
9789 return mGraphs.size();
9791 9790 }
9792 9791
9793 9792 /*!
@@ -9800,13 +9799,13 int QCustomPlot::graphCount() const
9800 9799 */
9801 9800 QList<QCPGraph*> QCustomPlot::selectedGraphs() const
9802 9801 {
9803 QList<QCPGraph*> result;
9804 foreach (QCPGraph *graph, mGraphs)
9805 {
9806 if (graph->selected())
9807 result.append(graph);
9808 }
9809 return result;
9802 QList<QCPGraph*> result;
9803 foreach (QCPGraph *graph, mGraphs)
9804 {
9805 if (graph->selected())
9806 result.append(graph);
9807 }
9808 return result;
9810 9809 }
9811 9810
9812 9811 /*!
@@ -9819,13 +9818,13 QList<QCPGraph*> QCustomPlot::selectedGr
9819 9818 */
9820 9819 QCPAbstractItem *QCustomPlot::item(int index) const
9821 9820 {
9822 if (index >= 0 && index < mItems.size())
9823 {
9824 return mItems.at(index);
9825 } else
9826 {
9827 qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
9828 return 0;
9821 if (index >= 0 && index < mItems.size())
9822 {
9823 return mItems.at(index);
9824 } else
9825 {
9826 qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
9827 return 0;
9829 9828 }
9830 9829 }
9831 9830
@@ -9838,11 +9837,11 QCPAbstractItem *QCustomPlot::item(int i
9838 9837 */
9839 9838 QCPAbstractItem *QCustomPlot::item() const
9840 9839 {
9841 if (!mItems.isEmpty())
9842 {
9843 return mItems.last();
9844 } else
9845 return 0;
9840 if (!mItems.isEmpty())
9841 {
9842 return mItems.last();
9843 } else
9844 return 0;
9846 9845 }
9847 9846
9848 9847 /*!
@@ -9855,14 +9854,14 QCPAbstractItem *QCustomPlot::item() con
9855 9854 */
9856 9855 bool QCustomPlot::addItem(QCPAbstractItem *item)
9857 9856 {
9858 if (!mItems.contains(item) && item->parentPlot() == this)
9859 {
9860 mItems.append(item);
9861 return true;
9862 } else
9863 {
9864 qDebug() << Q_FUNC_INFO << "item either already in list or not created with this QCustomPlot as parent:" << reinterpret_cast<quintptr>(item);
9865 return false;
9857 if (!mItems.contains(item) && item->parentPlot() == this)
9858 {
9859 mItems.append(item);
9860 return true;
9861 } else
9862 {
9863 qDebug() << Q_FUNC_INFO << "item either already in list or not created with this QCustomPlot as parent:" << reinterpret_cast<quintptr>(item);
9864 return false;
9866 9865 }
9867 9866 }
9868 9867
@@ -9875,15 +9874,15 bool QCustomPlot::addItem(QCPAbstractIte
9875 9874 */
9876 9875 bool QCustomPlot::removeItem(QCPAbstractItem *item)
9877 9876 {
9878 if (mItems.contains(item))
9879 {
9880 delete item;
9881 mItems.removeOne(item);
9882 return true;
9883 } else
9884 {
9885 qDebug() << Q_FUNC_INFO << "item not in list:" << reinterpret_cast<quintptr>(item);
9886 return false;
9877 if (mItems.contains(item))
9878 {
9879 delete item;
9880 mItems.removeOne(item);
9881 return true;
9882 } else
9883 {
9884 qDebug() << Q_FUNC_INFO << "item not in list:" << reinterpret_cast<quintptr>(item);
9885 return false;
9887 9886 }
9888 9887 }
9889 9888
@@ -9893,12 +9892,12 bool QCustomPlot::removeItem(QCPAbstract
9893 9892 */
9894 9893 bool QCustomPlot::removeItem(int index)
9895 9894 {
9896 if (index >= 0 && index < mItems.size())
9897 return removeItem(mItems[index]);
9898 else
9899 {
9900 qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
9901 return false;
9895 if (index >= 0 && index < mItems.size())
9896 return removeItem(mItems[index]);
9897 else
9898 {
9899 qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
9900 return false;
9902 9901 }
9903 9902 }
9904 9903
@@ -9911,10 +9910,10 bool QCustomPlot::removeItem(int index)
9911 9910 */
9912 9911 int QCustomPlot::clearItems()
9913 9912 {
9914 int c = mItems.size();
9915 for (int i=c-1; i >= 0; --i)
9916 removeItem(mItems[i]);
9917 return c;
9913 int c = mItems.size();
9914 for (int i=c-1; i >= 0; --i)
9915 removeItem(mItems[i]);
9916 return c;
9918 9917 }
9919 9918
9920 9919 /*!
@@ -9924,7 +9923,7 int QCustomPlot::clearItems()
9924 9923 */
9925 9924 int QCustomPlot::itemCount() const
9926 9925 {
9927 return mItems.size();
9926 return mItems.size();
9928 9927 }
9929 9928
9930 9929 /*!
@@ -9934,13 +9933,13 int QCustomPlot::itemCount() const
9934 9933 */
9935 9934 QList<QCPAbstractItem*> QCustomPlot::selectedItems() const
9936 9935 {
9937 QList<QCPAbstractItem*> result;
9938 foreach (QCPAbstractItem *item, mItems)
9939 {
9940 if (item->selected())
9941 result.append(item);
9942 }
9943 return result;
9936 QList<QCPAbstractItem*> result;
9937 foreach (QCPAbstractItem *item, mItems)
9938 {
9939 if (item->selected())
9940 result.append(item);
9941 }
9942 return result;
9944 9943 }
9945 9944
9946 9945 /*!
@@ -9958,25 +9957,25 QList<QCPAbstractItem*> QCustomPlot::sel
9958 9957 */
9959 9958 QCPAbstractItem *QCustomPlot::itemAt(const QPointF &pos, bool onlySelectable) const
9960 9959 {
9961 QCPAbstractItem *resultItem = 0;
9962 double resultDistance = mSelectionTolerance; // only regard clicks with distances smaller than mSelectionTolerance as selections, so initialize with that value
9963
9964 foreach (QCPAbstractItem *item, mItems)
9965 {
9966 if (onlySelectable && !item->selectable()) // we could have also passed onlySelectable to the selectTest function, but checking here is faster, because we have access to QCPAbstractItem::selectable
9967 continue;
9968 if (!item->clipToAxisRect() || item->clipRect().contains(pos.toPoint())) // only consider clicks inside axis cliprect of the item if actually clipped to it
9969 {
9970 double currentDistance = item->selectTest(pos, false);
9971 if (currentDistance >= 0 && currentDistance < resultDistance)
9972 {
9973 resultItem = item;
9974 resultDistance = currentDistance;
9975 }
9976 }
9977 }
9978
9979 return resultItem;
9960 QCPAbstractItem *resultItem = 0;
9961 double resultDistance = mSelectionTolerance; // only regard clicks with distances smaller than mSelectionTolerance as selections, so initialize with that value
9962
9963 foreach (QCPAbstractItem *item, mItems)
9964 {
9965 if (onlySelectable && !item->selectable()) // we could have also passed onlySelectable to the selectTest function, but checking here is faster, because we have access to QCPAbstractItem::selectable
9966 continue;
9967 if (!item->clipToAxisRect() || item->clipRect().contains(pos.toPoint())) // only consider clicks inside axis cliprect of the item if actually clipped to it
9968 {
9969 double currentDistance = item->selectTest(pos, false);
9970 if (currentDistance >= 0 && currentDistance < resultDistance)
9971 {
9972 resultItem = item;
9973 resultDistance = currentDistance;
9974 }
9975 }
9976 }
9977
9978 return resultItem;
9980 9979 }
9981 9980
9982 9981 /*!
@@ -9986,7 +9985,7 QCPAbstractItem *QCustomPlot::itemAt(con
9986 9985 */
9987 9986 bool QCustomPlot::hasItem(QCPAbstractItem *item) const
9988 9987 {
9989 return mItems.contains(item);
9988 return mItems.contains(item);
9990 9989 }
9991 9990
9992 9991 /*!
@@ -9999,12 +9998,12 bool QCustomPlot::hasItem(QCPAbstractIte
9999 9998 */
10000 9999 QCPLayer *QCustomPlot::layer(const QString &name) const
10001 10000 {
10002 foreach (QCPLayer *layer, mLayers)
10003 {
10004 if (layer->name() == name)
10005 return layer;
10006 }
10007 return 0;
10001 foreach (QCPLayer *layer, mLayers)
10002 {
10003 if (layer->name() == name)
10004 return layer;
10005 }
10006 return 0;
10008 10007 }
10009 10008
10010 10009 /*! \overload
@@ -10015,13 +10014,13 QCPLayer *QCustomPlot::layer(const QStri
10015 10014 */
10016 10015 QCPLayer *QCustomPlot::layer(int index) const
10017 10016 {
10018 if (index >= 0 && index < mLayers.size())
10019 {
10020 return mLayers.at(index);
10021 } else
10022 {
10023 qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
10024 return 0;
10017 if (index >= 0 && index < mLayers.size())
10018 {
10019 return mLayers.at(index);
10020 } else
10021 {
10022 qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
10023 return 0;
10025 10024 }
10026 10025 }
10027 10026
@@ -10030,7 +10029,7 QCPLayer *QCustomPlot::layer(int index)
10030 10029 */
10031 10030 QCPLayer *QCustomPlot::currentLayer() const
10032 10031 {
10033 return mCurrentLayer;
10032 return mCurrentLayer;
10034 10033 }
10035 10034
10036 10035 /*!
@@ -10045,13 +10044,13 QCPLayer *QCustomPlot::currentLayer() co
10045 10044 */
10046 10045 bool QCustomPlot::setCurrentLayer(const QString &name)
10047 10046 {
10048 if (QCPLayer *newCurrentLayer = layer(name))
10049 {
10050 return setCurrentLayer(newCurrentLayer);
10051 } else
10052 {
10053 qDebug() << Q_FUNC_INFO << "layer with name doesn't exist:" << name;
10054 return false;
10047 if (QCPLayer *newCurrentLayer = layer(name))
10048 {
10049 return setCurrentLayer(newCurrentLayer);
10050 } else
10051 {
10052 qDebug() << Q_FUNC_INFO << "layer with name doesn't exist:" << name;
10053 return false;
10055 10054 }
10056 10055 }
10057 10056
@@ -10065,14 +10064,14 bool QCustomPlot::setCurrentLayer(const
10065 10064 */
10066 10065 bool QCustomPlot::setCurrentLayer(QCPLayer *layer)
10067 10066 {
10068 if (!mLayers.contains(layer))
10069 {
10070 qDebug() << Q_FUNC_INFO << "layer not a layer of this QCustomPlot:" << reinterpret_cast<quintptr>(layer);
10071 return false;
10072 }
10073
10074 mCurrentLayer = layer;
10075 return true;
10067 if (!mLayers.contains(layer))
10068 {
10069 qDebug() << Q_FUNC_INFO << "layer not a layer of this QCustomPlot:" << reinterpret_cast<quintptr>(layer);
10070 return false;
10071 }
10072
10073 mCurrentLayer = layer;
10074 return true;
10076 10075 }
10077 10076
10078 10077 /*!
@@ -10082,7 +10081,7 bool QCustomPlot::setCurrentLayer(QCPLay
10082 10081 */
10083 10082 int QCustomPlot::layerCount() const
10084 10083 {
10085 return mLayers.size();
10084 return mLayers.size();
10086 10085 }
10087 10086
10088 10087 /*!
@@ -10100,23 +10099,23 int QCustomPlot::layerCount() const
10100 10099 */
10101 10100 bool QCustomPlot::addLayer(const QString &name, QCPLayer *otherLayer, QCustomPlot::LayerInsertMode insertMode)
10102 10101 {
10103 if (!otherLayer)
10104 otherLayer = mLayers.last();
10105 if (!mLayers.contains(otherLayer))
10106 {
10107 qDebug() << Q_FUNC_INFO << "otherLayer not a layer of this QCustomPlot:" << reinterpret_cast<quintptr>(otherLayer);
10108 return false;
10109 }
10110 if (layer(name))
10111 {
10112 qDebug() << Q_FUNC_INFO << "A layer exists already with the name" << name;
10113 return false;
10114 }
10115
10116 QCPLayer *newLayer = new QCPLayer(this, name);
10117 mLayers.insert(otherLayer->index() + (insertMode==limAbove ? 1:0), newLayer);
10118 updateLayerIndices();
10119 return true;
10102 if (!otherLayer)
10103 otherLayer = mLayers.last();
10104 if (!mLayers.contains(otherLayer))
10105 {
10106 qDebug() << Q_FUNC_INFO << "otherLayer not a layer of this QCustomPlot:" << reinterpret_cast<quintptr>(otherLayer);
10107 return false;
10108 }
10109 if (layer(name))
10110 {
10111 qDebug() << Q_FUNC_INFO << "A layer exists already with the name" << name;
10112 return false;
10113 }
10114
10115 QCPLayer *newLayer = new QCPLayer(this, name);
10116 mLayers.insert(otherLayer->index() + (insertMode==limAbove ? 1:0), newLayer);
10117 updateLayerIndices();
10118 return true;
10120 10119 }
10121 10120
10122 10121 /*!
@@ -10135,39 +10134,39 bool QCustomPlot::addLayer(const QString
10135 10134 */
10136 10135 bool QCustomPlot::removeLayer(QCPLayer *layer)
10137 10136 {
10138 if (!mLayers.contains(layer))
10139 {
10140 qDebug() << Q_FUNC_INFO << "layer not a layer of this QCustomPlot:" << reinterpret_cast<quintptr>(layer);
10141 return false;
10142 }
10143 if (mLayers.size() < 2)
10144 {
10145 qDebug() << Q_FUNC_INFO << "can't remove last layer";
10146 return false;
10147 }
10148
10149 // append all children of this layer to layer below (if this is lowest layer, prepend to layer above)
10150 int removedIndex = layer->index();
10151 bool isFirstLayer = removedIndex==0;
10152 QCPLayer *targetLayer = isFirstLayer ? mLayers.at(removedIndex+1) : mLayers.at(removedIndex-1);
10153 QList<QCPLayerable*> children = layer->children();
10154 if (isFirstLayer) // prepend in reverse order (so order relative to each other stays the same)
10155 {
10156 for (int i=children.size()-1; i>=0; --i)
10157 children.at(i)->moveToLayer(targetLayer, true);
10137 if (!mLayers.contains(layer))
10138 {
10139 qDebug() << Q_FUNC_INFO << "layer not a layer of this QCustomPlot:" << reinterpret_cast<quintptr>(layer);
10140 return false;
10141 }
10142 if (mLayers.size() < 2)
10143 {
10144 qDebug() << Q_FUNC_INFO << "can't remove last layer";
10145 return false;
10146 }
10147
10148 // append all children of this layer to layer below (if this is lowest layer, prepend to layer above)
10149 int removedIndex = layer->index();
10150 bool isFirstLayer = removedIndex==0;
10151 QCPLayer *targetLayer = isFirstLayer ? mLayers.at(removedIndex+1) : mLayers.at(removedIndex-1);
10152 QList<QCPLayerable*> children = layer->children();
10153 if (isFirstLayer) // prepend in reverse order (so order relative to each other stays the same)
10154 {
10155 for (int i=children.size()-1; i>=0; --i)
10156 children.at(i)->moveToLayer(targetLayer, true);
10158 10157 } else // append normally
10159 10158 {
10160 for (int i=0; i<children.size(); ++i)
10161 children.at(i)->moveToLayer(targetLayer, false);
10162 }
10163 // if removed layer is current layer, change current layer to layer below/above:
10164 if (layer == mCurrentLayer)
10165 setCurrentLayer(targetLayer);
10166 // remove layer:
10167 delete layer;
10168 mLayers.removeOne(layer);
10169 updateLayerIndices();
10170 return true;
10159 for (int i=0; i<children.size(); ++i)
10160 children.at(i)->moveToLayer(targetLayer, false);
10161 }
10162 // if removed layer is current layer, change current layer to layer below/above:
10163 if (layer == mCurrentLayer)
10164 setCurrentLayer(targetLayer);
10165 // remove layer:
10166 delete layer;
10167 mLayers.removeOne(layer);
10168 updateLayerIndices();
10169 return true;
10171 10170 }
10172 10171
10173 10172 /*!
@@ -10181,20 +10180,20 bool QCustomPlot::removeLayer(QCPLayer *
10181 10180 */
10182 10181 bool QCustomPlot::moveLayer(QCPLayer *layer, QCPLayer *otherLayer, QCustomPlot::LayerInsertMode insertMode)
10183 10182 {
10184 if (!mLayers.contains(layer))
10185 {
10186 qDebug() << Q_FUNC_INFO << "layer not a layer of this QCustomPlot:" << reinterpret_cast<quintptr>(layer);
10187 return false;
10188 }
10189 if (!mLayers.contains(otherLayer))
10190 {
10191 qDebug() << Q_FUNC_INFO << "otherLayer not a layer of this QCustomPlot:" << reinterpret_cast<quintptr>(otherLayer);
10192 return false;
10193 }
10194
10195 mLayers.move(layer->index(), otherLayer->index() + (insertMode==limAbove ? 1:0));
10196 updateLayerIndices();
10197 return true;
10183 if (!mLayers.contains(layer))
10184 {
10185 qDebug() << Q_FUNC_INFO << "layer not a layer of this QCustomPlot:" << reinterpret_cast<quintptr>(layer);
10186 return false;
10187 }
10188 if (!mLayers.contains(otherLayer))
10189 {
10190 qDebug() << Q_FUNC_INFO << "otherLayer not a layer of this QCustomPlot:" << reinterpret_cast<quintptr>(otherLayer);
10191 return false;
10192 }
10193
10194 mLayers.move(layer->index(), otherLayer->index() + (insertMode==limAbove ? 1:0));
10195 updateLayerIndices();
10196 return true;
10198 10197 }
10199 10198
10200 10199 /*!
@@ -10208,7 +10207,7 bool QCustomPlot::moveLayer(QCPLayer *la
10208 10207 */
10209 10208 int QCustomPlot::axisRectCount() const
10210 10209 {
10211 return axisRects().size();
10210 return axisRects().size();
10212 10211 }
10213 10212
10214 10213 /*!
@@ -10222,14 +10221,14 int QCustomPlot::axisRectCount() const
10222 10221 */
10223 10222 QCPAxisRect *QCustomPlot::axisRect(int index) const
10224 10223 {
10225 const QList<QCPAxisRect*> rectList = axisRects();
10226 if (index >= 0 && index < rectList.size())
10227 {
10228 return rectList.at(index);
10229 } else
10230 {
10231 qDebug() << Q_FUNC_INFO << "invalid axis rect index" << index;
10232 return 0;
10224 const QList<QCPAxisRect*> rectList = axisRects();
10225 if (index >= 0 && index < rectList.size())
10226 {
10227 return rectList.at(index);
10228 } else
10229 {
10230 qDebug() << Q_FUNC_INFO << "invalid axis rect index" << index;
10231 return 0;
10233 10232 }
10234 10233 }
10235 10234
@@ -10240,25 +10239,25 QCPAxisRect *QCustomPlot::axisRect(int i
10240 10239 */
10241 10240 QList<QCPAxisRect*> QCustomPlot::axisRects() const
10242 10241 {
10243 QList<QCPAxisRect*> result;
10244 QStack<QCPLayoutElement*> elementStack;
10245 if (mPlotLayout)
10246 elementStack.push(mPlotLayout);
10247
10248 while (!elementStack.isEmpty())
10249 {
10250 foreach (QCPLayoutElement *element, elementStack.pop()->elements(false))
10251 {
10252 if (element)
10253 {
10254 elementStack.push(element);
10255 if (QCPAxisRect *ar = qobject_cast<QCPAxisRect*>(element))
10256 result.append(ar);
10257 }
10258 }
10259 }
10260
10261 return result;
10242 QList<QCPAxisRect*> result;
10243 QStack<QCPLayoutElement*> elementStack;
10244 if (mPlotLayout)
10245 elementStack.push(mPlotLayout);
10246
10247 while (!elementStack.isEmpty())
10248 {
10249 foreach (QCPLayoutElement *element, elementStack.pop()->elements(false))
10250 {
10251 if (element)
10252 {
10253 elementStack.push(element);
10254 if (QCPAxisRect *ar = qobject_cast<QCPAxisRect*>(element))
10255 result.append(ar);
10256 }
10257 }
10258 }
10259
10260 return result;
10262 10261 }
10263 10262
10264 10263 /*!
@@ -10272,22 +10271,22 QList<QCPAxisRect*> QCustomPlot::axisRec
10272 10271 */
10273 10272 QCPLayoutElement *QCustomPlot::layoutElementAt(const QPointF &pos) const
10274 10273 {
10275 QCPLayoutElement *currentElement = mPlotLayout;
10276 bool searchSubElements = true;
10277 while (searchSubElements && currentElement)
10278 {
10279 searchSubElements = false;
10280 foreach (QCPLayoutElement *subElement, currentElement->elements(false))
10281 {
10282 if (subElement && subElement->realVisibility() && subElement->selectTest(pos, false) >= 0)
10283 {
10284 currentElement = subElement;
10285 searchSubElements = true;
10286 break;
10287 }
10288 }
10289 }
10290 return currentElement;
10274 QCPLayoutElement *currentElement = mPlotLayout;
10275 bool searchSubElements = true;
10276 while (searchSubElements && currentElement)
10277 {
10278 searchSubElements = false;
10279 foreach (QCPLayoutElement *subElement, currentElement->elements(false))
10280 {
10281 if (subElement && subElement->realVisibility() && subElement->selectTest(pos, false) >= 0)
10282 {
10283 currentElement = subElement;
10284 searchSubElements = true;
10285 break;
10286 }
10287 }
10288 }
10289 return currentElement;
10291 10290 }
10292 10291
10293 10292 /*!
@@ -10299,17 +10298,17 QCPLayoutElement *QCustomPlot::layoutEle
10299 10298 */
10300 10299 QList<QCPAxis*> QCustomPlot::selectedAxes() const
10301 10300 {
10302 QList<QCPAxis*> result, allAxes;
10303 foreach (QCPAxisRect *rect, axisRects())
10304 allAxes << rect->axes();
10305
10306 foreach (QCPAxis *axis, allAxes)
10307 {
10308 if (axis->selectedParts() != QCPAxis::spNone)
10309 result.append(axis);
10310 }
10311
10312 return result;
10301 QList<QCPAxis*> result, allAxes;
10302 foreach (QCPAxisRect *rect, axisRects())
10303 allAxes << rect->axes();
10304
10305 foreach (QCPAxis *axis, allAxes)
10306 {
10307 if (axis->selectedParts() != QCPAxis::spNone)
10308 result.append(axis);
10309 }
10310
10311 return result;
10313 10312 }
10314 10313
10315 10314 /*!
@@ -10321,29 +10320,29 QList<QCPAxis*> QCustomPlot::selectedAxe
10321 10320 */
10322 10321 QList<QCPLegend*> QCustomPlot::selectedLegends() const
10323 10322 {
10324 QList<QCPLegend*> result;
10325
10326 QStack<QCPLayoutElement*> elementStack;
10327 if (mPlotLayout)
10328 elementStack.push(mPlotLayout);
10329
10330 while (!elementStack.isEmpty())
10331 {
10332 foreach (QCPLayoutElement *subElement, elementStack.pop()->elements(false))
10333 {
10334 if (subElement)
10335 {
10336 elementStack.push(subElement);
10337 if (QCPLegend *leg = qobject_cast<QCPLegend*>(subElement))
10323 QList<QCPLegend*> result;
10324
10325 QStack<QCPLayoutElement*> elementStack;
10326 if (mPlotLayout)
10327 elementStack.push(mPlotLayout);
10328
10329 while (!elementStack.isEmpty())
10330 {
10331 foreach (QCPLayoutElement *subElement, elementStack.pop()->elements(false))
10332 {
10333 if (subElement)
10334 {
10335 elementStack.push(subElement);
10336 if (QCPLegend *leg = qobject_cast<QCPLegend*>(subElement))
10338 10337 {
10339 if (leg->selectedParts() != QCPLegend::spNone)
10340 result.append(leg);
10338 if (leg->selectedParts() != QCPLegend::spNone)
10339 result.append(leg);
10341 10340 }
10342 10341 }
10343 10342 }
10344 10343 }
10345
10346 return result;
10344
10345 return result;
10347 10346 }
10348 10347
10349 10348 /*!
@@ -10357,10 +10356,10 QList<QCPLegend*> QCustomPlot::selectedL
10357 10356 */
10358 10357 void QCustomPlot::deselectAll()
10359 10358 {
10360 foreach (QCPLayer *layer, mLayers)
10361 {
10362 foreach (QCPLayerable *layerable, layer->children())
10363 layerable->deselectEvent(0);
10359 foreach (QCPLayer *layer, mLayers)
10360 {
10361 foreach (QCPLayerable *layerable, layer->children())
10362 layerable->deselectEvent(0);
10364 10363 }
10365 10364 }
10366 10365
@@ -10379,30 +10378,30 void QCustomPlot::deselectAll()
10379 10378 */
10380 10379 void QCustomPlot::replot(QCustomPlot::RefreshPriority refreshPriority)
10381 10380 {
10382 if (mReplotting) // incase signals loop back to replot slot
10383 return;
10384 mReplotting = true;
10385 emit beforeReplot();
10386
10387 mPaintBuffer.fill(mBackgroundBrush.style() == Qt::SolidPattern ? mBackgroundBrush.color() : Qt::transparent);
10388 QCPPainter painter;
10389 painter.begin(&mPaintBuffer);
10390 if (painter.isActive())
10391 {
10392 painter.setRenderHint(QPainter::HighQualityAntialiasing); // to make Antialiasing look good if using the OpenGL graphicssystem
10393 if (mBackgroundBrush.style() != Qt::SolidPattern && mBackgroundBrush.style() != Qt::NoBrush)
10394 painter.fillRect(mViewport, mBackgroundBrush);
10395 draw(&painter);
10396 painter.end();
10397 if ((refreshPriority == rpHint && mPlottingHints.testFlag(QCP::phForceRepaint)) || refreshPriority==rpImmediate)
10398 repaint();
10399 else
10400 update();
10381 if (mReplotting) // incase signals loop back to replot slot
10382 return;
10383 mReplotting = true;
10384 emit beforeReplot();
10385
10386 mPaintBuffer.fill(mBackgroundBrush.style() == Qt::SolidPattern ? mBackgroundBrush.color() : Qt::transparent);
10387 QCPPainter painter;
10388 painter.begin(&mPaintBuffer);
10389 if (painter.isActive())
10390 {
10391 painter.setRenderHint(QPainter::HighQualityAntialiasing); // to make Antialiasing look good if using the OpenGL graphicssystem
10392 if (mBackgroundBrush.style() != Qt::SolidPattern && mBackgroundBrush.style() != Qt::NoBrush)
10393 painter.fillRect(mViewport, mBackgroundBrush);
10394 draw(&painter);
10395 painter.end();
10396 if ((refreshPriority == rpHint && mPlottingHints.testFlag(QCP::phForceRepaint)) || refreshPriority==rpImmediate)
10397 repaint();
10398 else
10399 update();
10401 10400 } else // might happen if QCustomPlot has width or height zero
10402 qDebug() << Q_FUNC_INFO << "Couldn't activate painter on buffer. This usually happens because QCustomPlot has width or height zero.";
10403
10404 emit afterReplot();
10405 mReplotting = false;
10401 qDebug() << Q_FUNC_INFO << "Couldn't activate painter on buffer. This usually happens because QCustomPlot has width or height zero.";
10402
10403 emit afterReplot();
10404 mReplotting = false;
10406 10405 }
10407 10406
10408 10407 /*!
@@ -10415,12 +10414,12 void QCustomPlot::replot(QCustomPlot::Re
10415 10414 */
10416 10415 void QCustomPlot::rescaleAxes(bool onlyVisiblePlottables)
10417 10416 {
10418 QList<QCPAxis*> allAxes;
10419 foreach (QCPAxisRect *rect, axisRects())
10420 allAxes << rect->axes();
10421
10422 foreach (QCPAxis *axis, allAxes)
10423 axis->rescale(onlyVisiblePlottables);
10417 QList<QCPAxis*> allAxes;
10418 foreach (QCPAxisRect *rect, axisRects())
10419 allAxes << rect->axes();
10420
10421 foreach (QCPAxis *axis, allAxes)
10422 axis->rescale(onlyVisiblePlottables);
10424 10423 }
10425 10424
10426 10425 /*!
@@ -10462,63 +10461,63 void QCustomPlot::rescaleAxes(bool onlyV
10462 10461 */
10463 10462 bool QCustomPlot::savePdf(const QString &fileName, bool noCosmeticPen, int width, int height, const QString &pdfCreator, const QString &pdfTitle)
10464 10463 {
10465 bool success = false;
10464 bool success = false;
10466 10465 #ifdef QT_NO_PRINTER
10467 Q_UNUSED(fileName)
10468 Q_UNUSED(noCosmeticPen)
10469 Q_UNUSED(width)
10470 Q_UNUSED(height)
10471 qDebug() << Q_FUNC_INFO << "Qt was built without printer support (QT_NO_PRINTER). PDF not created.";
10466 Q_UNUSED(fileName)
10467 Q_UNUSED(noCosmeticPen)
10468 Q_UNUSED(width)
10469 Q_UNUSED(height)
10470 qDebug() << Q_FUNC_INFO << "Qt was built without printer support (QT_NO_PRINTER). PDF not created.";
10472 10471 #else
10473 int newWidth, newHeight;
10474 if (width == 0 || height == 0)
10475 {
10476 newWidth = this->width();
10477 newHeight = this->height();
10478 } else
10479 {
10480 newWidth = width;
10481 newHeight = height;
10482 }
10483
10484 QPrinter printer(QPrinter::ScreenResolution);
10485 printer.setOutputFileName(fileName);
10486 printer.setOutputFormat(QPrinter::PdfFormat);
10487 printer.setColorMode(QPrinter::Color);
10488 printer.printEngine()->setProperty(QPrintEngine::PPK_Creator, pdfCreator);
10489 printer.printEngine()->setProperty(QPrintEngine::PPK_DocumentName, pdfTitle);
10490 QRect oldViewport = viewport();
10491 setViewport(QRect(0, 0, newWidth, newHeight));
10472 int newWidth, newHeight;
10473 if (width == 0 || height == 0)
10474 {
10475 newWidth = this->width();
10476 newHeight = this->height();
10477 } else
10478 {
10479 newWidth = width;
10480 newHeight = height;
10481 }
10482
10483 QPrinter printer(QPrinter::ScreenResolution);
10484 printer.setOutputFileName(fileName);
10485 printer.setOutputFormat(QPrinter::PdfFormat);
10486 printer.setColorMode(QPrinter::Color);
10487 printer.printEngine()->setProperty(QPrintEngine::PPK_Creator, pdfCreator);
10488 printer.printEngine()->setProperty(QPrintEngine::PPK_DocumentName, pdfTitle);
10489 QRect oldViewport = viewport();
10490 setViewport(QRect(0, 0, newWidth, newHeight));
10492 10491 #if QT_VERSION < QT_VERSION_CHECK(5, 3, 0)
10493 printer.setFullPage(true);
10494 printer.setPaperSize(viewport().size(), QPrinter::DevicePixel);
10492 printer.setFullPage(true);
10493 printer.setPaperSize(viewport().size(), QPrinter::DevicePixel);
10495 10494 #else
10496 QPageLayout pageLayout;
10497 pageLayout.setMode(QPageLayout::FullPageMode);
10498 pageLayout.setOrientation(QPageLayout::Portrait);
10499 pageLayout.setMargins(QMarginsF(0, 0, 0, 0));
10500 pageLayout.setPageSize(QPageSize(viewport().size(), QPageSize::Point, QString(), QPageSize::ExactMatch));
10501 printer.setPageLayout(pageLayout);
10495 QPageLayout pageLayout;
10496 pageLayout.setMode(QPageLayout::FullPageMode);
10497 pageLayout.setOrientation(QPageLayout::Portrait);
10498 pageLayout.setMargins(QMarginsF(0, 0, 0, 0));
10499 pageLayout.setPageSize(QPageSize(viewport().size(), QPageSize::Point, QString(), QPageSize::ExactMatch));
10500 printer.setPageLayout(pageLayout);
10502 10501 #endif
10503 QCPPainter printpainter;
10504 if (printpainter.begin(&printer))
10505 {
10506 printpainter.setMode(QCPPainter::pmVectorized);
10507 printpainter.setMode(QCPPainter::pmNoCaching);
10508 printpainter.setMode(QCPPainter::pmNonCosmetic, noCosmeticPen);
10509 printpainter.setWindow(mViewport);
10510 if (mBackgroundBrush.style() != Qt::NoBrush &&
10511 mBackgroundBrush.color() != Qt::white &&
10512 mBackgroundBrush.color() != Qt::transparent &&
10513 mBackgroundBrush.color().alpha() > 0) // draw pdf background color if not white/transparent
10514 printpainter.fillRect(viewport(), mBackgroundBrush);
10515 draw(&printpainter);
10516 printpainter.end();
10517 success = true;
10518 }
10519 setViewport(oldViewport);
10502 QCPPainter printpainter;
10503 if (printpainter.begin(&printer))
10504 {
10505 printpainter.setMode(QCPPainter::pmVectorized);
10506 printpainter.setMode(QCPPainter::pmNoCaching);
10507 printpainter.setMode(QCPPainter::pmNonCosmetic, noCosmeticPen);
10508 printpainter.setWindow(mViewport);
10509 if (mBackgroundBrush.style() != Qt::NoBrush &&
10510 mBackgroundBrush.color() != Qt::white &&
10511 mBackgroundBrush.color() != Qt::transparent &&
10512 mBackgroundBrush.color().alpha() > 0) // draw pdf background color if not white/transparent
10513 printpainter.fillRect(viewport(), mBackgroundBrush);
10514 draw(&printpainter);
10515 printpainter.end();
10516 success = true;
10517 }
10518 setViewport(oldViewport);
10520 10519 #endif // QT_NO_PRINTER
10521 return success;
10520 return success;
10522 10521 }
10523 10522
10524 10523 /*!
@@ -10560,7 +10559,7 bool QCustomPlot::savePdf(const QString
10560 10559 */
10561 10560 bool QCustomPlot::savePng(const QString &fileName, int width, int height, double scale, int quality)
10562 10561 {
10563 return saveRastered(fileName, width, height, scale, "PNG", quality);
10562 return saveRastered(fileName, width, height, scale, "PNG", quality);
10564 10563 }
10565 10564
10566 10565 /*!
@@ -10599,7 +10598,7 bool QCustomPlot::savePng(const QString
10599 10598 */
10600 10599 bool QCustomPlot::saveJpg(const QString &fileName, int width, int height, double scale, int quality)
10601 10600 {
10602 return saveRastered(fileName, width, height, scale, "JPG", quality);
10601 return saveRastered(fileName, width, height, scale, "JPG", quality);
10603 10602 }
10604 10603
10605 10604 /*!
@@ -10635,7 +10634,7 bool QCustomPlot::saveJpg(const QString
10635 10634 */
10636 10635 bool QCustomPlot::saveBmp(const QString &fileName, int width, int height, double scale)
10637 10636 {
10638 return saveRastered(fileName, width, height, scale, "BMP");
10637 return saveRastered(fileName, width, height, scale, "BMP");
10639 10638 }
10640 10639
10641 10640 /*! \internal
@@ -10648,7 +10647,7 bool QCustomPlot::saveBmp(const QString
10648 10647 */
10649 10648 QSize QCustomPlot::minimumSizeHint() const
10650 10649 {
10651 return mPlotLayout->minimumSizeHint();
10650 return mPlotLayout->minimumSizeHint();
10652 10651 }
10653 10652
10654 10653 /*! \internal
@@ -10658,7 +10657,7 QSize QCustomPlot::minimumSizeHint() con
10658 10657 */
10659 10658 QSize QCustomPlot::sizeHint() const
10660 10659 {
10661 return mPlotLayout->minimumSizeHint();
10660 return mPlotLayout->minimumSizeHint();
10662 10661 }
10663 10662
10664 10663 /*! \internal
@@ -10668,9 +10667,9 QSize QCustomPlot::sizeHint() const
10668 10667 */
10669 10668 void QCustomPlot::paintEvent(QPaintEvent *event)
10670 10669 {
10671 Q_UNUSED(event);
10672 QPainter painter(this);
10673 painter.drawPixmap(0, 0, mPaintBuffer);
10670 Q_UNUSED(event);
10671 QPainter painter(this);
10672 painter.drawPixmap(0, 0, mPaintBuffer);
10674 10673 }
10675 10674
10676 10675 /*! \internal
@@ -10681,17 +10680,10 void QCustomPlot::paintEvent(QPaintEvent
10681 10680 */
10682 10681 void QCustomPlot::resizeEvent(QResizeEvent *event)
10683 10682 {
10684 // resize and repaint the buffer:
10685 mPaintBuffer = QPixmap(event->size());
10686 setViewport(rect());
10687 replot(rpQueued); // queued update is important here, to prevent painting issues in some contexts
10688 // resize and repaint the buffer:
10689 // QSize pbSize = event->size();
10690 // pbSize *= devicePixelRatio();
10691 // mPaintBuffer = QPixmap(pbSize);
10692 // mPaintBuffer.setDevicePixelRatio(devicePixelRatio());
10693 // setViewport(rect());
10694 // replot(rpQueued); // queued update is important here, to prevent painting issues in some contexts
10683 // resize and repaint the buffer:
10684 mPaintBuffer = QPixmap(event->size());
10685 setViewport(rect());
10686 replot(rpQueued); // queued update is important here, to prevent painting issues in some contexts
10695 10687 }
10696 10688
10697 10689 /*! \internal
@@ -10705,37 +10697,37 void QCustomPlot::resizeEvent(QResizeEve
10705 10697 */
10706 10698 void QCustomPlot::mouseDoubleClickEvent(QMouseEvent *event)
10707 10699 {
10708 emit mouseDoubleClick(event);
10709
10710 QVariant details;
10711 QCPLayerable *clickedLayerable = layerableAt(event->pos(), false, &details);
10712
10713 // emit specialized object double click signals:
10714 if (QCPAbstractPlottable *ap = qobject_cast<QCPAbstractPlottable*>(clickedLayerable))
10715 emit plottableDoubleClick(ap, event);
10716 else if (QCPAxis *ax = qobject_cast<QCPAxis*>(clickedLayerable))
10717 emit axisDoubleClick(ax, details.value<QCPAxis::SelectablePart>(), event);
10718 else if (QCPAbstractItem *ai = qobject_cast<QCPAbstractItem*>(clickedLayerable))
10719 emit itemDoubleClick(ai, event);
10720 else if (QCPLegend *lg = qobject_cast<QCPLegend*>(clickedLayerable))
10721 emit legendDoubleClick(lg, 0, event);
10722 else if (QCPAbstractLegendItem *li = qobject_cast<QCPAbstractLegendItem*>(clickedLayerable))
10723 emit legendDoubleClick(li->parentLegend(), li, event);
10724 else if (QCPPlotTitle *pt = qobject_cast<QCPPlotTitle*>(clickedLayerable))
10725 emit titleDoubleClick(event, pt);
10726
10727 // call double click event of affected layout element:
10728 if (QCPLayoutElement *el = layoutElementAt(event->pos()))
10729 el->mouseDoubleClickEvent(event);
10730
10731 // call release event of affected layout element (as in mouseReleaseEvent, since the mouseDoubleClick replaces the second release event in double click case):
10732 if (mMouseEventElement)
10733 {
10734 mMouseEventElement->mouseReleaseEvent(event);
10735 mMouseEventElement = 0;
10736 }
10737
10738 //QWidget::mouseDoubleClickEvent(event); don't call base class implementation because it would just cause a mousePress/ReleaseEvent, which we don't want.
10700 emit mouseDoubleClick(event);
10701
10702 QVariant details;
10703 QCPLayerable *clickedLayerable = layerableAt(event->pos(), false, &details);
10704
10705 // emit specialized object double click signals:
10706 if (QCPAbstractPlottable *ap = qobject_cast<QCPAbstractPlottable*>(clickedLayerable))
10707 emit plottableDoubleClick(ap, event);
10708 else if (QCPAxis *ax = qobject_cast<QCPAxis*>(clickedLayerable))
10709 emit axisDoubleClick(ax, details.value<QCPAxis::SelectablePart>(), event);
10710 else if (QCPAbstractItem *ai = qobject_cast<QCPAbstractItem*>(clickedLayerable))
10711 emit itemDoubleClick(ai, event);
10712 else if (QCPLegend *lg = qobject_cast<QCPLegend*>(clickedLayerable))
10713 emit legendDoubleClick(lg, 0, event);
10714 else if (QCPAbstractLegendItem *li = qobject_cast<QCPAbstractLegendItem*>(clickedLayerable))
10715 emit legendDoubleClick(li->parentLegend(), li, event);
10716 else if (QCPPlotTitle *pt = qobject_cast<QCPPlotTitle*>(clickedLayerable))
10717 emit titleDoubleClick(event, pt);
10718
10719 // call double click event of affected layout element:
10720 if (QCPLayoutElement *el = layoutElementAt(event->pos()))
10721 el->mouseDoubleClickEvent(event);
10722
10723 // call release event of affected layout element (as in mouseReleaseEvent, since the mouseDoubleClick replaces the second release event in double click case):
10724 if (mMouseEventElement)
10725 {
10726 mMouseEventElement->mouseReleaseEvent(event);
10727 mMouseEventElement = 0;
10728 }
10729
10730 //QWidget::mouseDoubleClickEvent(event); don't call base class implementation because it would just cause a mousePress/ReleaseEvent, which we don't want.
10739 10731 }
10740 10732
10741 10733 /*! \internal
@@ -10747,15 +10739,15 void QCustomPlot::mouseDoubleClickEvent(
10747 10739 */
10748 10740 void QCustomPlot::mousePressEvent(QMouseEvent *event)
10749 10741 {
10750 emit mousePress(event);
10751 mMousePressPos = event->pos(); // need this to determine in releaseEvent whether it was a click (no position change between press and release)
10752
10753 // call event of affected layout element:
10754 mMouseEventElement = layoutElementAt(event->pos());
10755 if (mMouseEventElement)
10756 mMouseEventElement->mousePressEvent(event);
10757
10758 QWidget::mousePressEvent(event);
10742 emit mousePress(event);
10743 mMousePressPos = event->pos(); // need this to determine in releaseEvent whether it was a click (no position change between press and release)
10744
10745 // call event of affected layout element:
10746 mMouseEventElement = layoutElementAt(event->pos());
10747 if (mMouseEventElement)
10748 mMouseEventElement->mousePressEvent(event);
10749
10750 QWidget::mousePressEvent(event);
10759 10751 }
10760 10752
10761 10753 /*! \internal
@@ -10769,13 +10761,13 void QCustomPlot::mousePressEvent(QMouse
10769 10761 */
10770 10762 void QCustomPlot::mouseMoveEvent(QMouseEvent *event)
10771 10763 {
10772 emit mouseMove(event);
10773
10774 // call event of affected layout element:
10775 if (mMouseEventElement)
10776 mMouseEventElement->mouseMoveEvent(event);
10777
10778 QWidget::mouseMoveEvent(event);
10764 emit mouseMove(event);
10765
10766 // call event of affected layout element:
10767 if (mMouseEventElement)
10768 mMouseEventElement->mouseMoveEvent(event);
10769
10770 QWidget::mouseMoveEvent(event);
10779 10771 }
10780 10772
10781 10773 /*! \internal
@@ -10794,74 +10786,74 void QCustomPlot::mouseMoveEvent(QMouseE
10794 10786 */
10795 10787 void QCustomPlot::mouseReleaseEvent(QMouseEvent *event)
10796 10788 {
10797 emit mouseRelease(event);
10798 bool doReplot = false;
10799
10800 if ((mMousePressPos-event->pos()).manhattanLength() < 5) // determine whether it was a click operation
10801 {
10802 if (event->button() == Qt::LeftButton)
10803 {
10804 // handle selection mechanism:
10805 QVariant details;
10806 QCPLayerable *clickedLayerable = layerableAt(event->pos(), true, &details);
10807 bool selectionStateChanged = false;
10808 bool additive = mInteractions.testFlag(QCP::iMultiSelect) && event->modifiers().testFlag(mMultiSelectModifier);
10809 // deselect all other layerables if not additive selection:
10810 if (!additive)
10811 {
10812 foreach (QCPLayer *layer, mLayers)
10789 emit mouseRelease(event);
10790 bool doReplot = false;
10791
10792 if ((mMousePressPos-event->pos()).manhattanLength() < 5) // determine whether it was a click operation
10793 {
10794 if (event->button() == Qt::LeftButton)
10795 {
10796 // handle selection mechanism:
10797 QVariant details;
10798 QCPLayerable *clickedLayerable = layerableAt(event->pos(), true, &details);
10799 bool selectionStateChanged = false;
10800 bool additive = mInteractions.testFlag(QCP::iMultiSelect) && event->modifiers().testFlag(mMultiSelectModifier);
10801 // deselect all other layerables if not additive selection:
10802 if (!additive)
10803 {
10804 foreach (QCPLayer *layer, mLayers)
10813 10805 {
10814 foreach (QCPLayerable *layerable, layer->children())
10806 foreach (QCPLayerable *layerable, layer->children())
10815 10807 {
10816 if (layerable != clickedLayerable && mInteractions.testFlag(layerable->selectionCategory()))
10808 if (layerable != clickedLayerable && mInteractions.testFlag(layerable->selectionCategory()))
10817 10809 {
10818 bool selChanged = false;
10819 layerable->deselectEvent(&selChanged);
10820 selectionStateChanged |= selChanged;
10810 bool selChanged = false;
10811 layerable->deselectEvent(&selChanged);
10812 selectionStateChanged |= selChanged;
10821 10813 }
10822 10814 }
10823 10815 }
10824 10816 }
10825 if (clickedLayerable && mInteractions.testFlag(clickedLayerable->selectionCategory()))
10826 {
10827 // a layerable was actually clicked, call its selectEvent:
10828 bool selChanged = false;
10829 clickedLayerable->selectEvent(event, additive, details, &selChanged);
10830 selectionStateChanged |= selChanged;
10831 }
10832 doReplot = true;
10833 if (selectionStateChanged)
10834 emit selectionChangedByUser();
10835 }
10836
10837 // emit specialized object click signals:
10838 QVariant details;
10839 QCPLayerable *clickedLayerable = layerableAt(event->pos(), false, &details); // for these signals, selectability is ignored, that's why we call this again with onlySelectable set to false
10840 if (QCPAbstractPlottable *ap = qobject_cast<QCPAbstractPlottable*>(clickedLayerable))
10841 emit plottableClick(ap, event);
10842 else if (QCPAxis *ax = qobject_cast<QCPAxis*>(clickedLayerable))
10843 emit axisClick(ax, details.value<QCPAxis::SelectablePart>(), event);
10844 else if (QCPAbstractItem *ai = qobject_cast<QCPAbstractItem*>(clickedLayerable))
10845 emit itemClick(ai, event);
10846 else if (QCPLegend *lg = qobject_cast<QCPLegend*>(clickedLayerable))
10847 emit legendClick(lg, 0, event);
10848 else if (QCPAbstractLegendItem *li = qobject_cast<QCPAbstractLegendItem*>(clickedLayerable))
10849 emit legendClick(li->parentLegend(), li, event);
10850 else if (QCPPlotTitle *pt = qobject_cast<QCPPlotTitle*>(clickedLayerable))
10851 emit titleClick(event, pt);
10852 }
10853
10854 // call event of affected layout element:
10855 if (mMouseEventElement)
10856 {
10857 mMouseEventElement->mouseReleaseEvent(event);
10858 mMouseEventElement = 0;
10859 }
10860
10861 if (doReplot || noAntialiasingOnDrag())
10862 replot();
10863
10864 QWidget::mouseReleaseEvent(event);
10817 if (clickedLayerable && mInteractions.testFlag(clickedLayerable->selectionCategory()))
10818 {
10819 // a layerable was actually clicked, call its selectEvent:
10820 bool selChanged = false;
10821 clickedLayerable->selectEvent(event, additive, details, &selChanged);
10822 selectionStateChanged |= selChanged;
10823 }
10824 doReplot = true;
10825 if (selectionStateChanged)
10826 emit selectionChangedByUser();
10827 }
10828
10829 // emit specialized object click signals:
10830 QVariant details;
10831 QCPLayerable *clickedLayerable = layerableAt(event->pos(), false, &details); // for these signals, selectability is ignored, that's why we call this again with onlySelectable set to false
10832 if (QCPAbstractPlottable *ap = qobject_cast<QCPAbstractPlottable*>(clickedLayerable))
10833 emit plottableClick(ap, event);
10834 else if (QCPAxis *ax = qobject_cast<QCPAxis*>(clickedLayerable))
10835 emit axisClick(ax, details.value<QCPAxis::SelectablePart>(), event);
10836 else if (QCPAbstractItem *ai = qobject_cast<QCPAbstractItem*>(clickedLayerable))
10837 emit itemClick(ai, event);
10838 else if (QCPLegend *lg = qobject_cast<QCPLegend*>(clickedLayerable))
10839 emit legendClick(lg, 0, event);
10840 else if (QCPAbstractLegendItem *li = qobject_cast<QCPAbstractLegendItem*>(clickedLayerable))
10841 emit legendClick(li->parentLegend(), li, event);
10842 else if (QCPPlotTitle *pt = qobject_cast<QCPPlotTitle*>(clickedLayerable))
10843 emit titleClick(event, pt);
10844 }
10845
10846 // call event of affected layout element:
10847 if (mMouseEventElement)
10848 {
10849 mMouseEventElement->mouseReleaseEvent(event);
10850 mMouseEventElement = 0;
10851 }
10852
10853 if (doReplot || noAntialiasingOnDrag())
10854 replot();
10855
10856 QWidget::mouseReleaseEvent(event);
10865 10857 }
10866 10858
10867 10859 /*! \internal
@@ -10872,13 +10864,13 void QCustomPlot::mouseReleaseEvent(QMou
10872 10864 */
10873 10865 void QCustomPlot::wheelEvent(QWheelEvent *event)
10874 10866 {
10875 emit mouseWheel(event);
10876
10877 // call event of affected layout element:
10878 if (QCPLayoutElement *el = layoutElementAt(event->pos()))
10879 el->wheelEvent(event);
10880
10881 QWidget::wheelEvent(event);
10867 emit mouseWheel(event);
10868
10869 // call event of affected layout element:
10870 if (QCPLayoutElement *el = layoutElementAt(event->pos()))
10871 el->wheelEvent(event);
10872
10873 QWidget::wheelEvent(event);
10882 10874 }
10883 10875
10884 10876 /*! \internal
@@ -10890,31 +10882,31 void QCustomPlot::wheelEvent(QWheelEvent
10890 10882 */
10891 10883 void QCustomPlot::draw(QCPPainter *painter)
10892 10884 {
10893 // run through layout phases:
10894 mPlotLayout->update(QCPLayoutElement::upPreparation);
10895 mPlotLayout->update(QCPLayoutElement::upMargins);
10896 mPlotLayout->update(QCPLayoutElement::upLayout);
10897
10898 // draw viewport background pixmap:
10899 drawBackground(painter);
10900
10901 // draw all layered objects (grid, axes, plottables, items, legend,...):
10902 foreach (QCPLayer *layer, mLayers)
10903 {
10904 foreach (QCPLayerable *child, layer->children())
10905 {
10906 if (child->realVisibility())
10907 {
10908 painter->save();
10909 painter->setClipRect(child->clipRect().translated(0, -1));
10910 child->applyDefaultAntialiasingHint(painter);
10911 child->draw(painter);
10912 painter->restore();
10913 }
10914 }
10915 }
10916
10917 /* Debug code to draw all layout element rects
10885 // run through layout phases:
10886 mPlotLayout->update(QCPLayoutElement::upPreparation);
10887 mPlotLayout->update(QCPLayoutElement::upMargins);
10888 mPlotLayout->update(QCPLayoutElement::upLayout);
10889
10890 // draw viewport background pixmap:
10891 drawBackground(painter);
10892
10893 // draw all layered objects (grid, axes, plottables, items, legend,...):
10894 foreach (QCPLayer *layer, mLayers)
10895 {
10896 foreach (QCPLayerable *child, layer->children())
10897 {
10898 if (child->realVisibility())
10899 {
10900 painter->save();
10901 painter->setClipRect(child->clipRect().translated(0, -1));
10902 child->applyDefaultAntialiasingHint(painter);
10903 child->draw(painter);
10904 painter->restore();
10905 }
10906 }
10907 }
10908
10909 /* Debug code to draw all layout element rects
10918 10910 foreach (QCPLayoutElement* el, findChildren<QCPLayoutElement*>())
10919 10911 {
10920 10912 painter->setBrush(Qt::NoBrush);
@@ -10945,22 +10937,22 void QCustomPlot::draw(QCPPainter *paint
10945 10937 */
10946 10938 void QCustomPlot::drawBackground(QCPPainter *painter)
10947 10939 {
10948 // Note: background color is handled in individual replot/save functions
10949
10950 // draw background pixmap (on top of fill, if brush specified):
10951 if (!mBackgroundPixmap.isNull())
10952 {
10953 if (mBackgroundScaled)
10954 {
10955 // check whether mScaledBackground needs to be updated:
10956 QSize scaledSize(mBackgroundPixmap.size());
10957 scaledSize.scale(mViewport.size(), mBackgroundScaledMode);
10958 if (mScaledBackgroundPixmap.size() != scaledSize)
10959 mScaledBackgroundPixmap = mBackgroundPixmap.scaled(mViewport.size(), mBackgroundScaledMode, Qt::SmoothTransformation);
10960 painter->drawPixmap(mViewport.topLeft(), mScaledBackgroundPixmap, QRect(0, 0, mViewport.width(), mViewport.height()) & mScaledBackgroundPixmap.rect());
10940 // Note: background color is handled in individual replot/save functions
10941
10942 // draw background pixmap (on top of fill, if brush specified):
10943 if (!mBackgroundPixmap.isNull())
10944 {
10945 if (mBackgroundScaled)
10946 {
10947 // check whether mScaledBackground needs to be updated:
10948 QSize scaledSize(mBackgroundPixmap.size());
10949 scaledSize.scale(mViewport.size(), mBackgroundScaledMode);
10950 if (mScaledBackgroundPixmap.size() != scaledSize)
10951 mScaledBackgroundPixmap = mBackgroundPixmap.scaled(mViewport.size(), mBackgroundScaledMode, Qt::SmoothTransformation);
10952 painter->drawPixmap(mViewport.topLeft(), mScaledBackgroundPixmap, QRect(0, 0, mViewport.width(), mViewport.height()) & mScaledBackgroundPixmap.rect());
10961 10953 } else
10962 10954 {
10963 painter->drawPixmap(mViewport.topLeft(), mBackgroundPixmap, QRect(0, 0, mViewport.width(), mViewport.height()));
10955 painter->drawPixmap(mViewport.topLeft(), mBackgroundPixmap, QRect(0, 0, mViewport.width(), mViewport.height()));
10964 10956 }
10965 10957 }
10966 10958 }
@@ -10973,16 +10965,16 void QCustomPlot::drawBackground(QCPPain
10973 10965 */
10974 10966 void QCustomPlot::axisRemoved(QCPAxis *axis)
10975 10967 {
10976 if (xAxis == axis)
10977 xAxis = 0;
10978 if (xAxis2 == axis)
10979 xAxis2 = 0;
10980 if (yAxis == axis)
10981 yAxis = 0;
10982 if (yAxis2 == axis)
10983 yAxis2 = 0;
10984
10985 // Note: No need to take care of range drag axes and range zoom axes, because they are stored in smart pointers
10968 if (xAxis == axis)
10969 xAxis = 0;
10970 if (xAxis2 == axis)
10971 xAxis2 = 0;
10972 if (yAxis == axis)
10973 yAxis = 0;
10974 if (yAxis2 == axis)
10975 yAxis2 = 0;
10976
10977 // Note: No need to take care of range drag axes and range zoom axes, because they are stored in smart pointers
10986 10978 }
10987 10979
10988 10980 /*! \internal
@@ -10992,8 +10984,8 void QCustomPlot::axisRemoved(QCPAxis *a
10992 10984 */
10993 10985 void QCustomPlot::legendRemoved(QCPLegend *legend)
10994 10986 {
10995 if (this->legend == legend)
10996 this->legend = 0;
10987 if (this->legend == legend)
10988 this->legend = 0;
10997 10989 }
10998 10990
10999 10991 /*! \internal
@@ -11004,8 +10996,8 void QCustomPlot::legendRemoved(QCPLegen
11004 10996 */
11005 10997 void QCustomPlot::updateLayerIndices() const
11006 10998 {
11007 for (int i=0; i<mLayers.size(); ++i)
11008 mLayers.at(i)->mIndex = i;
10999 for (int i=0; i<mLayers.size(); ++i)
11000 mLayers.at(i)->mIndex = i;
11009 11001 }
11010 11002
11011 11003 /*! \internal
@@ -11022,28 +11014,28 void QCustomPlot::updateLayerIndices() c
11022 11014 */
11023 11015 QCPLayerable *QCustomPlot::layerableAt(const QPointF &pos, bool onlySelectable, QVariant *selectionDetails) const
11024 11016 {
11025 for (int layerIndex=mLayers.size()-1; layerIndex>=0; --layerIndex)
11026 {
11027 const QList<QCPLayerable*> layerables = mLayers.at(layerIndex)->children();
11028 double minimumDistance = selectionTolerance()*1.1;
11029 QCPLayerable *minimumDistanceLayerable = 0;
11030 for (int i=layerables.size()-1; i>=0; --i)
11031 {
11032 if (!layerables.at(i)->realVisibility())
11033 continue;
11034 QVariant details;
11035 double dist = layerables.at(i)->selectTest(pos, onlySelectable, &details);
11036 if (dist >= 0 && dist < minimumDistance)
11037 {
11038 minimumDistance = dist;
11039 minimumDistanceLayerable = layerables.at(i);
11040 if (selectionDetails) *selectionDetails = details;
11041 }
11042 }
11043 if (minimumDistance < selectionTolerance())
11044 return minimumDistanceLayerable;
11045 }
11046 return 0;
11017 for (int layerIndex=mLayers.size()-1; layerIndex>=0; --layerIndex)
11018 {
11019 const QList<QCPLayerable*> layerables = mLayers.at(layerIndex)->children();
11020 double minimumDistance = selectionTolerance()*1.1;
11021 QCPLayerable *minimumDistanceLayerable = 0;
11022 for (int i=layerables.size()-1; i>=0; --i)
11023 {
11024 if (!layerables.at(i)->realVisibility())
11025 continue;
11026 QVariant details;
11027 double dist = layerables.at(i)->selectTest(pos, onlySelectable, &details);
11028 if (dist >= 0 && dist < minimumDistance)
11029 {
11030 minimumDistance = dist;
11031 minimumDistanceLayerable = layerables.at(i);
11032 if (selectionDetails) *selectionDetails = details;
11033 }
11034 }
11035 if (minimumDistance < selectionTolerance())
11036 return minimumDistanceLayerable;
11037 }
11038 return 0;
11047 11039 }
11048 11040
11049 11041 /*!
@@ -11059,11 +11051,11 QCPLayerable *QCustomPlot::layerableAt(c
11059 11051 */
11060 11052 bool QCustomPlot::saveRastered(const QString &fileName, int width, int height, double scale, const char *format, int quality)
11061 11053 {
11062 QPixmap buffer = toPixmap(width, height, scale);
11063 if (!buffer.isNull())
11064 return buffer.save(fileName, format, quality);
11065 else
11066 return false;
11054 QPixmap buffer = toPixmap(width, height, scale);
11055 if (!buffer.isNull())
11056 return buffer.save(fileName, format, quality);
11057 else
11058 return false;
11067 11059 }
11068 11060
11069 11061 /*!
@@ -11076,46 +11068,46 bool QCustomPlot::saveRastered(const QSt
11076 11068 */
11077 11069 QPixmap QCustomPlot::toPixmap(int width, int height, double scale)
11078 11070 {
11079 // this method is somewhat similar to toPainter. Change something here, and a change in toPainter might be necessary, too.
11080 int newWidth, newHeight;
11081 if (width == 0 || height == 0)
11082 {
11083 newWidth = this->width();
11084 newHeight = this->height();
11085 } else
11086 {
11087 newWidth = width;
11088 newHeight = height;
11089 }
11090 int scaledWidth = qRound(scale*newWidth);
11091 int scaledHeight = qRound(scale*newHeight);
11092
11093 QPixmap result(scaledWidth, scaledHeight);
11094 result.fill(mBackgroundBrush.style() == Qt::SolidPattern ? mBackgroundBrush.color() : Qt::transparent); // if using non-solid pattern, make transparent now and draw brush pattern later
11095 QCPPainter painter;
11096 painter.begin(&result);
11097 if (painter.isActive())
11098 {
11099 QRect oldViewport = viewport();
11100 setViewport(QRect(0, 0, newWidth, newHeight));
11101 painter.setMode(QCPPainter::pmNoCaching);
11102 if (!qFuzzyCompare(scale, 1.0))
11103 {
11104 if (scale > 1.0) // for scale < 1 we always want cosmetic pens where possible, because else lines might disappear for very small scales
11105 painter.setMode(QCPPainter::pmNonCosmetic);
11106 painter.scale(scale, scale);
11107 }
11108 if (mBackgroundBrush.style() != Qt::SolidPattern && mBackgroundBrush.style() != Qt::NoBrush)
11109 painter.fillRect(mViewport, mBackgroundBrush);
11110 draw(&painter);
11111 setViewport(oldViewport);
11112 painter.end();
11071 // this method is somewhat similar to toPainter. Change something here, and a change in toPainter might be necessary, too.
11072 int newWidth, newHeight;
11073 if (width == 0 || height == 0)
11074 {
11075 newWidth = this->width();
11076 newHeight = this->height();
11077 } else
11078 {
11079 newWidth = width;
11080 newHeight = height;
11081 }
11082 int scaledWidth = qRound(scale*newWidth);
11083 int scaledHeight = qRound(scale*newHeight);
11084
11085 QPixmap result(scaledWidth, scaledHeight);
11086 result.fill(mBackgroundBrush.style() == Qt::SolidPattern ? mBackgroundBrush.color() : Qt::transparent); // if using non-solid pattern, make transparent now and draw brush pattern later
11087 QCPPainter painter;
11088 painter.begin(&result);
11089 if (painter.isActive())
11090 {
11091 QRect oldViewport = viewport();
11092 setViewport(QRect(0, 0, newWidth, newHeight));
11093 painter.setMode(QCPPainter::pmNoCaching);
11094 if (!qFuzzyCompare(scale, 1.0))
11095 {
11096 if (scale > 1.0) // for scale < 1 we always want cosmetic pens where possible, because else lines might disappear for very small scales
11097 painter.setMode(QCPPainter::pmNonCosmetic);
11098 painter.scale(scale, scale);
11099 }
11100 if (mBackgroundBrush.style() != Qt::SolidPattern && mBackgroundBrush.style() != Qt::NoBrush)
11101 painter.fillRect(mViewport, mBackgroundBrush);
11102 draw(&painter);
11103 setViewport(oldViewport);
11104 painter.end();
11113 11105 } else // might happen if pixmap has width or height zero
11114 11106 {
11115 qDebug() << Q_FUNC_INFO << "Couldn't activate painter on pixmap";
11116 return QPixmap();
11117 }
11118 return result;
11107 qDebug() << Q_FUNC_INFO << "Couldn't activate painter on pixmap";
11108 return QPixmap();
11109 }
11110 return result;
11119 11111 }
11120 11112
11121 11113 /*!
@@ -11132,31 +11124,31 QPixmap QCustomPlot::toPixmap(int width,
11132 11124 */
11133 11125 void QCustomPlot::toPainter(QCPPainter *painter, int width, int height)
11134 11126 {
11135 // this method is somewhat similar to toPixmap. Change something here, and a change in toPixmap might be necessary, too.
11136 int newWidth, newHeight;
11137 if (width == 0 || height == 0)
11138 {
11139 newWidth = this->width();
11140 newHeight = this->height();
11141 } else
11142 {
11143 newWidth = width;
11144 newHeight = height;
11145 }
11146
11147 if (painter->isActive())
11148 {
11149 QRect oldViewport = viewport();
11150 setViewport(QRect(0, 0, newWidth, newHeight));
11151 painter->setMode(QCPPainter::pmNoCaching);
11152 // warning: the following is different in toPixmap, because a solid background color is applied there via QPixmap::fill
11153 // here, we need to do this via QPainter::fillRect.
11154 if (mBackgroundBrush.style() != Qt::NoBrush)
11155 painter->fillRect(mViewport, mBackgroundBrush);
11156 draw(painter);
11157 setViewport(oldViewport);
11158 } else
11159 qDebug() << Q_FUNC_INFO << "Passed painter is not active";
11127 // this method is somewhat similar to toPixmap. Change something here, and a change in toPixmap might be necessary, too.
11128 int newWidth, newHeight;
11129 if (width == 0 || height == 0)
11130 {
11131 newWidth = this->width();
11132 newHeight = this->height();
11133 } else
11134 {
11135 newWidth = width;
11136 newHeight = height;
11137 }
11138
11139 if (painter->isActive())
11140 {
11141 QRect oldViewport = viewport();
11142 setViewport(QRect(0, 0, newWidth, newHeight));
11143 painter->setMode(QCPPainter::pmNoCaching);
11144 // warning: the following is different in toPixmap, because a solid background color is applied there via QPixmap::fill
11145 // here, we need to do this via QPainter::fillRect.
11146 if (mBackgroundBrush.style() != Qt::NoBrush)
11147 painter->fillRect(mViewport, mBackgroundBrush);
11148 draw(painter);
11149 setViewport(oldViewport);
11150 } else
11151 qDebug() << Q_FUNC_INFO << "Passed painter is not active";
11160 11152 }
11161 11153
11162 11154
@@ -11197,22 +11189,22 void QCustomPlot::toPainter(QCPPainter *
11197 11189 The color level count is initialized to 350.
11198 11190 */
11199 11191 QCPColorGradient::QCPColorGradient(GradientPreset preset) :
11200 mLevelCount(350),
11201 mColorInterpolation(ciRGB),
11202 mPeriodic(false),
11203 mColorBufferInvalidated(true)
11204 {
11205 mColorBuffer.fill(qRgb(0, 0, 0), mLevelCount);
11206 loadPreset(preset);
11192 mLevelCount(350),
11193 mColorInterpolation(ciRGB),
11194 mPeriodic(false),
11195 mColorBufferInvalidated(true)
11196 {
11197 mColorBuffer.fill(qRgb(0, 0, 0), mLevelCount);
11198 loadPreset(preset);
11207 11199 }
11208 11200
11209 11201 /* undocumented operator */
11210 11202 bool QCPColorGradient::operator==(const QCPColorGradient &other) const
11211 11203 {
11212 return ((other.mLevelCount == this->mLevelCount) &&
11213 (other.mColorInterpolation == this->mColorInterpolation) &&
11214 (other.mPeriodic == this->mPeriodic) &&
11215 (other.mColorStops == this->mColorStops));
11204 return ((other.mLevelCount == this->mLevelCount) &&
11205 (other.mColorInterpolation == this->mColorInterpolation) &&
11206 (other.mPeriodic == this->mPeriodic) &&
11207 (other.mColorStops == this->mColorStops));
11216 11208 }
11217 11209
11218 11210 /*!
@@ -11223,15 +11215,15 bool QCPColorGradient::operator==(const
11223 11215 */
11224 11216 void QCPColorGradient::setLevelCount(int n)
11225 11217 {
11226 if (n < 2)
11227 {
11228 qDebug() << Q_FUNC_INFO << "n must be greater or equal 2 but was" << n;
11229 n = 2;
11230 }
11231 if (n != mLevelCount)
11232 {
11233 mLevelCount = n;
11234 mColorBufferInvalidated = true;
11218 if (n < 2)
11219 {
11220 qDebug() << Q_FUNC_INFO << "n must be greater or equal 2 but was" << n;
11221 n = 2;
11222 }
11223 if (n != mLevelCount)
11224 {
11225 mLevelCount = n;
11226 mColorBufferInvalidated = true;
11235 11227 }
11236 11228 }
11237 11229
@@ -11247,8 +11239,8 void QCPColorGradient::setLevelCount(int
11247 11239 */
11248 11240 void QCPColorGradient::setColorStops(const QMap<double, QColor> &colorStops)
11249 11241 {
11250 mColorStops = colorStops;
11251 mColorBufferInvalidated = true;
11242 mColorStops = colorStops;
11243 mColorBufferInvalidated = true;
11252 11244 }
11253 11245
11254 11246 /*!
@@ -11259,8 +11251,8 void QCPColorGradient::setColorStops(con
11259 11251 */
11260 11252 void QCPColorGradient::setColorStopAt(double position, const QColor &color)
11261 11253 {
11262 mColorStops.insert(position, color);
11263 mColorBufferInvalidated = true;
11254 mColorStops.insert(position, color);
11255 mColorBufferInvalidated = true;
11264 11256 }
11265 11257
11266 11258 /*!
@@ -11272,10 +11264,10 void QCPColorGradient::setColorStopAt(do
11272 11264 */
11273 11265 void QCPColorGradient::setColorInterpolation(QCPColorGradient::ColorInterpolation interpolation)
11274 11266 {
11275 if (interpolation != mColorInterpolation)
11276 {
11277 mColorInterpolation = interpolation;
11278 mColorBufferInvalidated = true;
11267 if (interpolation != mColorInterpolation)
11268 {
11269 mColorInterpolation = interpolation;
11270 mColorBufferInvalidated = true;
11279 11271 }
11280 11272 }
11281 11273
@@ -11296,7 +11288,7 void QCPColorGradient::setColorInterpola
11296 11288 */
11297 11289 void QCPColorGradient::setPeriodic(bool enabled)
11298 11290 {
11299 mPeriodic = enabled;
11291 mPeriodic = enabled;
11300 11292 }
11301 11293
11302 11294 /*!
@@ -11313,65 +11305,65 void QCPColorGradient::setPeriodic(bool
11313 11305 */
11314 11306 void QCPColorGradient::colorize(const double *data, const QCPRange &range, QRgb *scanLine, int n, int dataIndexFactor, bool logarithmic)
11315 11307 {
11316 // If you change something here, make sure to also adapt ::color()
11317 if (!data)
11318 {
11319 qDebug() << Q_FUNC_INFO << "null pointer given as data";
11320 return;
11321 }
11322 if (!scanLine)
11323 {
11324 qDebug() << Q_FUNC_INFO << "null pointer given as scanLine";
11325 return;
11326 }
11327 if (mColorBufferInvalidated)
11328 updateColorBuffer();
11329
11330 if (!logarithmic)
11331 {
11332 const double posToIndexFactor = (mLevelCount-1)/range.size();
11333 if (mPeriodic)
11334 {
11335 for (int i=0; i<n; ++i)
11336 {
11337 int index = (int)((data[dataIndexFactor*i]-range.lower)*posToIndexFactor) % mLevelCount;
11338 if (index < 0)
11339 index += mLevelCount;
11340 scanLine[i] = mColorBuffer.at(index);
11308 // If you change something here, make sure to also adapt ::color()
11309 if (!data)
11310 {
11311 qDebug() << Q_FUNC_INFO << "null pointer given as data";
11312 return;
11313 }
11314 if (!scanLine)
11315 {
11316 qDebug() << Q_FUNC_INFO << "null pointer given as scanLine";
11317 return;
11318 }
11319 if (mColorBufferInvalidated)
11320 updateColorBuffer();
11321
11322 if (!logarithmic)
11323 {
11324 const double posToIndexFactor = (mLevelCount-1)/range.size();
11325 if (mPeriodic)
11326 {
11327 for (int i=0; i<n; ++i)
11328 {
11329 int index = (int)((data[dataIndexFactor*i]-range.lower)*posToIndexFactor) % mLevelCount;
11330 if (index < 0)
11331 index += mLevelCount;
11332 scanLine[i] = mColorBuffer.at(index);
11341 11333 }
11342 11334 } else
11343 11335 {
11344 for (int i=0; i<n; ++i)
11345 {
11346 int index = (data[dataIndexFactor*i]-range.lower)*posToIndexFactor;
11347 if (index < 0)
11348 index = 0;
11349 else if (index >= mLevelCount)
11350 index = mLevelCount-1;
11351 scanLine[i] = mColorBuffer.at(index);
11336 for (int i=0; i<n; ++i)
11337 {
11338 int index = (data[dataIndexFactor*i]-range.lower)*posToIndexFactor;
11339 if (index < 0)
11340 index = 0;
11341 else if (index >= mLevelCount)
11342 index = mLevelCount-1;
11343 scanLine[i] = mColorBuffer.at(index);
11352 11344 }
11353 11345 }
11354 11346 } else // logarithmic == true
11355 11347 {
11356 if (mPeriodic)
11357 {
11358 for (int i=0; i<n; ++i)
11359 {
11360 int index = (int)(qLn(data[dataIndexFactor*i]/range.lower)/qLn(range.upper/range.lower)*(mLevelCount-1)) % mLevelCount;
11361 if (index < 0)
11362 index += mLevelCount;
11363 scanLine[i] = mColorBuffer.at(index);
11348 if (mPeriodic)
11349 {
11350 for (int i=0; i<n; ++i)
11351 {
11352 int index = (int)(qLn(data[dataIndexFactor*i]/range.lower)/qLn(range.upper/range.lower)*(mLevelCount-1)) % mLevelCount;
11353 if (index < 0)
11354 index += mLevelCount;
11355 scanLine[i] = mColorBuffer.at(index);
11364 11356 }
11365 11357 } else
11366 11358 {
11367 for (int i=0; i<n; ++i)
11368 {
11369 int index = qLn(data[dataIndexFactor*i]/range.lower)/qLn(range.upper/range.lower)*(mLevelCount-1);
11370 if (index < 0)
11371 index = 0;
11372 else if (index >= mLevelCount)
11373 index = mLevelCount-1;
11374 scanLine[i] = mColorBuffer.at(index);
11359 for (int i=0; i<n; ++i)
11360 {
11361 int index = qLn(data[dataIndexFactor*i]/range.lower)/qLn(range.upper/range.lower)*(mLevelCount-1);
11362 if (index < 0)
11363 index = 0;
11364 else if (index >= mLevelCount)
11365 index = mLevelCount-1;
11366 scanLine[i] = mColorBuffer.at(index);
11375 11367 }
11376 11368 }
11377 11369 }
@@ -11388,27 +11380,27 void QCPColorGradient::colorize(const do
11388 11380 */
11389 11381 QRgb QCPColorGradient::color(double position, const QCPRange &range, bool logarithmic)
11390 11382 {
11391 // If you change something here, make sure to also adapt ::colorize()
11392 if (mColorBufferInvalidated)
11393 updateColorBuffer();
11394 int index = 0;
11395 if (!logarithmic)
11396 index = (position-range.lower)*(mLevelCount-1)/range.size();
11397 else
11398 index = qLn(position/range.lower)/qLn(range.upper/range.lower)*(mLevelCount-1);
11399 if (mPeriodic)
11400 {
11401 index = index % mLevelCount;
11402 if (index < 0)
11403 index += mLevelCount;
11404 } else
11405 {
11406 if (index < 0)
11407 index = 0;
11408 else if (index >= mLevelCount)
11409 index = mLevelCount-1;
11410 }
11411 return mColorBuffer.at(index);
11383 // If you change something here, make sure to also adapt ::colorize()
11384 if (mColorBufferInvalidated)
11385 updateColorBuffer();
11386 int index = 0;
11387 if (!logarithmic)
11388 index = (position-range.lower)*(mLevelCount-1)/range.size();
11389 else
11390 index = qLn(position/range.lower)/qLn(range.upper/range.lower)*(mLevelCount-1);
11391 if (mPeriodic)
11392 {
11393 index = index % mLevelCount;
11394 if (index < 0)
11395 index += mLevelCount;
11396 } else
11397 {
11398 if (index < 0)
11399 index = 0;
11400 else if (index >= mLevelCount)
11401 index = mLevelCount-1;
11402 }
11403 return mColorBuffer.at(index);
11412 11404 }
11413 11405
11414 11406 /*!
@@ -11420,105 +11412,105 QRgb QCPColorGradient::color(double posi
11420 11412 */
11421 11413 void QCPColorGradient::loadPreset(GradientPreset preset)
11422 11414 {
11423 clearColorStops();
11424 switch (preset)
11415 clearColorStops();
11416 switch (preset)
11425 11417 {
11426 11418 case gpGrayscale:
11427 setColorInterpolation(ciRGB);
11428 setColorStopAt(0, Qt::black);
11429 setColorStopAt(1, Qt::white);
11430 break;
11419 setColorInterpolation(ciRGB);
11420 setColorStopAt(0, Qt::black);
11421 setColorStopAt(1, Qt::white);
11422 break;
11431 11423 case gpHot:
11432 setColorInterpolation(ciRGB);
11433 setColorStopAt(0, QColor(50, 0, 0));
11434 setColorStopAt(0.2, QColor(180, 10, 0));
11435 setColorStopAt(0.4, QColor(245, 50, 0));
11436 setColorStopAt(0.6, QColor(255, 150, 10));
11437 setColorStopAt(0.8, QColor(255, 255, 50));
11438 setColorStopAt(1, QColor(255, 255, 255));
11439 break;
11424 setColorInterpolation(ciRGB);
11425 setColorStopAt(0, QColor(50, 0, 0));
11426 setColorStopAt(0.2, QColor(180, 10, 0));
11427 setColorStopAt(0.4, QColor(245, 50, 0));
11428 setColorStopAt(0.6, QColor(255, 150, 10));
11429 setColorStopAt(0.8, QColor(255, 255, 50));
11430 setColorStopAt(1, QColor(255, 255, 255));
11431 break;
11440 11432 case gpCold:
11441 setColorInterpolation(ciRGB);
11442 setColorStopAt(0, QColor(0, 0, 50));
11443 setColorStopAt(0.2, QColor(0, 10, 180));
11444 setColorStopAt(0.4, QColor(0, 50, 245));
11445 setColorStopAt(0.6, QColor(10, 150, 255));
11446 setColorStopAt(0.8, QColor(50, 255, 255));
11447 setColorStopAt(1, QColor(255, 255, 255));
11448 break;
11433 setColorInterpolation(ciRGB);
11434 setColorStopAt(0, QColor(0, 0, 50));
11435 setColorStopAt(0.2, QColor(0, 10, 180));
11436 setColorStopAt(0.4, QColor(0, 50, 245));
11437 setColorStopAt(0.6, QColor(10, 150, 255));
11438 setColorStopAt(0.8, QColor(50, 255, 255));
11439 setColorStopAt(1, QColor(255, 255, 255));
11440 break;
11449 11441 case gpNight:
11450 setColorInterpolation(ciHSV);
11451 setColorStopAt(0, QColor(10, 20, 30));
11452 setColorStopAt(1, QColor(250, 255, 250));
11453 break;
11442 setColorInterpolation(ciHSV);
11443 setColorStopAt(0, QColor(10, 20, 30));
11444 setColorStopAt(1, QColor(250, 255, 250));
11445 break;
11454 11446 case gpCandy:
11455 setColorInterpolation(ciHSV);
11456 setColorStopAt(0, QColor(0, 0, 255));
11457 setColorStopAt(1, QColor(255, 250, 250));
11458 break;
11447 setColorInterpolation(ciHSV);
11448 setColorStopAt(0, QColor(0, 0, 255));
11449 setColorStopAt(1, QColor(255, 250, 250));
11450 break;
11459 11451 case gpGeography:
11460 setColorInterpolation(ciRGB);
11461 setColorStopAt(0, QColor(70, 170, 210));
11462 setColorStopAt(0.20, QColor(90, 160, 180));
11463 setColorStopAt(0.25, QColor(45, 130, 175));
11464 setColorStopAt(0.30, QColor(100, 140, 125));
11465 setColorStopAt(0.5, QColor(100, 140, 100));
11466 setColorStopAt(0.6, QColor(130, 145, 120));
11467 setColorStopAt(0.7, QColor(140, 130, 120));
11468 setColorStopAt(0.9, QColor(180, 190, 190));
11469 setColorStopAt(1, QColor(210, 210, 230));
11470 break;
11452 setColorInterpolation(ciRGB);
11453 setColorStopAt(0, QColor(70, 170, 210));
11454 setColorStopAt(0.20, QColor(90, 160, 180));
11455 setColorStopAt(0.25, QColor(45, 130, 175));
11456 setColorStopAt(0.30, QColor(100, 140, 125));
11457 setColorStopAt(0.5, QColor(100, 140, 100));
11458 setColorStopAt(0.6, QColor(130, 145, 120));
11459 setColorStopAt(0.7, QColor(140, 130, 120));
11460 setColorStopAt(0.9, QColor(180, 190, 190));
11461 setColorStopAt(1, QColor(210, 210, 230));
11462 break;
11471 11463 case gpIon:
11472 setColorInterpolation(ciHSV);
11473 setColorStopAt(0, QColor(50, 10, 10));
11474 setColorStopAt(0.45, QColor(0, 0, 255));
11475 setColorStopAt(0.8, QColor(0, 255, 255));
11476 setColorStopAt(1, QColor(0, 255, 0));
11477 break;
11464 setColorInterpolation(ciHSV);
11465 setColorStopAt(0, QColor(50, 10, 10));
11466 setColorStopAt(0.45, QColor(0, 0, 255));
11467 setColorStopAt(0.8, QColor(0, 255, 255));
11468 setColorStopAt(1, QColor(0, 255, 0));
11469 break;
11478 11470 case gpThermal:
11479 setColorInterpolation(ciRGB);
11480 setColorStopAt(0, QColor(0, 0, 50));
11481 setColorStopAt(0.15, QColor(20, 0, 120));
11482 setColorStopAt(0.33, QColor(200, 30, 140));
11483 setColorStopAt(0.6, QColor(255, 100, 0));
11484 setColorStopAt(0.85, QColor(255, 255, 40));
11485 setColorStopAt(1, QColor(255, 255, 255));
11486 break;
11471 setColorInterpolation(ciRGB);
11472 setColorStopAt(0, QColor(0, 0, 50));
11473 setColorStopAt(0.15, QColor(20, 0, 120));
11474 setColorStopAt(0.33, QColor(200, 30, 140));
11475 setColorStopAt(0.6, QColor(255, 100, 0));
11476 setColorStopAt(0.85, QColor(255, 255, 40));
11477 setColorStopAt(1, QColor(255, 255, 255));
11478 break;
11487 11479 case gpPolar:
11488 setColorInterpolation(ciRGB);
11489 setColorStopAt(0, QColor(50, 255, 255));
11490 setColorStopAt(0.18, QColor(10, 70, 255));
11491 setColorStopAt(0.28, QColor(10, 10, 190));
11492 setColorStopAt(0.5, QColor(0, 0, 0));
11493 setColorStopAt(0.72, QColor(190, 10, 10));
11494 setColorStopAt(0.82, QColor(255, 70, 10));
11495 setColorStopAt(1, QColor(255, 255, 50));
11496 break;
11480 setColorInterpolation(ciRGB);
11481 setColorStopAt(0, QColor(50, 255, 255));
11482 setColorStopAt(0.18, QColor(10, 70, 255));
11483 setColorStopAt(0.28, QColor(10, 10, 190));
11484 setColorStopAt(0.5, QColor(0, 0, 0));
11485 setColorStopAt(0.72, QColor(190, 10, 10));
11486 setColorStopAt(0.82, QColor(255, 70, 10));
11487 setColorStopAt(1, QColor(255, 255, 50));
11488 break;
11497 11489 case gpSpectrum:
11498 setColorInterpolation(ciHSV);
11499 setColorStopAt(0, QColor(50, 0, 50));
11500 setColorStopAt(0.15, QColor(0, 0, 255));
11501 setColorStopAt(0.35, QColor(0, 255, 255));
11502 setColorStopAt(0.6, QColor(255, 255, 0));
11503 setColorStopAt(0.75, QColor(255, 30, 0));
11504 setColorStopAt(1, QColor(50, 0, 0));
11505 break;
11490 setColorInterpolation(ciHSV);
11491 setColorStopAt(0, QColor(50, 0, 50));
11492 setColorStopAt(0.15, QColor(0, 0, 255));
11493 setColorStopAt(0.35, QColor(0, 255, 255));
11494 setColorStopAt(0.6, QColor(255, 255, 0));
11495 setColorStopAt(0.75, QColor(255, 30, 0));
11496 setColorStopAt(1, QColor(50, 0, 0));
11497 break;
11506 11498 case gpJet:
11507 setColorInterpolation(ciRGB);
11508 setColorStopAt(0, QColor(0, 0, 100));
11509 setColorStopAt(0.15, QColor(0, 50, 255));
11510 setColorStopAt(0.35, QColor(0, 255, 255));
11511 setColorStopAt(0.65, QColor(255, 255, 0));
11512 setColorStopAt(0.85, QColor(255, 30, 0));
11513 setColorStopAt(1, QColor(100, 0, 0));
11514 break;
11499 setColorInterpolation(ciRGB);
11500 setColorStopAt(0, QColor(0, 0, 100));
11501 setColorStopAt(0.15, QColor(0, 50, 255));
11502 setColorStopAt(0.35, QColor(0, 255, 255));
11503 setColorStopAt(0.65, QColor(255, 255, 0));
11504 setColorStopAt(0.85, QColor(255, 30, 0));
11505 setColorStopAt(1, QColor(100, 0, 0));
11506 break;
11515 11507 case gpHues:
11516 setColorInterpolation(ciHSV);
11517 setColorStopAt(0, QColor(255, 0, 0));
11518 setColorStopAt(1.0/3.0, QColor(0, 0, 255));
11519 setColorStopAt(2.0/3.0, QColor(0, 255, 0));
11520 setColorStopAt(1, QColor(255, 0, 0));
11521 break;
11508 setColorInterpolation(ciHSV);
11509 setColorStopAt(0, QColor(255, 0, 0));
11510 setColorStopAt(1.0/3.0, QColor(0, 0, 255));
11511 setColorStopAt(2.0/3.0, QColor(0, 255, 0));
11512 setColorStopAt(1, QColor(255, 0, 0));
11513 break;
11522 11514 }
11523 11515 }
11524 11516
@@ -11529,8 +11521,8 void QCPColorGradient::loadPreset(Gradie
11529 11521 */
11530 11522 void QCPColorGradient::clearColorStops()
11531 11523 {
11532 mColorStops.clear();
11533 mColorBufferInvalidated = true;
11524 mColorStops.clear();
11525 mColorBufferInvalidated = true;
11534 11526 }
11535 11527
11536 11528 /*!
@@ -11541,11 +11533,11 void QCPColorGradient::clearColorStops()
11541 11533 */
11542 11534 QCPColorGradient QCPColorGradient::inverted() const
11543 11535 {
11544 QCPColorGradient result(*this);
11545 result.clearColorStops();
11546 for (QMap<double, QColor>::const_iterator it=mColorStops.constBegin(); it!=mColorStops.constEnd(); ++it)
11547 result.setColorStopAt(1.0-it.key(), it.value());
11548 return result;
11536 QCPColorGradient result(*this);
11537 result.clearColorStops();
11538 for (QMap<double, QColor>::const_iterator it=mColorStops.constBegin(); it!=mColorStops.constEnd(); ++it)
11539 result.setColorStopAt(1.0-it.key(), it.value());
11540 return result;
11549 11541 }
11550 11542
11551 11543 /*! \internal
@@ -11555,63 +11547,63 QCPColorGradient QCPColorGradient::inver
11555 11547 */
11556 11548 void QCPColorGradient::updateColorBuffer()
11557 11549 {
11558 if (mColorBuffer.size() != mLevelCount)
11559 mColorBuffer.resize(mLevelCount);
11560 if (mColorStops.size() > 1)
11561 {
11562 double indexToPosFactor = 1.0/(double)(mLevelCount-1);
11563 for (int i=0; i<mLevelCount; ++i)
11564 {
11565 double position = i*indexToPosFactor;
11566 QMap<double, QColor>::const_iterator it = mColorStops.lowerBound(position);
11567 if (it == mColorStops.constEnd()) // position is on or after last stop, use color of last stop
11568 {
11569 mColorBuffer[i] = (it-1).value().rgb();
11550 if (mColorBuffer.size() != mLevelCount)
11551 mColorBuffer.resize(mLevelCount);
11552 if (mColorStops.size() > 1)
11553 {
11554 double indexToPosFactor = 1.0/(double)(mLevelCount-1);
11555 for (int i=0; i<mLevelCount; ++i)
11556 {
11557 double position = i*indexToPosFactor;
11558 QMap<double, QColor>::const_iterator it = mColorStops.lowerBound(position);
11559 if (it == mColorStops.constEnd()) // position is on or after last stop, use color of last stop
11560 {
11561 mColorBuffer[i] = (it-1).value().rgb();
11570 11562 } else if (it == mColorStops.constBegin()) // position is on or before first stop, use color of first stop
11571 11563 {
11572 mColorBuffer[i] = it.value().rgb();
11564 mColorBuffer[i] = it.value().rgb();
11573 11565 } else // position is in between stops (or on an intermediate stop), interpolate color
11574 11566 {
11575 QMap<double, QColor>::const_iterator high = it;
11576 QMap<double, QColor>::const_iterator low = it-1;
11577 double t = (position-low.key())/(high.key()-low.key()); // interpolation factor 0..1
11578 switch (mColorInterpolation)
11567 QMap<double, QColor>::const_iterator high = it;
11568 QMap<double, QColor>::const_iterator low = it-1;
11569 double t = (position-low.key())/(high.key()-low.key()); // interpolation factor 0..1
11570 switch (mColorInterpolation)
11579 11571 {
11580 11572 case ciRGB:
11581 {
11573 {
11582 11574 mColorBuffer[i] = qRgb((1-t)*low.value().red() + t*high.value().red(),
11583 11575 (1-t)*low.value().green() + t*high.value().green(),
11584 11576 (1-t)*low.value().blue() + t*high.value().blue());
11585 11577 break;
11586 }
11578 }
11587 11579 case ciHSV:
11588 {
11580 {
11589 11581 QColor lowHsv = low.value().toHsv();
11590 11582 QColor highHsv = high.value().toHsv();
11591 11583 double hue = 0;
11592 11584 double hueDiff = highHsv.hueF()-lowHsv.hueF();
11593 11585 if (hueDiff > 0.5)
11594 hue = lowHsv.hueF() - t*(1.0-hueDiff);
11586 hue = lowHsv.hueF() - t*(1.0-hueDiff);
11595 11587 else if (hueDiff < -0.5)
11596 hue = lowHsv.hueF() + t*(1.0+hueDiff);
11588 hue = lowHsv.hueF() + t*(1.0+hueDiff);
11597 11589 else
11598 hue = lowHsv.hueF() + t*hueDiff;
11590 hue = lowHsv.hueF() + t*hueDiff;
11599 11591 if (hue < 0) hue += 1.0;
11600 11592 else if (hue >= 1.0) hue -= 1.0;
11601 11593 mColorBuffer[i] = QColor::fromHsvF(hue, (1-t)*lowHsv.saturationF() + t*highHsv.saturationF(), (1-t)*lowHsv.valueF() + t*highHsv.valueF()).rgb();
11602 11594 break;
11603 }
11595 }
11604 11596 }
11605 11597 }
11606 11598 }
11607 11599 } else if (mColorStops.size() == 1)
11608 11600 {
11609 mColorBuffer.fill(mColorStops.constBegin().value().rgb());
11601 mColorBuffer.fill(mColorStops.constBegin().value().rgb());
11610 11602 } else // mColorStops is empty, fill color buffer with black
11611 11603 {
11612 mColorBuffer.fill(qRgb(0, 0, 0));
11613 }
11614 mColorBufferInvalidated = false;
11604 mColorBuffer.fill(qRgb(0, 0, 0));
11605 }
11606 mColorBufferInvalidated = false;
11615 11607 }
11616 11608
11617 11609
@@ -11745,57 +11737,57 void QCPColorGradient::updateColorBuffer
11745 11737 sides, the top and right axes are set invisible initially.
11746 11738 */
11747 11739 QCPAxisRect::QCPAxisRect(QCustomPlot *parentPlot, bool setupDefaultAxes) :
11748 QCPLayoutElement(parentPlot),
11749 mBackgroundBrush(Qt::NoBrush),
11750 mBackgroundScaled(true),
11751 mBackgroundScaledMode(Qt::KeepAspectRatioByExpanding),
11752 mInsetLayout(new QCPLayoutInset),
11753 mRangeDrag(Qt::Horizontal|Qt::Vertical),
11754 mRangeZoom(Qt::Horizontal|Qt::Vertical),
11755 mRangeZoomFactorHorz(0.85),
11756 mRangeZoomFactorVert(0.85),
11757 mDragging(false)
11758 {
11759 mInsetLayout->initializeParentPlot(mParentPlot);
11760 mInsetLayout->setParentLayerable(this);
11761 mInsetLayout->setParent(this);
11762
11763 setMinimumSize(50, 50);
11764 setMinimumMargins(QMargins(15, 15, 15, 15));
11765 mAxes.insert(QCPAxis::atLeft, QList<QCPAxis*>());
11766 mAxes.insert(QCPAxis::atRight, QList<QCPAxis*>());
11767 mAxes.insert(QCPAxis::atTop, QList<QCPAxis*>());
11768 mAxes.insert(QCPAxis::atBottom, QList<QCPAxis*>());
11769
11770 if (setupDefaultAxes)
11771 {
11772 QCPAxis *xAxis = addAxis(QCPAxis::atBottom);
11773 QCPAxis *yAxis = addAxis(QCPAxis::atLeft);
11774 QCPAxis *xAxis2 = addAxis(QCPAxis::atTop);
11775 QCPAxis *yAxis2 = addAxis(QCPAxis::atRight);
11776 setRangeDragAxes(xAxis, yAxis);
11777 setRangeZoomAxes(xAxis, yAxis);
11778 xAxis2->setVisible(false);
11779 yAxis2->setVisible(false);
11780 xAxis->grid()->setVisible(true);
11781 yAxis->grid()->setVisible(true);
11782 xAxis2->grid()->setVisible(false);
11783 yAxis2->grid()->setVisible(false);
11784 xAxis2->grid()->setZeroLinePen(Qt::NoPen);
11785 yAxis2->grid()->setZeroLinePen(Qt::NoPen);
11786 xAxis2->grid()->setVisible(false);
11787 yAxis2->grid()->setVisible(false);
11740 QCPLayoutElement(parentPlot),
11741 mBackgroundBrush(Qt::NoBrush),
11742 mBackgroundScaled(true),
11743 mBackgroundScaledMode(Qt::KeepAspectRatioByExpanding),
11744 mInsetLayout(new QCPLayoutInset),
11745 mRangeDrag(Qt::Horizontal|Qt::Vertical),
11746 mRangeZoom(Qt::Horizontal|Qt::Vertical),
11747 mRangeZoomFactorHorz(0.85),
11748 mRangeZoomFactorVert(0.85),
11749 mDragging(false)
11750 {
11751 mInsetLayout->initializeParentPlot(mParentPlot);
11752 mInsetLayout->setParentLayerable(this);
11753 mInsetLayout->setParent(this);
11754
11755 setMinimumSize(50, 50);
11756 setMinimumMargins(QMargins(15, 15, 15, 15));
11757 mAxes.insert(QCPAxis::atLeft, QList<QCPAxis*>());
11758 mAxes.insert(QCPAxis::atRight, QList<QCPAxis*>());
11759 mAxes.insert(QCPAxis::atTop, QList<QCPAxis*>());
11760 mAxes.insert(QCPAxis::atBottom, QList<QCPAxis*>());
11761
11762 if (setupDefaultAxes)
11763 {
11764 QCPAxis *xAxis = addAxis(QCPAxis::atBottom);
11765 QCPAxis *yAxis = addAxis(QCPAxis::atLeft);
11766 QCPAxis *xAxis2 = addAxis(QCPAxis::atTop);
11767 QCPAxis *yAxis2 = addAxis(QCPAxis::atRight);
11768 setRangeDragAxes(xAxis, yAxis);
11769 setRangeZoomAxes(xAxis, yAxis);
11770 xAxis2->setVisible(false);
11771 yAxis2->setVisible(false);
11772 xAxis->grid()->setVisible(true);
11773 yAxis->grid()->setVisible(true);
11774 xAxis2->grid()->setVisible(false);
11775 yAxis2->grid()->setVisible(false);
11776 xAxis2->grid()->setZeroLinePen(Qt::NoPen);
11777 yAxis2->grid()->setZeroLinePen(Qt::NoPen);
11778 xAxis2->grid()->setVisible(false);
11779 yAxis2->grid()->setVisible(false);
11788 11780 }
11789 11781 }
11790 11782
11791 11783 QCPAxisRect::~QCPAxisRect()
11792 11784 {
11793 delete mInsetLayout;
11794 mInsetLayout = 0;
11795
11796 QList<QCPAxis*> axesList = axes();
11797 for (int i=0; i<axesList.size(); ++i)
11798 removeAxis(axesList.at(i));
11785 delete mInsetLayout;
11786 mInsetLayout = 0;
11787
11788 QList<QCPAxis*> axesList = axes();
11789 for (int i=0; i<axesList.size(); ++i)
11790 removeAxis(axesList.at(i));
11799 11791 }
11800 11792
11801 11793 /*!
@@ -11805,7 +11797,7 QCPAxisRect::~QCPAxisRect()
11805 11797 */
11806 11798 int QCPAxisRect::axisCount(QCPAxis::AxisType type) const
11807 11799 {
11808 return mAxes.value(type).size();
11800 return mAxes.value(type).size();
11809 11801 }
11810 11802
11811 11803 /*!
@@ -11815,14 +11807,14 int QCPAxisRect::axisCount(QCPAxis::Axis
11815 11807 */
11816 11808 QCPAxis *QCPAxisRect::axis(QCPAxis::AxisType type, int index) const
11817 11809 {
11818 QList<QCPAxis*> ax(mAxes.value(type));
11819 if (index >= 0 && index < ax.size())
11820 {
11821 return ax.at(index);
11822 } else
11823 {
11824 qDebug() << Q_FUNC_INFO << "Axis index out of bounds:" << index;
11825 return 0;
11810 QList<QCPAxis*> ax(mAxes.value(type));
11811 if (index >= 0 && index < ax.size())
11812 {
11813 return ax.at(index);
11814 } else
11815 {
11816 qDebug() << Q_FUNC_INFO << "Axis index out of bounds:" << index;
11817 return 0;
11826 11818 }
11827 11819 }
11828 11820
@@ -11836,16 +11828,16 QCPAxis *QCPAxisRect::axis(QCPAxis::Axis
11836 11828 */
11837 11829 QList<QCPAxis*> QCPAxisRect::axes(QCPAxis::AxisTypes types) const
11838 11830 {
11839 QList<QCPAxis*> result;
11840 if (types.testFlag(QCPAxis::atLeft))
11841 result << mAxes.value(QCPAxis::atLeft);
11842 if (types.testFlag(QCPAxis::atRight))
11843 result << mAxes.value(QCPAxis::atRight);
11844 if (types.testFlag(QCPAxis::atTop))
11845 result << mAxes.value(QCPAxis::atTop);
11846 if (types.testFlag(QCPAxis::atBottom))
11847 result << mAxes.value(QCPAxis::atBottom);
11848 return result;
11831 QList<QCPAxis*> result;
11832 if (types.testFlag(QCPAxis::atLeft))
11833 result << mAxes.value(QCPAxis::atLeft);
11834 if (types.testFlag(QCPAxis::atRight))
11835 result << mAxes.value(QCPAxis::atRight);
11836 if (types.testFlag(QCPAxis::atTop))
11837 result << mAxes.value(QCPAxis::atTop);
11838 if (types.testFlag(QCPAxis::atBottom))
11839 result << mAxes.value(QCPAxis::atBottom);
11840 return result;
11849 11841 }
11850 11842
11851 11843 /*! \overload
@@ -11854,14 +11846,14 QList<QCPAxis*> QCPAxisRect::axes(QCPAxi
11854 11846 */
11855 11847 QList<QCPAxis*> QCPAxisRect::axes() const
11856 11848 {
11857 QList<QCPAxis*> result;
11858 QHashIterator<QCPAxis::AxisType, QList<QCPAxis*> > it(mAxes);
11859 while (it.hasNext())
11860 {
11861 it.next();
11862 result << it.value();
11863 }
11864 return result;
11849 QList<QCPAxis*> result;
11850 QHashIterator<QCPAxis::AxisType, QList<QCPAxis*> > it(mAxes);
11851 while (it.hasNext())
11852 {
11853 it.next();
11854 result << it.value();
11855 }
11856 return result;
11865 11857 }
11866 11858
11867 11859 /*!
@@ -11885,36 +11877,36 QList<QCPAxis*> QCPAxisRect::axes() cons
11885 11877 */
11886 11878 QCPAxis *QCPAxisRect::addAxis(QCPAxis::AxisType type, QCPAxis *axis)
11887 11879 {
11888 QCPAxis *newAxis = axis;
11889 if (!newAxis)
11890 {
11891 newAxis = new QCPAxis(this, type);
11880 QCPAxis *newAxis = axis;
11881 if (!newAxis)
11882 {
11883 newAxis = new QCPAxis(this, type);
11892 11884 } else // user provided existing axis instance, do some sanity checks
11893 11885 {
11894 if (newAxis->axisType() != type)
11895 {
11896 qDebug() << Q_FUNC_INFO << "passed axis has different axis type than specified in type parameter";
11897 return 0;
11898 }
11899 if (newAxis->axisRect() != this)
11900 {
11901 qDebug() << Q_FUNC_INFO << "passed axis doesn't have this axis rect as parent axis rect";
11902 return 0;
11903 }
11904 if (axes().contains(newAxis))
11905 {
11906 qDebug() << Q_FUNC_INFO << "passed axis is already owned by this axis rect";
11907 return 0;
11908 }
11909 }
11910 if (mAxes[type].size() > 0) // multiple axes on one side, add half-bar axis ending to additional axes with offset
11911 {
11912 bool invert = (type == QCPAxis::atRight) || (type == QCPAxis::atBottom);
11913 newAxis->setLowerEnding(QCPLineEnding(QCPLineEnding::esHalfBar, 6, 10, !invert));
11914 newAxis->setUpperEnding(QCPLineEnding(QCPLineEnding::esHalfBar, 6, 10, invert));
11915 }
11916 mAxes[type].append(newAxis);
11917 return newAxis;
11886 if (newAxis->axisType() != type)
11887 {
11888 qDebug() << Q_FUNC_INFO << "passed axis has different axis type than specified in type parameter";
11889 return 0;
11890 }
11891 if (newAxis->axisRect() != this)
11892 {
11893 qDebug() << Q_FUNC_INFO << "passed axis doesn't have this axis rect as parent axis rect";
11894 return 0;
11895 }
11896 if (axes().contains(newAxis))
11897 {
11898 qDebug() << Q_FUNC_INFO << "passed axis is already owned by this axis rect";
11899 return 0;
11900 }
11901 }
11902 if (mAxes[type].size() > 0) // multiple axes on one side, add half-bar axis ending to additional axes with offset
11903 {
11904 bool invert = (type == QCPAxis::atRight) || (type == QCPAxis::atBottom);
11905 newAxis->setLowerEnding(QCPLineEnding(QCPLineEnding::esHalfBar, 6, 10, !invert));
11906 newAxis->setUpperEnding(QCPLineEnding(QCPLineEnding::esHalfBar, 6, 10, invert));
11907 }
11908 mAxes[type].append(newAxis);
11909 return newAxis;
11918 11910 }
11919 11911
11920 11912 /*!
@@ -11927,16 +11919,16 QCPAxis *QCPAxisRect::addAxis(QCPAxis::A
11927 11919 */
11928 11920 QList<QCPAxis*> QCPAxisRect::addAxes(QCPAxis::AxisTypes types)
11929 11921 {
11930 QList<QCPAxis*> result;
11931 if (types.testFlag(QCPAxis::atLeft))
11932 result << addAxis(QCPAxis::atLeft);
11933 if (types.testFlag(QCPAxis::atRight))
11934 result << addAxis(QCPAxis::atRight);
11935 if (types.testFlag(QCPAxis::atTop))
11936 result << addAxis(QCPAxis::atTop);
11937 if (types.testFlag(QCPAxis::atBottom))
11938 result << addAxis(QCPAxis::atBottom);
11939 return result;
11922 QList<QCPAxis*> result;
11923 if (types.testFlag(QCPAxis::atLeft))
11924 result << addAxis(QCPAxis::atLeft);
11925 if (types.testFlag(QCPAxis::atRight))
11926 result << addAxis(QCPAxis::atRight);
11927 if (types.testFlag(QCPAxis::atTop))
11928 result << addAxis(QCPAxis::atTop);
11929 if (types.testFlag(QCPAxis::atBottom))
11930 result << addAxis(QCPAxis::atBottom);
11931 return result;
11940 11932 }
11941 11933
11942 11934 /*!
@@ -11948,22 +11940,22 QList<QCPAxis*> QCPAxisRect::addAxes(QCP
11948 11940 */
11949 11941 bool QCPAxisRect::removeAxis(QCPAxis *axis)
11950 11942 {
11951 // don't access axis->axisType() to provide safety when axis is an invalid pointer, rather go through all axis containers:
11952 QHashIterator<QCPAxis::AxisType, QList<QCPAxis*> > it(mAxes);
11953 while (it.hasNext())
11954 {
11955 it.next();
11956 if (it.value().contains(axis))
11957 {
11958 mAxes[it.key()].removeOne(axis);
11959 if (qobject_cast<QCustomPlot*>(parentPlot())) // make sure this isn't called from QObject dtor when QCustomPlot is already destructed (happens when the axis rect is not in any layout and thus QObject-child of QCustomPlot)
11960 parentPlot()->axisRemoved(axis);
11961 delete axis;
11962 return true;
11963 }
11964 }
11965 qDebug() << Q_FUNC_INFO << "Axis isn't in axis rect:" << reinterpret_cast<quintptr>(axis);
11966 return false;
11943 // don't access axis->axisType() to provide safety when axis is an invalid pointer, rather go through all axis containers:
11944 QHashIterator<QCPAxis::AxisType, QList<QCPAxis*> > it(mAxes);
11945 while (it.hasNext())
11946 {
11947 it.next();
11948 if (it.value().contains(axis))
11949 {
11950 mAxes[it.key()].removeOne(axis);
11951 if (qobject_cast<QCustomPlot*>(parentPlot())) // make sure this isn't called from QObject dtor when QCustomPlot is already destructed (happens when the axis rect is not in any layout and thus QObject-child of QCustomPlot)
11952 parentPlot()->axisRemoved(axis);
11953 delete axis;
11954 return true;
11955 }
11956 }
11957 qDebug() << Q_FUNC_INFO << "Axis isn't in axis rect:" << reinterpret_cast<quintptr>(axis);
11958 return false;
11967 11959 }
11968 11960
11969 11961 /*!
@@ -11994,70 +11986,70 bool QCPAxisRect::removeAxis(QCPAxis *ax
11994 11986 */
11995 11987 void QCPAxisRect::setupFullAxesBox(bool connectRanges)
11996 11988 {
11997 QCPAxis *xAxis, *yAxis, *xAxis2, *yAxis2;
11998 if (axisCount(QCPAxis::atBottom) == 0)
11999 xAxis = addAxis(QCPAxis::atBottom);
12000 else
12001 xAxis = axis(QCPAxis::atBottom);
12002
12003 if (axisCount(QCPAxis::atLeft) == 0)
12004 yAxis = addAxis(QCPAxis::atLeft);
12005 else
12006 yAxis = axis(QCPAxis::atLeft);
12007
12008 if (axisCount(QCPAxis::atTop) == 0)
12009 xAxis2 = addAxis(QCPAxis::atTop);
12010 else
12011 xAxis2 = axis(QCPAxis::atTop);
12012
12013 if (axisCount(QCPAxis::atRight) == 0)
12014 yAxis2 = addAxis(QCPAxis::atRight);
12015 else
12016 yAxis2 = axis(QCPAxis::atRight);
12017
12018 xAxis->setVisible(true);
12019 yAxis->setVisible(true);
12020 xAxis2->setVisible(true);
12021 yAxis2->setVisible(true);
12022 xAxis2->setTickLabels(false);
12023 yAxis2->setTickLabels(false);
12024
12025 xAxis2->setRange(xAxis->range());
12026 xAxis2->setRangeReversed(xAxis->rangeReversed());
12027 xAxis2->setScaleType(xAxis->scaleType());
12028 xAxis2->setScaleLogBase(xAxis->scaleLogBase());
12029 xAxis2->setTicks(xAxis->ticks());
12030 xAxis2->setAutoTickCount(xAxis->autoTickCount());
12031 xAxis2->setSubTickCount(xAxis->subTickCount());
12032 xAxis2->setAutoSubTicks(xAxis->autoSubTicks());
12033 xAxis2->setTickStep(xAxis->tickStep());
12034 xAxis2->setAutoTickStep(xAxis->autoTickStep());
12035 xAxis2->setNumberFormat(xAxis->numberFormat());
12036 xAxis2->setNumberPrecision(xAxis->numberPrecision());
12037 xAxis2->setTickLabelType(xAxis->tickLabelType());
12038 xAxis2->setDateTimeFormat(xAxis->dateTimeFormat());
12039 xAxis2->setDateTimeSpec(xAxis->dateTimeSpec());
12040
12041 yAxis2->setRange(yAxis->range());
12042 yAxis2->setRangeReversed(yAxis->rangeReversed());
12043 yAxis2->setScaleType(yAxis->scaleType());
12044 yAxis2->setScaleLogBase(yAxis->scaleLogBase());
12045 yAxis2->setTicks(yAxis->ticks());
12046 yAxis2->setAutoTickCount(yAxis->autoTickCount());
12047 yAxis2->setSubTickCount(yAxis->subTickCount());
12048 yAxis2->setAutoSubTicks(yAxis->autoSubTicks());
12049 yAxis2->setTickStep(yAxis->tickStep());
12050 yAxis2->setAutoTickStep(yAxis->autoTickStep());
12051 yAxis2->setNumberFormat(yAxis->numberFormat());
12052 yAxis2->setNumberPrecision(yAxis->numberPrecision());
12053 yAxis2->setTickLabelType(yAxis->tickLabelType());
12054 yAxis2->setDateTimeFormat(yAxis->dateTimeFormat());
12055 yAxis2->setDateTimeSpec(yAxis->dateTimeSpec());
12056
12057 if (connectRanges)
12058 {
12059 connect(xAxis, SIGNAL(rangeChanged(QCPRange)), xAxis2, SLOT(setRange(QCPRange)));
12060 connect(yAxis, SIGNAL(rangeChanged(QCPRange)), yAxis2, SLOT(setRange(QCPRange)));
11989 QCPAxis *xAxis, *yAxis, *xAxis2, *yAxis2;
11990 if (axisCount(QCPAxis::atBottom) == 0)
11991 xAxis = addAxis(QCPAxis::atBottom);
11992 else
11993 xAxis = axis(QCPAxis::atBottom);
11994
11995 if (axisCount(QCPAxis::atLeft) == 0)
11996 yAxis = addAxis(QCPAxis::atLeft);
11997 else
11998 yAxis = axis(QCPAxis::atLeft);
11999
12000 if (axisCount(QCPAxis::atTop) == 0)
12001 xAxis2 = addAxis(QCPAxis::atTop);
12002 else
12003 xAxis2 = axis(QCPAxis::atTop);
12004
12005 if (axisCount(QCPAxis::atRight) == 0)
12006 yAxis2 = addAxis(QCPAxis::atRight);
12007 else
12008 yAxis2 = axis(QCPAxis::atRight);
12009
12010 xAxis->setVisible(true);
12011 yAxis->setVisible(true);
12012 xAxis2->setVisible(true);
12013 yAxis2->setVisible(true);
12014 xAxis2->setTickLabels(false);
12015 yAxis2->setTickLabels(false);
12016
12017 xAxis2->setRange(xAxis->range());
12018 xAxis2->setRangeReversed(xAxis->rangeReversed());
12019 xAxis2->setScaleType(xAxis->scaleType());
12020 xAxis2->setScaleLogBase(xAxis->scaleLogBase());
12021 xAxis2->setTicks(xAxis->ticks());
12022 xAxis2->setAutoTickCount(xAxis->autoTickCount());
12023 xAxis2->setSubTickCount(xAxis->subTickCount());
12024 xAxis2->setAutoSubTicks(xAxis->autoSubTicks());
12025 xAxis2->setTickStep(xAxis->tickStep());
12026 xAxis2->setAutoTickStep(xAxis->autoTickStep());
12027 xAxis2->setNumberFormat(xAxis->numberFormat());
12028 xAxis2->setNumberPrecision(xAxis->numberPrecision());
12029 xAxis2->setTickLabelType(xAxis->tickLabelType());
12030 xAxis2->setDateTimeFormat(xAxis->dateTimeFormat());
12031 xAxis2->setDateTimeSpec(xAxis->dateTimeSpec());
12032
12033 yAxis2->setRange(yAxis->range());
12034 yAxis2->setRangeReversed(yAxis->rangeReversed());
12035 yAxis2->setScaleType(yAxis->scaleType());
12036 yAxis2->setScaleLogBase(yAxis->scaleLogBase());
12037 yAxis2->setTicks(yAxis->ticks());
12038 yAxis2->setAutoTickCount(yAxis->autoTickCount());
12039 yAxis2->setSubTickCount(yAxis->subTickCount());
12040 yAxis2->setAutoSubTicks(yAxis->autoSubTicks());
12041 yAxis2->setTickStep(yAxis->tickStep());
12042 yAxis2->setAutoTickStep(yAxis->autoTickStep());
12043 yAxis2->setNumberFormat(yAxis->numberFormat());
12044 yAxis2->setNumberPrecision(yAxis->numberPrecision());
12045 yAxis2->setTickLabelType(yAxis->tickLabelType());
12046 yAxis2->setDateTimeFormat(yAxis->dateTimeFormat());
12047 yAxis2->setDateTimeSpec(yAxis->dateTimeSpec());
12048
12049 if (connectRanges)
12050 {
12051 connect(xAxis, SIGNAL(rangeChanged(QCPRange)), xAxis2, SLOT(setRange(QCPRange)));
12052 connect(yAxis, SIGNAL(rangeChanged(QCPRange)), yAxis2, SLOT(setRange(QCPRange)));
12061 12053 }
12062 12054 }
12063 12055
@@ -12071,14 +12063,14 void QCPAxisRect::setupFullAxesBox(bool
12071 12063 */
12072 12064 QList<QCPAbstractPlottable*> QCPAxisRect::plottables() const
12073 12065 {
12074 // Note: don't append all QCPAxis::plottables() into a list, because we might get duplicate entries
12075 QList<QCPAbstractPlottable*> result;
12076 for (int i=0; i<mParentPlot->mPlottables.size(); ++i)
12077 {
12078 if (mParentPlot->mPlottables.at(i)->keyAxis()->axisRect() == this ||mParentPlot->mPlottables.at(i)->valueAxis()->axisRect() == this)
12079 result.append(mParentPlot->mPlottables.at(i));
12080 }
12081 return result;
12066 // Note: don't append all QCPAxis::plottables() into a list, because we might get duplicate entries
12067 QList<QCPAbstractPlottable*> result;
12068 for (int i=0; i<mParentPlot->mPlottables.size(); ++i)
12069 {
12070 if (mParentPlot->mPlottables.at(i)->keyAxis()->axisRect() == this ||mParentPlot->mPlottables.at(i)->valueAxis()->axisRect() == this)
12071 result.append(mParentPlot->mPlottables.at(i));
12072 }
12073 return result;
12082 12074 }
12083 12075
12084 12076 /*!
@@ -12091,14 +12083,14 QList<QCPAbstractPlottable*> QCPAxisRect
12091 12083 */
12092 12084 QList<QCPGraph*> QCPAxisRect::graphs() const
12093 12085 {
12094 // Note: don't append all QCPAxis::graphs() into a list, because we might get duplicate entries
12095 QList<QCPGraph*> result;
12096 for (int i=0; i<mParentPlot->mGraphs.size(); ++i)
12097 {
12098 if (mParentPlot->mGraphs.at(i)->keyAxis()->axisRect() == this || mParentPlot->mGraphs.at(i)->valueAxis()->axisRect() == this)
12099 result.append(mParentPlot->mGraphs.at(i));
12100 }
12101 return result;
12086 // Note: don't append all QCPAxis::graphs() into a list, because we might get duplicate entries
12087 QList<QCPGraph*> result;
12088 for (int i=0; i<mParentPlot->mGraphs.size(); ++i)
12089 {
12090 if (mParentPlot->mGraphs.at(i)->keyAxis()->axisRect() == this || mParentPlot->mGraphs.at(i)->valueAxis()->axisRect() == this)
12091 result.append(mParentPlot->mGraphs.at(i));
12092 }
12093 return result;
12102 12094 }
12103 12095
12104 12096 /*!
@@ -12113,29 +12105,29 QList<QCPGraph*> QCPAxisRect::graphs() c
12113 12105 */
12114 12106 QList<QCPAbstractItem *> QCPAxisRect::items() const
12115 12107 {
12116 // Note: don't just append all QCPAxis::items() into a list, because we might get duplicate entries
12117 // and miss those items that have this axis rect as clipAxisRect.
12118 QList<QCPAbstractItem*> result;
12119 for (int itemId=0; itemId<mParentPlot->mItems.size(); ++itemId)
12120 {
12121 if (mParentPlot->mItems.at(itemId)->clipAxisRect() == this)
12122 {
12123 result.append(mParentPlot->mItems.at(itemId));
12124 continue;
12125 }
12126 QList<QCPItemPosition*> positions = mParentPlot->mItems.at(itemId)->positions();
12127 for (int posId=0; posId<positions.size(); ++posId)
12128 {
12129 if (positions.at(posId)->axisRect() == this ||
12130 positions.at(posId)->keyAxis()->axisRect() == this ||
12131 positions.at(posId)->valueAxis()->axisRect() == this)
12132 {
12133 result.append(mParentPlot->mItems.at(itemId));
12134 break;
12135 }
12136 }
12137 }
12138 return result;
12108 // Note: don't just append all QCPAxis::items() into a list, because we might get duplicate entries
12109 // and miss those items that have this axis rect as clipAxisRect.
12110 QList<QCPAbstractItem*> result;
12111 for (int itemId=0; itemId<mParentPlot->mItems.size(); ++itemId)
12112 {
12113 if (mParentPlot->mItems.at(itemId)->clipAxisRect() == this)
12114 {
12115 result.append(mParentPlot->mItems.at(itemId));
12116 continue;
12117 }
12118 QList<QCPItemPosition*> positions = mParentPlot->mItems.at(itemId)->positions();
12119 for (int posId=0; posId<positions.size(); ++posId)
12120 {
12121 if (positions.at(posId)->axisRect() == this ||
12122 positions.at(posId)->keyAxis()->axisRect() == this ||
12123 positions.at(posId)->valueAxis()->axisRect() == this)
12124 {
12125 result.append(mParentPlot->mItems.at(itemId));
12126 break;
12127 }
12128 }
12129 }
12130 return result;
12139 12131 }
12140 12132
12141 12133 /*!
@@ -12148,52 +12140,52 QList<QCPAbstractItem *> QCPAxisRect::it
12148 12140 */
12149 12141 void QCPAxisRect::update(UpdatePhase phase)
12150 12142 {
12151 QCPLayoutElement::update(phase);
12152
12153 switch (phase)
12143 QCPLayoutElement::update(phase);
12144
12145 switch (phase)
12154 12146 {
12155 12147 case upPreparation:
12156 {
12148 {
12157 12149 QList<QCPAxis*> allAxes = axes();
12158 12150 for (int i=0; i<allAxes.size(); ++i)
12159 allAxes.at(i)->setupTickVectors();
12160 break;
12161 }
12151 allAxes.at(i)->setupTickVectors();
12152 break;
12153 }
12162 12154 case upLayout:
12163 {
12155 {
12164 12156 mInsetLayout->setOuterRect(rect());
12165 12157 break;
12166 }
12158 }
12167 12159 default: break;
12168 12160 }
12169
12170 // pass update call on to inset layout (doesn't happen automatically, because QCPAxisRect doesn't derive from QCPLayout):
12171 mInsetLayout->update(phase);
12161
12162 // pass update call on to inset layout (doesn't happen automatically, because QCPAxisRect doesn't derive from QCPLayout):
12163 mInsetLayout->update(phase);
12172 12164 }
12173 12165
12174 12166 /* inherits documentation from base class */
12175 12167 QList<QCPLayoutElement*> QCPAxisRect::elements(bool recursive) const
12176 12168 {
12177 QList<QCPLayoutElement*> result;
12178 if (mInsetLayout)
12179 {
12180 result << mInsetLayout;
12181 if (recursive)
12182 result << mInsetLayout->elements(recursive);
12183 }
12184 return result;
12169 QList<QCPLayoutElement*> result;
12170 if (mInsetLayout)
12171 {
12172 result << mInsetLayout;
12173 if (recursive)
12174 result << mInsetLayout->elements(recursive);
12175 }
12176 return result;
12185 12177 }
12186 12178
12187 12179 /* inherits documentation from base class */
12188 12180 void QCPAxisRect::applyDefaultAntialiasingHint(QCPPainter *painter) const
12189 12181 {
12190 painter->setAntialiasing(false);
12182 painter->setAntialiasing(false);
12191 12183 }
12192 12184
12193 12185 /* inherits documentation from base class */
12194 12186 void QCPAxisRect::draw(QCPPainter *painter)
12195 12187 {
12196 drawBackground(painter);
12188 drawBackground(painter);
12197 12189 }
12198 12190
12199 12191 /*!
@@ -12213,8 +12205,8 void QCPAxisRect::draw(QCPPainter *paint
12213 12205 */
12214 12206 void QCPAxisRect::setBackground(const QPixmap &pm)
12215 12207 {
12216 mBackgroundPixmap = pm;
12217 mScaledBackgroundPixmap = QPixmap();
12208 mBackgroundPixmap = pm;
12209 mScaledBackgroundPixmap = QPixmap();
12218 12210 }
12219 12211
12220 12212 /*! \overload
@@ -12232,7 +12224,7 void QCPAxisRect::setBackground(const QP
12232 12224 */
12233 12225 void QCPAxisRect::setBackground(const QBrush &brush)
12234 12226 {
12235 mBackgroundBrush = brush;
12227 mBackgroundBrush = brush;
12236 12228 }
12237 12229
12238 12230 /*! \overload
@@ -12244,10 +12236,10 void QCPAxisRect::setBackground(const QB
12244 12236 */
12245 12237 void QCPAxisRect::setBackground(const QPixmap &pm, bool scaled, Qt::AspectRatioMode mode)
12246 12238 {
12247 mBackgroundPixmap = pm;
12248 mScaledBackgroundPixmap = QPixmap();
12249 mBackgroundScaled = scaled;
12250 mBackgroundScaledMode = mode;
12239 mBackgroundPixmap = pm;
12240 mScaledBackgroundPixmap = QPixmap();
12241 mBackgroundScaled = scaled;
12242 mBackgroundScaledMode = mode;
12251 12243 }
12252 12244
12253 12245 /*!
@@ -12262,7 +12254,7 void QCPAxisRect::setBackground(const QP
12262 12254 */
12263 12255 void QCPAxisRect::setBackgroundScaled(bool scaled)
12264 12256 {
12265 mBackgroundScaled = scaled;
12257 mBackgroundScaled = scaled;
12266 12258 }
12267 12259
12268 12260 /*!
@@ -12272,7 +12264,7 void QCPAxisRect::setBackgroundScaled(bo
12272 12264 */
12273 12265 void QCPAxisRect::setBackgroundScaledMode(Qt::AspectRatioMode mode)
12274 12266 {
12275 mBackgroundScaledMode = mode;
12267 mBackgroundScaledMode = mode;
12276 12268 }
12277 12269
12278 12270 /*!
@@ -12282,7 +12274,7 void QCPAxisRect::setBackgroundScaledMod
12282 12274 */
12283 12275 QCPAxis *QCPAxisRect::rangeDragAxis(Qt::Orientation orientation)
12284 12276 {
12285 return (orientation == Qt::Horizontal ? mRangeDragHorzAxis.data() : mRangeDragVertAxis.data());
12277 return (orientation == Qt::Horizontal ? mRangeDragHorzAxis.data() : mRangeDragVertAxis.data());
12286 12278 }
12287 12279
12288 12280 /*!
@@ -12292,7 +12284,7 QCPAxis *QCPAxisRect::rangeDragAxis(Qt::
12292 12284 */
12293 12285 QCPAxis *QCPAxisRect::rangeZoomAxis(Qt::Orientation orientation)
12294 12286 {
12295 return (orientation == Qt::Horizontal ? mRangeZoomHorzAxis.data() : mRangeZoomVertAxis.data());
12287 return (orientation == Qt::Horizontal ? mRangeZoomHorzAxis.data() : mRangeZoomVertAxis.data());
12296 12288 }
12297 12289
12298 12290 /*!
@@ -12302,7 +12294,7 QCPAxis *QCPAxisRect::rangeZoomAxis(Qt::
12302 12294 */
12303 12295 double QCPAxisRect::rangeZoomFactor(Qt::Orientation orientation)
12304 12296 {
12305 return (orientation == Qt::Horizontal ? mRangeZoomFactorHorz : mRangeZoomFactorVert);
12297 return (orientation == Qt::Horizontal ? mRangeZoomFactorHorz : mRangeZoomFactorVert);
12306 12298 }
12307 12299
12308 12300 /*!
@@ -12323,7 +12315,7 double QCPAxisRect::rangeZoomFactor(Qt::
12323 12315 */
12324 12316 void QCPAxisRect::setRangeDrag(Qt::Orientations orientations)
12325 12317 {
12326 mRangeDrag = orientations;
12318 mRangeDrag = orientations;
12327 12319 }
12328 12320
12329 12321 /*!
@@ -12343,7 +12335,7 void QCPAxisRect::setRangeDrag(Qt::Orien
12343 12335 */
12344 12336 void QCPAxisRect::setRangeZoom(Qt::Orientations orientations)
12345 12337 {
12346 mRangeZoom = orientations;
12338 mRangeZoom = orientations;
12347 12339 }
12348 12340
12349 12341 /*!
@@ -12354,8 +12346,8 void QCPAxisRect::setRangeZoom(Qt::Orien
12354 12346 */
12355 12347 void QCPAxisRect::setRangeDragAxes(QCPAxis *horizontal, QCPAxis *vertical)
12356 12348 {
12357 mRangeDragHorzAxis = horizontal;
12358 mRangeDragVertAxis = vertical;
12349 mRangeDragHorzAxis = horizontal;
12350 mRangeDragVertAxis = vertical;
12359 12351 }
12360 12352
12361 12353 /*!
@@ -12367,8 +12359,8 void QCPAxisRect::setRangeDragAxes(QCPAx
12367 12359 */
12368 12360 void QCPAxisRect::setRangeZoomAxes(QCPAxis *horizontal, QCPAxis *vertical)
12369 12361 {
12370 mRangeZoomHorzAxis = horizontal;
12371 mRangeZoomVertAxis = vertical;
12362 mRangeZoomHorzAxis = horizontal;
12363 mRangeZoomVertAxis = vertical;
12372 12364 }
12373 12365
12374 12366 /*!
@@ -12383,8 +12375,8 void QCPAxisRect::setRangeZoomAxes(QCPAx
12383 12375 */
12384 12376 void QCPAxisRect::setRangeZoomFactor(double horizontalFactor, double verticalFactor)
12385 12377 {
12386 mRangeZoomFactorHorz = horizontalFactor;
12387 mRangeZoomFactorVert = verticalFactor;
12378 mRangeZoomFactorHorz = horizontalFactor;
12379 mRangeZoomFactorVert = verticalFactor;
12388 12380 }
12389 12381
12390 12382 /*! \overload
@@ -12393,8 +12385,8 void QCPAxisRect::setRangeZoomFactor(dou
12393 12385 */
12394 12386 void QCPAxisRect::setRangeZoomFactor(double factor)
12395 12387 {
12396 mRangeZoomFactorHorz = factor;
12397 mRangeZoomFactorVert = factor;
12388 mRangeZoomFactorHorz = factor;
12389 mRangeZoomFactorVert = factor;
12398 12390 }
12399 12391
12400 12392 /*! \internal
@@ -12417,24 +12409,24 void QCPAxisRect::setRangeZoomFactor(dou
12417 12409 */
12418 12410 void QCPAxisRect::drawBackground(QCPPainter *painter)
12419 12411 {
12420 // draw background fill:
12421 if (mBackgroundBrush != Qt::NoBrush)
12422 painter->fillRect(mRect, mBackgroundBrush);
12423
12424 // draw background pixmap (on top of fill, if brush specified):
12425 if (!mBackgroundPixmap.isNull())
12426 {
12427 if (mBackgroundScaled)
12428 {
12429 // check whether mScaledBackground needs to be updated:
12430 QSize scaledSize(mBackgroundPixmap.size());
12431 scaledSize.scale(mRect.size(), mBackgroundScaledMode);
12432 if (mScaledBackgroundPixmap.size() != scaledSize)
12433 mScaledBackgroundPixmap = mBackgroundPixmap.scaled(mRect.size(), mBackgroundScaledMode, Qt::SmoothTransformation);
12434 painter->drawPixmap(mRect.topLeft(), mScaledBackgroundPixmap, QRect(0, 0, mRect.width(), mRect.height()) & mScaledBackgroundPixmap.rect());
12412 // draw background fill:
12413 if (mBackgroundBrush != Qt::NoBrush)
12414 painter->fillRect(mRect, mBackgroundBrush);
12415
12416 // draw background pixmap (on top of fill, if brush specified):
12417 if (!mBackgroundPixmap.isNull())
12418 {
12419 if (mBackgroundScaled)
12420 {
12421 // check whether mScaledBackground needs to be updated:
12422 QSize scaledSize(mBackgroundPixmap.size());
12423 scaledSize.scale(mRect.size(), mBackgroundScaledMode);
12424 if (mScaledBackgroundPixmap.size() != scaledSize)
12425 mScaledBackgroundPixmap = mBackgroundPixmap.scaled(mRect.size(), mBackgroundScaledMode, Qt::SmoothTransformation);
12426 painter->drawPixmap(mRect.topLeft(), mScaledBackgroundPixmap, QRect(0, 0, mRect.width(), mRect.height()) & mScaledBackgroundPixmap.rect());
12435 12427 } else
12436 12428 {
12437 painter->drawPixmap(mRect.topLeft(), mBackgroundPixmap, QRect(0, 0, mRect.width(), mRect.height()));
12429 painter->drawPixmap(mRect.topLeft(), mBackgroundPixmap, QRect(0, 0, mRect.width(), mRect.height()));
12438 12430 }
12439 12431 }
12440 12432 }
@@ -12451,38 +12443,38 void QCPAxisRect::drawBackground(QCPPain
12451 12443 */
12452 12444 void QCPAxisRect::updateAxesOffset(QCPAxis::AxisType type)
12453 12445 {
12454 const QList<QCPAxis*> axesList = mAxes.value(type);
12455 if (axesList.isEmpty())
12456 return;
12457
12458 bool isFirstVisible = !axesList.first()->visible(); // if the first axis is visible, the second axis (which is where the loop starts) isn't the first visible axis, so initialize with false
12459 for (int i=1; i<axesList.size(); ++i)
12460 {
12461 int offset = axesList.at(i-1)->offset() + axesList.at(i-1)->calculateMargin();
12462 if (axesList.at(i)->visible()) // only add inner tick length to offset if this axis is visible and it's not the first visible one (might happen if true first axis is invisible)
12463 {
12464 if (!isFirstVisible)
12465 offset += axesList.at(i)->tickLengthIn();
12466 isFirstVisible = false;
12467 }
12468 axesList.at(i)->setOffset(offset);
12446 const QList<QCPAxis*> axesList = mAxes.value(type);
12447 if (axesList.isEmpty())
12448 return;
12449
12450 bool isFirstVisible = !axesList.first()->visible(); // if the first axis is visible, the second axis (which is where the loop starts) isn't the first visible axis, so initialize with false
12451 for (int i=1; i<axesList.size(); ++i)
12452 {
12453 int offset = axesList.at(i-1)->offset() + axesList.at(i-1)->calculateMargin();
12454 if (axesList.at(i)->visible()) // only add inner tick length to offset if this axis is visible and it's not the first visible one (might happen if true first axis is invisible)
12455 {
12456 if (!isFirstVisible)
12457 offset += axesList.at(i)->tickLengthIn();
12458 isFirstVisible = false;
12459 }
12460 axesList.at(i)->setOffset(offset);
12469 12461 }
12470 12462 }
12471 12463
12472 12464 /* inherits documentation from base class */
12473 12465 int QCPAxisRect::calculateAutoMargin(QCP::MarginSide side)
12474 12466 {
12475 if (!mAutoMargins.testFlag(side))
12476 qDebug() << Q_FUNC_INFO << "Called with side that isn't specified as auto margin";
12477
12478 updateAxesOffset(QCPAxis::marginSideToAxisType(side));
12479
12480 // note: only need to look at the last (outer most) axis to determine the total margin, due to updateAxisOffset call
12481 const QList<QCPAxis*> axesList = mAxes.value(QCPAxis::marginSideToAxisType(side));
12482 if (axesList.size() > 0)
12483 return axesList.last()->offset() + axesList.last()->calculateMargin();
12484 else
12485 return 0;
12467 if (!mAutoMargins.testFlag(side))
12468 qDebug() << Q_FUNC_INFO << "Called with side that isn't specified as auto margin";
12469
12470 updateAxesOffset(QCPAxis::marginSideToAxisType(side));
12471
12472 // note: only need to look at the last (outer most) axis to determine the total margin, due to updateAxisOffset call
12473 const QList<QCPAxis*> axesList = mAxes.value(QCPAxis::marginSideToAxisType(side));
12474 if (axesList.size() > 0)
12475 return axesList.last()->offset() + axesList.last()->calculateMargin();
12476 else
12477 return 0;
12486 12478 }
12487 12479
12488 12480 /*! \internal
@@ -12498,23 +12490,23 int QCPAxisRect::calculateAutoMargin(QCP
12498 12490 */
12499 12491 void QCPAxisRect::mousePressEvent(QMouseEvent *event)
12500 12492 {
12501 mDragStart = event->pos(); // need this even when not LeftButton is pressed, to determine in releaseEvent whether it was a full click (no position change between press and release)
12502 if (event->buttons() & Qt::LeftButton)
12503 {
12504 mDragging = true;
12505 // initialize antialiasing backup in case we start dragging:
12506 if (mParentPlot->noAntialiasingOnDrag())
12507 {
12508 mAADragBackup = mParentPlot->antialiasedElements();
12509 mNotAADragBackup = mParentPlot->notAntialiasedElements();
12510 }
12511 // Mouse range dragging interaction:
12512 if (mParentPlot->interactions().testFlag(QCP::iRangeDrag))
12513 {
12514 if (mRangeDragHorzAxis)
12515 mDragStartHorzRange = mRangeDragHorzAxis.data()->range();
12516 if (mRangeDragVertAxis)
12517 mDragStartVertRange = mRangeDragVertAxis.data()->range();
12493 mDragStart = event->pos(); // need this even when not LeftButton is pressed, to determine in releaseEvent whether it was a full click (no position change between press and release)
12494 if (event->buttons() & Qt::LeftButton)
12495 {
12496 mDragging = true;
12497 // initialize antialiasing backup in case we start dragging:
12498 if (mParentPlot->noAntialiasingOnDrag())
12499 {
12500 mAADragBackup = mParentPlot->antialiasedElements();
12501 mNotAADragBackup = mParentPlot->notAntialiasedElements();
12502 }
12503 // Mouse range dragging interaction:
12504 if (mParentPlot->interactions().testFlag(QCP::iRangeDrag))
12505 {
12506 if (mRangeDragHorzAxis)
12507 mDragStartHorzRange = mRangeDragHorzAxis.data()->range();
12508 if (mRangeDragVertAxis)
12509 mDragStartVertRange = mRangeDragVertAxis.data()->range();
12518 12510 }
12519 12511 }
12520 12512 }
@@ -12528,44 +12520,44 void QCPAxisRect::mousePressEvent(QMouse
12528 12520 */
12529 12521 void QCPAxisRect::mouseMoveEvent(QMouseEvent *event)
12530 12522 {
12531 // Mouse range dragging interaction:
12532 if (mDragging && mParentPlot->interactions().testFlag(QCP::iRangeDrag))
12533 {
12534 if (mRangeDrag.testFlag(Qt::Horizontal))
12535 {
12536 if (QCPAxis *rangeDragHorzAxis = mRangeDragHorzAxis.data())
12537 {
12538 if (rangeDragHorzAxis->mScaleType == QCPAxis::stLinear)
12523 // Mouse range dragging interaction:
12524 if (mDragging && mParentPlot->interactions().testFlag(QCP::iRangeDrag))
12525 {
12526 if (mRangeDrag.testFlag(Qt::Horizontal))
12527 {
12528 if (QCPAxis *rangeDragHorzAxis = mRangeDragHorzAxis.data())
12529 {
12530 if (rangeDragHorzAxis->mScaleType == QCPAxis::stLinear)
12539 12531 {
12540 double diff = rangeDragHorzAxis->pixelToCoord(mDragStart.x()) - rangeDragHorzAxis->pixelToCoord(event->pos().x());
12541 rangeDragHorzAxis->setRange(mDragStartHorzRange.lower+diff, mDragStartHorzRange.upper+diff);
12532 double diff = rangeDragHorzAxis->pixelToCoord(mDragStart.x()) - rangeDragHorzAxis->pixelToCoord(event->pos().x());
12533 rangeDragHorzAxis->setRange(mDragStartHorzRange.lower+diff, mDragStartHorzRange.upper+diff);
12542 12534 } else if (rangeDragHorzAxis->mScaleType == QCPAxis::stLogarithmic)
12543 12535 {
12544 double diff = rangeDragHorzAxis->pixelToCoord(mDragStart.x()) / rangeDragHorzAxis->pixelToCoord(event->pos().x());
12545 rangeDragHorzAxis->setRange(mDragStartHorzRange.lower*diff, mDragStartHorzRange.upper*diff);
12536 double diff = rangeDragHorzAxis->pixelToCoord(mDragStart.x()) / rangeDragHorzAxis->pixelToCoord(event->pos().x());
12537 rangeDragHorzAxis->setRange(mDragStartHorzRange.lower*diff, mDragStartHorzRange.upper*diff);
12546 12538 }
12547 12539 }
12548 12540 }
12549 if (mRangeDrag.testFlag(Qt::Vertical))
12550 {
12551 if (QCPAxis *rangeDragVertAxis = mRangeDragVertAxis.data())
12552 {
12553 if (rangeDragVertAxis->mScaleType == QCPAxis::stLinear)
12541 if (mRangeDrag.testFlag(Qt::Vertical))
12542 {
12543 if (QCPAxis *rangeDragVertAxis = mRangeDragVertAxis.data())
12544 {
12545 if (rangeDragVertAxis->mScaleType == QCPAxis::stLinear)
12554 12546 {
12555 double diff = rangeDragVertAxis->pixelToCoord(mDragStart.y()) - rangeDragVertAxis->pixelToCoord(event->pos().y());
12556 rangeDragVertAxis->setRange(mDragStartVertRange.lower+diff, mDragStartVertRange.upper+diff);
12547 double diff = rangeDragVertAxis->pixelToCoord(mDragStart.y()) - rangeDragVertAxis->pixelToCoord(event->pos().y());
12548 rangeDragVertAxis->setRange(mDragStartVertRange.lower+diff, mDragStartVertRange.upper+diff);
12557 12549 } else if (rangeDragVertAxis->mScaleType == QCPAxis::stLogarithmic)
12558 12550 {
12559 double diff = rangeDragVertAxis->pixelToCoord(mDragStart.y()) / rangeDragVertAxis->pixelToCoord(event->pos().y());
12560 rangeDragVertAxis->setRange(mDragStartVertRange.lower*diff, mDragStartVertRange.upper*diff);
12551 double diff = rangeDragVertAxis->pixelToCoord(mDragStart.y()) / rangeDragVertAxis->pixelToCoord(event->pos().y());
12552 rangeDragVertAxis->setRange(mDragStartVertRange.lower*diff, mDragStartVertRange.upper*diff);
12561 12553 }
12562 12554 }
12563 12555 }
12564 if (mRangeDrag != 0) // if either vertical or horizontal drag was enabled, do a replot
12565 {
12566 if (mParentPlot->noAntialiasingOnDrag())
12567 mParentPlot->setNotAntialiasedElements(QCP::aeAll);
12568 mParentPlot->replot();
12556 if (mRangeDrag != 0) // if either vertical or horizontal drag was enabled, do a replot
12557 {
12558 if (mParentPlot->noAntialiasingOnDrag())
12559 mParentPlot->setNotAntialiasedElements(QCP::aeAll);
12560 mParentPlot->replot();
12569 12561 }
12570 12562 }
12571 12563 }
@@ -12573,12 +12565,12 void QCPAxisRect::mouseMoveEvent(QMouseE
12573 12565 /* inherits documentation from base class */
12574 12566 void QCPAxisRect::mouseReleaseEvent(QMouseEvent *event)
12575 12567 {
12576 Q_UNUSED(event)
12577 mDragging = false;
12578 if (mParentPlot->noAntialiasingOnDrag())
12579 {
12580 mParentPlot->setAntialiasedElements(mAADragBackup);
12581 mParentPlot->setNotAntialiasedElements(mNotAADragBackup);
12568 Q_UNUSED(event)
12569 mDragging = false;
12570 if (mParentPlot->noAntialiasingOnDrag())
12571 {
12572 mParentPlot->setAntialiasedElements(mAADragBackup);
12573 mParentPlot->setNotAntialiasedElements(mNotAADragBackup);
12582 12574 }
12583 12575 }
12584 12576
@@ -12598,26 +12590,26 void QCPAxisRect::mouseReleaseEvent(QMou
12598 12590 */
12599 12591 void QCPAxisRect::wheelEvent(QWheelEvent *event)
12600 12592 {
12601 // Mouse range zooming interaction:
12602 if (mParentPlot->interactions().testFlag(QCP::iRangeZoom))
12603 {
12604 if (mRangeZoom != 0)
12605 {
12606 double factor;
12607 double wheelSteps = event->delta()/120.0; // a single step delta is +/-120 usually
12608 if (mRangeZoom.testFlag(Qt::Horizontal))
12609 {
12610 factor = qPow(mRangeZoomFactorHorz, wheelSteps);
12611 if (mRangeZoomHorzAxis.data())
12612 mRangeZoomHorzAxis.data()->scaleRange(factor, mRangeZoomHorzAxis.data()->pixelToCoord(event->pos().x()));
12613 }
12614 if (mRangeZoom.testFlag(Qt::Vertical))
12615 {
12616 factor = qPow(mRangeZoomFactorVert, wheelSteps);
12617 if (mRangeZoomVertAxis.data())
12618 mRangeZoomVertAxis.data()->scaleRange(factor, mRangeZoomVertAxis.data()->pixelToCoord(event->pos().y()));
12619 }
12620 mParentPlot->replot();
12593 // Mouse range zooming interaction:
12594 if (mParentPlot->interactions().testFlag(QCP::iRangeZoom))
12595 {
12596 if (mRangeZoom != 0)
12597 {
12598 double factor;
12599 double wheelSteps = event->delta()/120.0; // a single step delta is +/-120 usually
12600 if (mRangeZoom.testFlag(Qt::Horizontal))
12601 {
12602 factor = qPow(mRangeZoomFactorHorz, wheelSteps);
12603 if (mRangeZoomHorzAxis.data())
12604 mRangeZoomHorzAxis.data()->scaleRange(factor, mRangeZoomHorzAxis.data()->pixelToCoord(event->pos().x()));
12605 }
12606 if (mRangeZoom.testFlag(Qt::Vertical))
12607 {
12608 factor = qPow(mRangeZoomFactorVert, wheelSteps);
12609 if (mRangeZoomVertAxis.data())
12610 mRangeZoomVertAxis.data()->scaleRange(factor, mRangeZoomVertAxis.data()->pixelToCoord(event->pos().y()));
12611 }
12612 mParentPlot->replot();
12621 12613 }
12622 12614 }
12623 12615 }
@@ -12666,17 +12658,17 void QCPAxisRect::wheelEvent(QWheelEvent
12666 12658 cause the item to be added to \a parent, so \ref QCPLegend::addItem must be called separately.
12667 12659 */
12668 12660 QCPAbstractLegendItem::QCPAbstractLegendItem(QCPLegend *parent) :
12669 QCPLayoutElement(parent->parentPlot()),
12670 mParentLegend(parent),
12671 mFont(parent->font()),
12672 mTextColor(parent->textColor()),
12673 mSelectedFont(parent->selectedFont()),
12674 mSelectedTextColor(parent->selectedTextColor()),
12675 mSelectable(true),
12676 mSelected(false)
12677 {
12678 setLayer(QLatin1String("legend"));
12679 setMargins(QMargins(8, 2, 8, 2));
12661 QCPLayoutElement(parent->parentPlot()),
12662 mParentLegend(parent),
12663 mFont(parent->font()),
12664 mTextColor(parent->textColor()),
12665 mSelectedFont(parent->selectedFont()),
12666 mSelectedTextColor(parent->selectedTextColor()),
12667 mSelectable(true),
12668 mSelected(false)
12669 {
12670 setLayer(QLatin1String("legend"));
12671 setMargins(QMargins(8, 2, 8, 2));
12680 12672 }
12681 12673
12682 12674 /*!
@@ -12686,7 +12678,7 QCPAbstractLegendItem::QCPAbstractLegend
12686 12678 */
12687 12679 void QCPAbstractLegendItem::setFont(const QFont &font)
12688 12680 {
12689 mFont = font;
12681 mFont = font;
12690 12682 }
12691 12683
12692 12684 /*!
@@ -12696,7 +12688,7 void QCPAbstractLegendItem::setFont(cons
12696 12688 */
12697 12689 void QCPAbstractLegendItem::setTextColor(const QColor &color)
12698 12690 {
12699 mTextColor = color;
12691 mTextColor = color;
12700 12692 }
12701 12693
12702 12694 /*!
@@ -12707,7 +12699,7 void QCPAbstractLegendItem::setTextColor
12707 12699 */
12708 12700 void QCPAbstractLegendItem::setSelectedFont(const QFont &font)
12709 12701 {
12710 mSelectedFont = font;
12702 mSelectedFont = font;
12711 12703 }
12712 12704
12713 12705 /*!
@@ -12718,7 +12710,7 void QCPAbstractLegendItem::setSelectedF
12718 12710 */
12719 12711 void QCPAbstractLegendItem::setSelectedTextColor(const QColor &color)
12720 12712 {
12721 mSelectedTextColor = color;
12713 mSelectedTextColor = color;
12722 12714 }
12723 12715
12724 12716 /*!
@@ -12728,10 +12720,10 void QCPAbstractLegendItem::setSelectedT
12728 12720 */
12729 12721 void QCPAbstractLegendItem::setSelectable(bool selectable)
12730 12722 {
12731 if (mSelectable != selectable)
12732 {
12733 mSelectable = selectable;
12734 emit selectableChanged(mSelectable);
12723 if (mSelectable != selectable)
12724 {
12725 mSelectable = selectable;
12726 emit selectableChanged(mSelectable);
12735 12727 }
12736 12728 }
12737 12729
@@ -12745,62 +12737,62 void QCPAbstractLegendItem::setSelectabl
12745 12737 */
12746 12738 void QCPAbstractLegendItem::setSelected(bool selected)
12747 12739 {
12748 if (mSelected != selected)
12749 {
12750 mSelected = selected;
12751 emit selectionChanged(mSelected);
12740 if (mSelected != selected)
12741 {
12742 mSelected = selected;
12743 emit selectionChanged(mSelected);
12752 12744 }
12753 12745 }
12754 12746
12755 12747 /* inherits documentation from base class */
12756 12748 double QCPAbstractLegendItem::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
12757 12749 {
12758 Q_UNUSED(details)
12759 if (!mParentPlot) return -1;
12760 if (onlySelectable && (!mSelectable || !mParentLegend->selectableParts().testFlag(QCPLegend::spItems)))
12761 return -1;
12762
12763 if (mRect.contains(pos.toPoint()))
12764 return mParentPlot->selectionTolerance()*0.99;
12765 else
12766 return -1;
12750 Q_UNUSED(details)
12751 if (!mParentPlot) return -1;
12752 if (onlySelectable && (!mSelectable || !mParentLegend->selectableParts().testFlag(QCPLegend::spItems)))
12753 return -1;
12754
12755 if (mRect.contains(pos.toPoint()))
12756 return mParentPlot->selectionTolerance()*0.99;
12757 else
12758 return -1;
12767 12759 }
12768 12760
12769 12761 /* inherits documentation from base class */
12770 12762 void QCPAbstractLegendItem::applyDefaultAntialiasingHint(QCPPainter *painter) const
12771 12763 {
12772 applyAntialiasingHint(painter, mAntialiased, QCP::aeLegendItems);
12764 applyAntialiasingHint(painter, mAntialiased, QCP::aeLegendItems);
12773 12765 }
12774 12766
12775 12767 /* inherits documentation from base class */
12776 12768 QRect QCPAbstractLegendItem::clipRect() const
12777 12769 {
12778 return mOuterRect;
12770 return mOuterRect;
12779 12771 }
12780 12772
12781 12773 /* inherits documentation from base class */
12782 12774 void QCPAbstractLegendItem::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged)
12783 12775 {
12784 Q_UNUSED(event)
12785 Q_UNUSED(details)
12786 if (mSelectable && mParentLegend->selectableParts().testFlag(QCPLegend::spItems))
12787 {
12788 bool selBefore = mSelected;
12789 setSelected(additive ? !mSelected : true);
12790 if (selectionStateChanged)
12791 *selectionStateChanged = mSelected != selBefore;
12776 Q_UNUSED(event)
12777 Q_UNUSED(details)
12778 if (mSelectable && mParentLegend->selectableParts().testFlag(QCPLegend::spItems))
12779 {
12780 bool selBefore = mSelected;
12781 setSelected(additive ? !mSelected : true);
12782 if (selectionStateChanged)
12783 *selectionStateChanged = mSelected != selBefore;
12792 12784 }
12793 12785 }
12794 12786
12795 12787 /* inherits documentation from base class */
12796 12788 void QCPAbstractLegendItem::deselectEvent(bool *selectionStateChanged)
12797 12789 {
12798 if (mSelectable && mParentLegend->selectableParts().testFlag(QCPLegend::spItems))
12799 {
12800 bool selBefore = mSelected;
12801 setSelected(false);
12802 if (selectionStateChanged)
12803 *selectionStateChanged = mSelected != selBefore;
12790 if (mSelectable && mParentLegend->selectableParts().testFlag(QCPLegend::spItems))
12791 {
12792 bool selBefore = mSelected;
12793 setSelected(false);
12794 if (selectionStateChanged)
12795 *selectionStateChanged = mSelected != selBefore;
12804 12796 }
12805 12797 }
12806 12798
@@ -12842,8 +12834,8 void QCPAbstractLegendItem::deselectEven
12842 12834 QCPAbstractPlottable::addToLegend and \ref QCPAbstractPlottable::removeFromLegend.
12843 12835 */
12844 12836 QCPPlottableLegendItem::QCPPlottableLegendItem(QCPLegend *parent, QCPAbstractPlottable *plottable) :
12845 QCPAbstractLegendItem(parent),
12846 mPlottable(plottable)
12837 QCPAbstractLegendItem(parent),
12838 mPlottable(plottable)
12847 12839 {
12848 12840 }
12849 12841
@@ -12854,7 +12846,7 QCPPlottableLegendItem::QCPPlottableLege
12854 12846 */
12855 12847 QPen QCPPlottableLegendItem::getIconBorderPen() const
12856 12848 {
12857 return mSelected ? mParentLegend->selectedIconBorderPen() : mParentLegend->iconBorderPen();
12849 return mSelected ? mParentLegend->selectedIconBorderPen() : mParentLegend->iconBorderPen();
12858 12850 }
12859 12851
12860 12852 /*! \internal
@@ -12864,7 +12856,7 QPen QCPPlottableLegendItem::getIconBord
12864 12856 */
12865 12857 QColor QCPPlottableLegendItem::getTextColor() const
12866 12858 {
12867 return mSelected ? mSelectedTextColor : mTextColor;
12859 return mSelected ? mSelectedTextColor : mTextColor;
12868 12860 }
12869 12861
12870 12862 /*! \internal
@@ -12874,7 +12866,7 QColor QCPPlottableLegendItem::getTextCo
12874 12866 */
12875 12867 QFont QCPPlottableLegendItem::getFont() const
12876 12868 {
12877 return mSelected ? mSelectedFont : mFont;
12869 return mSelected ? mSelectedFont : mFont;
12878 12870 }
12879 12871
12880 12872 /*! \internal
@@ -12885,25 +12877,25 QFont QCPPlottableLegendItem::getFont()
12885 12877 */
12886 12878 void QCPPlottableLegendItem::draw(QCPPainter *painter)
12887 12879 {
12888 if (!mPlottable) return;
12889 painter->setFont(getFont());
12890 painter->setPen(QPen(getTextColor()));
12891 QSizeF iconSize = mParentLegend->iconSize();
12892 QRectF textRect = painter->fontMetrics().boundingRect(0, 0, 0, iconSize.height(), Qt::TextDontClip, mPlottable->name());
12893 QRectF iconRect(mRect.topLeft(), iconSize);
12894 int textHeight = qMax(textRect.height(), iconSize.height()); // if text has smaller height than icon, center text vertically in icon height, else align tops
12895 painter->drawText(mRect.x()+iconSize.width()+mParentLegend->iconTextPadding(), mRect.y(), textRect.width(), textHeight, Qt::TextDontClip, mPlottable->name());
12896 // draw icon:
12897 painter->save();
12898 painter->setClipRect(iconRect, Qt::IntersectClip);
12899 mPlottable->drawLegendIcon(painter, iconRect);
12900 painter->restore();
12901 // draw icon border:
12902 if (getIconBorderPen().style() != Qt::NoPen)
12903 {
12904 painter->setPen(getIconBorderPen());
12905 painter->setBrush(Qt::NoBrush);
12906 painter->drawRect(iconRect);
12880 if (!mPlottable) return;
12881 painter->setFont(getFont());
12882 painter->setPen(QPen(getTextColor()));
12883 QSizeF iconSize = mParentLegend->iconSize();
12884 QRectF textRect = painter->fontMetrics().boundingRect(0, 0, 0, iconSize.height(), Qt::TextDontClip, mPlottable->name());
12885 QRectF iconRect(mRect.topLeft(), iconSize);
12886 int textHeight = qMax(textRect.height(), iconSize.height()); // if text has smaller height than icon, center text vertically in icon height, else align tops
12887 painter->drawText(mRect.x()+iconSize.width()+mParentLegend->iconTextPadding(), mRect.y(), textRect.width(), textHeight, Qt::TextDontClip, mPlottable->name());
12888 // draw icon:
12889 painter->save();
12890 painter->setClipRect(iconRect, Qt::IntersectClip);
12891 mPlottable->drawLegendIcon(painter, iconRect);
12892 painter->restore();
12893 // draw icon border:
12894 if (getIconBorderPen().style() != Qt::NoPen)
12895 {
12896 painter->setPen(getIconBorderPen());
12897 painter->setBrush(Qt::NoBrush);
12898 painter->drawRect(iconRect);
12907 12899 }
12908 12900 }
12909 12901
@@ -12914,15 +12906,15 void QCPPlottableLegendItem::draw(QCPPai
12914 12906 */
12915 12907 QSize QCPPlottableLegendItem::minimumSizeHint() const
12916 12908 {
12917 if (!mPlottable) return QSize();
12918 QSize result(0, 0);
12919 QRect textRect;
12920 QFontMetrics fontMetrics(getFont());
12921 QSize iconSize = mParentLegend->iconSize();
12922 textRect = fontMetrics.boundingRect(0, 0, 0, iconSize.height(), Qt::TextDontClip, mPlottable->name());
12923 result.setWidth(iconSize.width() + mParentLegend->iconTextPadding() + textRect.width() + mMargins.left() + mMargins.right());
12924 result.setHeight(qMax(textRect.height(), iconSize.height()) + mMargins.top() + mMargins.bottom());
12925 return result;
12909 if (!mPlottable) return QSize();
12910 QSize result(0, 0);
12911 QRect textRect;
12912 QFontMetrics fontMetrics(getFont());
12913 QSize iconSize = mParentLegend->iconSize();
12914 textRect = fontMetrics.boundingRect(0, 0, 0, iconSize.height(), Qt::TextDontClip, mPlottable->name());
12915 result.setWidth(iconSize.width() + mParentLegend->iconTextPadding() + textRect.width() + mMargins.left() + mMargins.right());
12916 result.setHeight(qMax(textRect.height(), iconSize.height()) + mMargins.top() + mMargins.bottom());
12917 return result;
12926 12918 }
12927 12919
12928 12920
@@ -12973,51 +12965,51 QSize QCPPlottableLegendItem::minimumSiz
12973 12965 */
12974 12966 QCPLegend::QCPLegend()
12975 12967 {
12976 setRowSpacing(0);
12977 setColumnSpacing(10);
12978 setMargins(QMargins(2, 3, 2, 2));
12979 setAntialiased(false);
12980 setIconSize(32, 18);
12981
12982 setIconTextPadding(7);
12983
12984 setSelectableParts(spLegendBox | spItems);
12985 setSelectedParts(spNone);
12986
12987 setBorderPen(QPen(Qt::black));
12988 setSelectedBorderPen(QPen(Qt::blue, 2));
12989 setIconBorderPen(Qt::NoPen);
12990 setSelectedIconBorderPen(QPen(Qt::blue, 2));
12991 setBrush(Qt::white);
12992 setSelectedBrush(Qt::white);
12993 setTextColor(Qt::black);
12994 setSelectedTextColor(Qt::blue);
12968 setRowSpacing(0);
12969 setColumnSpacing(10);
12970 setMargins(QMargins(2, 3, 2, 2));
12971 setAntialiased(false);
12972 setIconSize(32, 18);
12973
12974 setIconTextPadding(7);
12975
12976 setSelectableParts(spLegendBox | spItems);
12977 setSelectedParts(spNone);
12978
12979 setBorderPen(QPen(Qt::black));
12980 setSelectedBorderPen(QPen(Qt::blue, 2));
12981 setIconBorderPen(Qt::NoPen);
12982 setSelectedIconBorderPen(QPen(Qt::blue, 2));
12983 setBrush(Qt::white);
12984 setSelectedBrush(Qt::white);
12985 setTextColor(Qt::black);
12986 setSelectedTextColor(Qt::blue);
12995 12987 }
12996 12988
12997 12989 QCPLegend::~QCPLegend()
12998 12990 {
12999 clearItems();
13000 if (qobject_cast<QCustomPlot*>(mParentPlot)) // make sure this isn't called from QObject dtor when QCustomPlot is already destructed (happens when the legend is not in any layout and thus QObject-child of QCustomPlot)
13001 mParentPlot->legendRemoved(this);
12991 clearItems();
12992 if (qobject_cast<QCustomPlot*>(mParentPlot)) // make sure this isn't called from QObject dtor when QCustomPlot is already destructed (happens when the legend is not in any layout and thus QObject-child of QCustomPlot)
12993 mParentPlot->legendRemoved(this);
13002 12994 }
13003 12995
13004 12996 /* no doc for getter, see setSelectedParts */
13005 12997 QCPLegend::SelectableParts QCPLegend::selectedParts() const
13006 12998 {
13007 // check whether any legend elements selected, if yes, add spItems to return value
13008 bool hasSelectedItems = false;
13009 for (int i=0; i<itemCount(); ++i)
13010 {
13011 if (item(i) && item(i)->selected())
13012 {
13013 hasSelectedItems = true;
13014 break;
13015 }
13016 }
13017 if (hasSelectedItems)
13018 return mSelectedParts | spItems;
13019 else
13020 return mSelectedParts & ~spItems;
12999 // check whether any legend elements selected, if yes, add spItems to return value
13000 bool hasSelectedItems = false;
13001 for (int i=0; i<itemCount(); ++i)
13002 {
13003 if (item(i) && item(i)->selected())
13004 {
13005 hasSelectedItems = true;
13006 break;
13007 }
13008 }
13009 if (hasSelectedItems)
13010 return mSelectedParts | spItems;
13011 else
13012 return mSelectedParts & ~spItems;
13021 13013 }
13022 13014
13023 13015 /*!
@@ -13025,7 +13017,7 QCPLegend::SelectableParts QCPLegend::se
13025 13017 */
13026 13018 void QCPLegend::setBorderPen(const QPen &pen)
13027 13019 {
13028 mBorderPen = pen;
13020 mBorderPen = pen;
13029 13021 }
13030 13022
13031 13023 /*!
@@ -13033,7 +13025,7 void QCPLegend::setBorderPen(const QPen
13033 13025 */
13034 13026 void QCPLegend::setBrush(const QBrush &brush)
13035 13027 {
13036 mBrush = brush;
13028 mBrush = brush;
13037 13029 }
13038 13030
13039 13031 /*!
@@ -13047,11 +13039,11 void QCPLegend::setBrush(const QBrush &b
13047 13039 */
13048 13040 void QCPLegend::setFont(const QFont &font)
13049 13041 {
13050 mFont = font;
13051 for (int i=0; i<itemCount(); ++i)
13052 {
13053 if (item(i))
13054 item(i)->setFont(mFont);
13042 mFont = font;
13043 for (int i=0; i<itemCount(); ++i)
13044 {
13045 if (item(i))
13046 item(i)->setFont(mFont);
13055 13047 }
13056 13048 }
13057 13049
@@ -13066,11 +13058,11 void QCPLegend::setFont(const QFont &fon
13066 13058 */
13067 13059 void QCPLegend::setTextColor(const QColor &color)
13068 13060 {
13069 mTextColor = color;
13070 for (int i=0; i<itemCount(); ++i)
13071 {
13072 if (item(i))
13073 item(i)->setTextColor(color);
13061 mTextColor = color;
13062 for (int i=0; i<itemCount(); ++i)
13063 {
13064 if (item(i))
13065 item(i)->setTextColor(color);
13074 13066 }
13075 13067 }
13076 13068
@@ -13080,15 +13072,15 void QCPLegend::setTextColor(const QColo
13080 13072 */
13081 13073 void QCPLegend::setIconSize(const QSize &size)
13082 13074 {
13083 mIconSize = size;
13075 mIconSize = size;
13084 13076 }
13085 13077
13086 13078 /*! \overload
13087 13079 */
13088 13080 void QCPLegend::setIconSize(int width, int height)
13089 13081 {
13090 mIconSize.setWidth(width);
13091 mIconSize.setHeight(height);
13082 mIconSize.setWidth(width);
13083 mIconSize.setHeight(height);
13092 13084 }
13093 13085
13094 13086 /*!
@@ -13098,7 +13090,7 void QCPLegend::setIconSize(int width, i
13098 13090 */
13099 13091 void QCPLegend::setIconTextPadding(int padding)
13100 13092 {
13101 mIconTextPadding = padding;
13093 mIconTextPadding = padding;
13102 13094 }
13103 13095
13104 13096 /*!
@@ -13109,7 +13101,7 void QCPLegend::setIconTextPadding(int p
13109 13101 */
13110 13102 void QCPLegend::setIconBorderPen(const QPen &pen)
13111 13103 {
13112 mIconBorderPen = pen;
13104 mIconBorderPen = pen;
13113 13105 }
13114 13106
13115 13107 /*!
@@ -13124,10 +13116,10 void QCPLegend::setIconBorderPen(const Q
13124 13116 */
13125 13117 void QCPLegend::setSelectableParts(const SelectableParts &selectable)
13126 13118 {
13127 if (mSelectableParts != selectable)
13128 {
13129 mSelectableParts = selectable;
13130 emit selectableChanged(mSelectableParts);
13119 if (mSelectableParts != selectable)
13120 {
13121 mSelectableParts = selectable;
13122 emit selectableChanged(mSelectableParts);
13131 13123 }
13132 13124 }
13133 13125
@@ -13154,26 +13146,26 void QCPLegend::setSelectableParts(const
13154 13146 */
13155 13147 void QCPLegend::setSelectedParts(const SelectableParts &selected)
13156 13148 {
13157 SelectableParts newSelected = selected;
13158 mSelectedParts = this->selectedParts(); // update mSelectedParts in case item selection changed
13159
13160 if (mSelectedParts != newSelected)
13161 {
13162 if (!mSelectedParts.testFlag(spItems) && newSelected.testFlag(spItems)) // attempt to set spItems flag (can't do that)
13163 {
13164 qDebug() << Q_FUNC_INFO << "spItems flag can not be set, it can only be unset with this function";
13165 newSelected &= ~spItems;
13166 }
13167 if (mSelectedParts.testFlag(spItems) && !newSelected.testFlag(spItems)) // spItems flag was unset, so clear item selection
13168 {
13169 for (int i=0; i<itemCount(); ++i)
13170 {
13171 if (item(i))
13172 item(i)->setSelected(false);
13173 }
13174 }
13175 mSelectedParts = newSelected;
13176 emit selectionChanged(mSelectedParts);
13149 SelectableParts newSelected = selected;
13150 mSelectedParts = this->selectedParts(); // update mSelectedParts in case item selection changed
13151
13152 if (mSelectedParts != newSelected)
13153 {
13154 if (!mSelectedParts.testFlag(spItems) && newSelected.testFlag(spItems)) // attempt to set spItems flag (can't do that)
13155 {
13156 qDebug() << Q_FUNC_INFO << "spItems flag can not be set, it can only be unset with this function";
13157 newSelected &= ~spItems;
13158 }
13159 if (mSelectedParts.testFlag(spItems) && !newSelected.testFlag(spItems)) // spItems flag was unset, so clear item selection
13160 {
13161 for (int i=0; i<itemCount(); ++i)
13162 {
13163 if (item(i))
13164 item(i)->setSelected(false);
13165 }
13166 }
13167 mSelectedParts = newSelected;
13168 emit selectionChanged(mSelectedParts);
13177 13169 }
13178 13170 }
13179 13171
@@ -13185,7 +13177,7 void QCPLegend::setSelectedParts(const S
13185 13177 */
13186 13178 void QCPLegend::setSelectedBorderPen(const QPen &pen)
13187 13179 {
13188 mSelectedBorderPen = pen;
13180 mSelectedBorderPen = pen;
13189 13181 }
13190 13182
13191 13183 /*!
@@ -13195,7 +13187,7 void QCPLegend::setSelectedBorderPen(con
13195 13187 */
13196 13188 void QCPLegend::setSelectedIconBorderPen(const QPen &pen)
13197 13189 {
13198 mSelectedIconBorderPen = pen;
13190 mSelectedIconBorderPen = pen;
13199 13191 }
13200 13192
13201 13193 /*!
@@ -13206,7 +13198,7 void QCPLegend::setSelectedIconBorderPen
13206 13198 */
13207 13199 void QCPLegend::setSelectedBrush(const QBrush &brush)
13208 13200 {
13209 mSelectedBrush = brush;
13201 mSelectedBrush = brush;
13210 13202 }
13211 13203
13212 13204 /*!
@@ -13218,11 +13210,11 void QCPLegend::setSelectedBrush(const Q
13218 13210 */
13219 13211 void QCPLegend::setSelectedFont(const QFont &font)
13220 13212 {
13221 mSelectedFont = font;
13222 for (int i=0; i<itemCount(); ++i)
13223 {
13224 if (item(i))
13225 item(i)->setSelectedFont(font);
13213 mSelectedFont = font;
13214 for (int i=0; i<itemCount(); ++i)
13215 {
13216 if (item(i))
13217 item(i)->setSelectedFont(font);
13226 13218 }
13227 13219 }
13228 13220
@@ -13235,11 +13227,11 void QCPLegend::setSelectedFont(const QF
13235 13227 */
13236 13228 void QCPLegend::setSelectedTextColor(const QColor &color)
13237 13229 {
13238 mSelectedTextColor = color;
13239 for (int i=0; i<itemCount(); ++i)
13240 {
13241 if (item(i))
13242 item(i)->setSelectedTextColor(color);
13230 mSelectedTextColor = color;
13231 for (int i=0; i<itemCount(); ++i)
13232 {
13233 if (item(i))
13234 item(i)->setSelectedTextColor(color);
13243 13235 }
13244 13236 }
13245 13237
@@ -13250,7 +13242,7 void QCPLegend::setSelectedTextColor(con
13250 13242 */
13251 13243 QCPAbstractLegendItem *QCPLegend::item(int index) const
13252 13244 {
13253 return qobject_cast<QCPAbstractLegendItem*>(elementAt(index));
13245 return qobject_cast<QCPAbstractLegendItem*>(elementAt(index));
13254 13246 }
13255 13247
13256 13248 /*!
@@ -13261,15 +13253,15 QCPAbstractLegendItem *QCPLegend::item(i
13261 13253 */
13262 13254 QCPPlottableLegendItem *QCPLegend::itemWithPlottable(const QCPAbstractPlottable *plottable) const
13263 13255 {
13264 for (int i=0; i<itemCount(); ++i)
13265 {
13266 if (QCPPlottableLegendItem *pli = qobject_cast<QCPPlottableLegendItem*>(item(i)))
13267 {
13268 if (pli->plottable() == plottable)
13269 return pli;
13270 }
13271 }
13272 return 0;
13256 for (int i=0; i<itemCount(); ++i)
13257 {
13258 if (QCPPlottableLegendItem *pli = qobject_cast<QCPPlottableLegendItem*>(item(i)))
13259 {
13260 if (pli->plottable() == plottable)
13261 return pli;
13262 }
13263 }
13264 return 0;
13273 13265 }
13274 13266
13275 13267 /*!
@@ -13278,7 +13270,7 QCPPlottableLegendItem *QCPLegend::itemW
13278 13270 */
13279 13271 int QCPLegend::itemCount() const
13280 13272 {
13281 return elementCount();
13273 return elementCount();
13282 13274 }
13283 13275
13284 13276 /*!
@@ -13286,12 +13278,12 int QCPLegend::itemCount() const
13286 13278 */
13287 13279 bool QCPLegend::hasItem(QCPAbstractLegendItem *item) const
13288 13280 {
13289 for (int i=0; i<itemCount(); ++i)
13290 {
13291 if (item == this->item(i))
13292 return true;
13293 }
13294 return false;
13281 for (int i=0; i<itemCount(); ++i)
13282 {
13283 if (item == this->item(i))
13284 return true;
13285 }
13286 return false;
13295 13287 }
13296 13288
13297 13289 /*!
@@ -13302,7 +13294,7 bool QCPLegend::hasItem(QCPAbstractLegen
13302 13294 */
13303 13295 bool QCPLegend::hasItemWithPlottable(const QCPAbstractPlottable *plottable) const
13304 13296 {
13305 return itemWithPlottable(plottable);
13297 return itemWithPlottable(plottable);
13306 13298 }
13307 13299
13308 13300 /*!
@@ -13314,11 +13306,11 bool QCPLegend::hasItemWithPlottable(con
13314 13306 */
13315 13307 bool QCPLegend::addItem(QCPAbstractLegendItem *item)
13316 13308 {
13317 if (!hasItem(item))
13318 {
13319 return addElement(rowCount(), 0, item);
13320 } else
13321 return false;
13309 if (!hasItem(item))
13310 {
13311 return addElement(rowCount(), 0, item);
13312 } else
13313 return false;
13322 13314 }
13323 13315
13324 13316 /*!
@@ -13330,13 +13322,13 bool QCPLegend::addItem(QCPAbstractLegen
13330 13322 */
13331 13323 bool QCPLegend::removeItem(int index)
13332 13324 {
13333 if (QCPAbstractLegendItem *ali = item(index))
13334 {
13335 bool success = remove(ali);
13336 simplify();
13337 return success;
13338 } else
13339 return false;
13325 if (QCPAbstractLegendItem *ali = item(index))
13326 {
13327 bool success = remove(ali);
13328 simplify();
13329 return success;
13330 } else
13331 return false;
13340 13332 }
13341 13333
13342 13334 /*! \overload
@@ -13349,9 +13341,9 bool QCPLegend::removeItem(int index)
13349 13341 */
13350 13342 bool QCPLegend::removeItem(QCPAbstractLegendItem *item)
13351 13343 {
13352 bool success = remove(item);
13353 simplify();
13354 return success;
13344 bool success = remove(item);
13345 simplify();
13346 return success;
13355 13347 }
13356 13348
13357 13349 /*!
@@ -13359,8 +13351,8 bool QCPLegend::removeItem(QCPAbstractLe
13359 13351 */
13360 13352 void QCPLegend::clearItems()
13361 13353 {
13362 for (int i=itemCount()-1; i>=0; --i)
13363 removeItem(i);
13354 for (int i=itemCount()-1; i>=0; --i)
13355 removeItem(i);
13364 13356 }
13365 13357
13366 13358 /*!
@@ -13371,16 +13363,16 void QCPLegend::clearItems()
13371 13363 */
13372 13364 QList<QCPAbstractLegendItem *> QCPLegend::selectedItems() const
13373 13365 {
13374 QList<QCPAbstractLegendItem*> result;
13375 for (int i=0; i<itemCount(); ++i)
13376 {
13377 if (QCPAbstractLegendItem *ali = item(i))
13378 {
13379 if (ali->selected())
13380 result.append(ali);
13381 }
13382 }
13383 return result;
13366 QList<QCPAbstractLegendItem*> result;
13367 for (int i=0; i<itemCount(); ++i)
13368 {
13369 if (QCPAbstractLegendItem *ali = item(i))
13370 {
13371 if (ali->selected())
13372 result.append(ali);
13373 }
13374 }
13375 return result;
13384 13376 }
13385 13377
13386 13378 /*! \internal
@@ -13398,7 +13390,7 QList<QCPAbstractLegendItem *> QCPLegend
13398 13390 */
13399 13391 void QCPLegend::applyDefaultAntialiasingHint(QCPPainter *painter) const
13400 13392 {
13401 applyAntialiasingHint(painter, mAntialiased, QCP::aeLegend);
13393 applyAntialiasingHint(painter, mAntialiased, QCP::aeLegend);
13402 13394 }
13403 13395
13404 13396 /*! \internal
@@ -13408,7 +13400,7 void QCPLegend::applyDefaultAntialiasing
13408 13400 */
13409 13401 QPen QCPLegend::getBorderPen() const
13410 13402 {
13411 return mSelectedParts.testFlag(spLegendBox) ? mSelectedBorderPen : mBorderPen;
13403 return mSelectedParts.testFlag(spLegendBox) ? mSelectedBorderPen : mBorderPen;
13412 13404 }
13413 13405
13414 13406 /*! \internal
@@ -13418,7 +13410,7 QPen QCPLegend::getBorderPen() const
13418 13410 */
13419 13411 QBrush QCPLegend::getBrush() const
13420 13412 {
13421 return mSelectedParts.testFlag(spLegendBox) ? mSelectedBrush : mBrush;
13413 return mSelectedParts.testFlag(spLegendBox) ? mSelectedBrush : mBrush;
13422 13414 }
13423 13415
13424 13416 /*! \internal
@@ -13428,70 +13420,70 QBrush QCPLegend::getBrush() const
13428 13420 */
13429 13421 void QCPLegend::draw(QCPPainter *painter)
13430 13422 {
13431 // draw background rect:
13432 painter->setBrush(getBrush());
13433 painter->setPen(getBorderPen());
13434 painter->drawRect(mOuterRect);
13423 // draw background rect:
13424 painter->setBrush(getBrush());
13425 painter->setPen(getBorderPen());
13426 painter->drawRect(mOuterRect);
13435 13427 }
13436 13428
13437 13429 /* inherits documentation from base class */
13438 13430 double QCPLegend::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
13439 13431 {
13440 if (!mParentPlot) return -1;
13441 if (onlySelectable && !mSelectableParts.testFlag(spLegendBox))
13432 if (!mParentPlot) return -1;
13433 if (onlySelectable && !mSelectableParts.testFlag(spLegendBox))
13434 return -1;
13435
13436 if (mOuterRect.contains(pos.toPoint()))
13437 {
13438 if (details) details->setValue(spLegendBox);
13439 return mParentPlot->selectionTolerance()*0.99;
13440 }
13442 13441 return -1;
13443
13444 if (mOuterRect.contains(pos.toPoint()))
13445 {
13446 if (details) details->setValue(spLegendBox);
13447 return mParentPlot->selectionTolerance()*0.99;
13448 }
13449 return -1;
13450 13442 }
13451 13443
13452 13444 /* inherits documentation from base class */
13453 13445 void QCPLegend::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged)
13454 13446 {
13455 Q_UNUSED(event)
13456 mSelectedParts = selectedParts(); // in case item selection has changed
13457 if (details.value<SelectablePart>() == spLegendBox && mSelectableParts.testFlag(spLegendBox))
13458 {
13459 SelectableParts selBefore = mSelectedParts;
13460 setSelectedParts(additive ? mSelectedParts^spLegendBox : mSelectedParts|spLegendBox); // no need to unset spItems in !additive case, because they will be deselected by QCustomPlot (they're normal QCPLayerables with own deselectEvent)
13461 if (selectionStateChanged)
13462 *selectionStateChanged = mSelectedParts != selBefore;
13447 Q_UNUSED(event)
13448 mSelectedParts = selectedParts(); // in case item selection has changed
13449 if (details.value<SelectablePart>() == spLegendBox && mSelectableParts.testFlag(spLegendBox))
13450 {
13451 SelectableParts selBefore = mSelectedParts;
13452 setSelectedParts(additive ? mSelectedParts^spLegendBox : mSelectedParts|spLegendBox); // no need to unset spItems in !additive case, because they will be deselected by QCustomPlot (they're normal QCPLayerables with own deselectEvent)
13453 if (selectionStateChanged)
13454 *selectionStateChanged = mSelectedParts != selBefore;
13463 13455 }
13464 13456 }
13465 13457
13466 13458 /* inherits documentation from base class */
13467 13459 void QCPLegend::deselectEvent(bool *selectionStateChanged)
13468 13460 {
13469 mSelectedParts = selectedParts(); // in case item selection has changed
13470 if (mSelectableParts.testFlag(spLegendBox))
13471 {
13472 SelectableParts selBefore = mSelectedParts;
13473 setSelectedParts(selectedParts() & ~spLegendBox);
13474 if (selectionStateChanged)
13475 *selectionStateChanged = mSelectedParts != selBefore;
13461 mSelectedParts = selectedParts(); // in case item selection has changed
13462 if (mSelectableParts.testFlag(spLegendBox))
13463 {
13464 SelectableParts selBefore = mSelectedParts;
13465 setSelectedParts(selectedParts() & ~spLegendBox);
13466 if (selectionStateChanged)
13467 *selectionStateChanged = mSelectedParts != selBefore;
13476 13468 }
13477 13469 }
13478 13470
13479 13471 /* inherits documentation from base class */
13480 13472 QCP::Interaction QCPLegend::selectionCategory() const
13481 13473 {
13482 return QCP::iSelectLegend;
13474 return QCP::iSelectLegend;
13483 13475 }
13484 13476
13485 13477 /* inherits documentation from base class */
13486 13478 QCP::Interaction QCPAbstractLegendItem::selectionCategory() const
13487 13479 {
13488 return QCP::iSelectLegend;
13480 return QCP::iSelectLegend;
13489 13481 }
13490 13482
13491 13483 /* inherits documentation from base class */
13492 13484 void QCPLegend::parentPlotInitialized(QCustomPlot *parentPlot)
13493 13485 {
13494 Q_UNUSED(parentPlot)
13486 Q_UNUSED(parentPlot)
13495 13487 }
13496 13488
13497 13489
@@ -13535,21 +13527,21 void QCPLegend::parentPlotInitialized(QC
13535 13527 To set the title text in the constructor, rather use \ref QCPPlotTitle(QCustomPlot *parentPlot, const QString &text).
13536 13528 */
13537 13529 QCPPlotTitle::QCPPlotTitle(QCustomPlot *parentPlot) :
13538 QCPLayoutElement(parentPlot),
13539 mFont(QFont(QLatin1String("sans serif"), 13*1.5, QFont::Bold)),
13540 mTextColor(Qt::black),
13541 mSelectedFont(QFont(QLatin1String("sans serif"), 13*1.6, QFont::Bold)),
13542 mSelectedTextColor(Qt::blue),
13543 mSelectable(false),
13544 mSelected(false)
13545 {
13546 if (parentPlot)
13547 {
13548 setLayer(parentPlot->currentLayer());
13549 mFont = QFont(parentPlot->font().family(), parentPlot->font().pointSize()*1.5, QFont::Bold);
13550 mSelectedFont = QFont(parentPlot->font().family(), parentPlot->font().pointSize()*1.6, QFont::Bold);
13551 }
13552 setMargins(QMargins(5, 5, 5, 0));
13530 QCPLayoutElement(parentPlot),
13531 mFont(QFont(QLatin1String("sans serif"), 13*1.5, QFont::Bold)),
13532 mTextColor(Qt::black),
13533 mSelectedFont(QFont(QLatin1String("sans serif"), 13*1.6, QFont::Bold)),
13534 mSelectedTextColor(Qt::blue),
13535 mSelectable(false),
13536 mSelected(false)
13537 {
13538 if (parentPlot)
13539 {
13540 setLayer(parentPlot->currentLayer());
13541 mFont = QFont(parentPlot->font().family(), parentPlot->font().pointSize()*1.5, QFont::Bold);
13542 mSelectedFont = QFont(parentPlot->font().family(), parentPlot->font().pointSize()*1.6, QFont::Bold);
13543 }
13544 setMargins(QMargins(5, 5, 5, 0));
13553 13545 }
13554 13546
13555 13547 /*! \overload
@@ -13557,17 +13549,17 QCPPlotTitle::QCPPlotTitle(QCustomPlot *
13557 13549 Creates a new QCPPlotTitle instance and sets default values. The initial text is set to \a text.
13558 13550 */
13559 13551 QCPPlotTitle::QCPPlotTitle(QCustomPlot *parentPlot, const QString &text) :
13560 QCPLayoutElement(parentPlot),
13561 mText(text),
13562 mFont(QFont(parentPlot->font().family(), parentPlot->font().pointSize()*1.5, QFont::Bold)),
13563 mTextColor(Qt::black),
13564 mSelectedFont(QFont(parentPlot->font().family(), parentPlot->font().pointSize()*1.6, QFont::Bold)),
13565 mSelectedTextColor(Qt::blue),
13566 mSelectable(false),
13567 mSelected(false)
13568 {
13569 setLayer(QLatin1String("axes"));
13570 setMargins(QMargins(5, 5, 5, 0));
13552 QCPLayoutElement(parentPlot),
13553 mText(text),
13554 mFont(QFont(parentPlot->font().family(), parentPlot->font().pointSize()*1.5, QFont::Bold)),
13555 mTextColor(Qt::black),
13556 mSelectedFont(QFont(parentPlot->font().family(), parentPlot->font().pointSize()*1.6, QFont::Bold)),
13557 mSelectedTextColor(Qt::blue),
13558 mSelectable(false),
13559 mSelected(false)
13560 {
13561 setLayer(QLatin1String("axes"));
13562 setMargins(QMargins(5, 5, 5, 0));
13571 13563 }
13572 13564
13573 13565 /*!
@@ -13577,7 +13569,7 QCPPlotTitle::QCPPlotTitle(QCustomPlot *
13577 13569 */
13578 13570 void QCPPlotTitle::setText(const QString &text)
13579 13571 {
13580 mText = text;
13572 mText = text;
13581 13573 }
13582 13574
13583 13575 /*!
@@ -13587,7 +13579,7 void QCPPlotTitle::setText(const QString
13587 13579 */
13588 13580 void QCPPlotTitle::setFont(const QFont &font)
13589 13581 {
13590 mFont = font;
13582 mFont = font;
13591 13583 }
13592 13584
13593 13585 /*!
@@ -13597,7 +13589,7 void QCPPlotTitle::setFont(const QFont &
13597 13589 */
13598 13590 void QCPPlotTitle::setTextColor(const QColor &color)
13599 13591 {
13600 mTextColor = color;
13592 mTextColor = color;
13601 13593 }
13602 13594
13603 13595 /*!
@@ -13607,7 +13599,7 void QCPPlotTitle::setTextColor(const QC
13607 13599 */
13608 13600 void QCPPlotTitle::setSelectedFont(const QFont &font)
13609 13601 {
13610 mSelectedFont = font;
13602 mSelectedFont = font;
13611 13603 }
13612 13604
13613 13605 /*!
@@ -13617,7 +13609,7 void QCPPlotTitle::setSelectedFont(const
13617 13609 */
13618 13610 void QCPPlotTitle::setSelectedTextColor(const QColor &color)
13619 13611 {
13620 mSelectedTextColor = color;
13612 mSelectedTextColor = color;
13621 13613 }
13622 13614
13623 13615 /*!
@@ -13628,10 +13620,10 void QCPPlotTitle::setSelectedTextColor(
13628 13620 */
13629 13621 void QCPPlotTitle::setSelectable(bool selectable)
13630 13622 {
13631 if (mSelectable != selectable)
13632 {
13633 mSelectable = selectable;
13634 emit selectableChanged(mSelectable);
13623 if (mSelectable != selectable)
13624 {
13625 mSelectable = selectable;
13626 emit selectableChanged(mSelectable);
13635 13627 }
13636 13628 }
13637 13629
@@ -13644,84 +13636,84 void QCPPlotTitle::setSelectable(bool se
13644 13636 */
13645 13637 void QCPPlotTitle::setSelected(bool selected)
13646 13638 {
13647 if (mSelected != selected)
13648 {
13649 mSelected = selected;
13650 emit selectionChanged(mSelected);
13639 if (mSelected != selected)
13640 {
13641 mSelected = selected;
13642 emit selectionChanged(mSelected);
13651 13643 }
13652 13644 }
13653 13645
13654 13646 /* inherits documentation from base class */
13655 13647 void QCPPlotTitle::applyDefaultAntialiasingHint(QCPPainter *painter) const
13656 13648 {
13657 applyAntialiasingHint(painter, mAntialiased, QCP::aeNone);
13649 applyAntialiasingHint(painter, mAntialiased, QCP::aeNone);
13658 13650 }
13659 13651
13660 13652 /* inherits documentation from base class */
13661 13653 void QCPPlotTitle::draw(QCPPainter *painter)
13662 13654 {
13663 painter->setFont(mainFont());
13664 painter->setPen(QPen(mainTextColor()));
13665 painter->drawText(mRect, Qt::AlignCenter, mText, &mTextBoundingRect);
13655 painter->setFont(mainFont());
13656 painter->setPen(QPen(mainTextColor()));
13657 painter->drawText(mRect, Qt::AlignCenter, mText, &mTextBoundingRect);
13666 13658 }
13667 13659
13668 13660 /* inherits documentation from base class */
13669 13661 QSize QCPPlotTitle::minimumSizeHint() const
13670 13662 {
13671 QFontMetrics metrics(mFont);
13672 QSize result = metrics.boundingRect(0, 0, 0, 0, Qt::AlignCenter, mText).size();
13673 result.rwidth() += mMargins.left() + mMargins.right();
13674 result.rheight() += mMargins.top() + mMargins.bottom();
13675 return result;
13663 QFontMetrics metrics(mFont);
13664 QSize result = metrics.boundingRect(0, 0, 0, 0, Qt::AlignCenter, mText).size();
13665 result.rwidth() += mMargins.left() + mMargins.right();
13666 result.rheight() += mMargins.top() + mMargins.bottom();
13667 return result;
13676 13668 }
13677 13669
13678 13670 /* inherits documentation from base class */
13679 13671 QSize QCPPlotTitle::maximumSizeHint() const
13680 13672 {
13681 QFontMetrics metrics(mFont);
13682 QSize result = metrics.boundingRect(0, 0, 0, 0, Qt::AlignCenter, mText).size();
13683 result.rheight() += mMargins.top() + mMargins.bottom();
13684 result.setWidth(QWIDGETSIZE_MAX);
13685 return result;
13673 QFontMetrics metrics(mFont);
13674 QSize result = metrics.boundingRect(0, 0, 0, 0, Qt::AlignCenter, mText).size();
13675 result.rheight() += mMargins.top() + mMargins.bottom();
13676 result.setWidth(QWIDGETSIZE_MAX);
13677 return result;
13686 13678 }
13687 13679
13688 13680 /* inherits documentation from base class */
13689 13681 void QCPPlotTitle::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged)
13690 13682 {
13691 Q_UNUSED(event)
13692 Q_UNUSED(details)
13693 if (mSelectable)
13694 {
13695 bool selBefore = mSelected;
13696 setSelected(additive ? !mSelected : true);
13697 if (selectionStateChanged)
13698 *selectionStateChanged = mSelected != selBefore;
13683 Q_UNUSED(event)
13684 Q_UNUSED(details)
13685 if (mSelectable)
13686 {
13687 bool selBefore = mSelected;
13688 setSelected(additive ? !mSelected : true);
13689 if (selectionStateChanged)
13690 *selectionStateChanged = mSelected != selBefore;
13699 13691 }
13700 13692 }
13701 13693
13702 13694 /* inherits documentation from base class */
13703 13695 void QCPPlotTitle::deselectEvent(bool *selectionStateChanged)
13704 13696 {
13705 if (mSelectable)
13706 {
13707 bool selBefore = mSelected;
13708 setSelected(false);
13709 if (selectionStateChanged)
13710 *selectionStateChanged = mSelected != selBefore;
13697 if (mSelectable)
13698 {
13699 bool selBefore = mSelected;
13700 setSelected(false);
13701 if (selectionStateChanged)
13702 *selectionStateChanged = mSelected != selBefore;
13711 13703 }
13712 13704 }
13713 13705
13714 13706 /* inherits documentation from base class */
13715 13707 double QCPPlotTitle::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
13716 13708 {
13717 Q_UNUSED(details)
13718 if (onlySelectable && !mSelectable)
13719 return -1;
13720
13721 if (mTextBoundingRect.contains(pos.toPoint()))
13722 return mParentPlot->selectionTolerance()*0.99;
13723 else
13724 return -1;
13709 Q_UNUSED(details)
13710 if (onlySelectable && !mSelectable)
13711 return -1;
13712
13713 if (mTextBoundingRect.contains(pos.toPoint()))
13714 return mParentPlot->selectionTolerance()*0.99;
13715 else
13716 return -1;
13725 13717 }
13726 13718
13727 13719 /*! \internal
@@ -13731,7 +13723,7 double QCPPlotTitle::selectTest(const QP
13731 13723 */
13732 13724 QFont QCPPlotTitle::mainFont() const
13733 13725 {
13734 return mSelected ? mSelectedFont : mFont;
13726 return mSelected ? mSelectedFont : mFont;
13735 13727 }
13736 13728
13737 13729 /*! \internal
@@ -13741,7 +13733,7 QFont QCPPlotTitle::mainFont() const
13741 13733 */
13742 13734 QColor QCPPlotTitle::mainTextColor() const
13743 13735 {
13744 return mSelected ? mSelectedTextColor : mTextColor;
13736 return mSelected ? mSelectedTextColor : mTextColor;
13745 13737 }
13746 13738
13747 13739
@@ -13842,60 +13834,60 QColor QCPPlotTitle::mainTextColor() con
13842 13834 Constructs a new QCPColorScale.
13843 13835 */
13844 13836 QCPColorScale::QCPColorScale(QCustomPlot *parentPlot) :
13845 QCPLayoutElement(parentPlot),
13846 mType(QCPAxis::atTop), // set to atTop such that setType(QCPAxis::atRight) below doesn't skip work because it thinks it's already atRight
13847 mDataScaleType(QCPAxis::stLinear),
13848 mBarWidth(20),
13849 mAxisRect(new QCPColorScaleAxisRectPrivate(this))
13850 {
13851 setMinimumMargins(QMargins(0, 6, 0, 6)); // for default right color scale types, keep some room at bottom and top (important if no margin group is used)
13852 setType(QCPAxis::atRight);
13853 setDataRange(QCPRange(0, 6));
13837 QCPLayoutElement(parentPlot),
13838 mType(QCPAxis::atTop), // set to atTop such that setType(QCPAxis::atRight) below doesn't skip work because it thinks it's already atRight
13839 mDataScaleType(QCPAxis::stLinear),
13840 mBarWidth(20),
13841 mAxisRect(new QCPColorScaleAxisRectPrivate(this))
13842 {
13843 setMinimumMargins(QMargins(0, 6, 0, 6)); // for default right color scale types, keep some room at bottom and top (important if no margin group is used)
13844 setType(QCPAxis::atRight);
13845 setDataRange(QCPRange(0, 6));
13854 13846 }
13855 13847
13856 13848 QCPColorScale::~QCPColorScale()
13857 13849 {
13858 delete mAxisRect;
13850 delete mAxisRect;
13859 13851 }
13860 13852
13861 13853 /* undocumented getter */
13862 13854 QString QCPColorScale::label() const
13863 13855 {
13864 if (!mColorAxis)
13865 {
13866 qDebug() << Q_FUNC_INFO << "internal color axis undefined";
13867 return QString();
13868 }
13869
13870 return mColorAxis.data()->label();
13856 if (!mColorAxis)
13857 {
13858 qDebug() << Q_FUNC_INFO << "internal color axis undefined";
13859 return QString();
13860 }
13861
13862 return mColorAxis.data()->label();
13871 13863 }
13872 13864
13873 13865 /* undocumented getter */
13874 13866 bool QCPColorScale::rangeDrag() const
13875 13867 {
13876 if (!mAxisRect)
13877 {
13878 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
13879 return false;
13880 }
13881
13882 return mAxisRect.data()->rangeDrag().testFlag(QCPAxis::orientation(mType)) &&
13883 mAxisRect.data()->rangeDragAxis(QCPAxis::orientation(mType)) &&
13884 mAxisRect.data()->rangeDragAxis(QCPAxis::orientation(mType))->orientation() == QCPAxis::orientation(mType);
13868 if (!mAxisRect)
13869 {
13870 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
13871 return false;
13872 }
13873
13874 return mAxisRect.data()->rangeDrag().testFlag(QCPAxis::orientation(mType)) &&
13875 mAxisRect.data()->rangeDragAxis(QCPAxis::orientation(mType)) &&
13876 mAxisRect.data()->rangeDragAxis(QCPAxis::orientation(mType))->orientation() == QCPAxis::orientation(mType);
13885 13877 }
13886 13878
13887 13879 /* undocumented getter */
13888 13880 bool QCPColorScale::rangeZoom() const
13889 13881 {
13890 if (!mAxisRect)
13891 {
13892 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
13893 return false;
13894 }
13895
13896 return mAxisRect.data()->rangeZoom().testFlag(QCPAxis::orientation(mType)) &&
13897 mAxisRect.data()->rangeZoomAxis(QCPAxis::orientation(mType)) &&
13898 mAxisRect.data()->rangeZoomAxis(QCPAxis::orientation(mType))->orientation() == QCPAxis::orientation(mType);
13882 if (!mAxisRect)
13883 {
13884 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
13885 return false;
13886 }
13887
13888 return mAxisRect.data()->rangeZoom().testFlag(QCPAxis::orientation(mType)) &&
13889 mAxisRect.data()->rangeZoomAxis(QCPAxis::orientation(mType)) &&
13890 mAxisRect.data()->rangeZoomAxis(QCPAxis::orientation(mType))->orientation() == QCPAxis::orientation(mType);
13899 13891 }
13900 13892
13901 13893 /*!
@@ -13907,42 +13899,42 bool QCPColorScale::rangeZoom() const
13907 13899 */
13908 13900 void QCPColorScale::setType(QCPAxis::AxisType type)
13909 13901 {
13910 if (!mAxisRect)
13911 {
13912 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
13913 return;
13914 }
13915 if (mType != type)
13916 {
13917 mType = type;
13918 QCPRange rangeTransfer(0, 6);
13919 double logBaseTransfer = 10;
13920 QString labelTransfer;
13921 // revert some settings on old axis:
13922 if (mColorAxis)
13923 {
13924 rangeTransfer = mColorAxis.data()->range();
13925 labelTransfer = mColorAxis.data()->label();
13926 logBaseTransfer = mColorAxis.data()->scaleLogBase();
13927 mColorAxis.data()->setLabel(QString());
13928 disconnect(mColorAxis.data(), SIGNAL(rangeChanged(QCPRange)), this, SLOT(setDataRange(QCPRange)));
13929 disconnect(mColorAxis.data(), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), this, SLOT(setDataScaleType(QCPAxis::ScaleType)));
13930 }
13931 foreach (QCPAxis::AxisType atype, QList<QCPAxis::AxisType>() << QCPAxis::atLeft << QCPAxis::atRight << QCPAxis::atBottom << QCPAxis::atTop)
13932 {
13933 mAxisRect.data()->axis(atype)->setTicks(atype == mType);
13934 mAxisRect.data()->axis(atype)->setTickLabels(atype== mType);
13935 }
13936 // set new mColorAxis pointer:
13937 mColorAxis = mAxisRect.data()->axis(mType);
13938 // transfer settings to new axis:
13939 mColorAxis.data()->setRange(rangeTransfer); // transfer range of old axis to new one (necessary if axis changes from vertical to horizontal or vice versa)
13940 mColorAxis.data()->setLabel(labelTransfer);
13941 mColorAxis.data()->setScaleLogBase(logBaseTransfer); // scaleType is synchronized among axes in realtime via signals (connected in QCPColorScale ctor), so we only need to take care of log base here
13942 connect(mColorAxis.data(), SIGNAL(rangeChanged(QCPRange)), this, SLOT(setDataRange(QCPRange)));
13943 connect(mColorAxis.data(), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), this, SLOT(setDataScaleType(QCPAxis::ScaleType)));
13944 mAxisRect.data()->setRangeDragAxes(QCPAxis::orientation(mType) == Qt::Horizontal ? mColorAxis.data() : 0,
13945 QCPAxis::orientation(mType) == Qt::Vertical ? mColorAxis.data() : 0);
13902 if (!mAxisRect)
13903 {
13904 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
13905 return;
13906 }
13907 if (mType != type)
13908 {
13909 mType = type;
13910 QCPRange rangeTransfer(0, 6);
13911 double logBaseTransfer = 10;
13912 QString labelTransfer;
13913 // revert some settings on old axis:
13914 if (mColorAxis)
13915 {
13916 rangeTransfer = mColorAxis.data()->range();
13917 labelTransfer = mColorAxis.data()->label();
13918 logBaseTransfer = mColorAxis.data()->scaleLogBase();
13919 mColorAxis.data()->setLabel(QString());
13920 disconnect(mColorAxis.data(), SIGNAL(rangeChanged(QCPRange)), this, SLOT(setDataRange(QCPRange)));
13921 disconnect(mColorAxis.data(), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), this, SLOT(setDataScaleType(QCPAxis::ScaleType)));
13922 }
13923 foreach (QCPAxis::AxisType atype, QList<QCPAxis::AxisType>() << QCPAxis::atLeft << QCPAxis::atRight << QCPAxis::atBottom << QCPAxis::atTop)
13924 {
13925 mAxisRect.data()->axis(atype)->setTicks(atype == mType);
13926 mAxisRect.data()->axis(atype)->setTickLabels(atype== mType);
13927 }
13928 // set new mColorAxis pointer:
13929 mColorAxis = mAxisRect.data()->axis(mType);
13930 // transfer settings to new axis:
13931 mColorAxis.data()->setRange(rangeTransfer); // transfer range of old axis to new one (necessary if axis changes from vertical to horizontal or vice versa)
13932 mColorAxis.data()->setLabel(labelTransfer);
13933 mColorAxis.data()->setScaleLogBase(logBaseTransfer); // scaleType is synchronized among axes in realtime via signals (connected in QCPColorScale ctor), so we only need to take care of log base here
13934 connect(mColorAxis.data(), SIGNAL(rangeChanged(QCPRange)), this, SLOT(setDataRange(QCPRange)));
13935 connect(mColorAxis.data(), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), this, SLOT(setDataScaleType(QCPAxis::ScaleType)));
13936 mAxisRect.data()->setRangeDragAxes(QCPAxis::orientation(mType) == Qt::Horizontal ? mColorAxis.data() : 0,
13937 QCPAxis::orientation(mType) == Qt::Vertical ? mColorAxis.data() : 0);
13946 13938 }
13947 13939 }
13948 13940
@@ -13957,12 +13949,12 void QCPColorScale::setType(QCPAxis::Axi
13957 13949 */
13958 13950 void QCPColorScale::setDataRange(const QCPRange &dataRange)
13959 13951 {
13960 if (mDataRange.lower != dataRange.lower || mDataRange.upper != dataRange.upper)
13961 {
13962 mDataRange = dataRange;
13963 if (mColorAxis)
13964 mColorAxis.data()->setRange(mDataRange);
13965 emit dataRangeChanged(mDataRange);
13952 if (mDataRange.lower != dataRange.lower || mDataRange.upper != dataRange.upper)
13953 {
13954 mDataRange = dataRange;
13955 if (mColorAxis)
13956 mColorAxis.data()->setRange(mDataRange);
13957 emit dataRangeChanged(mDataRange);
13966 13958 }
13967 13959 }
13968 13960
@@ -13978,14 +13970,14 void QCPColorScale::setDataRange(const Q
13978 13970 */
13979 13971 void QCPColorScale::setDataScaleType(QCPAxis::ScaleType scaleType)
13980 13972 {
13981 if (mDataScaleType != scaleType)
13982 {
13983 mDataScaleType = scaleType;
13984 if (mColorAxis)
13985 mColorAxis.data()->setScaleType(mDataScaleType);
13986 if (mDataScaleType == QCPAxis::stLogarithmic)
13987 setDataRange(mDataRange.sanitizedForLogScale());
13988 emit dataScaleTypeChanged(mDataScaleType);
13973 if (mDataScaleType != scaleType)
13974 {
13975 mDataScaleType = scaleType;
13976 if (mColorAxis)
13977 mColorAxis.data()->setScaleType(mDataScaleType);
13978 if (mDataScaleType == QCPAxis::stLogarithmic)
13979 setDataRange(mDataRange.sanitizedForLogScale());
13980 emit dataScaleTypeChanged(mDataScaleType);
13989 13981 }
13990 13982 }
13991 13983
@@ -13998,12 +13990,12 void QCPColorScale::setDataScaleType(QCP
13998 13990 */
13999 13991 void QCPColorScale::setGradient(const QCPColorGradient &gradient)
14000 13992 {
14001 if (mGradient != gradient)
14002 {
14003 mGradient = gradient;
14004 if (mAxisRect)
14005 mAxisRect.data()->mGradientImageInvalidated = true;
14006 emit gradientChanged(mGradient);
13993 if (mGradient != gradient)
13994 {
13995 mGradient = gradient;
13996 if (mAxisRect)
13997 mAxisRect.data()->mGradientImageInvalidated = true;
13998 emit gradientChanged(mGradient);
14007 13999 }
14008 14000 }
14009 14001
@@ -14013,13 +14005,13 void QCPColorScale::setGradient(const QC
14013 14005 */
14014 14006 void QCPColorScale::setLabel(const QString &str)
14015 14007 {
14016 if (!mColorAxis)
14017 {
14018 qDebug() << Q_FUNC_INFO << "internal color axis undefined";
14019 return;
14020 }
14021
14022 mColorAxis.data()->setLabel(str);
14008 if (!mColorAxis)
14009 {
14010 qDebug() << Q_FUNC_INFO << "internal color axis undefined";
14011 return;
14012 }
14013
14014 mColorAxis.data()->setLabel(str);
14023 14015 }
14024 14016
14025 14017 /*!
@@ -14028,7 +14020,7 void QCPColorScale::setLabel(const QStri
14028 14020 */
14029 14021 void QCPColorScale::setBarWidth(int width)
14030 14022 {
14031 mBarWidth = width;
14023 mBarWidth = width;
14032 14024 }
14033 14025
14034 14026 /*!
@@ -14039,16 +14031,16 void QCPColorScale::setBarWidth(int widt
14039 14031 */
14040 14032 void QCPColorScale::setRangeDrag(bool enabled)
14041 14033 {
14042 if (!mAxisRect)
14043 {
14044 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14045 return;
14046 }
14047
14048 if (enabled)
14049 mAxisRect.data()->setRangeDrag(QCPAxis::orientation(mType));
14050 else
14051 mAxisRect.data()->setRangeDrag(0);
14034 if (!mAxisRect)
14035 {
14036 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14037 return;
14038 }
14039
14040 if (enabled)
14041 mAxisRect.data()->setRangeDrag(QCPAxis::orientation(mType));
14042 else
14043 mAxisRect.data()->setRangeDrag(0);
14052 14044 }
14053 14045
14054 14046 /*!
@@ -14059,16 +14051,16 void QCPColorScale::setRangeDrag(bool en
14059 14051 */
14060 14052 void QCPColorScale::setRangeZoom(bool enabled)
14061 14053 {
14062 if (!mAxisRect)
14063 {
14064 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14065 return;
14066 }
14067
14068 if (enabled)
14069 mAxisRect.data()->setRangeZoom(QCPAxis::orientation(mType));
14070 else
14071 mAxisRect.data()->setRangeZoom(0);
14054 if (!mAxisRect)
14055 {
14056 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14057 return;
14058 }
14059
14060 if (enabled)
14061 mAxisRect.data()->setRangeZoom(QCPAxis::orientation(mType));
14062 else
14063 mAxisRect.data()->setRangeZoom(0);
14072 14064 }
14073 14065
14074 14066 /*!
@@ -14076,14 +14068,14 void QCPColorScale::setRangeZoom(bool en
14076 14068 */
14077 14069 QList<QCPColorMap*> QCPColorScale::colorMaps() const
14078 14070 {
14079 QList<QCPColorMap*> result;
14080 for (int i=0; i<mParentPlot->plottableCount(); ++i)
14081 {
14082 if (QCPColorMap *cm = qobject_cast<QCPColorMap*>(mParentPlot->plottable(i)))
14083 if (cm->colorScale() == this)
14084 result.append(cm);
14085 }
14086 return result;
14071 QList<QCPColorMap*> result;
14072 for (int i=0; i<mParentPlot->plottableCount(); ++i)
14073 {
14074 if (QCPColorMap *cm = qobject_cast<QCPColorMap*>(mParentPlot->plottable(i)))
14075 if (cm->colorScale() == this)
14076 result.append(cm);
14077 }
14078 return result;
14087 14079 }
14088 14080
14089 14081 /*!
@@ -14094,95 +14086,95 QList<QCPColorMap*> QCPColorScale::color
14094 14086 */
14095 14087 void QCPColorScale::rescaleDataRange(bool onlyVisibleMaps)
14096 14088 {
14097 QList<QCPColorMap*> maps = colorMaps();
14098 QCPRange newRange;
14099 bool haveRange = false;
14100 int sign = 0; // TODO: should change this to QCPAbstractPlottable::SignDomain later (currently is protected, maybe move to QCP namespace)
14101 if (mDataScaleType == QCPAxis::stLogarithmic)
14102 sign = (mDataRange.upper < 0 ? -1 : 1);
14103 for (int i=0; i<maps.size(); ++i)
14104 {
14105 if (!maps.at(i)->realVisibility() && onlyVisibleMaps)
14106 continue;
14107 QCPRange mapRange;
14108 if (maps.at(i)->colorScale() == this)
14109 {
14110 bool currentFoundRange = true;
14111 mapRange = maps.at(i)->data()->dataBounds();
14112 if (sign == 1)
14113 {
14114 if (mapRange.lower <= 0 && mapRange.upper > 0)
14115 mapRange.lower = mapRange.upper*1e-3;
14116 else if (mapRange.lower <= 0 && mapRange.upper <= 0)
14117 currentFoundRange = false;
14089 QList<QCPColorMap*> maps = colorMaps();
14090 QCPRange newRange;
14091 bool haveRange = false;
14092 int sign = 0; // TODO: should change this to QCPAbstractPlottable::SignDomain later (currently is protected, maybe move to QCP namespace)
14093 if (mDataScaleType == QCPAxis::stLogarithmic)
14094 sign = (mDataRange.upper < 0 ? -1 : 1);
14095 for (int i=0; i<maps.size(); ++i)
14096 {
14097 if (!maps.at(i)->realVisibility() && onlyVisibleMaps)
14098 continue;
14099 QCPRange mapRange;
14100 if (maps.at(i)->colorScale() == this)
14101 {
14102 bool currentFoundRange = true;
14103 mapRange = maps.at(i)->data()->dataBounds();
14104 if (sign == 1)
14105 {
14106 if (mapRange.lower <= 0 && mapRange.upper > 0)
14107 mapRange.lower = mapRange.upper*1e-3;
14108 else if (mapRange.lower <= 0 && mapRange.upper <= 0)
14109 currentFoundRange = false;
14118 14110 } else if (sign == -1)
14119 14111 {
14120 if (mapRange.upper >= 0 && mapRange.lower < 0)
14121 mapRange.upper = mapRange.lower*1e-3;
14122 else if (mapRange.upper >= 0 && mapRange.lower >= 0)
14123 currentFoundRange = false;
14124 }
14125 if (currentFoundRange)
14126 {
14127 if (!haveRange)
14128 newRange = mapRange;
14129 else
14130 newRange.expand(mapRange);
14131 haveRange = true;
14132 }
14133 }
14134 }
14135 if (haveRange)
14136 {
14137 if (!QCPRange::validRange(newRange)) // likely due to range being zero (plottable has only constant data in this dimension), shift current range to at least center the data
14138 {
14139 double center = (newRange.lower+newRange.upper)*0.5; // upper and lower should be equal anyway, but just to make sure, incase validRange returned false for other reason
14140 if (mDataScaleType == QCPAxis::stLinear)
14141 {
14142 newRange.lower = center-mDataRange.size()/2.0;
14143 newRange.upper = center+mDataRange.size()/2.0;
14112 if (mapRange.upper >= 0 && mapRange.lower < 0)
14113 mapRange.upper = mapRange.lower*1e-3;
14114 else if (mapRange.upper >= 0 && mapRange.lower >= 0)
14115 currentFoundRange = false;
14116 }
14117 if (currentFoundRange)
14118 {
14119 if (!haveRange)
14120 newRange = mapRange;
14121 else
14122 newRange.expand(mapRange);
14123 haveRange = true;
14124 }
14125 }
14126 }
14127 if (haveRange)
14128 {
14129 if (!QCPRange::validRange(newRange)) // likely due to range being zero (plottable has only constant data in this dimension), shift current range to at least center the data
14130 {
14131 double center = (newRange.lower+newRange.upper)*0.5; // upper and lower should be equal anyway, but just to make sure, incase validRange returned false for other reason
14132 if (mDataScaleType == QCPAxis::stLinear)
14133 {
14134 newRange.lower = center-mDataRange.size()/2.0;
14135 newRange.upper = center+mDataRange.size()/2.0;
14144 14136 } else // mScaleType == stLogarithmic
14145 14137 {
14146 newRange.lower = center/qSqrt(mDataRange.upper/mDataRange.lower);
14147 newRange.upper = center*qSqrt(mDataRange.upper/mDataRange.lower);
14148 }
14149 }
14150 setDataRange(newRange);
14138 newRange.lower = center/qSqrt(mDataRange.upper/mDataRange.lower);
14139 newRange.upper = center*qSqrt(mDataRange.upper/mDataRange.lower);
14140 }
14141 }
14142 setDataRange(newRange);
14151 14143 }
14152 14144 }
14153 14145
14154 14146 /* inherits documentation from base class */
14155 14147 void QCPColorScale::update(UpdatePhase phase)
14156 14148 {
14157 QCPLayoutElement::update(phase);
14158 if (!mAxisRect)
14159 {
14160 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14161 return;
14162 }
14163
14164 mAxisRect.data()->update(phase);
14165
14166 switch (phase)
14149 QCPLayoutElement::update(phase);
14150 if (!mAxisRect)
14151 {
14152 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14153 return;
14154 }
14155
14156 mAxisRect.data()->update(phase);
14157
14158 switch (phase)
14167 14159 {
14168 14160 case upMargins:
14169 {
14161 {
14170 14162 if (mType == QCPAxis::atBottom || mType == QCPAxis::atTop)
14171 {
14163 {
14172 14164 setMaximumSize(QWIDGETSIZE_MAX, mBarWidth+mAxisRect.data()->margins().top()+mAxisRect.data()->margins().bottom()+margins().top()+margins().bottom());
14173 14165 setMinimumSize(0, mBarWidth+mAxisRect.data()->margins().top()+mAxisRect.data()->margins().bottom()+margins().top()+margins().bottom());
14174 } else
14175 {
14166 } else
14167 {
14176 14168 setMaximumSize(mBarWidth+mAxisRect.data()->margins().left()+mAxisRect.data()->margins().right()+margins().left()+margins().right(), QWIDGETSIZE_MAX);
14177 14169 setMinimumSize(mBarWidth+mAxisRect.data()->margins().left()+mAxisRect.data()->margins().right()+margins().left()+margins().right(), 0);
14178 }
14179 break;
14180 }
14170 }
14171 break;
14172 }
14181 14173 case upLayout:
14182 {
14174 {
14183 14175 mAxisRect.data()->setOuterRect(rect());
14184 14176 break;
14185 }
14177 }
14186 14178 default: break;
14187 14179 }
14188 14180 }
@@ -14190,51 +14182,51 void QCPColorScale::update(UpdatePhase p
14190 14182 /* inherits documentation from base class */
14191 14183 void QCPColorScale::applyDefaultAntialiasingHint(QCPPainter *painter) const
14192 14184 {
14193 painter->setAntialiasing(false);
14185 painter->setAntialiasing(false);
14194 14186 }
14195 14187
14196 14188 /* inherits documentation from base class */
14197 14189 void QCPColorScale::mousePressEvent(QMouseEvent *event)
14198 14190 {
14199 if (!mAxisRect)
14200 {
14201 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14202 return;
14203 }
14204 mAxisRect.data()->mousePressEvent(event);
14191 if (!mAxisRect)
14192 {
14193 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14194 return;
14195 }
14196 mAxisRect.data()->mousePressEvent(event);
14205 14197 }
14206 14198
14207 14199 /* inherits documentation from base class */
14208 14200 void QCPColorScale::mouseMoveEvent(QMouseEvent *event)
14209 14201 {
14210 if (!mAxisRect)
14211 {
14212 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14213 return;
14214 }
14215 mAxisRect.data()->mouseMoveEvent(event);
14202 if (!mAxisRect)
14203 {
14204 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14205 return;
14206 }
14207 mAxisRect.data()->mouseMoveEvent(event);
14216 14208 }
14217 14209
14218 14210 /* inherits documentation from base class */
14219 14211 void QCPColorScale::mouseReleaseEvent(QMouseEvent *event)
14220 14212 {
14221 if (!mAxisRect)
14222 {
14223 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14224 return;
14225 }
14226 mAxisRect.data()->mouseReleaseEvent(event);
14213 if (!mAxisRect)
14214 {
14215 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14216 return;
14217 }
14218 mAxisRect.data()->mouseReleaseEvent(event);
14227 14219 }
14228 14220
14229 14221 /* inherits documentation from base class */
14230 14222 void QCPColorScale::wheelEvent(QWheelEvent *event)
14231 14223 {
14232 if (!mAxisRect)
14233 {
14234 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14235 return;
14236 }
14237 mAxisRect.data()->wheelEvent(event);
14224 if (!mAxisRect)
14225 {
14226 qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14227 return;
14228 }
14229 mAxisRect.data()->wheelEvent(event);
14238 14230 }
14239 14231
14240 14232 ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -14256,35 +14248,35 void QCPColorScale::wheelEvent(QWheelEve
14256 14248 Creates a new instance, as a child of \a parentColorScale.
14257 14249 */
14258 14250 QCPColorScaleAxisRectPrivate::QCPColorScaleAxisRectPrivate(QCPColorScale *parentColorScale) :
14259 QCPAxisRect(parentColorScale->parentPlot(), true),
14260 mParentColorScale(parentColorScale),
14261 mGradientImageInvalidated(true)
14262 {
14263 setParentLayerable(parentColorScale);
14264 setMinimumMargins(QMargins(0, 0, 0, 0));
14265 foreach (QCPAxis::AxisType type, QList<QCPAxis::AxisType>() << QCPAxis::atBottom << QCPAxis::atTop << QCPAxis::atLeft << QCPAxis::atRight)
14266 {
14267 axis(type)->setVisible(true);
14268 axis(type)->grid()->setVisible(false);
14269 axis(type)->setPadding(0);
14270 connect(axis(type), SIGNAL(selectionChanged(QCPAxis::SelectableParts)), this, SLOT(axisSelectionChanged(QCPAxis::SelectableParts)));
14271 connect(axis(type), SIGNAL(selectableChanged(QCPAxis::SelectableParts)), this, SLOT(axisSelectableChanged(QCPAxis::SelectableParts)));
14272 }
14273
14274 connect(axis(QCPAxis::atLeft), SIGNAL(rangeChanged(QCPRange)), axis(QCPAxis::atRight), SLOT(setRange(QCPRange)));
14275 connect(axis(QCPAxis::atRight), SIGNAL(rangeChanged(QCPRange)), axis(QCPAxis::atLeft), SLOT(setRange(QCPRange)));
14276 connect(axis(QCPAxis::atBottom), SIGNAL(rangeChanged(QCPRange)), axis(QCPAxis::atTop), SLOT(setRange(QCPRange)));
14277 connect(axis(QCPAxis::atTop), SIGNAL(rangeChanged(QCPRange)), axis(QCPAxis::atBottom), SLOT(setRange(QCPRange)));
14278 connect(axis(QCPAxis::atLeft), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), axis(QCPAxis::atRight), SLOT(setScaleType(QCPAxis::ScaleType)));
14279 connect(axis(QCPAxis::atRight), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), axis(QCPAxis::atLeft), SLOT(setScaleType(QCPAxis::ScaleType)));
14280 connect(axis(QCPAxis::atBottom), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), axis(QCPAxis::atTop), SLOT(setScaleType(QCPAxis::ScaleType)));
14281 connect(axis(QCPAxis::atTop), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), axis(QCPAxis::atBottom), SLOT(setScaleType(QCPAxis::ScaleType)));
14282
14283 // make layer transfers of color scale transfer to axis rect and axes
14284 // the axes must be set after axis rect, such that they appear above color gradient drawn by axis rect:
14285 connect(parentColorScale, SIGNAL(layerChanged(QCPLayer*)), this, SLOT(setLayer(QCPLayer*)));
14286 foreach (QCPAxis::AxisType type, QList<QCPAxis::AxisType>() << QCPAxis::atBottom << QCPAxis::atTop << QCPAxis::atLeft << QCPAxis::atRight)
14287 connect(parentColorScale, SIGNAL(layerChanged(QCPLayer*)), axis(type), SLOT(setLayer(QCPLayer*)));
14251 QCPAxisRect(parentColorScale->parentPlot(), true),
14252 mParentColorScale(parentColorScale),
14253 mGradientImageInvalidated(true)
14254 {
14255 setParentLayerable(parentColorScale);
14256 setMinimumMargins(QMargins(0, 0, 0, 0));
14257 foreach (QCPAxis::AxisType type, QList<QCPAxis::AxisType>() << QCPAxis::atBottom << QCPAxis::atTop << QCPAxis::atLeft << QCPAxis::atRight)
14258 {
14259 axis(type)->setVisible(true);
14260 axis(type)->grid()->setVisible(false);
14261 axis(type)->setPadding(0);
14262 connect(axis(type), SIGNAL(selectionChanged(QCPAxis::SelectableParts)), this, SLOT(axisSelectionChanged(QCPAxis::SelectableParts)));
14263 connect(axis(type), SIGNAL(selectableChanged(QCPAxis::SelectableParts)), this, SLOT(axisSelectableChanged(QCPAxis::SelectableParts)));
14264 }
14265
14266 connect(axis(QCPAxis::atLeft), SIGNAL(rangeChanged(QCPRange)), axis(QCPAxis::atRight), SLOT(setRange(QCPRange)));
14267 connect(axis(QCPAxis::atRight), SIGNAL(rangeChanged(QCPRange)), axis(QCPAxis::atLeft), SLOT(setRange(QCPRange)));
14268 connect(axis(QCPAxis::atBottom), SIGNAL(rangeChanged(QCPRange)), axis(QCPAxis::atTop), SLOT(setRange(QCPRange)));
14269 connect(axis(QCPAxis::atTop), SIGNAL(rangeChanged(QCPRange)), axis(QCPAxis::atBottom), SLOT(setRange(QCPRange)));
14270 connect(axis(QCPAxis::atLeft), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), axis(QCPAxis::atRight), SLOT(setScaleType(QCPAxis::ScaleType)));
14271 connect(axis(QCPAxis::atRight), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), axis(QCPAxis::atLeft), SLOT(setScaleType(QCPAxis::ScaleType)));
14272 connect(axis(QCPAxis::atBottom), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), axis(QCPAxis::atTop), SLOT(setScaleType(QCPAxis::ScaleType)));
14273 connect(axis(QCPAxis::atTop), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), axis(QCPAxis::atBottom), SLOT(setScaleType(QCPAxis::ScaleType)));
14274
14275 // make layer transfers of color scale transfer to axis rect and axes
14276 // the axes must be set after axis rect, such that they appear above color gradient drawn by axis rect:
14277 connect(parentColorScale, SIGNAL(layerChanged(QCPLayer*)), this, SLOT(setLayer(QCPLayer*)));
14278 foreach (QCPAxis::AxisType type, QList<QCPAxis::AxisType>() << QCPAxis::atBottom << QCPAxis::atTop << QCPAxis::atLeft << QCPAxis::atRight)
14279 connect(parentColorScale, SIGNAL(layerChanged(QCPLayer*)), axis(type), SLOT(setLayer(QCPLayer*)));
14288 14280 }
14289 14281
14290 14282 /*! \internal
@@ -14293,19 +14285,19 QCPColorScaleAxisRectPrivate::QCPColorSc
14293 14285 */
14294 14286 void QCPColorScaleAxisRectPrivate::draw(QCPPainter *painter)
14295 14287 {
14296 if (mGradientImageInvalidated)
14297 updateGradientImage();
14298
14299 bool mirrorHorz = false;
14300 bool mirrorVert = false;
14301 if (mParentColorScale->mColorAxis)
14302 {
14303 mirrorHorz = mParentColorScale->mColorAxis.data()->rangeReversed() && (mParentColorScale->type() == QCPAxis::atBottom || mParentColorScale->type() == QCPAxis::atTop);
14304 mirrorVert = mParentColorScale->mColorAxis.data()->rangeReversed() && (mParentColorScale->type() == QCPAxis::atLeft || mParentColorScale->type() == QCPAxis::atRight);
14305 }
14306
14307 painter->drawImage(rect(), mGradientImage.mirrored(mirrorHorz, mirrorVert));
14308 QCPAxisRect::draw(painter);
14288 if (mGradientImageInvalidated)
14289 updateGradientImage();
14290
14291 bool mirrorHorz = false;
14292 bool mirrorVert = false;
14293 if (mParentColorScale->mColorAxis)
14294 {
14295 mirrorHorz = mParentColorScale->mColorAxis.data()->rangeReversed() && (mParentColorScale->type() == QCPAxis::atBottom || mParentColorScale->type() == QCPAxis::atTop);
14296 mirrorVert = mParentColorScale->mColorAxis.data()->rangeReversed() && (mParentColorScale->type() == QCPAxis::atLeft || mParentColorScale->type() == QCPAxis::atRight);
14297 }
14298
14299 painter->drawImage(rect(), mGradientImage.mirrored(mirrorHorz, mirrorVert));
14300 QCPAxisRect::draw(painter);
14309 14301 }
14310 14302
14311 14303 /*! \internal
@@ -14315,39 +14307,39 void QCPColorScaleAxisRectPrivate::draw(
14315 14307 */
14316 14308 void QCPColorScaleAxisRectPrivate::updateGradientImage()
14317 14309 {
14318 if (rect().isEmpty())
14319 return;
14320
14321 int n = mParentColorScale->mGradient.levelCount();
14322 int w, h;
14323 QVector<double> data(n);
14324 for (int i=0; i<n; ++i)
14325 data[i] = i;
14326 if (mParentColorScale->mType == QCPAxis::atBottom || mParentColorScale->mType == QCPAxis::atTop)
14327 {
14328 w = n;
14329 h = rect().height();
14330 mGradientImage = QImage(w, h, QImage::Format_RGB32);
14331 QVector<QRgb*> pixels;
14332 for (int y=0; y<h; ++y)
14333 pixels.append(reinterpret_cast<QRgb*>(mGradientImage.scanLine(y)));
14334 mParentColorScale->mGradient.colorize(data.constData(), QCPRange(0, n-1), pixels.first(), n);
14335 for (int y=1; y<h; ++y)
14336 memcpy(pixels.at(y), pixels.first(), n*sizeof(QRgb));
14337 } else
14338 {
14339 w = rect().width();
14340 h = n;
14341 mGradientImage = QImage(w, h, QImage::Format_RGB32);
14342 for (int y=0; y<h; ++y)
14343 {
14344 QRgb *pixels = reinterpret_cast<QRgb*>(mGradientImage.scanLine(y));
14345 const QRgb lineColor = mParentColorScale->mGradient.color(data[h-1-y], QCPRange(0, n-1));
14346 for (int x=0; x<w; ++x)
14347 pixels[x] = lineColor;
14348 }
14349 }
14350 mGradientImageInvalidated = false;
14310 if (rect().isEmpty())
14311 return;
14312
14313 int n = mParentColorScale->mGradient.levelCount();
14314 int w, h;
14315 QVector<double> data(n);
14316 for (int i=0; i<n; ++i)
14317 data[i] = i;
14318 if (mParentColorScale->mType == QCPAxis::atBottom || mParentColorScale->mType == QCPAxis::atTop)
14319 {
14320 w = n;
14321 h = rect().height();
14322 mGradientImage = QImage(w, h, QImage::Format_RGB32);
14323 QVector<QRgb*> pixels;
14324 for (int y=0; y<h; ++y)
14325 pixels.append(reinterpret_cast<QRgb*>(mGradientImage.scanLine(y)));
14326 mParentColorScale->mGradient.colorize(data.constData(), QCPRange(0, n-1), pixels.first(), n);
14327 for (int y=1; y<h; ++y)
14328 memcpy(pixels.at(y), pixels.first(), n*sizeof(QRgb));
14329 } else
14330 {
14331 w = rect().width();
14332 h = n;
14333 mGradientImage = QImage(w, h, QImage::Format_RGB32);
14334 for (int y=0; y<h; ++y)
14335 {
14336 QRgb *pixels = reinterpret_cast<QRgb*>(mGradientImage.scanLine(y));
14337 const QRgb lineColor = mParentColorScale->mGradient.color(data[h-1-y], QCPRange(0, n-1));
14338 for (int x=0; x<w; ++x)
14339 pixels[x] = lineColor;
14340 }
14341 }
14342 mGradientImageInvalidated = false;
14351 14343 }
14352 14344
14353 14345 /*! \internal
@@ -14357,19 +14349,19 void QCPColorScaleAxisRectPrivate::updat
14357 14349 */
14358 14350 void QCPColorScaleAxisRectPrivate::axisSelectionChanged(QCPAxis::SelectableParts selectedParts)
14359 14351 {
14360 // axis bases of four axes shall always (de-)selected synchronously:
14361 foreach (QCPAxis::AxisType type, QList<QCPAxis::AxisType>() << QCPAxis::atBottom << QCPAxis::atTop << QCPAxis::atLeft << QCPAxis::atRight)
14362 {
14363 if (QCPAxis *senderAxis = qobject_cast<QCPAxis*>(sender()))
14364 if (senderAxis->axisType() == type)
14365 continue;
14366
14367 if (axis(type)->selectableParts().testFlag(QCPAxis::spAxis))
14368 {
14369 if (selectedParts.testFlag(QCPAxis::spAxis))
14370 axis(type)->setSelectedParts(axis(type)->selectedParts() | QCPAxis::spAxis);
14371 else
14372 axis(type)->setSelectedParts(axis(type)->selectedParts() & ~QCPAxis::spAxis);
14352 // axis bases of four axes shall always (de-)selected synchronously:
14353 foreach (QCPAxis::AxisType type, QList<QCPAxis::AxisType>() << QCPAxis::atBottom << QCPAxis::atTop << QCPAxis::atLeft << QCPAxis::atRight)
14354 {
14355 if (QCPAxis *senderAxis = qobject_cast<QCPAxis*>(sender()))
14356 if (senderAxis->axisType() == type)
14357 continue;
14358
14359 if (axis(type)->selectableParts().testFlag(QCPAxis::spAxis))
14360 {
14361 if (selectedParts.testFlag(QCPAxis::spAxis))
14362 axis(type)->setSelectedParts(axis(type)->selectedParts() | QCPAxis::spAxis);
14363 else
14364 axis(type)->setSelectedParts(axis(type)->selectedParts() & ~QCPAxis::spAxis);
14373 14365 }
14374 14366 }
14375 14367 }
@@ -14381,19 +14373,19 void QCPColorScaleAxisRectPrivate::axisS
14381 14373 */
14382 14374 void QCPColorScaleAxisRectPrivate::axisSelectableChanged(QCPAxis::SelectableParts selectableParts)
14383 14375 {
14384 // synchronize axis base selectability:
14385 foreach (QCPAxis::AxisType type, QList<QCPAxis::AxisType>() << QCPAxis::atBottom << QCPAxis::atTop << QCPAxis::atLeft << QCPAxis::atRight)
14386 {
14387 if (QCPAxis *senderAxis = qobject_cast<QCPAxis*>(sender()))
14388 if (senderAxis->axisType() == type)
14389 continue;
14390
14391 if (axis(type)->selectableParts().testFlag(QCPAxis::spAxis))
14392 {
14393 if (selectableParts.testFlag(QCPAxis::spAxis))
14394 axis(type)->setSelectableParts(axis(type)->selectableParts() | QCPAxis::spAxis);
14395 else
14396 axis(type)->setSelectableParts(axis(type)->selectableParts() & ~QCPAxis::spAxis);
14376 // synchronize axis base selectability:
14377 foreach (QCPAxis::AxisType type, QList<QCPAxis::AxisType>() << QCPAxis::atBottom << QCPAxis::atTop << QCPAxis::atLeft << QCPAxis::atRight)
14378 {
14379 if (QCPAxis *senderAxis = qobject_cast<QCPAxis*>(sender()))
14380 if (senderAxis->axisType() == type)
14381 continue;
14382
14383 if (axis(type)->selectableParts().testFlag(QCPAxis::spAxis))
14384 {
14385 if (selectableParts.testFlag(QCPAxis::spAxis))
14386 axis(type)->setSelectableParts(axis(type)->selectableParts() | QCPAxis::spAxis);
14387 else
14388 axis(type)->setSelectableParts(axis(type)->selectableParts() & ~QCPAxis::spAxis);
14397 14389 }
14398 14390 }
14399 14391 }
@@ -14423,12 +14415,12 void QCPColorScaleAxisRectPrivate::axisS
14423 14415 Constructs a data point with key, value and all errors set to zero.
14424 14416 */
14425 14417 QCPData::QCPData() :
14426 key(0),
14427 value(0),
14428 keyErrorPlus(0),
14429 keyErrorMinus(0),
14430 valueErrorPlus(0),
14431 valueErrorMinus(0)
14418 key(0),
14419 value(0),
14420 keyErrorPlus(0),
14421 keyErrorMinus(0),
14422 valueErrorPlus(0),
14423 valueErrorMinus(0)
14432 14424 {
14433 14425 }
14434 14426
@@ -14436,12 +14428,12 QCPData::QCPData() :
14436 14428 Constructs a data point with the specified \a key and \a value. All errors are set to zero.
14437 14429 */
14438 14430 QCPData::QCPData(double key, double value) :
14439 key(key),
14440 value(value),
14441 keyErrorPlus(0),
14442 keyErrorMinus(0),
14443 valueErrorPlus(0),
14444 valueErrorMinus(0)
14431 key(key),
14432 value(value),
14433 keyErrorPlus(0),
14434 keyErrorMinus(0),
14435 valueErrorPlus(0),
14436 valueErrorMinus(0)
14445 14437 {
14446 14438 }
14447 14439
@@ -14507,29 +14499,27 QCPData::QCPData(double key, double valu
14507 14499 To directly create a graph inside a plot, you can also use the simpler QCustomPlot::addGraph function.
14508 14500 */
14509 14501 QCPGraph::QCPGraph(QCPAxis *keyAxis, QCPAxis *valueAxis) :
14510 QCPAbstractPlottable(keyAxis, valueAxis)
14511 {
14512 mData = new QCPDataMap;
14513 mDataVector = new QVector<QCPData>();
14514 setPen(QPen(Qt::blue, 0));
14515 setErrorPen(QPen(Qt::black));
14516 setBrush(Qt::NoBrush);
14517 setSelectedPen(QPen(QColor(80, 80, 255), 2.5));
14518 setSelectedBrush(Qt::NoBrush);
14519
14520 setLineStyle(lsLine);
14521 setErrorType(etNone);
14522 setErrorBarSize(6);
14523 setErrorBarSkipSymbol(true);
14524 setChannelFillGraph(0);
14525 setAdaptiveSampling(true);
14526 setUseFastVectors(false);
14502 QCPAbstractPlottable(keyAxis, valueAxis)
14503 {
14504 mData = new QCPDataMap;
14505
14506 setPen(QPen(Qt::blue, 0));
14507 setErrorPen(QPen(Qt::black));
14508 setBrush(Qt::NoBrush);
14509 setSelectedPen(QPen(QColor(80, 80, 255), 2.5));
14510 setSelectedBrush(Qt::NoBrush);
14511
14512 setLineStyle(lsLine);
14513 setErrorType(etNone);
14514 setErrorBarSize(6);
14515 setErrorBarSkipSymbol(true);
14516 setChannelFillGraph(0);
14517 setAdaptiveSampling(true);
14527 14518 }
14528 14519
14529 14520 QCPGraph::~QCPGraph()
14530 14521 {
14531 delete mData;
14532 delete mDataVector;
14522 delete mData;
14533 14523 }
14534 14524
14535 14525 /*!
@@ -14544,18 +14534,18 QCPGraph::~QCPGraph()
14544 14534 */
14545 14535 void QCPGraph::setData(QCPDataMap *data, bool copy)
14546 14536 {
14547 if (mData == data)
14548 {
14549 qDebug() << Q_FUNC_INFO << "The data pointer is already in (and owned by) this plottable" << reinterpret_cast<quintptr>(data);
14550 return;
14551 }
14552 if (copy)
14553 {
14554 *mData = *data;
14555 } else
14556 {
14557 delete mData;
14558 mData = data;
14537 if (mData == data)
14538 {
14539 qDebug() << Q_FUNC_INFO << "The data pointer is already in (and owned by) this plottable" << reinterpret_cast<quintptr>(data);
14540 return;
14541 }
14542 if (copy)
14543 {
14544 *mData = *data;
14545 } else
14546 {
14547 delete mData;
14548 mData = data;
14559 14549 }
14560 14550 }
14561 14551
@@ -14567,24 +14557,15 void QCPGraph::setData(QCPDataMap *data,
14567 14557 */
14568 14558 void QCPGraph::setData(const QVector<double> &key, const QVector<double> &value)
14569 14559 {
14570 mData->clear();
14571 int n = key.size();
14572 n = qMin(n, value.size());
14573 QCPData newData;
14574 for (int i=0; i<n; ++i)
14575 {
14576 newData.key = key[i];
14577 newData.value = value[i];
14578 mData->insertMulti(newData.key, newData);
14579 }
14580 }
14581
14582 void QCPGraph::setData(QVector<QCPData> *data)
14583 {
14584 if(data!=mDataVector)
14585 {
14586 delete this->mDataVector;
14587 this->mDataVector = data;
14560 mData->clear();
14561 int n = key.size();
14562 n = qMin(n, value.size());
14563 QCPData newData;
14564 for (int i=0; i<n; ++i)
14565 {
14566 newData.key = key[i];
14567 newData.value = value[i];
14568 mData->insertMulti(newData.key, newData);
14588 14569 }
14589 14570 }
14590 14571
@@ -14599,18 +14580,18 void QCPGraph::setData(QVector<QCPData>
14599 14580 */
14600 14581 void QCPGraph::setDataValueError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &valueError)
14601 14582 {
14602 mData->clear();
14603 int n = key.size();
14604 n = qMin(n, value.size());
14605 n = qMin(n, valueError.size());
14606 QCPData newData;
14607 for (int i=0; i<n; ++i)
14608 {
14609 newData.key = key[i];
14610 newData.value = value[i];
14611 newData.valueErrorMinus = valueError[i];
14612 newData.valueErrorPlus = valueError[i];
14613 mData->insertMulti(key[i], newData);
14583 mData->clear();
14584 int n = key.size();
14585 n = qMin(n, value.size());
14586 n = qMin(n, valueError.size());
14587 QCPData newData;
14588 for (int i=0; i<n; ++i)
14589 {
14590 newData.key = key[i];
14591 newData.value = value[i];
14592 newData.valueErrorMinus = valueError[i];
14593 newData.valueErrorPlus = valueError[i];
14594 mData->insertMulti(key[i], newData);
14614 14595 }
14615 14596 }
14616 14597
@@ -14625,19 +14606,19 void QCPGraph::setDataValueError(const Q
14625 14606 */
14626 14607 void QCPGraph::setDataValueError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &valueErrorMinus, const QVector<double> &valueErrorPlus)
14627 14608 {
14628 mData->clear();
14629 int n = key.size();
14630 n = qMin(n, value.size());
14631 n = qMin(n, valueErrorMinus.size());
14632 n = qMin(n, valueErrorPlus.size());
14633 QCPData newData;
14634 for (int i=0; i<n; ++i)
14635 {
14636 newData.key = key[i];
14637 newData.value = value[i];
14638 newData.valueErrorMinus = valueErrorMinus[i];
14639 newData.valueErrorPlus = valueErrorPlus[i];
14640 mData->insertMulti(key[i], newData);
14609 mData->clear();
14610 int n = key.size();
14611 n = qMin(n, value.size());
14612 n = qMin(n, valueErrorMinus.size());
14613 n = qMin(n, valueErrorPlus.size());
14614 QCPData newData;
14615 for (int i=0; i<n; ++i)
14616 {
14617 newData.key = key[i];
14618 newData.value = value[i];
14619 newData.valueErrorMinus = valueErrorMinus[i];
14620 newData.valueErrorPlus = valueErrorPlus[i];
14621 mData->insertMulti(key[i], newData);
14641 14622 }
14642 14623 }
14643 14624
@@ -14652,18 +14633,18 void QCPGraph::setDataValueError(const Q
14652 14633 */
14653 14634 void QCPGraph::setDataKeyError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyError)
14654 14635 {
14655 mData->clear();
14656 int n = key.size();
14657 n = qMin(n, value.size());
14658 n = qMin(n, keyError.size());
14659 QCPData newData;
14660 for (int i=0; i<n; ++i)
14661 {
14662 newData.key = key[i];
14663 newData.value = value[i];
14664 newData.keyErrorMinus = keyError[i];
14665 newData.keyErrorPlus = keyError[i];
14666 mData->insertMulti(key[i], newData);
14636 mData->clear();
14637 int n = key.size();
14638 n = qMin(n, value.size());
14639 n = qMin(n, keyError.size());
14640 QCPData newData;
14641 for (int i=0; i<n; ++i)
14642 {
14643 newData.key = key[i];
14644 newData.value = value[i];
14645 newData.keyErrorMinus = keyError[i];
14646 newData.keyErrorPlus = keyError[i];
14647 mData->insertMulti(key[i], newData);
14667 14648 }
14668 14649 }
14669 14650
@@ -14678,19 +14659,19 void QCPGraph::setDataKeyError(const QVe
14678 14659 */
14679 14660 void QCPGraph::setDataKeyError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyErrorMinus, const QVector<double> &keyErrorPlus)
14680 14661 {
14681 mData->clear();
14682 int n = key.size();
14683 n = qMin(n, value.size());
14684 n = qMin(n, keyErrorMinus.size());
14685 n = qMin(n, keyErrorPlus.size());
14686 QCPData newData;
14687 for (int i=0; i<n; ++i)
14688 {
14689 newData.key = key[i];
14690 newData.value = value[i];
14691 newData.keyErrorMinus = keyErrorMinus[i];
14692 newData.keyErrorPlus = keyErrorPlus[i];
14693 mData->insertMulti(key[i], newData);
14662 mData->clear();
14663 int n = key.size();
14664 n = qMin(n, value.size());
14665 n = qMin(n, keyErrorMinus.size());
14666 n = qMin(n, keyErrorPlus.size());
14667 QCPData newData;
14668 for (int i=0; i<n; ++i)
14669 {
14670 newData.key = key[i];
14671 newData.value = value[i];
14672 newData.keyErrorMinus = keyErrorMinus[i];
14673 newData.keyErrorPlus = keyErrorPlus[i];
14674 mData->insertMulti(key[i], newData);
14694 14675 }
14695 14676 }
14696 14677
@@ -14705,21 +14686,21 void QCPGraph::setDataKeyError(const QVe
14705 14686 */
14706 14687 void QCPGraph::setDataBothError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyError, const QVector<double> &valueError)
14707 14688 {
14708 mData->clear();
14709 int n = key.size();
14710 n = qMin(n, value.size());
14711 n = qMin(n, valueError.size());
14712 n = qMin(n, keyError.size());
14713 QCPData newData;
14714 for (int i=0; i<n; ++i)
14715 {
14716 newData.key = key[i];
14717 newData.value = value[i];
14718 newData.keyErrorMinus = keyError[i];
14719 newData.keyErrorPlus = keyError[i];
14720 newData.valueErrorMinus = valueError[i];
14721 newData.valueErrorPlus = valueError[i];
14722 mData->insertMulti(key[i], newData);
14689 mData->clear();
14690 int n = key.size();
14691 n = qMin(n, value.size());
14692 n = qMin(n, valueError.size());
14693 n = qMin(n, keyError.size());
14694 QCPData newData;
14695 for (int i=0; i<n; ++i)
14696 {
14697 newData.key = key[i];
14698 newData.value = value[i];
14699 newData.keyErrorMinus = keyError[i];
14700 newData.keyErrorPlus = keyError[i];
14701 newData.valueErrorMinus = valueError[i];
14702 newData.valueErrorPlus = valueError[i];
14703 mData->insertMulti(key[i], newData);
14723 14704 }
14724 14705 }
14725 14706
@@ -14734,23 +14715,23 void QCPGraph::setDataBothError(const QV
14734 14715 */
14735 14716 void QCPGraph::setDataBothError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyErrorMinus, const QVector<double> &keyErrorPlus, const QVector<double> &valueErrorMinus, const QVector<double> &valueErrorPlus)
14736 14717 {
14737 mData->clear();
14738 int n = key.size();
14739 n = qMin(n, value.size());
14740 n = qMin(n, valueErrorMinus.size());
14741 n = qMin(n, valueErrorPlus.size());
14742 n = qMin(n, keyErrorMinus.size());
14743 n = qMin(n, keyErrorPlus.size());
14744 QCPData newData;
14745 for (int i=0; i<n; ++i)
14746 {
14747 newData.key = key[i];
14748 newData.value = value[i];
14749 newData.keyErrorMinus = keyErrorMinus[i];
14750 newData.keyErrorPlus = keyErrorPlus[i];
14751 newData.valueErrorMinus = valueErrorMinus[i];
14752 newData.valueErrorPlus = valueErrorPlus[i];
14753 mData->insertMulti(key[i], newData);
14718 mData->clear();
14719 int n = key.size();
14720 n = qMin(n, value.size());
14721 n = qMin(n, valueErrorMinus.size());
14722 n = qMin(n, valueErrorPlus.size());
14723 n = qMin(n, keyErrorMinus.size());
14724 n = qMin(n, keyErrorPlus.size());
14725 QCPData newData;
14726 for (int i=0; i<n; ++i)
14727 {
14728 newData.key = key[i];
14729 newData.value = value[i];
14730 newData.keyErrorMinus = keyErrorMinus[i];
14731 newData.keyErrorPlus = keyErrorPlus[i];
14732 newData.valueErrorMinus = valueErrorMinus[i];
14733 newData.valueErrorPlus = valueErrorPlus[i];
14734 mData->insertMulti(key[i], newData);
14754 14735 }
14755 14736 }
14756 14737
@@ -14763,7 +14744,7 void QCPGraph::setDataBothError(const QV
14763 14744 */
14764 14745 void QCPGraph::setLineStyle(LineStyle ls)
14765 14746 {
14766 mLineStyle = ls;
14747 mLineStyle = ls;
14767 14748 }
14768 14749
14769 14750 /*!
@@ -14774,7 +14755,7 void QCPGraph::setLineStyle(LineStyle ls
14774 14755 */
14775 14756 void QCPGraph::setScatterStyle(const QCPScatterStyle &style)
14776 14757 {
14777 mScatterStyle = style;
14758 mScatterStyle = style;
14778 14759 }
14779 14760
14780 14761 /*!
@@ -14787,7 +14768,7 void QCPGraph::setScatterStyle(const QCP
14787 14768 */
14788 14769 void QCPGraph::setErrorType(ErrorType errorType)
14789 14770 {
14790 mErrorType = errorType;
14771 mErrorType = errorType;
14791 14772 }
14792 14773
14793 14774 /*!
@@ -14796,7 +14777,7 void QCPGraph::setErrorType(ErrorType er
14796 14777 */
14797 14778 void QCPGraph::setErrorPen(const QPen &pen)
14798 14779 {
14799 mErrorPen = pen;
14780 mErrorPen = pen;
14800 14781 }
14801 14782
14802 14783 /*!
@@ -14804,7 +14785,7 void QCPGraph::setErrorPen(const QPen &p
14804 14785 */
14805 14786 void QCPGraph::setErrorBarSize(double size)
14806 14787 {
14807 mErrorBarSize = size;
14788 mErrorBarSize = size;
14808 14789 }
14809 14790
14810 14791 /*!
@@ -14820,7 +14801,7 void QCPGraph::setErrorBarSize(double si
14820 14801 */
14821 14802 void QCPGraph::setErrorBarSkipSymbol(bool enabled)
14822 14803 {
14823 mErrorBarSkipSymbol = enabled;
14804 mErrorBarSkipSymbol = enabled;
14824 14805 }
14825 14806
14826 14807 /*!
@@ -14834,22 +14815,22 void QCPGraph::setErrorBarSkipSymbol(boo
14834 14815 */
14835 14816 void QCPGraph::setChannelFillGraph(QCPGraph *targetGraph)
14836 14817 {
14837 // prevent setting channel target to this graph itself:
14838 if (targetGraph == this)
14839 {
14840 qDebug() << Q_FUNC_INFO << "targetGraph is this graph itself";
14841 mChannelFillGraph = 0;
14842 return;
14843 }
14844 // prevent setting channel target to a graph not in the plot:
14845 if (targetGraph && targetGraph->mParentPlot != mParentPlot)
14846 {
14847 qDebug() << Q_FUNC_INFO << "targetGraph not in same plot";
14848 mChannelFillGraph = 0;
14849 return;
14850 }
14851
14852 mChannelFillGraph = targetGraph;
14818 // prevent setting channel target to this graph itself:
14819 if (targetGraph == this)
14820 {
14821 qDebug() << Q_FUNC_INFO << "targetGraph is this graph itself";
14822 mChannelFillGraph = 0;
14823 return;
14824 }
14825 // prevent setting channel target to a graph not in the plot:
14826 if (targetGraph && targetGraph->mParentPlot != mParentPlot)
14827 {
14828 qDebug() << Q_FUNC_INFO << "targetGraph not in same plot";
14829 mChannelFillGraph = 0;
14830 return;
14831 }
14832
14833 mChannelFillGraph = targetGraph;
14853 14834 }
14854 14835
14855 14836 /*!
@@ -14885,12 +14866,7 void QCPGraph::setChannelFillGraph(QCPGr
14885 14866 */
14886 14867 void QCPGraph::setAdaptiveSampling(bool enabled)
14887 14868 {
14888 mAdaptiveSampling = enabled;
14889 }
14890
14891 void QCPGraph::setUseFastVectors(bool useFastVectors)
14892 {
14893 mUseFastVectors=useFastVectors;
14869 mAdaptiveSampling = enabled;
14894 14870 }
14895 14871
14896 14872 /*!
@@ -14903,7 +14879,7 void QCPGraph::setUseFastVectors(bool us
14903 14879 */
14904 14880 void QCPGraph::addData(const QCPDataMap &dataMap)
14905 14881 {
14906 mData->unite(dataMap);
14882 mData->unite(dataMap);
14907 14883 }
14908 14884
14909 14885 /*! \overload
@@ -14916,7 +14892,7 void QCPGraph::addData(const QCPDataMap
14916 14892 */
14917 14893 void QCPGraph::addData(const QCPData &data)
14918 14894 {
14919 mData->insertMulti(data.key, data);
14895 mData->insertMulti(data.key, data);
14920 14896 }
14921 14897
14922 14898 /*! \overload
@@ -14929,10 +14905,10 void QCPGraph::addData(const QCPData &da
14929 14905 */
14930 14906 void QCPGraph::addData(double key, double value)
14931 14907 {
14932 QCPData newData;
14933 newData.key = key;
14934 newData.value = value;
14935 mData->insertMulti(newData.key, newData);
14908 QCPData newData;
14909 newData.key = key;
14910 newData.value = value;
14911 mData->insertMulti(newData.key, newData);
14936 14912 }
14937 14913
14938 14914 /*! \overload
@@ -14945,13 +14921,13 void QCPGraph::addData(double key, doubl
14945 14921 */
14946 14922 void QCPGraph::addData(const QVector<double> &keys, const QVector<double> &values)
14947 14923 {
14948 int n = qMin(keys.size(), values.size());
14949 QCPData newData;
14950 for (int i=0; i<n; ++i)
14951 {
14952 newData.key = keys[i];
14953 newData.value = values[i];
14954 mData->insertMulti(newData.key, newData);
14924 int n = qMin(keys.size(), values.size());
14925 QCPData newData;
14926 for (int i=0; i<n; ++i)
14927 {
14928 newData.key = keys[i];
14929 newData.value = values[i];
14930 mData->insertMulti(newData.key, newData);
14955 14931 }
14956 14932 }
14957 14933
@@ -14961,9 +14937,9 void QCPGraph::addData(const QVector<dou
14961 14937 */
14962 14938 void QCPGraph::removeDataBefore(double key)
14963 14939 {
14964 QCPDataMap::iterator it = mData->begin();
14965 while (it != mData->end() && it.key() < key)
14966 it = mData->erase(it);
14940 QCPDataMap::iterator it = mData->begin();
14941 while (it != mData->end() && it.key() < key)
14942 it = mData->erase(it);
14967 14943 }
14968 14944
14969 14945 /*!
@@ -14972,10 +14948,10 void QCPGraph::removeDataBefore(double k
14972 14948 */
14973 14949 void QCPGraph::removeDataAfter(double key)
14974 14950 {
14975 if (mData->isEmpty()) return;
14976 QCPDataMap::iterator it = mData->upperBound(key);
14977 while (it != mData->end())
14978 it = mData->erase(it);
14951 if (mData->isEmpty()) return;
14952 QCPDataMap::iterator it = mData->upperBound(key);
14953 while (it != mData->end())
14954 it = mData->erase(it);
14979 14955 }
14980 14956
14981 14957 /*!
@@ -14987,11 +14963,11 void QCPGraph::removeDataAfter(double ke
14987 14963 */
14988 14964 void QCPGraph::removeData(double fromKey, double toKey)
14989 14965 {
14990 if (fromKey >= toKey || mData->isEmpty()) return;
14991 QCPDataMap::iterator it = mData->upperBound(fromKey);
14992 QCPDataMap::iterator itEnd = mData->upperBound(toKey);
14993 while (it != itEnd)
14994 it = mData->erase(it);
14966 if (fromKey >= toKey || mData->isEmpty()) return;
14967 QCPDataMap::iterator it = mData->upperBound(fromKey);
14968 QCPDataMap::iterator itEnd = mData->upperBound(toKey);
14969 while (it != itEnd)
14970 it = mData->erase(it);
14995 14971 }
14996 14972
14997 14973 /*! \overload
@@ -15004,7 +14980,7 void QCPGraph::removeData(double fromKey
15004 14980 */
15005 14981 void QCPGraph::removeData(double key)
15006 14982 {
15007 mData->remove(key);
14983 mData->remove(key);
15008 14984 }
15009 14985
15010 14986 /*!
@@ -15013,21 +14989,21 void QCPGraph::removeData(double key)
15013 14989 */
15014 14990 void QCPGraph::clearData()
15015 14991 {
15016 mData->clear();
14992 mData->clear();
15017 14993 }
15018 14994
15019 14995 /* inherits documentation from base class */
15020 14996 double QCPGraph::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
15021 14997 {
15022 Q_UNUSED(details)
15023 if ((onlySelectable && !mSelectable) || mData->isEmpty())
15024 return -1;
15025 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
15026
15027 if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()))
15028 return pointDistance(pos);
15029 else
15030 return -1;
14998 Q_UNUSED(details)
14999 if ((onlySelectable && !mSelectable) || mData->isEmpty())
15000 return -1;
15001 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
15002
15003 if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()))
15004 return pointDistance(pos);
15005 else
15006 return -1;
15031 15007 }
15032 15008
15033 15009 /*! \overload
@@ -15039,8 +15015,8 double QCPGraph::selectTest(const QPoint
15039 15015 */
15040 15016 void QCPGraph::rescaleAxes(bool onlyEnlarge, bool includeErrorBars) const
15041 15017 {
15042 rescaleKeyAxis(onlyEnlarge, includeErrorBars);
15043 rescaleValueAxis(onlyEnlarge, includeErrorBars);
15018 rescaleKeyAxis(onlyEnlarge, includeErrorBars);
15019 rescaleValueAxis(onlyEnlarge, includeErrorBars);
15044 15020 }
15045 15021
15046 15022 /*! \overload
@@ -15052,30 +15028,30 void QCPGraph::rescaleAxes(bool onlyEnla
15052 15028 */
15053 15029 void QCPGraph::rescaleKeyAxis(bool onlyEnlarge, bool includeErrorBars) const
15054 15030 {
15055 // this code is a copy of QCPAbstractPlottable::rescaleKeyAxis with the only change
15056 // that getKeyRange is passed the includeErrorBars value.
15057 if (mData->isEmpty()) return;
15058
15059 QCPAxis *keyAxis = mKeyAxis.data();
15060 if (!keyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
15061
15062 SignDomain signDomain = sdBoth;
15063 if (keyAxis->scaleType() == QCPAxis::stLogarithmic)
15064 signDomain = (keyAxis->range().upper < 0 ? sdNegative : sdPositive);
15065
15066 bool foundRange;
15067 QCPRange newRange = getKeyRange(foundRange, signDomain, includeErrorBars);
15068
15069 if (foundRange)
15070 {
15071 if (onlyEnlarge)
15072 {
15073 if (keyAxis->range().lower < newRange.lower)
15074 newRange.lower = keyAxis->range().lower;
15075 if (keyAxis->range().upper > newRange.upper)
15076 newRange.upper = keyAxis->range().upper;
15077 }
15078 keyAxis->setRange(newRange);
15031 // this code is a copy of QCPAbstractPlottable::rescaleKeyAxis with the only change
15032 // that getKeyRange is passed the includeErrorBars value.
15033 if (mData->isEmpty()) return;
15034
15035 QCPAxis *keyAxis = mKeyAxis.data();
15036 if (!keyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
15037
15038 SignDomain signDomain = sdBoth;
15039 if (keyAxis->scaleType() == QCPAxis::stLogarithmic)
15040 signDomain = (keyAxis->range().upper < 0 ? sdNegative : sdPositive);
15041
15042 bool foundRange;
15043 QCPRange newRange = getKeyRange(foundRange, signDomain, includeErrorBars);
15044
15045 if (foundRange)
15046 {
15047 if (onlyEnlarge)
15048 {
15049 if (keyAxis->range().lower < newRange.lower)
15050 newRange.lower = keyAxis->range().lower;
15051 if (keyAxis->range().upper > newRange.upper)
15052 newRange.upper = keyAxis->range().upper;
15053 }
15054 keyAxis->setRange(newRange);
15079 15055 }
15080 15056 }
15081 15057
@@ -15088,111 +15064,113 void QCPGraph::rescaleKeyAxis(bool onlyE
15088 15064 */
15089 15065 void QCPGraph::rescaleValueAxis(bool onlyEnlarge, bool includeErrorBars) const
15090 15066 {
15091 // this code is a copy of QCPAbstractPlottable::rescaleValueAxis with the only change
15092 // is that getValueRange is passed the includeErrorBars value.
15093 if (mData->isEmpty()) return;
15094
15095 QCPAxis *valueAxis = mValueAxis.data();
15096 if (!valueAxis) { qDebug() << Q_FUNC_INFO << "invalid value axis"; return; }
15097
15098 SignDomain signDomain = sdBoth;
15099 if (valueAxis->scaleType() == QCPAxis::stLogarithmic)
15100 signDomain = (valueAxis->range().upper < 0 ? sdNegative : sdPositive);
15101
15102 bool foundRange;
15103 QCPRange newRange = getValueRange(foundRange, signDomain, includeErrorBars);
15104
15105 if (foundRange)
15106 {
15107 if (onlyEnlarge)
15108 {
15109 if (valueAxis->range().lower < newRange.lower)
15110 newRange.lower = valueAxis->range().lower;
15111 if (valueAxis->range().upper > newRange.upper)
15112 newRange.upper = valueAxis->range().upper;
15113 }
15114 valueAxis->setRange(newRange);
15067 // this code is a copy of QCPAbstractPlottable::rescaleValueAxis with the only change
15068 // is that getValueRange is passed the includeErrorBars value.
15069 if (mData->isEmpty()) return;
15070
15071 QCPAxis *valueAxis = mValueAxis.data();
15072 if (!valueAxis) { qDebug() << Q_FUNC_INFO << "invalid value axis"; return; }
15073
15074 SignDomain signDomain = sdBoth;
15075 if (valueAxis->scaleType() == QCPAxis::stLogarithmic)
15076 signDomain = (valueAxis->range().upper < 0 ? sdNegative : sdPositive);
15077
15078 bool foundRange;
15079 QCPRange newRange = getValueRange(foundRange, signDomain, includeErrorBars);
15080
15081 if (foundRange)
15082 {
15083 if (onlyEnlarge)
15084 {
15085 if (valueAxis->range().lower < newRange.lower)
15086 newRange.lower = valueAxis->range().lower;
15087 if (valueAxis->range().upper > newRange.upper)
15088 newRange.upper = valueAxis->range().upper;
15089 }
15090 valueAxis->setRange(newRange);
15115 15091 }
15116 15092 }
15117 15093
15118 15094 /* inherits documentation from base class */
15119 15095 void QCPGraph::draw(QCPPainter *painter)
15120 15096 {
15121 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15122 if (mKeyAxis.data()->range().size() <= 0 || (mData->isEmpty() && mDataVector->isEmpty())) return;
15123 if (mLineStyle == lsNone && mScatterStyle.isNone()) return;
15124
15125 // allocate line and (if necessary) point vectors:
15126 QVector<QPointF> *lineData = new QVector<QPointF>;
15127 QVector<QCPData> *scatterData = 0;
15128 if (!mScatterStyle.isNone())
15129 scatterData = new QVector<QCPData>;
15130
15131 // fill vectors with data appropriate to plot style:
15132 getPlotData(lineData, scatterData);
15133
15134 // check data validity if flag set:
15097 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15098 int test = mKeyAxis.data()->range().size();
15099 test = mData->count();
15100 if (mKeyAxis.data()->range().size() <= 0 || mData->isEmpty()) return;
15101 if (mLineStyle == lsNone && mScatterStyle.isNone()) return;
15102
15103 // allocate line and (if necessary) point vectors:
15104 QVector<QPointF> *lineData = new QVector<QPointF>;
15105 QVector<QCPData> *scatterData = 0;
15106 if (!mScatterStyle.isNone())
15107 scatterData = new QVector<QCPData>;
15108
15109 // fill vectors with data appropriate to plot style:
15110 getPlotData(lineData, scatterData);
15111
15112 // check data validity if flag set:
15135 15113 #ifdef QCUSTOMPLOT_CHECK_DATA
15136 QCPDataMap::const_iterator it;
15137 for (it = mData->constBegin(); it != mData->constEnd(); ++it)
15138 {
15139 if (QCP::isInvalidData(it.value().key, it.value().value) ||
15140 QCP::isInvalidData(it.value().keyErrorPlus, it.value().keyErrorMinus) ||
15141 QCP::isInvalidData(it.value().valueErrorPlus, it.value().valueErrorPlus))
15142 qDebug() << Q_FUNC_INFO << "Data point at" << it.key() << "invalid." << "Plottable name:" << name();
15114 QCPDataMap::const_iterator it;
15115 for (it = mData->constBegin(); it != mData->constEnd(); ++it)
15116 {
15117 if (QCP::isInvalidData(it.value().key, it.value().value) ||
15118 QCP::isInvalidData(it.value().keyErrorPlus, it.value().keyErrorMinus) ||
15119 QCP::isInvalidData(it.value().valueErrorPlus, it.value().valueErrorPlus))
15120 qDebug() << Q_FUNC_INFO << "Data point at" << it.key() << "invalid." << "Plottable name:" << name();
15143 15121 }
15144 15122 #endif
15145 15123
15146 // draw fill of graph:
15147 drawFill(painter, lineData);
15148
15149 // draw line:
15150 if (mLineStyle == lsImpulse)
15151 drawImpulsePlot(painter, lineData);
15152 else if (mLineStyle != lsNone)
15153 drawLinePlot(painter, lineData); // also step plots can be drawn as a line plot
15154
15155 // draw scatters:
15156 if (scatterData)
15157 drawScatterPlot(painter, scatterData);
15158
15159 // free allocated line and point vectors:
15160 delete lineData;
15161 if (scatterData)
15162 delete scatterData;
15124 // draw fill of graph:
15125 drawFill(painter, lineData);
15126
15127 // draw line:
15128 if (mLineStyle == lsImpulse)
15129 drawImpulsePlot(painter, lineData);
15130 else if (mLineStyle != lsNone)
15131 drawLinePlot(painter, lineData); // also step plots can be drawn as a line plot
15132
15133 // draw scatters:
15134 if (scatterData)
15135 drawScatterPlot(painter, scatterData);
15136
15137 // free allocated line and point vectors:
15138 delete lineData;
15139 if (scatterData)
15140 delete scatterData;
15163 15141 }
15164 15142
15165 15143 /* inherits documentation from base class */
15166 15144 void QCPGraph::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const
15167 15145 {
15168 // draw fill:
15169 if (mBrush.style() != Qt::NoBrush)
15170 {
15171 applyFillAntialiasingHint(painter);
15172 painter->fillRect(QRectF(rect.left(), rect.top()+rect.height()/2.0, rect.width(), rect.height()/3.0), mBrush);
15173 }
15174 // draw line vertically centered:
15175 if (mLineStyle != lsNone)
15176 {
15177 applyDefaultAntialiasingHint(painter);
15178 painter->setPen(mPen);
15179 painter->drawLine(QLineF(rect.left(), rect.top()+rect.height()/2.0, rect.right()+5, rect.top()+rect.height()/2.0)); // +5 on x2 else last segment is missing from dashed/dotted pens
15180 }
15181 // draw scatter symbol:
15182 if (!mScatterStyle.isNone())
15183 {
15184 applyScattersAntialiasingHint(painter);
15185 // scale scatter pixmap if it's too large to fit in legend icon rect:
15186 if (mScatterStyle.shape() == QCPScatterStyle::ssPixmap && (mScatterStyle.pixmap().size().width() > rect.width() || mScatterStyle.pixmap().size().height() > rect.height()))
15187 {
15188 QCPScatterStyle scaledStyle(mScatterStyle);
15189 scaledStyle.setPixmap(scaledStyle.pixmap().scaled(rect.size().toSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
15190 scaledStyle.applyTo(painter, mPen);
15191 scaledStyle.drawShape(painter, QRectF(rect).center());
15146 // draw fill:
15147 if (mBrush.style() != Qt::NoBrush)
15148 {
15149 applyFillAntialiasingHint(painter);
15150 painter->fillRect(QRectF(rect.left(), rect.top()+rect.height()/2.0, rect.width(), rect.height()/3.0), mBrush);
15151 }
15152 // draw line vertically centered:
15153 if (mLineStyle != lsNone)
15154 {
15155 applyDefaultAntialiasingHint(painter);
15156 painter->setPen(mPen);
15157 painter->drawLine(QLineF(rect.left(), rect.top()+rect.height()/2.0, rect.right()+5, rect.top()+rect.height()/2.0)); // +5 on x2 else last segment is missing from dashed/dotted pens
15158 }
15159 // draw scatter symbol:
15160 if (!mScatterStyle.isNone())
15161 {
15162 applyScattersAntialiasingHint(painter);
15163 // scale scatter pixmap if it's too large to fit in legend icon rect:
15164 if (mScatterStyle.shape() == QCPScatterStyle::ssPixmap && (mScatterStyle.pixmap().size().width() > rect.width() || mScatterStyle.pixmap().size().height() > rect.height()))
15165 {
15166 QCPScatterStyle scaledStyle(mScatterStyle);
15167 scaledStyle.setPixmap(scaledStyle.pixmap().scaled(rect.size().toSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
15168 scaledStyle.applyTo(painter, mPen);
15169 scaledStyle.drawShape(painter, QRectF(rect).center());
15192 15170 } else
15193 15171 {
15194 mScatterStyle.applyTo(painter, mPen);
15195 mScatterStyle.drawShape(painter, QRectF(rect).center());
15172 mScatterStyle.applyTo(painter, mPen);
15173 mScatterStyle.drawShape(painter, QRectF(rect).center());
15196 15174 }
15197 15175 }
15198 15176 }
@@ -15217,7 +15195,7 void QCPGraph::drawLegendIcon(QCPPainter
15217 15195 */
15218 15196 void QCPGraph::getPlotData(QVector<QPointF> *lineData, QVector<QCPData> *scatterData) const
15219 15197 {
15220 switch(mLineStyle)
15198 switch(mLineStyle)
15221 15199 {
15222 15200 case lsNone: getScatterPlotData(scatterData); break;
15223 15201 case lsLine: getLinePlotData(lineData, scatterData); break;
@@ -15241,7 +15219,7 void QCPGraph::getPlotData(QVector<QPoin
15241 15219 */
15242 15220 void QCPGraph::getScatterPlotData(QVector<QCPData> *scatterData) const
15243 15221 {
15244 getPreparedData(0, scatterData);
15222 getPreparedData(0, scatterData);
15245 15223 }
15246 15224
15247 15225 /*! \internal
@@ -15257,33 +15235,30 void QCPGraph::getScatterPlotData(QVecto
15257 15235 */
15258 15236 void QCPGraph::getLinePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const
15259 15237 {
15260 QCPAxis *keyAxis = mKeyAxis.data();
15261 QCPAxis *valueAxis = mValueAxis.data();
15262 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15263 if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as linePixelData"; return; }
15264
15265 QVector<QCPData> lineData;
15266 if(mUseFastVectors)
15267 getPreparedDataVector(&lineData, scatterData);
15268 else
15238 QCPAxis *keyAxis = mKeyAxis.data();
15239 QCPAxis *valueAxis = mValueAxis.data();
15240 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15241 if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as linePixelData"; return; }
15242
15243 QVector<QCPData> lineData;
15269 15244 getPreparedData(&lineData, scatterData);
15270 linePixelData->reserve(lineData.size()+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill
15271 linePixelData->resize(lineData.size());
15272
15273 // transform lineData points to pixels:
15274 if (keyAxis->orientation() == Qt::Vertical)
15275 {
15276 for (int i=0; i<lineData.size(); ++i)
15277 {
15278 (*linePixelData)[i].setX(valueAxis->coordToPixel(lineData.at(i).value));
15279 (*linePixelData)[i].setY(keyAxis->coordToPixel(lineData.at(i).key));
15245 linePixelData->reserve(lineData.size()+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill
15246 linePixelData->resize(lineData.size());
15247
15248 // transform lineData points to pixels:
15249 if (keyAxis->orientation() == Qt::Vertical)
15250 {
15251 for (int i=0; i<lineData.size(); ++i)
15252 {
15253 (*linePixelData)[i].setX(valueAxis->coordToPixel(lineData.at(i).value));
15254 (*linePixelData)[i].setY(keyAxis->coordToPixel(lineData.at(i).key));
15280 15255 }
15281 15256 } else // key axis is horizontal
15282 15257 {
15283 for (int i=0; i<lineData.size(); ++i)
15284 {
15285 (*linePixelData)[i].setX(keyAxis->coordToPixel(lineData.at(i).key));
15286 (*linePixelData)[i].setY(valueAxis->coordToPixel(lineData.at(i).value));
15258 for (int i=0; i<lineData.size(); ++i)
15259 {
15260 (*linePixelData)[i].setX(keyAxis->coordToPixel(lineData.at(i).key));
15261 (*linePixelData)[i].setY(valueAxis->coordToPixel(lineData.at(i).value));
15287 15262 }
15288 15263 }
15289 15264 }
@@ -15301,42 +15276,42 void QCPGraph::getLinePlotData(QVector<Q
15301 15276 */
15302 15277 void QCPGraph::getStepLeftPlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const
15303 15278 {
15304 QCPAxis *keyAxis = mKeyAxis.data();
15305 QCPAxis *valueAxis = mValueAxis.data();
15306 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15307 if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as lineData"; return; }
15308
15309 QVector<QCPData> lineData;
15310 getPreparedData(&lineData, scatterData);
15311 linePixelData->reserve(lineData.size()*2+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill
15312 linePixelData->resize(lineData.size()*2);
15313
15314 // calculate steps from lineData and transform to pixel coordinates:
15315 if (keyAxis->orientation() == Qt::Vertical)
15316 {
15317 double lastValue = valueAxis->coordToPixel(lineData.first().value);
15318 double key;
15319 for (int i=0; i<lineData.size(); ++i)
15320 {
15321 key = keyAxis->coordToPixel(lineData.at(i).key);
15322 (*linePixelData)[i*2+0].setX(lastValue);
15323 (*linePixelData)[i*2+0].setY(key);
15324 lastValue = valueAxis->coordToPixel(lineData.at(i).value);
15325 (*linePixelData)[i*2+1].setX(lastValue);
15326 (*linePixelData)[i*2+1].setY(key);
15279 QCPAxis *keyAxis = mKeyAxis.data();
15280 QCPAxis *valueAxis = mValueAxis.data();
15281 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15282 if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as lineData"; return; }
15283
15284 QVector<QCPData> lineData;
15285 getPreparedData(&lineData, scatterData);
15286 linePixelData->reserve(lineData.size()*2+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill
15287 linePixelData->resize(lineData.size()*2);
15288
15289 // calculate steps from lineData and transform to pixel coordinates:
15290 if (keyAxis->orientation() == Qt::Vertical)
15291 {
15292 double lastValue = valueAxis->coordToPixel(lineData.first().value);
15293 double key;
15294 for (int i=0; i<lineData.size(); ++i)
15295 {
15296 key = keyAxis->coordToPixel(lineData.at(i).key);
15297 (*linePixelData)[i*2+0].setX(lastValue);
15298 (*linePixelData)[i*2+0].setY(key);
15299 lastValue = valueAxis->coordToPixel(lineData.at(i).value);
15300 (*linePixelData)[i*2+1].setX(lastValue);
15301 (*linePixelData)[i*2+1].setY(key);
15327 15302 }
15328 15303 } else // key axis is horizontal
15329 15304 {
15330 double lastValue = valueAxis->coordToPixel(lineData.first().value);
15331 double key;
15332 for (int i=0; i<lineData.size(); ++i)
15333 {
15334 key = keyAxis->coordToPixel(lineData.at(i).key);
15335 (*linePixelData)[i*2+0].setX(key);
15336 (*linePixelData)[i*2+0].setY(lastValue);
15337 lastValue = valueAxis->coordToPixel(lineData.at(i).value);
15338 (*linePixelData)[i*2+1].setX(key);
15339 (*linePixelData)[i*2+1].setY(lastValue);
15305 double lastValue = valueAxis->coordToPixel(lineData.first().value);
15306 double key;
15307 for (int i=0; i<lineData.size(); ++i)
15308 {
15309 key = keyAxis->coordToPixel(lineData.at(i).key);
15310 (*linePixelData)[i*2+0].setX(key);
15311 (*linePixelData)[i*2+0].setY(lastValue);
15312 lastValue = valueAxis->coordToPixel(lineData.at(i).value);
15313 (*linePixelData)[i*2+1].setX(key);
15314 (*linePixelData)[i*2+1].setY(lastValue);
15340 15315 }
15341 15316 }
15342 15317 }
@@ -15354,42 +15329,42 void QCPGraph::getStepLeftPlotData(QVect
15354 15329 */
15355 15330 void QCPGraph::getStepRightPlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const
15356 15331 {
15357 QCPAxis *keyAxis = mKeyAxis.data();
15358 QCPAxis *valueAxis = mValueAxis.data();
15359 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15360 if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as lineData"; return; }
15361
15362 QVector<QCPData> lineData;
15363 getPreparedData(&lineData, scatterData);
15364 linePixelData->reserve(lineData.size()*2+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill
15365 linePixelData->resize(lineData.size()*2);
15366
15367 // calculate steps from lineData and transform to pixel coordinates:
15368 if (keyAxis->orientation() == Qt::Vertical)
15369 {
15370 double lastKey = keyAxis->coordToPixel(lineData.first().key);
15371 double value;
15372 for (int i=0; i<lineData.size(); ++i)
15373 {
15374 value = valueAxis->coordToPixel(lineData.at(i).value);
15375 (*linePixelData)[i*2+0].setX(value);
15376 (*linePixelData)[i*2+0].setY(lastKey);
15377 lastKey = keyAxis->coordToPixel(lineData.at(i).key);
15378 (*linePixelData)[i*2+1].setX(value);
15379 (*linePixelData)[i*2+1].setY(lastKey);
15332 QCPAxis *keyAxis = mKeyAxis.data();
15333 QCPAxis *valueAxis = mValueAxis.data();
15334 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15335 if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as lineData"; return; }
15336
15337 QVector<QCPData> lineData;
15338 getPreparedData(&lineData, scatterData);
15339 linePixelData->reserve(lineData.size()*2+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill
15340 linePixelData->resize(lineData.size()*2);
15341
15342 // calculate steps from lineData and transform to pixel coordinates:
15343 if (keyAxis->orientation() == Qt::Vertical)
15344 {
15345 double lastKey = keyAxis->coordToPixel(lineData.first().key);
15346 double value;
15347 for (int i=0; i<lineData.size(); ++i)
15348 {
15349 value = valueAxis->coordToPixel(lineData.at(i).value);
15350 (*linePixelData)[i*2+0].setX(value);
15351 (*linePixelData)[i*2+0].setY(lastKey);
15352 lastKey = keyAxis->coordToPixel(lineData.at(i).key);
15353 (*linePixelData)[i*2+1].setX(value);
15354 (*linePixelData)[i*2+1].setY(lastKey);
15380 15355 }
15381 15356 } else // key axis is horizontal
15382 15357 {
15383 double lastKey = keyAxis->coordToPixel(lineData.first().key);
15384 double value;
15385 for (int i=0; i<lineData.size(); ++i)
15386 {
15387 value = valueAxis->coordToPixel(lineData.at(i).value);
15388 (*linePixelData)[i*2+0].setX(lastKey);
15389 (*linePixelData)[i*2+0].setY(value);
15390 lastKey = keyAxis->coordToPixel(lineData.at(i).key);
15391 (*linePixelData)[i*2+1].setX(lastKey);
15392 (*linePixelData)[i*2+1].setY(value);
15358 double lastKey = keyAxis->coordToPixel(lineData.first().key);
15359 double value;
15360 for (int i=0; i<lineData.size(); ++i)
15361 {
15362 value = valueAxis->coordToPixel(lineData.at(i).value);
15363 (*linePixelData)[i*2+0].setX(lastKey);
15364 (*linePixelData)[i*2+0].setY(value);
15365 lastKey = keyAxis->coordToPixel(lineData.at(i).key);
15366 (*linePixelData)[i*2+1].setX(lastKey);
15367 (*linePixelData)[i*2+1].setY(value);
15393 15368 }
15394 15369 }
15395 15370 }
@@ -15407,54 +15382,54 void QCPGraph::getStepRightPlotData(QVec
15407 15382 */
15408 15383 void QCPGraph::getStepCenterPlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const
15409 15384 {
15410 QCPAxis *keyAxis = mKeyAxis.data();
15411 QCPAxis *valueAxis = mValueAxis.data();
15412 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15413 if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as lineData"; return; }
15414
15415 QVector<QCPData> lineData;
15416 getPreparedData(&lineData, scatterData);
15417 linePixelData->reserve(lineData.size()*2+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill
15418 linePixelData->resize(lineData.size()*2);
15419 // calculate steps from lineData and transform to pixel coordinates:
15420 if (keyAxis->orientation() == Qt::Vertical)
15421 {
15422 double lastKey = keyAxis->coordToPixel(lineData.first().key);
15423 double lastValue = valueAxis->coordToPixel(lineData.first().value);
15424 double key;
15425 (*linePixelData)[0].setX(lastValue);
15426 (*linePixelData)[0].setY(lastKey);
15427 for (int i=1; i<lineData.size(); ++i)
15428 {
15429 key = (keyAxis->coordToPixel(lineData.at(i).key)+lastKey)*0.5;
15430 (*linePixelData)[i*2-1].setX(lastValue);
15431 (*linePixelData)[i*2-1].setY(key);
15432 lastValue = valueAxis->coordToPixel(lineData.at(i).value);
15433 lastKey = keyAxis->coordToPixel(lineData.at(i).key);
15434 (*linePixelData)[i*2+0].setX(lastValue);
15435 (*linePixelData)[i*2+0].setY(key);
15436 }
15437 (*linePixelData)[lineData.size()*2-1].setX(lastValue);
15438 (*linePixelData)[lineData.size()*2-1].setY(lastKey);
15385 QCPAxis *keyAxis = mKeyAxis.data();
15386 QCPAxis *valueAxis = mValueAxis.data();
15387 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15388 if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as lineData"; return; }
15389
15390 QVector<QCPData> lineData;
15391 getPreparedData(&lineData, scatterData);
15392 linePixelData->reserve(lineData.size()*2+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill
15393 linePixelData->resize(lineData.size()*2);
15394 // calculate steps from lineData and transform to pixel coordinates:
15395 if (keyAxis->orientation() == Qt::Vertical)
15396 {
15397 double lastKey = keyAxis->coordToPixel(lineData.first().key);
15398 double lastValue = valueAxis->coordToPixel(lineData.first().value);
15399 double key;
15400 (*linePixelData)[0].setX(lastValue);
15401 (*linePixelData)[0].setY(lastKey);
15402 for (int i=1; i<lineData.size(); ++i)
15403 {
15404 key = (keyAxis->coordToPixel(lineData.at(i).key)+lastKey)*0.5;
15405 (*linePixelData)[i*2-1].setX(lastValue);
15406 (*linePixelData)[i*2-1].setY(key);
15407 lastValue = valueAxis->coordToPixel(lineData.at(i).value);
15408 lastKey = keyAxis->coordToPixel(lineData.at(i).key);
15409 (*linePixelData)[i*2+0].setX(lastValue);
15410 (*linePixelData)[i*2+0].setY(key);
15411 }
15412 (*linePixelData)[lineData.size()*2-1].setX(lastValue);
15413 (*linePixelData)[lineData.size()*2-1].setY(lastKey);
15439 15414 } else // key axis is horizontal
15440 15415 {
15441 double lastKey = keyAxis->coordToPixel(lineData.first().key);
15442 double lastValue = valueAxis->coordToPixel(lineData.first().value);
15443 double key;
15444 (*linePixelData)[0].setX(lastKey);
15445 (*linePixelData)[0].setY(lastValue);
15446 for (int i=1; i<lineData.size(); ++i)
15447 {
15448 key = (keyAxis->coordToPixel(lineData.at(i).key)+lastKey)*0.5;
15449 (*linePixelData)[i*2-1].setX(key);
15450 (*linePixelData)[i*2-1].setY(lastValue);
15451 lastValue = valueAxis->coordToPixel(lineData.at(i).value);
15452 lastKey = keyAxis->coordToPixel(lineData.at(i).key);
15453 (*linePixelData)[i*2+0].setX(key);
15454 (*linePixelData)[i*2+0].setY(lastValue);
15455 }
15456 (*linePixelData)[lineData.size()*2-1].setX(lastKey);
15457 (*linePixelData)[lineData.size()*2-1].setY(lastValue);
15416 double lastKey = keyAxis->coordToPixel(lineData.first().key);
15417 double lastValue = valueAxis->coordToPixel(lineData.first().value);
15418 double key;
15419 (*linePixelData)[0].setX(lastKey);
15420 (*linePixelData)[0].setY(lastValue);
15421 for (int i=1; i<lineData.size(); ++i)
15422 {
15423 key = (keyAxis->coordToPixel(lineData.at(i).key)+lastKey)*0.5;
15424 (*linePixelData)[i*2-1].setX(key);
15425 (*linePixelData)[i*2-1].setY(lastValue);
15426 lastValue = valueAxis->coordToPixel(lineData.at(i).value);
15427 lastKey = keyAxis->coordToPixel(lineData.at(i).key);
15428 (*linePixelData)[i*2+0].setX(key);
15429 (*linePixelData)[i*2+0].setY(lastValue);
15430 }
15431 (*linePixelData)[lineData.size()*2-1].setX(lastKey);
15432 (*linePixelData)[lineData.size()*2-1].setY(lastValue);
15458 15433 }
15459 15434
15460 15435 }
@@ -15472,39 +15447,39 void QCPGraph::getStepCenterPlotData(QVe
15472 15447 */
15473 15448 void QCPGraph::getImpulsePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const
15474 15449 {
15475 QCPAxis *keyAxis = mKeyAxis.data();
15476 QCPAxis *valueAxis = mValueAxis.data();
15477 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15478 if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as linePixelData"; return; }
15479
15480 QVector<QCPData> lineData;
15481 getPreparedData(&lineData, scatterData);
15482 linePixelData->resize(lineData.size()*2); // no need to reserve 2 extra points because impulse plot has no fill
15483
15484 // transform lineData points to pixels:
15485 if (keyAxis->orientation() == Qt::Vertical)
15486 {
15487 double zeroPointX = valueAxis->coordToPixel(0);
15488 double key;
15489 for (int i=0; i<lineData.size(); ++i)
15490 {
15491 key = keyAxis->coordToPixel(lineData.at(i).key);
15492 (*linePixelData)[i*2+0].setX(zeroPointX);
15493 (*linePixelData)[i*2+0].setY(key);
15494 (*linePixelData)[i*2+1].setX(valueAxis->coordToPixel(lineData.at(i).value));
15495 (*linePixelData)[i*2+1].setY(key);
15450 QCPAxis *keyAxis = mKeyAxis.data();
15451 QCPAxis *valueAxis = mValueAxis.data();
15452 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15453 if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as linePixelData"; return; }
15454
15455 QVector<QCPData> lineData;
15456 getPreparedData(&lineData, scatterData);
15457 linePixelData->resize(lineData.size()*2); // no need to reserve 2 extra points because impulse plot has no fill
15458
15459 // transform lineData points to pixels:
15460 if (keyAxis->orientation() == Qt::Vertical)
15461 {
15462 double zeroPointX = valueAxis->coordToPixel(0);
15463 double key;
15464 for (int i=0; i<lineData.size(); ++i)
15465 {
15466 key = keyAxis->coordToPixel(lineData.at(i).key);
15467 (*linePixelData)[i*2+0].setX(zeroPointX);
15468 (*linePixelData)[i*2+0].setY(key);
15469 (*linePixelData)[i*2+1].setX(valueAxis->coordToPixel(lineData.at(i).value));
15470 (*linePixelData)[i*2+1].setY(key);
15496 15471 }
15497 15472 } else // key axis is horizontal
15498 15473 {
15499 double zeroPointY = valueAxis->coordToPixel(0);
15500 double key;
15501 for (int i=0; i<lineData.size(); ++i)
15502 {
15503 key = keyAxis->coordToPixel(lineData.at(i).key);
15504 (*linePixelData)[i*2+0].setX(key);
15505 (*linePixelData)[i*2+0].setY(zeroPointY);
15506 (*linePixelData)[i*2+1].setX(key);
15507 (*linePixelData)[i*2+1].setY(valueAxis->coordToPixel(lineData.at(i).value));
15474 double zeroPointY = valueAxis->coordToPixel(0);
15475 double key;
15476 for (int i=0; i<lineData.size(); ++i)
15477 {
15478 key = keyAxis->coordToPixel(lineData.at(i).key);
15479 (*linePixelData)[i*2+0].setX(key);
15480 (*linePixelData)[i*2+0].setY(zeroPointY);
15481 (*linePixelData)[i*2+1].setX(key);
15482 (*linePixelData)[i*2+1].setY(valueAxis->coordToPixel(lineData.at(i).value));
15508 15483 }
15509 15484 }
15510 15485 }
@@ -15524,24 +15499,24 void QCPGraph::getImpulsePlotData(QVecto
15524 15499 */
15525 15500 void QCPGraph::drawFill(QCPPainter *painter, QVector<QPointF> *lineData) const
15526 15501 {
15527 if (mLineStyle == lsImpulse) return; // fill doesn't make sense for impulse plot
15528 if (mainBrush().style() == Qt::NoBrush || mainBrush().color().alpha() == 0) return;
15529
15530 applyFillAntialiasingHint(painter);
15531 if (!mChannelFillGraph)
15532 {
15533 // draw base fill under graph, fill goes all the way to the zero-value-line:
15534 addFillBasePoints(lineData);
15535 painter->setPen(Qt::NoPen);
15536 painter->setBrush(mainBrush());
15537 painter->drawPolygon(QPolygonF(*lineData));
15538 removeFillBasePoints(lineData);
15539 } else
15540 {
15541 // draw channel fill between this graph and mChannelFillGraph:
15542 painter->setPen(Qt::NoPen);
15543 painter->setBrush(mainBrush());
15544 painter->drawPolygon(getChannelFillPolygon(lineData));
15502 if (mLineStyle == lsImpulse) return; // fill doesn't make sense for impulse plot
15503 if (mainBrush().style() == Qt::NoBrush || mainBrush().color().alpha() == 0) return;
15504
15505 applyFillAntialiasingHint(painter);
15506 if (!mChannelFillGraph)
15507 {
15508 // draw base fill under graph, fill goes all the way to the zero-value-line:
15509 addFillBasePoints(lineData);
15510 painter->setPen(Qt::NoPen);
15511 painter->setBrush(mainBrush());
15512 painter->drawPolygon(QPolygonF(*lineData));
15513 removeFillBasePoints(lineData);
15514 } else
15515 {
15516 // draw channel fill between this graph and mChannelFillGraph:
15517 painter->setPen(Qt::NoPen);
15518 painter->setBrush(mainBrush());
15519 painter->drawPolygon(getChannelFillPolygon(lineData));
15545 15520 }
15546 15521 }
15547 15522
@@ -15556,39 +15531,39 void QCPGraph::drawFill(QCPPainter *pain
15556 15531 */
15557 15532 void QCPGraph::drawScatterPlot(QCPPainter *painter, QVector<QCPData> *scatterData) const
15558 15533 {
15559 QCPAxis *keyAxis = mKeyAxis.data();
15560 QCPAxis *valueAxis = mValueAxis.data();
15561 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15562
15563 // draw error bars:
15564 if (mErrorType != etNone)
15565 {
15566 applyErrorBarsAntialiasingHint(painter);
15567 painter->setPen(mErrorPen);
15568 if (keyAxis->orientation() == Qt::Vertical)
15569 {
15570 for (int i=0; i<scatterData->size(); ++i)
15571 drawError(painter, valueAxis->coordToPixel(scatterData->at(i).value), keyAxis->coordToPixel(scatterData->at(i).key), scatterData->at(i));
15534 QCPAxis *keyAxis = mKeyAxis.data();
15535 QCPAxis *valueAxis = mValueAxis.data();
15536 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15537
15538 // draw error bars:
15539 if (mErrorType != etNone)
15540 {
15541 applyErrorBarsAntialiasingHint(painter);
15542 painter->setPen(mErrorPen);
15543 if (keyAxis->orientation() == Qt::Vertical)
15544 {
15545 for (int i=0; i<scatterData->size(); ++i)
15546 drawError(painter, valueAxis->coordToPixel(scatterData->at(i).value), keyAxis->coordToPixel(scatterData->at(i).key), scatterData->at(i));
15572 15547 } else
15573 15548 {
15574 for (int i=0; i<scatterData->size(); ++i)
15575 drawError(painter, keyAxis->coordToPixel(scatterData->at(i).key), valueAxis->coordToPixel(scatterData->at(i).value), scatterData->at(i));
15576 }
15577 }
15578
15579 // draw scatter point symbols:
15580 applyScattersAntialiasingHint(painter);
15581 mScatterStyle.applyTo(painter, mPen);
15582 if (keyAxis->orientation() == Qt::Vertical)
15583 {
15584 for (int i=0; i<scatterData->size(); ++i)
15585 if (!qIsNaN(scatterData->at(i).value))
15586 mScatterStyle.drawShape(painter, valueAxis->coordToPixel(scatterData->at(i).value), keyAxis->coordToPixel(scatterData->at(i).key));
15587 } else
15588 {
15589 for (int i=0; i<scatterData->size(); ++i)
15590 if (!qIsNaN(scatterData->at(i).value))
15591 mScatterStyle.drawShape(painter, keyAxis->coordToPixel(scatterData->at(i).key), valueAxis->coordToPixel(scatterData->at(i).value));
15549 for (int i=0; i<scatterData->size(); ++i)
15550 drawError(painter, keyAxis->coordToPixel(scatterData->at(i).key), valueAxis->coordToPixel(scatterData->at(i).value), scatterData->at(i));
15551 }
15552 }
15553
15554 // draw scatter point symbols:
15555 applyScattersAntialiasingHint(painter);
15556 mScatterStyle.applyTo(painter, mPen);
15557 if (keyAxis->orientation() == Qt::Vertical)
15558 {
15559 for (int i=0; i<scatterData->size(); ++i)
15560 if (!qIsNaN(scatterData->at(i).value))
15561 mScatterStyle.drawShape(painter, valueAxis->coordToPixel(scatterData->at(i).value), keyAxis->coordToPixel(scatterData->at(i).key));
15562 } else
15563 {
15564 for (int i=0; i<scatterData->size(); ++i)
15565 if (!qIsNaN(scatterData->at(i).value))
15566 mScatterStyle.drawShape(painter, keyAxis->coordToPixel(scatterData->at(i).key), valueAxis->coordToPixel(scatterData->at(i).value));
15592 15567 }
15593 15568 }
15594 15569
@@ -15603,14 +15578,14 void QCPGraph::drawScatterPlot(QCPPainte
15603 15578 */
15604 15579 void QCPGraph::drawLinePlot(QCPPainter *painter, QVector<QPointF> *lineData) const
15605 15580 {
15606 // draw line of graph:
15607 if (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0)
15608 {
15609 applyDefaultAntialiasingHint(painter);
15610 painter->setPen(mainPen());
15611 painter->setBrush(Qt::NoBrush);
15612
15613 /* Draws polyline in batches, currently not used:
15581 // draw line of graph:
15582 if (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0)
15583 {
15584 applyDefaultAntialiasingHint(painter);
15585 painter->setPen(mainPen());
15586 painter->setBrush(Qt::NoBrush);
15587
15588 /* Draws polyline in batches, currently not used:
15614 15589 int p = 0;
15615 15590 while (p < lineData->size())
15616 15591 {
@@ -15625,38 +15600,38 void QCPGraph::drawLinePlot(QCPPainter *
15625 15600 }
15626 15601 */
15627 15602
15628 // if drawing solid line and not in PDF, use much faster line drawing instead of polyline:
15629 if (mParentPlot->plottingHints().testFlag(QCP::phFastPolylines) &&
15630 painter->pen().style() == Qt::SolidLine &&
15631 !painter->modes().testFlag(QCPPainter::pmVectorized)&&
15632 !painter->modes().testFlag(QCPPainter::pmNoCaching))
15633 {
15634 int i = 1;
15635 int lineDataSize = lineData->size();
15636 while (i < lineDataSize)
15637 {
15638 if (!qIsNaN(lineData->at(i).y()) && !qIsNaN(lineData->at(i).x())) // NaNs create a gap in the line
15639 painter->drawLine(lineData->at(i-1), lineData->at(i));
15640 else
15603 // if drawing solid line and not in PDF, use much faster line drawing instead of polyline:
15604 if (mParentPlot->plottingHints().testFlag(QCP::phFastPolylines) &&
15605 painter->pen().style() == Qt::SolidLine &&
15606 !painter->modes().testFlag(QCPPainter::pmVectorized)&&
15607 !painter->modes().testFlag(QCPPainter::pmNoCaching))
15608 {
15609 int i = 1;
15610 int lineDataSize = lineData->size();
15611 while (i < lineDataSize)
15612 {
15613 if (!qIsNaN(lineData->at(i).y()) && !qIsNaN(lineData->at(i).x())) // NaNs create a gap in the line
15614 painter->drawLine(lineData->at(i-1), lineData->at(i));
15615 else
15616 ++i;
15641 15617 ++i;
15642 ++i;
15643 15618 }
15644 15619 } else
15645 15620 {
15646 int segmentStart = 0;
15647 int i = 0;
15648 int lineDataSize = lineData->size();
15649 while (i < lineDataSize)
15650 {
15651 if (qIsNaN(lineData->at(i).y()) || qIsNaN(lineData->at(i).x())) // NaNs create a gap in the line
15621 int segmentStart = 0;
15622 int i = 0;
15623 int lineDataSize = lineData->size();
15624 while (i < lineDataSize)
15625 {
15626 if (qIsNaN(lineData->at(i).y()) || qIsNaN(lineData->at(i).x())) // NaNs create a gap in the line
15652 15627 {
15653 painter->drawPolyline(lineData->constData()+segmentStart, i-segmentStart); // i, because we don't want to include the current NaN point
15654 segmentStart = i+1;
15628 painter->drawPolyline(lineData->constData()+segmentStart, i-segmentStart); // i, because we don't want to include the current NaN point
15629 segmentStart = i+1;
15655 15630 }
15656 ++i;
15657 }
15658 // draw last segment:
15659 painter->drawPolyline(lineData->constData()+segmentStart, lineDataSize-segmentStart); // lineDataSize, because we do want to include the last point
15631 ++i;
15632 }
15633 // draw last segment:
15634 painter->drawPolyline(lineData->constData()+segmentStart, lineDataSize-segmentStart); // lineDataSize, because we do want to include the last point
15660 15635 }
15661 15636 }
15662 15637 }
@@ -15670,15 +15645,15 void QCPGraph::drawLinePlot(QCPPainter *
15670 15645 */
15671 15646 void QCPGraph::drawImpulsePlot(QCPPainter *painter, QVector<QPointF> *lineData) const
15672 15647 {
15673 // draw impulses:
15674 if (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0)
15675 {
15676 applyDefaultAntialiasingHint(painter);
15677 QPen pen = mainPen();
15678 pen.setCapStyle(Qt::FlatCap); // so impulse line doesn't reach beyond zero-line
15679 painter->setPen(pen);
15680 painter->setBrush(Qt::NoBrush);
15681 painter->drawLines(*lineData);
15648 // draw impulses:
15649 if (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0)
15650 {
15651 applyDefaultAntialiasingHint(painter);
15652 QPen pen = mainPen();
15653 pen.setCapStyle(Qt::FlatCap); // so impulse line doesn't reach beyond zero-line
15654 painter->setPen(pen);
15655 painter->setBrush(Qt::NoBrush);
15656 painter->drawLines(*lineData);
15682 15657 }
15683 15658 }
15684 15659
@@ -15696,368 +15671,182 void QCPGraph::drawImpulsePlot(QCPPainte
15696 15671 */
15697 15672 void QCPGraph::getPreparedData(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const
15698 15673 {
15699 QCPAxis *keyAxis = mKeyAxis.data();
15700 QCPAxis *valueAxis = mValueAxis.data();
15701 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15702 // get visible data range:
15703 QCPDataMap::const_iterator lower, upper; // note that upper is the actual upper point, and not 1 step after the upper point
15704 getVisibleDataBounds(lower, upper);
15705 if (lower == mData->constEnd() || upper == mData->constEnd())
15706 return;
15707
15708 // count points in visible range, taking into account that we only need to count to the limit maxCount if using adaptive sampling:
15709 int maxCount = std::numeric_limits<int>::max();
15710 if (mAdaptiveSampling)
15711 {
15712 int keyPixelSpan = qAbs(keyAxis->coordToPixel(lower.key())-keyAxis->coordToPixel(upper.key()));
15713 maxCount = 2*keyPixelSpan+2;
15714 }
15715 int dataCount = countDataInBounds(lower, upper, maxCount);
15716
15717 if (mAdaptiveSampling && dataCount >= maxCount) // use adaptive sampling only if there are at least two points per pixel on average
15718 {
15719 if (lineData)
15720 {
15721 QCPDataMap::const_iterator it = lower;
15722 QCPDataMap::const_iterator upperEnd = upper+1;
15723 double minValue = it.value().value;
15724 double maxValue = it.value().value;
15725 QCPDataMap::const_iterator currentIntervalFirstPoint = it;
15726 int reversedFactor = keyAxis->rangeReversed() != (keyAxis->orientation()==Qt::Vertical) ? -1 : 1; // is used to calculate keyEpsilon pixel into the correct direction
15727 int reversedRound = keyAxis->rangeReversed() != (keyAxis->orientation()==Qt::Vertical) ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey
15728 double currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel(lower.key())+reversedRound));
15729 double lastIntervalEndKey = currentIntervalStartKey;
15730 double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates
15731 bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes)
15732 int intervalDataCount = 1;
15733 ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect
15734 while (it != upperEnd)
15735 {
15736 if (it.key() < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this cluster if necessary
15674 QCPAxis *keyAxis = mKeyAxis.data();
15675 QCPAxis *valueAxis = mValueAxis.data();
15676 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15677 // get visible data range:
15678 QCPDataMap::const_iterator lower, upper; // note that upper is the actual upper point, and not 1 step after the upper point
15679 getVisibleDataBounds(lower, upper);
15680 if (lower == mData->constEnd() || upper == mData->constEnd())
15681 return;
15682
15683 // count points in visible range, taking into account that we only need to count to the limit maxCount if using adaptive sampling:
15684 int maxCount = std::numeric_limits<int>::max();
15685 if (mAdaptiveSampling)
15686 {
15687 int keyPixelSpan = qAbs(keyAxis->coordToPixel(lower.key())-keyAxis->coordToPixel(upper.key()));
15688 maxCount = 2*keyPixelSpan+2;
15689 }
15690 int dataCount = countDataInBounds(lower, upper, maxCount);
15691
15692 if (mAdaptiveSampling && dataCount >= maxCount) // use adaptive sampling only if there are at least two points per pixel on average
15693 {
15694 if (lineData)
15695 {
15696 QCPDataMap::const_iterator it = lower;
15697 QCPDataMap::const_iterator upperEnd = upper+1;
15698 double minValue = it.value().value;
15699 double maxValue = it.value().value;
15700 QCPDataMap::const_iterator currentIntervalFirstPoint = it;
15701 int reversedFactor = keyAxis->rangeReversed() != (keyAxis->orientation()==Qt::Vertical) ? -1 : 1; // is used to calculate keyEpsilon pixel into the correct direction
15702 int reversedRound = keyAxis->rangeReversed() != (keyAxis->orientation()==Qt::Vertical) ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey
15703 double currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel(lower.key())+reversedRound));
15704 double lastIntervalEndKey = currentIntervalStartKey;
15705 double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates
15706 bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes)
15707 int intervalDataCount = 1;
15708 ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect
15709 while (it != upperEnd)
15710 {
15711 if (it.key() < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this cluster if necessary
15737 15712 {
15738 if (it.value().value < minValue)
15739 minValue = it.value().value;
15740 else if (it.value().value > maxValue)
15741 maxValue = it.value().value;
15742 ++intervalDataCount;
15713 if (it.value().value < minValue)
15714 minValue = it.value().value;
15715 else if (it.value().value > maxValue)
15716 maxValue = it.value().value;
15717 ++intervalDataCount;
15743 15718 } else // new pixel interval started
15744 15719 {
15745 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster
15720 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster
15746 15721 {
15747 if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point is further away, so first point of this cluster must be at a real data point
15748 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.2, currentIntervalFirstPoint.value().value));
15749 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue));
15750 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue));
15751 if (it.key() > currentIntervalStartKey+keyEpsilon*2) // new pixel started further away from previous cluster, so make sure the last point of the cluster is at a real data point
15752 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.8, (it-1).value().value));
15722 if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point is further away, so first point of this cluster must be at a real data point
15723 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.2, currentIntervalFirstPoint.value().value));
15724 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue));
15725 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue));
15726 if (it.key() > currentIntervalStartKey+keyEpsilon*2) // new pixel started further away from previous cluster, so make sure the last point of the cluster is at a real data point
15727 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.8, (it-1).value().value));
15753 15728 } else
15754 lineData->append(QCPData(currentIntervalFirstPoint.key(), currentIntervalFirstPoint.value().value));
15755 lastIntervalEndKey = (it-1).value().key;
15756 minValue = it.value().value;
15757 maxValue = it.value().value;
15758 currentIntervalFirstPoint = it;
15759 currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel(it.key())+reversedRound));
15760 if (keyEpsilonVariable)
15761 keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor));
15762 intervalDataCount = 1;
15729 lineData->append(QCPData(currentIntervalFirstPoint.key(), currentIntervalFirstPoint.value().value));
15730 lastIntervalEndKey = (it-1).value().key;
15731 minValue = it.value().value;
15732 maxValue = it.value().value;
15733 currentIntervalFirstPoint = it;
15734 currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel(it.key())+reversedRound));
15735 if (keyEpsilonVariable)
15736 keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor));
15737 intervalDataCount = 1;
15763 15738 }
15764 ++it;
15765 }
15766 // handle last interval:
15767 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster
15768 {
15769 if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point wasn't a cluster, so first point of this cluster must be at a real data point
15770 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.2, currentIntervalFirstPoint.value().value));
15771 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue));
15772 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue));
15739 ++it;
15740 }
15741 // handle last interval:
15742 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster
15743 {
15744 if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point wasn't a cluster, so first point of this cluster must be at a real data point
15745 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.2, currentIntervalFirstPoint.value().value));
15746 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue));
15747 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue));
15773 15748 } else
15774 lineData->append(QCPData(currentIntervalFirstPoint.key(), currentIntervalFirstPoint.value().value));
15775 }
15776
15777 if (scatterData)
15778 {
15779 double valueMaxRange = valueAxis->range().upper;
15780 double valueMinRange = valueAxis->range().lower;
15781 QCPDataMap::const_iterator it = lower;
15782 QCPDataMap::const_iterator upperEnd = upper+1;
15783 double minValue = it.value().value;
15784 double maxValue = it.value().value;
15785 QCPDataMap::const_iterator minValueIt = it;
15786 QCPDataMap::const_iterator maxValueIt = it;
15787 QCPDataMap::const_iterator currentIntervalStart = it;
15788 int reversedFactor = keyAxis->rangeReversed() ? -1 : 1; // is used to calculate keyEpsilon pixel into the correct direction
15789 int reversedRound = keyAxis->rangeReversed() ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey
15790 double currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel(lower.key())+reversedRound));
15791 double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates
15792 bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes)
15793 int intervalDataCount = 1;
15794 ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect
15795 while (it != upperEnd)
15796 {
15797 if (it.key() < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this pixel if necessary
15749 lineData->append(QCPData(currentIntervalFirstPoint.key(), currentIntervalFirstPoint.value().value));
15750 }
15751
15752 if (scatterData)
15753 {
15754 double valueMaxRange = valueAxis->range().upper;
15755 double valueMinRange = valueAxis->range().lower;
15756 QCPDataMap::const_iterator it = lower;
15757 QCPDataMap::const_iterator upperEnd = upper+1;
15758 double minValue = it.value().value;
15759 double maxValue = it.value().value;
15760 QCPDataMap::const_iterator minValueIt = it;
15761 QCPDataMap::const_iterator maxValueIt = it;
15762 QCPDataMap::const_iterator currentIntervalStart = it;
15763 int reversedFactor = keyAxis->rangeReversed() ? -1 : 1; // is used to calculate keyEpsilon pixel into the correct direction
15764 int reversedRound = keyAxis->rangeReversed() ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey
15765 double currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel(lower.key())+reversedRound));
15766 double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates
15767 bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes)
15768 int intervalDataCount = 1;
15769 ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect
15770 while (it != upperEnd)
15771 {
15772 if (it.key() < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this pixel if necessary
15798 15773 {
15799 if (it.value().value < minValue && it.value().value > valueMinRange && it.value().value < valueMaxRange)
15774 if (it.value().value < minValue && it.value().value > valueMinRange && it.value().value < valueMaxRange)
15800 15775 {
15801 minValue = it.value().value;
15802 minValueIt = it;
15776 minValue = it.value().value;
15777 minValueIt = it;
15803 15778 } else if (it.value().value > maxValue && it.value().value > valueMinRange && it.value().value < valueMaxRange)
15804 15779 {
15805 maxValue = it.value().value;
15806 maxValueIt = it;
15780 maxValue = it.value().value;
15781 maxValueIt = it;
15807 15782 }
15808 ++intervalDataCount;
15783 ++intervalDataCount;
15809 15784 } else // new pixel started
15810 15785 {
15811 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them
15786 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them
15812 15787 {
15813 // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot):
15814 double valuePixelSpan = qAbs(valueAxis->coordToPixel(minValue)-valueAxis->coordToPixel(maxValue));
15815 int dataModulo = qMax(1, qRound(intervalDataCount/(valuePixelSpan/4.0))); // approximately every 4 value pixels one data point on average
15816 QCPDataMap::const_iterator intervalIt = currentIntervalStart;
15817 int c = 0;
15818 while (intervalIt != it)
15788 // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot):
15789 double valuePixelSpan = qAbs(valueAxis->coordToPixel(minValue)-valueAxis->coordToPixel(maxValue));
15790 int dataModulo = qMax(1, qRound(intervalDataCount/(valuePixelSpan/4.0))); // approximately every 4 value pixels one data point on average
15791 QCPDataMap::const_iterator intervalIt = currentIntervalStart;
15792 int c = 0;
15793 while (intervalIt != it)
15819 15794 {
15820 if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && intervalIt.value().value > valueMinRange && intervalIt.value().value < valueMaxRange)
15821 scatterData->append(intervalIt.value());
15822 ++c;
15823 ++intervalIt;
15795 if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && intervalIt.value().value > valueMinRange && intervalIt.value().value < valueMaxRange)
15796 scatterData->append(intervalIt.value());
15797 ++c;
15798 ++intervalIt;
15824 15799 }
15825 15800 } else if (currentIntervalStart.value().value > valueMinRange && currentIntervalStart.value().value < valueMaxRange)
15826 scatterData->append(currentIntervalStart.value());
15827 minValue = it.value().value;
15828 maxValue = it.value().value;
15829 currentIntervalStart = it;
15830 currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel(it.key())+reversedRound));
15831 if (keyEpsilonVariable)
15832 keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor));
15833 intervalDataCount = 1;
15801 scatterData->append(currentIntervalStart.value());
15802 minValue = it.value().value;
15803 maxValue = it.value().value;
15804 currentIntervalStart = it;
15805 currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel(it.key())+reversedRound));
15806 if (keyEpsilonVariable)
15807 keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor));
15808 intervalDataCount = 1;
15834 15809 }
15835 ++it;
15836 }
15837 // handle last interval:
15838 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them
15839 {
15840 // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot):
15841 double valuePixelSpan = qAbs(valueAxis->coordToPixel(minValue)-valueAxis->coordToPixel(maxValue));
15842 int dataModulo = qMax(1, qRound(intervalDataCount/(valuePixelSpan/4.0))); // approximately every 4 value pixels one data point on average
15843 QCPDataMap::const_iterator intervalIt = currentIntervalStart;
15844 int c = 0;
15845 while (intervalIt != it)
15810 ++it;
15811 }
15812 // handle last interval:
15813 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them
15814 {
15815 // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot):
15816 double valuePixelSpan = qAbs(valueAxis->coordToPixel(minValue)-valueAxis->coordToPixel(maxValue));
15817 int dataModulo = qMax(1, qRound(intervalDataCount/(valuePixelSpan/4.0))); // approximately every 4 value pixels one data point on average
15818 QCPDataMap::const_iterator intervalIt = currentIntervalStart;
15819 int c = 0;
15820 while (intervalIt != it)
15846 15821 {
15847 if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && intervalIt.value().value > valueMinRange && intervalIt.value().value < valueMaxRange)
15848 scatterData->append(intervalIt.value());
15849 ++c;
15850 ++intervalIt;
15822 if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && intervalIt.value().value > valueMinRange && intervalIt.value().value < valueMaxRange)
15823 scatterData->append(intervalIt.value());
15824 ++c;
15825 ++intervalIt;
15851 15826 }
15852 15827 } else if (currentIntervalStart.value().value > valueMinRange && currentIntervalStart.value().value < valueMaxRange)
15853 scatterData->append(currentIntervalStart.value());
15828 scatterData->append(currentIntervalStart.value());
15854 15829 }
15855 15830 } else // don't use adaptive sampling algorithm, transfer points one-to-one from the map into the output parameters
15856 15831 {
15857 QVector<QCPData> *dataVector = 0;
15858 if (lineData)
15859 {
15860 dataVector = lineData;
15861 }
15862 else if (scatterData)
15863 dataVector = scatterData;
15864 if (dataVector)
15865 {
15866 QCPDataMap::const_iterator it = lower;
15867 QCPDataMap::const_iterator upperEnd = upper+1;
15868 dataVector->reserve(dataCount+2); // +2 for possible fill end points
15869 while (it != upperEnd)
15870 {
15871 dataVector->append(it.value());
15872 ++it;
15873 }
15874 }
15875 if (lineData && scatterData)
15876 *scatterData = *dataVector;
15877 }
15878 }
15879
15880
15881 void QCPGraph::getPreparedDataVector(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const
15882 {
15883 QCPAxis *keyAxis = mKeyAxis.data();
15884 QCPAxis *valueAxis = mValueAxis.data();
15885 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15886 // get visible data range:
15887 QVector<QCPData>::const_iterator lower, upper; // note that upper is the actual upper point, and not 1 step after the upper point
15888 getVisibleDataBoundsVector(lower, upper);
15889 if (lower == mDataVector->constEnd() || upper == mDataVector->constEnd())
15890 return;
15891
15892 // count points in visible range, taking into account that we only need to count to the limit maxCount if using adaptive sampling:
15893 int maxCount = std::numeric_limits<int>::max();
15894 if (mAdaptiveSampling)
15895 {
15896 int keyPixelSpan = qAbs(keyAxis->coordToPixel((*lower).key)-keyAxis->coordToPixel((*upper).key));
15897 maxCount = 2*keyPixelSpan+2;
15898 }
15899 int dataCount = countDataInBoundsVector(lower, upper, maxCount);
15900
15901 if (mAdaptiveSampling && dataCount >= maxCount) // use adaptive sampling only if there are at least two points per pixel on average
15902 {
15903 if (lineData)
15904 {
15905 QVector<QCPData>::const_iterator it = lower;
15906 QVector<QCPData>::const_iterator upperEnd = upper+1;
15907 double minValue = (*it).value;
15908 double maxValue = (*it).value;
15909 QVector<QCPData>::const_iterator currentIntervalFirstPoint = it;
15910 int reversedFactor = keyAxis->rangeReversed() != (keyAxis->orientation()==Qt::Vertical) ? -1 : 1; // is used to calculate keyEpsilon pixel into the correct direction
15911 int reversedRound = keyAxis->rangeReversed() != (keyAxis->orientation()==Qt::Vertical) ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey
15912 double currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*lower).key)+reversedRound));
15913 double lastIntervalEndKey = currentIntervalStartKey;
15914 double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates
15915 bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes)
15916 int intervalDataCount = 1;
15917 ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect
15918 while (it != upperEnd)
15919 {
15920 if ((*it).key < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this cluster if necessary
15921 {
15922 if ((*it).value < minValue)
15923 minValue = (*it).value;
15924 else if ((*it).value > maxValue)
15925 maxValue = (*it).value;
15926 ++intervalDataCount;
15927 } else // new pixel interval started
15928 {
15929 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster
15930 {
15931 if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point is further away, so first point of this cluster must be at a real data point
15932 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.2, (*currentIntervalFirstPoint).value));
15933 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue));
15934 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue));
15935 if ((*it).key > currentIntervalStartKey+keyEpsilon*2) // new pixel started further away from previous cluster, so make sure the last point of the cluster is at a real data point
15936 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.8, (*(it-1)).value));
15937 } else
15938 lineData->append(QCPData((*currentIntervalFirstPoint).key, (*currentIntervalFirstPoint).value));
15939 lastIntervalEndKey = (*(it-1)).key;
15940 minValue = (*it).value;
15941 maxValue = (*it).value;
15942 currentIntervalFirstPoint = it;
15943 currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*it).key)+reversedRound));
15944 if (keyEpsilonVariable)
15945 keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor));
15946 intervalDataCount = 1;
15947 }
15948 ++it;
15949 }
15950 // handle last interval:
15951 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster
15952 {
15953 if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point wasn't a cluster, so first point of this cluster must be at a real data point
15954 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.2, (*currentIntervalFirstPoint).value));
15955 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue));
15956 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue));
15957 } else
15958 lineData->append(QCPData((*currentIntervalFirstPoint).key, (*currentIntervalFirstPoint).value));
15959 }
15960
15961 if (scatterData)
15962 {
15963 double valueMaxRange = valueAxis->range().upper;
15964 double valueMinRange = valueAxis->range().lower;
15965 QVector<QCPData>::const_iterator it = lower;
15966 QVector<QCPData>::const_iterator upperEnd = upper+1;
15967 double minValue = (*it).value;
15968 double maxValue = (*it).value;
15969 QVector<QCPData>::const_iterator minValueIt = it;
15970 QVector<QCPData>::const_iterator maxValueIt = it;
15971 QVector<QCPData>::const_iterator currentIntervalStart = it;
15972 int reversedFactor = keyAxis->rangeReversed() ? -1 : 1; // is used to calculate keyEpsilon pixel into the correct direction
15973 int reversedRound = keyAxis->rangeReversed() ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey
15974 double currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*lower).key)+reversedRound));
15975 double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates
15976 bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes)
15977 int intervalDataCount = 1;
15978 ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect
15979 while (it != upperEnd)
15980 {
15981 if ((*it).key < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this pixel if necessary
15982 {
15983 if ((*it).value < minValue && (*it).value > valueMinRange && (*it).value < valueMaxRange)
15984 {
15985 minValue = (*it).value;
15986 minValueIt = it;
15987 } else if ((*it).value > maxValue && (*it).value > valueMinRange && (*it).value < valueMaxRange)
15988 {
15989 maxValue = (*it).value;
15990 maxValueIt = it;
15991 }
15992 ++intervalDataCount;
15993 } else // new pixel started
15994 {
15995 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them
15996 {
15997 // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot):
15998 double valuePixelSpan = qAbs(valueAxis->coordToPixel(minValue)-valueAxis->coordToPixel(maxValue));
15999 int dataModulo = qMax(1, qRound(intervalDataCount/(valuePixelSpan/4.0))); // approximately every 4 value pixels one data point on average
16000 QVector<QCPData>::const_iterator intervalIt = currentIntervalStart;
16001 int c = 0;
16002 while (intervalIt != it)
16003 {
16004 if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && (*intervalIt).value > valueMinRange && (*intervalIt).value < valueMaxRange)
16005 scatterData->append((*intervalIt));
16006 ++c;
16007 ++intervalIt;
16008 }
16009 } else if ((*currentIntervalStart).value > valueMinRange && (*currentIntervalStart).value < valueMaxRange)
16010 scatterData->append((*currentIntervalStart));
16011 minValue = (*it).value;
16012 maxValue = (*it).value;
16013 currentIntervalStart = it;
16014 currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*it).key)+reversedRound));
16015 if (keyEpsilonVariable)
16016 keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor));
16017 intervalDataCount = 1;
16018 }
16019 ++it;
16020 }
16021 // handle last interval:
16022 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them
16023 {
16024 // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot):
16025 double valuePixelSpan = qAbs(valueAxis->coordToPixel(minValue)-valueAxis->coordToPixel(maxValue));
16026 int dataModulo = qMax(1, qRound(intervalDataCount/(valuePixelSpan/4.0))); // approximately every 4 value pixels one data point on average
16027 QVector<QCPData>::const_iterator intervalIt = currentIntervalStart;
16028 int c = 0;
16029 while (intervalIt != it)
16030 {
16031 if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && (*intervalIt).value > valueMinRange && (*intervalIt).value < valueMaxRange)
16032 scatterData->append((*intervalIt));
16033 ++c;
16034 ++intervalIt;
16035 }
16036 } else if ((*currentIntervalStart).value > valueMinRange && (*currentIntervalStart).value < valueMaxRange)
16037 scatterData->append(*currentIntervalStart);
16038 }
16039 } else // don't use adaptive sampling algorithm, transfer points one-to-one from the map into the output parameters
16040 {
16041 QVector<QCPData> *dataVector = 0;
16042 if (lineData)
16043 {
16044 dataVector = lineData;
16045 }
16046 else if (scatterData)
16047 dataVector = scatterData;
16048 if (dataVector)
16049 {
16050 QVector<QCPData>::const_iterator it = lower;
16051 QVector<QCPData>::const_iterator upperEnd = upper+1;
16052 dataVector->reserve(dataCount+2); // +2 for possible fill end points
16053 while (it != upperEnd)
16054 {
16055 dataVector->append(*it);
16056 ++it;
16057 }
16058 }
16059 if (lineData && scatterData)
16060 *scatterData = *dataVector;
15832 QVector<QCPData> *dataVector = 0;
15833 if (lineData)
15834 dataVector = lineData;
15835 else if (scatterData)
15836 dataVector = scatterData;
15837 if (dataVector)
15838 {
15839 QCPDataMap::const_iterator it = lower;
15840 QCPDataMap::const_iterator upperEnd = upper+1;
15841 dataVector->reserve(dataCount+2); // +2 for possible fill end points
15842 while (it != upperEnd)
15843 {
15844 dataVector->append(it.value());
15845 ++it;
15846 }
15847 }
15848 if (lineData && scatterData)
15849 *scatterData = *dataVector;
16061 15850 }
16062 15851 }
16063 15852
@@ -16070,97 +15859,97 void QCPGraph::getPreparedDataVector(QVe
16070 15859 */
16071 15860 void QCPGraph::drawError(QCPPainter *painter, double x, double y, const QCPData &data) const
16072 15861 {
16073 if (qIsNaN(data.value))
16074 return;
16075 QCPAxis *keyAxis = mKeyAxis.data();
16076 QCPAxis *valueAxis = mValueAxis.data();
16077 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
16078
16079 double a, b; // positions of error bar bounds in pixels
16080 double barWidthHalf = mErrorBarSize*0.5;
16081 double skipSymbolMargin = mScatterStyle.size(); // pixels left blank per side, when mErrorBarSkipSymbol is true
16082
16083 if (keyAxis->orientation() == Qt::Vertical)
16084 {
16085 // draw key error vertically and value error horizontally
16086 if (mErrorType == etKey || mErrorType == etBoth)
16087 {
16088 a = keyAxis->coordToPixel(data.key-data.keyErrorMinus);
16089 b = keyAxis->coordToPixel(data.key+data.keyErrorPlus);
16090 if (keyAxis->rangeReversed())
16091 qSwap(a,b);
16092 // draw spine:
16093 if (mErrorBarSkipSymbol)
16094 {
16095 if (a-y > skipSymbolMargin) // don't draw spine if error is so small it's within skipSymbolmargin
16096 painter->drawLine(QLineF(x, a, x, y+skipSymbolMargin));
16097 if (y-b > skipSymbolMargin)
16098 painter->drawLine(QLineF(x, y-skipSymbolMargin, x, b));
15862 if (qIsNaN(data.value))
15863 return;
15864 QCPAxis *keyAxis = mKeyAxis.data();
15865 QCPAxis *valueAxis = mValueAxis.data();
15866 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15867
15868 double a, b; // positions of error bar bounds in pixels
15869 double barWidthHalf = mErrorBarSize*0.5;
15870 double skipSymbolMargin = mScatterStyle.size(); // pixels left blank per side, when mErrorBarSkipSymbol is true
15871
15872 if (keyAxis->orientation() == Qt::Vertical)
15873 {
15874 // draw key error vertically and value error horizontally
15875 if (mErrorType == etKey || mErrorType == etBoth)
15876 {
15877 a = keyAxis->coordToPixel(data.key-data.keyErrorMinus);
15878 b = keyAxis->coordToPixel(data.key+data.keyErrorPlus);
15879 if (keyAxis->rangeReversed())
15880 qSwap(a,b);
15881 // draw spine:
15882 if (mErrorBarSkipSymbol)
15883 {
15884 if (a-y > skipSymbolMargin) // don't draw spine if error is so small it's within skipSymbolmargin
15885 painter->drawLine(QLineF(x, a, x, y+skipSymbolMargin));
15886 if (y-b > skipSymbolMargin)
15887 painter->drawLine(QLineF(x, y-skipSymbolMargin, x, b));
16099 15888 } else
16100 painter->drawLine(QLineF(x, a, x, b));
16101 // draw handles:
16102 painter->drawLine(QLineF(x-barWidthHalf, a, x+barWidthHalf, a));
16103 painter->drawLine(QLineF(x-barWidthHalf, b, x+barWidthHalf, b));
16104 }
16105 if (mErrorType == etValue || mErrorType == etBoth)
16106 {
16107 a = valueAxis->coordToPixel(data.value-data.valueErrorMinus);
16108 b = valueAxis->coordToPixel(data.value+data.valueErrorPlus);
16109 if (valueAxis->rangeReversed())
16110 qSwap(a,b);
16111 // draw spine:
16112 if (mErrorBarSkipSymbol)
16113 {
16114 if (x-a > skipSymbolMargin) // don't draw spine if error is so small it's within skipSymbolmargin
16115 painter->drawLine(QLineF(a, y, x-skipSymbolMargin, y));
16116 if (b-x > skipSymbolMargin)
16117 painter->drawLine(QLineF(x+skipSymbolMargin, y, b, y));
15889 painter->drawLine(QLineF(x, a, x, b));
15890 // draw handles:
15891 painter->drawLine(QLineF(x-barWidthHalf, a, x+barWidthHalf, a));
15892 painter->drawLine(QLineF(x-barWidthHalf, b, x+barWidthHalf, b));
15893 }
15894 if (mErrorType == etValue || mErrorType == etBoth)
15895 {
15896 a = valueAxis->coordToPixel(data.value-data.valueErrorMinus);
15897 b = valueAxis->coordToPixel(data.value+data.valueErrorPlus);
15898 if (valueAxis->rangeReversed())
15899 qSwap(a,b);
15900 // draw spine:
15901 if (mErrorBarSkipSymbol)
15902 {
15903 if (x-a > skipSymbolMargin) // don't draw spine if error is so small it's within skipSymbolmargin
15904 painter->drawLine(QLineF(a, y, x-skipSymbolMargin, y));
15905 if (b-x > skipSymbolMargin)
15906 painter->drawLine(QLineF(x+skipSymbolMargin, y, b, y));
16118 15907 } else
16119 painter->drawLine(QLineF(a, y, b, y));
16120 // draw handles:
16121 painter->drawLine(QLineF(a, y-barWidthHalf, a, y+barWidthHalf));
16122 painter->drawLine(QLineF(b, y-barWidthHalf, b, y+barWidthHalf));
15908 painter->drawLine(QLineF(a, y, b, y));
15909 // draw handles:
15910 painter->drawLine(QLineF(a, y-barWidthHalf, a, y+barWidthHalf));
15911 painter->drawLine(QLineF(b, y-barWidthHalf, b, y+barWidthHalf));
16123 15912 }
16124 15913 } else // mKeyAxis->orientation() is Qt::Horizontal
16125 15914 {
16126 // draw value error vertically and key error horizontally
16127 if (mErrorType == etKey || mErrorType == etBoth)
16128 {
16129 a = keyAxis->coordToPixel(data.key-data.keyErrorMinus);
16130 b = keyAxis->coordToPixel(data.key+data.keyErrorPlus);
16131 if (keyAxis->rangeReversed())
16132 qSwap(a,b);
16133 // draw spine:
16134 if (mErrorBarSkipSymbol)
16135 {
16136 if (x-a > skipSymbolMargin) // don't draw spine if error is so small it's within skipSymbolmargin
16137 painter->drawLine(QLineF(a, y, x-skipSymbolMargin, y));
16138 if (b-x > skipSymbolMargin)
16139 painter->drawLine(QLineF(x+skipSymbolMargin, y, b, y));
15915 // draw value error vertically and key error horizontally
15916 if (mErrorType == etKey || mErrorType == etBoth)
15917 {
15918 a = keyAxis->coordToPixel(data.key-data.keyErrorMinus);
15919 b = keyAxis->coordToPixel(data.key+data.keyErrorPlus);
15920 if (keyAxis->rangeReversed())
15921 qSwap(a,b);
15922 // draw spine:
15923 if (mErrorBarSkipSymbol)
15924 {
15925 if (x-a > skipSymbolMargin) // don't draw spine if error is so small it's within skipSymbolmargin
15926 painter->drawLine(QLineF(a, y, x-skipSymbolMargin, y));
15927 if (b-x > skipSymbolMargin)
15928 painter->drawLine(QLineF(x+skipSymbolMargin, y, b, y));
16140 15929 } else
16141 painter->drawLine(QLineF(a, y, b, y));
16142 // draw handles:
16143 painter->drawLine(QLineF(a, y-barWidthHalf, a, y+barWidthHalf));
16144 painter->drawLine(QLineF(b, y-barWidthHalf, b, y+barWidthHalf));
16145 }
16146 if (mErrorType == etValue || mErrorType == etBoth)
16147 {
16148 a = valueAxis->coordToPixel(data.value-data.valueErrorMinus);
16149 b = valueAxis->coordToPixel(data.value+data.valueErrorPlus);
16150 if (valueAxis->rangeReversed())
16151 qSwap(a,b);
16152 // draw spine:
16153 if (mErrorBarSkipSymbol)
16154 {
16155 if (a-y > skipSymbolMargin) // don't draw spine if error is so small it's within skipSymbolmargin
16156 painter->drawLine(QLineF(x, a, x, y+skipSymbolMargin));
16157 if (y-b > skipSymbolMargin)
16158 painter->drawLine(QLineF(x, y-skipSymbolMargin, x, b));
15930 painter->drawLine(QLineF(a, y, b, y));
15931 // draw handles:
15932 painter->drawLine(QLineF(a, y-barWidthHalf, a, y+barWidthHalf));
15933 painter->drawLine(QLineF(b, y-barWidthHalf, b, y+barWidthHalf));
15934 }
15935 if (mErrorType == etValue || mErrorType == etBoth)
15936 {
15937 a = valueAxis->coordToPixel(data.value-data.valueErrorMinus);
15938 b = valueAxis->coordToPixel(data.value+data.valueErrorPlus);
15939 if (valueAxis->rangeReversed())
15940 qSwap(a,b);
15941 // draw spine:
15942 if (mErrorBarSkipSymbol)
15943 {
15944 if (a-y > skipSymbolMargin) // don't draw spine if error is so small it's within skipSymbolmargin
15945 painter->drawLine(QLineF(x, a, x, y+skipSymbolMargin));
15946 if (y-b > skipSymbolMargin)
15947 painter->drawLine(QLineF(x, y-skipSymbolMargin, x, b));
16159 15948 } else
16160 painter->drawLine(QLineF(x, a, x, b));
16161 // draw handles:
16162 painter->drawLine(QLineF(x-barWidthHalf, a, x+barWidthHalf, a));
16163 painter->drawLine(QLineF(x-barWidthHalf, b, x+barWidthHalf, b));
15949 painter->drawLine(QLineF(x, a, x, b));
15950 // draw handles:
15951 painter->drawLine(QLineF(x-barWidthHalf, a, x+barWidthHalf, a));
15952 painter->drawLine(QLineF(x-barWidthHalf, b, x+barWidthHalf, b));
16164 15953 }
16165 15954 }
16166 15955 }
@@ -16181,93 +15970,22 void QCPGraph::drawError(QCPPainter *pai
16181 15970 */
16182 15971 void QCPGraph::getVisibleDataBounds(QCPDataMap::const_iterator &lower, QCPDataMap::const_iterator &upper) const
16183 15972 {
16184 if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
16185 if (mData->isEmpty())
16186 {
16187 lower = mData->constEnd();
16188 upper = mData->constEnd();
16189 return;
16190 }
16191
16192 // get visible data range as QMap iterators
16193 QCPDataMap::const_iterator lbound = mData->lowerBound(mKeyAxis.data()->range().lower);
16194 QCPDataMap::const_iterator ubound = mData->upperBound(mKeyAxis.data()->range().upper);
16195 bool lowoutlier = lbound != mData->constBegin(); // indicates whether there exist points below axis range
16196 bool highoutlier = ubound != mData->constEnd(); // indicates whether there exist points above axis range
16197
16198 lower = (lowoutlier ? lbound-1 : lbound); // data point range that will be actually drawn
16199 upper = (highoutlier ? ubound : ubound-1); // data point range that will be actually drawn
16200 }
16201
16202
16203
16204
16205 QVector<QCPData>::const_iterator __lowerBoundDico(QVector<QCPData>* vector,double key)
16206 {
16207 int DX=vector->size()/2;
16208 int pos=DX;
16209 double test=(*vector)[vector->length()-1].key;
16210 if(key>((*vector)[vector->length()-1].key))
16211 return vector->constEnd();
16212 if(key<((*vector)[0].key))
16213 return vector->constBegin();
16214 while (DX>1)
16215 {
16216 DX=DX/2;
16217 if((*vector)[pos].key > key)
16218 {
16219 pos-=DX;
16220 }
16221 else
16222 {
16223 pos+=DX;
16224 }
16225 }
16226 if((*vector)[pos].key >= key)
16227 return vector->constBegin()+pos;
16228 return vector->constBegin()+pos+1;
16229 }
16230
16231
16232 QVector<QCPData>::const_iterator __upperBoundDico(QVector<QCPData>* vector,double key)
16233 {
16234 int DX=vector->size()/2;
16235 int pos=DX;
16236 if(key>((*vector)[vector->length()-1].key))
16237 return vector->constEnd();
16238 if(key<((*vector)[0].key))
16239 return vector->constBegin();
16240 while (DX>1)
16241 {
16242 DX=DX/2;
16243 if((*vector)[pos].key > key)
16244 {
16245 pos-=DX;
16246 }
16247 else
16248 {
16249 pos+=DX;
16250 }
16251 }
16252 return vector->constBegin()+pos+1;
16253 }
16254
16255 void QCPGraph::getVisibleDataBoundsVector(QVector<QCPData>::const_iterator &lower, QVector<QCPData>::const_iterator &upper) const
16256 {
16257 if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
16258 if (mDataVector->isEmpty())
16259 {
16260 lower = mDataVector->constEnd();
16261 upper = mDataVector->constEnd();
16262 return;
16263 }
16264 QVector<QCPData>::const_iterator lbound = __lowerBoundDico(mDataVector,mKeyAxis.data()->range().lower);
16265 QVector<QCPData>::const_iterator ubound = __upperBoundDico(mDataVector,mKeyAxis.data()->range().upper);
16266 bool lowoutlier = lbound != mDataVector->constBegin(); // indicates whether there exist points below axis range
16267 bool highoutlier = ubound != mDataVector->constEnd(); // indicates whether there exist points above axis range
16268
16269 lower = (lowoutlier ? lbound-1 : lbound); // data point range that will be actually drawn
16270 upper = (highoutlier ? ubound : ubound-1); // data point range that will be actually drawn
15973 if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
15974 if (mData->isEmpty())
15975 {
15976 lower = mData->constEnd();
15977 upper = mData->constEnd();
15978 return;
15979 }
15980
15981 // get visible data range as QMap iterators
15982 QCPDataMap::const_iterator lbound = mData->lowerBound(mKeyAxis.data()->range().lower);
15983 QCPDataMap::const_iterator ubound = mData->upperBound(mKeyAxis.data()->range().upper);
15984 bool lowoutlier = lbound != mData->constBegin(); // indicates whether there exist points below axis range
15985 bool highoutlier = ubound != mData->constEnd(); // indicates whether there exist points above axis range
15986
15987 lower = (lowoutlier ? lbound-1 : lbound); // data point range that will be actually drawn
15988 upper = (highoutlier ? ubound : ubound-1); // data point range that will be actually drawn
16271 15989 }
16272 15990
16273 15991 /*! \internal
@@ -16282,30 +16000,16 void QCPGraph::getVisibleDataBoundsVecto
16282 16000 */
16283 16001 int QCPGraph::countDataInBounds(const QCPDataMap::const_iterator &lower, const QCPDataMap::const_iterator &upper, int maxCount) const
16284 16002 {
16285 if (upper == mData->constEnd() && lower == mData->constEnd())
16286 return 0;
16287 QCPDataMap::const_iterator it = lower;
16288 int count = 1;
16289 while (it != upper && count < maxCount)
16290 {
16291 ++it;
16292 ++count;
16293 }
16294 return count;
16295 }
16296
16297 int QCPGraph::countDataInBoundsVector(const QVector<QCPData>::const_iterator &lower, const QVector<QCPData>::const_iterator &upper, int maxCount) const
16298 {
16299 if (upper == mDataVector->constEnd() && lower == mDataVector->constEnd())
16300 return 0;
16301 QVector<QCPData>::const_iterator it = lower;
16302 int count = 1;
16303 while (it != upper && count < maxCount)
16304 {
16305 ++it;
16306 ++count;
16307 }
16308 return count;
16003 if (upper == mData->constEnd() && lower == mData->constEnd())
16004 return 0;
16005 QCPDataMap::const_iterator it = lower;
16006 int count = 1;
16007 while (it != upper && count < maxCount)
16008 {
16009 ++it;
16010 ++count;
16011 }
16012 return count;
16309 16013 }
16310 16014
16311 16015 /*! \internal
@@ -16325,17 +16029,17 int QCPGraph::countDataInBoundsVector(co
16325 16029 */
16326 16030 void QCPGraph::addFillBasePoints(QVector<QPointF> *lineData) const
16327 16031 {
16328 if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
16329
16330 // append points that close the polygon fill at the key axis:
16331 if (mKeyAxis.data()->orientation() == Qt::Vertical)
16332 {
16333 *lineData << upperFillBasePoint(lineData->last().y());
16334 *lineData << lowerFillBasePoint(lineData->first().y());
16335 } else
16336 {
16337 *lineData << upperFillBasePoint(lineData->last().x());
16338 *lineData << lowerFillBasePoint(lineData->first().x());
16032 if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
16033
16034 // append points that close the polygon fill at the key axis:
16035 if (mKeyAxis.data()->orientation() == Qt::Vertical)
16036 {
16037 *lineData << upperFillBasePoint(lineData->last().y());
16038 *lineData << lowerFillBasePoint(lineData->first().y());
16039 } else
16040 {
16041 *lineData << upperFillBasePoint(lineData->last().x());
16042 *lineData << lowerFillBasePoint(lineData->first().x());
16339 16043 }
16340 16044 }
16341 16045
@@ -16347,7 +16051,7 void QCPGraph::addFillBasePoints(QVector
16347 16051 */
16348 16052 void QCPGraph::removeFillBasePoints(QVector<QPointF> *lineData) const
16349 16053 {
16350 lineData->remove(lineData->size()-2, 2);
16054 lineData->remove(lineData->size()-2, 2);
16351 16055 }
16352 16056
16353 16057 /*! \internal
@@ -16366,53 +16070,53 void QCPGraph::removeFillBasePoints(QVec
16366 16070 */
16367 16071 QPointF QCPGraph::lowerFillBasePoint(double lowerKey) const
16368 16072 {
16369 QCPAxis *keyAxis = mKeyAxis.data();
16370 QCPAxis *valueAxis = mValueAxis.data();
16371 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return QPointF(); }
16372
16373 QPointF point;
16374 if (valueAxis->scaleType() == QCPAxis::stLinear)
16375 {
16376 if (keyAxis->axisType() == QCPAxis::atLeft)
16377 {
16378 point.setX(valueAxis->coordToPixel(0));
16379 point.setY(lowerKey);
16073 QCPAxis *keyAxis = mKeyAxis.data();
16074 QCPAxis *valueAxis = mValueAxis.data();
16075 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return QPointF(); }
16076
16077 QPointF point;
16078 if (valueAxis->scaleType() == QCPAxis::stLinear)
16079 {
16080 if (keyAxis->axisType() == QCPAxis::atLeft)
16081 {
16082 point.setX(valueAxis->coordToPixel(0));
16083 point.setY(lowerKey);
16380 16084 } else if (keyAxis->axisType() == QCPAxis::atRight)
16381 16085 {
16382 point.setX(valueAxis->coordToPixel(0));
16383 point.setY(lowerKey);
16086 point.setX(valueAxis->coordToPixel(0));
16087 point.setY(lowerKey);
16384 16088 } else if (keyAxis->axisType() == QCPAxis::atTop)
16385 16089 {
16386 point.setX(lowerKey);
16387 point.setY(valueAxis->coordToPixel(0));
16090 point.setX(lowerKey);
16091 point.setY(valueAxis->coordToPixel(0));
16388 16092 } else if (keyAxis->axisType() == QCPAxis::atBottom)
16389 16093 {
16390 point.setX(lowerKey);
16391 point.setY(valueAxis->coordToPixel(0));
16094 point.setX(lowerKey);
16095 point.setY(valueAxis->coordToPixel(0));
16392 16096 }
16393 16097 } else // valueAxis->mScaleType == QCPAxis::stLogarithmic
16394 16098 {
16395 // In logarithmic scaling we can't just draw to value zero so we just fill all the way
16396 // to the axis which is in the direction towards zero
16397 if (keyAxis->orientation() == Qt::Vertical)
16398 {
16399 if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed()) ||
16400 (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is negative, zero is on opposite side of key axis
16401 point.setX(keyAxis->axisRect()->right());
16402 else
16403 point.setX(keyAxis->axisRect()->left());
16404 point.setY(lowerKey);
16099 // In logarithmic scaling we can't just draw to value zero so we just fill all the way
16100 // to the axis which is in the direction towards zero
16101 if (keyAxis->orientation() == Qt::Vertical)
16102 {
16103 if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed()) ||
16104 (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is negative, zero is on opposite side of key axis
16105 point.setX(keyAxis->axisRect()->right());
16106 else
16107 point.setX(keyAxis->axisRect()->left());
16108 point.setY(lowerKey);
16405 16109 } else if (keyAxis->axisType() == QCPAxis::atTop || keyAxis->axisType() == QCPAxis::atBottom)
16406 16110 {
16407 point.setX(lowerKey);
16408 if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed()) ||
16409 (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is negative, zero is on opposite side of key axis
16410 point.setY(keyAxis->axisRect()->top());
16411 else
16412 point.setY(keyAxis->axisRect()->bottom());
16413 }
16414 }
16415 return point;
16111 point.setX(lowerKey);
16112 if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed()) ||
16113 (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is negative, zero is on opposite side of key axis
16114 point.setY(keyAxis->axisRect()->top());
16115 else
16116 point.setY(keyAxis->axisRect()->bottom());
16117 }
16118 }
16119 return point;
16416 16120 }
16417 16121
16418 16122 /*! \internal
@@ -16431,53 +16135,53 QPointF QCPGraph::lowerFillBasePoint(dou
16431 16135 */
16432 16136 QPointF QCPGraph::upperFillBasePoint(double upperKey) const
16433 16137 {
16434 QCPAxis *keyAxis = mKeyAxis.data();
16435 QCPAxis *valueAxis = mValueAxis.data();
16436 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return QPointF(); }
16437
16438 QPointF point;
16439 if (valueAxis->scaleType() == QCPAxis::stLinear)
16440 {
16441 if (keyAxis->axisType() == QCPAxis::atLeft)
16442 {
16443 point.setX(valueAxis->coordToPixel(0));
16444 point.setY(upperKey);
16138 QCPAxis *keyAxis = mKeyAxis.data();
16139 QCPAxis *valueAxis = mValueAxis.data();
16140 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return QPointF(); }
16141
16142 QPointF point;
16143 if (valueAxis->scaleType() == QCPAxis::stLinear)
16144 {
16145 if (keyAxis->axisType() == QCPAxis::atLeft)
16146 {
16147 point.setX(valueAxis->coordToPixel(0));
16148 point.setY(upperKey);
16445 16149 } else if (keyAxis->axisType() == QCPAxis::atRight)
16446 16150 {
16447 point.setX(valueAxis->coordToPixel(0));
16448 point.setY(upperKey);
16151 point.setX(valueAxis->coordToPixel(0));
16152 point.setY(upperKey);
16449 16153 } else if (keyAxis->axisType() == QCPAxis::atTop)
16450 16154 {
16451 point.setX(upperKey);
16452 point.setY(valueAxis->coordToPixel(0));
16155 point.setX(upperKey);
16156 point.setY(valueAxis->coordToPixel(0));
16453 16157 } else if (keyAxis->axisType() == QCPAxis::atBottom)
16454 16158 {
16455 point.setX(upperKey);
16456 point.setY(valueAxis->coordToPixel(0));
16159 point.setX(upperKey);
16160 point.setY(valueAxis->coordToPixel(0));
16457 16161 }
16458 16162 } else // valueAxis->mScaleType == QCPAxis::stLogarithmic
16459 16163 {
16460 // In logarithmic scaling we can't just draw to value 0 so we just fill all the way
16461 // to the axis which is in the direction towards 0
16462 if (keyAxis->orientation() == Qt::Vertical)
16463 {
16464 if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed()) ||
16465 (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is negative, zero is on opposite side of key axis
16466 point.setX(keyAxis->axisRect()->right());
16467 else
16468 point.setX(keyAxis->axisRect()->left());
16469 point.setY(upperKey);
16164 // In logarithmic scaling we can't just draw to value 0 so we just fill all the way
16165 // to the axis which is in the direction towards 0
16166 if (keyAxis->orientation() == Qt::Vertical)
16167 {
16168 if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed()) ||
16169 (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is negative, zero is on opposite side of key axis
16170 point.setX(keyAxis->axisRect()->right());
16171 else
16172 point.setX(keyAxis->axisRect()->left());
16173 point.setY(upperKey);
16470 16174 } else if (keyAxis->axisType() == QCPAxis::atTop || keyAxis->axisType() == QCPAxis::atBottom)
16471 16175 {
16472 point.setX(upperKey);
16473 if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed()) ||
16474 (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is negative, zero is on opposite side of key axis
16475 point.setY(keyAxis->axisRect()->top());
16476 else
16477 point.setY(keyAxis->axisRect()->bottom());
16478 }
16479 }
16480 return point;
16176 point.setX(upperKey);
16177 if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed()) ||
16178 (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is negative, zero is on opposite side of key axis
16179 point.setY(keyAxis->axisRect()->top());
16180 else
16181 point.setY(keyAxis->axisRect()->bottom());
16182 }
16183 }
16184 return point;
16481 16185 }
16482 16186
16483 16187 /*! \internal
@@ -16491,137 +16195,137 QPointF QCPGraph::upperFillBasePoint(dou
16491 16195 */
16492 16196 const QPolygonF QCPGraph::getChannelFillPolygon(const QVector<QPointF> *lineData) const
16493 16197 {
16494 if (!mChannelFillGraph)
16495 return QPolygonF();
16496
16497 QCPAxis *keyAxis = mKeyAxis.data();
16498 QCPAxis *valueAxis = mValueAxis.data();
16499 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return QPolygonF(); }
16500 if (!mChannelFillGraph.data()->mKeyAxis) { qDebug() << Q_FUNC_INFO << "channel fill target key axis invalid"; return QPolygonF(); }
16501
16502 if (mChannelFillGraph.data()->mKeyAxis.data()->orientation() != keyAxis->orientation())
16503 return QPolygonF(); // don't have same axis orientation, can't fill that (Note: if keyAxis fits, valueAxis will fit too, because it's always orthogonal to keyAxis)
16504
16505 if (lineData->isEmpty()) return QPolygonF();
16506 QVector<QPointF> otherData;
16507 mChannelFillGraph.data()->getPlotData(&otherData, 0);
16508 if (otherData.isEmpty()) return QPolygonF();
16509 QVector<QPointF> thisData;
16510 thisData.reserve(lineData->size()+otherData.size()); // because we will join both vectors at end of this function
16511 for (int i=0; i<lineData->size(); ++i) // don't use the vector<<(vector), it squeezes internally, which ruins the performance tuning with reserve()
16512 thisData << lineData->at(i);
16513
16514 // pointers to be able to swap them, depending which data range needs cropping:
16515 QVector<QPointF> *staticData = &thisData;
16516 QVector<QPointF> *croppedData = &otherData;
16517
16518 // crop both vectors to ranges in which the keys overlap (which coord is key, depends on axisType):
16519 if (keyAxis->orientation() == Qt::Horizontal)
16520 {
16521 // x is key
16522 // if an axis range is reversed, the data point keys will be descending. Reverse them, since following algorithm assumes ascending keys:
16523 if (staticData->first().x() > staticData->last().x())
16524 {
16525 int size = staticData->size();
16526 for (int i=0; i<size/2; ++i)
16527 qSwap((*staticData)[i], (*staticData)[size-1-i]);
16528 }
16529 if (croppedData->first().x() > croppedData->last().x())
16530 {
16531 int size = croppedData->size();
16532 for (int i=0; i<size/2; ++i)
16533 qSwap((*croppedData)[i], (*croppedData)[size-1-i]);
16534 }
16535 // crop lower bound:
16536 if (staticData->first().x() < croppedData->first().x()) // other one must be cropped
16537 qSwap(staticData, croppedData);
16538 int lowBound = findIndexBelowX(croppedData, staticData->first().x());
16539 if (lowBound == -1) return QPolygonF(); // key ranges have no overlap
16540 croppedData->remove(0, lowBound);
16541 // set lowest point of cropped data to fit exactly key position of first static data
16542 // point via linear interpolation:
16543 if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation
16544 double slope;
16545 if (croppedData->at(1).x()-croppedData->at(0).x() != 0)
16546 slope = (croppedData->at(1).y()-croppedData->at(0).y())/(croppedData->at(1).x()-croppedData->at(0).x());
16547 else
16548 slope = 0;
16549 (*croppedData)[0].setY(croppedData->at(0).y()+slope*(staticData->first().x()-croppedData->at(0).x()));
16550 (*croppedData)[0].setX(staticData->first().x());
16551
16552 // crop upper bound:
16553 if (staticData->last().x() > croppedData->last().x()) // other one must be cropped
16554 qSwap(staticData, croppedData);
16555 int highBound = findIndexAboveX(croppedData, staticData->last().x());
16556 if (highBound == -1) return QPolygonF(); // key ranges have no overlap
16557 croppedData->remove(highBound+1, croppedData->size()-(highBound+1));
16558 // set highest point of cropped data to fit exactly key position of last static data
16559 // point via linear interpolation:
16560 if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation
16561 int li = croppedData->size()-1; // last index
16562 if (croppedData->at(li).x()-croppedData->at(li-1).x() != 0)
16563 slope = (croppedData->at(li).y()-croppedData->at(li-1).y())/(croppedData->at(li).x()-croppedData->at(li-1).x());
16564 else
16565 slope = 0;
16566 (*croppedData)[li].setY(croppedData->at(li-1).y()+slope*(staticData->last().x()-croppedData->at(li-1).x()));
16567 (*croppedData)[li].setX(staticData->last().x());
16198 if (!mChannelFillGraph)
16199 return QPolygonF();
16200
16201 QCPAxis *keyAxis = mKeyAxis.data();
16202 QCPAxis *valueAxis = mValueAxis.data();
16203 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return QPolygonF(); }
16204 if (!mChannelFillGraph.data()->mKeyAxis) { qDebug() << Q_FUNC_INFO << "channel fill target key axis invalid"; return QPolygonF(); }
16205
16206 if (mChannelFillGraph.data()->mKeyAxis.data()->orientation() != keyAxis->orientation())
16207 return QPolygonF(); // don't have same axis orientation, can't fill that (Note: if keyAxis fits, valueAxis will fit too, because it's always orthogonal to keyAxis)
16208
16209 if (lineData->isEmpty()) return QPolygonF();
16210 QVector<QPointF> otherData;
16211 mChannelFillGraph.data()->getPlotData(&otherData, 0);
16212 if (otherData.isEmpty()) return QPolygonF();
16213 QVector<QPointF> thisData;
16214 thisData.reserve(lineData->size()+otherData.size()); // because we will join both vectors at end of this function
16215 for (int i=0; i<lineData->size(); ++i) // don't use the vector<<(vector), it squeezes internally, which ruins the performance tuning with reserve()
16216 thisData << lineData->at(i);
16217
16218 // pointers to be able to swap them, depending which data range needs cropping:
16219 QVector<QPointF> *staticData = &thisData;
16220 QVector<QPointF> *croppedData = &otherData;
16221
16222 // crop both vectors to ranges in which the keys overlap (which coord is key, depends on axisType):
16223 if (keyAxis->orientation() == Qt::Horizontal)
16224 {
16225 // x is key
16226 // if an axis range is reversed, the data point keys will be descending. Reverse them, since following algorithm assumes ascending keys:
16227 if (staticData->first().x() > staticData->last().x())
16228 {
16229 int size = staticData->size();
16230 for (int i=0; i<size/2; ++i)
16231 qSwap((*staticData)[i], (*staticData)[size-1-i]);
16232 }
16233 if (croppedData->first().x() > croppedData->last().x())
16234 {
16235 int size = croppedData->size();
16236 for (int i=0; i<size/2; ++i)
16237 qSwap((*croppedData)[i], (*croppedData)[size-1-i]);
16238 }
16239 // crop lower bound:
16240 if (staticData->first().x() < croppedData->first().x()) // other one must be cropped
16241 qSwap(staticData, croppedData);
16242 int lowBound = findIndexBelowX(croppedData, staticData->first().x());
16243 if (lowBound == -1) return QPolygonF(); // key ranges have no overlap
16244 croppedData->remove(0, lowBound);
16245 // set lowest point of cropped data to fit exactly key position of first static data
16246 // point via linear interpolation:
16247 if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation
16248 double slope;
16249 if (croppedData->at(1).x()-croppedData->at(0).x() != 0)
16250 slope = (croppedData->at(1).y()-croppedData->at(0).y())/(croppedData->at(1).x()-croppedData->at(0).x());
16251 else
16252 slope = 0;
16253 (*croppedData)[0].setY(croppedData->at(0).y()+slope*(staticData->first().x()-croppedData->at(0).x()));
16254 (*croppedData)[0].setX(staticData->first().x());
16255
16256 // crop upper bound:
16257 if (staticData->last().x() > croppedData->last().x()) // other one must be cropped
16258 qSwap(staticData, croppedData);
16259 int highBound = findIndexAboveX(croppedData, staticData->last().x());
16260 if (highBound == -1) return QPolygonF(); // key ranges have no overlap
16261 croppedData->remove(highBound+1, croppedData->size()-(highBound+1));
16262 // set highest point of cropped data to fit exactly key position of last static data
16263 // point via linear interpolation:
16264 if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation
16265 int li = croppedData->size()-1; // last index
16266 if (croppedData->at(li).x()-croppedData->at(li-1).x() != 0)
16267 slope = (croppedData->at(li).y()-croppedData->at(li-1).y())/(croppedData->at(li).x()-croppedData->at(li-1).x());
16268 else
16269 slope = 0;
16270 (*croppedData)[li].setY(croppedData->at(li-1).y()+slope*(staticData->last().x()-croppedData->at(li-1).x()));
16271 (*croppedData)[li].setX(staticData->last().x());
16568 16272 } else // mKeyAxis->orientation() == Qt::Vertical
16569 16273 {
16570 // y is key
16571 // similar to "x is key" but switched x,y. Further, lower/upper meaning is inverted compared to x,
16572 // because in pixel coordinates, y increases from top to bottom, not bottom to top like data coordinate.
16573 // if an axis range is reversed, the data point keys will be descending. Reverse them, since following algorithm assumes ascending keys:
16574 if (staticData->first().y() < staticData->last().y())
16575 {
16576 int size = staticData->size();
16577 for (int i=0; i<size/2; ++i)
16578 qSwap((*staticData)[i], (*staticData)[size-1-i]);
16579 }
16580 if (croppedData->first().y() < croppedData->last().y())
16581 {
16582 int size = croppedData->size();
16583 for (int i=0; i<size/2; ++i)
16584 qSwap((*croppedData)[i], (*croppedData)[size-1-i]);
16585 }
16586 // crop lower bound:
16587 if (staticData->first().y() > croppedData->first().y()) // other one must be cropped
16588 qSwap(staticData, croppedData);
16589 int lowBound = findIndexAboveY(croppedData, staticData->first().y());
16590 if (lowBound == -1) return QPolygonF(); // key ranges have no overlap
16591 croppedData->remove(0, lowBound);
16592 // set lowest point of cropped data to fit exactly key position of first static data
16593 // point via linear interpolation:
16594 if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation
16595 double slope;
16596 if (croppedData->at(1).y()-croppedData->at(0).y() != 0) // avoid division by zero in step plots
16597 slope = (croppedData->at(1).x()-croppedData->at(0).x())/(croppedData->at(1).y()-croppedData->at(0).y());
16598 else
16599 slope = 0;
16600 (*croppedData)[0].setX(croppedData->at(0).x()+slope*(staticData->first().y()-croppedData->at(0).y()));
16601 (*croppedData)[0].setY(staticData->first().y());
16602
16603 // crop upper bound:
16604 if (staticData->last().y() < croppedData->last().y()) // other one must be cropped
16605 qSwap(staticData, croppedData);
16606 int highBound = findIndexBelowY(croppedData, staticData->last().y());
16607 if (highBound == -1) return QPolygonF(); // key ranges have no overlap
16608 croppedData->remove(highBound+1, croppedData->size()-(highBound+1));
16609 // set highest point of cropped data to fit exactly key position of last static data
16610 // point via linear interpolation:
16611 if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation
16612 int li = croppedData->size()-1; // last index
16613 if (croppedData->at(li).y()-croppedData->at(li-1).y() != 0) // avoid division by zero in step plots
16614 slope = (croppedData->at(li).x()-croppedData->at(li-1).x())/(croppedData->at(li).y()-croppedData->at(li-1).y());
16615 else
16616 slope = 0;
16617 (*croppedData)[li].setX(croppedData->at(li-1).x()+slope*(staticData->last().y()-croppedData->at(li-1).y()));
16618 (*croppedData)[li].setY(staticData->last().y());
16619 }
16620
16621 // return joined:
16622 for (int i=otherData.size()-1; i>=0; --i) // insert reversed, otherwise the polygon will be twisted
16623 thisData << otherData.at(i);
16624 return QPolygonF(thisData);
16274 // y is key
16275 // similar to "x is key" but switched x,y. Further, lower/upper meaning is inverted compared to x,
16276 // because in pixel coordinates, y increases from top to bottom, not bottom to top like data coordinate.
16277 // if an axis range is reversed, the data point keys will be descending. Reverse them, since following algorithm assumes ascending keys:
16278 if (staticData->first().y() < staticData->last().y())
16279 {
16280 int size = staticData->size();
16281 for (int i=0; i<size/2; ++i)
16282 qSwap((*staticData)[i], (*staticData)[size-1-i]);
16283 }
16284 if (croppedData->first().y() < croppedData->last().y())
16285 {
16286 int size = croppedData->size();
16287 for (int i=0; i<size/2; ++i)
16288 qSwap((*croppedData)[i], (*croppedData)[size-1-i]);
16289 }
16290 // crop lower bound:
16291 if (staticData->first().y() > croppedData->first().y()) // other one must be cropped
16292 qSwap(staticData, croppedData);
16293 int lowBound = findIndexAboveY(croppedData, staticData->first().y());
16294 if (lowBound == -1) return QPolygonF(); // key ranges have no overlap
16295 croppedData->remove(0, lowBound);
16296 // set lowest point of cropped data to fit exactly key position of first static data
16297 // point via linear interpolation:
16298 if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation
16299 double slope;
16300 if (croppedData->at(1).y()-croppedData->at(0).y() != 0) // avoid division by zero in step plots
16301 slope = (croppedData->at(1).x()-croppedData->at(0).x())/(croppedData->at(1).y()-croppedData->at(0).y());
16302 else
16303 slope = 0;
16304 (*croppedData)[0].setX(croppedData->at(0).x()+slope*(staticData->first().y()-croppedData->at(0).y()));
16305 (*croppedData)[0].setY(staticData->first().y());
16306
16307 // crop upper bound:
16308 if (staticData->last().y() < croppedData->last().y()) // other one must be cropped
16309 qSwap(staticData, croppedData);
16310 int highBound = findIndexBelowY(croppedData, staticData->last().y());
16311 if (highBound == -1) return QPolygonF(); // key ranges have no overlap
16312 croppedData->remove(highBound+1, croppedData->size()-(highBound+1));
16313 // set highest point of cropped data to fit exactly key position of last static data
16314 // point via linear interpolation:
16315 if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation
16316 int li = croppedData->size()-1; // last index
16317 if (croppedData->at(li).y()-croppedData->at(li-1).y() != 0) // avoid division by zero in step plots
16318 slope = (croppedData->at(li).x()-croppedData->at(li-1).x())/(croppedData->at(li).y()-croppedData->at(li-1).y());
16319 else
16320 slope = 0;
16321 (*croppedData)[li].setX(croppedData->at(li-1).x()+slope*(staticData->last().y()-croppedData->at(li-1).y()));
16322 (*croppedData)[li].setY(staticData->last().y());
16323 }
16324
16325 // return joined:
16326 for (int i=otherData.size()-1; i>=0; --i) // insert reversed, otherwise the polygon will be twisted
16327 thisData << otherData.at(i);
16328 return QPolygonF(thisData);
16625 16329 }
16626 16330
16627 16331 /*! \internal
@@ -16633,17 +16337,17 const QPolygonF QCPGraph::getChannelFill
16633 16337 */
16634 16338 int QCPGraph::findIndexAboveX(const QVector<QPointF> *data, double x) const
16635 16339 {
16636 for (int i=data->size()-1; i>=0; --i)
16637 {
16638 if (data->at(i).x() < x)
16639 {
16640 if (i<data->size()-1)
16641 return i+1;
16642 else
16643 return data->size()-1;
16644 }
16645 }
16646 return -1;
16340 for (int i=data->size()-1; i>=0; --i)
16341 {
16342 if (data->at(i).x() < x)
16343 {
16344 if (i<data->size()-1)
16345 return i+1;
16346 else
16347 return data->size()-1;
16348 }
16349 }
16350 return -1;
16647 16351 }
16648 16352
16649 16353 /*! \internal
@@ -16655,17 +16359,17 int QCPGraph::findIndexAboveX(const QVec
16655 16359 */
16656 16360 int QCPGraph::findIndexBelowX(const QVector<QPointF> *data, double x) const
16657 16361 {
16658 for (int i=0; i<data->size(); ++i)
16659 {
16660 if (data->at(i).x() > x)
16661 {
16662 if (i>0)
16663 return i-1;
16664 else
16665 return 0;
16666 }
16667 }
16668 return -1;
16362 for (int i=0; i<data->size(); ++i)
16363 {
16364 if (data->at(i).x() > x)
16365 {
16366 if (i>0)
16367 return i-1;
16368 else
16369 return 0;
16370 }
16371 }
16372 return -1;
16669 16373 }
16670 16374
16671 16375 /*! \internal
@@ -16677,17 +16381,17 int QCPGraph::findIndexBelowX(const QVec
16677 16381 */
16678 16382 int QCPGraph::findIndexAboveY(const QVector<QPointF> *data, double y) const
16679 16383 {
16680 for (int i=0; i<data->size(); ++i)
16681 {
16682 if (data->at(i).y() < y)
16683 {
16684 if (i>0)
16685 return i-1;
16686 else
16687 return 0;
16688 }
16689 }
16690 return -1;
16384 for (int i=0; i<data->size(); ++i)
16385 {
16386 if (data->at(i).y() < y)
16387 {
16388 if (i>0)
16389 return i-1;
16390 else
16391 return 0;
16392 }
16393 }
16394 return -1;
16691 16395 }
16692 16396
16693 16397 /*! \internal
@@ -16702,66 +16406,66 int QCPGraph::findIndexAboveY(const QVec
16702 16406 */
16703 16407 double QCPGraph::pointDistance(const QPointF &pixelPoint) const
16704 16408 {
16705 if (mData->isEmpty())
16706 {
16707 qDebug() << Q_FUNC_INFO << "requested point distance on graph" << mName << "without data";
16708 return 500;
16709 }
16710 if (mData->size() == 1)
16711 {
16712 QPointF dataPoint = coordsToPixels(mData->constBegin().key(), mData->constBegin().value().value);
16713 return QVector2D(dataPoint-pixelPoint).length();
16714 }
16715
16716 if (mLineStyle == lsNone && mScatterStyle.isNone())
16717 return 500;
16718
16719 // calculate minimum distances to graph representation:
16720 if (mLineStyle == lsNone)
16721 {
16722 // no line displayed, only calculate distance to scatter points:
16723 QVector<QCPData> *scatterData = new QVector<QCPData>;
16724 getScatterPlotData(scatterData);
16725 double minDistSqr = std::numeric_limits<double>::max();
16726 QPointF ptA;
16727 QPointF ptB = coordsToPixels(scatterData->at(0).key, scatterData->at(0).value); // getScatterPlotData returns in plot coordinates, so transform to pixels
16728 for (int i=1; i<scatterData->size(); ++i)
16729 {
16730 ptA = ptB;
16731 ptB = coordsToPixels(scatterData->at(i).key, scatterData->at(i).value);
16732 double currentDistSqr = distSqrToLine(ptA, ptB, pixelPoint);
16733 if (currentDistSqr < minDistSqr)
16734 minDistSqr = currentDistSqr;
16735 }
16736 delete scatterData;
16737 return qSqrt(minDistSqr);
16738 } else
16739 {
16740 // line displayed calculate distance to line segments:
16741 QVector<QPointF> *lineData = new QVector<QPointF>;
16742 getPlotData(lineData, 0); // unlike with getScatterPlotData we get pixel coordinates here
16743 double minDistSqr = std::numeric_limits<double>::max();
16744 if (mLineStyle == lsImpulse)
16745 {
16746 // impulse plot differs from other line styles in that the lineData points are only pairwise connected:
16747 for (int i=0; i<lineData->size()-1; i+=2) // iterate pairs
16748 {
16749 double currentDistSqr = distSqrToLine(lineData->at(i), lineData->at(i+1), pixelPoint);
16750 if (currentDistSqr < minDistSqr)
16409 if (mData->isEmpty())
16410 {
16411 qDebug() << Q_FUNC_INFO << "requested point distance on graph" << mName << "without data";
16412 return 500;
16413 }
16414 if (mData->size() == 1)
16415 {
16416 QPointF dataPoint = coordsToPixels(mData->constBegin().key(), mData->constBegin().value().value);
16417 return QVector2D(dataPoint-pixelPoint).length();
16418 }
16419
16420 if (mLineStyle == lsNone && mScatterStyle.isNone())
16421 return 500;
16422
16423 // calculate minimum distances to graph representation:
16424 if (mLineStyle == lsNone)
16425 {
16426 // no line displayed, only calculate distance to scatter points:
16427 QVector<QCPData> *scatterData = new QVector<QCPData>;
16428 getScatterPlotData(scatterData);
16429 double minDistSqr = std::numeric_limits<double>::max();
16430 QPointF ptA;
16431 QPointF ptB = coordsToPixels(scatterData->at(0).key, scatterData->at(0).value); // getScatterPlotData returns in plot coordinates, so transform to pixels
16432 for (int i=1; i<scatterData->size(); ++i)
16433 {
16434 ptA = ptB;
16435 ptB = coordsToPixels(scatterData->at(i).key, scatterData->at(i).value);
16436 double currentDistSqr = distSqrToLine(ptA, ptB, pixelPoint);
16437 if (currentDistSqr < minDistSqr)
16751 16438 minDistSqr = currentDistSqr;
16439 }
16440 delete scatterData;
16441 return qSqrt(minDistSqr);
16442 } else
16443 {
16444 // line displayed calculate distance to line segments:
16445 QVector<QPointF> *lineData = new QVector<QPointF>;
16446 getPlotData(lineData, 0); // unlike with getScatterPlotData we get pixel coordinates here
16447 double minDistSqr = std::numeric_limits<double>::max();
16448 if (mLineStyle == lsImpulse)
16449 {
16450 // impulse plot differs from other line styles in that the lineData points are only pairwise connected:
16451 for (int i=0; i<lineData->size()-1; i+=2) // iterate pairs
16452 {
16453 double currentDistSqr = distSqrToLine(lineData->at(i), lineData->at(i+1), pixelPoint);
16454 if (currentDistSqr < minDistSqr)
16455 minDistSqr = currentDistSqr;
16752 16456 }
16753 16457 } else
16754 16458 {
16755 // all other line plots (line and step) connect points directly:
16756 for (int i=0; i<lineData->size()-1; ++i)
16757 {
16758 double currentDistSqr = distSqrToLine(lineData->at(i), lineData->at(i+1), pixelPoint);
16759 if (currentDistSqr < minDistSqr)
16760 minDistSqr = currentDistSqr;
16761 }
16762 }
16763 delete lineData;
16764 return qSqrt(minDistSqr);
16459 // all other line plots (line and step) connect points directly:
16460 for (int i=0; i<lineData->size()-1; ++i)
16461 {
16462 double currentDistSqr = distSqrToLine(lineData->at(i), lineData->at(i+1), pixelPoint);
16463 if (currentDistSqr < minDistSqr)
16464 minDistSqr = currentDistSqr;
16465 }
16466 }
16467 delete lineData;
16468 return qSqrt(minDistSqr);
16765 16469 }
16766 16470 }
16767 16471
@@ -16775,37 +16479,33 double QCPGraph::pointDistance(const QPo
16775 16479 */
16776 16480 int QCPGraph::findIndexBelowY(const QVector<QPointF> *data, double y) const
16777 16481 {
16778 for (int i=data->size()-1; i>=0; --i)
16779 {
16780 if (data->at(i).y() > y)
16781 {
16782 if (i<data->size()-1)
16783 return i+1;
16784 else
16785 return data->size()-1;
16786 }
16787 }
16788 return -1;
16482 for (int i=data->size()-1; i>=0; --i)
16483 {
16484 if (data->at(i).y() > y)
16485 {
16486 if (i<data->size()-1)
16487 return i+1;
16488 else
16489 return data->size()-1;
16490 }
16491 }
16492 return -1;
16789 16493 }
16790 16494
16791 16495 /* inherits documentation from base class */
16792 16496 QCPRange QCPGraph::getKeyRange(bool &foundRange, SignDomain inSignDomain) const
16793 16497 {
16794 // just call the specialized version which takes an additional argument whether error bars
16795 // should also be taken into consideration for range calculation. We set this to true here.
16796 if(mUseFastVectors)
16797 return getKeyRangeVector(foundRange, inSignDomain, true);
16798 return getKeyRange(foundRange, inSignDomain, true);
16498 // just call the specialized version which takes an additional argument whether error bars
16499 // should also be taken into consideration for range calculation. We set this to true here.
16500 return getKeyRange(foundRange, inSignDomain, true);
16799 16501 }
16800 16502
16801 16503 /* inherits documentation from base class */
16802 16504 QCPRange QCPGraph::getValueRange(bool &foundRange, SignDomain inSignDomain) const
16803 16505 {
16804 // just call the specialized version which takes an additional argument whether error bars
16805 // should also be taken into consideration for range calculation. We set this to true here.
16806 if(mUseFastVectors)
16807 return getValueRangeVector(foundRange, inSignDomain, true);
16808 return getValueRange(foundRange, inSignDomain, true);
16506 // just call the specialized version which takes an additional argument whether error bars
16507 // should also be taken into consideration for range calculation. We set this to true here.
16508 return getValueRange(foundRange, inSignDomain, true);
16809 16509 }
16810 16510
16811 16511 /*! \overload
@@ -16816,202 +16516,102 QCPRange QCPGraph::getValueRange(bool &f
16816 16516 */
16817 16517 QCPRange QCPGraph::getKeyRange(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const
16818 16518 {
16819 QCPRange range;
16820 bool haveLower = false;
16821 bool haveUpper = false;
16822
16823 double current, currentErrorMinus, currentErrorPlus;
16824
16825 if (inSignDomain == sdBoth) // range may be anywhere
16826 {
16827 QCPDataMap::const_iterator it = mData->constBegin();
16828 while (it != mData->constEnd())
16829 {
16830 current = it.value().key;
16831 currentErrorMinus = (includeErrors ? it.value().keyErrorMinus : 0);
16832 currentErrorPlus = (includeErrors ? it.value().keyErrorPlus : 0);
16833 if (current-currentErrorMinus < range.lower || !haveLower)
16834 {
16835 range.lower = current-currentErrorMinus;
16836 haveLower = true;
16837 }
16838 if (current+currentErrorPlus > range.upper || !haveUpper)
16839 {
16840 range.upper = current+currentErrorPlus;
16841 haveUpper = true;
16842 }
16843 ++it;
16519 QCPRange range;
16520 bool haveLower = false;
16521 bool haveUpper = false;
16522
16523 double current, currentErrorMinus, currentErrorPlus;
16524
16525 if (inSignDomain == sdBoth) // range may be anywhere
16526 {
16527 QCPDataMap::const_iterator it = mData->constBegin();
16528 while (it != mData->constEnd())
16529 {
16530 current = it.value().key;
16531 currentErrorMinus = (includeErrors ? it.value().keyErrorMinus : 0);
16532 currentErrorPlus = (includeErrors ? it.value().keyErrorPlus : 0);
16533 if (current-currentErrorMinus < range.lower || !haveLower)
16534 {
16535 range.lower = current-currentErrorMinus;
16536 haveLower = true;
16537 }
16538 if (current+currentErrorPlus > range.upper || !haveUpper)
16539 {
16540 range.upper = current+currentErrorPlus;
16541 haveUpper = true;
16542 }
16543 ++it;
16844 16544 }
16845 16545 } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain
16846 16546 {
16847 QCPDataMap::const_iterator it = mData->constBegin();
16848 while (it != mData->constEnd())
16849 {
16850 current = it.value().key;
16851 currentErrorMinus = (includeErrors ? it.value().keyErrorMinus : 0);
16852 currentErrorPlus = (includeErrors ? it.value().keyErrorPlus : 0);
16853 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0)
16854 {
16855 range.lower = current-currentErrorMinus;
16856 haveLower = true;
16857 }
16858 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0)
16859 {
16860 range.upper = current+currentErrorPlus;
16861 haveUpper = true;
16862 }
16863 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point.
16864 {
16865 if ((current < range.lower || !haveLower) && current < 0)
16547 QCPDataMap::const_iterator it = mData->constBegin();
16548 while (it != mData->constEnd())
16549 {
16550 current = it.value().key;
16551 currentErrorMinus = (includeErrors ? it.value().keyErrorMinus : 0);
16552 currentErrorPlus = (includeErrors ? it.value().keyErrorPlus : 0);
16553 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0)
16554 {
16555 range.lower = current-currentErrorMinus;
16556 haveLower = true;
16557 }
16558 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0)
16559 {
16560 range.upper = current+currentErrorPlus;
16561 haveUpper = true;
16562 }
16563 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point.
16564 {
16565 if ((current < range.lower || !haveLower) && current < 0)
16866 16566 {
16867 range.lower = current;
16868 haveLower = true;
16567 range.lower = current;
16568 haveLower = true;
16869 16569 }
16870 if ((current > range.upper || !haveUpper) && current < 0)
16570 if ((current > range.upper || !haveUpper) && current < 0)
16871 16571 {
16872 range.upper = current;
16873 haveUpper = true;
16572 range.upper = current;
16573 haveUpper = true;
16874 16574 }
16875 16575 }
16876 ++it;
16576 ++it;
16877 16577 }
16878 16578 } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain
16879 16579 {
16880 QCPDataMap::const_iterator it = mData->constBegin();
16881 while (it != mData->constEnd())
16882 {
16883 current = it.value().key;
16884 currentErrorMinus = (includeErrors ? it.value().keyErrorMinus : 0);
16885 currentErrorPlus = (includeErrors ? it.value().keyErrorPlus : 0);
16886 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0)
16887 {
16888 range.lower = current-currentErrorMinus;
16889 haveLower = true;
16890 }
16891 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0)
16892 {
16893 range.upper = current+currentErrorPlus;
16894 haveUpper = true;
16895 }
16896 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point.
16897 {
16898 if ((current < range.lower || !haveLower) && current > 0)
16580 QCPDataMap::const_iterator it = mData->constBegin();
16581 while (it != mData->constEnd())
16582 {
16583 current = it.value().key;
16584 currentErrorMinus = (includeErrors ? it.value().keyErrorMinus : 0);
16585 currentErrorPlus = (includeErrors ? it.value().keyErrorPlus : 0);
16586 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0)
16587 {
16588 range.lower = current-currentErrorMinus;
16589 haveLower = true;
16590 }
16591 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0)
16592 {
16593 range.upper = current+currentErrorPlus;
16594 haveUpper = true;
16595 }
16596 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point.
16597 {
16598 if ((current < range.lower || !haveLower) && current > 0)
16899 16599 {
16900 range.lower = current;
16901 haveLower = true;
16902 }
16903 if ((current > range.upper || !haveUpper) && current > 0)
16904 {
16905 range.upper = current;
16906 haveUpper = true;
16600 range.lower = current;
16601 haveLower = true;
16907 16602 }
16908 }
16909 ++it;
16910 }
16911 }
16912
16913 foundRange = haveLower && haveUpper;
16914 return range;
16915 }
16916
16917 QCPRange QCPGraph::getKeyRangeVector(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const
16918 {
16919 QCPRange range;
16920 bool haveLower = false;
16921 bool haveUpper = false;
16922
16923 double current, currentErrorMinus, currentErrorPlus;
16924
16925 if (inSignDomain == sdBoth) // range may be anywhere
16926 {
16927 QVector<QCPData>::const_iterator it = mDataVector->constBegin();
16928 while (it != mDataVector->constEnd())
16929 {
16930 current = (*it).key;
16931 currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0);
16932 currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0);
16933 if (current-currentErrorMinus < range.lower || !haveLower)
16934 {
16935 range.lower = current-currentErrorMinus;
16936 haveLower = true;
16937 }
16938 if (current+currentErrorPlus > range.upper || !haveUpper)
16939 {
16940 range.upper = current+currentErrorPlus;
16941 haveUpper = true;
16942 }
16943 ++it;
16944 }
16945 } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain
16946 {
16947 QVector<QCPData>::const_iterator it = mDataVector->constBegin();
16948 while (it != mDataVector->constEnd())
16949 {
16950 current = (*it).key;
16951 currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0);
16952 currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0);
16953 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0)
16954 {
16955 range.lower = current-currentErrorMinus;
16956 haveLower = true;
16957 }
16958 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0)
16959 {
16960 range.upper = current+currentErrorPlus;
16961 haveUpper = true;
16962 }
16963 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point.
16964 {
16965 if ((current < range.lower || !haveLower) && current < 0)
16603 if ((current > range.upper || !haveUpper) && current > 0)
16966 16604 {
16967 range.lower = current;
16968 haveLower = true;
16969 }
16970 if ((current > range.upper || !haveUpper) && current < 0)
16971 {
16972 range.upper = current;
16973 haveUpper = true;
16605 range.upper = current;
16606 haveUpper = true;
16974 16607 }
16975 16608 }
16976 ++it;
16977 }
16978 } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain
16979 {
16980 QVector<QCPData>::const_iterator it = mDataVector->constBegin();
16981 while (it != mDataVector->constEnd())
16982 {
16983 current = (*it).key;
16984 currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0);
16985 currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0);
16986 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0)
16987 {
16988 range.lower = current-currentErrorMinus;
16989 haveLower = true;
16990 }
16991 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0)
16992 {
16993 range.upper = current+currentErrorPlus;
16994 haveUpper = true;
16995 }
16996 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point.
16997 {
16998 if ((current < range.lower || !haveLower) && current > 0)
16999 {
17000 range.lower = current;
17001 haveLower = true;
17002 }
17003 if ((current > range.upper || !haveUpper) && current > 0)
17004 {
17005 range.upper = current;
17006 haveUpper = true;
17007 }
17008 }
17009 ++it;
17010 }
17011 }
17012
17013 foundRange = haveLower && haveUpper;
17014 return range;
16609 ++it;
16610 }
16611 }
16612
16613 foundRange = haveLower && haveUpper;
16614 return range;
17015 16615 }
17016 16616
17017 16617 /*! \overload
@@ -17022,203 +16622,104 QCPRange QCPGraph::getKeyRangeVector(boo
17022 16622 */
17023 16623 QCPRange QCPGraph::getValueRange(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const
17024 16624 {
17025 QCPRange range;
17026 bool haveLower = false;
17027 bool haveUpper = false;
17028
17029 double current, currentErrorMinus, currentErrorPlus;
17030
17031 if (inSignDomain == sdBoth) // range may be anywhere
17032 {
17033 QCPDataMap::const_iterator it = mData->constBegin();
17034 while (it != mData->constEnd())
17035 {
17036 current = it.value().value;
17037 currentErrorMinus = (includeErrors ? it.value().valueErrorMinus : 0);
17038 currentErrorPlus = (includeErrors ? it.value().valueErrorPlus : 0);
17039 if (current-currentErrorMinus < range.lower || !haveLower)
17040 {
17041 range.lower = current-currentErrorMinus;
17042 haveLower = true;
17043 }
17044 if (current+currentErrorPlus > range.upper || !haveUpper)
17045 {
17046 range.upper = current+currentErrorPlus;
17047 haveUpper = true;
17048 }
17049 ++it;
16625 QCPRange range;
16626 bool haveLower = false;
16627 bool haveUpper = false;
16628
16629 double current, currentErrorMinus, currentErrorPlus;
16630
16631 if (inSignDomain == sdBoth) // range may be anywhere
16632 {
16633 QCPDataMap::const_iterator it = mData->constBegin();
16634 while (it != mData->constEnd())
16635 {
16636 current = it.value().value;
16637 currentErrorMinus = (includeErrors ? it.value().valueErrorMinus : 0);
16638 currentErrorPlus = (includeErrors ? it.value().valueErrorPlus : 0);
16639 if (current-currentErrorMinus < range.lower || !haveLower)
16640 {
16641 range.lower = current-currentErrorMinus;
16642 haveLower = true;
16643 }
16644 if (current+currentErrorPlus > range.upper || !haveUpper)
16645 {
16646 range.upper = current+currentErrorPlus;
16647 haveUpper = true;
16648 }
16649 ++it;
17050 16650 }
17051 16651 } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain
17052 16652 {
17053 QCPDataMap::const_iterator it = mData->constBegin();
17054 while (it != mData->constEnd())
17055 {
17056 current = it.value().value;
17057 currentErrorMinus = (includeErrors ? it.value().valueErrorMinus : 0);
17058 currentErrorPlus = (includeErrors ? it.value().valueErrorPlus : 0);
17059 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0)
17060 {
17061 range.lower = current-currentErrorMinus;
17062 haveLower = true;
17063 }
17064 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0)
17065 {
17066 range.upper = current+currentErrorPlus;
17067 haveUpper = true;
17068 }
17069 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point.
17070 {
17071 if ((current < range.lower || !haveLower) && current < 0)
16653 QCPDataMap::const_iterator it = mData->constBegin();
16654 while (it != mData->constEnd())
16655 {
16656 current = it.value().value;
16657 currentErrorMinus = (includeErrors ? it.value().valueErrorMinus : 0);
16658 currentErrorPlus = (includeErrors ? it.value().valueErrorPlus : 0);
16659 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0)
16660 {
16661 range.lower = current-currentErrorMinus;
16662 haveLower = true;
16663 }
16664 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0)
16665 {
16666 range.upper = current+currentErrorPlus;
16667 haveUpper = true;
16668 }
16669 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point.
16670 {
16671 if ((current < range.lower || !haveLower) && current < 0)
17072 16672 {
17073 range.lower = current;
17074 haveLower = true;
16673 range.lower = current;
16674 haveLower = true;
17075 16675 }
17076 if ((current > range.upper || !haveUpper) && current < 0)
16676 if ((current > range.upper || !haveUpper) && current < 0)
17077 16677 {
17078 range.upper = current;
17079 haveUpper = true;
16678 range.upper = current;
16679 haveUpper = true;
17080 16680 }
17081 16681 }
17082 ++it;
16682 ++it;
17083 16683 }
17084 16684 } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain
17085 16685 {
17086 QCPDataMap::const_iterator it = mData->constBegin();
17087 while (it != mData->constEnd())
17088 {
17089 current = it.value().value;
17090 currentErrorMinus = (includeErrors ? it.value().valueErrorMinus : 0);
17091 currentErrorPlus = (includeErrors ? it.value().valueErrorPlus : 0);
17092 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0)
17093 {
17094 range.lower = current-currentErrorMinus;
17095 haveLower = true;
17096 }
17097 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0)
17098 {
17099 range.upper = current+currentErrorPlus;
17100 haveUpper = true;
17101 }
17102 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point.
17103 {
17104 if ((current < range.lower || !haveLower) && current > 0)
16686 QCPDataMap::const_iterator it = mData->constBegin();
16687 while (it != mData->constEnd())
16688 {
16689 current = it.value().value;
16690 currentErrorMinus = (includeErrors ? it.value().valueErrorMinus : 0);
16691 currentErrorPlus = (includeErrors ? it.value().valueErrorPlus : 0);
16692 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0)
16693 {
16694 range.lower = current-currentErrorMinus;
16695 haveLower = true;
16696 }
16697 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0)
16698 {
16699 range.upper = current+currentErrorPlus;
16700 haveUpper = true;
16701 }
16702 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point.
16703 {
16704 if ((current < range.lower || !haveLower) && current > 0)
17105 16705 {
17106 range.lower = current;
17107 haveLower = true;
17108 }
17109 if ((current > range.upper || !haveUpper) && current > 0)
17110 {
17111 range.upper = current;
17112 haveUpper = true;
16706 range.lower = current;
16707 haveLower = true;
17113 16708 }
17114 }
17115 ++it;
17116 }
17117 }
17118
17119 foundRange = haveLower && haveUpper;
17120 return range;
17121 }
17122
17123 QCPRange QCPGraph::getValueRangeVector(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const
17124 {
17125 QCPRange range;
17126 bool haveLower = false;
17127 bool haveUpper = false;
17128
17129 double current, currentErrorMinus, currentErrorPlus;
17130
17131 if (inSignDomain == sdBoth) // range may be anywhere
17132 {
17133 QVector<QCPData>::const_iterator it = mDataVector->constBegin();
17134 while (it != mDataVector->constEnd())
17135 {
17136 current = (*it).value;
17137 currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0);
17138 currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0);
17139 if (current-currentErrorMinus < range.lower || !haveLower)
17140 {
17141 range.lower = current-currentErrorMinus;
17142 haveLower = true;
17143 }
17144 if (current+currentErrorPlus > range.upper || !haveUpper)
17145 {
17146 range.upper = current+currentErrorPlus;
17147 haveUpper = true;
17148 }
17149 ++it;
17150 }
17151 } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain
17152 {
17153 QVector<QCPData>::const_iterator it = mDataVector->constBegin();
17154 while (it != mDataVector->constEnd())
17155 {
17156 current = (*it).value;
17157 currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0);
17158 currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0);
17159 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0)
17160 {
17161 range.lower = current-currentErrorMinus;
17162 haveLower = true;
17163 }
17164 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0)
17165 {
17166 range.upper = current+currentErrorPlus;
17167 haveUpper = true;
17168 }
17169 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point.
17170 {
17171 if ((current < range.lower || !haveLower) && current < 0)
16709 if ((current > range.upper || !haveUpper) && current > 0)
17172 16710 {
17173 range.lower = current;
17174 haveLower = true;
17175 }
17176 if ((current > range.upper || !haveUpper) && current < 0)
17177 {
17178 range.upper = current;
17179 haveUpper = true;
16711 range.upper = current;
16712 haveUpper = true;
17180 16713 }
17181 16714 }
17182 ++it;
17183 }
17184 } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain
17185 {
17186 QVector<QCPData>::const_iterator it = mDataVector->constBegin();
17187 while (it != mDataVector->constEnd())
17188 {
17189 current = (*it).value;
17190 currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0);
17191 currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0);
17192 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0)
17193 {
17194 range.lower = current-currentErrorMinus;
17195 haveLower = true;
17196 }
17197 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0)
17198 {
17199 range.upper = current+currentErrorPlus;
17200 haveUpper = true;
17201 }
17202 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point.
17203 {
17204 if ((current < range.lower || !haveLower) && current > 0)
17205 {
17206 range.lower = current;
17207 haveLower = true;
17208 }
17209 if ((current > range.upper || !haveUpper) && current > 0)
17210 {
17211 range.upper = current;
17212 haveUpper = true;
17213 }
17214 }
17215 ++it;
17216 }
17217 }
17218
17219 foundRange = haveLower && haveUpper;
17220 return range;
17221 }
16715 ++it;
16716 }
16717 }
16718
16719 foundRange = haveLower && haveUpper;
16720 return range;
16721 }
16722
17222 16723
17223 16724 ////////////////////////////////////////////////////////////////////////////////////////////////////
17224 16725 //////////////////// QCPCurveData
@@ -17241,9 +16742,9 QCPRange QCPGraph::getValueRangeVector(b
17241 16742 Constructs a curve data point with t, key and value set to zero.
17242 16743 */
17243 16744 QCPCurveData::QCPCurveData() :
17244 t(0),
17245 key(0),
17246 value(0)
16745 t(0),
16746 key(0),
16747 value(0)
17247 16748 {
17248 16749 }
17249 16750
@@ -17251,9 +16752,9 QCPCurveData::QCPCurveData() :
17251 16752 Constructs a curve data point with the specified \a t, \a key and \a value.
17252 16753 */
17253 16754 QCPCurveData::QCPCurveData(double t, double key, double value) :
17254 t(t),
17255 key(key),
17256 value(value)
16755 t(t),
16756 key(key),
16757 value(value)
17257 16758 {
17258 16759 }
17259 16760
@@ -17304,25 +16805,25 QCPCurveData::QCPCurveData(double t, dou
17304 16805 then takes ownership of the graph.
17305 16806 */
17306 16807 QCPCurve::QCPCurve(QCPAxis *keyAxis, QCPAxis *valueAxis) :
17307 QCPAbstractPlottable(keyAxis, valueAxis)
17308 {
17309 mData = new QCPCurveDataMap;
17310 mPen.setColor(Qt::blue);
17311 mPen.setStyle(Qt::SolidLine);
17312 mBrush.setColor(Qt::blue);
17313 mBrush.setStyle(Qt::NoBrush);
17314 mSelectedPen = mPen;
17315 mSelectedPen.setWidthF(2.5);
17316 mSelectedPen.setColor(QColor(80, 80, 255)); // lighter than Qt::blue of mPen
17317 mSelectedBrush = mBrush;
17318
17319 setScatterStyle(QCPScatterStyle());
17320 setLineStyle(lsLine);
16808 QCPAbstractPlottable(keyAxis, valueAxis)
16809 {
16810 mData = new QCPCurveDataMap;
16811 mPen.setColor(Qt::blue);
16812 mPen.setStyle(Qt::SolidLine);
16813 mBrush.setColor(Qt::blue);
16814 mBrush.setStyle(Qt::NoBrush);
16815 mSelectedPen = mPen;
16816 mSelectedPen.setWidthF(2.5);
16817 mSelectedPen.setColor(QColor(80, 80, 255)); // lighter than Qt::blue of mPen
16818 mSelectedBrush = mBrush;
16819
16820 setScatterStyle(QCPScatterStyle());
16821 setLineStyle(lsLine);
17321 16822 }
17322 16823
17323 16824 QCPCurve::~QCPCurve()
17324 16825 {
17325 delete mData;
16826 delete mData;
17326 16827 }
17327 16828
17328 16829 /*!
@@ -17334,18 +16835,18 QCPCurve::~QCPCurve()
17334 16835 */
17335 16836 void QCPCurve::setData(QCPCurveDataMap *data, bool copy)
17336 16837 {
17337 if (mData == data)
17338 {
17339 qDebug() << Q_FUNC_INFO << "The data pointer is already in (and owned by) this plottable" << reinterpret_cast<quintptr>(data);
17340 return;
17341 }
17342 if (copy)
17343 {
17344 *mData = *data;
17345 } else
17346 {
17347 delete mData;
17348 mData = data;
16838 if (mData == data)
16839 {
16840 qDebug() << Q_FUNC_INFO << "The data pointer is already in (and owned by) this plottable" << reinterpret_cast<quintptr>(data);
16841 return;
16842 }
16843 if (copy)
16844 {
16845 *mData = *data;
16846 } else
16847 {
16848 delete mData;
16849 mData = data;
17349 16850 }
17350 16851 }
17351 16852
@@ -17357,17 +16858,17 void QCPCurve::setData(QCPCurveDataMap *
17357 16858 */
17358 16859 void QCPCurve::setData(const QVector<double> &t, const QVector<double> &key, const QVector<double> &value)
17359 16860 {
17360 mData->clear();
17361 int n = t.size();
17362 n = qMin(n, key.size());
17363 n = qMin(n, value.size());
17364 QCPCurveData newData;
17365 for (int i=0; i<n; ++i)
17366 {
17367 newData.t = t[i];
17368 newData.key = key[i];
17369 newData.value = value[i];
17370 mData->insertMulti(newData.t, newData);
16861 mData->clear();
16862 int n = t.size();
16863 n = qMin(n, key.size());
16864 n = qMin(n, value.size());
16865 QCPCurveData newData;
16866 for (int i=0; i<n; ++i)
16867 {
16868 newData.t = t[i];
16869 newData.key = key[i];
16870 newData.value = value[i];
16871 mData->insertMulti(newData.t, newData);
17371 16872 }
17372 16873 }
17373 16874
@@ -17378,16 +16879,16 void QCPCurve::setData(const QVector<dou
17378 16879 */
17379 16880 void QCPCurve::setData(const QVector<double> &key, const QVector<double> &value)
17380 16881 {
17381 mData->clear();
17382 int n = key.size();
17383 n = qMin(n, value.size());
17384 QCPCurveData newData;
17385 for (int i=0; i<n; ++i)
17386 {
17387 newData.t = i; // no t vector given, so we assign t the index of the key/value pair
17388 newData.key = key[i];
17389 newData.value = value[i];
17390 mData->insertMulti(newData.t, newData);
16882 mData->clear();
16883 int n = key.size();
16884 n = qMin(n, value.size());
16885 QCPCurveData newData;
16886 for (int i=0; i<n; ++i)
16887 {
16888 newData.t = i; // no t vector given, so we assign t the index of the key/value pair
16889 newData.key = key[i];
16890 newData.value = value[i];
16891 mData->insertMulti(newData.t, newData);
17391 16892 }
17392 16893 }
17393 16894
@@ -17400,7 +16901,7 void QCPCurve::setData(const QVector<dou
17400 16901 */
17401 16902 void QCPCurve::setScatterStyle(const QCPScatterStyle &style)
17402 16903 {
17403 mScatterStyle = style;
16904 mScatterStyle = style;
17404 16905 }
17405 16906
17406 16907 /*!
@@ -17412,7 +16913,7 void QCPCurve::setScatterStyle(const QCP
17412 16913 */
17413 16914 void QCPCurve::setLineStyle(QCPCurve::LineStyle style)
17414 16915 {
17415 mLineStyle = style;
16916 mLineStyle = style;
17416 16917 }
17417 16918
17418 16919 /*!
@@ -17421,7 +16922,7 void QCPCurve::setLineStyle(QCPCurve::Li
17421 16922 */
17422 16923 void QCPCurve::addData(const QCPCurveDataMap &dataMap)
17423 16924 {
17424 mData->unite(dataMap);
16925 mData->unite(dataMap);
17425 16926 }
17426 16927
17427 16928 /*! \overload
@@ -17430,7 +16931,7 void QCPCurve::addData(const QCPCurveDat
17430 16931 */
17431 16932 void QCPCurve::addData(const QCPCurveData &data)
17432 16933 {
17433 mData->insertMulti(data.t, data);
16934 mData->insertMulti(data.t, data);
17434 16935 }
17435 16936
17436 16937 /*! \overload
@@ -17439,11 +16940,11 void QCPCurve::addData(const QCPCurveDat
17439 16940 */
17440 16941 void QCPCurve::addData(double t, double key, double value)
17441 16942 {
17442 QCPCurveData newData;
17443 newData.t = t;
17444 newData.key = key;
17445 newData.value = value;
17446 mData->insertMulti(newData.t, newData);
16943 QCPCurveData newData;
16944 newData.t = t;
16945 newData.key = key;
16946 newData.value = value;
16947 mData->insertMulti(newData.t, newData);
17447 16948 }
17448 16949
17449 16950 /*! \overload
@@ -17456,14 +16957,14 void QCPCurve::addData(double t, double
17456 16957 */
17457 16958 void QCPCurve::addData(double key, double value)
17458 16959 {
17459 QCPCurveData newData;
17460 if (!mData->isEmpty())
17461 newData.t = (mData->constEnd()-1).key()+1;
17462 else
17463 newData.t = 0;
17464 newData.key = key;
17465 newData.value = value;
17466 mData->insertMulti(newData.t, newData);
16960 QCPCurveData newData;
16961 if (!mData->isEmpty())
16962 newData.t = (mData->constEnd()-1).key()+1;
16963 else
16964 newData.t = 0;
16965 newData.key = key;
16966 newData.value = value;
16967 mData->insertMulti(newData.t, newData);
17467 16968 }
17468 16969
17469 16970 /*! \overload
@@ -17472,16 +16973,16 void QCPCurve::addData(double key, doubl
17472 16973 */
17473 16974 void QCPCurve::addData(const QVector<double> &ts, const QVector<double> &keys, const QVector<double> &values)
17474 16975 {
17475 int n = ts.size();
17476 n = qMin(n, keys.size());
17477 n = qMin(n, values.size());
17478 QCPCurveData newData;
17479 for (int i=0; i<n; ++i)
17480 {
17481 newData.t = ts[i];
17482 newData.key = keys[i];
17483 newData.value = values[i];
17484 mData->insertMulti(newData.t, newData);
16976 int n = ts.size();
16977 n = qMin(n, keys.size());
16978 n = qMin(n, values.size());
16979 QCPCurveData newData;
16980 for (int i=0; i<n; ++i)
16981 {
16982 newData.t = ts[i];
16983 newData.key = keys[i];
16984 newData.value = values[i];
16985 mData->insertMulti(newData.t, newData);
17485 16986 }
17486 16987 }
17487 16988
@@ -17491,9 +16992,9 void QCPCurve::addData(const QVector<dou
17491 16992 */
17492 16993 void QCPCurve::removeDataBefore(double t)
17493 16994 {
17494 QCPCurveDataMap::iterator it = mData->begin();
17495 while (it != mData->end() && it.key() < t)
17496 it = mData->erase(it);
16995 QCPCurveDataMap::iterator it = mData->begin();
16996 while (it != mData->end() && it.key() < t)
16997 it = mData->erase(it);
17497 16998 }
17498 16999
17499 17000 /*!
@@ -17502,10 +17003,10 void QCPCurve::removeDataBefore(double t
17502 17003 */
17503 17004 void QCPCurve::removeDataAfter(double t)
17504 17005 {
17505 if (mData->isEmpty()) return;
17506 QCPCurveDataMap::iterator it = mData->upperBound(t);
17507 while (it != mData->end())
17508 it = mData->erase(it);
17006 if (mData->isEmpty()) return;
17007 QCPCurveDataMap::iterator it = mData->upperBound(t);
17008 while (it != mData->end())
17009 it = mData->erase(it);
17509 17010 }
17510 17011
17511 17012 /*!
@@ -17517,11 +17018,11 void QCPCurve::removeDataAfter(double t)
17517 17018 */
17518 17019 void QCPCurve::removeData(double fromt, double tot)
17519 17020 {
17520 if (fromt >= tot || mData->isEmpty()) return;
17521 QCPCurveDataMap::iterator it = mData->upperBound(fromt);
17522 QCPCurveDataMap::iterator itEnd = mData->upperBound(tot);
17523 while (it != itEnd)
17524 it = mData->erase(it);
17021 if (fromt >= tot || mData->isEmpty()) return;
17022 QCPCurveDataMap::iterator it = mData->upperBound(fromt);
17023 QCPCurveDataMap::iterator itEnd = mData->upperBound(tot);
17024 while (it != itEnd)
17025 it = mData->erase(it);
17525 17026 }
17526 17027
17527 17028 /*! \overload
@@ -17535,7 +17036,7 void QCPCurve::removeData(double fromt,
17535 17036 */
17536 17037 void QCPCurve::removeData(double t)
17537 17038 {
17538 mData->remove(t);
17039 mData->remove(t);
17539 17040 }
17540 17041
17541 17042 /*!
@@ -17544,134 +17045,134 void QCPCurve::removeData(double t)
17544 17045 */
17545 17046 void QCPCurve::clearData()
17546 17047 {
17547 mData->clear();
17048 mData->clear();
17548 17049 }
17549 17050
17550 17051 /* inherits documentation from base class */
17551 17052 double QCPCurve::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
17552 17053 {
17553 Q_UNUSED(details)
17554 if ((onlySelectable && !mSelectable) || mData->isEmpty())
17555 return -1;
17556 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
17557
17558 if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()))
17559 return pointDistance(pos);
17560 else
17561 return -1;
17054 Q_UNUSED(details)
17055 if ((onlySelectable && !mSelectable) || mData->isEmpty())
17056 return -1;
17057 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
17058
17059 if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()))
17060 return pointDistance(pos);
17061 else
17062 return -1;
17562 17063 }
17563 17064
17564 17065 /* inherits documentation from base class */
17565 17066 void QCPCurve::draw(QCPPainter *painter)
17566 17067 {
17567 if (mData->isEmpty()) return;
17568
17569 // allocate line vector:
17570 QVector<QPointF> *lineData = new QVector<QPointF>;
17571
17572 // fill with curve data:
17573 getCurveData(lineData);
17574
17575 // check data validity if flag set:
17068 if (mData->isEmpty()) return;
17069
17070 // allocate line vector:
17071 QVector<QPointF> *lineData = new QVector<QPointF>;
17072
17073 // fill with curve data:
17074 getCurveData(lineData);
17075
17076 // check data validity if flag set:
17576 17077 #ifdef QCUSTOMPLOT_CHECK_DATA
17577 QCPCurveDataMap::const_iterator it;
17578 for (it = mData->constBegin(); it != mData->constEnd(); ++it)
17579 {
17580 if (QCP::isInvalidData(it.value().t) ||
17581 QCP::isInvalidData(it.value().key, it.value().value))
17582 qDebug() << Q_FUNC_INFO << "Data point at" << it.key() << "invalid." << "Plottable name:" << name();
17078 QCPCurveDataMap::const_iterator it;
17079 for (it = mData->constBegin(); it != mData->constEnd(); ++it)
17080 {
17081 if (QCP::isInvalidData(it.value().t) ||
17082 QCP::isInvalidData(it.value().key, it.value().value))
17083 qDebug() << Q_FUNC_INFO << "Data point at" << it.key() << "invalid." << "Plottable name:" << name();
17583 17084 }
17584 17085 #endif
17585
17586 // draw curve fill:
17587 if (mainBrush().style() != Qt::NoBrush && mainBrush().color().alpha() != 0)
17588 {
17589 applyFillAntialiasingHint(painter);
17590 painter->setPen(Qt::NoPen);
17591 painter->setBrush(mainBrush());
17592 painter->drawPolygon(QPolygonF(*lineData));
17593 }
17594
17595 // draw curve line:
17596 if (mLineStyle != lsNone && mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0)
17597 {
17598 applyDefaultAntialiasingHint(painter);
17599 painter->setPen(mainPen());
17600 painter->setBrush(Qt::NoBrush);
17601 // if drawing solid line and not in PDF, use much faster line drawing instead of polyline:
17602 if (mParentPlot->plottingHints().testFlag(QCP::phFastPolylines) &&
17603 painter->pen().style() == Qt::SolidLine &&
17604 !painter->modes().testFlag(QCPPainter::pmVectorized) &&
17605 !painter->modes().testFlag(QCPPainter::pmNoCaching))
17606 {
17607 int i = 1;
17608 int lineDataSize = lineData->size();
17609 while (i < lineDataSize)
17610 {
17611 if (!qIsNaN(lineData->at(i).y()) && !qIsNaN(lineData->at(i).x())) // NaNs create a gap in the line
17612 painter->drawLine(lineData->at(i-1), lineData->at(i));
17613 else
17086
17087 // draw curve fill:
17088 if (mainBrush().style() != Qt::NoBrush && mainBrush().color().alpha() != 0)
17089 {
17090 applyFillAntialiasingHint(painter);
17091 painter->setPen(Qt::NoPen);
17092 painter->setBrush(mainBrush());
17093 painter->drawPolygon(QPolygonF(*lineData));
17094 }
17095
17096 // draw curve line:
17097 if (mLineStyle != lsNone && mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0)
17098 {
17099 applyDefaultAntialiasingHint(painter);
17100 painter->setPen(mainPen());
17101 painter->setBrush(Qt::NoBrush);
17102 // if drawing solid line and not in PDF, use much faster line drawing instead of polyline:
17103 if (mParentPlot->plottingHints().testFlag(QCP::phFastPolylines) &&
17104 painter->pen().style() == Qt::SolidLine &&
17105 !painter->modes().testFlag(QCPPainter::pmVectorized) &&
17106 !painter->modes().testFlag(QCPPainter::pmNoCaching))
17107 {
17108 int i = 1;
17109 int lineDataSize = lineData->size();
17110 while (i < lineDataSize)
17111 {
17112 if (!qIsNaN(lineData->at(i).y()) && !qIsNaN(lineData->at(i).x())) // NaNs create a gap in the line
17113 painter->drawLine(lineData->at(i-1), lineData->at(i));
17114 else
17115 ++i;
17614 17116 ++i;
17615 ++i;
17616 17117 }
17617 17118 } else
17618 17119 {
17619 int segmentStart = 0;
17620 int i = 0;
17621 int lineDataSize = lineData->size();
17622 while (i < lineDataSize)
17623 {
17624 if (qIsNaN(lineData->at(i).y()) || qIsNaN(lineData->at(i).x())) // NaNs create a gap in the line
17120 int segmentStart = 0;
17121 int i = 0;
17122 int lineDataSize = lineData->size();
17123 while (i < lineDataSize)
17124 {
17125 if (qIsNaN(lineData->at(i).y()) || qIsNaN(lineData->at(i).x())) // NaNs create a gap in the line
17625 17126 {
17626 painter->drawPolyline(lineData->constData()+segmentStart, i-segmentStart); // i, because we don't want to include the current NaN point
17627 segmentStart = i+1;
17127 painter->drawPolyline(lineData->constData()+segmentStart, i-segmentStart); // i, because we don't want to include the current NaN point
17128 segmentStart = i+1;
17628 17129 }
17629 ++i;
17630 }
17631 // draw last segment:
17632 painter->drawPolyline(lineData->constData()+segmentStart, lineDataSize-segmentStart); // lineDataSize, because we do want to include the last point
17633 }
17634 }
17635
17636 // draw scatters:
17637 if (!mScatterStyle.isNone())
17638 drawScatterPlot(painter, lineData);
17639
17640 // free allocated line data:
17641 delete lineData;
17130 ++i;
17131 }
17132 // draw last segment:
17133 painter->drawPolyline(lineData->constData()+segmentStart, lineDataSize-segmentStart); // lineDataSize, because we do want to include the last point
17134 }
17135 }
17136
17137 // draw scatters:
17138 if (!mScatterStyle.isNone())
17139 drawScatterPlot(painter, lineData);
17140
17141 // free allocated line data:
17142 delete lineData;
17642 17143 }
17643 17144
17644 17145 /* inherits documentation from base class */
17645 17146 void QCPCurve::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const
17646 17147 {
17647 // draw fill:
17648 if (mBrush.style() != Qt::NoBrush)
17649 {
17650 applyFillAntialiasingHint(painter);
17651 painter->fillRect(QRectF(rect.left(), rect.top()+rect.height()/2.0, rect.width(), rect.height()/3.0), mBrush);
17652 }
17653 // draw line vertically centered:
17654 if (mLineStyle != lsNone)
17655 {
17656 applyDefaultAntialiasingHint(painter);
17657 painter->setPen(mPen);
17658 painter->drawLine(QLineF(rect.left(), rect.top()+rect.height()/2.0, rect.right()+5, rect.top()+rect.height()/2.0)); // +5 on x2 else last segment is missing from dashed/dotted pens
17659 }
17660 // draw scatter symbol:
17661 if (!mScatterStyle.isNone())
17662 {
17663 applyScattersAntialiasingHint(painter);
17664 // scale scatter pixmap if it's too large to fit in legend icon rect:
17665 if (mScatterStyle.shape() == QCPScatterStyle::ssPixmap && (mScatterStyle.pixmap().size().width() > rect.width() || mScatterStyle.pixmap().size().height() > rect.height()))
17666 {
17667 QCPScatterStyle scaledStyle(mScatterStyle);
17668 scaledStyle.setPixmap(scaledStyle.pixmap().scaled(rect.size().toSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
17669 scaledStyle.applyTo(painter, mPen);
17670 scaledStyle.drawShape(painter, QRectF(rect).center());
17148 // draw fill:
17149 if (mBrush.style() != Qt::NoBrush)
17150 {
17151 applyFillAntialiasingHint(painter);
17152 painter->fillRect(QRectF(rect.left(), rect.top()+rect.height()/2.0, rect.width(), rect.height()/3.0), mBrush);
17153 }
17154 // draw line vertically centered:
17155 if (mLineStyle != lsNone)
17156 {
17157 applyDefaultAntialiasingHint(painter);
17158 painter->setPen(mPen);
17159 painter->drawLine(QLineF(rect.left(), rect.top()+rect.height()/2.0, rect.right()+5, rect.top()+rect.height()/2.0)); // +5 on x2 else last segment is missing from dashed/dotted pens
17160 }
17161 // draw scatter symbol:
17162 if (!mScatterStyle.isNone())
17163 {
17164 applyScattersAntialiasingHint(painter);
17165 // scale scatter pixmap if it's too large to fit in legend icon rect:
17166 if (mScatterStyle.shape() == QCPScatterStyle::ssPixmap && (mScatterStyle.pixmap().size().width() > rect.width() || mScatterStyle.pixmap().size().height() > rect.height()))
17167 {
17168 QCPScatterStyle scaledStyle(mScatterStyle);
17169 scaledStyle.setPixmap(scaledStyle.pixmap().scaled(rect.size().toSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
17170 scaledStyle.applyTo(painter, mPen);
17171 scaledStyle.drawShape(painter, QRectF(rect).center());
17671 17172 } else
17672 17173 {
17673 mScatterStyle.applyTo(painter, mPen);
17674 mScatterStyle.drawShape(painter, QRectF(rect).center());
17174 mScatterStyle.applyTo(painter, mPen);
17175 mScatterStyle.drawShape(painter, QRectF(rect).center());
17675 17176 }
17676 17177 }
17677 17178 }
@@ -17683,12 +17184,12 void QCPCurve::drawLegendIcon(QCPPainter
17683 17184 */
17684 17185 void QCPCurve::drawScatterPlot(QCPPainter *painter, const QVector<QPointF> *pointData) const
17685 17186 {
17686 // draw scatter point symbols:
17687 applyScattersAntialiasingHint(painter);
17688 mScatterStyle.applyTo(painter, mPen);
17689 for (int i=0; i<pointData->size(); ++i)
17690 if (!qIsNaN(pointData->at(i).x()) && !qIsNaN(pointData->at(i).y()))
17691 mScatterStyle.drawShape(painter, pointData->at(i));
17187 // draw scatter point symbols:
17188 applyScattersAntialiasingHint(painter);
17189 mScatterStyle.applyTo(painter, mPen);
17190 for (int i=0; i<pointData->size(); ++i)
17191 if (!qIsNaN(pointData->at(i).x()) && !qIsNaN(pointData->at(i).y()))
17192 mScatterStyle.drawShape(painter, pointData->at(i));
17692 17193 }
17693 17194
17694 17195 /*! \internal
@@ -17706,81 +17207,81 void QCPCurve::drawScatterPlot(QCPPainte
17706 17207 */
17707 17208 void QCPCurve::getCurveData(QVector<QPointF> *lineData) const
17708 17209 {
17709 QCPAxis *keyAxis = mKeyAxis.data();
17710 QCPAxis *valueAxis = mValueAxis.data();
17711 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
17712
17713 // add margins to rect to compensate for stroke width
17714 double strokeMargin = qMax(qreal(1.0), qreal(mainPen().widthF()*0.75)); // stroke radius + 50% safety
17715 if (!mScatterStyle.isNone())
17716 strokeMargin = qMax(strokeMargin, mScatterStyle.size());
17717 double rectLeft = keyAxis->pixelToCoord(keyAxis->coordToPixel(keyAxis->range().lower)-strokeMargin*((keyAxis->orientation()==Qt::Vertical)!=keyAxis->rangeReversed()?-1:1));
17718 double rectRight = keyAxis->pixelToCoord(keyAxis->coordToPixel(keyAxis->range().upper)+strokeMargin*((keyAxis->orientation()==Qt::Vertical)!=keyAxis->rangeReversed()?-1:1));
17719 double rectBottom = valueAxis->pixelToCoord(valueAxis->coordToPixel(valueAxis->range().lower)+strokeMargin*((valueAxis->orientation()==Qt::Horizontal)!=valueAxis->rangeReversed()?-1:1));
17720 double rectTop = valueAxis->pixelToCoord(valueAxis->coordToPixel(valueAxis->range().upper)-strokeMargin*((valueAxis->orientation()==Qt::Horizontal)!=valueAxis->rangeReversed()?-1:1));
17721 int currentRegion;
17722 QCPCurveDataMap::const_iterator it = mData->constBegin();
17723 QCPCurveDataMap::const_iterator prevIt = mData->constEnd()-1;
17724 int prevRegion = getRegion(prevIt.value().key, prevIt.value().value, rectLeft, rectTop, rectRight, rectBottom);
17725 QVector<QPointF> trailingPoints; // points that must be applied after all other points (are generated only when handling first point to get virtual segment between last and first point right)
17726 while (it != mData->constEnd())
17727 {
17728 currentRegion = getRegion(it.value().key, it.value().value, rectLeft, rectTop, rectRight, rectBottom);
17729 if (currentRegion != prevRegion) // changed region, possibly need to add some optimized edge points or original points if entering R
17730 {
17731 if (currentRegion != 5) // segment doesn't end in R, so it's a candidate for removal
17732 {
17733 QPointF crossA, crossB;
17734 if (prevRegion == 5) // we're coming from R, so add this point optimized
17210 QCPAxis *keyAxis = mKeyAxis.data();
17211 QCPAxis *valueAxis = mValueAxis.data();
17212 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
17213
17214 // add margins to rect to compensate for stroke width
17215 double strokeMargin = qMax(qreal(1.0), qreal(mainPen().widthF()*0.75)); // stroke radius + 50% safety
17216 if (!mScatterStyle.isNone())
17217 strokeMargin = qMax(strokeMargin, mScatterStyle.size());
17218 double rectLeft = keyAxis->pixelToCoord(keyAxis->coordToPixel(keyAxis->range().lower)-strokeMargin*((keyAxis->orientation()==Qt::Vertical)!=keyAxis->rangeReversed()?-1:1));
17219 double rectRight = keyAxis->pixelToCoord(keyAxis->coordToPixel(keyAxis->range().upper)+strokeMargin*((keyAxis->orientation()==Qt::Vertical)!=keyAxis->rangeReversed()?-1:1));
17220 double rectBottom = valueAxis->pixelToCoord(valueAxis->coordToPixel(valueAxis->range().lower)+strokeMargin*((valueAxis->orientation()==Qt::Horizontal)!=valueAxis->rangeReversed()?-1:1));
17221 double rectTop = valueAxis->pixelToCoord(valueAxis->coordToPixel(valueAxis->range().upper)-strokeMargin*((valueAxis->orientation()==Qt::Horizontal)!=valueAxis->rangeReversed()?-1:1));
17222 int currentRegion;
17223 QCPCurveDataMap::const_iterator it = mData->constBegin();
17224 QCPCurveDataMap::const_iterator prevIt = mData->constEnd()-1;
17225 int prevRegion = getRegion(prevIt.value().key, prevIt.value().value, rectLeft, rectTop, rectRight, rectBottom);
17226 QVector<QPointF> trailingPoints; // points that must be applied after all other points (are generated only when handling first point to get virtual segment between last and first point right)
17227 while (it != mData->constEnd())
17228 {
17229 currentRegion = getRegion(it.value().key, it.value().value, rectLeft, rectTop, rectRight, rectBottom);
17230 if (currentRegion != prevRegion) // changed region, possibly need to add some optimized edge points or original points if entering R
17231 {
17232 if (currentRegion != 5) // segment doesn't end in R, so it's a candidate for removal
17233 {
17234 QPointF crossA, crossB;
17235 if (prevRegion == 5) // we're coming from R, so add this point optimized
17735 17236 {
17736 lineData->append(getOptimizedPoint(currentRegion, it.value().key, it.value().value, prevIt.value().key, prevIt.value().value, rectLeft, rectTop, rectRight, rectBottom));
17737 // in the situations 5->1/7/9/3 the segment may leave R and directly cross through two outer regions. In these cases we need to add an additional corner point
17738 *lineData << getOptimizedCornerPoints(prevRegion, currentRegion, prevIt.value().key, prevIt.value().value, it.value().key, it.value().value, rectLeft, rectTop, rectRight, rectBottom);
17237 lineData->append(getOptimizedPoint(currentRegion, it.value().key, it.value().value, prevIt.value().key, prevIt.value().value, rectLeft, rectTop, rectRight, rectBottom));
17238 // in the situations 5->1/7/9/3 the segment may leave R and directly cross through two outer regions. In these cases we need to add an additional corner point
17239 *lineData << getOptimizedCornerPoints(prevRegion, currentRegion, prevIt.value().key, prevIt.value().value, it.value().key, it.value().value, rectLeft, rectTop, rectRight, rectBottom);
17739 17240 } else if (mayTraverse(prevRegion, currentRegion) &&
17740 17241 getTraverse(prevIt.value().key, prevIt.value().value, it.value().key, it.value().value, rectLeft, rectTop, rectRight, rectBottom, crossA, crossB))
17741 17242 {
17742 // add the two cross points optimized if segment crosses R and if segment isn't virtual zeroth segment between last and first curve point:
17743 QVector<QPointF> beforeTraverseCornerPoints, afterTraverseCornerPoints;
17744 getTraverseCornerPoints(prevRegion, currentRegion, rectLeft, rectTop, rectRight, rectBottom, beforeTraverseCornerPoints, afterTraverseCornerPoints);
17745 if (it != mData->constBegin())
17243 // add the two cross points optimized if segment crosses R and if segment isn't virtual zeroth segment between last and first curve point:
17244 QVector<QPointF> beforeTraverseCornerPoints, afterTraverseCornerPoints;
17245 getTraverseCornerPoints(prevRegion, currentRegion, rectLeft, rectTop, rectRight, rectBottom, beforeTraverseCornerPoints, afterTraverseCornerPoints);
17246 if (it != mData->constBegin())
17746 17247 {
17747 *lineData << beforeTraverseCornerPoints;
17748 lineData->append(crossA);
17749 lineData->append(crossB);
17750 *lineData << afterTraverseCornerPoints;
17248 *lineData << beforeTraverseCornerPoints;
17249 lineData->append(crossA);
17250 lineData->append(crossB);
17251 *lineData << afterTraverseCornerPoints;
17751 17252 } else
17752 17253 {
17753 lineData->append(crossB);
17754 *lineData << afterTraverseCornerPoints;
17755 trailingPoints << beforeTraverseCornerPoints << crossA ;
17254 lineData->append(crossB);
17255 *lineData << afterTraverseCornerPoints;
17256 trailingPoints << beforeTraverseCornerPoints << crossA ;
17756 17257 }
17757 17258 } else // doesn't cross R, line is just moving around in outside regions, so only need to add optimized point(s) at the boundary corner(s)
17758 17259 {
17759 *lineData << getOptimizedCornerPoints(prevRegion, currentRegion, prevIt.value().key, prevIt.value().value, it.value().key, it.value().value, rectLeft, rectTop, rectRight, rectBottom);
17260 *lineData << getOptimizedCornerPoints(prevRegion, currentRegion, prevIt.value().key, prevIt.value().value, it.value().key, it.value().value, rectLeft, rectTop, rectRight, rectBottom);
17760 17261 }
17761 17262 } else // segment does end in R, so we add previous point optimized and this point at original position
17762 17263 {
17763 if (it == mData->constBegin()) // it is first point in curve and prevIt is last one. So save optimized point for adding it to the lineData in the end
17764 trailingPoints << getOptimizedPoint(prevRegion, prevIt.value().key, prevIt.value().value, it.value().key, it.value().value, rectLeft, rectTop, rectRight, rectBottom);
17765 else
17766 lineData->append(getOptimizedPoint(prevRegion, prevIt.value().key, prevIt.value().value, it.value().key, it.value().value, rectLeft, rectTop, rectRight, rectBottom));
17767 lineData->append(coordsToPixels(it.value().key, it.value().value));
17264 if (it == mData->constBegin()) // it is first point in curve and prevIt is last one. So save optimized point for adding it to the lineData in the end
17265 trailingPoints << getOptimizedPoint(prevRegion, prevIt.value().key, prevIt.value().value, it.value().key, it.value().value, rectLeft, rectTop, rectRight, rectBottom);
17266 else
17267 lineData->append(getOptimizedPoint(prevRegion, prevIt.value().key, prevIt.value().value, it.value().key, it.value().value, rectLeft, rectTop, rectRight, rectBottom));
17268 lineData->append(coordsToPixels(it.value().key, it.value().value));
17768 17269 }
17769 17270 } else // region didn't change
17770 17271 {
17771 if (currentRegion == 5) // still in R, keep adding original points
17772 {
17773 lineData->append(coordsToPixels(it.value().key, it.value().value));
17272 if (currentRegion == 5) // still in R, keep adding original points
17273 {
17274 lineData->append(coordsToPixels(it.value().key, it.value().value));
17774 17275 } else // still outside R, no need to add anything
17775 17276 {
17776 // see how this is not doing anything? That's the main optimization...
17777 }
17778 }
17779 prevIt = it;
17780 prevRegion = currentRegion;
17781 ++it;
17782 }
17783 *lineData << trailingPoints;
17277 // see how this is not doing anything? That's the main optimization...
17278 }
17279 }
17280 prevIt = it;
17281 prevRegion = currentRegion;
17282 ++it;
17283 }
17284 *lineData << trailingPoints;
17784 17285 }
17785 17286
17786 17287 /*! \internal
@@ -17803,30 +17304,30 void QCPCurve::getCurveData(QVector<QPoi
17803 17304 */
17804 17305 int QCPCurve::getRegion(double x, double y, double rectLeft, double rectTop, double rectRight, double rectBottom) const
17805 17306 {
17806 if (x < rectLeft) // region 123
17807 {
17808 if (y > rectTop)
17809 return 1;
17810 else if (y < rectBottom)
17811 return 3;
17812 else
17813 return 2;
17307 if (x < rectLeft) // region 123
17308 {
17309 if (y > rectTop)
17310 return 1;
17311 else if (y < rectBottom)
17312 return 3;
17313 else
17314 return 2;
17814 17315 } else if (x > rectRight) // region 789
17815 17316 {
17816 if (y > rectTop)
17817 return 7;
17818 else if (y < rectBottom)
17819 return 9;
17820 else
17821 return 8;
17317 if (y > rectTop)
17318 return 7;
17319 else if (y < rectBottom)
17320 return 9;
17321 else
17322 return 8;
17822 17323 } else // region 456
17823 17324 {
17824 if (y > rectTop)
17825 return 4;
17826 else if (y < rectBottom)
17827 return 6;
17828 else
17829 return 5;
17325 if (y > rectTop)
17326 return 4;
17327 else if (y < rectBottom)
17328 return 6;
17329 else
17330 return 5;
17830 17331 }
17831 17332 }
17832 17333
@@ -17847,84 +17348,84 int QCPCurve::getRegion(double x, double
17847 17348 */
17848 17349 QPointF QCPCurve::getOptimizedPoint(int otherRegion, double otherKey, double otherValue, double key, double value, double rectLeft, double rectTop, double rectRight, double rectBottom) const
17849 17350 {
17850 double intersectKey = rectLeft; // initial value is just fail-safe
17851 double intersectValue = rectTop; // initial value is just fail-safe
17852 switch (otherRegion)
17351 double intersectKey = rectLeft; // initial value is just fail-safe
17352 double intersectValue = rectTop; // initial value is just fail-safe
17353 switch (otherRegion)
17853 17354 {
17854 17355 case 1: // top and left edge
17855 {
17356 {
17856 17357 intersectValue = rectTop;
17857 17358 intersectKey = otherKey + (key-otherKey)/(value-otherValue)*(intersectValue-otherValue);
17858 17359 if (intersectKey < rectLeft || intersectKey > rectRight) // doesn't intersect, so must intersect other:
17859 {
17360 {
17860 17361 intersectKey = rectLeft;
17861 17362 intersectValue = otherValue + (value-otherValue)/(key-otherKey)*(intersectKey-otherKey);
17862 }
17863 break;
17864 }
17363 }
17364 break;
17365 }
17865 17366 case 2: // left edge
17866 {
17367 {
17867 17368 intersectKey = rectLeft;
17868 17369 intersectValue = otherValue + (value-otherValue)/(key-otherKey)*(intersectKey-otherKey);
17869 17370 break;
17870 }
17371 }
17871 17372 case 3: // bottom and left edge
17872 {
17373 {
17873 17374 intersectValue = rectBottom;
17874 17375 intersectKey = otherKey + (key-otherKey)/(value-otherValue)*(intersectValue-otherValue);
17875 17376 if (intersectKey < rectLeft || intersectKey > rectRight) // doesn't intersect, so must intersect other:
17876 {
17377 {
17877 17378 intersectKey = rectLeft;
17878 17379 intersectValue = otherValue + (value-otherValue)/(key-otherKey)*(intersectKey-otherKey);
17879 }
17880 break;
17881 }
17380 }
17381 break;
17382 }
17882 17383 case 4: // top edge
17883 {
17384 {
17884 17385 intersectValue = rectTop;
17885 17386 intersectKey = otherKey + (key-otherKey)/(value-otherValue)*(intersectValue-otherValue);
17886 17387 break;
17887 }
17388 }
17888 17389 case 5:
17889 {
17390 {
17890 17391 break; // case 5 shouldn't happen for this function but we add it anyway to prevent potential discontinuity in branch table
17891 }
17392 }
17892 17393 case 6: // bottom edge
17893 {
17394 {
17894 17395 intersectValue = rectBottom;
17895 17396 intersectKey = otherKey + (key-otherKey)/(value-otherValue)*(intersectValue-otherValue);
17896 17397 break;
17897 }
17398 }
17898 17399 case 7: // top and right edge
17899 {
17400 {
17900 17401 intersectValue = rectTop;
17901 17402 intersectKey = otherKey + (key-otherKey)/(value-otherValue)*(intersectValue-otherValue);
17902 17403 if (intersectKey < rectLeft || intersectKey > rectRight) // doesn't intersect, so must intersect other:
17903 {
17404 {
17904 17405 intersectKey = rectRight;
17905 17406 intersectValue = otherValue + (value-otherValue)/(key-otherKey)*(intersectKey-otherKey);
17906 }
17907 break;
17908 }
17407 }
17408 break;
17409 }
17909 17410 case 8: // right edge
17910 {
17411 {
17911 17412 intersectKey = rectRight;
17912 17413 intersectValue = otherValue + (value-otherValue)/(key-otherKey)*(intersectKey-otherKey);
17913 17414 break;
17914 }
17415 }
17915 17416 case 9: // bottom and right edge
17916 {
17417 {
17917 17418 intersectValue = rectBottom;
17918 17419 intersectKey = otherKey + (key-otherKey)/(value-otherValue)*(intersectValue-otherValue);
17919 17420 if (intersectKey < rectLeft || intersectKey > rectRight) // doesn't intersect, so must intersect other:
17920 {
17421 {
17921 17422 intersectKey = rectRight;
17922 17423 intersectValue = otherValue + (value-otherValue)/(key-otherKey)*(intersectKey-otherKey);
17923 }
17924 break;
17925 }
17926 }
17927 return coordsToPixels(intersectKey, intersectValue);
17424 }
17425 break;
17426 }
17427 }
17428 return coordsToPixels(intersectKey, intersectValue);
17928 17429 }
17929 17430
17930 17431 /*! \internal
@@ -17947,154 +17448,154 QPointF QCPCurve::getOptimizedPoint(int
17947 17448 */
17948 17449 QVector<QPointF> QCPCurve::getOptimizedCornerPoints(int prevRegion, int currentRegion, double prevKey, double prevValue, double key, double value, double rectLeft, double rectTop, double rectRight, double rectBottom) const
17949 17450 {
17950 QVector<QPointF> result;
17951 switch (prevRegion)
17451 QVector<QPointF> result;
17452 switch (prevRegion)
17952 17453 {
17953 17454 case 1:
17954 {
17455 {
17955 17456 switch (currentRegion)
17956 {
17957 case 2: { result << coordsToPixels(rectLeft, rectTop); break; }
17958 case 4: { result << coordsToPixels(rectLeft, rectTop); break; }
17959 case 3: { result << coordsToPixels(rectLeft, rectTop) << coordsToPixels(rectLeft, rectBottom); break; }
17960 case 7: { result << coordsToPixels(rectLeft, rectTop) << coordsToPixels(rectRight, rectTop); break; }
17961 case 6: { result << coordsToPixels(rectLeft, rectTop) << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); break; }
17962 case 8: { result << coordsToPixels(rectLeft, rectTop) << coordsToPixels(rectRight, rectTop); result.append(result.last()); break; }
17963 case 9: { // in this case we need another distinction of cases: segment may pass below or above rect, requiring either bottom right or top left corner points
17964 if ((value-prevValue)/(key-prevKey)*(rectLeft-key)+value < rectBottom) // segment passes below R
17965 { result << coordsToPixels(rectLeft, rectTop) << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); result << coordsToPixels(rectRight, rectBottom); }
17966 else
17967 { result << coordsToPixels(rectLeft, rectTop) << coordsToPixels(rectRight, rectTop); result.append(result.last()); result << coordsToPixels(rectRight, rectBottom); }
17968 break;
17969 }
17970 }
17971 break;
17972 }
17457 {
17458 case 2: { result << coordsToPixels(rectLeft, rectTop); break; }
17459 case 4: { result << coordsToPixels(rectLeft, rectTop); break; }
17460 case 3: { result << coordsToPixels(rectLeft, rectTop) << coordsToPixels(rectLeft, rectBottom); break; }
17461 case 7: { result << coordsToPixels(rectLeft, rectTop) << coordsToPixels(rectRight, rectTop); break; }
17462 case 6: { result << coordsToPixels(rectLeft, rectTop) << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); break; }
17463 case 8: { result << coordsToPixels(rectLeft, rectTop) << coordsToPixels(rectRight, rectTop); result.append(result.last()); break; }
17464 case 9: { // in this case we need another distinction of cases: segment may pass below or above rect, requiring either bottom right or top left corner points
17465 if ((value-prevValue)/(key-prevKey)*(rectLeft-key)+value < rectBottom) // segment passes below R
17466 { result << coordsToPixels(rectLeft, rectTop) << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); result << coordsToPixels(rectRight, rectBottom); }
17467 else
17468 { result << coordsToPixels(rectLeft, rectTop) << coordsToPixels(rectRight, rectTop); result.append(result.last()); result << coordsToPixels(rectRight, rectBottom); }
17469 break;
17470 }
17471 }
17472 break;
17473 }
17973 17474 case 2:
17974 {
17475 {
17975 17476 switch (currentRegion)
17976 {
17977 case 1: { result << coordsToPixels(rectLeft, rectTop); break; }
17978 case 3: { result << coordsToPixels(rectLeft, rectBottom); break; }
17979 case 4: { result << coordsToPixels(rectLeft, rectTop); result.append(result.last()); break; }
17980 case 6: { result << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); break; }
17981 case 7: { result << coordsToPixels(rectLeft, rectTop); result.append(result.last()); result << coordsToPixels(rectRight, rectTop); break; }
17982 case 9: { result << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); result << coordsToPixels(rectRight, rectBottom); break; }
17983 }
17984 break;
17985 }
17477 {
17478 case 1: { result << coordsToPixels(rectLeft, rectTop); break; }
17479 case 3: { result << coordsToPixels(rectLeft, rectBottom); break; }
17480 case 4: { result << coordsToPixels(rectLeft, rectTop); result.append(result.last()); break; }
17481 case 6: { result << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); break; }
17482 case 7: { result << coordsToPixels(rectLeft, rectTop); result.append(result.last()); result << coordsToPixels(rectRight, rectTop); break; }
17483 case 9: { result << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); result << coordsToPixels(rectRight, rectBottom); break; }
17484 }
17485 break;
17486 }
17986 17487 case 3:
17987 {
17488 {
17988 17489 switch (currentRegion)
17989 {
17990 case 2: { result << coordsToPixels(rectLeft, rectBottom); break; }
17991 case 6: { result << coordsToPixels(rectLeft, rectBottom); break; }
17992 case 1: { result << coordsToPixels(rectLeft, rectBottom) << coordsToPixels(rectLeft, rectTop); break; }
17993 case 9: { result << coordsToPixels(rectLeft, rectBottom) << coordsToPixels(rectRight, rectBottom); break; }
17994 case 4: { result << coordsToPixels(rectLeft, rectBottom) << coordsToPixels(rectLeft, rectTop); result.append(result.last()); break; }
17995 case 8: { result << coordsToPixels(rectLeft, rectBottom) << coordsToPixels(rectRight, rectBottom); result.append(result.last()); break; }
17996 case 7: { // in this case we need another distinction of cases: segment may pass below or above rect, requiring either bottom right or top left corner points
17997 if ((value-prevValue)/(key-prevKey)*(rectRight-key)+value < rectBottom) // segment passes below R
17998 { result << coordsToPixels(rectLeft, rectBottom) << coordsToPixels(rectRight, rectBottom); result.append(result.last()); result << coordsToPixels(rectRight, rectTop); }
17999 else
18000 { result << coordsToPixels(rectLeft, rectBottom) << coordsToPixels(rectLeft, rectTop); result.append(result.last()); result << coordsToPixels(rectRight, rectTop); }
18001 break;
18002 }
18003 }
18004 break;
18005 }
17490 {
17491 case 2: { result << coordsToPixels(rectLeft, rectBottom); break; }
17492 case 6: { result << coordsToPixels(rectLeft, rectBottom); break; }
17493 case 1: { result << coordsToPixels(rectLeft, rectBottom) << coordsToPixels(rectLeft, rectTop); break; }
17494 case 9: { result << coordsToPixels(rectLeft, rectBottom) << coordsToPixels(rectRight, rectBottom); break; }
17495 case 4: { result << coordsToPixels(rectLeft, rectBottom) << coordsToPixels(rectLeft, rectTop); result.append(result.last()); break; }
17496 case 8: { result << coordsToPixels(rectLeft, rectBottom) << coordsToPixels(rectRight, rectBottom); result.append(result.last()); break; }
17497 case 7: { // in this case we need another distinction of cases: segment may pass below or above rect, requiring either bottom right or top left corner points
17498 if ((value-prevValue)/(key-prevKey)*(rectRight-key)+value < rectBottom) // segment passes below R
17499 { result << coordsToPixels(rectLeft, rectBottom) << coordsToPixels(rectRight, rectBottom); result.append(result.last()); result << coordsToPixels(rectRight, rectTop); }
17500 else
17501 { result << coordsToPixels(rectLeft, rectBottom) << coordsToPixels(rectLeft, rectTop); result.append(result.last()); result << coordsToPixels(rectRight, rectTop); }
17502 break;
17503 }
17504 }
17505 break;
17506 }
18006 17507 case 4:
18007 {
17508 {
18008 17509 switch (currentRegion)
18009 {
18010 case 1: { result << coordsToPixels(rectLeft, rectTop); break; }
18011 case 7: { result << coordsToPixels(rectRight, rectTop); break; }
18012 case 2: { result << coordsToPixels(rectLeft, rectTop); result.append(result.last()); break; }
18013 case 8: { result << coordsToPixels(rectRight, rectTop); result.append(result.last()); break; }
18014 case 3: { result << coordsToPixels(rectLeft, rectTop); result.append(result.last()); result << coordsToPixels(rectLeft, rectBottom); break; }
18015 case 9: { result << coordsToPixels(rectRight, rectTop); result.append(result.last()); result << coordsToPixels(rectRight, rectBottom); break; }
18016 }
18017 break;
18018 }
17510 {
17511 case 1: { result << coordsToPixels(rectLeft, rectTop); break; }
17512 case 7: { result << coordsToPixels(rectRight, rectTop); break; }
17513 case 2: { result << coordsToPixels(rectLeft, rectTop); result.append(result.last()); break; }
17514 case 8: { result << coordsToPixels(rectRight, rectTop); result.append(result.last()); break; }
17515 case 3: { result << coordsToPixels(rectLeft, rectTop); result.append(result.last()); result << coordsToPixels(rectLeft, rectBottom); break; }
17516 case 9: { result << coordsToPixels(rectRight, rectTop); result.append(result.last()); result << coordsToPixels(rectRight, rectBottom); break; }
17517 }
17518 break;
17519 }
18019 17520 case 5:
18020 {
17521 {
18021 17522 switch (currentRegion)
18022 {
18023 case 1: { result << coordsToPixels(rectLeft, rectTop); break; }
18024 case 7: { result << coordsToPixels(rectRight, rectTop); break; }
18025 case 9: { result << coordsToPixels(rectRight, rectBottom); break; }
18026 case 3: { result << coordsToPixels(rectLeft, rectBottom); break; }
18027 }
18028 break;
18029 }
17523 {
17524 case 1: { result << coordsToPixels(rectLeft, rectTop); break; }
17525 case 7: { result << coordsToPixels(rectRight, rectTop); break; }
17526 case 9: { result << coordsToPixels(rectRight, rectBottom); break; }
17527 case 3: { result << coordsToPixels(rectLeft, rectBottom); break; }
17528 }
17529 break;
17530 }
18030 17531 case 6:
18031 {
17532 {
18032 17533 switch (currentRegion)
18033 {
18034 case 3: { result << coordsToPixels(rectLeft, rectBottom); break; }
18035 case 9: { result << coordsToPixels(rectRight, rectBottom); break; }
18036 case 2: { result << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); break; }
18037 case 8: { result << coordsToPixels(rectRight, rectBottom); result.append(result.last()); break; }
18038 case 1: { result << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); result << coordsToPixels(rectLeft, rectTop); break; }
18039 case 7: { result << coordsToPixels(rectRight, rectBottom); result.append(result.last()); result << coordsToPixels(rectRight, rectTop); break; }
18040 }
18041 break;
18042 }
17534 {
17535 case 3: { result << coordsToPixels(rectLeft, rectBottom); break; }
17536 case 9: { result << coordsToPixels(rectRight, rectBottom); break; }
17537 case 2: { result << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); break; }
17538 case 8: { result << coordsToPixels(rectRight, rectBottom); result.append(result.last()); break; }
17539 case 1: { result << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); result << coordsToPixels(rectLeft, rectTop); break; }
17540 case 7: { result << coordsToPixels(rectRight, rectBottom); result.append(result.last()); result << coordsToPixels(rectRight, rectTop); break; }
17541 }
17542 break;
17543 }
18043 17544 case 7:
18044 {
17545 {
18045 17546 switch (currentRegion)
18046 {
18047 case 4: { result << coordsToPixels(rectRight, rectTop); break; }
18048 case 8: { result << coordsToPixels(rectRight, rectTop); break; }
18049 case 1: { result << coordsToPixels(rectRight, rectTop) << coordsToPixels(rectLeft, rectTop); break; }
18050 case 9: { result << coordsToPixels(rectRight, rectTop) << coordsToPixels(rectRight, rectBottom); break; }
18051 case 2: { result << coordsToPixels(rectRight, rectTop) << coordsToPixels(rectLeft, rectTop); result.append(result.last()); break; }
18052 case 6: { result << coordsToPixels(rectRight, rectTop) << coordsToPixels(rectRight, rectBottom); result.append(result.last()); break; }
18053 case 3: { // in this case we need another distinction of cases: segment may pass below or above rect, requiring either bottom right or top left corner points
18054 if ((value-prevValue)/(key-prevKey)*(rectRight-key)+value < rectBottom) // segment passes below R
18055 { result << coordsToPixels(rectRight, rectTop) << coordsToPixels(rectRight, rectBottom); result.append(result.last()); result << coordsToPixels(rectLeft, rectBottom); }
18056 else
18057 { result << coordsToPixels(rectRight, rectTop) << coordsToPixels(rectLeft, rectTop); result.append(result.last()); result << coordsToPixels(rectLeft, rectBottom); }
18058 break;
18059 }
18060 }
18061 break;
18062 }
17547 {
17548 case 4: { result << coordsToPixels(rectRight, rectTop); break; }
17549 case 8: { result << coordsToPixels(rectRight, rectTop); break; }
17550 case 1: { result << coordsToPixels(rectRight, rectTop) << coordsToPixels(rectLeft, rectTop); break; }
17551 case 9: { result << coordsToPixels(rectRight, rectTop) << coordsToPixels(rectRight, rectBottom); break; }
17552 case 2: { result << coordsToPixels(rectRight, rectTop) << coordsToPixels(rectLeft, rectTop); result.append(result.last()); break; }
17553 case 6: { result << coordsToPixels(rectRight, rectTop) << coordsToPixels(rectRight, rectBottom); result.append(result.last()); break; }
17554 case 3: { // in this case we need another distinction of cases: segment may pass below or above rect, requiring either bottom right or top left corner points
17555 if ((value-prevValue)/(key-prevKey)*(rectRight-key)+value < rectBottom) // segment passes below R
17556 { result << coordsToPixels(rectRight, rectTop) << coordsToPixels(rectRight, rectBottom); result.append(result.last()); result << coordsToPixels(rectLeft, rectBottom); }
17557 else
17558 { result << coordsToPixels(rectRight, rectTop) << coordsToPixels(rectLeft, rectTop); result.append(result.last()); result << coordsToPixels(rectLeft, rectBottom); }
17559 break;
17560 }
17561 }
17562 break;
17563 }
18063 17564 case 8:
18064 {
17565 {
18065 17566 switch (currentRegion)
18066 {
18067 case 7: { result << coordsToPixels(rectRight, rectTop); break; }
18068 case 9: { result << coordsToPixels(rectRight, rectBottom); break; }
18069 case 4: { result << coordsToPixels(rectRight, rectTop); result.append(result.last()); break; }
18070 case 6: { result << coordsToPixels(rectRight, rectBottom); result.append(result.last()); break; }
18071 case 1: { result << coordsToPixels(rectRight, rectTop); result.append(result.last()); result << coordsToPixels(rectLeft, rectTop); break; }
18072 case 3: { result << coordsToPixels(rectRight, rectBottom); result.append(result.last()); result << coordsToPixels(rectLeft, rectBottom); break; }
18073 }
18074 break;
18075 }
17567 {
17568 case 7: { result << coordsToPixels(rectRight, rectTop); break; }
17569 case 9: { result << coordsToPixels(rectRight, rectBottom); break; }
17570 case 4: { result << coordsToPixels(rectRight, rectTop); result.append(result.last()); break; }
17571 case 6: { result << coordsToPixels(rectRight, rectBottom); result.append(result.last()); break; }
17572 case 1: { result << coordsToPixels(rectRight, rectTop); result.append(result.last()); result << coordsToPixels(rectLeft, rectTop); break; }
17573 case 3: { result << coordsToPixels(rectRight, rectBottom); result.append(result.last()); result << coordsToPixels(rectLeft, rectBottom); break; }
17574 }
17575 break;
17576 }
18076 17577 case 9:
18077 {
17578 {
18078 17579 switch (currentRegion)
18079 {
18080 case 6: { result << coordsToPixels(rectRight, rectBottom); break; }
18081 case 8: { result << coordsToPixels(rectRight, rectBottom); break; }
18082 case 3: { result << coordsToPixels(rectRight, rectBottom) << coordsToPixels(rectLeft, rectBottom); break; }
18083 case 7: { result << coordsToPixels(rectRight, rectBottom) << coordsToPixels(rectRight, rectTop); break; }
18084 case 2: { result << coordsToPixels(rectRight, rectBottom) << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); break; }
18085 case 4: { result << coordsToPixels(rectRight, rectBottom) << coordsToPixels(rectRight, rectTop); result.append(result.last()); break; }
18086 case 1: { // in this case we need another distinction of cases: segment may pass below or above rect, requiring either bottom right or top left corner points
18087 if ((value-prevValue)/(key-prevKey)*(rectLeft-key)+value < rectBottom) // segment passes below R
18088 { result << coordsToPixels(rectRight, rectBottom) << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); result << coordsToPixels(rectLeft, rectTop); }
18089 else
18090 { result << coordsToPixels(rectRight, rectBottom) << coordsToPixels(rectRight, rectTop); result.append(result.last()); result << coordsToPixels(rectLeft, rectTop); }
18091 break;
18092 }
18093 }
18094 break;
18095 }
18096 }
18097 return result;
17580 {
17581 case 6: { result << coordsToPixels(rectRight, rectBottom); break; }
17582 case 8: { result << coordsToPixels(rectRight, rectBottom); break; }
17583 case 3: { result << coordsToPixels(rectRight, rectBottom) << coordsToPixels(rectLeft, rectBottom); break; }
17584 case 7: { result << coordsToPixels(rectRight, rectBottom) << coordsToPixels(rectRight, rectTop); break; }
17585 case 2: { result << coordsToPixels(rectRight, rectBottom) << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); break; }
17586 case 4: { result << coordsToPixels(rectRight, rectBottom) << coordsToPixels(rectRight, rectTop); result.append(result.last()); break; }
17587 case 1: { // in this case we need another distinction of cases: segment may pass below or above rect, requiring either bottom right or top left corner points
17588 if ((value-prevValue)/(key-prevKey)*(rectLeft-key)+value < rectBottom) // segment passes below R
17589 { result << coordsToPixels(rectRight, rectBottom) << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); result << coordsToPixels(rectLeft, rectTop); }
17590 else
17591 { result << coordsToPixels(rectRight, rectBottom) << coordsToPixels(rectRight, rectTop); result.append(result.last()); result << coordsToPixels(rectLeft, rectTop); }
17592 break;
17593 }
17594 }
17595 break;
17596 }
17597 }
17598 return result;
18098 17599 }
18099 17600
18100 17601 /*! \internal
@@ -18111,89 +17612,89 QVector<QPointF> QCPCurve::getOptimizedC
18111 17612 */
18112 17613 bool QCPCurve::mayTraverse(int prevRegion, int currentRegion) const
18113 17614 {
18114 switch (prevRegion)
17615 switch (prevRegion)
18115 17616 {
18116 17617 case 1:
18117 {
17618 {
18118 17619 switch (currentRegion)
18119 {
18120 case 4:
18121 case 7:
18122 case 2:
18123 case 3: return false;
18124 default: return true;
18125 }
18126 }
17620 {
17621 case 4:
17622 case 7:
17623 case 2:
17624 case 3: return false;
17625 default: return true;
17626 }
17627 }
18127 17628 case 2:
18128 {
17629 {
18129 17630 switch (currentRegion)
18130 {
18131 case 1:
18132 case 3: return false;
18133 default: return true;
18134 }
18135 }
17631 {
17632 case 1:
17633 case 3: return false;
17634 default: return true;
17635 }
17636 }
18136 17637 case 3:
18137 {
17638 {
18138 17639 switch (currentRegion)
18139 {
18140 case 1:
18141 case 2:
18142 case 6:
18143 case 9: return false;
18144 default: return true;
18145 }
18146 }
17640 {
17641 case 1:
17642 case 2:
17643 case 6:
17644 case 9: return false;
17645 default: return true;
17646 }
17647 }
18147 17648 case 4:
18148 {
17649 {
18149 17650 switch (currentRegion)
18150 {
18151 case 1:
18152 case 7: return false;
18153 default: return true;
18154 }
18155 }
17651 {
17652 case 1:
17653 case 7: return false;
17654 default: return true;
17655 }
17656 }
18156 17657 case 5: return false; // should never occur
18157 17658 case 6:
18158 {
17659 {
18159 17660 switch (currentRegion)
18160 {
18161 case 3:
18162 case 9: return false;
18163 default: return true;
18164 }
18165 }
17661 {
17662 case 3:
17663 case 9: return false;
17664 default: return true;
17665 }
17666 }
18166 17667 case 7:
18167 {
17668 {
18168 17669 switch (currentRegion)
18169 {
18170 case 1:
18171 case 4:
18172 case 8:
18173 case 9: return false;
18174 default: return true;
18175 }
18176 }
17670 {
17671 case 1:
17672 case 4:
17673 case 8:
17674 case 9: return false;
17675 default: return true;
17676 }
17677 }
18177 17678 case 8:
18178 {
17679 {
18179 17680 switch (currentRegion)
18180 {
18181 case 7:
18182 case 9: return false;
18183 default: return true;
18184 }
18185 }
17681 {
17682 case 7:
17683 case 9: return false;
17684 default: return true;
17685 }
17686 }
18186 17687 case 9:
18187 {
17688 {
18188 17689 switch (currentRegion)
18189 {
18190 case 3:
18191 case 6:
18192 case 8:
18193 case 7: return false;
18194 default: return true;
18195 }
18196 }
17690 {
17691 case 3:
17692 case 6:
17693 case 8:
17694 case 7: return false;
17695 default: return true;
17696 }
17697 }
18197 17698 default: return true;
18198 17699 }
18199 17700 }
@@ -18214,73 +17715,73 bool QCPCurve::mayTraverse(int prevRegio
18214 17715 */
18215 17716 bool QCPCurve::getTraverse(double prevKey, double prevValue, double key, double value, double rectLeft, double rectTop, double rectRight, double rectBottom, QPointF &crossA, QPointF &crossB) const
18216 17717 {
18217 QList<QPointF> intersections; // x of QPointF corresponds to key and y to value
18218 if (qFuzzyIsNull(key-prevKey)) // line is parallel to value axis
18219 {
18220 // due to region filter in mayTraverseR(), if line is parallel to value or key axis, R is traversed here
18221 intersections.append(QPointF(key, rectBottom)); // direction will be taken care of at end of method
18222 intersections.append(QPointF(key, rectTop));
17718 QList<QPointF> intersections; // x of QPointF corresponds to key and y to value
17719 if (qFuzzyIsNull(key-prevKey)) // line is parallel to value axis
17720 {
17721 // due to region filter in mayTraverseR(), if line is parallel to value or key axis, R is traversed here
17722 intersections.append(QPointF(key, rectBottom)); // direction will be taken care of at end of method
17723 intersections.append(QPointF(key, rectTop));
18223 17724 } else if (qFuzzyIsNull(value-prevValue)) // line is parallel to key axis
18224 17725 {
18225 // due to region filter in mayTraverseR(), if line is parallel to value or key axis, R is traversed here
18226 intersections.append(QPointF(rectLeft, value)); // direction will be taken care of at end of method
18227 intersections.append(QPointF(rectRight, value));
17726 // due to region filter in mayTraverseR(), if line is parallel to value or key axis, R is traversed here
17727 intersections.append(QPointF(rectLeft, value)); // direction will be taken care of at end of method
17728 intersections.append(QPointF(rectRight, value));
18228 17729 } else // line is skewed
18229 17730 {
18230 double gamma;
18231 double keyPerValue = (key-prevKey)/(value-prevValue);
18232 // check top of rect:
18233 gamma = prevKey + (rectTop-prevValue)*keyPerValue;
18234 if (gamma >= rectLeft && gamma <= rectRight)
18235 intersections.append(QPointF(gamma, rectTop));
18236 // check bottom of rect:
18237 gamma = prevKey + (rectBottom-prevValue)*keyPerValue;
18238 if (gamma >= rectLeft && gamma <= rectRight)
18239 intersections.append(QPointF(gamma, rectBottom));
18240 double valuePerKey = 1.0/keyPerValue;
18241 // check left of rect:
18242 gamma = prevValue + (rectLeft-prevKey)*valuePerKey;
18243 if (gamma >= rectBottom && gamma <= rectTop)
18244 intersections.append(QPointF(rectLeft, gamma));
18245 // check right of rect:
18246 gamma = prevValue + (rectRight-prevKey)*valuePerKey;
18247 if (gamma >= rectBottom && gamma <= rectTop)
18248 intersections.append(QPointF(rectRight, gamma));
18249 }
18250
18251 // handle cases where found points isn't exactly 2:
18252 if (intersections.size() > 2)
18253 {
18254 // line probably goes through corner of rect, and we got duplicate points there. single out the point pair with greatest distance in between:
18255 double distSqrMax = 0;
18256 QPointF pv1, pv2;
18257 for (int i=0; i<intersections.size()-1; ++i)
18258 {
18259 for (int k=i+1; k<intersections.size(); ++k)
18260 {
18261 QPointF distPoint = intersections.at(i)-intersections.at(k);
18262 double distSqr = distPoint.x()*distPoint.x()+distPoint.y()+distPoint.y();
18263 if (distSqr > distSqrMax)
17731 double gamma;
17732 double keyPerValue = (key-prevKey)/(value-prevValue);
17733 // check top of rect:
17734 gamma = prevKey + (rectTop-prevValue)*keyPerValue;
17735 if (gamma >= rectLeft && gamma <= rectRight)
17736 intersections.append(QPointF(gamma, rectTop));
17737 // check bottom of rect:
17738 gamma = prevKey + (rectBottom-prevValue)*keyPerValue;
17739 if (gamma >= rectLeft && gamma <= rectRight)
17740 intersections.append(QPointF(gamma, rectBottom));
17741 double valuePerKey = 1.0/keyPerValue;
17742 // check left of rect:
17743 gamma = prevValue + (rectLeft-prevKey)*valuePerKey;
17744 if (gamma >= rectBottom && gamma <= rectTop)
17745 intersections.append(QPointF(rectLeft, gamma));
17746 // check right of rect:
17747 gamma = prevValue + (rectRight-prevKey)*valuePerKey;
17748 if (gamma >= rectBottom && gamma <= rectTop)
17749 intersections.append(QPointF(rectRight, gamma));
17750 }
17751
17752 // handle cases where found points isn't exactly 2:
17753 if (intersections.size() > 2)
17754 {
17755 // line probably goes through corner of rect, and we got duplicate points there. single out the point pair with greatest distance in between:
17756 double distSqrMax = 0;
17757 QPointF pv1, pv2;
17758 for (int i=0; i<intersections.size()-1; ++i)
17759 {
17760 for (int k=i+1; k<intersections.size(); ++k)
17761 {
17762 QPointF distPoint = intersections.at(i)-intersections.at(k);
17763 double distSqr = distPoint.x()*distPoint.x()+distPoint.y()+distPoint.y();
17764 if (distSqr > distSqrMax)
18264 17765 {
18265 pv1 = intersections.at(i);
18266 pv2 = intersections.at(k);
18267 distSqrMax = distSqr;
17766 pv1 = intersections.at(i);
17767 pv2 = intersections.at(k);
17768 distSqrMax = distSqr;
18268 17769 }
18269 17770 }
18270 17771 }
18271 intersections = QList<QPointF>() << pv1 << pv2;
17772 intersections = QList<QPointF>() << pv1 << pv2;
18272 17773 } else if (intersections.size() != 2)
18273 17774 {
18274 // one or even zero points found (shouldn't happen unless line perfectly tangent to corner), no need to draw segment
18275 return false;
18276 }
18277
18278 // possibly re-sort points so optimized point segment has same direction as original segment:
18279 if ((key-prevKey)*(intersections.at(1).x()-intersections.at(0).x()) + (value-prevValue)*(intersections.at(1).y()-intersections.at(0).y()) < 0) // scalar product of both segments < 0 -> opposite direction
18280 intersections.move(0, 1);
18281 crossA = coordsToPixels(intersections.at(0).x(), intersections.at(0).y());
18282 crossB = coordsToPixels(intersections.at(1).x(), intersections.at(1).y());
18283 return true;
17775 // one or even zero points found (shouldn't happen unless line perfectly tangent to corner), no need to draw segment
17776 return false;
17777 }
17778
17779 // possibly re-sort points so optimized point segment has same direction as original segment:
17780 if ((key-prevKey)*(intersections.at(1).x()-intersections.at(0).x()) + (value-prevValue)*(intersections.at(1).y()-intersections.at(0).y()) < 0) // scalar product of both segments < 0 -> opposite direction
17781 intersections.move(0, 1);
17782 crossA = coordsToPixels(intersections.at(0).x(), intersections.at(0).y());
17783 crossB = coordsToPixels(intersections.at(1).x(), intersections.at(1).y());
17784 return true;
18284 17785 }
18285 17786
18286 17787 /*! \internal
@@ -18310,85 +17811,85 bool QCPCurve::getTraverse(double prevKe
18310 17811 */
18311 17812 void QCPCurve::getTraverseCornerPoints(int prevRegion, int currentRegion, double rectLeft, double rectTop, double rectRight, double rectBottom, QVector<QPointF> &beforeTraverse, QVector<QPointF> &afterTraverse) const
18312 17813 {
18313 switch (prevRegion)
17814 switch (prevRegion)
18314 17815 {
18315 17816 case 1:
18316 {
17817 {
18317 17818 switch (currentRegion)
18318 {
18319 case 6: { beforeTraverse << coordsToPixels(rectLeft, rectTop); break; }
18320 case 9: { beforeTraverse << coordsToPixels(rectLeft, rectTop); afterTraverse << coordsToPixels(rectRight, rectBottom); break; }
18321 case 8: { beforeTraverse << coordsToPixels(rectLeft, rectTop); break; }
18322 }
18323 break;
18324 }
17819 {
17820 case 6: { beforeTraverse << coordsToPixels(rectLeft, rectTop); break; }
17821 case 9: { beforeTraverse << coordsToPixels(rectLeft, rectTop); afterTraverse << coordsToPixels(rectRight, rectBottom); break; }
17822 case 8: { beforeTraverse << coordsToPixels(rectLeft, rectTop); break; }
17823 }
17824 break;
17825 }
18325 17826 case 2:
18326 {
17827 {
18327 17828 switch (currentRegion)
18328 {
18329 case 7: { afterTraverse << coordsToPixels(rectRight, rectTop); break; }
18330 case 9: { afterTraverse << coordsToPixels(rectRight, rectBottom); break; }
18331 }
18332 break;
18333 }
17829 {
17830 case 7: { afterTraverse << coordsToPixels(rectRight, rectTop); break; }
17831 case 9: { afterTraverse << coordsToPixels(rectRight, rectBottom); break; }
17832 }
17833 break;
17834 }
18334 17835 case 3:
18335 {
17836 {
18336 17837 switch (currentRegion)
18337 {
18338 case 4: { beforeTraverse << coordsToPixels(rectLeft, rectBottom); break; }
18339 case 7: { beforeTraverse << coordsToPixels(rectLeft, rectBottom); afterTraverse << coordsToPixels(rectRight, rectTop); break; }
18340 case 8: { beforeTraverse << coordsToPixels(rectLeft, rectBottom); break; }
18341 }
18342 break;
18343 }
17838 {
17839 case 4: { beforeTraverse << coordsToPixels(rectLeft, rectBottom); break; }
17840 case 7: { beforeTraverse << coordsToPixels(rectLeft, rectBottom); afterTraverse << coordsToPixels(rectRight, rectTop); break; }
17841 case 8: { beforeTraverse << coordsToPixels(rectLeft, rectBottom); break; }
17842 }
17843 break;
17844 }
18344 17845 case 4:
18345 {
17846 {
18346 17847 switch (currentRegion)
18347 {
18348 case 3: { afterTraverse << coordsToPixels(rectLeft, rectBottom); break; }
18349 case 9: { afterTraverse << coordsToPixels(rectRight, rectBottom); break; }
18350 }
18351 break;
18352 }
17848 {
17849 case 3: { afterTraverse << coordsToPixels(rectLeft, rectBottom); break; }
17850 case 9: { afterTraverse << coordsToPixels(rectRight, rectBottom); break; }
17851 }
17852 break;
17853 }
18353 17854 case 5: { break; } // shouldn't happen because this method only handles full traverses
18354 17855 case 6:
18355 {
17856 {
18356 17857 switch (currentRegion)
18357 {
18358 case 1: { afterTraverse << coordsToPixels(rectLeft, rectTop); break; }
18359 case 7: { afterTraverse << coordsToPixels(rectRight, rectTop); break; }
18360 }
18361 break;
18362 }
17858 {
17859 case 1: { afterTraverse << coordsToPixels(rectLeft, rectTop); break; }
17860 case 7: { afterTraverse << coordsToPixels(rectRight, rectTop); break; }
17861 }
17862 break;
17863 }
18363 17864 case 7:
18364 {
17865 {
18365 17866 switch (currentRegion)
18366 {
18367 case 2: { beforeTraverse << coordsToPixels(rectRight, rectTop); break; }
18368 case 3: { beforeTraverse << coordsToPixels(rectRight, rectTop); afterTraverse << coordsToPixels(rectLeft, rectBottom); break; }
18369 case 6: { beforeTraverse << coordsToPixels(rectRight, rectTop); break; }
18370 }
18371 break;
18372 }
17867 {
17868 case 2: { beforeTraverse << coordsToPixels(rectRight, rectTop); break; }
17869 case 3: { beforeTraverse << coordsToPixels(rectRight, rectTop); afterTraverse << coordsToPixels(rectLeft, rectBottom); break; }
17870 case 6: { beforeTraverse << coordsToPixels(rectRight, rectTop); break; }
17871 }
17872 break;
17873 }
18373 17874 case 8:
18374 {
17875 {
18375 17876 switch (currentRegion)
18376 {
18377 case 1: { afterTraverse << coordsToPixels(rectLeft, rectTop); break; }
18378 case 3: { afterTraverse << coordsToPixels(rectLeft, rectBottom); break; }
18379 }
18380 break;
18381 }
17877 {
17878 case 1: { afterTraverse << coordsToPixels(rectLeft, rectTop); break; }
17879 case 3: { afterTraverse << coordsToPixels(rectLeft, rectBottom); break; }
17880 }
17881 break;
17882 }
18382 17883 case 9:
18383 {
17884 {
18384 17885 switch (currentRegion)
18385 {
18386 case 2: { beforeTraverse << coordsToPixels(rectRight, rectBottom); break; }
18387 case 1: { beforeTraverse << coordsToPixels(rectRight, rectBottom); afterTraverse << coordsToPixels(rectLeft, rectTop); break; }
18388 case 4: { beforeTraverse << coordsToPixels(rectRight, rectBottom); break; }
18389 }
18390 break;
18391 }
17886 {
17887 case 2: { beforeTraverse << coordsToPixels(rectRight, rectBottom); break; }
17888 case 1: { beforeTraverse << coordsToPixels(rectRight, rectBottom); afterTraverse << coordsToPixels(rectLeft, rectTop); break; }
17889 case 4: { beforeTraverse << coordsToPixels(rectRight, rectBottom); break; }
17890 }
17891 break;
17892 }
18392 17893 }
18393 17894 }
18394 17895
@@ -18400,95 +17901,95 void QCPCurve::getTraverseCornerPoints(i
18400 17901 */
18401 17902 double QCPCurve::pointDistance(const QPointF &pixelPoint) const
18402 17903 {
18403 if (mData->isEmpty())
18404 {
18405 qDebug() << Q_FUNC_INFO << "requested point distance on curve" << mName << "without data";
18406 return 500;
18407 }
18408 if (mData->size() == 1)
18409 {
18410 QPointF dataPoint = coordsToPixels(mData->constBegin().key(), mData->constBegin().value().value);
18411 return QVector2D(dataPoint-pixelPoint).length();
18412 }
18413
18414 // calculate minimum distance to line segments:
18415 QVector<QPointF> *lineData = new QVector<QPointF>;
18416 getCurveData(lineData);
18417 double minDistSqr = std::numeric_limits<double>::max();
18418 for (int i=0; i<lineData->size()-1; ++i)
18419 {
18420 double currentDistSqr = distSqrToLine(lineData->at(i), lineData->at(i+1), pixelPoint);
18421 if (currentDistSqr < minDistSqr)
18422 minDistSqr = currentDistSqr;
18423 }
18424 delete lineData;
18425 return qSqrt(minDistSqr);
17904 if (mData->isEmpty())
17905 {
17906 qDebug() << Q_FUNC_INFO << "requested point distance on curve" << mName << "without data";
17907 return 500;
17908 }
17909 if (mData->size() == 1)
17910 {
17911 QPointF dataPoint = coordsToPixels(mData->constBegin().key(), mData->constBegin().value().value);
17912 return QVector2D(dataPoint-pixelPoint).length();
17913 }
17914
17915 // calculate minimum distance to line segments:
17916 QVector<QPointF> *lineData = new QVector<QPointF>;
17917 getCurveData(lineData);
17918 double minDistSqr = std::numeric_limits<double>::max();
17919 for (int i=0; i<lineData->size()-1; ++i)
17920 {
17921 double currentDistSqr = distSqrToLine(lineData->at(i), lineData->at(i+1), pixelPoint);
17922 if (currentDistSqr < minDistSqr)
17923 minDistSqr = currentDistSqr;
17924 }
17925 delete lineData;
17926 return qSqrt(minDistSqr);
18426 17927 }
18427 17928
18428 17929 /* inherits documentation from base class */
18429 17930 QCPRange QCPCurve::getKeyRange(bool &foundRange, SignDomain inSignDomain) const
18430 17931 {
18431 QCPRange range;
18432 bool haveLower = false;
18433 bool haveUpper = false;
18434
18435 double current;
18436
18437 QCPCurveDataMap::const_iterator it = mData->constBegin();
18438 while (it != mData->constEnd())
18439 {
18440 current = it.value().key;
18441 if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current < 0) || (inSignDomain == sdPositive && current > 0))
18442 {
18443 if (current < range.lower || !haveLower)
18444 {
18445 range.lower = current;
18446 haveLower = true;
18447 }
18448 if (current > range.upper || !haveUpper)
18449 {
18450 range.upper = current;
18451 haveUpper = true;
18452 }
18453 }
18454 ++it;
18455 }
18456
18457 foundRange = haveLower && haveUpper;
18458 return range;
17932 QCPRange range;
17933 bool haveLower = false;
17934 bool haveUpper = false;
17935
17936 double current;
17937
17938 QCPCurveDataMap::const_iterator it = mData->constBegin();
17939 while (it != mData->constEnd())
17940 {
17941 current = it.value().key;
17942 if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current < 0) || (inSignDomain == sdPositive && current > 0))
17943 {
17944 if (current < range.lower || !haveLower)
17945 {
17946 range.lower = current;
17947 haveLower = true;
17948 }
17949 if (current > range.upper || !haveUpper)
17950 {
17951 range.upper = current;
17952 haveUpper = true;
17953 }
17954 }
17955 ++it;
17956 }
17957
17958 foundRange = haveLower && haveUpper;
17959 return range;
18459 17960 }
18460 17961
18461 17962 /* inherits documentation from base class */
18462 17963 QCPRange QCPCurve::getValueRange(bool &foundRange, SignDomain inSignDomain) const
18463 17964 {
18464 QCPRange range;
18465 bool haveLower = false;
18466 bool haveUpper = false;
18467
18468 double current;
18469
18470 QCPCurveDataMap::const_iterator it = mData->constBegin();
18471 while (it != mData->constEnd())
18472 {
18473 current = it.value().value;
18474 if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current < 0) || (inSignDomain == sdPositive && current > 0))
18475 {
18476 if (current < range.lower || !haveLower)
18477 {
18478 range.lower = current;
18479 haveLower = true;
18480 }
18481 if (current > range.upper || !haveUpper)
18482 {
18483 range.upper = current;
18484 haveUpper = true;
18485 }
18486 }
18487 ++it;
18488 }
18489
18490 foundRange = haveLower && haveUpper;
18491 return range;
17965 QCPRange range;
17966 bool haveLower = false;
17967 bool haveUpper = false;
17968
17969 double current;
17970
17971 QCPCurveDataMap::const_iterator it = mData->constBegin();
17972 while (it != mData->constEnd())
17973 {
17974 current = it.value().value;
17975 if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current < 0) || (inSignDomain == sdPositive && current > 0))
17976 {
17977 if (current < range.lower || !haveLower)
17978 {
17979 range.lower = current;
17980 haveLower = true;
17981 }
17982 if (current > range.upper || !haveUpper)
17983 {
17984 range.upper = current;
17985 haveUpper = true;
17986 }
17987 }
17988 ++it;
17989 }
17990
17991 foundRange = haveLower && haveUpper;
17992 return range;
18492 17993 }
18493 17994
18494 17995
@@ -18563,16 +18064,16 QCPRange QCPCurve::getValueRange(bool &f
18563 18064 Constructs a new bars group for the specified QCustomPlot instance.
18564 18065 */
18565 18066 QCPBarsGroup::QCPBarsGroup(QCustomPlot *parentPlot) :
18566 QObject(parentPlot),
18567 mParentPlot(parentPlot),
18568 mSpacingType(stAbsolute),
18569 mSpacing(4)
18067 QObject(parentPlot),
18068 mParentPlot(parentPlot),
18069 mSpacingType(stAbsolute),
18070 mSpacing(4)
18570 18071 {
18571 18072 }
18572 18073
18573 18074 QCPBarsGroup::~QCPBarsGroup()
18574 18075 {
18575 clear();
18076 clear();
18576 18077 }
18577 18078
18578 18079 /*!
@@ -18584,7 +18085,7 QCPBarsGroup::~QCPBarsGroup()
18584 18085 */
18585 18086 void QCPBarsGroup::setSpacingType(SpacingType spacingType)
18586 18087 {
18587 mSpacingType = spacingType;
18088 mSpacingType = spacingType;
18588 18089 }
18589 18090
18590 18091 /*!
@@ -18595,7 +18096,7 void QCPBarsGroup::setSpacingType(Spacin
18595 18096 */
18596 18097 void QCPBarsGroup::setSpacing(double spacing)
18597 18098 {
18598 mSpacing = spacing;
18099 mSpacing = spacing;
18599 18100 }
18600 18101
18601 18102 /*!
@@ -18606,13 +18107,13 void QCPBarsGroup::setSpacing(double spa
18606 18107 */
18607 18108 QCPBars *QCPBarsGroup::bars(int index) const
18608 18109 {
18609 if (index >= 0 && index < mBars.size())
18610 {
18611 return mBars.at(index);
18612 } else
18613 {
18614 qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
18615 return 0;
18110 if (index >= 0 && index < mBars.size())
18111 {
18112 return mBars.at(index);
18113 } else
18114 {
18115 qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
18116 return 0;
18616 18117 }
18617 18118 }
18618 18119
@@ -18623,8 +18124,8 QCPBars *QCPBarsGroup::bars(int index) c
18623 18124 */
18624 18125 void QCPBarsGroup::clear()
18625 18126 {
18626 foreach (QCPBars *bars, mBars) // since foreach takes a copy, removing bars in the loop is okay
18627 bars->setBarsGroup(0); // removes itself via removeBars
18127 foreach (QCPBars *bars, mBars) // since foreach takes a copy, removing bars in the loop is okay
18128 bars->setBarsGroup(0); // removes itself via removeBars
18628 18129 }
18629 18130
18630 18131 /*!
@@ -18635,16 +18136,16 void QCPBarsGroup::clear()
18635 18136 */
18636 18137 void QCPBarsGroup::append(QCPBars *bars)
18637 18138 {
18638 if (!bars)
18639 {
18640 qDebug() << Q_FUNC_INFO << "bars is 0";
18641 return;
18642 }
18643
18644 if (!mBars.contains(bars))
18645 bars->setBarsGroup(this);
18646 else
18647 qDebug() << Q_FUNC_INFO << "bars plottable is already in this bars group:" << reinterpret_cast<quintptr>(bars);
18139 if (!bars)
18140 {
18141 qDebug() << Q_FUNC_INFO << "bars is 0";
18142 return;
18143 }
18144
18145 if (!mBars.contains(bars))
18146 bars->setBarsGroup(this);
18147 else
18148 qDebug() << Q_FUNC_INFO << "bars plottable is already in this bars group:" << reinterpret_cast<quintptr>(bars);
18648 18149 }
18649 18150
18650 18151 /*!
@@ -18658,17 +18159,17 void QCPBarsGroup::append(QCPBars *bars)
18658 18159 */
18659 18160 void QCPBarsGroup::insert(int i, QCPBars *bars)
18660 18161 {
18661 if (!bars)
18662 {
18663 qDebug() << Q_FUNC_INFO << "bars is 0";
18664 return;
18665 }
18666
18667 // first append to bars list normally:
18668 if (!mBars.contains(bars))
18669 bars->setBarsGroup(this);
18670 // then move to according position:
18671 mBars.move(mBars.indexOf(bars), qBound(0, i, mBars.size()-1));
18162 if (!bars)
18163 {
18164 qDebug() << Q_FUNC_INFO << "bars is 0";
18165 return;
18166 }
18167
18168 // first append to bars list normally:
18169 if (!mBars.contains(bars))
18170 bars->setBarsGroup(this);
18171 // then move to according position:
18172 mBars.move(mBars.indexOf(bars), qBound(0, i, mBars.size()-1));
18672 18173 }
18673 18174
18674 18175 /*!
@@ -18678,16 +18179,16 void QCPBarsGroup::insert(int i, QCPBars
18678 18179 */
18679 18180 void QCPBarsGroup::remove(QCPBars *bars)
18680 18181 {
18681 if (!bars)
18682 {
18683 qDebug() << Q_FUNC_INFO << "bars is 0";
18684 return;
18685 }
18686
18687 if (mBars.contains(bars))
18688 bars->setBarsGroup(0);
18689 else
18690 qDebug() << Q_FUNC_INFO << "bars plottable is not in this bars group:" << reinterpret_cast<quintptr>(bars);
18182 if (!bars)
18183 {
18184 qDebug() << Q_FUNC_INFO << "bars is 0";
18185 return;
18186 }
18187
18188 if (mBars.contains(bars))
18189 bars->setBarsGroup(0);
18190 else
18191 qDebug() << Q_FUNC_INFO << "bars plottable is not in this bars group:" << reinterpret_cast<quintptr>(bars);
18691 18192 }
18692 18193
18693 18194 /*! \internal
@@ -18699,8 +18200,8 void QCPBarsGroup::remove(QCPBars *bars)
18699 18200 */
18700 18201 void QCPBarsGroup::registerBars(QCPBars *bars)
18701 18202 {
18702 if (!mBars.contains(bars))
18703 mBars.append(bars);
18203 if (!mBars.contains(bars))
18204 mBars.append(bars);
18704 18205 }
18705 18206
18706 18207 /*! \internal
@@ -18712,7 +18213,7 void QCPBarsGroup::registerBars(QCPBars
18712 18213 */
18713 18214 void QCPBarsGroup::unregisterBars(QCPBars *bars)
18714 18215 {
18715 mBars.removeOne(bars);
18216 mBars.removeOne(bars);
18716 18217 }
18717 18218
18718 18219 /*! \internal
@@ -18723,77 +18224,77 void QCPBarsGroup::unregisterBars(QCPBar
18723 18224 */
18724 18225 double QCPBarsGroup::keyPixelOffset(const QCPBars *bars, double keyCoord)
18725 18226 {
18726 // find list of all base bars in case some mBars are stacked:
18727 QList<const QCPBars*> baseBars;
18728 foreach (const QCPBars *b, mBars)
18729 {
18730 while (b->barBelow())
18731 b = b->barBelow();
18732 if (!baseBars.contains(b))
18733 baseBars.append(b);
18734 }
18735 // find base bar this "bars" is stacked on:
18736 const QCPBars *thisBase = bars;
18737 while (thisBase->barBelow())
18738 thisBase = thisBase->barBelow();
18739
18740 // determine key pixel offset of this base bars considering all other base bars in this barsgroup:
18741 double result = 0;
18742 int index = baseBars.indexOf(thisBase);
18743 if (index >= 0)
18744 {
18745 int startIndex;
18746 double lowerPixelWidth, upperPixelWidth;
18747 if (baseBars.size() % 2 == 1 && index == (baseBars.size()-1)/2) // is center bar (int division on purpose)
18748 {
18749 return result;
18227 // find list of all base bars in case some mBars are stacked:
18228 QList<const QCPBars*> baseBars;
18229 foreach (const QCPBars *b, mBars)
18230 {
18231 while (b->barBelow())
18232 b = b->barBelow();
18233 if (!baseBars.contains(b))
18234 baseBars.append(b);
18235 }
18236 // find base bar this "bars" is stacked on:
18237 const QCPBars *thisBase = bars;
18238 while (thisBase->barBelow())
18239 thisBase = thisBase->barBelow();
18240
18241 // determine key pixel offset of this base bars considering all other base bars in this barsgroup:
18242 double result = 0;
18243 int index = baseBars.indexOf(thisBase);
18244 if (index >= 0)
18245 {
18246 int startIndex;
18247 double lowerPixelWidth, upperPixelWidth;
18248 if (baseBars.size() % 2 == 1 && index == (baseBars.size()-1)/2) // is center bar (int division on purpose)
18249 {
18250 return result;
18750 18251 } else if (index < (baseBars.size()-1)/2.0) // bar is to the left of center
18751 18252 {
18752 if (baseBars.size() % 2 == 0) // even number of bars
18753 {
18754 startIndex = baseBars.size()/2-1;
18755 result -= getPixelSpacing(baseBars.at(startIndex), keyCoord)*0.5; // half of middle spacing
18253 if (baseBars.size() % 2 == 0) // even number of bars
18254 {
18255 startIndex = baseBars.size()/2-1;
18256 result -= getPixelSpacing(baseBars.at(startIndex), keyCoord)*0.5; // half of middle spacing
18756 18257 } else // uneven number of bars
18757 18258 {
18758 startIndex = (baseBars.size()-1)/2-1;
18759 baseBars.at((baseBars.size()-1)/2)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth);
18760 result -= qAbs(upperPixelWidth-lowerPixelWidth)*0.5; // half of center bar
18761 result -= getPixelSpacing(baseBars.at((baseBars.size()-1)/2), keyCoord); // center bar spacing
18762 }
18763 for (int i=startIndex; i>index; --i) // add widths and spacings of bars in between center and our bars
18764 {
18765 baseBars.at(i)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth);
18766 result -= qAbs(upperPixelWidth-lowerPixelWidth);
18767 result -= getPixelSpacing(baseBars.at(i), keyCoord);
18768 }
18769 // finally half of our bars width:
18770 baseBars.at(index)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth);
18771 result -= qAbs(upperPixelWidth-lowerPixelWidth)*0.5;
18259 startIndex = (baseBars.size()-1)/2-1;
18260 baseBars.at((baseBars.size()-1)/2)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth);
18261 result -= qAbs(upperPixelWidth-lowerPixelWidth)*0.5; // half of center bar
18262 result -= getPixelSpacing(baseBars.at((baseBars.size()-1)/2), keyCoord); // center bar spacing
18263 }
18264 for (int i=startIndex; i>index; --i) // add widths and spacings of bars in between center and our bars
18265 {
18266 baseBars.at(i)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth);
18267 result -= qAbs(upperPixelWidth-lowerPixelWidth);
18268 result -= getPixelSpacing(baseBars.at(i), keyCoord);
18269 }
18270 // finally half of our bars width:
18271 baseBars.at(index)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth);
18272 result -= qAbs(upperPixelWidth-lowerPixelWidth)*0.5;
18772 18273 } else // bar is to the right of center
18773 18274 {
18774 if (baseBars.size() % 2 == 0) // even number of bars
18775 {
18776 startIndex = baseBars.size()/2;
18777 result += getPixelSpacing(baseBars.at(startIndex), keyCoord)*0.5; // half of middle spacing
18275 if (baseBars.size() % 2 == 0) // even number of bars
18276 {
18277 startIndex = baseBars.size()/2;
18278 result += getPixelSpacing(baseBars.at(startIndex), keyCoord)*0.5; // half of middle spacing
18778 18279 } else // uneven number of bars
18779 18280 {
18780 startIndex = (baseBars.size()-1)/2+1;
18781 baseBars.at((baseBars.size()-1)/2)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth);
18782 result += qAbs(upperPixelWidth-lowerPixelWidth)*0.5; // half of center bar
18783 result += getPixelSpacing(baseBars.at((baseBars.size()-1)/2), keyCoord); // center bar spacing
18784 }
18785 for (int i=startIndex; i<index; ++i) // add widths and spacings of bars in between center and our bars
18786 {
18787 baseBars.at(i)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth);
18788 result += qAbs(upperPixelWidth-lowerPixelWidth);
18789 result += getPixelSpacing(baseBars.at(i), keyCoord);
18790 }
18791 // finally half of our bars width:
18792 baseBars.at(index)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth);
18793 result += qAbs(upperPixelWidth-lowerPixelWidth)*0.5;
18794 }
18795 }
18796 return result;
18281 startIndex = (baseBars.size()-1)/2+1;
18282 baseBars.at((baseBars.size()-1)/2)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth);
18283 result += qAbs(upperPixelWidth-lowerPixelWidth)*0.5; // half of center bar
18284 result += getPixelSpacing(baseBars.at((baseBars.size()-1)/2), keyCoord); // center bar spacing
18285 }
18286 for (int i=startIndex; i<index; ++i) // add widths and spacings of bars in between center and our bars
18287 {
18288 baseBars.at(i)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth);
18289 result += qAbs(upperPixelWidth-lowerPixelWidth);
18290 result += getPixelSpacing(baseBars.at(i), keyCoord);
18291 }
18292 // finally half of our bars width:
18293 baseBars.at(index)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth);
18294 result += qAbs(upperPixelWidth-lowerPixelWidth)*0.5;
18295 }
18296 }
18297 return result;
18797 18298 }
18798 18299
18799 18300 /*! \internal
@@ -18808,26 +18309,26 double QCPBarsGroup::keyPixelOffset(cons
18808 18309 */
18809 18310 double QCPBarsGroup::getPixelSpacing(const QCPBars *bars, double keyCoord)
18810 18311 {
18811 switch (mSpacingType)
18312 switch (mSpacingType)
18812 18313 {
18813 18314 case stAbsolute:
18814 {
18315 {
18815 18316 return mSpacing;
18816 }
18317 }
18817 18318 case stAxisRectRatio:
18818 {
18319 {
18819 18320 if (bars->keyAxis()->orientation() == Qt::Horizontal)
18820 return bars->keyAxis()->axisRect()->width()*mSpacing;
18321 return bars->keyAxis()->axisRect()->width()*mSpacing;
18821 18322 else
18822 return bars->keyAxis()->axisRect()->height()*mSpacing;
18823 }
18323 return bars->keyAxis()->axisRect()->height()*mSpacing;
18324 }
18824 18325 case stPlotCoords:
18825 {
18326 {
18826 18327 double keyPixel = bars->keyAxis()->coordToPixel(keyCoord);
18827 18328 return bars->keyAxis()->coordToPixel(keyCoord+mSpacing)-keyPixel;
18828 }
18829 }
18830 return 0;
18329 }
18330 }
18331 return 0;
18831 18332 }
18832 18333
18833 18334
@@ -18851,8 +18352,8 double QCPBarsGroup::getPixelSpacing(con
18851 18352 Constructs a bar data point with key and value set to zero.
18852 18353 */
18853 18354 QCPBarData::QCPBarData() :
18854 key(0),
18855 value(0)
18355 key(0),
18356 value(0)
18856 18357 {
18857 18358 }
18858 18359
@@ -18860,8 +18361,8 QCPBarData::QCPBarData() :
18860 18361 Constructs a bar data point with the specified \a key and \a value.
18861 18362 */
18862 18363 QCPBarData::QCPBarData(double key, double value) :
18863 key(key),
18864 value(value)
18364 key(key),
18365 value(value)
18865 18366 {
18866 18367 }
18867 18368
@@ -18937,30 +18438,30 QCPBarData::QCPBarData(double key, doubl
18937 18438 then takes ownership of the bar chart.
18938 18439 */
18939 18440 QCPBars::QCPBars(QCPAxis *keyAxis, QCPAxis *valueAxis) :
18940 QCPAbstractPlottable(keyAxis, valueAxis),
18941 mData(new QCPBarDataMap),
18942 mWidth(0.75),
18943 mWidthType(wtPlotCoords),
18944 mBarsGroup(0),
18945 mBaseValue(0)
18946 {
18947 // modify inherited properties from abstract plottable:
18948 mPen.setColor(Qt::blue);
18949 mPen.setStyle(Qt::SolidLine);
18950 mBrush.setColor(QColor(40, 50, 255, 30));
18951 mBrush.setStyle(Qt::SolidPattern);
18952 mSelectedPen = mPen;
18953 mSelectedPen.setWidthF(2.5);
18954 mSelectedPen.setColor(QColor(80, 80, 255)); // lighter than Qt::blue of mPen
18955 mSelectedBrush = mBrush;
18441 QCPAbstractPlottable(keyAxis, valueAxis),
18442 mData(new QCPBarDataMap),
18443 mWidth(0.75),
18444 mWidthType(wtPlotCoords),
18445 mBarsGroup(0),
18446 mBaseValue(0)
18447 {
18448 // modify inherited properties from abstract plottable:
18449 mPen.setColor(Qt::blue);
18450 mPen.setStyle(Qt::SolidLine);
18451 mBrush.setColor(QColor(40, 50, 255, 30));
18452 mBrush.setStyle(Qt::SolidPattern);
18453 mSelectedPen = mPen;
18454 mSelectedPen.setWidthF(2.5);
18455 mSelectedPen.setColor(QColor(80, 80, 255)); // lighter than Qt::blue of mPen
18456 mSelectedBrush = mBrush;
18956 18457 }
18957 18458
18958 18459 QCPBars::~QCPBars()
18959 18460 {
18960 setBarsGroup(0);
18961 if (mBarBelow || mBarAbove)
18962 connectBars(mBarBelow.data(), mBarAbove.data()); // take this bar out of any stacking
18963 delete mData;
18461 setBarsGroup(0);
18462 if (mBarBelow || mBarAbove)
18463 connectBars(mBarBelow.data(), mBarAbove.data()); // take this bar out of any stacking
18464 delete mData;
18964 18465 }
18965 18466
18966 18467 /*!
@@ -18971,7 +18472,7 QCPBars::~QCPBars()
18971 18472 */
18972 18473 void QCPBars::setWidth(double width)
18973 18474 {
18974 mWidth = width;
18475 mWidth = width;
18975 18476 }
18976 18477
18977 18478 /*!
@@ -18984,7 +18485,7 void QCPBars::setWidth(double width)
18984 18485 */
18985 18486 void QCPBars::setWidthType(QCPBars::WidthType widthType)
18986 18487 {
18987 mWidthType = widthType;
18488 mWidthType = widthType;
18988 18489 }
18989 18490
18990 18491 /*!
@@ -18995,13 +18496,13 void QCPBars::setWidthType(QCPBars::Widt
18995 18496 */
18996 18497 void QCPBars::setBarsGroup(QCPBarsGroup *barsGroup)
18997 18498 {
18998 // deregister at old group:
18999 if (mBarsGroup)
19000 mBarsGroup->unregisterBars(this);
19001 mBarsGroup = barsGroup;
19002 // register at new group:
19003 if (mBarsGroup)
19004 mBarsGroup->registerBars(this);
18499 // deregister at old group:
18500 if (mBarsGroup)
18501 mBarsGroup->unregisterBars(this);
18502 mBarsGroup = barsGroup;
18503 // register at new group:
18504 if (mBarsGroup)
18505 mBarsGroup->registerBars(this);
19005 18506 }
19006 18507
19007 18508 /*!
@@ -19018,7 +18519,7 void QCPBars::setBarsGroup(QCPBarsGroup
19018 18519 */
19019 18520 void QCPBars::setBaseValue(double baseValue)
19020 18521 {
19021 mBaseValue = baseValue;
18522 mBaseValue = baseValue;
19022 18523 }
19023 18524
19024 18525 /*!
@@ -19030,18 +18531,18 void QCPBars::setBaseValue(double baseVa
19030 18531 */
19031 18532 void QCPBars::setData(QCPBarDataMap *data, bool copy)
19032 18533 {
19033 if (mData == data)
19034 {
19035 qDebug() << Q_FUNC_INFO << "The data pointer is already in (and owned by) this plottable" << reinterpret_cast<quintptr>(data);
19036 return;
19037 }
19038 if (copy)
19039 {
19040 *mData = *data;
19041 } else
19042 {
19043 delete mData;
19044 mData = data;
18534 if (mData == data)
18535 {
18536 qDebug() << Q_FUNC_INFO << "The data pointer is already in (and owned by) this plottable" << reinterpret_cast<quintptr>(data);
18537 return;
18538 }
18539 if (copy)
18540 {
18541 *mData = *data;
18542 } else
18543 {
18544 delete mData;
18545 mData = data;
19045 18546 }
19046 18547 }
19047 18548
@@ -19053,15 +18554,15 void QCPBars::setData(QCPBarDataMap *dat
19053 18554 */
19054 18555 void QCPBars::setData(const QVector<double> &key, const QVector<double> &value)
19055 18556 {
19056 mData->clear();
19057 int n = key.size();
19058 n = qMin(n, value.size());
19059 QCPBarData newData;
19060 for (int i=0; i<n; ++i)
19061 {
19062 newData.key = key[i];
19063 newData.value = value[i];
19064 mData->insertMulti(newData.key, newData);
18557 mData->clear();
18558 int n = key.size();
18559 n = qMin(n, value.size());
18560 QCPBarData newData;
18561 for (int i=0; i<n; ++i)
18562 {
18563 newData.key = key[i];
18564 newData.value = value[i];
18565 mData->insertMulti(newData.key, newData);
19065 18566 }
19066 18567 }
19067 18568
@@ -19081,20 +18582,20 void QCPBars::setData(const QVector<doub
19081 18582 */
19082 18583 void QCPBars::moveBelow(QCPBars *bars)
19083 18584 {
19084 if (bars == this) return;
19085 if (bars && (bars->keyAxis() != mKeyAxis.data() || bars->valueAxis() != mValueAxis.data()))
19086 {
19087 qDebug() << Q_FUNC_INFO << "passed QCPBars* doesn't have same key and value axis as this QCPBars";
19088 return;
19089 }
19090 // remove from stacking:
19091 connectBars(mBarBelow.data(), mBarAbove.data()); // Note: also works if one (or both) of them is 0
19092 // if new bar given, insert this bar below it:
19093 if (bars)
19094 {
19095 if (bars->mBarBelow)
19096 connectBars(bars->mBarBelow.data(), this);
19097 connectBars(this, bars);
18585 if (bars == this) return;
18586 if (bars && (bars->keyAxis() != mKeyAxis.data() || bars->valueAxis() != mValueAxis.data()))
18587 {
18588 qDebug() << Q_FUNC_INFO << "passed QCPBars* doesn't have same key and value axis as this QCPBars";
18589 return;
18590 }
18591 // remove from stacking:
18592 connectBars(mBarBelow.data(), mBarAbove.data()); // Note: also works if one (or both) of them is 0
18593 // if new bar given, insert this bar below it:
18594 if (bars)
18595 {
18596 if (bars->mBarBelow)
18597 connectBars(bars->mBarBelow.data(), this);
18598 connectBars(this, bars);
19098 18599 }
19099 18600 }
19100 18601
@@ -19114,20 +18615,20 void QCPBars::moveBelow(QCPBars *bars)
19114 18615 */
19115 18616 void QCPBars::moveAbove(QCPBars *bars)
19116 18617 {
19117 if (bars == this) return;
19118 if (bars && (bars->keyAxis() != mKeyAxis.data() || bars->valueAxis() != mValueAxis.data()))
19119 {
19120 qDebug() << Q_FUNC_INFO << "passed QCPBars* doesn't have same key and value axis as this QCPBars";
19121 return;
19122 }
19123 // remove from stacking:
19124 connectBars(mBarBelow.data(), mBarAbove.data()); // Note: also works if one (or both) of them is 0
19125 // if new bar given, insert this bar above it:
19126 if (bars)
19127 {
19128 if (bars->mBarAbove)
19129 connectBars(this, bars->mBarAbove.data());
19130 connectBars(bars, this);
18618 if (bars == this) return;
18619 if (bars && (bars->keyAxis() != mKeyAxis.data() || bars->valueAxis() != mValueAxis.data()))
18620 {
18621 qDebug() << Q_FUNC_INFO << "passed QCPBars* doesn't have same key and value axis as this QCPBars";
18622 return;
18623 }
18624 // remove from stacking:
18625 connectBars(mBarBelow.data(), mBarAbove.data()); // Note: also works if one (or both) of them is 0
18626 // if new bar given, insert this bar above it:
18627 if (bars)
18628 {
18629 if (bars->mBarAbove)
18630 connectBars(this, bars->mBarAbove.data());
18631 connectBars(bars, this);
19131 18632 }
19132 18633 }
19133 18634
@@ -19137,7 +18638,7 void QCPBars::moveAbove(QCPBars *bars)
19137 18638 */
19138 18639 void QCPBars::addData(const QCPBarDataMap &dataMap)
19139 18640 {
19140 mData->unite(dataMap);
18641 mData->unite(dataMap);
19141 18642 }
19142 18643
19143 18644 /*! \overload
@@ -19146,7 +18647,7 void QCPBars::addData(const QCPBarDataMa
19146 18647 */
19147 18648 void QCPBars::addData(const QCPBarData &data)
19148 18649 {
19149 mData->insertMulti(data.key, data);
18650 mData->insertMulti(data.key, data);
19150 18651 }
19151 18652
19152 18653 /*! \overload
@@ -19155,10 +18656,10 void QCPBars::addData(const QCPBarData &
19155 18656 */
19156 18657 void QCPBars::addData(double key, double value)
19157 18658 {
19158 QCPBarData newData;
19159 newData.key = key;
19160 newData.value = value;
19161 mData->insertMulti(newData.key, newData);
18659 QCPBarData newData;
18660 newData.key = key;
18661 newData.value = value;
18662 mData->insertMulti(newData.key, newData);
19162 18663 }
19163 18664
19164 18665 /*! \overload
@@ -19167,14 +18668,14 void QCPBars::addData(double key, double
19167 18668 */
19168 18669 void QCPBars::addData(const QVector<double> &keys, const QVector<double> &values)
19169 18670 {
19170 int n = keys.size();
19171 n = qMin(n, values.size());
19172 QCPBarData newData;
19173 for (int i=0; i<n; ++i)
19174 {
19175 newData.key = keys[i];
19176 newData.value = values[i];
19177 mData->insertMulti(newData.key, newData);
18671 int n = keys.size();
18672 n = qMin(n, values.size());
18673 QCPBarData newData;
18674 for (int i=0; i<n; ++i)
18675 {
18676 newData.key = keys[i];
18677 newData.value = values[i];
18678 mData->insertMulti(newData.key, newData);
19178 18679 }
19179 18680 }
19180 18681
@@ -19184,9 +18685,9 void QCPBars::addData(const QVector<doub
19184 18685 */
19185 18686 void QCPBars::removeDataBefore(double key)
19186 18687 {
19187 QCPBarDataMap::iterator it = mData->begin();
19188 while (it != mData->end() && it.key() < key)
19189 it = mData->erase(it);
18688 QCPBarDataMap::iterator it = mData->begin();
18689 while (it != mData->end() && it.key() < key)
18690 it = mData->erase(it);
19190 18691 }
19191 18692
19192 18693 /*!
@@ -19195,10 +18696,10 void QCPBars::removeDataBefore(double ke
19195 18696 */
19196 18697 void QCPBars::removeDataAfter(double key)
19197 18698 {
19198 if (mData->isEmpty()) return;
19199 QCPBarDataMap::iterator it = mData->upperBound(key);
19200 while (it != mData->end())
19201 it = mData->erase(it);
18699 if (mData->isEmpty()) return;
18700 QCPBarDataMap::iterator it = mData->upperBound(key);
18701 while (it != mData->end())
18702 it = mData->erase(it);
19202 18703 }
19203 18704
19204 18705 /*!
@@ -19210,11 +18711,11 void QCPBars::removeDataAfter(double key
19210 18711 */
19211 18712 void QCPBars::removeData(double fromKey, double toKey)
19212 18713 {
19213 if (fromKey >= toKey || mData->isEmpty()) return;
19214 QCPBarDataMap::iterator it = mData->upperBound(fromKey);
19215 QCPBarDataMap::iterator itEnd = mData->upperBound(toKey);
19216 while (it != itEnd)
19217 it = mData->erase(it);
18714 if (fromKey >= toKey || mData->isEmpty()) return;
18715 QCPBarDataMap::iterator it = mData->upperBound(fromKey);
18716 QCPBarDataMap::iterator itEnd = mData->upperBound(toKey);
18717 while (it != itEnd)
18718 it = mData->erase(it);
19218 18719 }
19219 18720
19220 18721 /*! \overload
@@ -19227,7 +18728,7 void QCPBars::removeData(double fromKey,
19227 18728 */
19228 18729 void QCPBars::removeData(double key)
19229 18730 {
19230 mData->remove(key);
18731 mData->remove(key);
19231 18732 }
19232 18733
19233 18734 /*!
@@ -19236,60 +18737,60 void QCPBars::removeData(double key)
19236 18737 */
19237 18738 void QCPBars::clearData()
19238 18739 {
19239 mData->clear();
18740 mData->clear();
19240 18741 }
19241 18742
19242 18743 /* inherits documentation from base class */
19243 18744 double QCPBars::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
19244 18745 {
19245 Q_UNUSED(details)
19246 if (onlySelectable && !mSelectable)
18746 Q_UNUSED(details)
18747 if (onlySelectable && !mSelectable)
18748 return -1;
18749 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
18750
18751 if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()))
18752 {
18753 QCPBarDataMap::ConstIterator it;
18754 for (it = mData->constBegin(); it != mData->constEnd(); ++it)
18755 {
18756 if (getBarPolygon(it.value().key, it.value().value).boundingRect().contains(pos))
18757 return mParentPlot->selectionTolerance()*0.99;
18758 }
18759 }
19247 18760 return -1;
19248 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
19249
19250 if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()))
19251 {
19252 QCPBarDataMap::ConstIterator it;
19253 for (it = mData->constBegin(); it != mData->constEnd(); ++it)
19254 {
19255 if (getBarPolygon(it.value().key, it.value().value).boundingRect().contains(pos))
19256 return mParentPlot->selectionTolerance()*0.99;
19257 }
19258 }
19259 return -1;
19260 18761 }
19261 18762
19262 18763 /* inherits documentation from base class */
19263 18764 void QCPBars::draw(QCPPainter *painter)
19264 18765 {
19265 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
19266 if (mData->isEmpty()) return;
19267
19268 QCPBarDataMap::const_iterator it, lower, upperEnd;
19269 getVisibleDataBounds(lower, upperEnd);
19270 for (it = lower; it != upperEnd; ++it)
19271 {
19272 // check data validity if flag set:
18766 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
18767 if (mData->isEmpty()) return;
18768
18769 QCPBarDataMap::const_iterator it, lower, upperEnd;
18770 getVisibleDataBounds(lower, upperEnd);
18771 for (it = lower; it != upperEnd; ++it)
18772 {
18773 // check data validity if flag set:
19273 18774 #ifdef QCUSTOMPLOT_CHECK_DATA
19274 if (QCP::isInvalidData(it.value().key, it.value().value))
19275 qDebug() << Q_FUNC_INFO << "Data point at" << it.key() << "of drawn range invalid." << "Plottable name:" << name();
18775 if (QCP::isInvalidData(it.value().key, it.value().value))
18776 qDebug() << Q_FUNC_INFO << "Data point at" << it.key() << "of drawn range invalid." << "Plottable name:" << name();
19276 18777 #endif
19277 QPolygonF barPolygon = getBarPolygon(it.key(), it.value().value);
19278 // draw bar fill:
19279 if (mainBrush().style() != Qt::NoBrush && mainBrush().color().alpha() != 0)
19280 {
19281 applyFillAntialiasingHint(painter);
19282 painter->setPen(Qt::NoPen);
19283 painter->setBrush(mainBrush());
19284 painter->drawPolygon(barPolygon);
19285 }
19286 // draw bar line:
19287 if (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0)
19288 {
19289 applyDefaultAntialiasingHint(painter);
19290 painter->setPen(mainPen());
19291 painter->setBrush(Qt::NoBrush);
19292 painter->drawPolyline(barPolygon);
18778 QPolygonF barPolygon = getBarPolygon(it.key(), it.value().value);
18779 // draw bar fill:
18780 if (mainBrush().style() != Qt::NoBrush && mainBrush().color().alpha() != 0)
18781 {
18782 applyFillAntialiasingHint(painter);
18783 painter->setPen(Qt::NoPen);
18784 painter->setBrush(mainBrush());
18785 painter->drawPolygon(barPolygon);
18786 }
18787 // draw bar line:
18788 if (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0)
18789 {
18790 applyDefaultAntialiasingHint(painter);
18791 painter->setPen(mainPen());
18792 painter->setBrush(Qt::NoBrush);
18793 painter->drawPolyline(barPolygon);
19293 18794 }
19294 18795 }
19295 18796 }
@@ -19297,13 +18798,13 void QCPBars::draw(QCPPainter *painter)
19297 18798 /* inherits documentation from base class */
19298 18799 void QCPBars::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const
19299 18800 {
19300 // draw filled rect:
19301 applyDefaultAntialiasingHint(painter);
19302 painter->setBrush(mBrush);
19303 painter->setPen(mPen);
19304 QRectF r = QRectF(0, 0, rect.width()*0.67, rect.height()*0.67);
19305 r.moveCenter(rect.center());
19306 painter->drawRect(r);
18801 // draw filled rect:
18802 applyDefaultAntialiasingHint(painter);
18803 painter->setBrush(mBrush);
18804 painter->setPen(mPen);
18805 QRectF r = QRectF(0, 0, rect.width()*0.67, rect.height()*0.67);
18806 r.moveCenter(rect.center());
18807 painter->drawRect(r);
19307 18808 }
19308 18809
19309 18810 /*! \internal
@@ -19322,49 +18823,49 void QCPBars::drawLegendIcon(QCPPainter
19322 18823 */
19323 18824 void QCPBars::getVisibleDataBounds(QCPBarDataMap::const_iterator &lower, QCPBarDataMap::const_iterator &upperEnd) const
19324 18825 {
19325 if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
19326 if (mData->isEmpty())
19327 {
19328 lower = mData->constEnd();
19329 upperEnd = mData->constEnd();
19330 return;
19331 }
19332
19333 // get visible data range as QMap iterators
19334 lower = mData->lowerBound(mKeyAxis.data()->range().lower);
19335 upperEnd = mData->upperBound(mKeyAxis.data()->range().upper);
19336 double lowerPixelBound = mKeyAxis.data()->coordToPixel(mKeyAxis.data()->range().lower);
19337 double upperPixelBound = mKeyAxis.data()->coordToPixel(mKeyAxis.data()->range().upper);
19338 bool isVisible = false;
19339 // walk left from lbound to find lower bar that actually is completely outside visible pixel range:
19340 QCPBarDataMap::const_iterator it = lower;
19341 while (it != mData->constBegin())
19342 {
19343 --it;
19344 QRectF barBounds = getBarPolygon(it.value().key, it.value().value).boundingRect();
19345 if (mKeyAxis.data()->orientation() == Qt::Horizontal)
19346 isVisible = ((!mKeyAxis.data()->rangeReversed() && barBounds.right() >= lowerPixelBound) || (mKeyAxis.data()->rangeReversed() && barBounds.left() <= lowerPixelBound));
19347 else // keyaxis is vertical
19348 isVisible = ((!mKeyAxis.data()->rangeReversed() && barBounds.top() <= lowerPixelBound) || (mKeyAxis.data()->rangeReversed() && barBounds.bottom() >= lowerPixelBound));
19349 if (isVisible)
19350 lower = it;
19351 else
19352 break;
19353 }
19354 // walk right from ubound to find upper bar that actually is completely outside visible pixel range:
19355 it = upperEnd;
19356 while (it != mData->constEnd())
19357 {
19358 QRectF barBounds = getBarPolygon(upperEnd.value().key, upperEnd.value().value).boundingRect();
19359 if (mKeyAxis.data()->orientation() == Qt::Horizontal)
19360 isVisible = ((!mKeyAxis.data()->rangeReversed() && barBounds.left() <= upperPixelBound) || (mKeyAxis.data()->rangeReversed() && barBounds.right() >= upperPixelBound));
19361 else // keyaxis is vertical
19362 isVisible = ((!mKeyAxis.data()->rangeReversed() && barBounds.bottom() >= upperPixelBound) || (mKeyAxis.data()->rangeReversed() && barBounds.top() <= upperPixelBound));
19363 if (isVisible)
19364 upperEnd = it+1;
19365 else
19366 break;
19367 ++it;
18826 if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
18827 if (mData->isEmpty())
18828 {
18829 lower = mData->constEnd();
18830 upperEnd = mData->constEnd();
18831 return;
18832 }
18833
18834 // get visible data range as QMap iterators
18835 lower = mData->lowerBound(mKeyAxis.data()->range().lower);
18836 upperEnd = mData->upperBound(mKeyAxis.data()->range().upper);
18837 double lowerPixelBound = mKeyAxis.data()->coordToPixel(mKeyAxis.data()->range().lower);
18838 double upperPixelBound = mKeyAxis.data()->coordToPixel(mKeyAxis.data()->range().upper);
18839 bool isVisible = false;
18840 // walk left from lbound to find lower bar that actually is completely outside visible pixel range:
18841 QCPBarDataMap::const_iterator it = lower;
18842 while (it != mData->constBegin())
18843 {
18844 --it;
18845 QRectF barBounds = getBarPolygon(it.value().key, it.value().value).boundingRect();
18846 if (mKeyAxis.data()->orientation() == Qt::Horizontal)
18847 isVisible = ((!mKeyAxis.data()->rangeReversed() && barBounds.right() >= lowerPixelBound) || (mKeyAxis.data()->rangeReversed() && barBounds.left() <= lowerPixelBound));
18848 else // keyaxis is vertical
18849 isVisible = ((!mKeyAxis.data()->rangeReversed() && barBounds.top() <= lowerPixelBound) || (mKeyAxis.data()->rangeReversed() && barBounds.bottom() >= lowerPixelBound));
18850 if (isVisible)
18851 lower = it;
18852 else
18853 break;
18854 }
18855 // walk right from ubound to find upper bar that actually is completely outside visible pixel range:
18856 it = upperEnd;
18857 while (it != mData->constEnd())
18858 {
18859 QRectF barBounds = getBarPolygon(upperEnd.value().key, upperEnd.value().value).boundingRect();
18860 if (mKeyAxis.data()->orientation() == Qt::Horizontal)
18861 isVisible = ((!mKeyAxis.data()->rangeReversed() && barBounds.left() <= upperPixelBound) || (mKeyAxis.data()->rangeReversed() && barBounds.right() >= upperPixelBound));
18862 else // keyaxis is vertical
18863 isVisible = ((!mKeyAxis.data()->rangeReversed() && barBounds.bottom() >= upperPixelBound) || (mKeyAxis.data()->rangeReversed() && barBounds.top() <= upperPixelBound));
18864 if (isVisible)
18865 upperEnd = it+1;
18866 else
18867 break;
18868 ++it;
19368 18869 }
19369 18870 }
19370 18871
@@ -19376,33 +18877,33 void QCPBars::getVisibleDataBounds(QCPBa
19376 18877 */
19377 18878 QPolygonF QCPBars::getBarPolygon(double key, double value) const
19378 18879 {
19379 QCPAxis *keyAxis = mKeyAxis.data();
19380 QCPAxis *valueAxis = mValueAxis.data();
19381 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return QPolygonF(); }
19382
19383 QPolygonF result;
19384 double lowerPixelWidth, upperPixelWidth;
19385 getPixelWidth(key, lowerPixelWidth, upperPixelWidth);
19386 double base = getStackedBaseValue(key, value >= 0);
19387 double basePixel = valueAxis->coordToPixel(base);
19388 double valuePixel = valueAxis->coordToPixel(base+value);
19389 double keyPixel = keyAxis->coordToPixel(key);
19390 if (mBarsGroup)
19391 keyPixel += mBarsGroup->keyPixelOffset(this, key);
19392 if (keyAxis->orientation() == Qt::Horizontal)
19393 {
19394 result << QPointF(keyPixel+lowerPixelWidth, basePixel);
19395 result << QPointF(keyPixel+lowerPixelWidth, valuePixel);
19396 result << QPointF(keyPixel+upperPixelWidth, valuePixel);
19397 result << QPointF(keyPixel+upperPixelWidth, basePixel);
19398 } else
19399 {
19400 result << QPointF(basePixel, keyPixel+lowerPixelWidth);
19401 result << QPointF(valuePixel, keyPixel+lowerPixelWidth);
19402 result << QPointF(valuePixel, keyPixel+upperPixelWidth);
19403 result << QPointF(basePixel, keyPixel+upperPixelWidth);
19404 }
19405 return result;
18880 QCPAxis *keyAxis = mKeyAxis.data();
18881 QCPAxis *valueAxis = mValueAxis.data();
18882 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return QPolygonF(); }
18883
18884 QPolygonF result;
18885 double lowerPixelWidth, upperPixelWidth;
18886 getPixelWidth(key, lowerPixelWidth, upperPixelWidth);
18887 double base = getStackedBaseValue(key, value >= 0);
18888 double basePixel = valueAxis->coordToPixel(base);
18889 double valuePixel = valueAxis->coordToPixel(base+value);
18890 double keyPixel = keyAxis->coordToPixel(key);
18891 if (mBarsGroup)
18892 keyPixel += mBarsGroup->keyPixelOffset(this, key);
18893 if (keyAxis->orientation() == Qt::Horizontal)
18894 {
18895 result << QPointF(keyPixel+lowerPixelWidth, basePixel);
18896 result << QPointF(keyPixel+lowerPixelWidth, valuePixel);
18897 result << QPointF(keyPixel+upperPixelWidth, valuePixel);
18898 result << QPointF(keyPixel+upperPixelWidth, basePixel);
18899 } else
18900 {
18901 result << QPointF(basePixel, keyPixel+lowerPixelWidth);
18902 result << QPointF(valuePixel, keyPixel+lowerPixelWidth);
18903 result << QPointF(valuePixel, keyPixel+upperPixelWidth);
18904 result << QPointF(basePixel, keyPixel+upperPixelWidth);
18905 }
18906 return result;
19406 18907 }
19407 18908
19408 18909 /*! \internal
@@ -19416,44 +18917,44 QPolygonF QCPBars::getBarPolygon(double
19416 18917 */
19417 18918 void QCPBars::getPixelWidth(double key, double &lower, double &upper) const
19418 18919 {
19419 switch (mWidthType)
18920 switch (mWidthType)
19420 18921 {
19421 18922 case wtAbsolute:
19422 {
18923 {
19423 18924 upper = mWidth*0.5;
19424 18925 lower = -upper;
19425 18926 if (mKeyAxis && (mKeyAxis.data()->rangeReversed() ^ (mKeyAxis.data()->orientation() == Qt::Vertical)))
19426 qSwap(lower, upper);
19427 break;
19428 }
18927 qSwap(lower, upper);
18928 break;
18929 }
19429 18930 case wtAxisRectRatio:
19430 {
18931 {
19431 18932 if (mKeyAxis && mKeyAxis.data()->axisRect())
19432 {
18933 {
19433 18934 if (mKeyAxis.data()->orientation() == Qt::Horizontal)
19434 upper = mKeyAxis.data()->axisRect()->width()*mWidth*0.5;
18935 upper = mKeyAxis.data()->axisRect()->width()*mWidth*0.5;
19435 18936 else
19436 upper = mKeyAxis.data()->axisRect()->height()*mWidth*0.5;
18937 upper = mKeyAxis.data()->axisRect()->height()*mWidth*0.5;
19437 18938 lower = -upper;
19438 18939 if (mKeyAxis && (mKeyAxis.data()->rangeReversed() ^ (mKeyAxis.data()->orientation() == Qt::Vertical)))
19439 qSwap(lower, upper);
19440 } else
19441 qDebug() << Q_FUNC_INFO << "No key axis or axis rect defined";
19442 break;
19443 }
18940 qSwap(lower, upper);
18941 } else
18942 qDebug() << Q_FUNC_INFO << "No key axis or axis rect defined";
18943 break;
18944 }
19444 18945 case wtPlotCoords:
19445 {
18946 {
19446 18947 if (mKeyAxis)
19447 {
18948 {
19448 18949 double keyPixel = mKeyAxis.data()->coordToPixel(key);
19449 18950 upper = mKeyAxis.data()->coordToPixel(key+mWidth*0.5)-keyPixel;
19450 18951 lower = mKeyAxis.data()->coordToPixel(key-mWidth*0.5)-keyPixel;
19451 18952 // no need to qSwap(lower, higher) when range reversed, because higher/lower are gained by
19452 18953 // coordinate transform which includes range direction
19453 } else
19454 qDebug() << Q_FUNC_INFO << "No key axis defined";
19455 break;
19456 }
18954 } else
18955 qDebug() << Q_FUNC_INFO << "No key axis defined";
18956 break;
18957 }
19457 18958 }
19458 18959 }
19459 18960
@@ -19468,26 +18969,26 void QCPBars::getPixelWidth(double key,
19468 18969 */
19469 18970 double QCPBars::getStackedBaseValue(double key, bool positive) const
19470 18971 {
19471 if (mBarBelow)
19472 {
19473 double max = 0; // don't use mBaseValue here because only base value of bottom-most bar has meaning in a bar stack
19474 // find bars of mBarBelow that are approximately at key and find largest one:
19475 double epsilon = qAbs(key)*1e-6; // should be safe even when changed to use float at some point
19476 if (key == 0)
19477 epsilon = 1e-6;
19478 QCPBarDataMap::const_iterator it = mBarBelow.data()->mData->lowerBound(key-epsilon);
19479 QCPBarDataMap::const_iterator itEnd = mBarBelow.data()->mData->upperBound(key+epsilon);
19480 while (it != itEnd)
19481 {
19482 if ((positive && it.value().value > max) ||
19483 (!positive && it.value().value < max))
19484 max = it.value().value;
19485 ++it;
19486 }
19487 // recurse down the bar-stack to find the total height:
19488 return max + mBarBelow.data()->getStackedBaseValue(key, positive);
19489 } else
19490 return mBaseValue;
18972 if (mBarBelow)
18973 {
18974 double max = 0; // don't use mBaseValue here because only base value of bottom-most bar has meaning in a bar stack
18975 // find bars of mBarBelow that are approximately at key and find largest one:
18976 double epsilon = qAbs(key)*1e-6; // should be safe even when changed to use float at some point
18977 if (key == 0)
18978 epsilon = 1e-6;
18979 QCPBarDataMap::const_iterator it = mBarBelow.data()->mData->lowerBound(key-epsilon);
18980 QCPBarDataMap::const_iterator itEnd = mBarBelow.data()->mData->upperBound(key+epsilon);
18981 while (it != itEnd)
18982 {
18983 if ((positive && it.value().value > max) ||
18984 (!positive && it.value().value < max))
18985 max = it.value().value;
18986 ++it;
18987 }
18988 // recurse down the bar-stack to find the total height:
18989 return max + mBarBelow.data()->getStackedBaseValue(key, positive);
18990 } else
18991 return mBaseValue;
19491 18992 }
19492 18993
19493 18994 /*! \internal
@@ -19500,115 +19001,115 double QCPBars::getStackedBaseValue(doub
19500 19001 */
19501 19002 void QCPBars::connectBars(QCPBars *lower, QCPBars *upper)
19502 19003 {
19503 if (!lower && !upper) return;
19504
19505 if (!lower) // disconnect upper at bottom
19506 {
19507 // disconnect old bar below upper:
19508 if (upper->mBarBelow && upper->mBarBelow.data()->mBarAbove.data() == upper)
19509 upper->mBarBelow.data()->mBarAbove = 0;
19510 upper->mBarBelow = 0;
19004 if (!lower && !upper) return;
19005
19006 if (!lower) // disconnect upper at bottom
19007 {
19008 // disconnect old bar below upper:
19009 if (upper->mBarBelow && upper->mBarBelow.data()->mBarAbove.data() == upper)
19010 upper->mBarBelow.data()->mBarAbove = 0;
19011 upper->mBarBelow = 0;
19511 19012 } else if (!upper) // disconnect lower at top
19512 19013 {
19513 // disconnect old bar above lower:
19514 if (lower->mBarAbove && lower->mBarAbove.data()->mBarBelow.data() == lower)
19515 lower->mBarAbove.data()->mBarBelow = 0;
19516 lower->mBarAbove = 0;
19014 // disconnect old bar above lower:
19015 if (lower->mBarAbove && lower->mBarAbove.data()->mBarBelow.data() == lower)
19016 lower->mBarAbove.data()->mBarBelow = 0;
19017 lower->mBarAbove = 0;
19517 19018 } else // connect lower and upper
19518 19019 {
19519 // disconnect old bar above lower:
19520 if (lower->mBarAbove && lower->mBarAbove.data()->mBarBelow.data() == lower)
19521 lower->mBarAbove.data()->mBarBelow = 0;
19522 // disconnect old bar below upper:
19523 if (upper->mBarBelow && upper->mBarBelow.data()->mBarAbove.data() == upper)
19524 upper->mBarBelow.data()->mBarAbove = 0;
19525 lower->mBarAbove = upper;
19526 upper->mBarBelow = lower;
19020 // disconnect old bar above lower:
19021 if (lower->mBarAbove && lower->mBarAbove.data()->mBarBelow.data() == lower)
19022 lower->mBarAbove.data()->mBarBelow = 0;
19023 // disconnect old bar below upper:
19024 if (upper->mBarBelow && upper->mBarBelow.data()->mBarAbove.data() == upper)
19025 upper->mBarBelow.data()->mBarAbove = 0;
19026 lower->mBarAbove = upper;
19027 upper->mBarBelow = lower;
19527 19028 }
19528 19029 }
19529 19030
19530 19031 /* inherits documentation from base class */
19531 19032 QCPRange QCPBars::getKeyRange(bool &foundRange, SignDomain inSignDomain) const
19532 19033 {
19533 QCPRange range;
19534 bool haveLower = false;
19535 bool haveUpper = false;
19536
19537 double current;
19538 QCPBarDataMap::const_iterator it = mData->constBegin();
19539 while (it != mData->constEnd())
19540 {
19541 current = it.value().key;
19542 if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current < 0) || (inSignDomain == sdPositive && current > 0))
19543 {
19544 if (current < range.lower || !haveLower)
19545 {
19546 range.lower = current;
19547 haveLower = true;
19548 }
19549 if (current > range.upper || !haveUpper)
19550 {
19551 range.upper = current;
19552 haveUpper = true;
19553 }
19554 }
19555 ++it;
19556 }
19557 // determine exact range of bars by including bar width and barsgroup offset:
19558 if (haveLower && mKeyAxis)
19559 {
19560 double lowerPixelWidth, upperPixelWidth, keyPixel;
19561 getPixelWidth(range.lower, lowerPixelWidth, upperPixelWidth);
19562 keyPixel = mKeyAxis.data()->coordToPixel(range.lower) + lowerPixelWidth;
19563 if (mBarsGroup)
19564 keyPixel += mBarsGroup->keyPixelOffset(this, range.lower);
19565 range.lower = mKeyAxis.data()->pixelToCoord(keyPixel);
19566 }
19567 if (haveUpper && mKeyAxis)
19568 {
19569 double lowerPixelWidth, upperPixelWidth, keyPixel;
19570 getPixelWidth(range.upper, lowerPixelWidth, upperPixelWidth);
19571 keyPixel = mKeyAxis.data()->coordToPixel(range.upper) + upperPixelWidth;
19572 if (mBarsGroup)
19573 keyPixel += mBarsGroup->keyPixelOffset(this, range.upper);
19574 range.upper = mKeyAxis.data()->pixelToCoord(keyPixel);
19575 }
19576 foundRange = haveLower && haveUpper;
19577 return range;
19034 QCPRange range;
19035 bool haveLower = false;
19036 bool haveUpper = false;
19037
19038 double current;
19039 QCPBarDataMap::const_iterator it = mData->constBegin();
19040 while (it != mData->constEnd())
19041 {
19042 current = it.value().key;
19043 if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current < 0) || (inSignDomain == sdPositive && current > 0))
19044 {
19045 if (current < range.lower || !haveLower)
19046 {
19047 range.lower = current;
19048 haveLower = true;
19049 }
19050 if (current > range.upper || !haveUpper)
19051 {
19052 range.upper = current;
19053 haveUpper = true;
19054 }
19055 }
19056 ++it;
19057 }
19058 // determine exact range of bars by including bar width and barsgroup offset:
19059 if (haveLower && mKeyAxis)
19060 {
19061 double lowerPixelWidth, upperPixelWidth, keyPixel;
19062 getPixelWidth(range.lower, lowerPixelWidth, upperPixelWidth);
19063 keyPixel = mKeyAxis.data()->coordToPixel(range.lower) + lowerPixelWidth;
19064 if (mBarsGroup)
19065 keyPixel += mBarsGroup->keyPixelOffset(this, range.lower);
19066 range.lower = mKeyAxis.data()->pixelToCoord(keyPixel);
19067 }
19068 if (haveUpper && mKeyAxis)
19069 {
19070 double lowerPixelWidth, upperPixelWidth, keyPixel;
19071 getPixelWidth(range.upper, lowerPixelWidth, upperPixelWidth);
19072 keyPixel = mKeyAxis.data()->coordToPixel(range.upper) + upperPixelWidth;
19073 if (mBarsGroup)
19074 keyPixel += mBarsGroup->keyPixelOffset(this, range.upper);
19075 range.upper = mKeyAxis.data()->pixelToCoord(keyPixel);
19076 }
19077 foundRange = haveLower && haveUpper;
19078 return range;
19578 19079 }
19579 19080
19580 19081 /* inherits documentation from base class */
19581 19082 QCPRange QCPBars::getValueRange(bool &foundRange, SignDomain inSignDomain) const
19582 19083 {
19583 QCPRange range;
19584 range.lower = mBaseValue;
19585 range.upper = mBaseValue;
19586 bool haveLower = true; // set to true, because baseValue should always be visible in bar charts
19587 bool haveUpper = true; // set to true, because baseValue should always be visible in bar charts
19588 double current;
19589
19590 QCPBarDataMap::const_iterator it = mData->constBegin();
19591 while (it != mData->constEnd())
19592 {
19593 current = it.value().value + getStackedBaseValue(it.value().key, it.value().value >= 0);
19594 if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current < 0) || (inSignDomain == sdPositive && current > 0))
19595 {
19596 if (current < range.lower || !haveLower)
19597 {
19598 range.lower = current;
19599 haveLower = true;
19600 }
19601 if (current > range.upper || !haveUpper)
19602 {
19603 range.upper = current;
19604 haveUpper = true;
19605 }
19606 }
19607 ++it;
19608 }
19609
19610 foundRange = true; // return true because bar charts always have the 0-line visible
19611 return range;
19084 QCPRange range;
19085 range.lower = mBaseValue;
19086 range.upper = mBaseValue;
19087 bool haveLower = true; // set to true, because baseValue should always be visible in bar charts
19088 bool haveUpper = true; // set to true, because baseValue should always be visible in bar charts
19089 double current;
19090
19091 QCPBarDataMap::const_iterator it = mData->constBegin();
19092 while (it != mData->constEnd())
19093 {
19094 current = it.value().value + getStackedBaseValue(it.value().key, it.value().value >= 0);
19095 if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current < 0) || (inSignDomain == sdPositive && current > 0))
19096 {
19097 if (current < range.lower || !haveLower)
19098 {
19099 range.lower = current;
19100 haveLower = true;
19101 }
19102 if (current > range.upper || !haveUpper)
19103 {
19104 range.upper = current;
19105 haveUpper = true;
19106 }
19107 }
19108 ++it;
19109 }
19110
19111 foundRange = true; // return true because bar charts always have the 0-line visible
19112 return range;
19612 19113 }
19613 19114
19614 19115
@@ -19679,25 +19180,25 QCPRange QCPBars::getValueRange(bool &fo
19679 19180 QCustomPlot then takes ownership of the statistical box.
19680 19181 */
19681 19182 QCPStatisticalBox::QCPStatisticalBox(QCPAxis *keyAxis, QCPAxis *valueAxis) :
19682 QCPAbstractPlottable(keyAxis, valueAxis),
19683 mKey(0),
19684 mMinimum(0),
19685 mLowerQuartile(0),
19686 mMedian(0),
19687 mUpperQuartile(0),
19688 mMaximum(0)
19689 {
19690 setOutlierStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, Qt::blue, 6));
19691 setWhiskerWidth(0.2);
19692 setWidth(0.5);
19693
19694 setPen(QPen(Qt::black));
19695 setSelectedPen(QPen(Qt::blue, 2.5));
19696 setMedianPen(QPen(Qt::black, 3, Qt::SolidLine, Qt::FlatCap));
19697 setWhiskerPen(QPen(Qt::black, 0, Qt::DashLine, Qt::FlatCap));
19698 setWhiskerBarPen(QPen(Qt::black));
19699 setBrush(Qt::NoBrush);
19700 setSelectedBrush(Qt::NoBrush);
19183 QCPAbstractPlottable(keyAxis, valueAxis),
19184 mKey(0),
19185 mMinimum(0),
19186 mLowerQuartile(0),
19187 mMedian(0),
19188 mUpperQuartile(0),
19189 mMaximum(0)
19190 {
19191 setOutlierStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, Qt::blue, 6));
19192 setWhiskerWidth(0.2);
19193 setWidth(0.5);
19194
19195 setPen(QPen(Qt::black));
19196 setSelectedPen(QPen(Qt::blue, 2.5));
19197 setMedianPen(QPen(Qt::black, 3, Qt::SolidLine, Qt::FlatCap));
19198 setWhiskerPen(QPen(Qt::black, 0, Qt::DashLine, Qt::FlatCap));
19199 setWhiskerBarPen(QPen(Qt::black));
19200 setBrush(Qt::NoBrush);
19201 setSelectedBrush(Qt::NoBrush);
19701 19202 }
19702 19203
19703 19204 /*!
@@ -19705,7 +19206,7 QCPStatisticalBox::QCPStatisticalBox(QCP
19705 19206 */
19706 19207 void QCPStatisticalBox::setKey(double key)
19707 19208 {
19708 mKey = key;
19209 mKey = key;
19709 19210 }
19710 19211
19711 19212 /*!
@@ -19716,7 +19217,7 void QCPStatisticalBox::setKey(double ke
19716 19217 */
19717 19218 void QCPStatisticalBox::setMinimum(double value)
19718 19219 {
19719 mMinimum = value;
19220 mMinimum = value;
19720 19221 }
19721 19222
19722 19223 /*!
@@ -19728,7 +19229,7 void QCPStatisticalBox::setMinimum(doubl
19728 19229 */
19729 19230 void QCPStatisticalBox::setLowerQuartile(double value)
19730 19231 {
19731 mLowerQuartile = value;
19232 mLowerQuartile = value;
19732 19233 }
19733 19234
19734 19235 /*!
@@ -19740,7 +19241,7 void QCPStatisticalBox::setLowerQuartile
19740 19241 */
19741 19242 void QCPStatisticalBox::setMedian(double value)
19742 19243 {
19743 mMedian = value;
19244 mMedian = value;
19744 19245 }
19745 19246
19746 19247 /*!
@@ -19752,7 +19253,7 void QCPStatisticalBox::setMedian(double
19752 19253 */
19753 19254 void QCPStatisticalBox::setUpperQuartile(double value)
19754 19255 {
19755 mUpperQuartile = value;
19256 mUpperQuartile = value;
19756 19257 }
19757 19258
19758 19259 /*!
@@ -19763,7 +19264,7 void QCPStatisticalBox::setUpperQuartile
19763 19264 */
19764 19265 void QCPStatisticalBox::setMaximum(double value)
19765 19266 {
19766 mMaximum = value;
19267 mMaximum = value;
19767 19268 }
19768 19269
19769 19270 /*!
@@ -19775,7 +19276,7 void QCPStatisticalBox::setMaximum(doubl
19775 19276 */
19776 19277 void QCPStatisticalBox::setOutliers(const QVector<double> &values)
19777 19278 {
19778 mOutliers = values;
19279 mOutliers = values;
19779 19280 }
19780 19281
19781 19282 /*!
@@ -19785,12 +19286,12 void QCPStatisticalBox::setOutliers(cons
19785 19286 */
19786 19287 void QCPStatisticalBox::setData(double key, double minimum, double lowerQuartile, double median, double upperQuartile, double maximum)
19787 19288 {
19788 setKey(key);
19789 setMinimum(minimum);
19790 setLowerQuartile(lowerQuartile);
19791 setMedian(median);
19792 setUpperQuartile(upperQuartile);
19793 setMaximum(maximum);
19289 setKey(key);
19290 setMinimum(minimum);
19291 setLowerQuartile(lowerQuartile);
19292 setMedian(median);
19293 setUpperQuartile(upperQuartile);
19294 setMaximum(maximum);
19794 19295 }
19795 19296
19796 19297 /*!
@@ -19800,7 +19301,7 void QCPStatisticalBox::setData(double k
19800 19301 */
19801 19302 void QCPStatisticalBox::setWidth(double width)
19802 19303 {
19803 mWidth = width;
19304 mWidth = width;
19804 19305 }
19805 19306
19806 19307 /*!
@@ -19810,7 +19311,7 void QCPStatisticalBox::setWidth(double
19810 19311 */
19811 19312 void QCPStatisticalBox::setWhiskerWidth(double width)
19812 19313 {
19813 mWhiskerWidth = width;
19314 mWhiskerWidth = width;
19814 19315 }
19815 19316
19816 19317 /*!
@@ -19823,7 +19324,7 void QCPStatisticalBox::setWhiskerWidth(
19823 19324 */
19824 19325 void QCPStatisticalBox::setWhiskerPen(const QPen &pen)
19825 19326 {
19826 mWhiskerPen = pen;
19327 mWhiskerPen = pen;
19827 19328 }
19828 19329
19829 19330 /*!
@@ -19834,7 +19335,7 void QCPStatisticalBox::setWhiskerPen(co
19834 19335 */
19835 19336 void QCPStatisticalBox::setWhiskerBarPen(const QPen &pen)
19836 19337 {
19837 mWhiskerBarPen = pen;
19338 mWhiskerBarPen = pen;
19838 19339 }
19839 19340
19840 19341 /*!
@@ -19842,7 +19343,7 void QCPStatisticalBox::setWhiskerBarPen
19842 19343 */
19843 19344 void QCPStatisticalBox::setMedianPen(const QPen &pen)
19844 19345 {
19845 mMedianPen = pen;
19346 mMedianPen = pen;
19846 19347 }
19847 19348
19848 19349 /*!
@@ -19852,84 +19353,84 void QCPStatisticalBox::setMedianPen(con
19852 19353 */
19853 19354 void QCPStatisticalBox::setOutlierStyle(const QCPScatterStyle &style)
19854 19355 {
19855 mOutlierStyle = style;
19356 mOutlierStyle = style;
19856 19357 }
19857 19358
19858 19359 /* inherits documentation from base class */
19859 19360 void QCPStatisticalBox::clearData()
19860 19361 {
19861 setOutliers(QVector<double>());
19862 setKey(0);
19863 setMinimum(0);
19864 setLowerQuartile(0);
19865 setMedian(0);
19866 setUpperQuartile(0);
19867 setMaximum(0);
19362 setOutliers(QVector<double>());
19363 setKey(0);
19364 setMinimum(0);
19365 setLowerQuartile(0);
19366 setMedian(0);
19367 setUpperQuartile(0);
19368 setMaximum(0);
19868 19369 }
19869 19370
19870 19371 /* inherits documentation from base class */
19871 19372 double QCPStatisticalBox::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
19872 19373 {
19873 Q_UNUSED(details)
19874 if (onlySelectable && !mSelectable)
19374 Q_UNUSED(details)
19375 if (onlySelectable && !mSelectable)
19376 return -1;
19377 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
19378
19379 if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()))
19380 {
19381 double posKey, posValue;
19382 pixelsToCoords(pos, posKey, posValue);
19383 // quartile box:
19384 QCPRange keyRange(mKey-mWidth*0.5, mKey+mWidth*0.5);
19385 QCPRange valueRange(mLowerQuartile, mUpperQuartile);
19386 if (keyRange.contains(posKey) && valueRange.contains(posValue))
19387 return mParentPlot->selectionTolerance()*0.99;
19388
19389 // min/max whiskers:
19390 if (QCPRange(mMinimum, mMaximum).contains(posValue))
19391 return qAbs(mKeyAxis.data()->coordToPixel(mKey)-mKeyAxis.data()->coordToPixel(posKey));
19392 }
19875 19393 return -1;
19876 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
19877
19878 if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()))
19879 {
19880 double posKey, posValue;
19881 pixelsToCoords(pos, posKey, posValue);
19882 // quartile box:
19883 QCPRange keyRange(mKey-mWidth*0.5, mKey+mWidth*0.5);
19884 QCPRange valueRange(mLowerQuartile, mUpperQuartile);
19885 if (keyRange.contains(posKey) && valueRange.contains(posValue))
19886 return mParentPlot->selectionTolerance()*0.99;
19887
19888 // min/max whiskers:
19889 if (QCPRange(mMinimum, mMaximum).contains(posValue))
19890 return qAbs(mKeyAxis.data()->coordToPixel(mKey)-mKeyAxis.data()->coordToPixel(posKey));
19891 }
19892 return -1;
19893 19394 }
19894 19395
19895 19396 /* inherits documentation from base class */
19896 19397 void QCPStatisticalBox::draw(QCPPainter *painter)
19897 19398 {
19898 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
19899
19900 // check data validity if flag set:
19399 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
19400
19401 // check data validity if flag set:
19901 19402 #ifdef QCUSTOMPLOT_CHECK_DATA
19902 if (QCP::isInvalidData(mKey, mMedian) ||
19903 QCP::isInvalidData(mLowerQuartile, mUpperQuartile) ||
19904 QCP::isInvalidData(mMinimum, mMaximum))
19905 qDebug() << Q_FUNC_INFO << "Data point at" << mKey << "of drawn range has invalid data." << "Plottable name:" << name();
19906 for (int i=0; i<mOutliers.size(); ++i)
19907 if (QCP::isInvalidData(mOutliers.at(i)))
19908 qDebug() << Q_FUNC_INFO << "Data point outlier at" << mKey << "of drawn range invalid." << "Plottable name:" << name();
19403 if (QCP::isInvalidData(mKey, mMedian) ||
19404 QCP::isInvalidData(mLowerQuartile, mUpperQuartile) ||
19405 QCP::isInvalidData(mMinimum, mMaximum))
19406 qDebug() << Q_FUNC_INFO << "Data point at" << mKey << "of drawn range has invalid data." << "Plottable name:" << name();
19407 for (int i=0; i<mOutliers.size(); ++i)
19408 if (QCP::isInvalidData(mOutliers.at(i)))
19409 qDebug() << Q_FUNC_INFO << "Data point outlier at" << mKey << "of drawn range invalid." << "Plottable name:" << name();
19909 19410 #endif
19910
19911 QRectF quartileBox;
19912 drawQuartileBox(painter, &quartileBox);
19913
19914 painter->save();
19915 painter->setClipRect(quartileBox, Qt::IntersectClip);
19916 drawMedian(painter);
19917 painter->restore();
19918
19919 drawWhiskers(painter);
19920 drawOutliers(painter);
19411
19412 QRectF quartileBox;
19413 drawQuartileBox(painter, &quartileBox);
19414
19415 painter->save();
19416 painter->setClipRect(quartileBox, Qt::IntersectClip);
19417 drawMedian(painter);
19418 painter->restore();
19419
19420 drawWhiskers(painter);
19421 drawOutliers(painter);
19921 19422 }
19922 19423
19923 19424 /* inherits documentation from base class */
19924 19425 void QCPStatisticalBox::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const
19925 19426 {
19926 // draw filled rect:
19927 applyDefaultAntialiasingHint(painter);
19928 painter->setPen(mPen);
19929 painter->setBrush(mBrush);
19930 QRectF r = QRectF(0, 0, rect.width()*0.67, rect.height()*0.67);
19931 r.moveCenter(rect.center());
19932 painter->drawRect(r);
19427 // draw filled rect:
19428 applyDefaultAntialiasingHint(painter);
19429 painter->setPen(mPen);
19430 painter->setBrush(mBrush);
19431 QRectF r = QRectF(0, 0, rect.width()*0.67, rect.height()*0.67);
19432 r.moveCenter(rect.center());
19433 painter->drawRect(r);
19933 19434 }
19934 19435
19935 19436 /*! \internal
@@ -19940,15 +19441,15 void QCPStatisticalBox::drawLegendIcon(Q
19940 19441 */
19941 19442 void QCPStatisticalBox::drawQuartileBox(QCPPainter *painter, QRectF *quartileBox) const
19942 19443 {
19943 QRectF box;
19944 box.setTopLeft(coordsToPixels(mKey-mWidth*0.5, mUpperQuartile));
19945 box.setBottomRight(coordsToPixels(mKey+mWidth*0.5, mLowerQuartile));
19946 applyDefaultAntialiasingHint(painter);
19947 painter->setPen(mainPen());
19948 painter->setBrush(mainBrush());
19949 painter->drawRect(box);
19950 if (quartileBox)
19951 *quartileBox = box;
19444 QRectF box;
19445 box.setTopLeft(coordsToPixels(mKey-mWidth*0.5, mUpperQuartile));
19446 box.setBottomRight(coordsToPixels(mKey+mWidth*0.5, mLowerQuartile));
19447 applyDefaultAntialiasingHint(painter);
19448 painter->setPen(mainPen());
19449 painter->setBrush(mainBrush());
19450 painter->drawRect(box);
19451 if (quartileBox)
19452 *quartileBox = box;
19952 19453 }
19953 19454
19954 19455 /*! \internal
@@ -19957,12 +19458,12 void QCPStatisticalBox::drawQuartileBox(
19957 19458 */
19958 19459 void QCPStatisticalBox::drawMedian(QCPPainter *painter) const
19959 19460 {
19960 QLineF medianLine;
19961 medianLine.setP1(coordsToPixels(mKey-mWidth*0.5, mMedian));
19962 medianLine.setP2(coordsToPixels(mKey+mWidth*0.5, mMedian));
19963 applyDefaultAntialiasingHint(painter);
19964 painter->setPen(mMedianPen);
19965 painter->drawLine(medianLine);
19461 QLineF medianLine;
19462 medianLine.setP1(coordsToPixels(mKey-mWidth*0.5, mMedian));
19463 medianLine.setP2(coordsToPixels(mKey+mWidth*0.5, mMedian));
19464 applyDefaultAntialiasingHint(painter);
19465 painter->setPen(mMedianPen);
19466 painter->drawLine(medianLine);
19966 19467 }
19967 19468
19968 19469 /*! \internal
@@ -19971,18 +19472,18 void QCPStatisticalBox::drawMedian(QCPPa
19971 19472 */
19972 19473 void QCPStatisticalBox::drawWhiskers(QCPPainter *painter) const
19973 19474 {
19974 QLineF backboneMin, backboneMax, barMin, barMax;
19975 backboneMax.setPoints(coordsToPixels(mKey, mUpperQuartile), coordsToPixels(mKey, mMaximum));
19976 backboneMin.setPoints(coordsToPixels(mKey, mLowerQuartile), coordsToPixels(mKey, mMinimum));
19977 barMax.setPoints(coordsToPixels(mKey-mWhiskerWidth*0.5, mMaximum), coordsToPixels(mKey+mWhiskerWidth*0.5, mMaximum));
19978 barMin.setPoints(coordsToPixels(mKey-mWhiskerWidth*0.5, mMinimum), coordsToPixels(mKey+mWhiskerWidth*0.5, mMinimum));
19979 applyErrorBarsAntialiasingHint(painter);
19980 painter->setPen(mWhiskerPen);
19981 painter->drawLine(backboneMin);
19982 painter->drawLine(backboneMax);
19983 painter->setPen(mWhiskerBarPen);
19984 painter->drawLine(barMin);
19985 painter->drawLine(barMax);
19475 QLineF backboneMin, backboneMax, barMin, barMax;
19476 backboneMax.setPoints(coordsToPixels(mKey, mUpperQuartile), coordsToPixels(mKey, mMaximum));
19477 backboneMin.setPoints(coordsToPixels(mKey, mLowerQuartile), coordsToPixels(mKey, mMinimum));
19478 barMax.setPoints(coordsToPixels(mKey-mWhiskerWidth*0.5, mMaximum), coordsToPixels(mKey+mWhiskerWidth*0.5, mMaximum));
19479 barMin.setPoints(coordsToPixels(mKey-mWhiskerWidth*0.5, mMinimum), coordsToPixels(mKey+mWhiskerWidth*0.5, mMinimum));
19480 applyErrorBarsAntialiasingHint(painter);
19481 painter->setPen(mWhiskerPen);
19482 painter->drawLine(backboneMin);
19483 painter->drawLine(backboneMax);
19484 painter->setPen(mWhiskerBarPen);
19485 painter->drawLine(barMin);
19486 painter->drawLine(barMax);
19986 19487 }
19987 19488
19988 19489 /*! \internal
@@ -19991,85 +19492,85 void QCPStatisticalBox::drawWhiskers(QCP
19991 19492 */
19992 19493 void QCPStatisticalBox::drawOutliers(QCPPainter *painter) const
19993 19494 {
19994 applyScattersAntialiasingHint(painter);
19995 mOutlierStyle.applyTo(painter, mPen);
19996 for (int i=0; i<mOutliers.size(); ++i)
19997 mOutlierStyle.drawShape(painter, coordsToPixels(mKey, mOutliers.at(i)));
19495 applyScattersAntialiasingHint(painter);
19496 mOutlierStyle.applyTo(painter, mPen);
19497 for (int i=0; i<mOutliers.size(); ++i)
19498 mOutlierStyle.drawShape(painter, coordsToPixels(mKey, mOutliers.at(i)));
19998 19499 }
19999 19500
20000 19501 /* inherits documentation from base class */
20001 19502 QCPRange QCPStatisticalBox::getKeyRange(bool &foundRange, SignDomain inSignDomain) const
20002 19503 {
20003 foundRange = true;
20004 if (inSignDomain == sdBoth)
20005 {
20006 return QCPRange(mKey-mWidth*0.5, mKey+mWidth*0.5);
19504 foundRange = true;
19505 if (inSignDomain == sdBoth)
19506 {
19507 return QCPRange(mKey-mWidth*0.5, mKey+mWidth*0.5);
20007 19508 } else if (inSignDomain == sdNegative)
20008 19509 {
20009 if (mKey+mWidth*0.5 < 0)
20010 return QCPRange(mKey-mWidth*0.5, mKey+mWidth*0.5);
20011 else if (mKey < 0)
20012 return QCPRange(mKey-mWidth*0.5, mKey);
20013 else
20014 {
20015 foundRange = false;
20016 return QCPRange();
19510 if (mKey+mWidth*0.5 < 0)
19511 return QCPRange(mKey-mWidth*0.5, mKey+mWidth*0.5);
19512 else if (mKey < 0)
19513 return QCPRange(mKey-mWidth*0.5, mKey);
19514 else
19515 {
19516 foundRange = false;
19517 return QCPRange();
20017 19518 }
20018 19519 } else if (inSignDomain == sdPositive)
20019 19520 {
20020 if (mKey-mWidth*0.5 > 0)
20021 return QCPRange(mKey-mWidth*0.5, mKey+mWidth*0.5);
20022 else if (mKey > 0)
20023 return QCPRange(mKey, mKey+mWidth*0.5);
20024 else
20025 {
20026 foundRange = false;
20027 return QCPRange();
20028 }
20029 }
20030 foundRange = false;
20031 return QCPRange();
19521 if (mKey-mWidth*0.5 > 0)
19522 return QCPRange(mKey-mWidth*0.5, mKey+mWidth*0.5);
19523 else if (mKey > 0)
19524 return QCPRange(mKey, mKey+mWidth*0.5);
19525 else
19526 {
19527 foundRange = false;
19528 return QCPRange();
19529 }
19530 }
19531 foundRange = false;
19532 return QCPRange();
20032 19533 }
20033 19534
20034 19535 /* inherits documentation from base class */
20035 19536 QCPRange QCPStatisticalBox::getValueRange(bool &foundRange, SignDomain inSignDomain) const
20036 19537 {
20037 QVector<double> values; // values that must be considered (i.e. all outliers and the five box-parameters)
20038 values.reserve(mOutliers.size() + 5);
20039 values << mMaximum << mUpperQuartile << mMedian << mLowerQuartile << mMinimum;
20040 values << mOutliers;
20041 // go through values and find the ones in legal range:
20042 bool haveUpper = false;
20043 bool haveLower = false;
20044 double upper = 0;
20045 double lower = 0;
20046 for (int i=0; i<values.size(); ++i)
20047 {
20048 if ((inSignDomain == sdNegative && values.at(i) < 0) ||
20049 (inSignDomain == sdPositive && values.at(i) > 0) ||
20050 (inSignDomain == sdBoth))
20051 {
20052 if (values.at(i) > upper || !haveUpper)
20053 {
20054 upper = values.at(i);
20055 haveUpper = true;
20056 }
20057 if (values.at(i) < lower || !haveLower)
20058 {
20059 lower = values.at(i);
20060 haveLower = true;
20061 }
20062 }
20063 }
20064 // return the bounds if we found some sensible values:
20065 if (haveLower && haveUpper)
20066 {
20067 foundRange = true;
20068 return QCPRange(lower, upper);
19538 QVector<double> values; // values that must be considered (i.e. all outliers and the five box-parameters)
19539 values.reserve(mOutliers.size() + 5);
19540 values << mMaximum << mUpperQuartile << mMedian << mLowerQuartile << mMinimum;
19541 values << mOutliers;
19542 // go through values and find the ones in legal range:
19543 bool haveUpper = false;
19544 bool haveLower = false;
19545 double upper = 0;
19546 double lower = 0;
19547 for (int i=0; i<values.size(); ++i)
19548 {
19549 if ((inSignDomain == sdNegative && values.at(i) < 0) ||
19550 (inSignDomain == sdPositive && values.at(i) > 0) ||
19551 (inSignDomain == sdBoth))
19552 {
19553 if (values.at(i) > upper || !haveUpper)
19554 {
19555 upper = values.at(i);
19556 haveUpper = true;
19557 }
19558 if (values.at(i) < lower || !haveLower)
19559 {
19560 lower = values.at(i);
19561 haveLower = true;
19562 }
19563 }
19564 }
19565 // return the bounds if we found some sensible values:
19566 if (haveLower && haveUpper)
19567 {
19568 foundRange = true;
19569 return QCPRange(lower, upper);
20069 19570 } else // might happen if all values are in other sign domain
20070 19571 {
20071 foundRange = false;
20072 return QCPRange();
19572 foundRange = false;
19573 return QCPRange();
20073 19574 }
20074 19575 }
20075 19576
@@ -20124,35 +19625,35 QCPRange QCPStatisticalBox::getValueRang
20124 19625 \see setSize, setKeySize, setValueSize, setRange, setKeyRange, setValueRange
20125 19626 */
20126 19627 QCPColorMapData::QCPColorMapData(int keySize, int valueSize, const QCPRange &keyRange, const QCPRange &valueRange) :
20127 mKeySize(0),
20128 mValueSize(0),
20129 mKeyRange(keyRange),
20130 mValueRange(valueRange),
20131 mIsEmpty(true),
20132 mData(0),
20133 mDataModified(true)
20134 {
20135 setSize(keySize, valueSize);
20136 fill(0);
19628 mKeySize(0),
19629 mValueSize(0),
19630 mKeyRange(keyRange),
19631 mValueRange(valueRange),
19632 mIsEmpty(true),
19633 mData(0),
19634 mDataModified(true)
19635 {
19636 setSize(keySize, valueSize);
19637 fill(0);
20137 19638 }
20138 19639
20139 19640 QCPColorMapData::~QCPColorMapData()
20140 19641 {
20141 if (mData)
20142 delete[] mData;
19642 if (mData)
19643 delete[] mData;
20143 19644 }
20144 19645
20145 19646 /*!
20146 19647 Constructs a new QCPColorMapData instance copying the data and range of \a other.
20147 19648 */
20148 19649 QCPColorMapData::QCPColorMapData(const QCPColorMapData &other) :
20149 mKeySize(0),
20150 mValueSize(0),
20151 mIsEmpty(true),
20152 mData(0),
20153 mDataModified(true)
20154 {
20155 *this = other;
19650 mKeySize(0),
19651 mValueSize(0),
19652 mIsEmpty(true),
19653 mData(0),
19654 mDataModified(true)
19655 {
19656 *this = other;
20156 19657 }
20157 19658
20158 19659 /*!
@@ -20160,38 +19661,38 QCPColorMapData::QCPColorMapData(const Q
20160 19661 */
20161 19662 QCPColorMapData &QCPColorMapData::operator=(const QCPColorMapData &other)
20162 19663 {
20163 if (&other != this)
20164 {
20165 const int keySize = other.keySize();
20166 const int valueSize = other.valueSize();
20167 setSize(keySize, valueSize);
20168 setRange(other.keyRange(), other.valueRange());
20169 if (!mIsEmpty)
20170 memcpy(mData, other.mData, sizeof(mData[0])*keySize*valueSize);
20171 mDataBounds = other.mDataBounds;
20172 mDataModified = true;
20173 }
20174 return *this;
19664 if (&other != this)
19665 {
19666 const int keySize = other.keySize();
19667 const int valueSize = other.valueSize();
19668 setSize(keySize, valueSize);
19669 setRange(other.keyRange(), other.valueRange());
19670 if (!mIsEmpty)
19671 memcpy(mData, other.mData, sizeof(mData[0])*keySize*valueSize);
19672 mDataBounds = other.mDataBounds;
19673 mDataModified = true;
19674 }
19675 return *this;
20175 19676 }
20176 19677
20177 19678 /* undocumented getter */
20178 19679 double QCPColorMapData::data(double key, double value)
20179 19680 {
20180 int keyCell = (key-mKeyRange.lower)/(mKeyRange.upper-mKeyRange.lower)*(mKeySize-1)+0.5;
20181 int valueCell = (value-mValueRange.lower)/(mValueRange.upper-mValueRange.lower)*(mValueSize-1)+0.5;
20182 if (keyCell >= 0 && keyCell < mKeySize && valueCell >= 0 && valueCell < mValueSize)
20183 return mData[valueCell*mKeySize + keyCell];
20184 else
20185 return 0;
19681 int keyCell = (key-mKeyRange.lower)/(mKeyRange.upper-mKeyRange.lower)*(mKeySize-1)+0.5;
19682 int valueCell = (value-mValueRange.lower)/(mValueRange.upper-mValueRange.lower)*(mValueSize-1)+0.5;
19683 if (keyCell >= 0 && keyCell < mKeySize && valueCell >= 0 && valueCell < mValueSize)
19684 return mData[valueCell*mKeySize + keyCell];
19685 else
19686 return 0;
20186 19687 }
20187 19688
20188 19689 /* undocumented getter */
20189 19690 double QCPColorMapData::cell(int keyIndex, int valueIndex)
20190 19691 {
20191 if (keyIndex >= 0 && keyIndex < mKeySize && valueIndex >= 0 && valueIndex < mValueSize)
20192 return mData[valueIndex*mKeySize + keyIndex];
20193 else
20194 return 0;
19692 if (keyIndex >= 0 && keyIndex < mKeySize && valueIndex >= 0 && valueIndex < mValueSize)
19693 return mData[valueIndex*mKeySize + keyIndex];
19694 else
19695 return 0;
20195 19696 }
20196 19697
20197 19698 /*!
@@ -20208,29 +19709,29 double QCPColorMapData::cell(int keyInde
20208 19709 */
20209 19710 void QCPColorMapData::setSize(int keySize, int valueSize)
20210 19711 {
20211 if (keySize != mKeySize || valueSize != mValueSize)
20212 {
20213 mKeySize = keySize;
20214 mValueSize = valueSize;
20215 if (mData)
20216 delete[] mData;
20217 mIsEmpty = mKeySize == 0 || mValueSize == 0;
20218 if (!mIsEmpty)
19712 if (keySize != mKeySize || valueSize != mValueSize)
19713 {
19714 mKeySize = keySize;
19715 mValueSize = valueSize;
19716 if (mData)
19717 delete[] mData;
19718 mIsEmpty = mKeySize == 0 || mValueSize == 0;
19719 if (!mIsEmpty)
20219 19720 {
20220 19721 #ifdef __EXCEPTIONS
20221 try { // 2D arrays get memory intensive fast. So if the allocation fails, at least output debug message
19722 try { // 2D arrays get memory intensive fast. So if the allocation fails, at least output debug message
20222 19723 #endif
20223 mData = new double[mKeySize*mValueSize];
19724 mData = new double[mKeySize*mValueSize];
20224 19725 #ifdef __EXCEPTIONS
20225 } catch (...) { mData = 0; }
19726 } catch (...) { mData = 0; }
20226 19727 #endif
20227 if (mData)
20228 fill(0);
20229 else
20230 qDebug() << Q_FUNC_INFO << "out of memory for data dimensions "<< mKeySize << "*" << mValueSize;
19728 if (mData)
19729 fill(0);
19730 else
19731 qDebug() << Q_FUNC_INFO << "out of memory for data dimensions "<< mKeySize << "*" << mValueSize;
20231 19732 } else
20232 mData = 0;
20233 mDataModified = true;
19733 mData = 0;
19734 mDataModified = true;
20234 19735 }
20235 19736 }
20236 19737
@@ -20246,7 +19747,7 void QCPColorMapData::setSize(int keySiz
20246 19747 */
20247 19748 void QCPColorMapData::setKeySize(int keySize)
20248 19749 {
20249 setSize(keySize, mValueSize);
19750 setSize(keySize, mValueSize);
20250 19751 }
20251 19752
20252 19753 /*!
@@ -20261,7 +19762,7 void QCPColorMapData::setKeySize(int key
20261 19762 */
20262 19763 void QCPColorMapData::setValueSize(int valueSize)
20263 19764 {
20264 setSize(mKeySize, valueSize);
19765 setSize(mKeySize, valueSize);
20265 19766 }
20266 19767
20267 19768 /*!
@@ -20276,8 +19777,8 void QCPColorMapData::setValueSize(int v
20276 19777 */
20277 19778 void QCPColorMapData::setRange(const QCPRange &keyRange, const QCPRange &valueRange)
20278 19779 {
20279 setKeyRange(keyRange);
20280 setValueRange(valueRange);
19780 setKeyRange(keyRange);
19781 setValueRange(valueRange);
20281 19782 }
20282 19783
20283 19784 /*!
@@ -20292,7 +19793,7 void QCPColorMapData::setRange(const QCP
20292 19793 */
20293 19794 void QCPColorMapData::setKeyRange(const QCPRange &keyRange)
20294 19795 {
20295 mKeyRange = keyRange;
19796 mKeyRange = keyRange;
20296 19797 }
20297 19798
20298 19799 /*!
@@ -20307,7 +19808,7 void QCPColorMapData::setKeyRange(const
20307 19808 */
20308 19809 void QCPColorMapData::setValueRange(const QCPRange &valueRange)
20309 19810 {
20310 mValueRange = valueRange;
19811 mValueRange = valueRange;
20311 19812 }
20312 19813
20313 19814 /*!
@@ -20318,16 +19819,16 void QCPColorMapData::setValueRange(cons
20318 19819 */
20319 19820 void QCPColorMapData::setData(double key, double value, double z)
20320 19821 {
20321 int keyCell = (key-mKeyRange.lower)/(mKeyRange.upper-mKeyRange.lower)*(mKeySize-1)+0.5;
20322 int valueCell = (value-mValueRange.lower)/(mValueRange.upper-mValueRange.lower)*(mValueSize-1)+0.5;
20323 if (keyCell >= 0 && keyCell < mKeySize && valueCell >= 0 && valueCell < mValueSize)
20324 {
20325 mData[valueCell*mKeySize + keyCell] = z;
20326 if (z < mDataBounds.lower)
20327 mDataBounds.lower = z;
20328 if (z > mDataBounds.upper)
20329 mDataBounds.upper = z;
20330 mDataModified = true;
19822 int keyCell = (key-mKeyRange.lower)/(mKeyRange.upper-mKeyRange.lower)*(mKeySize-1)+0.5;
19823 int valueCell = (value-mValueRange.lower)/(mValueRange.upper-mValueRange.lower)*(mValueSize-1)+0.5;
19824 if (keyCell >= 0 && keyCell < mKeySize && valueCell >= 0 && valueCell < mValueSize)
19825 {
19826 mData[valueCell*mKeySize + keyCell] = z;
19827 if (z < mDataBounds.lower)
19828 mDataBounds.lower = z;
19829 if (z > mDataBounds.upper)
19830 mDataBounds.upper = z;
19831 mDataModified = true;
20331 19832 }
20332 19833 }
20333 19834
@@ -20344,14 +19845,14 void QCPColorMapData::setData(double key
20344 19845 */
20345 19846 void QCPColorMapData::setCell(int keyIndex, int valueIndex, double z)
20346 19847 {
20347 if (keyIndex >= 0 && keyIndex < mKeySize && valueIndex >= 0 && valueIndex < mValueSize)
20348 {
20349 mData[valueIndex*mKeySize + keyIndex] = z;
20350 if (z < mDataBounds.lower)
20351 mDataBounds.lower = z;
20352 if (z > mDataBounds.upper)
20353 mDataBounds.upper = z;
20354 mDataModified = true;
19848 if (keyIndex >= 0 && keyIndex < mKeySize && valueIndex >= 0 && valueIndex < mValueSize)
19849 {
19850 mData[valueIndex*mKeySize + keyIndex] = z;
19851 if (z < mDataBounds.lower)
19852 mDataBounds.lower = z;
19853 if (z > mDataBounds.upper)
19854 mDataBounds.upper = z;
19855 mDataModified = true;
20355 19856 }
20356 19857 }
20357 19858
@@ -20370,20 +19871,20 void QCPColorMapData::setCell(int keyInd
20370 19871 */
20371 19872 void QCPColorMapData::recalculateDataBounds()
20372 19873 {
20373 if (mKeySize > 0 && mValueSize > 0)
20374 {
20375 double minHeight = mData[0];
20376 double maxHeight = mData[0];
20377 const int dataCount = mValueSize*mKeySize;
20378 for (int i=0; i<dataCount; ++i)
20379 {
20380 if (mData[i] > maxHeight)
20381 maxHeight = mData[i];
20382 if (mData[i] < minHeight)
20383 minHeight = mData[i];
20384 }
20385 mDataBounds.lower = minHeight;
20386 mDataBounds.upper = maxHeight;
19874 if (mKeySize > 0 && mValueSize > 0)
19875 {
19876 double minHeight = mData[0];
19877 double maxHeight = mData[0];
19878 const int dataCount = mValueSize*mKeySize;
19879 for (int i=0; i<dataCount; ++i)
19880 {
19881 if (mData[i] > maxHeight)
19882 maxHeight = mData[i];
19883 if (mData[i] < minHeight)
19884 minHeight = mData[i];
19885 }
19886 mDataBounds.lower = minHeight;
19887 mDataBounds.upper = maxHeight;
20387 19888 }
20388 19889 }
20389 19890
@@ -20394,7 +19895,7 void QCPColorMapData::recalculateDataBou
20394 19895 */
20395 19896 void QCPColorMapData::clear()
20396 19897 {
20397 setSize(0, 0);
19898 setSize(0, 0);
20398 19899 }
20399 19900
20400 19901 /*!
@@ -20402,10 +19903,10 void QCPColorMapData::clear()
20402 19903 */
20403 19904 void QCPColorMapData::fill(double z)
20404 19905 {
20405 const int dataCount = mValueSize*mKeySize;
20406 for (int i=0; i<dataCount; ++i)
20407 mData[i] = z;
20408 mDataBounds = QCPRange(z, z);
19906 const int dataCount = mValueSize*mKeySize;
19907 for (int i=0; i<dataCount; ++i)
19908 mData[i] = z;
19909 mDataBounds = QCPRange(z, z);
20409 19910 }
20410 19911
20411 19912 /*!
@@ -20422,10 +19923,10 void QCPColorMapData::fill(double z)
20422 19923 */
20423 19924 void QCPColorMapData::coordToCell(double key, double value, int *keyIndex, int *valueIndex) const
20424 19925 {
20425 if (keyIndex)
20426 *keyIndex = (key-mKeyRange.lower)/(mKeyRange.upper-mKeyRange.lower)*(mKeySize-1)+0.5;
20427 if (valueIndex)
20428 *valueIndex = (value-mValueRange.lower)/(mValueRange.upper-mValueRange.lower)*(mValueSize-1)+0.5;
19926 if (keyIndex)
19927 *keyIndex = (key-mKeyRange.lower)/(mKeyRange.upper-mKeyRange.lower)*(mKeySize-1)+0.5;
19928 if (valueIndex)
19929 *valueIndex = (value-mValueRange.lower)/(mValueRange.upper-mValueRange.lower)*(mValueSize-1)+0.5;
20429 19930 }
20430 19931
20431 19932 /*!
@@ -20440,10 +19941,10 void QCPColorMapData::coordToCell(double
20440 19941 */
20441 19942 void QCPColorMapData::cellToCoord(int keyIndex, int valueIndex, double *key, double *value) const
20442 19943 {
20443 if (key)
20444 *key = keyIndex/(double)(mKeySize-1)*(mKeyRange.upper-mKeyRange.lower)+mKeyRange.lower;
20445 if (value)
20446 *value = valueIndex/(double)(mValueSize-1)*(mValueRange.upper-mValueRange.lower)+mValueRange.lower;
19944 if (key)
19945 *key = keyIndex/(double)(mKeySize-1)*(mKeyRange.upper-mKeyRange.lower)+mKeyRange.lower;
19946 if (value)
19947 *value = valueIndex/(double)(mValueSize-1)*(mValueRange.upper-mValueRange.lower)+mValueRange.lower;
20447 19948 }
20448 19949
20449 19950
@@ -20567,18 +20068,18 void QCPColorMapData::cellToCoord(int ke
20567 20068 then takes ownership of the color map.
20568 20069 */
20569 20070 QCPColorMap::QCPColorMap(QCPAxis *keyAxis, QCPAxis *valueAxis) :
20570 QCPAbstractPlottable(keyAxis, valueAxis),
20571 mDataScaleType(QCPAxis::stLinear),
20572 mMapData(new QCPColorMapData(10, 10, QCPRange(0, 5), QCPRange(0, 5))),
20573 mInterpolate(true),
20574 mTightBoundary(false),
20575 mMapImageInvalidated(true)
20071 QCPAbstractPlottable(keyAxis, valueAxis),
20072 mDataScaleType(QCPAxis::stLinear),
20073 mMapData(new QCPColorMapData(10, 10, QCPRange(0, 5), QCPRange(0, 5))),
20074 mInterpolate(true),
20075 mTightBoundary(false),
20076 mMapImageInvalidated(true)
20576 20077 {
20577 20078 }
20578 20079
20579 20080 QCPColorMap::~QCPColorMap()
20580 20081 {
20581 delete mMapData;
20082 delete mMapData;
20582 20083 }
20583 20084
20584 20085 /*!
@@ -20590,20 +20091,20 QCPColorMap::~QCPColorMap()
20590 20091 */
20591 20092 void QCPColorMap::setData(QCPColorMapData *data, bool copy)
20592 20093 {
20593 if (mMapData == data)
20594 {
20595 qDebug() << Q_FUNC_INFO << "The data pointer is already in (and owned by) this plottable" << reinterpret_cast<quintptr>(data);
20596 return;
20597 }
20598 if (copy)
20599 {
20600 *mMapData = *data;
20601 } else
20602 {
20603 delete mMapData;
20604 mMapData = data;
20605 }
20606 mMapImageInvalidated = true;
20094 if (mMapData == data)
20095 {
20096 qDebug() << Q_FUNC_INFO << "The data pointer is already in (and owned by) this plottable" << reinterpret_cast<quintptr>(data);
20097 return;
20098 }
20099 if (copy)
20100 {
20101 *mMapData = *data;
20102 } else
20103 {
20104 delete mMapData;
20105 mMapData = data;
20106 }
20107 mMapImageInvalidated = true;
20607 20108 }
20608 20109
20609 20110 /*!
@@ -20616,15 +20117,15 void QCPColorMap::setData(QCPColorMapDat
20616 20117 */
20617 20118 void QCPColorMap::setDataRange(const QCPRange &dataRange)
20618 20119 {
20619 if (!QCPRange::validRange(dataRange)) return;
20620 if (mDataRange.lower != dataRange.lower || mDataRange.upper != dataRange.upper)
20621 {
20622 if (mDataScaleType == QCPAxis::stLogarithmic)
20623 mDataRange = dataRange.sanitizedForLogScale();
20624 else
20625 mDataRange = dataRange.sanitizedForLinScale();
20626 mMapImageInvalidated = true;
20627 emit dataRangeChanged(mDataRange);
20120 if (!QCPRange::validRange(dataRange)) return;
20121 if (mDataRange.lower != dataRange.lower || mDataRange.upper != dataRange.upper)
20122 {
20123 if (mDataScaleType == QCPAxis::stLogarithmic)
20124 mDataRange = dataRange.sanitizedForLogScale();
20125 else
20126 mDataRange = dataRange.sanitizedForLinScale();
20127 mMapImageInvalidated = true;
20128 emit dataRangeChanged(mDataRange);
20628 20129 }
20629 20130 }
20630 20131
@@ -20635,13 +20136,13 void QCPColorMap::setDataRange(const QCP
20635 20136 */
20636 20137 void QCPColorMap::setDataScaleType(QCPAxis::ScaleType scaleType)
20637 20138 {
20638 if (mDataScaleType != scaleType)
20639 {
20640 mDataScaleType = scaleType;
20641 mMapImageInvalidated = true;
20642 emit dataScaleTypeChanged(mDataScaleType);
20643 if (mDataScaleType == QCPAxis::stLogarithmic)
20644 setDataRange(mDataRange.sanitizedForLogScale());
20139 if (mDataScaleType != scaleType)
20140 {
20141 mDataScaleType = scaleType;
20142 mMapImageInvalidated = true;
20143 emit dataScaleTypeChanged(mDataScaleType);
20144 if (mDataScaleType == QCPAxis::stLogarithmic)
20145 setDataRange(mDataRange.sanitizedForLogScale());
20645 20146 }
20646 20147 }
20647 20148
@@ -20658,11 +20159,11 void QCPColorMap::setDataScaleType(QCPAx
20658 20159 */
20659 20160 void QCPColorMap::setGradient(const QCPColorGradient &gradient)
20660 20161 {
20661 if (mGradient != gradient)
20662 {
20663 mGradient = gradient;
20664 mMapImageInvalidated = true;
20665 emit gradientChanged(mGradient);
20162 if (mGradient != gradient)
20163 {
20164 mGradient = gradient;
20165 mMapImageInvalidated = true;
20166 emit gradientChanged(mGradient);
20666 20167 }
20667 20168 }
20668 20169
@@ -20674,7 +20175,7 void QCPColorMap::setGradient(const QCPC
20674 20175 */
20675 20176 void QCPColorMap::setInterpolate(bool enabled)
20676 20177 {
20677 mInterpolate = enabled;
20178 mInterpolate = enabled;
20678 20179 }
20679 20180
20680 20181 /*!
@@ -20690,7 +20191,7 void QCPColorMap::setInterpolate(bool en
20690 20191 */
20691 20192 void QCPColorMap::setTightBoundary(bool enabled)
20692 20193 {
20693 mTightBoundary = enabled;
20194 mTightBoundary = enabled;
20694 20195 }
20695 20196
20696 20197 /*!
@@ -20709,27 +20210,27 void QCPColorMap::setTightBoundary(bool
20709 20210 */
20710 20211 void QCPColorMap::setColorScale(QCPColorScale *colorScale)
20711 20212 {
20712 if (mColorScale) // unconnect signals from old color scale
20713 {
20714 disconnect(this, SIGNAL(dataRangeChanged(QCPRange)), mColorScale.data(), SLOT(setDataRange(QCPRange)));
20715 disconnect(this, SIGNAL(dataScaleTypeChanged(QCPAxis::ScaleType)), mColorScale.data(), SLOT(setDataScaleType(QCPAxis::ScaleType)));
20716 disconnect(this, SIGNAL(gradientChanged(QCPColorGradient)), mColorScale.data(), SLOT(setGradient(QCPColorGradient)));
20717 disconnect(mColorScale.data(), SIGNAL(dataRangeChanged(QCPRange)), this, SLOT(setDataRange(QCPRange)));
20718 disconnect(mColorScale.data(), SIGNAL(gradientChanged(QCPColorGradient)), this, SLOT(setGradient(QCPColorGradient)));
20719 disconnect(mColorScale.data(), SIGNAL(dataScaleTypeChanged(QCPAxis::ScaleType)), this, SLOT(setDataScaleType(QCPAxis::ScaleType)));
20720 }
20721 mColorScale = colorScale;
20722 if (mColorScale) // connect signals to new color scale
20723 {
20724 setGradient(mColorScale.data()->gradient());
20725 setDataRange(mColorScale.data()->dataRange());
20726 setDataScaleType(mColorScale.data()->dataScaleType());
20727 connect(this, SIGNAL(dataRangeChanged(QCPRange)), mColorScale.data(), SLOT(setDataRange(QCPRange)));
20728 connect(this, SIGNAL(dataScaleTypeChanged(QCPAxis::ScaleType)), mColorScale.data(), SLOT(setDataScaleType(QCPAxis::ScaleType)));
20729 connect(this, SIGNAL(gradientChanged(QCPColorGradient)), mColorScale.data(), SLOT(setGradient(QCPColorGradient)));
20730 connect(mColorScale.data(), SIGNAL(dataRangeChanged(QCPRange)), this, SLOT(setDataRange(QCPRange)));
20731 connect(mColorScale.data(), SIGNAL(gradientChanged(QCPColorGradient)), this, SLOT(setGradient(QCPColorGradient)));
20732 connect(mColorScale.data(), SIGNAL(dataScaleTypeChanged(QCPAxis::ScaleType)), this, SLOT(setDataScaleType(QCPAxis::ScaleType)));
20213 if (mColorScale) // unconnect signals from old color scale
20214 {
20215 disconnect(this, SIGNAL(dataRangeChanged(QCPRange)), mColorScale.data(), SLOT(setDataRange(QCPRange)));
20216 disconnect(this, SIGNAL(dataScaleTypeChanged(QCPAxis::ScaleType)), mColorScale.data(), SLOT(setDataScaleType(QCPAxis::ScaleType)));
20217 disconnect(this, SIGNAL(gradientChanged(QCPColorGradient)), mColorScale.data(), SLOT(setGradient(QCPColorGradient)));
20218 disconnect(mColorScale.data(), SIGNAL(dataRangeChanged(QCPRange)), this, SLOT(setDataRange(QCPRange)));
20219 disconnect(mColorScale.data(), SIGNAL(gradientChanged(QCPColorGradient)), this, SLOT(setGradient(QCPColorGradient)));
20220 disconnect(mColorScale.data(), SIGNAL(dataScaleTypeChanged(QCPAxis::ScaleType)), this, SLOT(setDataScaleType(QCPAxis::ScaleType)));
20221 }
20222 mColorScale = colorScale;
20223 if (mColorScale) // connect signals to new color scale
20224 {
20225 setGradient(mColorScale.data()->gradient());
20226 setDataRange(mColorScale.data()->dataRange());
20227 setDataScaleType(mColorScale.data()->dataScaleType());
20228 connect(this, SIGNAL(dataRangeChanged(QCPRange)), mColorScale.data(), SLOT(setDataRange(QCPRange)));
20229 connect(this, SIGNAL(dataScaleTypeChanged(QCPAxis::ScaleType)), mColorScale.data(), SLOT(setDataScaleType(QCPAxis::ScaleType)));
20230 connect(this, SIGNAL(gradientChanged(QCPColorGradient)), mColorScale.data(), SLOT(setGradient(QCPColorGradient)));
20231 connect(mColorScale.data(), SIGNAL(dataRangeChanged(QCPRange)), this, SLOT(setDataRange(QCPRange)));
20232 connect(mColorScale.data(), SIGNAL(gradientChanged(QCPColorGradient)), this, SLOT(setGradient(QCPColorGradient)));
20233 connect(mColorScale.data(), SIGNAL(dataScaleTypeChanged(QCPAxis::ScaleType)), this, SLOT(setDataScaleType(QCPAxis::ScaleType)));
20733 20234 }
20734 20235 }
20735 20236
@@ -20755,9 +20256,9 void QCPColorMap::setColorScale(QCPColor
20755 20256 */
20756 20257 void QCPColorMap::rescaleDataRange(bool recalculateDataBounds)
20757 20258 {
20758 if (recalculateDataBounds)
20759 mMapData->recalculateDataBounds();
20760 setDataRange(mMapData->dataBounds());
20259 if (recalculateDataBounds)
20260 mMapData->recalculateDataBounds();
20261 setDataRange(mMapData->dataBounds());
20761 20262 }
20762 20263
20763 20264 /*!
@@ -20776,14 +20277,14 void QCPColorMap::rescaleDataRange(bool
20776 20277 */
20777 20278 void QCPColorMap::updateLegendIcon(Qt::TransformationMode transformMode, const QSize &thumbSize)
20778 20279 {
20779 if (mMapImage.isNull() && !data()->isEmpty())
20780 updateMapImage(); // try to update map image if it's null (happens if no draw has happened yet)
20781
20782 if (!mMapImage.isNull()) // might still be null, e.g. if data is empty, so check here again
20783 {
20784 bool mirrorX = (keyAxis()->orientation() == Qt::Horizontal ? keyAxis() : valueAxis())->rangeReversed();
20785 bool mirrorY = (valueAxis()->orientation() == Qt::Vertical ? valueAxis() : keyAxis())->rangeReversed();
20786 mLegendIcon = QPixmap::fromImage(mMapImage.mirrored(mirrorX, mirrorY)).scaled(thumbSize, Qt::KeepAspectRatio, transformMode);
20280 if (mMapImage.isNull() && !data()->isEmpty())
20281 updateMapImage(); // try to update map image if it's null (happens if no draw has happened yet)
20282
20283 if (!mMapImage.isNull()) // might still be null, e.g. if data is empty, so check here again
20284 {
20285 bool mirrorX = (keyAxis()->orientation() == Qt::Horizontal ? keyAxis() : valueAxis())->rangeReversed();
20286 bool mirrorY = (valueAxis()->orientation() == Qt::Vertical ? valueAxis() : keyAxis())->rangeReversed();
20287 mLegendIcon = QPixmap::fromImage(mMapImage.mirrored(mirrorX, mirrorY)).scaled(thumbSize, Qt::KeepAspectRatio, transformMode);
20787 20288 }
20788 20289 }
20789 20290
@@ -20793,25 +20294,25 void QCPColorMap::updateLegendIcon(Qt::T
20793 20294 */
20794 20295 void QCPColorMap::clearData()
20795 20296 {
20796 mMapData->clear();
20297 mMapData->clear();
20797 20298 }
20798 20299
20799 20300 /* inherits documentation from base class */
20800 20301 double QCPColorMap::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
20801 20302 {
20802 Q_UNUSED(details)
20803 if (onlySelectable && !mSelectable)
20303 Q_UNUSED(details)
20304 if (onlySelectable && !mSelectable)
20305 return -1;
20306 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
20307
20308 if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()))
20309 {
20310 double posKey, posValue;
20311 pixelsToCoords(pos, posKey, posValue);
20312 if (mMapData->keyRange().contains(posKey) && mMapData->valueRange().contains(posValue))
20313 return mParentPlot->selectionTolerance()*0.99;
20314 }
20804 20315 return -1;
20805 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
20806
20807 if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()))
20808 {
20809 double posKey, posValue;
20810 pixelsToCoords(pos, posKey, posValue);
20811 if (mMapData->keyRange().contains(posKey) && mMapData->valueRange().contains(posValue))
20812 return mParentPlot->selectionTolerance()*0.99;
20813 }
20814 return -1;
20815 20316 }
20816 20317
20817 20318 /*! \internal
@@ -20825,92 +20326,92 double QCPColorMap::selectTest(const QPo
20825 20326 */
20826 20327 void QCPColorMap::updateMapImage()
20827 20328 {
20828 QCPAxis *keyAxis = mKeyAxis.data();
20829 if (!keyAxis) return;
20830
20831 // resize mMapImage to correct dimensions, according to key/value axes orientation:
20832 if (keyAxis->orientation() == Qt::Horizontal && (mMapImage.size().width() != mMapData->keySize() || mMapImage.size().height() != mMapData->valueSize()))
20833 mMapImage = QImage(QSize(mMapData->keySize(), mMapData->valueSize()), QImage::Format_RGB32);
20834 else if (keyAxis->orientation() == Qt::Vertical && (mMapImage.size().width() != mMapData->valueSize() || mMapImage.size().height() != mMapData->keySize()))
20835 mMapImage = QImage(QSize(mMapData->valueSize(), mMapData->keySize()), QImage::Format_RGB32);
20836
20837 const int keySize = mMapData->keySize();
20838 const int valueSize = mMapData->valueSize();
20839 const double *rawData = mMapData->mData;
20840
20841 if (keyAxis->orientation() == Qt::Horizontal)
20842 {
20843 const int lineCount = valueSize;
20844 const int rowCount = keySize;
20845 for (int line=0; line<lineCount; ++line)
20846 {
20847 QRgb* pixels = reinterpret_cast<QRgb*>(mMapImage.scanLine(lineCount-1-line)); // invert scanline index because QImage counts scanlines from top, but our vertical index counts from bottom (mathematical coordinate system)
20848 mGradient.colorize(rawData+line*rowCount, mDataRange, pixels, rowCount, 1, mDataScaleType==QCPAxis::stLogarithmic);
20329 QCPAxis *keyAxis = mKeyAxis.data();
20330 if (!keyAxis) return;
20331
20332 // resize mMapImage to correct dimensions, according to key/value axes orientation:
20333 if (keyAxis->orientation() == Qt::Horizontal && (mMapImage.size().width() != mMapData->keySize() || mMapImage.size().height() != mMapData->valueSize()))
20334 mMapImage = QImage(QSize(mMapData->keySize(), mMapData->valueSize()), QImage::Format_RGB32);
20335 else if (keyAxis->orientation() == Qt::Vertical && (mMapImage.size().width() != mMapData->valueSize() || mMapImage.size().height() != mMapData->keySize()))
20336 mMapImage = QImage(QSize(mMapData->valueSize(), mMapData->keySize()), QImage::Format_RGB32);
20337
20338 const int keySize = mMapData->keySize();
20339 const int valueSize = mMapData->valueSize();
20340 const double *rawData = mMapData->mData;
20341
20342 if (keyAxis->orientation() == Qt::Horizontal)
20343 {
20344 const int lineCount = valueSize;
20345 const int rowCount = keySize;
20346 for (int line=0; line<lineCount; ++line)
20347 {
20348 QRgb* pixels = reinterpret_cast<QRgb*>(mMapImage.scanLine(lineCount-1-line)); // invert scanline index because QImage counts scanlines from top, but our vertical index counts from bottom (mathematical coordinate system)
20349 mGradient.colorize(rawData+line*rowCount, mDataRange, pixels, rowCount, 1, mDataScaleType==QCPAxis::stLogarithmic);
20849 20350 }
20850 20351 } else // keyAxis->orientation() == Qt::Vertical
20851 20352 {
20852 const int lineCount = keySize;
20853 const int rowCount = valueSize;
20854 for (int line=0; line<lineCount; ++line)
20855 {
20856 QRgb* pixels = reinterpret_cast<QRgb*>(mMapImage.scanLine(lineCount-1-line)); // invert scanline index because QImage counts scanlines from top, but our vertical index counts from bottom (mathematical coordinate system)
20857 mGradient.colorize(rawData+line, mDataRange, pixels, rowCount, lineCount, mDataScaleType==QCPAxis::stLogarithmic);
20858 }
20859 }
20860
20861 mMapData->mDataModified = false;
20862 mMapImageInvalidated = false;
20353 const int lineCount = keySize;
20354 const int rowCount = valueSize;
20355 for (int line=0; line<lineCount; ++line)
20356 {
20357 QRgb* pixels = reinterpret_cast<QRgb*>(mMapImage.scanLine(lineCount-1-line)); // invert scanline index because QImage counts scanlines from top, but our vertical index counts from bottom (mathematical coordinate system)
20358 mGradient.colorize(rawData+line, mDataRange, pixels, rowCount, lineCount, mDataScaleType==QCPAxis::stLogarithmic);
20359 }
20360 }
20361
20362 mMapData->mDataModified = false;
20363 mMapImageInvalidated = false;
20863 20364 }
20864 20365
20865 20366 /* inherits documentation from base class */
20866 20367 void QCPColorMap::draw(QCPPainter *painter)
20867 20368 {
20868 if (mMapData->isEmpty()) return;
20869 if (!mKeyAxis || !mValueAxis) return;
20870 applyDefaultAntialiasingHint(painter);
20871
20872 if (mMapData->mDataModified || mMapImageInvalidated)
20873 updateMapImage();
20874
20875 double halfSampleKey = 0;
20876 double halfSampleValue = 0;
20877 if (mMapData->keySize() > 1)
20878 halfSampleKey = 0.5*mMapData->keyRange().size()/(double)(mMapData->keySize()-1);
20879 if (mMapData->valueSize() > 1)
20880 halfSampleValue = 0.5*mMapData->valueRange().size()/(double)(mMapData->valueSize()-1);
20881 QRectF imageRect(coordsToPixels(mMapData->keyRange().lower-halfSampleKey, mMapData->valueRange().lower-halfSampleValue),
20882 coordsToPixels(mMapData->keyRange().upper+halfSampleKey, mMapData->valueRange().upper+halfSampleValue));
20883 imageRect = imageRect.normalized();
20884 bool mirrorX = (keyAxis()->orientation() == Qt::Horizontal ? keyAxis() : valueAxis())->rangeReversed();
20885 bool mirrorY = (valueAxis()->orientation() == Qt::Vertical ? valueAxis() : keyAxis())->rangeReversed();
20886 bool smoothBackup = painter->renderHints().testFlag(QPainter::SmoothPixmapTransform);
20887 painter->setRenderHint(QPainter::SmoothPixmapTransform, mInterpolate);
20888 QRegion clipBackup;
20889 if (mTightBoundary)
20890 {
20891 clipBackup = painter->clipRegion();
20892 painter->setClipRect(QRectF(coordsToPixels(mMapData->keyRange().lower, mMapData->valueRange().lower),
20893 coordsToPixels(mMapData->keyRange().upper, mMapData->valueRange().upper)).normalized(), Qt::IntersectClip);
20894 }
20895 painter->drawImage(imageRect, mMapImage.mirrored(mirrorX, mirrorY));
20896 if (mTightBoundary)
20897 painter->setClipRegion(clipBackup);
20898 painter->setRenderHint(QPainter::SmoothPixmapTransform, smoothBackup);
20369 if (mMapData->isEmpty()) return;
20370 if (!mKeyAxis || !mValueAxis) return;
20371 applyDefaultAntialiasingHint(painter);
20372
20373 if (mMapData->mDataModified || mMapImageInvalidated)
20374 updateMapImage();
20375
20376 double halfSampleKey = 0;
20377 double halfSampleValue = 0;
20378 if (mMapData->keySize() > 1)
20379 halfSampleKey = 0.5*mMapData->keyRange().size()/(double)(mMapData->keySize()-1);
20380 if (mMapData->valueSize() > 1)
20381 halfSampleValue = 0.5*mMapData->valueRange().size()/(double)(mMapData->valueSize()-1);
20382 QRectF imageRect(coordsToPixels(mMapData->keyRange().lower-halfSampleKey, mMapData->valueRange().lower-halfSampleValue),
20383 coordsToPixels(mMapData->keyRange().upper+halfSampleKey, mMapData->valueRange().upper+halfSampleValue));
20384 imageRect = imageRect.normalized();
20385 bool mirrorX = (keyAxis()->orientation() == Qt::Horizontal ? keyAxis() : valueAxis())->rangeReversed();
20386 bool mirrorY = (valueAxis()->orientation() == Qt::Vertical ? valueAxis() : keyAxis())->rangeReversed();
20387 bool smoothBackup = painter->renderHints().testFlag(QPainter::SmoothPixmapTransform);
20388 painter->setRenderHint(QPainter::SmoothPixmapTransform, mInterpolate);
20389 QRegion clipBackup;
20390 if (mTightBoundary)
20391 {
20392 clipBackup = painter->clipRegion();
20393 painter->setClipRect(QRectF(coordsToPixels(mMapData->keyRange().lower, mMapData->valueRange().lower),
20394 coordsToPixels(mMapData->keyRange().upper, mMapData->valueRange().upper)).normalized(), Qt::IntersectClip);
20395 }
20396 painter->drawImage(imageRect, mMapImage.mirrored(mirrorX, mirrorY));
20397 if (mTightBoundary)
20398 painter->setClipRegion(clipBackup);
20399 painter->setRenderHint(QPainter::SmoothPixmapTransform, smoothBackup);
20899 20400 }
20900 20401
20901 20402 /* inherits documentation from base class */
20902 20403 void QCPColorMap::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const
20903 20404 {
20904 applyDefaultAntialiasingHint(painter);
20905 // draw map thumbnail:
20906 if (!mLegendIcon.isNull())
20907 {
20908 QPixmap scaledIcon = mLegendIcon.scaled(rect.size().toSize(), Qt::KeepAspectRatio, Qt::FastTransformation);
20909 QRectF iconRect = QRectF(0, 0, scaledIcon.width(), scaledIcon.height());
20910 iconRect.moveCenter(rect.center());
20911 painter->drawPixmap(iconRect.topLeft(), scaledIcon);
20912 }
20913 /*
20405 applyDefaultAntialiasingHint(painter);
20406 // draw map thumbnail:
20407 if (!mLegendIcon.isNull())
20408 {
20409 QPixmap scaledIcon = mLegendIcon.scaled(rect.size().toSize(), Qt::KeepAspectRatio, Qt::FastTransformation);
20410 QRectF iconRect = QRectF(0, 0, scaledIcon.width(), scaledIcon.height());
20411 iconRect.moveCenter(rect.center());
20412 painter->drawPixmap(iconRect.topLeft(), scaledIcon);
20413 }
20414 /*
20914 20415 // draw frame:
20915 20416 painter->setBrush(Qt::NoBrush);
20916 20417 painter->setPen(Qt::black);
@@ -20921,45 +20422,45 void QCPColorMap::drawLegendIcon(QCPPain
20921 20422 /* inherits documentation from base class */
20922 20423 QCPRange QCPColorMap::getKeyRange(bool &foundRange, SignDomain inSignDomain) const
20923 20424 {
20924 foundRange = true;
20925 QCPRange result = mMapData->keyRange();
20926 result.normalize();
20927 if (inSignDomain == QCPAbstractPlottable::sdPositive)
20928 {
20929 if (result.lower <= 0 && result.upper > 0)
20930 result.lower = result.upper*1e-3;
20931 else if (result.lower <= 0 && result.upper <= 0)
20932 foundRange = false;
20425 foundRange = true;
20426 QCPRange result = mMapData->keyRange();
20427 result.normalize();
20428 if (inSignDomain == QCPAbstractPlottable::sdPositive)
20429 {
20430 if (result.lower <= 0 && result.upper > 0)
20431 result.lower = result.upper*1e-3;
20432 else if (result.lower <= 0 && result.upper <= 0)
20433 foundRange = false;
20933 20434 } else if (inSignDomain == QCPAbstractPlottable::sdNegative)
20934 20435 {
20935 if (result.upper >= 0 && result.lower < 0)
20936 result.upper = result.lower*1e-3;
20937 else if (result.upper >= 0 && result.lower >= 0)
20938 foundRange = false;
20939 }
20940 return result;
20436 if (result.upper >= 0 && result.lower < 0)
20437 result.upper = result.lower*1e-3;
20438 else if (result.upper >= 0 && result.lower >= 0)
20439 foundRange = false;
20440 }
20441 return result;
20941 20442 }
20942 20443
20943 20444 /* inherits documentation from base class */
20944 20445 QCPRange QCPColorMap::getValueRange(bool &foundRange, SignDomain inSignDomain) const
20945 20446 {
20946 foundRange = true;
20947 QCPRange result = mMapData->valueRange();
20948 result.normalize();
20949 if (inSignDomain == QCPAbstractPlottable::sdPositive)
20950 {
20951 if (result.lower <= 0 && result.upper > 0)
20952 result.lower = result.upper*1e-3;
20953 else if (result.lower <= 0 && result.upper <= 0)
20954 foundRange = false;
20447 foundRange = true;
20448 QCPRange result = mMapData->valueRange();
20449 result.normalize();
20450 if (inSignDomain == QCPAbstractPlottable::sdPositive)
20451 {
20452 if (result.lower <= 0 && result.upper > 0)
20453 result.lower = result.upper*1e-3;
20454 else if (result.lower <= 0 && result.upper <= 0)
20455 foundRange = false;
20955 20456 } else if (inSignDomain == QCPAbstractPlottable::sdNegative)
20956 20457 {
20957 if (result.upper >= 0 && result.lower < 0)
20958 result.upper = result.lower*1e-3;
20959 else if (result.upper >= 0 && result.lower >= 0)
20960 foundRange = false;
20961 }
20962 return result;
20458 if (result.upper >= 0 && result.lower < 0)
20459 result.upper = result.lower*1e-3;
20460 else if (result.upper >= 0 && result.lower >= 0)
20461 foundRange = false;
20462 }
20463 return result;
20963 20464 }
20964 20465
20965 20466
@@ -20986,11 +20487,11 QCPRange QCPColorMap::getValueRange(bool
20986 20487 Constructs a data point with key and all values set to zero.
20987 20488 */
20988 20489 QCPFinancialData::QCPFinancialData() :
20989 key(0),
20990 open(0),
20991 high(0),
20992 low(0),
20993 close(0)
20490 key(0),
20491 open(0),
20492 high(0),
20493 low(0),
20494 close(0)
20994 20495 {
20995 20496 }
20996 20497
@@ -20998,11 +20499,11 QCPFinancialData::QCPFinancialData() :
20998 20499 Constructs a data point with the specified \a key and OHLC values.
20999 20500 */
21000 20501 QCPFinancialData::QCPFinancialData(double key, double open, double high, double low, double close) :
21001 key(key),
21002 open(open),
21003 high(high),
21004 low(low),
21005 close(close)
20502 key(key),
20503 open(open),
20504 high(high),
20505 low(low),
20506 close(close)
21006 20507 {
21007 20508 }
21008 20509
@@ -21064,25 +20565,25 QCPFinancialData::QCPFinancialData(doubl
21064 20565 then takes ownership of the financial chart.
21065 20566 */
21066 20567 QCPFinancial::QCPFinancial(QCPAxis *keyAxis, QCPAxis *valueAxis) :
21067 QCPAbstractPlottable(keyAxis, valueAxis),
21068 mData(0),
21069 mChartStyle(csOhlc),
21070 mWidth(0.5),
21071 mTwoColored(false),
21072 mBrushPositive(QBrush(QColor(210, 210, 255))),
21073 mBrushNegative(QBrush(QColor(255, 210, 210))),
21074 mPenPositive(QPen(QColor(10, 40, 180))),
21075 mPenNegative(QPen(QColor(180, 40, 10)))
21076 {
21077 mData = new QCPFinancialDataMap;
21078
21079 setSelectedPen(QPen(QColor(80, 80, 255), 2.5));
21080 setSelectedBrush(QBrush(QColor(80, 80, 255)));
20568 QCPAbstractPlottable(keyAxis, valueAxis),
20569 mData(0),
20570 mChartStyle(csOhlc),
20571 mWidth(0.5),
20572 mTwoColored(false),
20573 mBrushPositive(QBrush(QColor(210, 210, 255))),
20574 mBrushNegative(QBrush(QColor(255, 210, 210))),
20575 mPenPositive(QPen(QColor(10, 40, 180))),
20576 mPenNegative(QPen(QColor(180, 40, 10)))
20577 {
20578 mData = new QCPFinancialDataMap;
20579
20580 setSelectedPen(QPen(QColor(80, 80, 255), 2.5));
20581 setSelectedBrush(QBrush(QColor(80, 80, 255)));
21081 20582 }
21082 20583
21083 20584 QCPFinancial::~QCPFinancial()
21084 20585 {
21085 delete mData;
20586 delete mData;
21086 20587 }
21087 20588
21088 20589 /*!
@@ -21099,18 +20600,18 QCPFinancial::~QCPFinancial()
21099 20600 */
21100 20601 void QCPFinancial::setData(QCPFinancialDataMap *data, bool copy)
21101 20602 {
21102 if (mData == data)
21103 {
21104 qDebug() << Q_FUNC_INFO << "The data pointer is already in (and owned by) this plottable" << reinterpret_cast<quintptr>(data);
21105 return;
21106 }
21107 if (copy)
21108 {
21109 *mData = *data;
21110 } else
21111 {
21112 delete mData;
21113 mData = data;
20603 if (mData == data)
20604 {
20605 qDebug() << Q_FUNC_INFO << "The data pointer is already in (and owned by) this plottable" << reinterpret_cast<quintptr>(data);
20606 return;
20607 }
20608 if (copy)
20609 {
20610 *mData = *data;
20611 } else
20612 {
20613 delete mData;
20614 mData = data;
21114 20615 }
21115 20616 }
21116 20617
@@ -21123,15 +20624,15 void QCPFinancial::setData(QCPFinancialD
21123 20624 */
21124 20625 void QCPFinancial::setData(const QVector<double> &key, const QVector<double> &open, const QVector<double> &high, const QVector<double> &low, const QVector<double> &close)
21125 20626 {
21126 mData->clear();
21127 int n = key.size();
21128 n = qMin(n, open.size());
21129 n = qMin(n, high.size());
21130 n = qMin(n, low.size());
21131 n = qMin(n, close.size());
21132 for (int i=0; i<n; ++i)
21133 {
21134 mData->insertMulti(key[i], QCPFinancialData(key[i], open[i], high[i], low[i], close[i]));
20627 mData->clear();
20628 int n = key.size();
20629 n = qMin(n, open.size());
20630 n = qMin(n, high.size());
20631 n = qMin(n, low.size());
20632 n = qMin(n, close.size());
20633 for (int i=0; i<n; ++i)
20634 {
20635 mData->insertMulti(key[i], QCPFinancialData(key[i], open[i], high[i], low[i], close[i]));
21135 20636 }
21136 20637 }
21137 20638
@@ -21140,7 +20641,7 void QCPFinancial::setData(const QVector
21140 20641 */
21141 20642 void QCPFinancial::setChartStyle(QCPFinancial::ChartStyle style)
21142 20643 {
21143 mChartStyle = style;
20644 mChartStyle = style;
21144 20645 }
21145 20646
21146 20647 /*!
@@ -21150,7 +20651,7 void QCPFinancial::setChartStyle(QCPFina
21150 20651 */
21151 20652 void QCPFinancial::setWidth(double width)
21152 20653 {
21153 mWidth = width;
20654 mWidth = width;
21154 20655 }
21155 20656
21156 20657 /*!
@@ -21164,7 +20665,7 void QCPFinancial::setWidth(double width
21164 20665 */
21165 20666 void QCPFinancial::setTwoColored(bool twoColored)
21166 20667 {
21167 mTwoColored = twoColored;
20668 mTwoColored = twoColored;
21168 20669 }
21169 20670
21170 20671 /*!
@@ -21178,7 +20679,7 void QCPFinancial::setTwoColored(bool tw
21178 20679 */
21179 20680 void QCPFinancial::setBrushPositive(const QBrush &brush)
21180 20681 {
21181 mBrushPositive = brush;
20682 mBrushPositive = brush;
21182 20683 }
21183 20684
21184 20685 /*!
@@ -21192,7 +20693,7 void QCPFinancial::setBrushPositive(cons
21192 20693 */
21193 20694 void QCPFinancial::setBrushNegative(const QBrush &brush)
21194 20695 {
21195 mBrushNegative = brush;
20696 mBrushNegative = brush;
21196 20697 }
21197 20698
21198 20699 /*!
@@ -21206,7 +20707,7 void QCPFinancial::setBrushNegative(cons
21206 20707 */
21207 20708 void QCPFinancial::setPenPositive(const QPen &pen)
21208 20709 {
21209 mPenPositive = pen;
20710 mPenPositive = pen;
21210 20711 }
21211 20712
21212 20713 /*!
@@ -21220,7 +20721,7 void QCPFinancial::setPenPositive(const
21220 20721 */
21221 20722 void QCPFinancial::setPenNegative(const QPen &pen)
21222 20723 {
21223 mPenNegative = pen;
20724 mPenNegative = pen;
21224 20725 }
21225 20726
21226 20727 /*!
@@ -21233,7 +20734,7 void QCPFinancial::setPenNegative(const
21233 20734 */
21234 20735 void QCPFinancial::addData(const QCPFinancialDataMap &dataMap)
21235 20736 {
21236 mData->unite(dataMap);
20737 mData->unite(dataMap);
21237 20738 }
21238 20739
21239 20740 /*! \overload
@@ -21247,7 +20748,7 void QCPFinancial::addData(const QCPFina
21247 20748 */
21248 20749 void QCPFinancial::addData(const QCPFinancialData &data)
21249 20750 {
21250 mData->insertMulti(data.key, data);
20751 mData->insertMulti(data.key, data);
21251 20752 }
21252 20753
21253 20754 /*! \overload
@@ -21262,7 +20763,7 void QCPFinancial::addData(const QCPFina
21262 20763 */
21263 20764 void QCPFinancial::addData(double key, double open, double high, double low, double close)
21264 20765 {
21265 mData->insertMulti(key, QCPFinancialData(key, open, high, low, close));
20766 mData->insertMulti(key, QCPFinancialData(key, open, high, low, close));
21266 20767 }
21267 20768
21268 20769 /*! \overload
@@ -21276,14 +20777,14 void QCPFinancial::addData(double key, d
21276 20777 */
21277 20778 void QCPFinancial::addData(const QVector<double> &key, const QVector<double> &open, const QVector<double> &high, const QVector<double> &low, const QVector<double> &close)
21278 20779 {
21279 int n = key.size();
21280 n = qMin(n, open.size());
21281 n = qMin(n, high.size());
21282 n = qMin(n, low.size());
21283 n = qMin(n, close.size());
21284 for (int i=0; i<n; ++i)
21285 {
21286 mData->insertMulti(key[i], QCPFinancialData(key[i], open[i], high[i], low[i], close[i]));
20780 int n = key.size();
20781 n = qMin(n, open.size());
20782 n = qMin(n, high.size());
20783 n = qMin(n, low.size());
20784 n = qMin(n, close.size());
20785 for (int i=0; i<n; ++i)
20786 {
20787 mData->insertMulti(key[i], QCPFinancialData(key[i], open[i], high[i], low[i], close[i]));
21287 20788 }
21288 20789 }
21289 20790
@@ -21294,9 +20795,9 void QCPFinancial::addData(const QVector
21294 20795 */
21295 20796 void QCPFinancial::removeDataBefore(double key)
21296 20797 {
21297 QCPFinancialDataMap::iterator it = mData->begin();
21298 while (it != mData->end() && it.key() < key)
21299 it = mData->erase(it);
20798 QCPFinancialDataMap::iterator it = mData->begin();
20799 while (it != mData->end() && it.key() < key)
20800 it = mData->erase(it);
21300 20801 }
21301 20802
21302 20803 /*!
@@ -21306,10 +20807,10 void QCPFinancial::removeDataBefore(doub
21306 20807 */
21307 20808 void QCPFinancial::removeDataAfter(double key)
21308 20809 {
21309 if (mData->isEmpty()) return;
21310 QCPFinancialDataMap::iterator it = mData->upperBound(key);
21311 while (it != mData->end())
21312 it = mData->erase(it);
20810 if (mData->isEmpty()) return;
20811 QCPFinancialDataMap::iterator it = mData->upperBound(key);
20812 while (it != mData->end())
20813 it = mData->erase(it);
21313 20814 }
21314 20815
21315 20816 /*!
@@ -21321,11 +20822,11 void QCPFinancial::removeDataAfter(doubl
21321 20822 */
21322 20823 void QCPFinancial::removeData(double fromKey, double toKey)
21323 20824 {
21324 if (fromKey >= toKey || mData->isEmpty()) return;
21325 QCPFinancialDataMap::iterator it = mData->upperBound(fromKey);
21326 QCPFinancialDataMap::iterator itEnd = mData->upperBound(toKey);
21327 while (it != itEnd)
21328 it = mData->erase(it);
20825 if (fromKey >= toKey || mData->isEmpty()) return;
20826 QCPFinancialDataMap::iterator it = mData->upperBound(fromKey);
20827 QCPFinancialDataMap::iterator itEnd = mData->upperBound(toKey);
20828 while (it != itEnd)
20829 it = mData->erase(it);
21329 20830 }
21330 20831
21331 20832 /*! \overload
@@ -21338,7 +20839,7 void QCPFinancial::removeData(double fro
21338 20839 */
21339 20840 void QCPFinancial::removeData(double key)
21340 20841 {
21341 mData->remove(key);
20842 mData->remove(key);
21342 20843 }
21343 20844
21344 20845 /*!
@@ -21348,34 +20849,34 void QCPFinancial::removeData(double key
21348 20849 */
21349 20850 void QCPFinancial::clearData()
21350 20851 {
21351 mData->clear();
20852 mData->clear();
21352 20853 }
21353 20854
21354 20855 /* inherits documentation from base class */
21355 20856 double QCPFinancial::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
21356 20857 {
21357 Q_UNUSED(details)
21358 if (onlySelectable && !mSelectable)
21359 return -1;
21360 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
21361
21362 if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()))
21363 {
21364 // get visible data range:
21365 QCPFinancialDataMap::const_iterator lower, upper; // note that upper is the actual upper point, and not 1 step after the upper point
21366 getVisibleDataBounds(lower, upper);
21367 if (lower == mData->constEnd() || upper == mData->constEnd())
20858 Q_UNUSED(details)
20859 if (onlySelectable && !mSelectable)
21368 20860 return -1;
21369 // perform select test according to configured style:
21370 switch (mChartStyle)
20861 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
20862
20863 if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()))
20864 {
20865 // get visible data range:
20866 QCPFinancialDataMap::const_iterator lower, upper; // note that upper is the actual upper point, and not 1 step after the upper point
20867 getVisibleDataBounds(lower, upper);
20868 if (lower == mData->constEnd() || upper == mData->constEnd())
20869 return -1;
20870 // perform select test according to configured style:
20871 switch (mChartStyle)
21371 20872 {
21372 20873 case QCPFinancial::csOhlc:
21373 return ohlcSelectTest(pos, lower, upper+1); break;
20874 return ohlcSelectTest(pos, lower, upper+1); break;
21374 20875 case QCPFinancial::csCandlestick:
21375 return candlestickSelectTest(pos, lower, upper+1); break;
21376 }
21377 }
21378 return -1;
20876 return candlestickSelectTest(pos, lower, upper+1); break;
20877 }
20878 }
20879 return -1;
21379 20880 }
21380 20881
21381 20882 /*!
@@ -21393,117 +20894,117 double QCPFinancial::selectTest(const QP
21393 20894 */
21394 20895 QCPFinancialDataMap QCPFinancial::timeSeriesToOhlc(const QVector<double> &time, const QVector<double> &value, double timeBinSize, double timeBinOffset)
21395 20896 {
21396 QCPFinancialDataMap map;
21397 int count = qMin(time.size(), value.size());
21398 if (count == 0)
21399 return QCPFinancialDataMap();
21400
21401 QCPFinancialData currentBinData(0, value.first(), value.first(), value.first(), value.first());
21402 int currentBinIndex = qFloor((time.first()-timeBinOffset)/timeBinSize+0.5);
21403 for (int i=0; i<count; ++i)
21404 {
21405 int index = qFloor((time.at(i)-timeBinOffset)/timeBinSize+0.5);
21406 if (currentBinIndex == index) // data point still in current bin, extend high/low:
21407 {
21408 if (value.at(i) < currentBinData.low) currentBinData.low = value.at(i);
21409 if (value.at(i) > currentBinData.high) currentBinData.high = value.at(i);
21410 if (i == count-1) // last data point is in current bin, finalize bin:
21411 {
21412 currentBinData.close = value.at(i);
21413 currentBinData.key = timeBinOffset+(index)*timeBinSize;
21414 map.insert(currentBinData.key, currentBinData);
20897 QCPFinancialDataMap map;
20898 int count = qMin(time.size(), value.size());
20899 if (count == 0)
20900 return QCPFinancialDataMap();
20901
20902 QCPFinancialData currentBinData(0, value.first(), value.first(), value.first(), value.first());
20903 int currentBinIndex = qFloor((time.first()-timeBinOffset)/timeBinSize+0.5);
20904 for (int i=0; i<count; ++i)
20905 {
20906 int index = qFloor((time.at(i)-timeBinOffset)/timeBinSize+0.5);
20907 if (currentBinIndex == index) // data point still in current bin, extend high/low:
20908 {
20909 if (value.at(i) < currentBinData.low) currentBinData.low = value.at(i);
20910 if (value.at(i) > currentBinData.high) currentBinData.high = value.at(i);
20911 if (i == count-1) // last data point is in current bin, finalize bin:
20912 {
20913 currentBinData.close = value.at(i);
20914 currentBinData.key = timeBinOffset+(index)*timeBinSize;
20915 map.insert(currentBinData.key, currentBinData);
21415 20916 }
21416 20917 } else // data point not anymore in current bin, set close of old and open of new bin, and add old to map:
21417 20918 {
21418 // finalize current bin:
21419 currentBinData.close = value.at(i-1);
21420 currentBinData.key = timeBinOffset+(index-1)*timeBinSize;
21421 map.insert(currentBinData.key, currentBinData);
21422 // start next bin:
21423 currentBinIndex = index;
21424 currentBinData.open = value.at(i);
21425 currentBinData.high = value.at(i);
21426 currentBinData.low = value.at(i);
21427 }
21428 }
21429
21430 return map;
20919 // finalize current bin:
20920 currentBinData.close = value.at(i-1);
20921 currentBinData.key = timeBinOffset+(index-1)*timeBinSize;
20922 map.insert(currentBinData.key, currentBinData);
20923 // start next bin:
20924 currentBinIndex = index;
20925 currentBinData.open = value.at(i);
20926 currentBinData.high = value.at(i);
20927 currentBinData.low = value.at(i);
20928 }
20929 }
20930
20931 return map;
21431 20932 }
21432 20933
21433 20934 /* inherits documentation from base class */
21434 20935 void QCPFinancial::draw(QCPPainter *painter)
21435 20936 {
21436 // get visible data range:
21437 QCPFinancialDataMap::const_iterator lower, upper; // note that upper is the actual upper point, and not 1 step after the upper point
21438 getVisibleDataBounds(lower, upper);
21439 if (lower == mData->constEnd() || upper == mData->constEnd())
21440 return;
21441
21442 // draw visible data range according to configured style:
21443 switch (mChartStyle)
20937 // get visible data range:
20938 QCPFinancialDataMap::const_iterator lower, upper; // note that upper is the actual upper point, and not 1 step after the upper point
20939 getVisibleDataBounds(lower, upper);
20940 if (lower == mData->constEnd() || upper == mData->constEnd())
20941 return;
20942
20943 // draw visible data range according to configured style:
20944 switch (mChartStyle)
21444 20945 {
21445 20946 case QCPFinancial::csOhlc:
21446 drawOhlcPlot(painter, lower, upper+1); break;
20947 drawOhlcPlot(painter, lower, upper+1); break;
21447 20948 case QCPFinancial::csCandlestick:
21448 drawCandlestickPlot(painter, lower, upper+1); break;
20949 drawCandlestickPlot(painter, lower, upper+1); break;
21449 20950 }
21450 20951 }
21451 20952
21452 20953 /* inherits documentation from base class */
21453 20954 void QCPFinancial::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const
21454 20955 {
21455 painter->setAntialiasing(false); // legend icon especially of csCandlestick looks better without antialiasing
21456 if (mChartStyle == csOhlc)
21457 {
21458 if (mTwoColored)
21459 {
21460 // draw upper left half icon with positive color:
21461 painter->setBrush(mBrushPositive);
21462 painter->setPen(mPenPositive);
21463 painter->setClipRegion(QRegion(QPolygon() << rect.bottomLeft().toPoint() << rect.topRight().toPoint() << rect.topLeft().toPoint()));
21464 painter->drawLine(QLineF(0, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft()));
21465 painter->drawLine(QLineF(rect.width()*0.2, rect.height()*0.3, rect.width()*0.2, rect.height()*0.5).translated(rect.topLeft()));
21466 painter->drawLine(QLineF(rect.width()*0.8, rect.height()*0.5, rect.width()*0.8, rect.height()*0.7).translated(rect.topLeft()));
21467 // draw bottom right hald icon with negative color:
21468 painter->setBrush(mBrushNegative);
21469 painter->setPen(mPenNegative);
21470 painter->setClipRegion(QRegion(QPolygon() << rect.bottomLeft().toPoint() << rect.topRight().toPoint() << rect.bottomRight().toPoint()));
21471 painter->drawLine(QLineF(0, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft()));
21472 painter->drawLine(QLineF(rect.width()*0.2, rect.height()*0.3, rect.width()*0.2, rect.height()*0.5).translated(rect.topLeft()));
21473 painter->drawLine(QLineF(rect.width()*0.8, rect.height()*0.5, rect.width()*0.8, rect.height()*0.7).translated(rect.topLeft()));
20956 painter->setAntialiasing(false); // legend icon especially of csCandlestick looks better without antialiasing
20957 if (mChartStyle == csOhlc)
20958 {
20959 if (mTwoColored)
20960 {
20961 // draw upper left half icon with positive color:
20962 painter->setBrush(mBrushPositive);
20963 painter->setPen(mPenPositive);
20964 painter->setClipRegion(QRegion(QPolygon() << rect.bottomLeft().toPoint() << rect.topRight().toPoint() << rect.topLeft().toPoint()));
20965 painter->drawLine(QLineF(0, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft()));
20966 painter->drawLine(QLineF(rect.width()*0.2, rect.height()*0.3, rect.width()*0.2, rect.height()*0.5).translated(rect.topLeft()));
20967 painter->drawLine(QLineF(rect.width()*0.8, rect.height()*0.5, rect.width()*0.8, rect.height()*0.7).translated(rect.topLeft()));
20968 // draw bottom right hald icon with negative color:
20969 painter->setBrush(mBrushNegative);
20970 painter->setPen(mPenNegative);
20971 painter->setClipRegion(QRegion(QPolygon() << rect.bottomLeft().toPoint() << rect.topRight().toPoint() << rect.bottomRight().toPoint()));
20972 painter->drawLine(QLineF(0, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft()));
20973 painter->drawLine(QLineF(rect.width()*0.2, rect.height()*0.3, rect.width()*0.2, rect.height()*0.5).translated(rect.topLeft()));
20974 painter->drawLine(QLineF(rect.width()*0.8, rect.height()*0.5, rect.width()*0.8, rect.height()*0.7).translated(rect.topLeft()));
21474 20975 } else
21475 20976 {
21476 painter->setBrush(mBrush);
21477 painter->setPen(mPen);
21478 painter->drawLine(QLineF(0, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft()));
21479 painter->drawLine(QLineF(rect.width()*0.2, rect.height()*0.3, rect.width()*0.2, rect.height()*0.5).translated(rect.topLeft()));
21480 painter->drawLine(QLineF(rect.width()*0.8, rect.height()*0.5, rect.width()*0.8, rect.height()*0.7).translated(rect.topLeft()));
20977 painter->setBrush(mBrush);
20978 painter->setPen(mPen);
20979 painter->drawLine(QLineF(0, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft()));
20980 painter->drawLine(QLineF(rect.width()*0.2, rect.height()*0.3, rect.width()*0.2, rect.height()*0.5).translated(rect.topLeft()));
20981 painter->drawLine(QLineF(rect.width()*0.8, rect.height()*0.5, rect.width()*0.8, rect.height()*0.7).translated(rect.topLeft()));
21481 20982 }
21482 20983 } else if (mChartStyle == csCandlestick)
21483 20984 {
21484 if (mTwoColored)
21485 {
21486 // draw upper left half icon with positive color:
21487 painter->setBrush(mBrushPositive);
21488 painter->setPen(mPenPositive);
21489 painter->setClipRegion(QRegion(QPolygon() << rect.bottomLeft().toPoint() << rect.topRight().toPoint() << rect.topLeft().toPoint()));
21490 painter->drawLine(QLineF(0, rect.height()*0.5, rect.width()*0.25, rect.height()*0.5).translated(rect.topLeft()));
21491 painter->drawLine(QLineF(rect.width()*0.75, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft()));
21492 painter->drawRect(QRectF(rect.width()*0.25, rect.height()*0.25, rect.width()*0.5, rect.height()*0.5).translated(rect.topLeft()));
21493 // draw bottom right hald icon with negative color:
21494 painter->setBrush(mBrushNegative);
21495 painter->setPen(mPenNegative);
21496 painter->setClipRegion(QRegion(QPolygon() << rect.bottomLeft().toPoint() << rect.topRight().toPoint() << rect.bottomRight().toPoint()));
21497 painter->drawLine(QLineF(0, rect.height()*0.5, rect.width()*0.25, rect.height()*0.5).translated(rect.topLeft()));
21498 painter->drawLine(QLineF(rect.width()*0.75, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft()));
21499 painter->drawRect(QRectF(rect.width()*0.25, rect.height()*0.25, rect.width()*0.5, rect.height()*0.5).translated(rect.topLeft()));
20985 if (mTwoColored)
20986 {
20987 // draw upper left half icon with positive color:
20988 painter->setBrush(mBrushPositive);
20989 painter->setPen(mPenPositive);
20990 painter->setClipRegion(QRegion(QPolygon() << rect.bottomLeft().toPoint() << rect.topRight().toPoint() << rect.topLeft().toPoint()));
20991 painter->drawLine(QLineF(0, rect.height()*0.5, rect.width()*0.25, rect.height()*0.5).translated(rect.topLeft()));
20992 painter->drawLine(QLineF(rect.width()*0.75, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft()));
20993 painter->drawRect(QRectF(rect.width()*0.25, rect.height()*0.25, rect.width()*0.5, rect.height()*0.5).translated(rect.topLeft()));
20994 // draw bottom right hald icon with negative color:
20995 painter->setBrush(mBrushNegative);
20996 painter->setPen(mPenNegative);
20997 painter->setClipRegion(QRegion(QPolygon() << rect.bottomLeft().toPoint() << rect.topRight().toPoint() << rect.bottomRight().toPoint()));
20998 painter->drawLine(QLineF(0, rect.height()*0.5, rect.width()*0.25, rect.height()*0.5).translated(rect.topLeft()));
20999 painter->drawLine(QLineF(rect.width()*0.75, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft()));
21000 painter->drawRect(QRectF(rect.width()*0.25, rect.height()*0.25, rect.width()*0.5, rect.height()*0.5).translated(rect.topLeft()));
21500 21001 } else
21501 21002 {
21502 painter->setBrush(mBrush);
21503 painter->setPen(mPen);
21504 painter->drawLine(QLineF(0, rect.height()*0.5, rect.width()*0.25, rect.height()*0.5).translated(rect.topLeft()));
21505 painter->drawLine(QLineF(rect.width()*0.75, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft()));
21506 painter->drawRect(QRectF(rect.width()*0.25, rect.height()*0.25, rect.width()*0.5, rect.height()*0.5).translated(rect.topLeft()));
21003 painter->setBrush(mBrush);
21004 painter->setPen(mPen);
21005 painter->drawLine(QLineF(0, rect.height()*0.5, rect.width()*0.25, rect.height()*0.5).translated(rect.topLeft()));
21006 painter->drawLine(QLineF(rect.width()*0.75, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft()));
21007 painter->drawRect(QRectF(rect.width()*0.25, rect.height()*0.25, rect.width()*0.5, rect.height()*0.5).translated(rect.topLeft()));
21507 21008 }
21508 21009 }
21509 21010 }
@@ -21511,82 +21012,82 void QCPFinancial::drawLegendIcon(QCPPai
21511 21012 /* inherits documentation from base class */
21512 21013 QCPRange QCPFinancial::getKeyRange(bool &foundRange, QCPAbstractPlottable::SignDomain inSignDomain) const
21513 21014 {
21514 QCPRange range;
21515 bool haveLower = false;
21516 bool haveUpper = false;
21517
21518 double current;
21519 QCPFinancialDataMap::const_iterator it = mData->constBegin();
21520 while (it != mData->constEnd())
21521 {
21522 current = it.value().key;
21523 if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current < 0) || (inSignDomain == sdPositive && current > 0))
21524 {
21525 if (current < range.lower || !haveLower)
21526 {
21527 range.lower = current;
21528 haveLower = true;
21529 }
21530 if (current > range.upper || !haveUpper)
21531 {
21532 range.upper = current;
21533 haveUpper = true;
21534 }
21535 }
21536 ++it;
21537 }
21538 // determine exact range by including width of bars/flags:
21539 if (haveLower && mKeyAxis)
21540 range.lower = range.lower-mWidth*0.5;
21541 if (haveUpper && mKeyAxis)
21542 range.upper = range.upper+mWidth*0.5;
21543 foundRange = haveLower && haveUpper;
21544 return range;
21015 QCPRange range;
21016 bool haveLower = false;
21017 bool haveUpper = false;
21018
21019 double current;
21020 QCPFinancialDataMap::const_iterator it = mData->constBegin();
21021 while (it != mData->constEnd())
21022 {
21023 current = it.value().key;
21024 if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current < 0) || (inSignDomain == sdPositive && current > 0))
21025 {
21026 if (current < range.lower || !haveLower)
21027 {
21028 range.lower = current;
21029 haveLower = true;
21030 }
21031 if (current > range.upper || !haveUpper)
21032 {
21033 range.upper = current;
21034 haveUpper = true;
21035 }
21036 }
21037 ++it;
21038 }
21039 // determine exact range by including width of bars/flags:
21040 if (haveLower && mKeyAxis)
21041 range.lower = range.lower-mWidth*0.5;
21042 if (haveUpper && mKeyAxis)
21043 range.upper = range.upper+mWidth*0.5;
21044 foundRange = haveLower && haveUpper;
21045 return range;
21545 21046 }
21546 21047
21547 21048 /* inherits documentation from base class */
21548 21049 QCPRange QCPFinancial::getValueRange(bool &foundRange, QCPAbstractPlottable::SignDomain inSignDomain) const
21549 21050 {
21550 QCPRange range;
21551 bool haveLower = false;
21552 bool haveUpper = false;
21553
21554 QCPFinancialDataMap::const_iterator it = mData->constBegin();
21555 while (it != mData->constEnd())
21556 {
21557 // high:
21558 if (inSignDomain == sdBoth || (inSignDomain == sdNegative && it.value().high < 0) || (inSignDomain == sdPositive && it.value().high > 0))
21559 {
21560 if (it.value().high < range.lower || !haveLower)
21561 {
21562 range.lower = it.value().high;
21563 haveLower = true;
21564 }
21565 if (it.value().high > range.upper || !haveUpper)
21566 {
21567 range.upper = it.value().high;
21568 haveUpper = true;
21569 }
21570 }
21571 // low:
21572 if (inSignDomain == sdBoth || (inSignDomain == sdNegative && it.value().low < 0) || (inSignDomain == sdPositive && it.value().low > 0))
21573 {
21574 if (it.value().low < range.lower || !haveLower)
21575 {
21576 range.lower = it.value().low;
21577 haveLower = true;
21578 }
21579 if (it.value().low > range.upper || !haveUpper)
21580 {
21581 range.upper = it.value().low;
21582 haveUpper = true;
21583 }
21584 }
21585 ++it;
21586 }
21587
21588 foundRange = haveLower && haveUpper;
21589 return range;
21051 QCPRange range;
21052 bool haveLower = false;
21053 bool haveUpper = false;
21054
21055 QCPFinancialDataMap::const_iterator it = mData->constBegin();
21056 while (it != mData->constEnd())
21057 {
21058 // high:
21059 if (inSignDomain == sdBoth || (inSignDomain == sdNegative && it.value().high < 0) || (inSignDomain == sdPositive && it.value().high > 0))
21060 {
21061 if (it.value().high < range.lower || !haveLower)
21062 {
21063 range.lower = it.value().high;
21064 haveLower = true;
21065 }
21066 if (it.value().high > range.upper || !haveUpper)
21067 {
21068 range.upper = it.value().high;
21069 haveUpper = true;
21070 }
21071 }
21072 // low:
21073 if (inSignDomain == sdBoth || (inSignDomain == sdNegative && it.value().low < 0) || (inSignDomain == sdPositive && it.value().low > 0))
21074 {
21075 if (it.value().low < range.lower || !haveLower)
21076 {
21077 range.lower = it.value().low;
21078 haveLower = true;
21079 }
21080 if (it.value().low > range.upper || !haveUpper)
21081 {
21082 range.upper = it.value().low;
21083 haveUpper = true;
21084 }
21085 }
21086 ++it;
21087 }
21088
21089 foundRange = haveLower && haveUpper;
21090 return range;
21590 21091 }
21591 21092
21592 21093 /*! \internal
@@ -21597,55 +21098,55 QCPRange QCPFinancial::getValueRange(boo
21597 21098 */
21598 21099 void QCPFinancial::drawOhlcPlot(QCPPainter *painter, const QCPFinancialDataMap::const_iterator &begin, const QCPFinancialDataMap::const_iterator &end)
21599 21100 {
21600 QCPAxis *keyAxis = mKeyAxis.data();
21601 QCPAxis *valueAxis = mValueAxis.data();
21602 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
21603
21604 QPen linePen;
21605
21606 if (keyAxis->orientation() == Qt::Horizontal)
21607 {
21608 for (QCPFinancialDataMap::const_iterator it = begin; it != end; ++it)
21609 {
21610 if (mSelected)
21611 linePen = mSelectedPen;
21612 else if (mTwoColored)
21613 linePen = it.value().close >= it.value().open ? mPenPositive : mPenNegative;
21614 else
21615 linePen = mPen;
21616 painter->setPen(linePen);
21617 double keyPixel = keyAxis->coordToPixel(it.value().key);
21618 double openPixel = valueAxis->coordToPixel(it.value().open);
21619 double closePixel = valueAxis->coordToPixel(it.value().close);
21620 // draw backbone:
21621 painter->drawLine(QPointF(keyPixel, valueAxis->coordToPixel(it.value().high)), QPointF(keyPixel, valueAxis->coordToPixel(it.value().low)));
21622 // draw open:
21623 double keyWidthPixels = keyPixel-keyAxis->coordToPixel(it.value().key-mWidth*0.5); // sign of this makes sure open/close are on correct sides
21624 painter->drawLine(QPointF(keyPixel-keyWidthPixels, openPixel), QPointF(keyPixel, openPixel));
21625 // draw close:
21626 painter->drawLine(QPointF(keyPixel, closePixel), QPointF(keyPixel+keyWidthPixels, closePixel));
21627 }
21628 } else
21629 {
21630 for (QCPFinancialDataMap::const_iterator it = begin; it != end; ++it)
21631 {
21632 if (mSelected)
21633 linePen = mSelectedPen;
21634 else if (mTwoColored)
21635 linePen = it.value().close >= it.value().open ? mPenPositive : mPenNegative;
21636 else
21637 linePen = mPen;
21638 painter->setPen(linePen);
21639 double keyPixel = keyAxis->coordToPixel(it.value().key);
21640 double openPixel = valueAxis->coordToPixel(it.value().open);
21641 double closePixel = valueAxis->coordToPixel(it.value().close);
21642 // draw backbone:
21643 painter->drawLine(QPointF(valueAxis->coordToPixel(it.value().high), keyPixel), QPointF(valueAxis->coordToPixel(it.value().low), keyPixel));
21644 // draw open:
21645 double keyWidthPixels = keyPixel-keyAxis->coordToPixel(it.value().key-mWidth*0.5); // sign of this makes sure open/close are on correct sides
21646 painter->drawLine(QPointF(openPixel, keyPixel-keyWidthPixels), QPointF(openPixel, keyPixel));
21647 // draw close:
21648 painter->drawLine(QPointF(closePixel, keyPixel), QPointF(closePixel, keyPixel+keyWidthPixels));
21101 QCPAxis *keyAxis = mKeyAxis.data();
21102 QCPAxis *valueAxis = mValueAxis.data();
21103 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
21104
21105 QPen linePen;
21106
21107 if (keyAxis->orientation() == Qt::Horizontal)
21108 {
21109 for (QCPFinancialDataMap::const_iterator it = begin; it != end; ++it)
21110 {
21111 if (mSelected)
21112 linePen = mSelectedPen;
21113 else if (mTwoColored)
21114 linePen = it.value().close >= it.value().open ? mPenPositive : mPenNegative;
21115 else
21116 linePen = mPen;
21117 painter->setPen(linePen);
21118 double keyPixel = keyAxis->coordToPixel(it.value().key);
21119 double openPixel = valueAxis->coordToPixel(it.value().open);
21120 double closePixel = valueAxis->coordToPixel(it.value().close);
21121 // draw backbone:
21122 painter->drawLine(QPointF(keyPixel, valueAxis->coordToPixel(it.value().high)), QPointF(keyPixel, valueAxis->coordToPixel(it.value().low)));
21123 // draw open:
21124 double keyWidthPixels = keyPixel-keyAxis->coordToPixel(it.value().key-mWidth*0.5); // sign of this makes sure open/close are on correct sides
21125 painter->drawLine(QPointF(keyPixel-keyWidthPixels, openPixel), QPointF(keyPixel, openPixel));
21126 // draw close:
21127 painter->drawLine(QPointF(keyPixel, closePixel), QPointF(keyPixel+keyWidthPixels, closePixel));
21128 }
21129 } else
21130 {
21131 for (QCPFinancialDataMap::const_iterator it = begin; it != end; ++it)
21132 {
21133 if (mSelected)
21134 linePen = mSelectedPen;
21135 else if (mTwoColored)
21136 linePen = it.value().close >= it.value().open ? mPenPositive : mPenNegative;
21137 else
21138 linePen = mPen;
21139 painter->setPen(linePen);
21140 double keyPixel = keyAxis->coordToPixel(it.value().key);
21141 double openPixel = valueAxis->coordToPixel(it.value().open);
21142 double closePixel = valueAxis->coordToPixel(it.value().close);
21143 // draw backbone:
21144 painter->drawLine(QPointF(valueAxis->coordToPixel(it.value().high), keyPixel), QPointF(valueAxis->coordToPixel(it.value().low), keyPixel));
21145 // draw open:
21146 double keyWidthPixels = keyPixel-keyAxis->coordToPixel(it.value().key-mWidth*0.5); // sign of this makes sure open/close are on correct sides
21147 painter->drawLine(QPointF(openPixel, keyPixel-keyWidthPixels), QPointF(openPixel, keyPixel));
21148 // draw close:
21149 painter->drawLine(QPointF(closePixel, keyPixel), QPointF(closePixel, keyPixel+keyWidthPixels));
21649 21150 }
21650 21151 }
21651 21152 }
@@ -21658,86 +21159,86 void QCPFinancial::drawOhlcPlot(QCPPaint
21658 21159 */
21659 21160 void QCPFinancial::drawCandlestickPlot(QCPPainter *painter, const QCPFinancialDataMap::const_iterator &begin, const QCPFinancialDataMap::const_iterator &end)
21660 21161 {
21661 QCPAxis *keyAxis = mKeyAxis.data();
21662 QCPAxis *valueAxis = mValueAxis.data();
21663 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
21664
21665 QPen linePen;
21666 QBrush boxBrush;
21667
21668 if (keyAxis->orientation() == Qt::Horizontal)
21669 {
21670 for (QCPFinancialDataMap::const_iterator it = begin; it != end; ++it)
21671 {
21672 if (mSelected)
21673 {
21674 linePen = mSelectedPen;
21675 boxBrush = mSelectedBrush;
21162 QCPAxis *keyAxis = mKeyAxis.data();
21163 QCPAxis *valueAxis = mValueAxis.data();
21164 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
21165
21166 QPen linePen;
21167 QBrush boxBrush;
21168
21169 if (keyAxis->orientation() == Qt::Horizontal)
21170 {
21171 for (QCPFinancialDataMap::const_iterator it = begin; it != end; ++it)
21172 {
21173 if (mSelected)
21174 {
21175 linePen = mSelectedPen;
21176 boxBrush = mSelectedBrush;
21676 21177 } else if (mTwoColored)
21677 21178 {
21678 if (it.value().close >= it.value().open)
21179 if (it.value().close >= it.value().open)
21679 21180 {
21680 linePen = mPenPositive;
21681 boxBrush = mBrushPositive;
21181 linePen = mPenPositive;
21182 boxBrush = mBrushPositive;
21682 21183 } else
21683 21184 {
21684 linePen = mPenNegative;
21685 boxBrush = mBrushNegative;
21185 linePen = mPenNegative;
21186 boxBrush = mBrushNegative;
21686 21187 }
21687 21188 } else
21688 21189 {
21689 linePen = mPen;
21690 boxBrush = mBrush;
21691 }
21692 painter->setPen(linePen);
21693 painter->setBrush(boxBrush);
21694 double keyPixel = keyAxis->coordToPixel(it.value().key);
21695 double openPixel = valueAxis->coordToPixel(it.value().open);
21696 double closePixel = valueAxis->coordToPixel(it.value().close);
21697 // draw high:
21698 painter->drawLine(QPointF(keyPixel, valueAxis->coordToPixel(it.value().high)), QPointF(keyPixel, valueAxis->coordToPixel(qMax(it.value().open, it.value().close))));
21699 // draw low:
21700 painter->drawLine(QPointF(keyPixel, valueAxis->coordToPixel(it.value().low)), QPointF(keyPixel, valueAxis->coordToPixel(qMin(it.value().open, it.value().close))));
21701 // draw open-close box:
21702 double keyWidthPixels = keyPixel-keyAxis->coordToPixel(it.value().key-mWidth*0.5);
21703 painter->drawRect(QRectF(QPointF(keyPixel-keyWidthPixels, closePixel), QPointF(keyPixel+keyWidthPixels, openPixel)));
21190 linePen = mPen;
21191 boxBrush = mBrush;
21192 }
21193 painter->setPen(linePen);
21194 painter->setBrush(boxBrush);
21195 double keyPixel = keyAxis->coordToPixel(it.value().key);
21196 double openPixel = valueAxis->coordToPixel(it.value().open);
21197 double closePixel = valueAxis->coordToPixel(it.value().close);
21198 // draw high:
21199 painter->drawLine(QPointF(keyPixel, valueAxis->coordToPixel(it.value().high)), QPointF(keyPixel, valueAxis->coordToPixel(qMax(it.value().open, it.value().close))));
21200 // draw low:
21201 painter->drawLine(QPointF(keyPixel, valueAxis->coordToPixel(it.value().low)), QPointF(keyPixel, valueAxis->coordToPixel(qMin(it.value().open, it.value().close))));
21202 // draw open-close box:
21203 double keyWidthPixels = keyPixel-keyAxis->coordToPixel(it.value().key-mWidth*0.5);
21204 painter->drawRect(QRectF(QPointF(keyPixel-keyWidthPixels, closePixel), QPointF(keyPixel+keyWidthPixels, openPixel)));
21704 21205 }
21705 21206 } else // keyAxis->orientation() == Qt::Vertical
21706 21207 {
21707 for (QCPFinancialDataMap::const_iterator it = begin; it != end; ++it)
21708 {
21709 if (mSelected)
21710 {
21711 linePen = mSelectedPen;
21712 boxBrush = mSelectedBrush;
21208 for (QCPFinancialDataMap::const_iterator it = begin; it != end; ++it)
21209 {
21210 if (mSelected)
21211 {
21212 linePen = mSelectedPen;
21213 boxBrush = mSelectedBrush;
21713 21214 } else if (mTwoColored)
21714 21215 {
21715 if (it.value().close >= it.value().open)
21216 if (it.value().close >= it.value().open)
21716 21217 {
21717 linePen = mPenPositive;
21718 boxBrush = mBrushPositive;
21218 linePen = mPenPositive;
21219 boxBrush = mBrushPositive;
21719 21220 } else
21720 21221 {
21721 linePen = mPenNegative;
21722 boxBrush = mBrushNegative;
21222 linePen = mPenNegative;
21223 boxBrush = mBrushNegative;
21723 21224 }
21724 21225 } else
21725 21226 {
21726 linePen = mPen;
21727 boxBrush = mBrush;
21728 }
21729 painter->setPen(linePen);
21730 painter->setBrush(boxBrush);
21731 double keyPixel = keyAxis->coordToPixel(it.value().key);
21732 double openPixel = valueAxis->coordToPixel(it.value().open);
21733 double closePixel = valueAxis->coordToPixel(it.value().close);
21734 // draw high:
21735 painter->drawLine(QPointF(valueAxis->coordToPixel(it.value().high), keyPixel), QPointF(valueAxis->coordToPixel(qMax(it.value().open, it.value().close)), keyPixel));
21736 // draw low:
21737 painter->drawLine(QPointF(valueAxis->coordToPixel(it.value().low), keyPixel), QPointF(valueAxis->coordToPixel(qMin(it.value().open, it.value().close)), keyPixel));
21738 // draw open-close box:
21739 double keyWidthPixels = keyPixel-keyAxis->coordToPixel(it.value().key-mWidth*0.5);
21740 painter->drawRect(QRectF(QPointF(closePixel, keyPixel-keyWidthPixels), QPointF(openPixel, keyPixel+keyWidthPixels)));
21227 linePen = mPen;
21228 boxBrush = mBrush;
21229 }
21230 painter->setPen(linePen);
21231 painter->setBrush(boxBrush);
21232 double keyPixel = keyAxis->coordToPixel(it.value().key);
21233 double openPixel = valueAxis->coordToPixel(it.value().open);
21234 double closePixel = valueAxis->coordToPixel(it.value().close);
21235 // draw high:
21236 painter->drawLine(QPointF(valueAxis->coordToPixel(it.value().high), keyPixel), QPointF(valueAxis->coordToPixel(qMax(it.value().open, it.value().close)), keyPixel));
21237 // draw low:
21238 painter->drawLine(QPointF(valueAxis->coordToPixel(it.value().low), keyPixel), QPointF(valueAxis->coordToPixel(qMin(it.value().open, it.value().close)), keyPixel));
21239 // draw open-close box:
21240 double keyWidthPixels = keyPixel-keyAxis->coordToPixel(it.value().key-mWidth*0.5);
21241 painter->drawRect(QRectF(QPointF(closePixel, keyPixel-keyWidthPixels), QPointF(openPixel, keyPixel+keyWidthPixels)));
21741 21242 }
21742 21243 }
21743 21244 }
@@ -21749,34 +21250,34 void QCPFinancial::drawCandlestickPlot(Q
21749 21250 */
21750 21251 double QCPFinancial::ohlcSelectTest(const QPointF &pos, const QCPFinancialDataMap::const_iterator &begin, const QCPFinancialDataMap::const_iterator &end) const
21751 21252 {
21752 QCPAxis *keyAxis = mKeyAxis.data();
21753 QCPAxis *valueAxis = mValueAxis.data();
21754 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
21755
21756 double minDistSqr = std::numeric_limits<double>::max();
21757 QCPFinancialDataMap::const_iterator it;
21758 if (keyAxis->orientation() == Qt::Horizontal)
21759 {
21760 for (it = begin; it != end; ++it)
21761 {
21762 double keyPixel = keyAxis->coordToPixel(it.value().key);
21763 // calculate distance to backbone:
21764 double currentDistSqr = distSqrToLine(QPointF(keyPixel, valueAxis->coordToPixel(it.value().high)), QPointF(keyPixel, valueAxis->coordToPixel(it.value().low)), pos);
21765 if (currentDistSqr < minDistSqr)
21766 minDistSqr = currentDistSqr;
21253 QCPAxis *keyAxis = mKeyAxis.data();
21254 QCPAxis *valueAxis = mValueAxis.data();
21255 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
21256
21257 double minDistSqr = std::numeric_limits<double>::max();
21258 QCPFinancialDataMap::const_iterator it;
21259 if (keyAxis->orientation() == Qt::Horizontal)
21260 {
21261 for (it = begin; it != end; ++it)
21262 {
21263 double keyPixel = keyAxis->coordToPixel(it.value().key);
21264 // calculate distance to backbone:
21265 double currentDistSqr = distSqrToLine(QPointF(keyPixel, valueAxis->coordToPixel(it.value().high)), QPointF(keyPixel, valueAxis->coordToPixel(it.value().low)), pos);
21266 if (currentDistSqr < minDistSqr)
21267 minDistSqr = currentDistSqr;
21767 21268 }
21768 21269 } else // keyAxis->orientation() == Qt::Vertical
21769 21270 {
21770 for (it = begin; it != end; ++it)
21771 {
21772 double keyPixel = keyAxis->coordToPixel(it.value().key);
21773 // calculate distance to backbone:
21774 double currentDistSqr = distSqrToLine(QPointF(valueAxis->coordToPixel(it.value().high), keyPixel), QPointF(valueAxis->coordToPixel(it.value().low), keyPixel), pos);
21775 if (currentDistSqr < minDistSqr)
21776 minDistSqr = currentDistSqr;
21777 }
21778 }
21779 return qSqrt(minDistSqr);
21271 for (it = begin; it != end; ++it)
21272 {
21273 double keyPixel = keyAxis->coordToPixel(it.value().key);
21274 // calculate distance to backbone:
21275 double currentDistSqr = distSqrToLine(QPointF(valueAxis->coordToPixel(it.value().high), keyPixel), QPointF(valueAxis->coordToPixel(it.value().low), keyPixel), pos);
21276 if (currentDistSqr < minDistSqr)
21277 minDistSqr = currentDistSqr;
21278 }
21279 }
21280 return qSqrt(minDistSqr);
21780 21281 }
21781 21282
21782 21283 /*! \internal
@@ -21787,62 +21288,62 double QCPFinancial::ohlcSelectTest(cons
21787 21288 */
21788 21289 double QCPFinancial::candlestickSelectTest(const QPointF &pos, const QCPFinancialDataMap::const_iterator &begin, const QCPFinancialDataMap::const_iterator &end) const
21789 21290 {
21790 QCPAxis *keyAxis = mKeyAxis.data();
21791 QCPAxis *valueAxis = mValueAxis.data();
21792 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
21793
21794 double minDistSqr = std::numeric_limits<double>::max();
21795 QCPFinancialDataMap::const_iterator it;
21796 if (keyAxis->orientation() == Qt::Horizontal)
21797 {
21798 for (it = begin; it != end; ++it)
21799 {
21800 double currentDistSqr;
21801 // determine whether pos is in open-close-box:
21802 QCPRange boxKeyRange(it.value().key-mWidth*0.5, it.value().key+mWidth*0.5);
21803 QCPRange boxValueRange(it.value().close, it.value().open);
21804 double posKey, posValue;
21805 pixelsToCoords(pos, posKey, posValue);
21806 if (boxKeyRange.contains(posKey) && boxValueRange.contains(posValue)) // is in open-close-box
21807 {
21808 currentDistSqr = mParentPlot->selectionTolerance()*0.99 * mParentPlot->selectionTolerance()*0.99;
21291 QCPAxis *keyAxis = mKeyAxis.data();
21292 QCPAxis *valueAxis = mValueAxis.data();
21293 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
21294
21295 double minDistSqr = std::numeric_limits<double>::max();
21296 QCPFinancialDataMap::const_iterator it;
21297 if (keyAxis->orientation() == Qt::Horizontal)
21298 {
21299 for (it = begin; it != end; ++it)
21300 {
21301 double currentDistSqr;
21302 // determine whether pos is in open-close-box:
21303 QCPRange boxKeyRange(it.value().key-mWidth*0.5, it.value().key+mWidth*0.5);
21304 QCPRange boxValueRange(it.value().close, it.value().open);
21305 double posKey, posValue;
21306 pixelsToCoords(pos, posKey, posValue);
21307 if (boxKeyRange.contains(posKey) && boxValueRange.contains(posValue)) // is in open-close-box
21308 {
21309 currentDistSqr = mParentPlot->selectionTolerance()*0.99 * mParentPlot->selectionTolerance()*0.99;
21809 21310 } else
21810 21311 {
21811 // calculate distance to high/low lines:
21812 double keyPixel = keyAxis->coordToPixel(it.value().key);
21813 double highLineDistSqr = distSqrToLine(QPointF(keyPixel, valueAxis->coordToPixel(it.value().high)), QPointF(keyPixel, valueAxis->coordToPixel(qMax(it.value().open, it.value().close))), pos);
21814 double lowLineDistSqr = distSqrToLine(QPointF(keyPixel, valueAxis->coordToPixel(it.value().low)), QPointF(keyPixel, valueAxis->coordToPixel(qMin(it.value().open, it.value().close))), pos);
21815 currentDistSqr = qMin(highLineDistSqr, lowLineDistSqr);
21816 }
21817 if (currentDistSqr < minDistSqr)
21818 minDistSqr = currentDistSqr;
21312 // calculate distance to high/low lines:
21313 double keyPixel = keyAxis->coordToPixel(it.value().key);
21314 double highLineDistSqr = distSqrToLine(QPointF(keyPixel, valueAxis->coordToPixel(it.value().high)), QPointF(keyPixel, valueAxis->coordToPixel(qMax(it.value().open, it.value().close))), pos);
21315 double lowLineDistSqr = distSqrToLine(QPointF(keyPixel, valueAxis->coordToPixel(it.value().low)), QPointF(keyPixel, valueAxis->coordToPixel(qMin(it.value().open, it.value().close))), pos);
21316 currentDistSqr = qMin(highLineDistSqr, lowLineDistSqr);
21317 }
21318 if (currentDistSqr < minDistSqr)
21319 minDistSqr = currentDistSqr;
21819 21320 }
21820 21321 } else // keyAxis->orientation() == Qt::Vertical
21821 21322 {
21822 for (it = begin; it != end; ++it)
21823 {
21824 double currentDistSqr;
21825 // determine whether pos is in open-close-box:
21826 QCPRange boxKeyRange(it.value().key-mWidth*0.5, it.value().key+mWidth*0.5);
21827 QCPRange boxValueRange(it.value().close, it.value().open);
21828 double posKey, posValue;
21829 pixelsToCoords(pos, posKey, posValue);
21830 if (boxKeyRange.contains(posKey) && boxValueRange.contains(posValue)) // is in open-close-box
21831 {
21832 currentDistSqr = mParentPlot->selectionTolerance()*0.99 * mParentPlot->selectionTolerance()*0.99;
21323 for (it = begin; it != end; ++it)
21324 {
21325 double currentDistSqr;
21326 // determine whether pos is in open-close-box:
21327 QCPRange boxKeyRange(it.value().key-mWidth*0.5, it.value().key+mWidth*0.5);
21328 QCPRange boxValueRange(it.value().close, it.value().open);
21329 double posKey, posValue;
21330 pixelsToCoords(pos, posKey, posValue);
21331 if (boxKeyRange.contains(posKey) && boxValueRange.contains(posValue)) // is in open-close-box
21332 {
21333 currentDistSqr = mParentPlot->selectionTolerance()*0.99 * mParentPlot->selectionTolerance()*0.99;
21833 21334 } else
21834 21335 {
21835 // calculate distance to high/low lines:
21836 double keyPixel = keyAxis->coordToPixel(it.value().key);
21837 double highLineDistSqr = distSqrToLine(QPointF(valueAxis->coordToPixel(it.value().high), keyPixel), QPointF(valueAxis->coordToPixel(qMax(it.value().open, it.value().close)), keyPixel), pos);
21838 double lowLineDistSqr = distSqrToLine(QPointF(valueAxis->coordToPixel(it.value().low), keyPixel), QPointF(valueAxis->coordToPixel(qMin(it.value().open, it.value().close)), keyPixel), pos);
21839 currentDistSqr = qMin(highLineDistSqr, lowLineDistSqr);
21840 }
21841 if (currentDistSqr < minDistSqr)
21842 minDistSqr = currentDistSqr;
21843 }
21844 }
21845 return qSqrt(minDistSqr);
21336 // calculate distance to high/low lines:
21337 double keyPixel = keyAxis->coordToPixel(it.value().key);
21338 double highLineDistSqr = distSqrToLine(QPointF(valueAxis->coordToPixel(it.value().high), keyPixel), QPointF(valueAxis->coordToPixel(qMax(it.value().open, it.value().close)), keyPixel), pos);
21339 double lowLineDistSqr = distSqrToLine(QPointF(valueAxis->coordToPixel(it.value().low), keyPixel), QPointF(valueAxis->coordToPixel(qMin(it.value().open, it.value().close)), keyPixel), pos);
21340 currentDistSqr = qMin(highLineDistSqr, lowLineDistSqr);
21341 }
21342 if (currentDistSqr < minDistSqr)
21343 minDistSqr = currentDistSqr;
21344 }
21345 }
21346 return qSqrt(minDistSqr);
21846 21347 }
21847 21348
21848 21349 /*! \internal
@@ -21863,22 +21364,22 double QCPFinancial::candlestickSelectTe
21863 21364 */
21864 21365 void QCPFinancial::getVisibleDataBounds(QCPFinancialDataMap::const_iterator &lower, QCPFinancialDataMap::const_iterator &upper) const
21865 21366 {
21866 if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
21867 if (mData->isEmpty())
21868 {
21869 lower = mData->constEnd();
21870 upper = mData->constEnd();
21871 return;
21872 }
21873
21874 // get visible data range as QMap iterators
21875 QCPFinancialDataMap::const_iterator lbound = mData->lowerBound(mKeyAxis.data()->range().lower);
21876 QCPFinancialDataMap::const_iterator ubound = mData->upperBound(mKeyAxis.data()->range().upper);
21877 bool lowoutlier = lbound != mData->constBegin(); // indicates whether there exist points below axis range
21878 bool highoutlier = ubound != mData->constEnd(); // indicates whether there exist points above axis range
21879
21880 lower = (lowoutlier ? lbound-1 : lbound); // data point range that will be actually drawn
21881 upper = (highoutlier ? ubound : ubound-1); // data point range that will be actually drawn
21367 if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
21368 if (mData->isEmpty())
21369 {
21370 lower = mData->constEnd();
21371 upper = mData->constEnd();
21372 return;
21373 }
21374
21375 // get visible data range as QMap iterators
21376 QCPFinancialDataMap::const_iterator lbound = mData->lowerBound(mKeyAxis.data()->range().lower);
21377 QCPFinancialDataMap::const_iterator ubound = mData->upperBound(mKeyAxis.data()->range().upper);
21378 bool lowoutlier = lbound != mData->constBegin(); // indicates whether there exist points below axis range
21379 bool highoutlier = ubound != mData->constEnd(); // indicates whether there exist points above axis range
21380
21381 lower = (lowoutlier ? lbound-1 : lbound); // data point range that will be actually drawn
21382 upper = (highoutlier ? ubound : ubound-1); // data point range that will be actually drawn
21882 21383 }
21883 21384
21884 21385
@@ -21900,15 +21401,15 void QCPFinancial::getVisibleDataBounds(
21900 21401 The constructed item can be added to the plot with QCustomPlot::addItem.
21901 21402 */
21902 21403 QCPItemStraightLine::QCPItemStraightLine(QCustomPlot *parentPlot) :
21903 QCPAbstractItem(parentPlot),
21904 point1(createPosition(QLatin1String("point1"))),
21905 point2(createPosition(QLatin1String("point2")))
21906 {
21907 point1->setCoords(0, 0);
21908 point2->setCoords(1, 1);
21909
21910 setPen(QPen(Qt::black));
21911 setSelectedPen(QPen(Qt::blue,2));
21404 QCPAbstractItem(parentPlot),
21405 point1(createPosition(QLatin1String("point1"))),
21406 point2(createPosition(QLatin1String("point2")))
21407 {
21408 point1->setCoords(0, 0);
21409 point2->setCoords(1, 1);
21410
21411 setPen(QPen(Qt::black));
21412 setSelectedPen(QPen(Qt::blue,2));
21912 21413 }
21913 21414
21914 21415 QCPItemStraightLine::~QCPItemStraightLine()
@@ -21922,7 +21423,7 QCPItemStraightLine::~QCPItemStraightLin
21922 21423 */
21923 21424 void QCPItemStraightLine::setPen(const QPen &pen)
21924 21425 {
21925 mPen = pen;
21426 mPen = pen;
21926 21427 }
21927 21428
21928 21429 /*!
@@ -21932,32 +21433,32 void QCPItemStraightLine::setPen(const Q
21932 21433 */
21933 21434 void QCPItemStraightLine::setSelectedPen(const QPen &pen)
21934 21435 {
21935 mSelectedPen = pen;
21436 mSelectedPen = pen;
21936 21437 }
21937 21438
21938 21439 /* inherits documentation from base class */
21939 21440 double QCPItemStraightLine::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
21940 21441 {
21941 Q_UNUSED(details)
21942 if (onlySelectable && !mSelectable)
21943 return -1;
21944
21945 return distToStraightLine(QVector2D(point1->pixelPoint()), QVector2D(point2->pixelPoint()-point1->pixelPoint()), QVector2D(pos));
21442 Q_UNUSED(details)
21443 if (onlySelectable && !mSelectable)
21444 return -1;
21445
21446 return distToStraightLine(QVector2D(point1->pixelPoint()), QVector2D(point2->pixelPoint()-point1->pixelPoint()), QVector2D(pos));
21946 21447 }
21947 21448
21948 21449 /* inherits documentation from base class */
21949 21450 void QCPItemStraightLine::draw(QCPPainter *painter)
21950 21451 {
21951 QVector2D start(point1->pixelPoint());
21952 QVector2D end(point2->pixelPoint());
21953 // get visible segment of straight line inside clipRect:
21954 double clipPad = mainPen().widthF();
21955 QLineF line = getRectClippedStraightLine(start, end-start, clipRect().adjusted(-clipPad, -clipPad, clipPad, clipPad));
21956 // paint visible segment, if existent:
21957 if (!line.isNull())
21958 {
21959 painter->setPen(mainPen());
21960 painter->drawLine(line);
21452 QVector2D start(point1->pixelPoint());
21453 QVector2D end(point2->pixelPoint());
21454 // get visible segment of straight line inside clipRect:
21455 double clipPad = mainPen().widthF();
21456 QLineF line = getRectClippedStraightLine(start, end-start, clipRect().adjusted(-clipPad, -clipPad, clipPad, clipPad));
21457 // paint visible segment, if existent:
21458 if (!line.isNull())
21459 {
21460 painter->setPen(mainPen());
21461 painter->drawLine(line);
21961 21462 }
21962 21463 }
21963 21464
@@ -21970,7 +21471,7 void QCPItemStraightLine::draw(QCPPainte
21970 21471 */
21971 21472 double QCPItemStraightLine::distToStraightLine(const QVector2D &base, const QVector2D &vec, const QVector2D &point) const
21972 21473 {
21973 return qAbs((base.y()-point.y())*vec.x()-(base.x()-point.x())*vec.y())/vec.length();
21474 return qAbs((base.y()-point.y())*vec.x()-(base.x()-point.x())*vec.y())/vec.length();
21974 21475 }
21975 21476
21976 21477 /*! \internal
@@ -21982,81 +21483,81 double QCPItemStraightLine::distToStraig
21982 21483 */
21983 21484 QLineF QCPItemStraightLine::getRectClippedStraightLine(const QVector2D &base, const QVector2D &vec, const QRect &rect) const
21984 21485 {
21985 double bx, by;
21986 double gamma;
21987 QLineF result;
21988 if (vec.x() == 0 && vec.y() == 0)
21989 return result;
21990 if (qFuzzyIsNull(vec.x())) // line is vertical
21991 {
21992 // check top of rect:
21993 bx = rect.left();
21994 by = rect.top();
21995 gamma = base.x()-bx + (by-base.y())*vec.x()/vec.y();
21996 if (gamma >= 0 && gamma <= rect.width())
21997 result.setLine(bx+gamma, rect.top(), bx+gamma, rect.bottom()); // no need to check bottom because we know line is vertical
21486 double bx, by;
21487 double gamma;
21488 QLineF result;
21489 if (vec.x() == 0 && vec.y() == 0)
21490 return result;
21491 if (qFuzzyIsNull(vec.x())) // line is vertical
21492 {
21493 // check top of rect:
21494 bx = rect.left();
21495 by = rect.top();
21496 gamma = base.x()-bx + (by-base.y())*vec.x()/vec.y();
21497 if (gamma >= 0 && gamma <= rect.width())
21498 result.setLine(bx+gamma, rect.top(), bx+gamma, rect.bottom()); // no need to check bottom because we know line is vertical
21998 21499 } else if (qFuzzyIsNull(vec.y())) // line is horizontal
21999 21500 {
22000 // check left of rect:
22001 bx = rect.left();
22002 by = rect.top();
22003 gamma = base.y()-by + (bx-base.x())*vec.y()/vec.x();
22004 if (gamma >= 0 && gamma <= rect.height())
22005 result.setLine(rect.left(), by+gamma, rect.right(), by+gamma); // no need to check right because we know line is horizontal
21501 // check left of rect:
21502 bx = rect.left();
21503 by = rect.top();
21504 gamma = base.y()-by + (bx-base.x())*vec.y()/vec.x();
21505 if (gamma >= 0 && gamma <= rect.height())
21506 result.setLine(rect.left(), by+gamma, rect.right(), by+gamma); // no need to check right because we know line is horizontal
22006 21507 } else // line is skewed
22007 21508 {
22008 QList<QVector2D> pointVectors;
22009 // check top of rect:
22010 bx = rect.left();
22011 by = rect.top();
22012 gamma = base.x()-bx + (by-base.y())*vec.x()/vec.y();
22013 if (gamma >= 0 && gamma <= rect.width())
22014 pointVectors.append(QVector2D(bx+gamma, by));
22015 // check bottom of rect:
22016 bx = rect.left();
22017 by = rect.bottom();
22018 gamma = base.x()-bx + (by-base.y())*vec.x()/vec.y();
22019 if (gamma >= 0 && gamma <= rect.width())
22020 pointVectors.append(QVector2D(bx+gamma, by));
22021 // check left of rect:
22022 bx = rect.left();
22023 by = rect.top();
22024 gamma = base.y()-by + (bx-base.x())*vec.y()/vec.x();
22025 if (gamma >= 0 && gamma <= rect.height())
22026 pointVectors.append(QVector2D(bx, by+gamma));
22027 // check right of rect:
22028 bx = rect.right();
22029 by = rect.top();
22030 gamma = base.y()-by + (bx-base.x())*vec.y()/vec.x();
22031 if (gamma >= 0 && gamma <= rect.height())
22032 pointVectors.append(QVector2D(bx, by+gamma));
22033
22034 // evaluate points:
22035 if (pointVectors.size() == 2)
22036 {
22037 result.setPoints(pointVectors.at(0).toPointF(), pointVectors.at(1).toPointF());
21509 QList<QVector2D> pointVectors;
21510 // check top of rect:
21511 bx = rect.left();
21512 by = rect.top();
21513 gamma = base.x()-bx + (by-base.y())*vec.x()/vec.y();
21514 if (gamma >= 0 && gamma <= rect.width())
21515 pointVectors.append(QVector2D(bx+gamma, by));
21516 // check bottom of rect:
21517 bx = rect.left();
21518 by = rect.bottom();
21519 gamma = base.x()-bx + (by-base.y())*vec.x()/vec.y();
21520 if (gamma >= 0 && gamma <= rect.width())
21521 pointVectors.append(QVector2D(bx+gamma, by));
21522 // check left of rect:
21523 bx = rect.left();
21524 by = rect.top();
21525 gamma = base.y()-by + (bx-base.x())*vec.y()/vec.x();
21526 if (gamma >= 0 && gamma <= rect.height())
21527 pointVectors.append(QVector2D(bx, by+gamma));
21528 // check right of rect:
21529 bx = rect.right();
21530 by = rect.top();
21531 gamma = base.y()-by + (bx-base.x())*vec.y()/vec.x();
21532 if (gamma >= 0 && gamma <= rect.height())
21533 pointVectors.append(QVector2D(bx, by+gamma));
21534
21535 // evaluate points:
21536 if (pointVectors.size() == 2)
21537 {
21538 result.setPoints(pointVectors.at(0).toPointF(), pointVectors.at(1).toPointF());
22038 21539 } else if (pointVectors.size() > 2)
22039 21540 {
22040 // line probably goes through corner of rect, and we got two points there. single out the point pair with greatest distance:
22041 double distSqrMax = 0;
22042 QVector2D pv1, pv2;
22043 for (int i=0; i<pointVectors.size()-1; ++i)
22044 {
22045 for (int k=i+1; k<pointVectors.size(); ++k)
21541 // line probably goes through corner of rect, and we got two points there. single out the point pair with greatest distance:
21542 double distSqrMax = 0;
21543 QVector2D pv1, pv2;
21544 for (int i=0; i<pointVectors.size()-1; ++i)
21545 {
21546 for (int k=i+1; k<pointVectors.size(); ++k)
22046 21547 {
22047 double distSqr = (pointVectors.at(i)-pointVectors.at(k)).lengthSquared();
22048 if (distSqr > distSqrMax)
21548 double distSqr = (pointVectors.at(i)-pointVectors.at(k)).lengthSquared();
21549 if (distSqr > distSqrMax)
22049 21550 {
22050 pv1 = pointVectors.at(i);
22051 pv2 = pointVectors.at(k);
22052 distSqrMax = distSqr;
21551 pv1 = pointVectors.at(i);
21552 pv2 = pointVectors.at(k);
21553 distSqrMax = distSqr;
22053 21554 }
22054 21555 }
22055 21556 }
22056 result.setPoints(pv1.toPointF(), pv2.toPointF());
22057 }
22058 }
22059 return result;
21557 result.setPoints(pv1.toPointF(), pv2.toPointF());
21558 }
21559 }
21560 return result;
22060 21561 }
22061 21562
22062 21563 /*! \internal
@@ -22066,7 +21567,7 QLineF QCPItemStraightLine::getRectClipp
22066 21567 */
22067 21568 QPen QCPItemStraightLine::mainPen() const
22068 21569 {
22069 return mSelected ? mSelectedPen : mPen;
21570 return mSelected ? mSelectedPen : mPen;
22070 21571 }
22071 21572
22072 21573
@@ -22090,15 +21591,15 QPen QCPItemStraightLine::mainPen() cons
22090 21591 The constructed item can be added to the plot with QCustomPlot::addItem.
22091 21592 */
22092 21593 QCPItemLine::QCPItemLine(QCustomPlot *parentPlot) :
22093 QCPAbstractItem(parentPlot),
22094 start(createPosition(QLatin1String("start"))),
22095 end(createPosition(QLatin1String("end")))
22096 {
22097 start->setCoords(0, 0);
22098 end->setCoords(1, 1);
22099
22100 setPen(QPen(Qt::black));
22101 setSelectedPen(QPen(Qt::blue,2));
21594 QCPAbstractItem(parentPlot),
21595 start(createPosition(QLatin1String("start"))),
21596 end(createPosition(QLatin1String("end")))
21597 {
21598 start->setCoords(0, 0);
21599 end->setCoords(1, 1);
21600
21601 setPen(QPen(Qt::black));
21602 setSelectedPen(QPen(Qt::blue,2));
22102 21603 }
22103 21604
22104 21605 QCPItemLine::~QCPItemLine()
@@ -22112,7 +21613,7 QCPItemLine::~QCPItemLine()
22112 21613 */
22113 21614 void QCPItemLine::setPen(const QPen &pen)
22114 21615 {
22115 mPen = pen;
21616 mPen = pen;
22116 21617 }
22117 21618
22118 21619 /*!
@@ -22122,7 +21623,7 void QCPItemLine::setPen(const QPen &pen
22122 21623 */
22123 21624 void QCPItemLine::setSelectedPen(const QPen &pen)
22124 21625 {
22125 mSelectedPen = pen;
21626 mSelectedPen = pen;
22126 21627 }
22127 21628
22128 21629 /*!
@@ -22135,7 +21636,7 void QCPItemLine::setSelectedPen(const Q
22135 21636 */
22136 21637 void QCPItemLine::setHead(const QCPLineEnding &head)
22137 21638 {
22138 mHead = head;
21639 mHead = head;
22139 21640 }
22140 21641
22141 21642 /*!
@@ -22148,40 +21649,40 void QCPItemLine::setHead(const QCPLineE
22148 21649 */
22149 21650 void QCPItemLine::setTail(const QCPLineEnding &tail)
22150 21651 {
22151 mTail = tail;
21652 mTail = tail;
22152 21653 }
22153 21654
22154 21655 /* inherits documentation from base class */
22155 21656 double QCPItemLine::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
22156 21657 {
22157 Q_UNUSED(details)
22158 if (onlySelectable && !mSelectable)
22159 return -1;
22160
22161 return qSqrt(distSqrToLine(start->pixelPoint(), end->pixelPoint(), pos));
21658 Q_UNUSED(details)
21659 if (onlySelectable && !mSelectable)
21660 return -1;
21661
21662 return qSqrt(distSqrToLine(start->pixelPoint(), end->pixelPoint(), pos));
22162 21663 }
22163 21664
22164 21665 /* inherits documentation from base class */
22165 21666 void QCPItemLine::draw(QCPPainter *painter)
22166 21667 {
22167 QVector2D startVec(start->pixelPoint());
22168 QVector2D endVec(end->pixelPoint());
22169 if (startVec.toPoint() == endVec.toPoint())
22170 return;
22171 // get visible segment of straight line inside clipRect:
22172 double clipPad = qMax(mHead.boundingDistance(), mTail.boundingDistance());
22173 clipPad = qMax(clipPad, (double)mainPen().widthF());
22174 QLineF line = getRectClippedLine(startVec, endVec, clipRect().adjusted(-clipPad, -clipPad, clipPad, clipPad));
22175 // paint visible segment, if existent:
22176 if (!line.isNull())
22177 {
22178 painter->setPen(mainPen());
22179 painter->drawLine(line);
22180 painter->setBrush(Qt::SolidPattern);
22181 if (mTail.style() != QCPLineEnding::esNone)
22182 mTail.draw(painter, startVec, startVec-endVec);
22183 if (mHead.style() != QCPLineEnding::esNone)
22184 mHead.draw(painter, endVec, endVec-startVec);
21668 QVector2D startVec(start->pixelPoint());
21669 QVector2D endVec(end->pixelPoint());
21670 if (startVec.toPoint() == endVec.toPoint())
21671 return;
21672 // get visible segment of straight line inside clipRect:
21673 double clipPad = qMax(mHead.boundingDistance(), mTail.boundingDistance());
21674 clipPad = qMax(clipPad, (double)mainPen().widthF());
21675 QLineF line = getRectClippedLine(startVec, endVec, clipRect().adjusted(-clipPad, -clipPad, clipPad, clipPad));
21676 // paint visible segment, if existent:
21677 if (!line.isNull())
21678 {
21679 painter->setPen(mainPen());
21680 painter->drawLine(line);
21681 painter->setBrush(Qt::SolidPattern);
21682 if (mTail.style() != QCPLineEnding::esNone)
21683 mTail.draw(painter, startVec, startVec-endVec);
21684 if (mHead.style() != QCPLineEnding::esNone)
21685 mHead.draw(painter, endVec, endVec-startVec);
22185 21686 }
22186 21687 }
22187 21688
@@ -22194,95 +21695,95 void QCPItemLine::draw(QCPPainter *paint
22194 21695 */
22195 21696 QLineF QCPItemLine::getRectClippedLine(const QVector2D &start, const QVector2D &end, const QRect &rect) const
22196 21697 {
22197 bool containsStart = rect.contains(start.x(), start.y());
22198 bool containsEnd = rect.contains(end.x(), end.y());
22199 if (containsStart && containsEnd)
22200 return QLineF(start.toPointF(), end.toPointF());
22201
22202 QVector2D base = start;
22203 QVector2D vec = end-start;
22204 double bx, by;
22205 double gamma, mu;
22206 QLineF result;
22207 QList<QVector2D> pointVectors;
22208
22209 if (!qFuzzyIsNull(vec.y())) // line is not horizontal
22210 {
22211 // check top of rect:
22212 bx = rect.left();
22213 by = rect.top();
22214 mu = (by-base.y())/vec.y();
22215 if (mu >= 0 && mu <= 1)
22216 {
22217 gamma = base.x()-bx + mu*vec.x();
22218 if (gamma >= 0 && gamma <= rect.width())
22219 pointVectors.append(QVector2D(bx+gamma, by));
22220 }
22221 // check bottom of rect:
22222 bx = rect.left();
22223 by = rect.bottom();
22224 mu = (by-base.y())/vec.y();
22225 if (mu >= 0 && mu <= 1)
22226 {
22227 gamma = base.x()-bx + mu*vec.x();
22228 if (gamma >= 0 && gamma <= rect.width())
22229 pointVectors.append(QVector2D(bx+gamma, by));
22230 }
22231 }
22232 if (!qFuzzyIsNull(vec.x())) // line is not vertical
22233 {
22234 // check left of rect:
22235 bx = rect.left();
22236 by = rect.top();
22237 mu = (bx-base.x())/vec.x();
22238 if (mu >= 0 && mu <= 1)
22239 {
22240 gamma = base.y()-by + mu*vec.y();
22241 if (gamma >= 0 && gamma <= rect.height())
22242 pointVectors.append(QVector2D(bx, by+gamma));
22243 }
22244 // check right of rect:
22245 bx = rect.right();
22246 by = rect.top();
22247 mu = (bx-base.x())/vec.x();
22248 if (mu >= 0 && mu <= 1)
22249 {
22250 gamma = base.y()-by + mu*vec.y();
22251 if (gamma >= 0 && gamma <= rect.height())
22252 pointVectors.append(QVector2D(bx, by+gamma));
22253 }
22254 }
22255
22256 if (containsStart)
22257 pointVectors.append(start);
22258 if (containsEnd)
22259 pointVectors.append(end);
22260
22261 // evaluate points:
22262 if (pointVectors.size() == 2)
22263 {
22264 result.setPoints(pointVectors.at(0).toPointF(), pointVectors.at(1).toPointF());
21698 bool containsStart = rect.contains(start.x(), start.y());
21699 bool containsEnd = rect.contains(end.x(), end.y());
21700 if (containsStart && containsEnd)
21701 return QLineF(start.toPointF(), end.toPointF());
21702
21703 QVector2D base = start;
21704 QVector2D vec = end-start;
21705 double bx, by;
21706 double gamma, mu;
21707 QLineF result;
21708 QList<QVector2D> pointVectors;
21709
21710 if (!qFuzzyIsNull(vec.y())) // line is not horizontal
21711 {
21712 // check top of rect:
21713 bx = rect.left();
21714 by = rect.top();
21715 mu = (by-base.y())/vec.y();
21716 if (mu >= 0 && mu <= 1)
21717 {
21718 gamma = base.x()-bx + mu*vec.x();
21719 if (gamma >= 0 && gamma <= rect.width())
21720 pointVectors.append(QVector2D(bx+gamma, by));
21721 }
21722 // check bottom of rect:
21723 bx = rect.left();
21724 by = rect.bottom();
21725 mu = (by-base.y())/vec.y();
21726 if (mu >= 0 && mu <= 1)
21727 {
21728 gamma = base.x()-bx + mu*vec.x();
21729 if (gamma >= 0 && gamma <= rect.width())
21730 pointVectors.append(QVector2D(bx+gamma, by));
21731 }
21732 }
21733 if (!qFuzzyIsNull(vec.x())) // line is not vertical
21734 {
21735 // check left of rect:
21736 bx = rect.left();
21737 by = rect.top();
21738 mu = (bx-base.x())/vec.x();
21739 if (mu >= 0 && mu <= 1)
21740 {
21741 gamma = base.y()-by + mu*vec.y();
21742 if (gamma >= 0 && gamma <= rect.height())
21743 pointVectors.append(QVector2D(bx, by+gamma));
21744 }
21745 // check right of rect:
21746 bx = rect.right();
21747 by = rect.top();
21748 mu = (bx-base.x())/vec.x();
21749 if (mu >= 0 && mu <= 1)
21750 {
21751 gamma = base.y()-by + mu*vec.y();
21752 if (gamma >= 0 && gamma <= rect.height())
21753 pointVectors.append(QVector2D(bx, by+gamma));
21754 }
21755 }
21756
21757 if (containsStart)
21758 pointVectors.append(start);
21759 if (containsEnd)
21760 pointVectors.append(end);
21761
21762 // evaluate points:
21763 if (pointVectors.size() == 2)
21764 {
21765 result.setPoints(pointVectors.at(0).toPointF(), pointVectors.at(1).toPointF());
22265 21766 } else if (pointVectors.size() > 2)
22266 21767 {
22267 // line probably goes through corner of rect, and we got two points there. single out the point pair with greatest distance:
22268 double distSqrMax = 0;
22269 QVector2D pv1, pv2;
22270 for (int i=0; i<pointVectors.size()-1; ++i)
22271 {
22272 for (int k=i+1; k<pointVectors.size(); ++k)
22273 {
22274 double distSqr = (pointVectors.at(i)-pointVectors.at(k)).lengthSquared();
22275 if (distSqr > distSqrMax)
21768 // line probably goes through corner of rect, and we got two points there. single out the point pair with greatest distance:
21769 double distSqrMax = 0;
21770 QVector2D pv1, pv2;
21771 for (int i=0; i<pointVectors.size()-1; ++i)
21772 {
21773 for (int k=i+1; k<pointVectors.size(); ++k)
21774 {
21775 double distSqr = (pointVectors.at(i)-pointVectors.at(k)).lengthSquared();
21776 if (distSqr > distSqrMax)
22276 21777 {
22277 pv1 = pointVectors.at(i);
22278 pv2 = pointVectors.at(k);
22279 distSqrMax = distSqr;
21778 pv1 = pointVectors.at(i);
21779 pv2 = pointVectors.at(k);
21780 distSqrMax = distSqr;
22280 21781 }
22281 21782 }
22282 21783 }
22283 result.setPoints(pv1.toPointF(), pv2.toPointF());
22284 }
22285 return result;
21784 result.setPoints(pv1.toPointF(), pv2.toPointF());
21785 }
21786 return result;
22286 21787 }
22287 21788
22288 21789 /*! \internal
@@ -22292,7 +21793,7 QLineF QCPItemLine::getRectClippedLine(c
22292 21793 */
22293 21794 QPen QCPItemLine::mainPen() const
22294 21795 {
22295 return mSelected ? mSelectedPen : mPen;
21796 return mSelected ? mSelectedPen : mPen;
22296 21797 }
22297 21798
22298 21799
@@ -22323,19 +21824,19 QPen QCPItemLine::mainPen() const
22323 21824 The constructed item can be added to the plot with QCustomPlot::addItem.
22324 21825 */
22325 21826 QCPItemCurve::QCPItemCurve(QCustomPlot *parentPlot) :
22326 QCPAbstractItem(parentPlot),
22327 start(createPosition(QLatin1String("start"))),
22328 startDir(createPosition(QLatin1String("startDir"))),
22329 endDir(createPosition(QLatin1String("endDir"))),
22330 end(createPosition(QLatin1String("end")))
22331 {
22332 start->setCoords(0, 0);
22333 startDir->setCoords(0.5, 0);
22334 endDir->setCoords(0, 0.5);
22335 end->setCoords(1, 1);
22336
22337 setPen(QPen(Qt::black));
22338 setSelectedPen(QPen(Qt::blue,2));
21827 QCPAbstractItem(parentPlot),
21828 start(createPosition(QLatin1String("start"))),
21829 startDir(createPosition(QLatin1String("startDir"))),
21830 endDir(createPosition(QLatin1String("endDir"))),
21831 end(createPosition(QLatin1String("end")))
21832 {
21833 start->setCoords(0, 0);
21834 startDir->setCoords(0.5, 0);
21835 endDir->setCoords(0, 0.5);
21836 end->setCoords(1, 1);
21837
21838 setPen(QPen(Qt::black));
21839 setSelectedPen(QPen(Qt::blue,2));
22339 21840 }
22340 21841
22341 21842 QCPItemCurve::~QCPItemCurve()
@@ -22349,7 +21850,7 QCPItemCurve::~QCPItemCurve()
22349 21850 */
22350 21851 void QCPItemCurve::setPen(const QPen &pen)
22351 21852 {
22352 mPen = pen;
21853 mPen = pen;
22353 21854 }
22354 21855
22355 21856 /*!
@@ -22359,7 +21860,7 void QCPItemCurve::setPen(const QPen &pe
22359 21860 */
22360 21861 void QCPItemCurve::setSelectedPen(const QPen &pen)
22361 21862 {
22362 mSelectedPen = pen;
21863 mSelectedPen = pen;
22363 21864 }
22364 21865
22365 21866 /*!
@@ -22372,7 +21873,7 void QCPItemCurve::setSelectedPen(const
22372 21873 */
22373 21874 void QCPItemCurve::setHead(const QCPLineEnding &head)
22374 21875 {
22375 mHead = head;
21876 mHead = head;
22376 21877 }
22377 21878
22378 21879 /*!
@@ -22385,62 +21886,62 void QCPItemCurve::setHead(const QCPLine
22385 21886 */
22386 21887 void QCPItemCurve::setTail(const QCPLineEnding &tail)
22387 21888 {
22388 mTail = tail;
21889 mTail = tail;
22389 21890 }
22390 21891
22391 21892 /* inherits documentation from base class */
22392 21893 double QCPItemCurve::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
22393 21894 {
22394 Q_UNUSED(details)
22395 if (onlySelectable && !mSelectable)
22396 return -1;
22397
22398 QPointF startVec(start->pixelPoint());
22399 QPointF startDirVec(startDir->pixelPoint());
22400 QPointF endDirVec(endDir->pixelPoint());
22401 QPointF endVec(end->pixelPoint());
22402
22403 QPainterPath cubicPath(startVec);
22404 cubicPath.cubicTo(startDirVec, endDirVec, endVec);
22405
22406 QPolygonF polygon = cubicPath.toSubpathPolygons().first();
22407 double minDistSqr = std::numeric_limits<double>::max();
22408 for (int i=1; i<polygon.size(); ++i)
22409 {
22410 double distSqr = distSqrToLine(polygon.at(i-1), polygon.at(i), pos);
22411 if (distSqr < minDistSqr)
22412 minDistSqr = distSqr;
22413 }
22414 return qSqrt(minDistSqr);
21895 Q_UNUSED(details)
21896 if (onlySelectable && !mSelectable)
21897 return -1;
21898
21899 QPointF startVec(start->pixelPoint());
21900 QPointF startDirVec(startDir->pixelPoint());
21901 QPointF endDirVec(endDir->pixelPoint());
21902 QPointF endVec(end->pixelPoint());
21903
21904 QPainterPath cubicPath(startVec);
21905 cubicPath.cubicTo(startDirVec, endDirVec, endVec);
21906
21907 QPolygonF polygon = cubicPath.toSubpathPolygons().first();
21908 double minDistSqr = std::numeric_limits<double>::max();
21909 for (int i=1; i<polygon.size(); ++i)
21910 {
21911 double distSqr = distSqrToLine(polygon.at(i-1), polygon.at(i), pos);
21912 if (distSqr < minDistSqr)
21913 minDistSqr = distSqr;
21914 }
21915 return qSqrt(minDistSqr);
22415 21916 }
22416 21917
22417 21918 /* inherits documentation from base class */
22418 21919 void QCPItemCurve::draw(QCPPainter *painter)
22419 21920 {
22420 QPointF startVec(start->pixelPoint());
22421 QPointF startDirVec(startDir->pixelPoint());
22422 QPointF endDirVec(endDir->pixelPoint());
22423 QPointF endVec(end->pixelPoint());
22424 if (QVector2D(endVec-startVec).length() > 1e10f) // too large curves cause crash
22425 return;
22426
22427 QPainterPath cubicPath(startVec);
22428 cubicPath.cubicTo(startDirVec, endDirVec, endVec);
22429
22430 // paint visible segment, if existent:
22431 QRect clip = clipRect().adjusted(-mainPen().widthF(), -mainPen().widthF(), mainPen().widthF(), mainPen().widthF());
22432 QRect cubicRect = cubicPath.controlPointRect().toRect();
22433 if (cubicRect.isEmpty()) // may happen when start and end exactly on same x or y position
22434 cubicRect.adjust(0, 0, 1, 1);
22435 if (clip.intersects(cubicRect))
22436 {
22437 painter->setPen(mainPen());
22438 painter->drawPath(cubicPath);
22439 painter->setBrush(Qt::SolidPattern);
22440 if (mTail.style() != QCPLineEnding::esNone)
22441 mTail.draw(painter, QVector2D(startVec), M_PI-cubicPath.angleAtPercent(0)/180.0*M_PI);
22442 if (mHead.style() != QCPLineEnding::esNone)
22443 mHead.draw(painter, QVector2D(endVec), -cubicPath.angleAtPercent(1)/180.0*M_PI);
21921 QPointF startVec(start->pixelPoint());
21922 QPointF startDirVec(startDir->pixelPoint());
21923 QPointF endDirVec(endDir->pixelPoint());
21924 QPointF endVec(end->pixelPoint());
21925 if (QVector2D(endVec-startVec).length() > 1e10f) // too large curves cause crash
21926 return;
21927
21928 QPainterPath cubicPath(startVec);
21929 cubicPath.cubicTo(startDirVec, endDirVec, endVec);
21930
21931 // paint visible segment, if existent:
21932 QRect clip = clipRect().adjusted(-mainPen().widthF(), -mainPen().widthF(), mainPen().widthF(), mainPen().widthF());
21933 QRect cubicRect = cubicPath.controlPointRect().toRect();
21934 if (cubicRect.isEmpty()) // may happen when start and end exactly on same x or y position
21935 cubicRect.adjust(0, 0, 1, 1);
21936 if (clip.intersects(cubicRect))
21937 {
21938 painter->setPen(mainPen());
21939 painter->drawPath(cubicPath);
21940 painter->setBrush(Qt::SolidPattern);
21941 if (mTail.style() != QCPLineEnding::esNone)
21942 mTail.draw(painter, QVector2D(startVec), M_PI-cubicPath.angleAtPercent(0)/180.0*M_PI);
21943 if (mHead.style() != QCPLineEnding::esNone)
21944 mHead.draw(painter, QVector2D(endVec), -cubicPath.angleAtPercent(1)/180.0*M_PI);
22444 21945 }
22445 21946 }
22446 21947
@@ -22451,7 +21952,7 void QCPItemCurve::draw(QCPPainter *pain
22451 21952 */
22452 21953 QPen QCPItemCurve::mainPen() const
22453 21954 {
22454 return mSelected ? mSelectedPen : mPen;
21955 return mSelected ? mSelectedPen : mPen;
22455 21956 }
22456 21957
22457 21958
@@ -22473,23 +21974,23 QPen QCPItemCurve::mainPen() const
22473 21974 The constructed item can be added to the plot with QCustomPlot::addItem.
22474 21975 */
22475 21976 QCPItemRect::QCPItemRect(QCustomPlot *parentPlot) :
22476 QCPAbstractItem(parentPlot),
22477 topLeft(createPosition(QLatin1String("topLeft"))),
22478 bottomRight(createPosition(QLatin1String("bottomRight"))),
22479 top(createAnchor(QLatin1String("top"), aiTop)),
22480 topRight(createAnchor(QLatin1String("topRight"), aiTopRight)),
22481 right(createAnchor(QLatin1String("right"), aiRight)),
22482 bottom(createAnchor(QLatin1String("bottom"), aiBottom)),
22483 bottomLeft(createAnchor(QLatin1String("bottomLeft"), aiBottomLeft)),
22484 left(createAnchor(QLatin1String("left"), aiLeft))
22485 {
22486 topLeft->setCoords(0, 1);
22487 bottomRight->setCoords(1, 0);
22488
22489 setPen(QPen(Qt::black));
22490 setSelectedPen(QPen(Qt::blue,2));
22491 setBrush(Qt::NoBrush);
22492 setSelectedBrush(Qt::NoBrush);
21977 QCPAbstractItem(parentPlot),
21978 topLeft(createPosition(QLatin1String("topLeft"))),
21979 bottomRight(createPosition(QLatin1String("bottomRight"))),
21980 top(createAnchor(QLatin1String("top"), aiTop)),
21981 topRight(createAnchor(QLatin1String("topRight"), aiTopRight)),
21982 right(createAnchor(QLatin1String("right"), aiRight)),
21983 bottom(createAnchor(QLatin1String("bottom"), aiBottom)),
21984 bottomLeft(createAnchor(QLatin1String("bottomLeft"), aiBottomLeft)),
21985 left(createAnchor(QLatin1String("left"), aiLeft))
21986 {
21987 topLeft->setCoords(0, 1);
21988 bottomRight->setCoords(1, 0);
21989
21990 setPen(QPen(Qt::black));
21991 setSelectedPen(QPen(Qt::blue,2));
21992 setBrush(Qt::NoBrush);
21993 setSelectedBrush(Qt::NoBrush);
22493 21994 }
22494 21995
22495 21996 QCPItemRect::~QCPItemRect()
@@ -22503,7 +22004,7 QCPItemRect::~QCPItemRect()
22503 22004 */
22504 22005 void QCPItemRect::setPen(const QPen &pen)
22505 22006 {
22506 mPen = pen;
22007 mPen = pen;
22507 22008 }
22508 22009
22509 22010 /*!
@@ -22513,7 +22014,7 void QCPItemRect::setPen(const QPen &pen
22513 22014 */
22514 22015 void QCPItemRect::setSelectedPen(const QPen &pen)
22515 22016 {
22516 mSelectedPen = pen;
22017 mSelectedPen = pen;
22517 22018 }
22518 22019
22519 22020 /*!
@@ -22524,7 +22025,7 void QCPItemRect::setSelectedPen(const Q
22524 22025 */
22525 22026 void QCPItemRect::setBrush(const QBrush &brush)
22526 22027 {
22527 mBrush = brush;
22028 mBrush = brush;
22528 22029 }
22529 22030
22530 22031 /*!
@@ -22535,44 +22036,44 void QCPItemRect::setBrush(const QBrush
22535 22036 */
22536 22037 void QCPItemRect::setSelectedBrush(const QBrush &brush)
22537 22038 {
22538 mSelectedBrush = brush;
22039 mSelectedBrush = brush;
22539 22040 }
22540 22041
22541 22042 /* inherits documentation from base class */
22542 22043 double QCPItemRect::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
22543 22044 {
22544 Q_UNUSED(details)
22545 if (onlySelectable && !mSelectable)
22546 return -1;
22547
22548 QRectF rect = QRectF(topLeft->pixelPoint(), bottomRight->pixelPoint()).normalized();
22549 bool filledRect = mBrush.style() != Qt::NoBrush && mBrush.color().alpha() != 0;
22550 return rectSelectTest(rect, pos, filledRect);
22045 Q_UNUSED(details)
22046 if (onlySelectable && !mSelectable)
22047 return -1;
22048
22049 QRectF rect = QRectF(topLeft->pixelPoint(), bottomRight->pixelPoint()).normalized();
22050 bool filledRect = mBrush.style() != Qt::NoBrush && mBrush.color().alpha() != 0;
22051 return rectSelectTest(rect, pos, filledRect);
22551 22052 }
22552 22053
22553 22054 /* inherits documentation from base class */
22554 22055 void QCPItemRect::draw(QCPPainter *painter)
22555 22056 {
22556 QPointF p1 = topLeft->pixelPoint();
22557 QPointF p2 = bottomRight->pixelPoint();
22558 if (p1.toPoint() == p2.toPoint())
22559 return;
22560 QRectF rect = QRectF(p1, p2).normalized();
22561 double clipPad = mainPen().widthF();
22562 QRectF boundingRect = rect.adjusted(-clipPad, -clipPad, clipPad, clipPad);
22563 if (boundingRect.intersects(clipRect())) // only draw if bounding rect of rect item is visible in cliprect
22564 {
22565 painter->setPen(mainPen());
22566 painter->setBrush(mainBrush());
22567 painter->drawRect(rect);
22057 QPointF p1 = topLeft->pixelPoint();
22058 QPointF p2 = bottomRight->pixelPoint();
22059 if (p1.toPoint() == p2.toPoint())
22060 return;
22061 QRectF rect = QRectF(p1, p2).normalized();
22062 double clipPad = mainPen().widthF();
22063 QRectF boundingRect = rect.adjusted(-clipPad, -clipPad, clipPad, clipPad);
22064 if (boundingRect.intersects(clipRect())) // only draw if bounding rect of rect item is visible in cliprect
22065 {
22066 painter->setPen(mainPen());
22067 painter->setBrush(mainBrush());
22068 painter->drawRect(rect);
22568 22069 }
22569 22070 }
22570 22071
22571 22072 /* inherits documentation from base class */
22572 22073 QPointF QCPItemRect::anchorPixelPoint(int anchorId) const
22573 22074 {
22574 QRectF rect = QRectF(topLeft->pixelPoint(), bottomRight->pixelPoint());
22575 switch (anchorId)
22075 QRectF rect = QRectF(topLeft->pixelPoint(), bottomRight->pixelPoint());
22076 switch (anchorId)
22576 22077 {
22577 22078 case aiTop: return (rect.topLeft()+rect.topRight())*0.5;
22578 22079 case aiTopRight: return rect.topRight();
@@ -22581,9 +22082,9 QPointF QCPItemRect::anchorPixelPoint(in
22581 22082 case aiBottomLeft: return rect.bottomLeft();
22582 22083 case aiLeft: return (rect.topLeft()+rect.bottomLeft())*0.5;
22583 22084 }
22584
22585 qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId;
22586 return QPointF();
22085
22086 qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId;
22087 return QPointF();
22587 22088 }
22588 22089
22589 22090 /*! \internal
@@ -22593,7 +22094,7 QPointF QCPItemRect::anchorPixelPoint(in
22593 22094 */
22594 22095 QPen QCPItemRect::mainPen() const
22595 22096 {
22596 return mSelected ? mSelectedPen : mPen;
22097 return mSelected ? mSelectedPen : mPen;
22597 22098 }
22598 22099
22599 22100 /*! \internal
@@ -22603,7 +22104,7 QPen QCPItemRect::mainPen() const
22603 22104 */
22604 22105 QBrush QCPItemRect::mainBrush() const
22605 22106 {
22606 return mSelected ? mSelectedBrush : mBrush;
22107 return mSelected ? mSelectedBrush : mBrush;
22607 22108 }
22608 22109
22609 22110
@@ -22631,30 +22132,30 QBrush QCPItemRect::mainBrush() const
22631 22132 The constructed item can be added to the plot with QCustomPlot::addItem.
22632 22133 */
22633 22134 QCPItemText::QCPItemText(QCustomPlot *parentPlot) :
22634 QCPAbstractItem(parentPlot),
22635 position(createPosition(QLatin1String("position"))),
22636 topLeft(createAnchor(QLatin1String("topLeft"), aiTopLeft)),
22637 top(createAnchor(QLatin1String("top"), aiTop)),
22638 topRight(createAnchor(QLatin1String("topRight"), aiTopRight)),
22639 right(createAnchor(QLatin1String("right"), aiRight)),
22640 bottomRight(createAnchor(QLatin1String("bottomRight"), aiBottomRight)),
22641 bottom(createAnchor(QLatin1String("bottom"), aiBottom)),
22642 bottomLeft(createAnchor(QLatin1String("bottomLeft"), aiBottomLeft)),
22643 left(createAnchor(QLatin1String("left"), aiLeft))
22644 {
22645 position->setCoords(0, 0);
22646
22647 setRotation(0);
22648 setTextAlignment(Qt::AlignTop|Qt::AlignHCenter);
22649 setPositionAlignment(Qt::AlignCenter);
22650 setText(QLatin1String("text"));
22651
22652 setPen(Qt::NoPen);
22653 setSelectedPen(Qt::NoPen);
22654 setBrush(Qt::NoBrush);
22655 setSelectedBrush(Qt::NoBrush);
22656 setColor(Qt::black);
22657 setSelectedColor(Qt::blue);
22135 QCPAbstractItem(parentPlot),
22136 position(createPosition(QLatin1String("position"))),
22137 topLeft(createAnchor(QLatin1String("topLeft"), aiTopLeft)),
22138 top(createAnchor(QLatin1String("top"), aiTop)),
22139 topRight(createAnchor(QLatin1String("topRight"), aiTopRight)),
22140 right(createAnchor(QLatin1String("right"), aiRight)),
22141 bottomRight(createAnchor(QLatin1String("bottomRight"), aiBottomRight)),
22142 bottom(createAnchor(QLatin1String("bottom"), aiBottom)),
22143 bottomLeft(createAnchor(QLatin1String("bottomLeft"), aiBottomLeft)),
22144 left(createAnchor(QLatin1String("left"), aiLeft))
22145 {
22146 position->setCoords(0, 0);
22147
22148 setRotation(0);
22149 setTextAlignment(Qt::AlignTop|Qt::AlignHCenter);
22150 setPositionAlignment(Qt::AlignCenter);
22151 setText(QLatin1String("text"));
22152
22153 setPen(Qt::NoPen);
22154 setSelectedPen(Qt::NoPen);
22155 setBrush(Qt::NoBrush);
22156 setSelectedBrush(Qt::NoBrush);
22157 setColor(Qt::black);
22158 setSelectedColor(Qt::blue);
22658 22159 }
22659 22160
22660 22161 QCPItemText::~QCPItemText()
@@ -22666,7 +22167,7 QCPItemText::~QCPItemText()
22666 22167 */
22667 22168 void QCPItemText::setColor(const QColor &color)
22668 22169 {
22669 mColor = color;
22170 mColor = color;
22670 22171 }
22671 22172
22672 22173 /*!
@@ -22674,7 +22175,7 void QCPItemText::setColor(const QColor
22674 22175 */
22675 22176 void QCPItemText::setSelectedColor(const QColor &color)
22676 22177 {
22677 mSelectedColor = color;
22178 mSelectedColor = color;
22678 22179 }
22679 22180
22680 22181 /*!
@@ -22685,7 +22186,7 void QCPItemText::setSelectedColor(const
22685 22186 */
22686 22187 void QCPItemText::setPen(const QPen &pen)
22687 22188 {
22688 mPen = pen;
22189 mPen = pen;
22689 22190 }
22690 22191
22691 22192 /*!
@@ -22696,7 +22197,7 void QCPItemText::setPen(const QPen &pen
22696 22197 */
22697 22198 void QCPItemText::setSelectedPen(const QPen &pen)
22698 22199 {
22699 mSelectedPen = pen;
22200 mSelectedPen = pen;
22700 22201 }
22701 22202
22702 22203 /*!
@@ -22707,7 +22208,7 void QCPItemText::setSelectedPen(const Q
22707 22208 */
22708 22209 void QCPItemText::setBrush(const QBrush &brush)
22709 22210 {
22710 mBrush = brush;
22211 mBrush = brush;
22711 22212 }
22712 22213
22713 22214 /*!
@@ -22718,7 +22219,7 void QCPItemText::setBrush(const QBrush
22718 22219 */
22719 22220 void QCPItemText::setSelectedBrush(const QBrush &brush)
22720 22221 {
22721 mSelectedBrush = brush;
22222 mSelectedBrush = brush;
22722 22223 }
22723 22224
22724 22225 /*!
@@ -22728,7 +22229,7 void QCPItemText::setSelectedBrush(const
22728 22229 */
22729 22230 void QCPItemText::setFont(const QFont &font)
22730 22231 {
22731 mFont = font;
22232 mFont = font;
22732 22233 }
22733 22234
22734 22235 /*!
@@ -22738,7 +22239,7 void QCPItemText::setFont(const QFont &f
22738 22239 */
22739 22240 void QCPItemText::setSelectedFont(const QFont &font)
22740 22241 {
22741 mSelectedFont = font;
22242 mSelectedFont = font;
22742 22243 }
22743 22244
22744 22245 /*!
@@ -22749,7 +22250,7 void QCPItemText::setSelectedFont(const
22749 22250 */
22750 22251 void QCPItemText::setText(const QString &text)
22751 22252 {
22752 mText = text;
22253 mText = text;
22753 22254 }
22754 22255
22755 22256 /*!
@@ -22766,7 +22267,7 void QCPItemText::setText(const QString
22766 22267 */
22767 22268 void QCPItemText::setPositionAlignment(Qt::Alignment alignment)
22768 22269 {
22769 mPositionAlignment = alignment;
22270 mPositionAlignment = alignment;
22770 22271 }
22771 22272
22772 22273 /*!
@@ -22774,7 +22275,7 void QCPItemText::setPositionAlignment(Q
22774 22275 */
22775 22276 void QCPItemText::setTextAlignment(Qt::Alignment alignment)
22776 22277 {
22777 mTextAlignment = alignment;
22278 mTextAlignment = alignment;
22778 22279 }
22779 22280
22780 22281 /*!
@@ -22783,7 +22284,7 void QCPItemText::setTextAlignment(Qt::A
22783 22284 */
22784 22285 void QCPItemText::setRotation(double degrees)
22785 22286 {
22786 mRotation = degrees;
22287 mRotation = degrees;
22787 22288 }
22788 22289
22789 22290 /*!
@@ -22792,82 +22293,82 void QCPItemText::setRotation(double deg
22792 22293 */
22793 22294 void QCPItemText::setPadding(const QMargins &padding)
22794 22295 {
22795 mPadding = padding;
22296 mPadding = padding;
22796 22297 }
22797 22298
22798 22299 /* inherits documentation from base class */
22799 22300 double QCPItemText::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
22800 22301 {
22801 Q_UNUSED(details)
22802 if (onlySelectable && !mSelectable)
22803 return -1;
22804
22805 // The rect may be rotated, so we transform the actual clicked pos to the rotated
22806 // coordinate system, so we can use the normal rectSelectTest function for non-rotated rects:
22807 QPointF positionPixels(position->pixelPoint());
22808 QTransform inputTransform;
22809 inputTransform.translate(positionPixels.x(), positionPixels.y());
22810 inputTransform.rotate(-mRotation);
22811 inputTransform.translate(-positionPixels.x(), -positionPixels.y());
22812 QPointF rotatedPos = inputTransform.map(pos);
22813 QFontMetrics fontMetrics(mFont);
22814 QRect textRect = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip|mTextAlignment, mText);
22815 QRect textBoxRect = textRect.adjusted(-mPadding.left(), -mPadding.top(), mPadding.right(), mPadding.bottom());
22816 QPointF textPos = getTextDrawPoint(positionPixels, textBoxRect, mPositionAlignment);
22817 textBoxRect.moveTopLeft(textPos.toPoint());
22818
22819 return rectSelectTest(textBoxRect, rotatedPos, true);
22302 Q_UNUSED(details)
22303 if (onlySelectable && !mSelectable)
22304 return -1;
22305
22306 // The rect may be rotated, so we transform the actual clicked pos to the rotated
22307 // coordinate system, so we can use the normal rectSelectTest function for non-rotated rects:
22308 QPointF positionPixels(position->pixelPoint());
22309 QTransform inputTransform;
22310 inputTransform.translate(positionPixels.x(), positionPixels.y());
22311 inputTransform.rotate(-mRotation);
22312 inputTransform.translate(-positionPixels.x(), -positionPixels.y());
22313 QPointF rotatedPos = inputTransform.map(pos);
22314 QFontMetrics fontMetrics(mFont);
22315 QRect textRect = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip|mTextAlignment, mText);
22316 QRect textBoxRect = textRect.adjusted(-mPadding.left(), -mPadding.top(), mPadding.right(), mPadding.bottom());
22317 QPointF textPos = getTextDrawPoint(positionPixels, textBoxRect, mPositionAlignment);
22318 textBoxRect.moveTopLeft(textPos.toPoint());
22319
22320 return rectSelectTest(textBoxRect, rotatedPos, true);
22820 22321 }
22821 22322
22822 22323 /* inherits documentation from base class */
22823 22324 void QCPItemText::draw(QCPPainter *painter)
22824 22325 {
22825 QPointF pos(position->pixelPoint());
22826 QTransform transform = painter->transform();
22827 transform.translate(pos.x(), pos.y());
22828 if (!qFuzzyIsNull(mRotation))
22829 transform.rotate(mRotation);
22830 painter->setFont(mainFont());
22831 QRect textRect = painter->fontMetrics().boundingRect(0, 0, 0, 0, Qt::TextDontClip|mTextAlignment, mText);
22832 QRect textBoxRect = textRect.adjusted(-mPadding.left(), -mPadding.top(), mPadding.right(), mPadding.bottom());
22833 QPointF textPos = getTextDrawPoint(QPointF(0, 0), textBoxRect, mPositionAlignment); // 0, 0 because the transform does the translation
22834 textRect.moveTopLeft(textPos.toPoint()+QPoint(mPadding.left(), mPadding.top()));
22835 textBoxRect.moveTopLeft(textPos.toPoint());
22836 double clipPad = mainPen().widthF();
22837 QRect boundingRect = textBoxRect.adjusted(-clipPad, -clipPad, clipPad, clipPad);
22838 if (transform.mapRect(boundingRect).intersects(painter->transform().mapRect(clipRect())))
22839 {
22840 painter->setTransform(transform);
22841 if ((mainBrush().style() != Qt::NoBrush && mainBrush().color().alpha() != 0) ||
22842 (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0))
22843 {
22844 painter->setPen(mainPen());
22845 painter->setBrush(mainBrush());
22846 painter->drawRect(textBoxRect);
22847 }
22848 painter->setBrush(Qt::NoBrush);
22849 painter->setPen(QPen(mainColor()));
22850 painter->drawText(textRect, Qt::TextDontClip|mTextAlignment, mText);
22326 QPointF pos(position->pixelPoint());
22327 QTransform transform = painter->transform();
22328 transform.translate(pos.x(), pos.y());
22329 if (!qFuzzyIsNull(mRotation))
22330 transform.rotate(mRotation);
22331 painter->setFont(mainFont());
22332 QRect textRect = painter->fontMetrics().boundingRect(0, 0, 0, 0, Qt::TextDontClip|mTextAlignment, mText);
22333 QRect textBoxRect = textRect.adjusted(-mPadding.left(), -mPadding.top(), mPadding.right(), mPadding.bottom());
22334 QPointF textPos = getTextDrawPoint(QPointF(0, 0), textBoxRect, mPositionAlignment); // 0, 0 because the transform does the translation
22335 textRect.moveTopLeft(textPos.toPoint()+QPoint(mPadding.left(), mPadding.top()));
22336 textBoxRect.moveTopLeft(textPos.toPoint());
22337 double clipPad = mainPen().widthF();
22338 QRect boundingRect = textBoxRect.adjusted(-clipPad, -clipPad, clipPad, clipPad);
22339 if (transform.mapRect(boundingRect).intersects(painter->transform().mapRect(clipRect())))
22340 {
22341 painter->setTransform(transform);
22342 if ((mainBrush().style() != Qt::NoBrush && mainBrush().color().alpha() != 0) ||
22343 (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0))
22344 {
22345 painter->setPen(mainPen());
22346 painter->setBrush(mainBrush());
22347 painter->drawRect(textBoxRect);
22348 }
22349 painter->setBrush(Qt::NoBrush);
22350 painter->setPen(QPen(mainColor()));
22351 painter->drawText(textRect, Qt::TextDontClip|mTextAlignment, mText);
22851 22352 }
22852 22353 }
22853 22354
22854 22355 /* inherits documentation from base class */
22855 22356 QPointF QCPItemText::anchorPixelPoint(int anchorId) const
22856 22357 {
22857 // get actual rect points (pretty much copied from draw function):
22858 QPointF pos(position->pixelPoint());
22859 QTransform transform;
22860 transform.translate(pos.x(), pos.y());
22861 if (!qFuzzyIsNull(mRotation))
22862 transform.rotate(mRotation);
22863 QFontMetrics fontMetrics(mainFont());
22864 QRect textRect = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip|mTextAlignment, mText);
22865 QRectF textBoxRect = textRect.adjusted(-mPadding.left(), -mPadding.top(), mPadding.right(), mPadding.bottom());
22866 QPointF textPos = getTextDrawPoint(QPointF(0, 0), textBoxRect, mPositionAlignment); // 0, 0 because the transform does the translation
22867 textBoxRect.moveTopLeft(textPos.toPoint());
22868 QPolygonF rectPoly = transform.map(QPolygonF(textBoxRect));
22869
22870 switch (anchorId)
22358 // get actual rect points (pretty much copied from draw function):
22359 QPointF pos(position->pixelPoint());
22360 QTransform transform;
22361 transform.translate(pos.x(), pos.y());
22362 if (!qFuzzyIsNull(mRotation))
22363 transform.rotate(mRotation);
22364 QFontMetrics fontMetrics(mainFont());
22365 QRect textRect = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip|mTextAlignment, mText);
22366 QRectF textBoxRect = textRect.adjusted(-mPadding.left(), -mPadding.top(), mPadding.right(), mPadding.bottom());
22367 QPointF textPos = getTextDrawPoint(QPointF(0, 0), textBoxRect, mPositionAlignment); // 0, 0 because the transform does the translation
22368 textBoxRect.moveTopLeft(textPos.toPoint());
22369 QPolygonF rectPoly = transform.map(QPolygonF(textBoxRect));
22370
22371 switch (anchorId)
22871 22372 {
22872 22373 case aiTopLeft: return rectPoly.at(0);
22873 22374 case aiTop: return (rectPoly.at(0)+rectPoly.at(1))*0.5;
@@ -22878,9 +22379,9 QPointF QCPItemText::anchorPixelPoint(in
22878 22379 case aiBottomLeft: return rectPoly.at(3);
22879 22380 case aiLeft: return (rectPoly.at(3)+rectPoly.at(0))*0.5;
22880 22381 }
22881
22882 qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId;
22883 return QPointF();
22382
22383 qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId;
22384 return QPointF();
22884 22385 }
22885 22386
22886 22387 /*! \internal
@@ -22895,19 +22396,19 QPointF QCPItemText::anchorPixelPoint(in
22895 22396 */
22896 22397 QPointF QCPItemText::getTextDrawPoint(const QPointF &pos, const QRectF &rect, Qt::Alignment positionAlignment) const
22897 22398 {
22898 if (positionAlignment == 0 || positionAlignment == (Qt::AlignLeft|Qt::AlignTop))
22899 return pos;
22900
22901 QPointF result = pos; // start at top left
22902 if (positionAlignment.testFlag(Qt::AlignHCenter))
22903 result.rx() -= rect.width()/2.0;
22904 else if (positionAlignment.testFlag(Qt::AlignRight))
22905 result.rx() -= rect.width();
22906 if (positionAlignment.testFlag(Qt::AlignVCenter))
22907 result.ry() -= rect.height()/2.0;
22908 else if (positionAlignment.testFlag(Qt::AlignBottom))
22909 result.ry() -= rect.height();
22910 return result;
22399 if (positionAlignment == 0 || positionAlignment == (Qt::AlignLeft|Qt::AlignTop))
22400 return pos;
22401
22402 QPointF result = pos; // start at top left
22403 if (positionAlignment.testFlag(Qt::AlignHCenter))
22404 result.rx() -= rect.width()/2.0;
22405 else if (positionAlignment.testFlag(Qt::AlignRight))
22406 result.rx() -= rect.width();
22407 if (positionAlignment.testFlag(Qt::AlignVCenter))
22408 result.ry() -= rect.height()/2.0;
22409 else if (positionAlignment.testFlag(Qt::AlignBottom))
22410 result.ry() -= rect.height();
22411 return result;
22911 22412 }
22912 22413
22913 22414 /*! \internal
@@ -22917,7 +22418,7 QPointF QCPItemText::getTextDrawPoint(co
22917 22418 */
22918 22419 QFont QCPItemText::mainFont() const
22919 22420 {
22920 return mSelected ? mSelectedFont : mFont;
22421 return mSelected ? mSelectedFont : mFont;
22921 22422 }
22922 22423
22923 22424 /*! \internal
@@ -22927,7 +22428,7 QFont QCPItemText::mainFont() const
22927 22428 */
22928 22429 QColor QCPItemText::mainColor() const
22929 22430 {
22930 return mSelected ? mSelectedColor : mColor;
22431 return mSelected ? mSelectedColor : mColor;
22931 22432 }
22932 22433
22933 22434 /*! \internal
@@ -22937,7 +22438,7 QColor QCPItemText::mainColor() const
22937 22438 */
22938 22439 QPen QCPItemText::mainPen() const
22939 22440 {
22940 return mSelected ? mSelectedPen : mPen;
22441 return mSelected ? mSelectedPen : mPen;
22941 22442 }
22942 22443
22943 22444 /*! \internal
@@ -22947,7 +22448,7 QPen QCPItemText::mainPen() const
22947 22448 */
22948 22449 QBrush QCPItemText::mainBrush() const
22949 22450 {
22950 return mSelected ? mSelectedBrush : mBrush;
22451 return mSelected ? mSelectedBrush : mBrush;
22951 22452 }
22952 22453
22953 22454
@@ -22969,26 +22470,26 QBrush QCPItemText::mainBrush() const
22969 22470 The constructed item can be added to the plot with QCustomPlot::addItem.
22970 22471 */
22971 22472 QCPItemEllipse::QCPItemEllipse(QCustomPlot *parentPlot) :
22972 QCPAbstractItem(parentPlot),
22973 topLeft(createPosition(QLatin1String("topLeft"))),
22974 bottomRight(createPosition(QLatin1String("bottomRight"))),
22975 topLeftRim(createAnchor(QLatin1String("topLeftRim"), aiTopLeftRim)),
22976 top(createAnchor(QLatin1String("top"), aiTop)),
22977 topRightRim(createAnchor(QLatin1String("topRightRim"), aiTopRightRim)),
22978 right(createAnchor(QLatin1String("right"), aiRight)),
22979 bottomRightRim(createAnchor(QLatin1String("bottomRightRim"), aiBottomRightRim)),
22980 bottom(createAnchor(QLatin1String("bottom"), aiBottom)),
22981 bottomLeftRim(createAnchor(QLatin1String("bottomLeftRim"), aiBottomLeftRim)),
22982 left(createAnchor(QLatin1String("left"), aiLeft)),
22983 center(createAnchor(QLatin1String("center"), aiCenter))
22984 {
22985 topLeft->setCoords(0, 1);
22986 bottomRight->setCoords(1, 0);
22987
22988 setPen(QPen(Qt::black));
22989 setSelectedPen(QPen(Qt::blue, 2));
22990 setBrush(Qt::NoBrush);
22991 setSelectedBrush(Qt::NoBrush);
22473 QCPAbstractItem(parentPlot),
22474 topLeft(createPosition(QLatin1String("topLeft"))),
22475 bottomRight(createPosition(QLatin1String("bottomRight"))),
22476 topLeftRim(createAnchor(QLatin1String("topLeftRim"), aiTopLeftRim)),
22477 top(createAnchor(QLatin1String("top"), aiTop)),
22478 topRightRim(createAnchor(QLatin1String("topRightRim"), aiTopRightRim)),
22479 right(createAnchor(QLatin1String("right"), aiRight)),
22480 bottomRightRim(createAnchor(QLatin1String("bottomRightRim"), aiBottomRightRim)),
22481 bottom(createAnchor(QLatin1String("bottom"), aiBottom)),
22482 bottomLeftRim(createAnchor(QLatin1String("bottomLeftRim"), aiBottomLeftRim)),
22483 left(createAnchor(QLatin1String("left"), aiLeft)),
22484 center(createAnchor(QLatin1String("center"), aiCenter))
22485 {
22486 topLeft->setCoords(0, 1);
22487 bottomRight->setCoords(1, 0);
22488
22489 setPen(QPen(Qt::black));
22490 setSelectedPen(QPen(Qt::blue, 2));
22491 setBrush(Qt::NoBrush);
22492 setSelectedBrush(Qt::NoBrush);
22992 22493 }
22993 22494
22994 22495 QCPItemEllipse::~QCPItemEllipse()
@@ -23002,7 +22503,7 QCPItemEllipse::~QCPItemEllipse()
23002 22503 */
23003 22504 void QCPItemEllipse::setPen(const QPen &pen)
23004 22505 {
23005 mPen = pen;
22506 mPen = pen;
23006 22507 }
23007 22508
23008 22509 /*!
@@ -23012,7 +22513,7 void QCPItemEllipse::setPen(const QPen &
23012 22513 */
23013 22514 void QCPItemEllipse::setSelectedPen(const QPen &pen)
23014 22515 {
23015 mSelectedPen = pen;
22516 mSelectedPen = pen;
23016 22517 }
23017 22518
23018 22519 /*!
@@ -23023,7 +22524,7 void QCPItemEllipse::setSelectedPen(cons
23023 22524 */
23024 22525 void QCPItemEllipse::setBrush(const QBrush &brush)
23025 22526 {
23026 mBrush = brush;
22527 mBrush = brush;
23027 22528 }
23028 22529
23029 22530 /*!
@@ -23034,61 +22535,61 void QCPItemEllipse::setBrush(const QBru
23034 22535 */
23035 22536 void QCPItemEllipse::setSelectedBrush(const QBrush &brush)
23036 22537 {
23037 mSelectedBrush = brush;
22538 mSelectedBrush = brush;
23038 22539 }
23039 22540
23040 22541 /* inherits documentation from base class */
23041 22542 double QCPItemEllipse::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
23042 22543 {
23043 Q_UNUSED(details)
23044 if (onlySelectable && !mSelectable)
23045 return -1;
23046
23047 double result = -1;
23048 QPointF p1 = topLeft->pixelPoint();
23049 QPointF p2 = bottomRight->pixelPoint();
23050 QPointF center((p1+p2)/2.0);
23051 double a = qAbs(p1.x()-p2.x())/2.0;
23052 double b = qAbs(p1.y()-p2.y())/2.0;
23053 double x = pos.x()-center.x();
23054 double y = pos.y()-center.y();
23055
23056 // distance to border:
23057 double c = 1.0/qSqrt(x*x/(a*a)+y*y/(b*b));
23058 result = qAbs(c-1)*qSqrt(x*x+y*y);
23059 // filled ellipse, allow click inside to count as hit:
23060 if (result > mParentPlot->selectionTolerance()*0.99 && mBrush.style() != Qt::NoBrush && mBrush.color().alpha() != 0)
23061 {
23062 if (x*x/(a*a) + y*y/(b*b) <= 1)
23063 result = mParentPlot->selectionTolerance()*0.99;
23064 }
23065 return result;
22544 Q_UNUSED(details)
22545 if (onlySelectable && !mSelectable)
22546 return -1;
22547
22548 double result = -1;
22549 QPointF p1 = topLeft->pixelPoint();
22550 QPointF p2 = bottomRight->pixelPoint();
22551 QPointF center((p1+p2)/2.0);
22552 double a = qAbs(p1.x()-p2.x())/2.0;
22553 double b = qAbs(p1.y()-p2.y())/2.0;
22554 double x = pos.x()-center.x();
22555 double y = pos.y()-center.y();
22556
22557 // distance to border:
22558 double c = 1.0/qSqrt(x*x/(a*a)+y*y/(b*b));
22559 result = qAbs(c-1)*qSqrt(x*x+y*y);
22560 // filled ellipse, allow click inside to count as hit:
22561 if (result > mParentPlot->selectionTolerance()*0.99 && mBrush.style() != Qt::NoBrush && mBrush.color().alpha() != 0)
22562 {
22563 if (x*x/(a*a) + y*y/(b*b) <= 1)
22564 result = mParentPlot->selectionTolerance()*0.99;
22565 }
22566 return result;
23066 22567 }
23067 22568
23068 22569 /* inherits documentation from base class */
23069 22570 void QCPItemEllipse::draw(QCPPainter *painter)
23070 22571 {
23071 QPointF p1 = topLeft->pixelPoint();
23072 QPointF p2 = bottomRight->pixelPoint();
23073 if (p1.toPoint() == p2.toPoint())
23074 return;
23075 QRectF ellipseRect = QRectF(p1, p2).normalized();
23076 QRect clip = clipRect().adjusted(-mainPen().widthF(), -mainPen().widthF(), mainPen().widthF(), mainPen().widthF());
23077 if (ellipseRect.intersects(clip)) // only draw if bounding rect of ellipse is visible in cliprect
23078 {
23079 painter->setPen(mainPen());
23080 painter->setBrush(mainBrush());
22572 QPointF p1 = topLeft->pixelPoint();
22573 QPointF p2 = bottomRight->pixelPoint();
22574 if (p1.toPoint() == p2.toPoint())
22575 return;
22576 QRectF ellipseRect = QRectF(p1, p2).normalized();
22577 QRect clip = clipRect().adjusted(-mainPen().widthF(), -mainPen().widthF(), mainPen().widthF(), mainPen().widthF());
22578 if (ellipseRect.intersects(clip)) // only draw if bounding rect of ellipse is visible in cliprect
22579 {
22580 painter->setPen(mainPen());
22581 painter->setBrush(mainBrush());
23081 22582 #ifdef __EXCEPTIONS
23082 try // drawEllipse sometimes throws exceptions if ellipse is too big
23083 {
22583 try // drawEllipse sometimes throws exceptions if ellipse is too big
22584 {
23084 22585 #endif
23085 painter->drawEllipse(ellipseRect);
22586 painter->drawEllipse(ellipseRect);
23086 22587 #ifdef __EXCEPTIONS
23087 } catch (...)
23088 {
23089 qDebug() << Q_FUNC_INFO << "Item too large for memory, setting invisible";
23090 setVisible(false);
23091 }
22588 } catch (...)
22589 {
22590 qDebug() << Q_FUNC_INFO << "Item too large for memory, setting invisible";
22591 setVisible(false);
22592 }
23092 22593 #endif
23093 22594 }
23094 22595 }
@@ -23096,8 +22597,8 void QCPItemEllipse::draw(QCPPainter *pa
23096 22597 /* inherits documentation from base class */
23097 22598 QPointF QCPItemEllipse::anchorPixelPoint(int anchorId) const
23098 22599 {
23099 QRectF rect = QRectF(topLeft->pixelPoint(), bottomRight->pixelPoint());
23100 switch (anchorId)
22600 QRectF rect = QRectF(topLeft->pixelPoint(), bottomRight->pixelPoint());
22601 switch (anchorId)
23101 22602 {
23102 22603 case aiTopLeftRim: return rect.center()+(rect.topLeft()-rect.center())*1/qSqrt(2);
23103 22604 case aiTop: return (rect.topLeft()+rect.topRight())*0.5;
@@ -23109,9 +22610,9 QPointF QCPItemEllipse::anchorPixelPoint
23109 22610 case aiLeft: return (rect.topLeft()+rect.bottomLeft())*0.5;
23110 22611 case aiCenter: return (rect.topLeft()+rect.bottomRight())*0.5;
23111 22612 }
23112
23113 qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId;
23114 return QPointF();
22613
22614 qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId;
22615 return QPointF();
23115 22616 }
23116 22617
23117 22618 /*! \internal
@@ -23121,7 +22622,7 QPointF QCPItemEllipse::anchorPixelPoint
23121 22622 */
23122 22623 QPen QCPItemEllipse::mainPen() const
23123 22624 {
23124 return mSelected ? mSelectedPen : mPen;
22625 return mSelected ? mSelectedPen : mPen;
23125 22626 }
23126 22627
23127 22628 /*! \internal
@@ -23131,7 +22632,7 QPen QCPItemEllipse::mainPen() const
23131 22632 */
23132 22633 QBrush QCPItemEllipse::mainBrush() const
23133 22634 {
23134 return mSelected ? mSelectedBrush : mBrush;
22635 return mSelected ? mSelectedBrush : mBrush;
23135 22636 }
23136 22637
23137 22638
@@ -23159,22 +22660,22 QBrush QCPItemEllipse::mainBrush() const
23159 22660 The constructed item can be added to the plot with QCustomPlot::addItem.
23160 22661 */
23161 22662 QCPItemPixmap::QCPItemPixmap(QCustomPlot *parentPlot) :
23162 QCPAbstractItem(parentPlot),
23163 topLeft(createPosition(QLatin1String("topLeft"))),
23164 bottomRight(createPosition(QLatin1String("bottomRight"))),
23165 top(createAnchor(QLatin1String("top"), aiTop)),
23166 topRight(createAnchor(QLatin1String("topRight"), aiTopRight)),
23167 right(createAnchor(QLatin1String("right"), aiRight)),
23168 bottom(createAnchor(QLatin1String("bottom"), aiBottom)),
23169 bottomLeft(createAnchor(QLatin1String("bottomLeft"), aiBottomLeft)),
23170 left(createAnchor(QLatin1String("left"), aiLeft))
23171 {
23172 topLeft->setCoords(0, 1);
23173 bottomRight->setCoords(1, 0);
23174
23175 setPen(Qt::NoPen);
23176 setSelectedPen(QPen(Qt::blue));
23177 setScaled(false, Qt::KeepAspectRatio, Qt::SmoothTransformation);
22663 QCPAbstractItem(parentPlot),
22664 topLeft(createPosition(QLatin1String("topLeft"))),
22665 bottomRight(createPosition(QLatin1String("bottomRight"))),
22666 top(createAnchor(QLatin1String("top"), aiTop)),
22667 topRight(createAnchor(QLatin1String("topRight"), aiTopRight)),
22668 right(createAnchor(QLatin1String("right"), aiRight)),
22669 bottom(createAnchor(QLatin1String("bottom"), aiBottom)),
22670 bottomLeft(createAnchor(QLatin1String("bottomLeft"), aiBottomLeft)),
22671 left(createAnchor(QLatin1String("left"), aiLeft))
22672 {
22673 topLeft->setCoords(0, 1);
22674 bottomRight->setCoords(1, 0);
22675
22676 setPen(Qt::NoPen);
22677 setSelectedPen(QPen(Qt::blue));
22678 setScaled(false, Qt::KeepAspectRatio, Qt::SmoothTransformation);
23178 22679 }
23179 22680
23180 22681 QCPItemPixmap::~QCPItemPixmap()
@@ -23186,9 +22687,9 QCPItemPixmap::~QCPItemPixmap()
23186 22687 */
23187 22688 void QCPItemPixmap::setPixmap(const QPixmap &pixmap)
23188 22689 {
23189 mPixmap = pixmap;
23190 if (mPixmap.isNull())
23191 qDebug() << Q_FUNC_INFO << "pixmap is null";
22690 mPixmap = pixmap;
22691 if (mPixmap.isNull())
22692 qDebug() << Q_FUNC_INFO << "pixmap is null";
23192 22693 }
23193 22694
23194 22695 /*!
@@ -23197,10 +22698,10 void QCPItemPixmap::setPixmap(const QPix
23197 22698 */
23198 22699 void QCPItemPixmap::setScaled(bool scaled, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformationMode)
23199 22700 {
23200 mScaled = scaled;
23201 mAspectRatioMode = aspectRatioMode;
23202 mTransformationMode = transformationMode;
23203 updateScaledPixmap();
22701 mScaled = scaled;
22702 mAspectRatioMode = aspectRatioMode;
22703 mTransformationMode = transformationMode;
22704 updateScaledPixmap();
23204 22705 }
23205 22706
23206 22707 /*!
@@ -23210,7 +22711,7 void QCPItemPixmap::setScaled(bool scale
23210 22711 */
23211 22712 void QCPItemPixmap::setPen(const QPen &pen)
23212 22713 {
23213 mPen = pen;
22714 mPen = pen;
23214 22715 }
23215 22716
23216 22717 /*!
@@ -23220,37 +22721,37 void QCPItemPixmap::setPen(const QPen &p
23220 22721 */
23221 22722 void QCPItemPixmap::setSelectedPen(const QPen &pen)
23222 22723 {
23223 mSelectedPen = pen;
22724 mSelectedPen = pen;
23224 22725 }
23225 22726
23226 22727 /* inherits documentation from base class */
23227 22728 double QCPItemPixmap::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
23228 22729 {
23229 Q_UNUSED(details)
23230 if (onlySelectable && !mSelectable)
23231 return -1;
23232
23233 return rectSelectTest(getFinalRect(), pos, true);
22730 Q_UNUSED(details)
22731 if (onlySelectable && !mSelectable)
22732 return -1;
22733
22734 return rectSelectTest(getFinalRect(), pos, true);
23234 22735 }
23235 22736
23236 22737 /* inherits documentation from base class */
23237 22738 void QCPItemPixmap::draw(QCPPainter *painter)
23238 22739 {
23239 bool flipHorz = false;
23240 bool flipVert = false;
23241 QRect rect = getFinalRect(&flipHorz, &flipVert);
23242 double clipPad = mainPen().style() == Qt::NoPen ? 0 : mainPen().widthF();
23243 QRect boundingRect = rect.adjusted(-clipPad, -clipPad, clipPad, clipPad);
23244 if (boundingRect.intersects(clipRect()))
23245 {
23246 updateScaledPixmap(rect, flipHorz, flipVert);
23247 painter->drawPixmap(rect.topLeft(), mScaled ? mScaledPixmap : mPixmap);
23248 QPen pen = mainPen();
23249 if (pen.style() != Qt::NoPen)
23250 {
23251 painter->setPen(pen);
23252 painter->setBrush(Qt::NoBrush);
23253 painter->drawRect(rect);
22740 bool flipHorz = false;
22741 bool flipVert = false;
22742 QRect rect = getFinalRect(&flipHorz, &flipVert);
22743 double clipPad = mainPen().style() == Qt::NoPen ? 0 : mainPen().widthF();
22744 QRect boundingRect = rect.adjusted(-clipPad, -clipPad, clipPad, clipPad);
22745 if (boundingRect.intersects(clipRect()))
22746 {
22747 updateScaledPixmap(rect, flipHorz, flipVert);
22748 painter->drawPixmap(rect.topLeft(), mScaled ? mScaledPixmap : mPixmap);
22749 QPen pen = mainPen();
22750 if (pen.style() != Qt::NoPen)
22751 {
22752 painter->setPen(pen);
22753 painter->setBrush(Qt::NoBrush);
22754 painter->drawRect(rect);
23254 22755 }
23255 22756 }
23256 22757 }
@@ -23258,17 +22759,17 void QCPItemPixmap::draw(QCPPainter *pai
23258 22759 /* inherits documentation from base class */
23259 22760 QPointF QCPItemPixmap::anchorPixelPoint(int anchorId) const
23260 22761 {
23261 bool flipHorz;
23262 bool flipVert;
23263 QRect rect = getFinalRect(&flipHorz, &flipVert);
23264 // we actually want denormal rects (negative width/height) here, so restore
23265 // the flipped state:
23266 if (flipHorz)
23267 rect.adjust(rect.width(), 0, -rect.width(), 0);
23268 if (flipVert)
23269 rect.adjust(0, rect.height(), 0, -rect.height());
23270
23271 switch (anchorId)
22762 bool flipHorz;
22763 bool flipVert;
22764 QRect rect = getFinalRect(&flipHorz, &flipVert);
22765 // we actually want denormal rects (negative width/height) here, so restore
22766 // the flipped state:
22767 if (flipHorz)
22768 rect.adjust(rect.width(), 0, -rect.width(), 0);
22769 if (flipVert)
22770 rect.adjust(0, rect.height(), 0, -rect.height());
22771
22772 switch (anchorId)
23272 22773 {
23273 22774 case aiTop: return (rect.topLeft()+rect.topRight())*0.5;
23274 22775 case aiTopRight: return rect.topRight();
@@ -23277,9 +22778,9 QPointF QCPItemPixmap::anchorPixelPoint(
23277 22778 case aiBottomLeft: return rect.bottomLeft();
23278 22779 case aiLeft: return (rect.topLeft()+rect.bottomLeft())*0.5;;
23279 22780 }
23280
23281 qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId;
23282 return QPointF();
22781
22782 qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId;
22783 return QPointF();
23283 22784 }
23284 22785
23285 22786 /*! \internal
@@ -23297,21 +22798,21 QPointF QCPItemPixmap::anchorPixelPoint(
23297 22798 */
23298 22799 void QCPItemPixmap::updateScaledPixmap(QRect finalRect, bool flipHorz, bool flipVert)
23299 22800 {
23300 if (mPixmap.isNull())
23301 return;
23302
23303 if (mScaled)
23304 {
23305 if (finalRect.isNull())
23306 finalRect = getFinalRect(&flipHorz, &flipVert);
23307 if (finalRect.size() != mScaledPixmap.size())
23308 {
23309 mScaledPixmap = mPixmap.scaled(finalRect.size(), mAspectRatioMode, mTransformationMode);
23310 if (flipHorz || flipVert)
23311 mScaledPixmap = QPixmap::fromImage(mScaledPixmap.toImage().mirrored(flipHorz, flipVert));
22801 if (mPixmap.isNull())
22802 return;
22803
22804 if (mScaled)
22805 {
22806 if (finalRect.isNull())
22807 finalRect = getFinalRect(&flipHorz, &flipVert);
22808 if (finalRect.size() != mScaledPixmap.size())
22809 {
22810 mScaledPixmap = mPixmap.scaled(finalRect.size(), mAspectRatioMode, mTransformationMode);
22811 if (flipHorz || flipVert)
22812 mScaledPixmap = QPixmap::fromImage(mScaledPixmap.toImage().mirrored(flipHorz, flipVert));
23312 22813 }
23313 22814 } else if (!mScaledPixmap.isNull())
23314 mScaledPixmap = QPixmap();
22815 mScaledPixmap = QPixmap();
23315 22816 }
23316 22817
23317 22818 /*! \internal
@@ -23330,41 +22831,41 void QCPItemPixmap::updateScaledPixmap(Q
23330 22831 */
23331 22832 QRect QCPItemPixmap::getFinalRect(bool *flippedHorz, bool *flippedVert) const
23332 22833 {
23333 QRect result;
23334 bool flipHorz = false;
23335 bool flipVert = false;
23336 QPoint p1 = topLeft->pixelPoint().toPoint();
23337 QPoint p2 = bottomRight->pixelPoint().toPoint();
23338 if (p1 == p2)
23339 return QRect(p1, QSize(0, 0));
23340 if (mScaled)
23341 {
23342 QSize newSize = QSize(p2.x()-p1.x(), p2.y()-p1.y());
23343 QPoint topLeft = p1;
23344 if (newSize.width() < 0)
23345 {
23346 flipHorz = true;
23347 newSize.rwidth() *= -1;
23348 topLeft.setX(p2.x());
23349 }
23350 if (newSize.height() < 0)
23351 {
23352 flipVert = true;
23353 newSize.rheight() *= -1;
23354 topLeft.setY(p2.y());
23355 }
23356 QSize scaledSize = mPixmap.size();
23357 scaledSize.scale(newSize, mAspectRatioMode);
23358 result = QRect(topLeft, scaledSize);
23359 } else
23360 {
23361 result = QRect(p1, mPixmap.size());
23362 }
23363 if (flippedHorz)
23364 *flippedHorz = flipHorz;
23365 if (flippedVert)
23366 *flippedVert = flipVert;
23367 return result;
22834 QRect result;
22835 bool flipHorz = false;
22836 bool flipVert = false;
22837 QPoint p1 = topLeft->pixelPoint().toPoint();
22838 QPoint p2 = bottomRight->pixelPoint().toPoint();
22839 if (p1 == p2)
22840 return QRect(p1, QSize(0, 0));
22841 if (mScaled)
22842 {
22843 QSize newSize = QSize(p2.x()-p1.x(), p2.y()-p1.y());
22844 QPoint topLeft = p1;
22845 if (newSize.width() < 0)
22846 {
22847 flipHorz = true;
22848 newSize.rwidth() *= -1;
22849 topLeft.setX(p2.x());
22850 }
22851 if (newSize.height() < 0)
22852 {
22853 flipVert = true;
22854 newSize.rheight() *= -1;
22855 topLeft.setY(p2.y());
22856 }
22857 QSize scaledSize = mPixmap.size();
22858 scaledSize.scale(newSize, mAspectRatioMode);
22859 result = QRect(topLeft, scaledSize);
22860 } else
22861 {
22862 result = QRect(p1, mPixmap.size());
22863 }
22864 if (flippedHorz)
22865 *flippedHorz = flipHorz;
22866 if (flippedVert)
22867 *flippedVert = flipVert;
22868 return result;
23368 22869 }
23369 22870
23370 22871 /*! \internal
@@ -23374,7 +22875,7 QRect QCPItemPixmap::getFinalRect(bool *
23374 22875 */
23375 22876 QPen QCPItemPixmap::mainPen() const
23376 22877 {
23377 return mSelected ? mSelectedPen : mPen;
22878 return mSelected ? mSelectedPen : mPen;
23378 22879 }
23379 22880
23380 22881
@@ -23418,20 +22919,20 QPen QCPItemPixmap::mainPen() const
23418 22919 The constructed item can be added to the plot with QCustomPlot::addItem.
23419 22920 */
23420 22921 QCPItemTracer::QCPItemTracer(QCustomPlot *parentPlot) :
23421 QCPAbstractItem(parentPlot),
23422 position(createPosition(QLatin1String("position"))),
23423 mGraph(0)
23424 {
23425 position->setCoords(0, 0);
23426
23427 setBrush(Qt::NoBrush);
23428 setSelectedBrush(Qt::NoBrush);
23429 setPen(QPen(Qt::black));
23430 setSelectedPen(QPen(Qt::blue, 2));
23431 setStyle(tsCrosshair);
23432 setSize(6);
23433 setInterpolating(false);
23434 setGraphKey(0);
22922 QCPAbstractItem(parentPlot),
22923 position(createPosition(QLatin1String("position"))),
22924 mGraph(0)
22925 {
22926 position->setCoords(0, 0);
22927
22928 setBrush(Qt::NoBrush);
22929 setSelectedBrush(Qt::NoBrush);
22930 setPen(QPen(Qt::black));
22931 setSelectedPen(QPen(Qt::blue, 2));
22932 setStyle(tsCrosshair);
22933 setSize(6);
22934 setInterpolating(false);
22935 setGraphKey(0);
23435 22936 }
23436 22937
23437 22938 QCPItemTracer::~QCPItemTracer()
@@ -23445,7 +22946,7 QCPItemTracer::~QCPItemTracer()
23445 22946 */
23446 22947 void QCPItemTracer::setPen(const QPen &pen)
23447 22948 {
23448 mPen = pen;
22949 mPen = pen;
23449 22950 }
23450 22951
23451 22952 /*!
@@ -23455,7 +22956,7 void QCPItemTracer::setPen(const QPen &p
23455 22956 */
23456 22957 void QCPItemTracer::setSelectedPen(const QPen &pen)
23457 22958 {
23458 mSelectedPen = pen;
22959 mSelectedPen = pen;
23459 22960 }
23460 22961
23461 22962 /*!
@@ -23465,7 +22966,7 void QCPItemTracer::setSelectedPen(const
23465 22966 */
23466 22967 void QCPItemTracer::setBrush(const QBrush &brush)
23467 22968 {
23468 mBrush = brush;
22969 mBrush = brush;
23469 22970 }
23470 22971
23471 22972 /*!
@@ -23475,7 +22976,7 void QCPItemTracer::setBrush(const QBrus
23475 22976 */
23476 22977 void QCPItemTracer::setSelectedBrush(const QBrush &brush)
23477 22978 {
23478 mSelectedBrush = brush;
22979 mSelectedBrush = brush;
23479 22980 }
23480 22981
23481 22982 /*!
@@ -23484,7 +22985,7 void QCPItemTracer::setSelectedBrush(con
23484 22985 */
23485 22986 void QCPItemTracer::setSize(double size)
23486 22987 {
23487 mSize = size;
22988 mSize = size;
23488 22989 }
23489 22990
23490 22991 /*!
@@ -23495,7 +22996,7 void QCPItemTracer::setSize(double size)
23495 22996 */
23496 22997 void QCPItemTracer::setStyle(QCPItemTracer::TracerStyle style)
23497 22998 {
23498 mStyle = style;
22999 mStyle = style;
23499 23000 }
23500 23001
23501 23002 /*!
@@ -23510,19 +23011,19 void QCPItemTracer::setStyle(QCPItemTrac
23510 23011 */
23511 23012 void QCPItemTracer::setGraph(QCPGraph *graph)
23512 23013 {
23513 if (graph)
23514 {
23515 if (graph->parentPlot() == mParentPlot)
23516 {
23517 position->setType(QCPItemPosition::ptPlotCoords);
23518 position->setAxes(graph->keyAxis(), graph->valueAxis());
23519 mGraph = graph;
23520 updatePosition();
23014 if (graph)
23015 {
23016 if (graph->parentPlot() == mParentPlot)
23017 {
23018 position->setType(QCPItemPosition::ptPlotCoords);
23019 position->setAxes(graph->keyAxis(), graph->valueAxis());
23020 mGraph = graph;
23021 updatePosition();
23521 23022 } else
23522 qDebug() << Q_FUNC_INFO << "graph isn't in same QCustomPlot instance as this item";
23523 } else
23524 {
23525 mGraph = 0;
23023 qDebug() << Q_FUNC_INFO << "graph isn't in same QCustomPlot instance as this item";
23024 } else
23025 {
23026 mGraph = 0;
23526 23027 }
23527 23028 }
23528 23029
@@ -23537,7 +23038,7 void QCPItemTracer::setGraph(QCPGraph *g
23537 23038 */
23538 23039 void QCPItemTracer::setGraphKey(double key)
23539 23040 {
23540 mGraphKey = key;
23041 mGraphKey = key;
23541 23042 }
23542 23043
23543 23044 /*!
@@ -23553,110 +23054,110 void QCPItemTracer::setGraphKey(double k
23553 23054 */
23554 23055 void QCPItemTracer::setInterpolating(bool enabled)
23555 23056 {
23556 mInterpolating = enabled;
23057 mInterpolating = enabled;
23557 23058 }
23558 23059
23559 23060 /* inherits documentation from base class */
23560 23061 double QCPItemTracer::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
23561 23062 {
23562 Q_UNUSED(details)
23563 if (onlySelectable && !mSelectable)
23564 return -1;
23565
23566 QPointF center(position->pixelPoint());
23567 double w = mSize/2.0;
23568 QRect clip = clipRect();
23569 switch (mStyle)
23063 Q_UNUSED(details)
23064 if (onlySelectable && !mSelectable)
23065 return -1;
23066
23067 QPointF center(position->pixelPoint());
23068 double w = mSize/2.0;
23069 QRect clip = clipRect();
23070 switch (mStyle)
23570 23071 {
23571 23072 case tsNone: return -1;
23572 23073 case tsPlus:
23573 {
23074 {
23574 23075 if (clipRect().intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect()))
23575 return qSqrt(qMin(distSqrToLine(center+QPointF(-w, 0), center+QPointF(w, 0), pos),
23576 distSqrToLine(center+QPointF(0, -w), center+QPointF(0, w), pos)));
23577 break;
23578 }
23076 return qSqrt(qMin(distSqrToLine(center+QPointF(-w, 0), center+QPointF(w, 0), pos),
23077 distSqrToLine(center+QPointF(0, -w), center+QPointF(0, w), pos)));
23078 break;
23079 }
23579 23080 case tsCrosshair:
23580 {
23081 {
23581 23082 return qSqrt(qMin(distSqrToLine(QPointF(clip.left(), center.y()), QPointF(clip.right(), center.y()), pos),
23582 23083 distSqrToLine(QPointF(center.x(), clip.top()), QPointF(center.x(), clip.bottom()), pos)));
23583 }
23084 }
23584 23085 case tsCircle:
23585 {
23086 {
23586 23087 if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect()))
23587 {
23088 {
23588 23089 // distance to border:
23589 23090 double centerDist = QVector2D(center-pos).length();
23590 23091 double circleLine = w;
23591 23092 double result = qAbs(centerDist-circleLine);
23592 23093 // filled ellipse, allow click inside to count as hit:
23593 23094 if (result > mParentPlot->selectionTolerance()*0.99 && mBrush.style() != Qt::NoBrush && mBrush.color().alpha() != 0)
23594 {
23095 {
23595 23096 if (centerDist <= circleLine)
23596 result = mParentPlot->selectionTolerance()*0.99;
23597 }
23097 result = mParentPlot->selectionTolerance()*0.99;
23098 }
23598 23099 return result;
23599 }
23600 break;
23601 }
23100 }
23101 break;
23102 }
23602 23103 case tsSquare:
23603 {
23104 {
23604 23105 if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect()))
23605 {
23106 {
23606 23107 QRectF rect = QRectF(center-QPointF(w, w), center+QPointF(w, w));
23607 23108 bool filledRect = mBrush.style() != Qt::NoBrush && mBrush.color().alpha() != 0;
23608 23109 return rectSelectTest(rect, pos, filledRect);
23609 }
23610 break;
23611 }
23612 }
23613 return -1;
23110 }
23111 break;
23112 }
23113 }
23114 return -1;
23614 23115 }
23615 23116
23616 23117 /* inherits documentation from base class */
23617 23118 void QCPItemTracer::draw(QCPPainter *painter)
23618 23119 {
23619 updatePosition();
23620 if (mStyle == tsNone)
23621 return;
23622
23623 painter->setPen(mainPen());
23624 painter->setBrush(mainBrush());
23625 QPointF center(position->pixelPoint());
23626 double w = mSize/2.0;
23627 QRect clip = clipRect();
23628 switch (mStyle)
23120 updatePosition();
23121 if (mStyle == tsNone)
23122 return;
23123
23124 painter->setPen(mainPen());
23125 painter->setBrush(mainBrush());
23126 QPointF center(position->pixelPoint());
23127 double w = mSize/2.0;
23128 QRect clip = clipRect();
23129 switch (mStyle)
23629 23130 {
23630 23131 case tsNone: return;
23631 23132 case tsPlus:
23632 {
23133 {
23633 23134 if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect()))
23634 {
23135 {
23635 23136 painter->drawLine(QLineF(center+QPointF(-w, 0), center+QPointF(w, 0)));
23636 23137 painter->drawLine(QLineF(center+QPointF(0, -w), center+QPointF(0, w)));
23637 }
23638 break;
23639 }
23138 }
23139 break;
23140 }
23640 23141 case tsCrosshair:
23641 {
23142 {
23642 23143 if (center.y() > clip.top() && center.y() < clip.bottom())
23643 painter->drawLine(QLineF(clip.left(), center.y(), clip.right(), center.y()));
23144 painter->drawLine(QLineF(clip.left(), center.y(), clip.right(), center.y()));
23644 23145 if (center.x() > clip.left() && center.x() < clip.right())
23645 painter->drawLine(QLineF(center.x(), clip.top(), center.x(), clip.bottom()));
23646 break;
23647 }
23146 painter->drawLine(QLineF(center.x(), clip.top(), center.x(), clip.bottom()));
23147 break;
23148 }
23648 23149 case tsCircle:
23649 {
23150 {
23650 23151 if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect()))
23651 painter->drawEllipse(center, w, w);
23652 break;
23653 }
23152 painter->drawEllipse(center, w, w);
23153 break;
23154 }
23654 23155 case tsSquare:
23655 {
23156 {
23656 23157 if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect()))
23657 painter->drawRect(QRectF(center-QPointF(w, w), center+QPointF(w, w)));
23658 break;
23659 }
23158 painter->drawRect(QRectF(center-QPointF(w, w), center+QPointF(w, w)));
23159 break;
23160 }
23660 23161 }
23661 23162 }
23662 23163
@@ -23674,49 +23175,49 void QCPItemTracer::draw(QCPPainter *pai
23674 23175 */
23675 23176 void QCPItemTracer::updatePosition()
23676 23177 {
23677 if (mGraph)
23678 {
23679 if (mParentPlot->hasPlottable(mGraph))
23680 {
23681 if (mGraph->data()->size() > 1)
23682 {
23683 QCPDataMap::const_iterator first = mGraph->data()->constBegin();
23684 QCPDataMap::const_iterator last = mGraph->data()->constEnd()-1;
23685 if (mGraphKey < first.key())
23686 position->setCoords(first.key(), first.value().value);
23687 else if (mGraphKey > last.key())
23688 position->setCoords(last.key(), last.value().value);
23689 else
23178 if (mGraph)
23179 {
23180 if (mParentPlot->hasPlottable(mGraph))
23181 {
23182 if (mGraph->data()->size() > 1)
23183 {
23184 QCPDataMap::const_iterator first = mGraph->data()->constBegin();
23185 QCPDataMap::const_iterator last = mGraph->data()->constEnd()-1;
23186 if (mGraphKey < first.key())
23187 position->setCoords(first.key(), first.value().value);
23188 else if (mGraphKey > last.key())
23189 position->setCoords(last.key(), last.value().value);
23190 else
23690 23191 {
23691 QCPDataMap::const_iterator it = mGraph->data()->lowerBound(mGraphKey);
23692 if (it != first) // mGraphKey is somewhere between iterators
23192 QCPDataMap::const_iterator it = mGraph->data()->lowerBound(mGraphKey);
23193 if (it != first) // mGraphKey is somewhere between iterators
23693 23194 {
23694 QCPDataMap::const_iterator prevIt = it-1;
23695 if (mInterpolating)
23195 QCPDataMap::const_iterator prevIt = it-1;
23196 if (mInterpolating)
23696 23197 {
23697 // interpolate between iterators around mGraphKey:
23698 double slope = 0;
23699 if (!qFuzzyCompare((double)it.key(), (double)prevIt.key()))
23700 slope = (it.value().value-prevIt.value().value)/(it.key()-prevIt.key());
23701 position->setCoords(mGraphKey, (mGraphKey-prevIt.key())*slope+prevIt.value().value);
23198 // interpolate between iterators around mGraphKey:
23199 double slope = 0;
23200 if (!qFuzzyCompare((double)it.key(), (double)prevIt.key()))
23201 slope = (it.value().value-prevIt.value().value)/(it.key()-prevIt.key());
23202 position->setCoords(mGraphKey, (mGraphKey-prevIt.key())*slope+prevIt.value().value);
23702 23203 } else
23703 23204 {
23704 // find iterator with key closest to mGraphKey:
23705 if (mGraphKey < (prevIt.key()+it.key())*0.5)
23706 it = prevIt;
23707 position->setCoords(it.key(), it.value().value);
23205 // find iterator with key closest to mGraphKey:
23206 if (mGraphKey < (prevIt.key()+it.key())*0.5)
23207 it = prevIt;
23208 position->setCoords(it.key(), it.value().value);
23708 23209 }
23709 23210 } else // mGraphKey is exactly on first iterator
23710 position->setCoords(it.key(), it.value().value);
23211 position->setCoords(it.key(), it.value().value);
23711 23212 }
23712 23213 } else if (mGraph->data()->size() == 1)
23713 23214 {
23714 QCPDataMap::const_iterator it = mGraph->data()->constBegin();
23715 position->setCoords(it.key(), it.value().value);
23215 QCPDataMap::const_iterator it = mGraph->data()->constBegin();
23216 position->setCoords(it.key(), it.value().value);
23716 23217 } else
23717 qDebug() << Q_FUNC_INFO << "graph has no data";
23218 qDebug() << Q_FUNC_INFO << "graph has no data";
23718 23219 } else
23719 qDebug() << Q_FUNC_INFO << "graph not contained in QCustomPlot instance (anymore)";
23220 qDebug() << Q_FUNC_INFO << "graph not contained in QCustomPlot instance (anymore)";
23720 23221 }
23721 23222 }
23722 23223
@@ -23727,7 +23228,7 void QCPItemTracer::updatePosition()
23727 23228 */
23728 23229 QPen QCPItemTracer::mainPen() const
23729 23230 {
23730 return mSelected ? mSelectedPen : mPen;
23231 return mSelected ? mSelectedPen : mPen;
23731 23232 }
23732 23233
23733 23234 /*! \internal
@@ -23737,7 +23238,7 QPen QCPItemTracer::mainPen() const
23737 23238 */
23738 23239 QBrush QCPItemTracer::mainBrush() const
23739 23240 {
23740 return mSelected ? mSelectedBrush : mBrush;
23241 return mSelected ? mSelectedBrush : mBrush;
23741 23242 }
23742 23243
23743 23244
@@ -23771,18 +23272,18 QBrush QCPItemTracer::mainBrush() const
23771 23272 The constructed item can be added to the plot with QCustomPlot::addItem.
23772 23273 */
23773 23274 QCPItemBracket::QCPItemBracket(QCustomPlot *parentPlot) :
23774 QCPAbstractItem(parentPlot),
23775 left(createPosition(QLatin1String("left"))),
23776 right(createPosition(QLatin1String("right"))),
23777 center(createAnchor(QLatin1String("center"), aiCenter))
23778 {
23779 left->setCoords(0, 0);
23780 right->setCoords(1, 1);
23781
23782 setPen(QPen(Qt::black));
23783 setSelectedPen(QPen(Qt::blue, 2));
23784 setLength(8);
23785 setStyle(bsCalligraphic);
23275 QCPAbstractItem(parentPlot),
23276 left(createPosition(QLatin1String("left"))),
23277 right(createPosition(QLatin1String("right"))),
23278 center(createAnchor(QLatin1String("center"), aiCenter))
23279 {
23280 left->setCoords(0, 0);
23281 right->setCoords(1, 1);
23282
23283 setPen(QPen(Qt::black));
23284 setSelectedPen(QPen(Qt::blue, 2));
23285 setLength(8);
23286 setStyle(bsCalligraphic);
23786 23287 }
23787 23288
23788 23289 QCPItemBracket::~QCPItemBracket()
@@ -23800,7 +23301,7 QCPItemBracket::~QCPItemBracket()
23800 23301 */
23801 23302 void QCPItemBracket::setPen(const QPen &pen)
23802 23303 {
23803 mPen = pen;
23304 mPen = pen;
23804 23305 }
23805 23306
23806 23307 /*!
@@ -23810,7 +23311,7 void QCPItemBracket::setPen(const QPen &
23810 23311 */
23811 23312 void QCPItemBracket::setSelectedPen(const QPen &pen)
23812 23313 {
23813 mSelectedPen = pen;
23314 mSelectedPen = pen;
23814 23315 }
23815 23316
23816 23317 /*!
@@ -23823,7 +23324,7 void QCPItemBracket::setSelectedPen(cons
23823 23324 */
23824 23325 void QCPItemBracket::setLength(double length)
23825 23326 {
23826 mLength = length;
23327 mLength = length;
23827 23328 }
23828 23329
23829 23330 /*!
@@ -23833,60 +23334,60 void QCPItemBracket::setLength(double le
23833 23334 */
23834 23335 void QCPItemBracket::setStyle(QCPItemBracket::BracketStyle style)
23835 23336 {
23836 mStyle = style;
23337 mStyle = style;
23837 23338 }
23838 23339
23839 23340 /* inherits documentation from base class */
23840 23341 double QCPItemBracket::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
23841 23342 {
23842 Q_UNUSED(details)
23843 if (onlySelectable && !mSelectable)
23844 return -1;
23845
23846 QVector2D leftVec(left->pixelPoint());
23847 QVector2D rightVec(right->pixelPoint());
23848 if (leftVec.toPoint() == rightVec.toPoint())
23849 return -1;
23850
23851 QVector2D widthVec = (rightVec-leftVec)*0.5f;
23852 QVector2D lengthVec(-widthVec.y(), widthVec.x());
23853 lengthVec = lengthVec.normalized()*mLength;
23854 QVector2D centerVec = (rightVec+leftVec)*0.5f-lengthVec;
23855
23856 return qSqrt(distSqrToLine((centerVec-widthVec).toPointF(), (centerVec+widthVec).toPointF(), pos));
23343 Q_UNUSED(details)
23344 if (onlySelectable && !mSelectable)
23345 return -1;
23346
23347 QVector2D leftVec(left->pixelPoint());
23348 QVector2D rightVec(right->pixelPoint());
23349 if (leftVec.toPoint() == rightVec.toPoint())
23350 return -1;
23351
23352 QVector2D widthVec = (rightVec-leftVec)*0.5f;
23353 QVector2D lengthVec(-widthVec.y(), widthVec.x());
23354 lengthVec = lengthVec.normalized()*mLength;
23355 QVector2D centerVec = (rightVec+leftVec)*0.5f-lengthVec;
23356
23357 return qSqrt(distSqrToLine((centerVec-widthVec).toPointF(), (centerVec+widthVec).toPointF(), pos));
23857 23358 }
23858 23359
23859 23360 /* inherits documentation from base class */
23860 23361 void QCPItemBracket::draw(QCPPainter *painter)
23861 23362 {
23862 QVector2D leftVec(left->pixelPoint());
23863 QVector2D rightVec(right->pixelPoint());
23864 if (leftVec.toPoint() == rightVec.toPoint())
23865 return;
23866
23867 QVector2D widthVec = (rightVec-leftVec)*0.5f;
23868 QVector2D lengthVec(-widthVec.y(), widthVec.x());
23869 lengthVec = lengthVec.normalized()*mLength;
23870 QVector2D centerVec = (rightVec+leftVec)*0.5f-lengthVec;
23871
23872 QPolygon boundingPoly;
23873 boundingPoly << leftVec.toPoint() << rightVec.toPoint()
23874 << (rightVec-lengthVec).toPoint() << (leftVec-lengthVec).toPoint();
23875 QRect clip = clipRect().adjusted(-mainPen().widthF(), -mainPen().widthF(), mainPen().widthF(), mainPen().widthF());
23876 if (clip.intersects(boundingPoly.boundingRect()))
23877 {
23878 painter->setPen(mainPen());
23879 switch (mStyle)
23363 QVector2D leftVec(left->pixelPoint());
23364 QVector2D rightVec(right->pixelPoint());
23365 if (leftVec.toPoint() == rightVec.toPoint())
23366 return;
23367
23368 QVector2D widthVec = (rightVec-leftVec)*0.5f;
23369 QVector2D lengthVec(-widthVec.y(), widthVec.x());
23370 lengthVec = lengthVec.normalized()*mLength;
23371 QVector2D centerVec = (rightVec+leftVec)*0.5f-lengthVec;
23372
23373 QPolygon boundingPoly;
23374 boundingPoly << leftVec.toPoint() << rightVec.toPoint()
23375 << (rightVec-lengthVec).toPoint() << (leftVec-lengthVec).toPoint();
23376 QRect clip = clipRect().adjusted(-mainPen().widthF(), -mainPen().widthF(), mainPen().widthF(), mainPen().widthF());
23377 if (clip.intersects(boundingPoly.boundingRect()))
23378 {
23379 painter->setPen(mainPen());
23380 switch (mStyle)
23880 23381 {
23881 23382 case bsSquare:
23882 {
23383 {
23883 23384 painter->drawLine((centerVec+widthVec).toPointF(), (centerVec-widthVec).toPointF());
23884 23385 painter->drawLine((centerVec+widthVec).toPointF(), (centerVec+widthVec+lengthVec).toPointF());
23885 23386 painter->drawLine((centerVec-widthVec).toPointF(), (centerVec-widthVec+lengthVec).toPointF());
23886 23387 break;
23887 }
23388 }
23888 23389 case bsRound:
23889 {
23390 {
23890 23391 painter->setBrush(Qt::NoBrush);
23891 23392 QPainterPath path;
23892 23393 path.moveTo((centerVec+widthVec+lengthVec).toPointF());
@@ -23894,9 +23395,9 void QCPItemBracket::draw(QCPPainter *pa
23894 23395 path.cubicTo((centerVec-widthVec).toPointF(), (centerVec-widthVec).toPointF(), (centerVec-widthVec+lengthVec).toPointF());
23895 23396 painter->drawPath(path);
23896 23397 break;
23897 }
23398 }
23898 23399 case bsCurly:
23899 {
23400 {
23900 23401 painter->setBrush(Qt::NoBrush);
23901 23402 QPainterPath path;
23902 23403 path.moveTo((centerVec+widthVec+lengthVec).toPointF());
@@ -23904,9 +23405,9 void QCPItemBracket::draw(QCPPainter *pa
23904 23405 path.cubicTo((centerVec-0.4f*widthVec+lengthVec).toPointF(), (centerVec-widthVec-lengthVec*0.8f).toPointF(), (centerVec-widthVec+lengthVec).toPointF());
23905 23406 painter->drawPath(path);
23906 23407 break;
23907 }
23408 }
23908 23409 case bsCalligraphic:
23909 {
23410 {
23910 23411 painter->setPen(Qt::NoPen);
23911 23412 painter->setBrush(QBrush(mainPen().color()));
23912 23413 QPainterPath path;
@@ -23920,7 +23421,7 void QCPItemBracket::draw(QCPPainter *pa
23920 23421
23921 23422 painter->drawPath(path);
23922 23423 break;
23923 }
23424 }
23924 23425 }
23925 23426 }
23926 23427 }
@@ -23928,23 +23429,23 void QCPItemBracket::draw(QCPPainter *pa
23928 23429 /* inherits documentation from base class */
23929 23430 QPointF QCPItemBracket::anchorPixelPoint(int anchorId) const
23930 23431 {
23931 QVector2D leftVec(left->pixelPoint());
23932 QVector2D rightVec(right->pixelPoint());
23933 if (leftVec.toPoint() == rightVec.toPoint())
23934 return leftVec.toPointF();
23935
23936 QVector2D widthVec = (rightVec-leftVec)*0.5f;
23937 QVector2D lengthVec(-widthVec.y(), widthVec.x());
23938 lengthVec = lengthVec.normalized()*mLength;
23939 QVector2D centerVec = (rightVec+leftVec)*0.5f-lengthVec;
23940
23941 switch (anchorId)
23432 QVector2D leftVec(left->pixelPoint());
23433 QVector2D rightVec(right->pixelPoint());
23434 if (leftVec.toPoint() == rightVec.toPoint())
23435 return leftVec.toPointF();
23436
23437 QVector2D widthVec = (rightVec-leftVec)*0.5f;
23438 QVector2D lengthVec(-widthVec.y(), widthVec.x());
23439 lengthVec = lengthVec.normalized()*mLength;
23440 QVector2D centerVec = (rightVec+leftVec)*0.5f-lengthVec;
23441
23442 switch (anchorId)
23942 23443 {
23943 23444 case aiCenter:
23944 return centerVec.toPointF();
23945 }
23946 qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId;
23947 return QPointF();
23445 return centerVec.toPointF();
23446 }
23447 qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId;
23448 return QPointF();
23948 23449 }
23949 23450
23950 23451 /*! \internal
@@ -23954,6 +23455,6 QPointF QCPItemBracket::anchorPixelPoint
23954 23455 */
23955 23456 QPen QCPItemBracket::mainPen() const
23956 23457 {
23957 return mSelected ? mSelectedPen : mPen;
23958 }
23959
23458 return mSelected ? mSelectedPen : mPen;
23459 }
23460
@@ -1862,7 +1862,6 protected:
1862 1862 QCPLayer *mCurrentLayer;
1863 1863 QCP::PlottingHints mPlottingHints;
1864 1864 Qt::KeyboardModifier mMultiSelectModifier;
1865 bool mUseFastVectors;
1866 1865
1867 1866 // non-property members:
1868 1867 QPixmap mPaintBuffer;
@@ -2539,12 +2538,10 public:
2539 2538 bool errorBarSkipSymbol() const { return mErrorBarSkipSymbol; }
2540 2539 QCPGraph *channelFillGraph() const { return mChannelFillGraph.data(); }
2541 2540 bool adaptiveSampling() const { return mAdaptiveSampling; }
2542 bool useFastVectors() const { return mUseFastVectors; }
2543 2541
2544 2542 // setters:
2545 2543 void setData(QCPDataMap *data, bool copy=false);
2546 2544 void setData(const QVector<double> &key, const QVector<double> &value);
2547 void setData(QVector<QCPData> *data);
2548 2545 void setDataKeyError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyError);
2549 2546 void setDataKeyError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyErrorMinus, const QVector<double> &keyErrorPlus);
2550 2547 void setDataValueError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &valueError);
@@ -2559,7 +2556,6 public:
2559 2556 void setErrorBarSkipSymbol(bool enabled);
2560 2557 void setChannelFillGraph(QCPGraph *targetGraph);
2561 2558 void setAdaptiveSampling(bool enabled);
2562 void setUseFastVectors(bool useFastVectors);
2563 2559
2564 2560 // non-property methods:
2565 2561 void addData(const QCPDataMap &dataMap);
@@ -2584,7 +2580,6 public:
2584 2580 protected:
2585 2581 // property members:
2586 2582 QCPDataMap *mData;
2587 QVector<QCPData>* mDataVector;
2588 2583 QPen mErrorPen;
2589 2584 LineStyle mLineStyle;
2590 2585 QCPScatterStyle mScatterStyle;
@@ -2593,7 +2588,6 protected:
2593 2588 bool mErrorBarSkipSymbol;
2594 2589 QPointer<QCPGraph> mChannelFillGraph;
2595 2590 bool mAdaptiveSampling;
2596 bool mUseFastVectors;
2597 2591
2598 2592 // reimplemented virtual methods:
2599 2593 virtual void draw(QCPPainter *painter);
@@ -2601,9 +2595,8 protected:
2601 2595 virtual QCPRange getKeyRange(bool &foundRange, SignDomain inSignDomain=sdBoth) const;
2602 2596 virtual QCPRange getValueRange(bool &foundRange, SignDomain inSignDomain=sdBoth) const;
2603 2597 virtual QCPRange getKeyRange(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const; // overloads base class interface
2604 virtual QCPRange getKeyRangeVector(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const; // overloads base class interface
2605 2598 virtual QCPRange getValueRange(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const; // overloads base class interface
2606 virtual QCPRange getValueRangeVector(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const;
2599
2607 2600 // introduced virtual methods:
2608 2601 virtual void drawFill(QCPPainter *painter, QVector<QPointF> *lineData) const;
2609 2602 virtual void drawScatterPlot(QCPPainter *painter, QVector<QCPData> *scatterData) const;
@@ -2612,7 +2605,6 protected:
2612 2605
2613 2606 // non-virtual methods:
2614 2607 void getPreparedData(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const;
2615 void getPreparedDataVector(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const;
2616 2608 void getPlotData(QVector<QPointF> *lineData, QVector<QCPData> *scatterData) const;
2617 2609 void getScatterPlotData(QVector<QCPData> *scatterData) const;
2618 2610 void getLinePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const;
@@ -2622,9 +2614,7 protected:
2622 2614 void getImpulsePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const;
2623 2615 void drawError(QCPPainter *painter, double x, double y, const QCPData &data) const;
2624 2616 void getVisibleDataBounds(QCPDataMap::const_iterator &lower, QCPDataMap::const_iterator &upper) const;
2625 void getVisibleDataBoundsVector(QVector<QCPData>::const_iterator &lower, QVector<QCPData>::const_iterator &upper) const;
2626 2617 int countDataInBounds(const QCPDataMap::const_iterator &lower, const QCPDataMap::const_iterator &upper, int maxCount) const;
2627 int countDataInBoundsVector(const QVector<QCPData>::const_iterator &lower, const QVector<QCPData>::const_iterator &upper, int maxCount) const;
2628 2618 void addFillBasePoints(QVector<QPointF> *lineData) const;
2629 2619 void removeFillBasePoints(QVector<QPointF> *lineData) const;
2630 2620 QPointF lowerFillBasePoint(double lowerKey) const;
@@ -28,7 +28,7
28 28 SocExplorerPlot::SocExplorerPlot(QWidget *parent) :
29 29 QWidget(parent), mRubberBand(new QRubberBand(QRubberBand::Rectangle, this))
30 30 {
31 this->m_plot = new QCustomPlot(this);
31 this->m_plot = new QCustomPlotVect(this);
32 32 this->m_plot->setInteractions(QCP::iRangeDrag | QCP::iSelectAxes |
33 33 QCP::iSelectLegend | QCP::iSelectPlottables);
34 34 this->m_plot->axisRect()->setRangeDrag(Qt::Horizontal|Qt::Vertical);
@@ -85,6 +85,18 void SocExplorerPlot::exportToPDF(const
85 85 qcpPainter.end();
86 86 }
87 87
88 void SocExplorerPlot::addAction(SocExplorerPlotActions *action)
89 {
90 this->m_actions.append(action);
91 QWidget::addAction((QAction*)action);
92 }
93
94 QVector<QCPData> *SocExplorerPlot::getVisibleData(int graphIndex)
95 {
96 QVector<QCPData> *wholeData=((QCPGraphVect*)m_plot->graph(graphIndex))->data();
97 // m_plot->xAxis->
98 }
99
88 100 void SocExplorerPlot::setTitle(QString title)
89 101 {
90 102 Q_UNUSED(title)
@@ -144,7 +156,8 void SocExplorerPlot::setAdaptativeSampl
144 156
145 157 void SocExplorerPlot::setUseFastVector(int graphIndex, bool enable)
146 158 {
147 this->m_plot->graph(graphIndex)->setUseFastVectors(enable);
159 // TODO deprecated
160 // this->m_plot->graph(graphIndex)->setUseFastVectors(enable);
148 161 }
149 162
150 163 int SocExplorerPlot::addGraph()
@@ -155,7 +168,12 int SocExplorerPlot::addGraph()
155 168
156 169 bool SocExplorerPlot::removeGraph(int graphIndex)
157 170 {
158 return this->m_plot->removeGraph(graphIndex);
171 return this->m_plot->removeGraph(graphIndex);
172 }
173
174 int SocExplorerPlot::graphCount()
175 {
176 return m_plot->graphCount();
159 177 }
160 178
161 179 void SocExplorerPlot::removeAllGraphs()
@@ -226,7 +244,7 void SocExplorerPlot::setGraphData(int g
226 244 {
227 245 if((graphIndex<this->m_plot->graphCount()))// && (x.at(0).type()==QVariant::Double))
228 246 {
229 this->m_plot->graph(graphIndex)->setData(data);
247 ((QCPGraphVect*)this->m_plot->graph(graphIndex))->setData(data);
230 248 }
231 249 if(replot)
232 250 this->m_plot->replot();
@@ -25,9 +25,37
25 25 #include <QWidget>
26 26 #include <QGridLayout>
27 27 #include <qcustomplot.h>
28 #include <qcustomplotvect.h>
28 29 #include <QRubberBand>
29 30 #include <QPoint>
30 31
32 class SocExplorerPlotActions : public QAction
33 {
34 Q_OBJECT
35 public:
36 SocExplorerPlotActions(const QString &text,int PID,QObject* parent=0)
37 :QAction(text,parent)
38 {
39 setPID(PID);
40 connect(this,SIGNAL(triggered()),this,SLOT(trigger()));
41 }
42 SocExplorerPlotActions(const QIcon &icon, const QString &text,int PID, QObject* parent)
43 :QAction(icon,text,parent)
44 {
45 setPID(PID);
46 connect(this,SIGNAL(triggered()),this,SLOT(trigger()));
47 }
48 ~SocExplorerPlotActions(){}
49 void setPID(int PID){this->m_PID=PID;}
50 int PID(){return m_PID;}
51 private slots:
52 void trigger(){emit triggered(m_PID);}
53 signals:
54 void triggered(int PID);
55 private:
56 int m_PID;
57 };
58
31 59 class SocExplorerPlot : public QWidget
32 60 {
33 61 Q_OBJECT
@@ -46,6 +74,7 public:
46 74 void setUseFastVector(int graphIndex,bool enable);
47 75 int addGraph();
48 76 bool removeGraph(int graphIndex);
77 int graphCount();
49 78 void removeAllGraphs();
50 79 void setGraphName(int graphIndex,QString name);
51 80 void setGraphData(int graphIndex, QList<QVariant> x, QList<QVariant> y);
@@ -63,6 +92,10 public:
63 92 void replot();
64 93 void exportToSVG(const QString& fileName);
65 94 void exportToPDF(const QString& fileName);
95 void addAction(SocExplorerPlotActions* action);
96 int PID(){return m_PID;}
97 void setPID(int PID){m_PID = PID;}
98 QVector<QCPData>* getVisibleData(int graphIndex);
66 99 signals:
67 100 void titleChanged(const QString& newTitle);
68 101 public slots:
@@ -78,7 +111,7 protected:
78 111 private:
79 112 void zoom(double factor, int center, Qt::Orientation orientation);
80 113 void move(double factor, Qt::Orientation orientation);
81 QCustomPlot* m_plot;
114 QCustomPlotVect* m_plot;
82 115 QGridLayout* m_mainlayout;
83 116 bool ctrl_hold;
84 117 bool shift_hold;
@@ -89,6 +122,8 private:
89 122 bool mZoomMode;
90 123 QRubberBand * mRubberBand;
91 124 QPoint mOrigin;
125 QList<SocExplorerPlotActions*> m_actions;
126 int m_PID;
92 127 };
93 128
94 129 #endif // SOCEXPLORERPLOT_H
@@ -78,15 +78,15 MainWindow::~MainWindow()
78 78 delete ui;
79 79 }
80 80
81 QString MainWindow::getFilePath(const QString &name)
82 {
83 // for(int i=0;i<this->folderViews.count();i++)
84 // {
85 // if(folderViews.at(i)->isDraging(name))
86 // return folderViews.at(i)->currentFolder();
87 // }
88 return "";
89 }
81 //QString MainWindow::getFilePath(const QString &name)
82 //{
83 //// for(int i=0;i<this->folderViews.count();i++)
84 //// {
85 //// if(folderViews.at(i)->isDraging(name))
86 //// return folderViews.at(i)->currentFolder();
87 //// }
88 // return "";
89 //}
90 90
91 91
92 92
@@ -30,7 +30,6
30 30 #include <QListWidgetItem>
31 31 #include <QVBoxLayout>
32 32 #include <QWidget>
33 #include "folderview.h"
34 33 #include "abstractfileloader.h"
35 34 #include "cassiniindexfileviewer.h"
36 35 #include <downloadhistory.h>
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now