]> Creatis software - cpPlugins.git/blob - lib/QCustomPlot/QCustomPlot.cxx
...
[cpPlugins.git] / lib / QCustomPlot / QCustomPlot.cxx
1 /***************************************************************************
2 **                                                                        **
3 **  QCustomPlot, an easy to use, modern plotting widget for Qt            **
4 **  Copyright (C) 2011-2015 Emanuel Eichhammer                            **
5 **                                                                        **
6 **  This program is free software: you can redistribute it and/or modify  **
7 **  it under the terms of the GNU General Public License as published by  **
8 **  the Free Software Foundation, either version 3 of the License, or     **
9 **  (at your option) any later version.                                   **
10 **                                                                        **
11 **  This program is distributed in the hope that it will be useful,       **
12 **  but WITHOUT ANY WARRANTY; without even the implied warranty of        **
13 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         **
14 **  GNU General Public License for more details.                          **
15 **                                                                        **
16 **  You should have received a copy of the GNU General Public License     **
17 **  along with this program.  If not, see http://www.gnu.org/licenses/.   **
18 **                                                                        **
19 ****************************************************************************
20 **           Author: Emanuel Eichhammer                                   **
21 **  Website/Contact: http://www.qcustomplot.com/                          **
22 **             Date: 22.12.15                                             **
23 **          Version: 1.3.2                                                **
24 ****************************************************************************/
25
26 #include <QCustomPlot/QCustomPlot.h>
27
28
29
30 ////////////////////////////////////////////////////////////////////////////////////////////////////
31 //////////////////// QCPPainter
32 ////////////////////////////////////////////////////////////////////////////////////////////////////
33
34 /*! \class QCPPainter
35   \brief QPainter subclass used internally
36   
37   This QPainter subclass is used to provide some extended functionality e.g. for tweaking position
38   consistency between antialiased and non-antialiased painting. Further it provides workarounds
39   for QPainter quirks.
40   
41   \warning This class intentionally hides non-virtual functions of QPainter, e.g. setPen, save and
42   restore. So while it is possible to pass a QCPPainter instance to a function that expects a
43   QPainter pointer, some of the workarounds and tweaks will be unavailable to the function (because
44   it will call the base class implementations of the functions actually hidden by QCPPainter).
45 */
46
47 /*!
48   Creates a new QCPPainter instance and sets default values
49 */
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
57 }
58
59 /*!
60   Creates a new QCPPainter instance on the specified paint \a device and sets default values. Just
61   like the analogous QPainter constructor, begins painting on \a device immediately.
62   
63   Like \ref begin, this method sets QPainter::NonCosmeticDefaultPen in Qt versions before Qt5.
64 */
65 QCPPainter::QCPPainter(QPaintDevice *device) :
66   QPainter(device),
67   mModes(pmDefault),
68   mIsAntialiasing(false)
69 {
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);
73 #endif
74 }
75
76 QCPPainter::~QCPPainter()
77 {
78 }
79
80 /*!
81   Sets the pen of the painter and applies certain fixes to it, depending on the mode of this
82   QCPPainter.
83   
84   \note this function hides the non-virtual base class implementation.
85 */
86 void QCPPainter::setPen(const QPen &pen)
87 {
88   QPainter::setPen(pen);
89   if (mModes.testFlag(pmNonCosmetic))
90     makeNonCosmetic();
91 }
92
93 /*! \overload
94   
95   Sets the pen (by color) of the painter and applies certain fixes to it, depending on the mode of
96   this QCPPainter.
97   
98   \note this function hides the non-virtual base class implementation.
99 */
100 void QCPPainter::setPen(const QColor &color)
101 {
102   QPainter::setPen(color);
103   if (mModes.testFlag(pmNonCosmetic))
104     makeNonCosmetic();
105 }
106
107 /*! \overload
108   
109   Sets the pen (by style) of the painter and applies certain fixes to it, depending on the mode of
110   this QCPPainter.
111   
112   \note this function hides the non-virtual base class implementation.
113 */
114 void QCPPainter::setPen(Qt::PenStyle penStyle)
115 {
116   QPainter::setPen(penStyle);
117   if (mModes.testFlag(pmNonCosmetic))
118     makeNonCosmetic();
119 }
120
121 /*! \overload
122   
123   Works around a Qt bug introduced with Qt 4.8 which makes drawing QLineF unpredictable when
124   antialiasing is disabled. Thus when antialiasing is disabled, it rounds the \a line to
125   integer coordinates and then passes it to the original drawLine.
126   
127   \note this function hides the non-virtual base class implementation.
128 */
129 void QCPPainter::drawLine(const QLineF &line)
130 {
131   if (mIsAntialiasing || mModes.testFlag(pmVectorized))
132     QPainter::drawLine(line);
133   else
134     QPainter::drawLine(line.toLine());
135 }
136
137 /*!
138   Sets whether painting uses antialiasing or not. Use this method instead of using setRenderHint
139   with QPainter::Antialiasing directly, as it allows QCPPainter to regain pixel exactness between
140   antialiased and non-antialiased painting (Since Qt < 5.0 uses slightly different coordinate systems for
141   AA/Non-AA painting).
142 */
143 void QCPPainter::setAntialiasing(bool enabled)
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);
155     }
156   }
157 }
158
159 /*!
160   Sets the mode of the painter. This controls whether the painter shall adjust its
161   fixes/workarounds optimized for certain output devices.
162 */
163 void QCPPainter::setModes(QCPPainter::PainterModes modes)
164 {
165   mModes = modes;
166 }
167
168 /*!
169   Sets the QPainter::NonCosmeticDefaultPen in Qt versions before Qt5 after beginning painting on \a
170   device. This is necessary to get cosmetic pen consistency across Qt versions, because since Qt5,
171   all pens are non-cosmetic by default, and in Qt4 this render hint must be set to get that
172   behaviour.
173   
174   The Constructor \ref QCPPainter(QPaintDevice *device) which directly starts painting also sets
175   the render hint as appropriate.
176   
177   \note this function hides the non-virtual base class implementation.
178 */
179 bool QCPPainter::begin(QPaintDevice *device)
180 {
181   bool result = QPainter::begin(device);
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);
185 #endif
186   return result;
187 }
188
189 /*! \overload
190   
191   Sets the mode of the painter. This controls whether the painter shall adjust its
192   fixes/workarounds optimized for certain output devices.
193 */
194 void QCPPainter::setMode(QCPPainter::PainterMode mode, bool enabled)
195 {
196   if (!enabled && mModes.testFlag(mode))
197     mModes &= ~mode;
198   else if (enabled && !mModes.testFlag(mode))
199     mModes |= mode;
200 }
201
202 /*!
203   Saves the painter (see QPainter::save). Since QCPPainter adds some new internal state to
204   QPainter, the save/restore functions are reimplemented to also save/restore those members.
205   
206   \note this function hides the non-virtual base class implementation.
207   
208   \see restore
209 */
210 void QCPPainter::save()
211 {
212   mAntialiasingStack.push(mIsAntialiasing);
213   QPainter::save();
214 }
215
216 /*!
217   Restores the painter (see QPainter::restore). Since QCPPainter adds some new internal state to
218   QPainter, the save/restore functions are reimplemented to also save/restore those members.
219   
220   \note this function hides the non-virtual base class implementation.
221   
222   \see save
223 */
224 void QCPPainter::restore()
225 {
226   if (!mAntialiasingStack.isEmpty())
227     mIsAntialiasing = mAntialiasingStack.pop();
228   else
229     qDebug() << Q_FUNC_INFO << "Unbalanced save/restore";
230   QPainter::restore();
231 }
232
233 /*!
234   Changes the pen width to 1 if it currently is 0. This function is called in the \ref setPen
235   overrides when the \ref pmNonCosmetic mode is set.
236 */
237 void QCPPainter::makeNonCosmetic()
238 {
239   if (qFuzzyIsNull(pen().widthF()))
240   {
241     QPen p = pen();
242     p.setWidth(1);
243     QPainter::setPen(p);
244   }
245 }
246
247
248 ////////////////////////////////////////////////////////////////////////////////////////////////////
249 //////////////////// QCPScatterStyle
250 ////////////////////////////////////////////////////////////////////////////////////////////////////
251
252 /*! \class QCPScatterStyle
253   \brief Represents the visual appearance of scatter points
254   
255   This class holds information about shape, color and size of scatter points. In plottables like
256   QCPGraph it is used to store how scatter points shall be drawn. For example, \ref
257   QCPGraph::setScatterStyle takes a QCPScatterStyle instance.
258   
259   A scatter style consists of a shape (\ref setShape), a line color (\ref setPen) and possibly a
260   fill (\ref setBrush), if the shape provides a fillable area. Further, the size of the shape can
261   be controlled with \ref setSize.
262
263   \section QCPScatterStyle-defining Specifying a scatter style
264   
265   You can set all these configurations either by calling the respective functions on an instance:
266   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpscatterstyle-creation-1
267   
268   Or you can use one of the various constructors that take different parameter combinations, making
269   it easy to specify a scatter style in a single call, like so:
270   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpscatterstyle-creation-2
271   
272   \section QCPScatterStyle-undefinedpen Leaving the color/pen up to the plottable
273   
274   There are two constructors which leave the pen undefined: \ref QCPScatterStyle() and \ref
275   QCPScatterStyle(ScatterShape shape, double size). If those constructors are used, a call to \ref
276   isPenDefined will return false. It leads to scatter points that inherit the pen from the
277   plottable that uses the scatter style. Thus, if such a scatter style is passed to QCPGraph, the line
278   color of the graph (\ref QCPGraph::setPen) will be used by the scatter points. This makes
279   it very convenient to set up typical scatter settings:
280   
281   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpscatterstyle-shortcreation
282
283   Notice that it wasn't even necessary to explicitly call a QCPScatterStyle constructor. This works
284   because QCPScatterStyle provides a constructor that can transform a \ref ScatterShape directly
285   into a QCPScatterStyle instance (that's the \ref QCPScatterStyle(ScatterShape shape, double size)
286   constructor with a default for \a size). In those cases, C++ allows directly supplying a \ref
287   ScatterShape, where actually a QCPScatterStyle is expected.
288   
289   \section QCPScatterStyle-custompath-and-pixmap Custom shapes and pixmaps
290   
291   QCPScatterStyle supports drawing custom shapes and arbitrary pixmaps as scatter points.
292
293   For custom shapes, you can provide a QPainterPath with the desired shape to the \ref
294   setCustomPath function or call the constructor that takes a painter path. The scatter shape will
295   automatically be set to \ref ssCustom.
296   
297   For pixmaps, you call \ref setPixmap with the desired QPixmap. Alternatively you can use the
298   constructor that takes a QPixmap. The scatter shape will automatically be set to \ref ssPixmap.
299   Note that \ref setSize does not influence the appearance of the pixmap.
300 */
301
302 /* start documentation of inline functions */
303
304 /*! \fn bool QCPScatterStyle::isNone() const
305   
306   Returns whether the scatter shape is \ref ssNone.
307   
308   \see setShape
309 */
310
311 /*! \fn bool QCPScatterStyle::isPenDefined() const
312   
313   Returns whether a pen has been defined for this scatter style.
314   
315   The pen is undefined if a constructor is called that does not carry \a pen as parameter. Those are
316   \ref QCPScatterStyle() and \ref QCPScatterStyle(ScatterShape shape, double size). If the pen is
317   left undefined, the scatter color will be inherited from the plottable that uses this scatter
318   style.
319   
320   \see setPen
321 */
322
323 /* end documentation of inline functions */
324
325 /*!
326   Creates a new QCPScatterStyle instance with size set to 6. No shape, pen or brush is defined.
327   
328   Since the pen is undefined (\ref isPenDefined returns false), the scatter color will be inherited
329   from the plottable that uses this scatter style.
330 */
331 QCPScatterStyle::QCPScatterStyle() :
332   mSize(6),
333   mShape(ssNone),
334   mPen(Qt::NoPen),
335   mBrush(Qt::NoBrush),
336   mPenDefined(false)
337 {
338 }
339
340 /*!
341   Creates a new QCPScatterStyle instance with shape set to \a shape and size to \a size. No pen or
342   brush is defined.
343   
344   Since the pen is undefined (\ref isPenDefined returns false), the scatter color will be inherited
345   from the plottable that uses this scatter style.
346 */
347 QCPScatterStyle::QCPScatterStyle(ScatterShape shape, double size) :
348   mSize(size),
349   mShape(shape),
350   mPen(Qt::NoPen),
351   mBrush(Qt::NoBrush),
352   mPenDefined(false)
353 {
354 }
355
356 /*!
357   Creates a new QCPScatterStyle instance with shape set to \a shape, the pen color set to \a color,
358   and size to \a size. No brush is defined, i.e. the scatter point will not be filled.
359 */
360 QCPScatterStyle::QCPScatterStyle(ScatterShape shape, const QColor &color, double size) :
361   mSize(size),
362   mShape(shape),
363   mPen(QPen(color)),
364   mBrush(Qt::NoBrush),
365   mPenDefined(true)
366 {
367 }
368
369 /*!
370   Creates a new QCPScatterStyle instance with shape set to \a shape, the pen color set to \a color,
371   the brush color to \a fill (with a solid pattern), and size to \a size.
372 */
373 QCPScatterStyle::QCPScatterStyle(ScatterShape shape, const QColor &color, const QColor &fill, double size) :
374   mSize(size),
375   mShape(shape),
376   mPen(QPen(color)),
377   mBrush(QBrush(fill)),
378   mPenDefined(true)
379 {
380 }
381
382 /*!
383   Creates a new QCPScatterStyle instance with shape set to \a shape, the pen set to \a pen, the
384   brush to \a brush, and size to \a size.
385   
386   \warning In some cases it might be tempting to directly use a pen style like <tt>Qt::NoPen</tt> as \a pen
387   and a color like <tt>Qt::blue</tt> as \a brush. Notice however, that the corresponding call\n
388   <tt>QCPScatterStyle(QCPScatterShape::ssCircle, Qt::NoPen, Qt::blue, 5)</tt>\n
389   doesn't necessarily lead C++ to use this constructor in some cases, but might mistake
390   <tt>Qt::NoPen</tt> for a QColor and use the
391   \ref QCPScatterStyle(ScatterShape shape, const QColor &color, const QColor &fill, double size)
392   constructor instead (which will lead to an unexpected look of the scatter points). To prevent
393   this, be more explicit with the parameter types. For example, use <tt>QBrush(Qt::blue)</tt>
394   instead of just <tt>Qt::blue</tt>, to clearly point out to the compiler that this constructor is
395   wanted.
396 */
397 QCPScatterStyle::QCPScatterStyle(ScatterShape shape, const QPen &pen, const QBrush &brush, double size) :
398   mSize(size),
399   mShape(shape),
400   mPen(pen),
401   mBrush(brush),
402   mPenDefined(pen.style() != Qt::NoPen)
403 {
404 }
405
406 /*!
407   Creates a new QCPScatterStyle instance which will show the specified \a pixmap. The scatter shape
408   is set to \ref ssPixmap.
409 */
410 QCPScatterStyle::QCPScatterStyle(const QPixmap &pixmap) :
411   mSize(5),
412   mShape(ssPixmap),
413   mPen(Qt::NoPen),
414   mBrush(Qt::NoBrush),
415   mPixmap(pixmap),
416   mPenDefined(false)
417 {
418 }
419
420 /*!
421   Creates a new QCPScatterStyle instance with a custom shape that is defined via \a customPath. The
422   scatter shape is set to \ref ssCustom.
423   
424   The custom shape line will be drawn with \a pen and filled with \a brush. The size has a slightly
425   different meaning than for built-in scatter points: The custom path will be drawn scaled by a
426   factor of \a size/6.0. Since the default \a size is 6, the custom path will appear at a its
427   natural size by default. To double the size of the path for example, set \a size to 12.
428 */
429 QCPScatterStyle::QCPScatterStyle(const QPainterPath &customPath, const QPen &pen, const QBrush &brush, double size) :
430   mSize(size),
431   mShape(ssCustom),
432   mPen(pen),
433   mBrush(brush),
434   mCustomPath(customPath),
435   mPenDefined(pen.style() != Qt::NoPen)
436 {
437 }
438
439 /*!
440   Sets the size (pixel diameter) of the drawn scatter points to \a size.
441   
442   \see setShape
443 */
444 void QCPScatterStyle::setSize(double size)
445 {
446   mSize = size;
447 }
448
449 /*!
450   Sets the shape to \a shape.
451   
452   Note that the calls \ref setPixmap and \ref setCustomPath automatically set the shape to \ref
453   ssPixmap and \ref ssCustom, respectively.
454   
455   \see setSize
456 */
457 void QCPScatterStyle::setShape(QCPScatterStyle::ScatterShape shape)
458 {
459   mShape = shape;
460 }
461
462 /*!
463   Sets the pen that will be used to draw scatter points to \a pen.
464   
465   If the pen was previously undefined (see \ref isPenDefined), the pen is considered defined after
466   a call to this function, even if \a pen is <tt>Qt::NoPen</tt>.
467   
468   \see setBrush
469 */
470 void QCPScatterStyle::setPen(const QPen &pen)
471 {
472   mPenDefined = true;
473   mPen = pen;
474 }
475
476 /*!
477   Sets the brush that will be used to fill scatter points to \a brush. Note that not all scatter
478   shapes have fillable areas. For example, \ref ssPlus does not while \ref ssCircle does.
479   
480   \see setPen
481 */
482 void QCPScatterStyle::setBrush(const QBrush &brush)
483 {
484   mBrush = brush;
485 }
486
487 /*!
488   Sets the pixmap that will be drawn as scatter point to \a pixmap.
489   
490   Note that \ref setSize does not influence the appearance of the pixmap.
491   
492   The scatter shape is automatically set to \ref ssPixmap.
493 */
494 void QCPScatterStyle::setPixmap(const QPixmap &pixmap)
495 {
496   setShape(ssPixmap);
497   mPixmap = pixmap;
498 }
499
500 /*!
501   Sets the custom shape that will be drawn as scatter point to \a customPath.
502   
503   The scatter shape is automatically set to \ref ssCustom.
504 */
505 void QCPScatterStyle::setCustomPath(const QPainterPath &customPath)
506 {
507   setShape(ssCustom);
508   mCustomPath = customPath;
509 }
510
511 /*!
512   Applies the pen and the brush of this scatter style to \a painter. If this scatter style has an
513   undefined pen (\ref isPenDefined), sets the pen of \a painter to \a defaultPen instead.
514   
515   This function is used by plottables (or any class that wants to draw scatters) just before a
516   number of scatters with this style shall be drawn with the \a painter.
517   
518   \see drawShape
519 */
520 void QCPScatterStyle::applyTo(QCPPainter *painter, const QPen &defaultPen) const
521 {
522   painter->setPen(mPenDefined ? mPen : defaultPen);
523   painter->setBrush(mBrush);
524 }
525
526 /*!
527   Draws the scatter shape with \a painter at position \a pos.
528   
529   This function does not modify the pen or the brush on the painter, as \ref applyTo is meant to be
530   called before scatter points are drawn with \ref drawShape.
531   
532   \see applyTo
533 */
534 void QCPScatterStyle::drawShape(QCPPainter *painter, QPointF pos) const
535 {
536   drawShape(painter, pos.x(), pos.y());
537 }
538
539 /*! \overload
540   Draws the scatter shape with \a painter at position \a x and \a y.
541 */
542 void QCPScatterStyle::drawShape(QCPPainter *painter, double x, double y) const
543 {
544   double w = mSize/2.0;
545   switch (mShape)
546   {
547     case ssNone: break;
548     case ssDot:
549     {
550       painter->drawLine(QPointF(x, y), QPointF(x+0.0001, y));
551       break;
552     }
553     case ssCross:
554     {
555       painter->drawLine(QLineF(x-w, y-w, x+w, y+w));
556       painter->drawLine(QLineF(x-w, y+w, x+w, y-w));
557       break;
558     }
559     case ssPlus:
560     {
561       painter->drawLine(QLineF(x-w,   y, x+w,   y));
562       painter->drawLine(QLineF(  x, y+w,   x, y-w));
563       break;
564     }
565     case ssCircle:
566     {
567       painter->drawEllipse(QPointF(x , y), w, w);
568       break;
569     }
570     case ssDisc:
571     {
572       QBrush b = painter->brush();
573       painter->setBrush(painter->pen().color());
574       painter->drawEllipse(QPointF(x , y), w, w);
575       painter->setBrush(b);
576       break;
577     }
578     case ssSquare:
579     {
580       painter->drawRect(QRectF(x-w, y-w, mSize, mSize));
581       break;
582     }
583     case ssDiamond:
584     {
585       painter->drawLine(QLineF(x-w,   y,   x, y-w));
586       painter->drawLine(QLineF(  x, y-w, x+w,   y));
587       painter->drawLine(QLineF(x+w,   y,   x, y+w));
588       painter->drawLine(QLineF(  x, y+w, x-w,   y));
589       break;
590     }
591     case ssStar:
592     {
593       painter->drawLine(QLineF(x-w,   y, x+w,   y));
594       painter->drawLine(QLineF(  x, y+w,   x, y-w));
595       painter->drawLine(QLineF(x-w*0.707, y-w*0.707, x+w*0.707, y+w*0.707));
596       painter->drawLine(QLineF(x-w*0.707, y+w*0.707, x+w*0.707, y-w*0.707));
597       break;
598     }
599     case ssTriangle:
600     {
601        painter->drawLine(QLineF(x-w, y+0.755*w, x+w, y+0.755*w));
602        painter->drawLine(QLineF(x+w, y+0.755*w,   x, y-0.977*w));
603        painter->drawLine(QLineF(  x, y-0.977*w, x-w, y+0.755*w));
604       break;
605     }
606     case ssTriangleInverted:
607     {
608        painter->drawLine(QLineF(x-w, y-0.755*w, x+w, y-0.755*w));
609        painter->drawLine(QLineF(x+w, y-0.755*w,   x, y+0.977*w));
610        painter->drawLine(QLineF(  x, y+0.977*w, x-w, y-0.755*w));
611       break;
612     }
613     case ssCrossSquare:
614     {
615        painter->drawLine(QLineF(x-w, y-w, x+w*0.95, y+w*0.95));
616        painter->drawLine(QLineF(x-w, y+w*0.95, x+w*0.95, y-w));
617        painter->drawRect(QRectF(x-w, y-w, mSize, mSize));
618       break;
619     }
620     case ssPlusSquare:
621     {
622        painter->drawLine(QLineF(x-w,   y, x+w*0.95,   y));
623        painter->drawLine(QLineF(  x, y+w,        x, y-w));
624        painter->drawRect(QRectF(x-w, y-w, mSize, mSize));
625       break;
626     }
627     case ssCrossCircle:
628     {
629        painter->drawLine(QLineF(x-w*0.707, y-w*0.707, x+w*0.670, y+w*0.670));
630        painter->drawLine(QLineF(x-w*0.707, y+w*0.670, x+w*0.670, y-w*0.707));
631        painter->drawEllipse(QPointF(x, y), w, w);
632       break;
633     }
634     case ssPlusCircle:
635     {
636        painter->drawLine(QLineF(x-w,   y, x+w,   y));
637        painter->drawLine(QLineF(  x, y+w,   x, y-w));
638        painter->drawEllipse(QPointF(x, y), w, w);
639       break;
640     }
641     case ssPeace:
642     {
643        painter->drawLine(QLineF(x, y-w,         x,       y+w));
644        painter->drawLine(QLineF(x,   y, x-w*0.707, y+w*0.707));
645        painter->drawLine(QLineF(x,   y, x+w*0.707, y+w*0.707));
646        painter->drawEllipse(QPointF(x, y), w, w);
647       break;
648     }
649     case ssPixmap:
650     {
651       painter->drawPixmap(x-mPixmap.width()*0.5, y-mPixmap.height()*0.5, mPixmap);
652       break;
653     }
654     case ssCustom:
655     {
656       QTransform oldTransform = painter->transform();
657       painter->translate(x, y);
658       painter->scale(mSize/6.0, mSize/6.0);
659       painter->drawPath(mCustomPath);
660       painter->setTransform(oldTransform);
661       break;
662     }
663   }
664 }
665
666
667 ////////////////////////////////////////////////////////////////////////////////////////////////////
668 //////////////////// QCPLayer
669 ////////////////////////////////////////////////////////////////////////////////////////////////////
670
671 /*! \class QCPLayer
672   \brief A layer that may contain objects, to control the rendering order
673   
674   The Layering system of QCustomPlot is the mechanism to control the rendering order of the
675   elements inside the plot.
676   
677   It is based on the two classes QCPLayer and QCPLayerable. QCustomPlot holds an ordered list of
678   one or more instances of QCPLayer (see QCustomPlot::addLayer, QCustomPlot::layer,
679   QCustomPlot::moveLayer, etc.). When replotting, QCustomPlot goes through the list of layers
680   bottom to top and successively draws the layerables of the layers.
681   
682   A QCPLayer contains an ordered list of QCPLayerable instances. QCPLayerable is an abstract base
683   class from which almost all visible objects derive, like axes, grids, graphs, items, etc.
684   
685   Initially, QCustomPlot has five layers: "background", "grid", "main", "axes" and "legend" (in
686   that order). The top two layers "axes" and "legend" contain the default axes and legend, so they
687   will be drawn on top. In the middle, there is the "main" layer. It is initially empty and set as
688   the current layer (see QCustomPlot::setCurrentLayer). This means, all new plottables, items etc.
689   are created on this layer by default. Then comes the "grid" layer which contains the QCPGrid
690   instances (which belong tightly to QCPAxis, see \ref QCPAxis::grid). The Axis rect background
691   shall be drawn behind everything else, thus the default QCPAxisRect instance is placed on the
692   "background" layer. Of course, the layer affiliation of the individual objects can be changed as
693   required (\ref QCPLayerable::setLayer).
694   
695   Controlling the ordering of objects is easy: Create a new layer in the position you want it to
696   be, e.g. above "main", with QCustomPlot::addLayer. Then set the current layer with
697   QCustomPlot::setCurrentLayer to that new layer and finally create the objects normally. They will
698   be placed on the new layer automatically, due to the current layer setting. Alternatively you
699   could have also ignored the current layer setting and just moved the objects with
700   QCPLayerable::setLayer to the desired layer after creating them.
701   
702   It is also possible to move whole layers. For example, If you want the grid to be shown in front
703   of all plottables/items on the "main" layer, just move it above "main" with
704   QCustomPlot::moveLayer.
705   
706   The rendering order within one layer is simply by order of creation or insertion. The item
707   created last (or added last to the layer), is drawn on top of all other objects on that layer.
708   
709   When a layer is deleted, the objects on it are not deleted with it, but fall on the layer below
710   the deleted layer, see QCustomPlot::removeLayer.
711 */
712
713 /* start documentation of inline functions */
714
715 /*! \fn QList<QCPLayerable*> QCPLayer::children() const
716   
717   Returns a list of all layerables on this layer. The order corresponds to the rendering order:
718   layerables with higher indices are drawn above layerables with lower indices.
719 */
720
721 /*! \fn int QCPLayer::index() const
722   
723   Returns the index this layer has in the QCustomPlot. The index is the integer number by which this layer can be
724   accessed via \ref QCustomPlot::layer.
725   
726   Layers with higher indices will be drawn above layers with lower indices.
727 */
728
729 /* end documentation of inline functions */
730
731 /*!
732   Creates a new QCPLayer instance.
733   
734   Normally you shouldn't directly instantiate layers, use \ref QCustomPlot::addLayer instead.
735   
736   \warning It is not checked that \a layerName is actually a unique layer name in \a parentPlot.
737   This check is only performed by \ref QCustomPlot::addLayer.
738 */
739 QCPLayer::QCPLayer(QCustomPlot *parentPlot, const QString &layerName) :
740   QObject(parentPlot),
741   mParentPlot(parentPlot),
742   mName(layerName),
743   mIndex(-1), // will be set to a proper value by the QCustomPlot layer creation function
744   mVisible(true)
745 {
746   // Note: no need to make sure layerName is unique, because layer
747   // management is done with QCustomPlot functions.
748 }
749
750 QCPLayer::~QCPLayer()
751 {
752   // If child layerables are still on this layer, detach them, so they don't try to reach back to this
753   // then invalid layer once they get deleted/moved themselves. This only happens when layers are deleted
754   // directly, like in the QCustomPlot destructor. (The regular layer removal procedure for the user is to
755   // call QCustomPlot::removeLayer, which moves all layerables off this layer before deleting it.)
756   
757   while (!mChildren.isEmpty())
758     mChildren.last()->setLayer(0); // removes itself from mChildren via removeChild()
759   
760   if (mParentPlot->currentLayer() == this)
761     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.";
762 }
763
764 /*!
765   Sets whether this layer is visible or not. If \a visible is set to false, all layerables on this
766   layer will be invisible.
767
768   This function doesn't change the visibility property of the layerables (\ref
769   QCPLayerable::setVisible), but the \ref QCPLayerable::realVisibility of each layerable takes the
770   visibility of the parent layer into account.
771 */
772 void QCPLayer::setVisible(bool visible)
773 {
774   mVisible = visible;
775 }
776
777 /*! \internal
778   
779   Adds the \a layerable to the list of this layer. If \a prepend is set to true, the layerable will
780   be prepended to the list, i.e. be drawn beneath the other layerables already in the list.
781   
782   This function does not change the \a mLayer member of \a layerable to this layer. (Use
783   QCPLayerable::setLayer to change the layer of an object, not this function.)
784   
785   \see removeChild
786 */
787 void QCPLayer::addChild(QCPLayerable *layerable, bool prepend)
788 {
789   if (!mChildren.contains(layerable))
790   {
791     if (prepend)
792       mChildren.prepend(layerable);
793     else
794       mChildren.append(layerable);
795   } else
796     qDebug() << Q_FUNC_INFO << "layerable is already child of this layer" << reinterpret_cast<quintptr>(layerable);
797 }
798
799 /*! \internal
800   
801   Removes the \a layerable from the list of this layer.
802   
803   This function does not change the \a mLayer member of \a layerable. (Use QCPLayerable::setLayer
804   to change the layer of an object, not this function.)
805   
806   \see addChild
807 */
808 void QCPLayer::removeChild(QCPLayerable *layerable)
809 {
810   if (!mChildren.removeOne(layerable))
811     qDebug() << Q_FUNC_INFO << "layerable is not child of this layer" << reinterpret_cast<quintptr>(layerable);
812 }
813
814
815 ////////////////////////////////////////////////////////////////////////////////////////////////////
816 //////////////////// QCPLayerable
817 ////////////////////////////////////////////////////////////////////////////////////////////////////
818
819 /*! \class QCPLayerable
820   \brief Base class for all drawable objects
821   
822   This is the abstract base class most visible objects derive from, e.g. plottables, axes, grid
823   etc.
824
825   Every layerable is on a layer (QCPLayer) which allows controlling the rendering order by stacking
826   the layers accordingly.
827   
828   For details about the layering mechanism, see the QCPLayer documentation.
829 */
830
831 /* start documentation of inline functions */
832
833 /*! \fn QCPLayerable *QCPLayerable::parentLayerable() const
834  
835   Returns the parent layerable of this layerable. The parent layerable is used to provide
836   visibility hierarchies in conjunction with the method \ref realVisibility. This way, layerables
837   only get drawn if their parent layerables are visible, too.
838   
839   Note that a parent layerable is not necessarily also the QObject parent for memory management.
840   Further, a layerable doesn't always have a parent layerable, so this function may return 0.
841   
842   A parent layerable is set implicitly with when placed inside layout elements and doesn't need to be
843   set manually by the user.
844 */
845
846 /* end documentation of inline functions */
847 /* start documentation of pure virtual functions */
848
849 /*! \fn virtual void QCPLayerable::applyDefaultAntialiasingHint(QCPPainter *painter) const = 0
850   \internal
851   
852   This function applies the default antialiasing setting to the specified \a painter, using the
853   function \ref applyAntialiasingHint. It is the antialiasing state the painter is put in, when
854   \ref draw is called on the layerable. If the layerable has multiple entities whose antialiasing
855   setting may be specified individually, this function should set the antialiasing state of the
856   most prominent entity. In this case however, the \ref draw function usually calls the specialized
857   versions of this function before drawing each entity, effectively overriding the setting of the
858   default antialiasing hint.
859   
860   <b>First example:</b> QCPGraph has multiple entities that have an antialiasing setting: The graph
861   line, fills, scatters and error bars. Those can be configured via QCPGraph::setAntialiased,
862   QCPGraph::setAntialiasedFill, QCPGraph::setAntialiasedScatters etc. Consequently, there isn't
863   only the QCPGraph::applyDefaultAntialiasingHint function (which corresponds to the graph line's
864   antialiasing), but specialized ones like QCPGraph::applyFillAntialiasingHint and
865   QCPGraph::applyScattersAntialiasingHint. So before drawing one of those entities, QCPGraph::draw
866   calls the respective specialized applyAntialiasingHint function.
867   
868   <b>Second example:</b> QCPItemLine consists only of a line so there is only one antialiasing
869   setting which can be controlled with QCPItemLine::setAntialiased. (This function is inherited by
870   all layerables. The specialized functions, as seen on QCPGraph, must be added explicitly to the
871   respective layerable subclass.) Consequently it only has the normal
872   QCPItemLine::applyDefaultAntialiasingHint. The \ref QCPItemLine::draw function doesn't need to
873   care about setting any antialiasing states, because the default antialiasing hint is already set
874   on the painter when the \ref draw function is called, and that's the state it wants to draw the
875   line with.
876 */
877
878 /*! \fn virtual void QCPLayerable::draw(QCPPainter *painter) const = 0
879   \internal
880   
881   This function draws the layerable with the specified \a painter. It is only called by
882   QCustomPlot, if the layerable is visible (\ref setVisible).
883   
884   Before this function is called, the painter's antialiasing state is set via \ref
885   applyDefaultAntialiasingHint, see the documentation there. Further, the clipping rectangle was
886   set to \ref clipRect.
887 */
888
889 /* end documentation of pure virtual functions */
890 /* start documentation of signals */
891
892 /*! \fn void QCPLayerable::layerChanged(QCPLayer *newLayer);
893   
894   This signal is emitted when the layer of this layerable changes, i.e. this layerable is moved to
895   a different layer.
896   
897   \see setLayer
898 */
899
900 /* end documentation of signals */
901
902 /*!
903   Creates a new QCPLayerable instance.
904   
905   Since QCPLayerable is an abstract base class, it can't be instantiated directly. Use one of the
906   derived classes.
907   
908   If \a plot is provided, it automatically places itself on the layer named \a targetLayer. If \a
909   targetLayer is an empty string, it places itself on the current layer of the plot (see \ref
910   QCustomPlot::setCurrentLayer).
911   
912   It is possible to provide 0 as \a plot. In that case, you should assign a parent plot at a later
913   time with \ref initializeParentPlot.
914   
915   The layerable's parent layerable is set to \a parentLayerable, if provided. Direct layerable
916   parents are mainly used to control visibility in a hierarchy of layerables. This means a
917   layerable is only drawn, if all its ancestor layerables are also visible. Note that \a
918   parentLayerable does not become the QObject-parent (for memory management) of this layerable, \a
919   plot does. It is not uncommon to set the QObject-parent to something else in the constructors of
920   QCPLayerable subclasses, to guarantee a working destruction hierarchy.
921 */
922 QCPLayerable::QCPLayerable(QCustomPlot *plot, QString targetLayer, QCPLayerable *parentLayerable) :
923   QObject(plot),
924   mVisible(true),
925   mParentPlot(plot),
926   mParentLayerable(parentLayerable),
927   mLayer(0),
928   mAntialiased(true)
929 {
930   if (mParentPlot)
931   {
932     if (targetLayer.isEmpty())
933       setLayer(mParentPlot->currentLayer());
934     else if (!setLayer(targetLayer))
935       qDebug() << Q_FUNC_INFO << "setting QCPlayerable initial layer to" << targetLayer << "failed.";
936   }
937 }
938
939 QCPLayerable::~QCPLayerable()
940 {
941   if (mLayer)
942   {
943     mLayer->removeChild(this);
944     mLayer = 0;
945   }
946 }
947
948 /*!
949   Sets the visibility of this layerable object. If an object is not visible, it will not be drawn
950   on the QCustomPlot surface, and user interaction with it (e.g. click and selection) is not
951   possible.
952 */
953 void QCPLayerable::setVisible(bool on)
954 {
955   mVisible = on;
956 }
957
958 /*!
959   Sets the \a layer of this layerable object. The object will be placed on top of the other objects
960   already on \a layer.
961   
962   If \a layer is 0, this layerable will not be on any layer and thus not appear in the plot (or
963   interact/receive events).
964   
965   Returns true if the layer of this layerable was successfully changed to \a layer.
966 */
967 bool QCPLayerable::setLayer(QCPLayer *layer)
968 {
969   return moveToLayer(layer, false);
970 }
971
972 /*! \overload
973   Sets the layer of this layerable object by name
974   
975   Returns true on success, i.e. if \a layerName is a valid layer name.
976 */
977 bool QCPLayerable::setLayer(const QString &layerName)
978 {
979   if (!mParentPlot)
980   {
981     qDebug() << Q_FUNC_INFO << "no parent QCustomPlot set";
982     return false;
983   }
984   if (QCPLayer *layer = mParentPlot->layer(layerName))
985   {
986     return setLayer(layer);
987   } else
988   {
989     qDebug() << Q_FUNC_INFO << "there is no layer with name" << layerName;
990     return false;
991   }
992 }
993
994 /*!
995   Sets whether this object will be drawn antialiased or not.
996   
997   Note that antialiasing settings may be overridden by QCustomPlot::setAntialiasedElements and
998   QCustomPlot::setNotAntialiasedElements.
999 */
1000 void QCPLayerable::setAntialiased(bool enabled)
1001 {
1002   mAntialiased = enabled;
1003 }
1004
1005 /*!
1006   Returns whether this layerable is visible, taking the visibility of the layerable parent and the
1007   visibility of the layer this layerable is on into account. This is the method that is consulted
1008   to decide whether a layerable shall be drawn or not.
1009   
1010   If this layerable has a direct layerable parent (usually set via hierarchies implemented in
1011   subclasses, like in the case of QCPLayoutElement), this function returns true only if this
1012   layerable has its visibility set to true and the parent layerable's \ref realVisibility returns
1013   true.
1014   
1015   If this layerable doesn't have a direct layerable parent, returns the state of this layerable's
1016   visibility.
1017 */
1018 bool QCPLayerable::realVisibility() const
1019 {
1020   return mVisible && (!mLayer || mLayer->visible()) && (!mParentLayerable || mParentLayerable.data()->realVisibility());
1021 }
1022
1023 /*!
1024   This function is used to decide whether a click hits a layerable object or not.
1025
1026   \a pos is a point in pixel coordinates on the QCustomPlot surface. This function returns the
1027   shortest pixel distance of this point to the object. If the object is either invisible or the
1028   distance couldn't be determined, -1.0 is returned. Further, if \a onlySelectable is true and the
1029   object is not selectable, -1.0 is returned, too.
1030
1031   If the object is represented not by single lines but by an area like a \ref QCPItemText or the
1032   bars of a \ref QCPBars plottable, a click inside the area should also be considered a hit. In
1033   these cases this function thus returns a constant value greater zero but still below the parent
1034   plot's selection tolerance. (typically the selectionTolerance multiplied by 0.99).
1035   
1036   Providing a constant value for area objects allows selecting line objects even when they are
1037   obscured by such area objects, by clicking close to the lines (i.e. closer than
1038   0.99*selectionTolerance).
1039   
1040   The actual setting of the selection state is not done by this function. This is handled by the
1041   parent QCustomPlot when the mouseReleaseEvent occurs, and the finally selected object is notified
1042   via the selectEvent/deselectEvent methods.
1043   
1044   \a details is an optional output parameter. Every layerable subclass may place any information
1045   in \a details. This information will be passed to \ref selectEvent when the parent QCustomPlot
1046   decides on the basis of this selectTest call, that the object was successfully selected. The
1047   subsequent call to \ref selectEvent will carry the \a details. This is useful for multi-part
1048   objects (like QCPAxis). This way, a possibly complex calculation to decide which part was clicked
1049   is only done once in \ref selectTest. The result (i.e. the actually clicked part) can then be
1050   placed in \a details. So in the subsequent \ref selectEvent, the decision which part was
1051   selected doesn't have to be done a second time for a single selection operation.
1052   
1053   You may pass 0 as \a details to indicate that you are not interested in those selection details.
1054   
1055   \see selectEvent, deselectEvent, QCustomPlot::setInteractions
1056 */
1057 double QCPLayerable::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
1058 {
1059   Q_UNUSED(pos)
1060   Q_UNUSED(onlySelectable)
1061   Q_UNUSED(details)
1062   return -1.0;
1063 }
1064
1065 /*! \internal
1066   
1067   Sets the parent plot of this layerable. Use this function once to set the parent plot if you have
1068   passed 0 in the constructor. It can not be used to move a layerable from one QCustomPlot to
1069   another one.
1070   
1071   Note that, unlike when passing a non-null parent plot in the constructor, this function does not
1072   make \a parentPlot the QObject-parent of this layerable. If you want this, call
1073   QObject::setParent(\a parentPlot) in addition to this function.
1074   
1075   Further, you will probably want to set a layer (\ref setLayer) after calling this function, to
1076   make the layerable appear on the QCustomPlot.
1077   
1078   The parent plot change will be propagated to subclasses via a call to \ref parentPlotInitialized
1079   so they can react accordingly (e.g. also initialize the parent plot of child layerables, like
1080   QCPLayout does).
1081 */
1082 void QCPLayerable::initializeParentPlot(QCustomPlot *parentPlot)
1083 {
1084   if (mParentPlot)
1085   {
1086     qDebug() << Q_FUNC_INFO << "called with mParentPlot already initialized";
1087     return;
1088   }
1089   
1090   if (!parentPlot)
1091     qDebug() << Q_FUNC_INFO << "called with parentPlot zero";
1092   
1093   mParentPlot = parentPlot;
1094   parentPlotInitialized(mParentPlot);
1095 }
1096
1097 /*! \internal
1098   
1099   Sets the parent layerable of this layerable to \a parentLayerable. Note that \a parentLayerable does not
1100   become the QObject-parent (for memory management) of this layerable.
1101   
1102   The parent layerable has influence on the return value of the \ref realVisibility method. Only
1103   layerables with a fully visible parent tree will return true for \ref realVisibility, and thus be
1104   drawn.
1105   
1106   \see realVisibility
1107 */
1108 void QCPLayerable::setParentLayerable(QCPLayerable *parentLayerable)
1109 {
1110   mParentLayerable = parentLayerable;
1111 }
1112
1113 /*! \internal
1114   
1115   Moves this layerable object to \a layer. If \a prepend is true, this object will be prepended to
1116   the new layer's list, i.e. it will be drawn below the objects already on the layer. If it is
1117   false, the object will be appended.
1118   
1119   Returns true on success, i.e. if \a layer is a valid layer.
1120 */
1121 bool QCPLayerable::moveToLayer(QCPLayer *layer, bool prepend)
1122 {
1123   if (layer && !mParentPlot)
1124   {
1125     qDebug() << Q_FUNC_INFO << "no parent QCustomPlot set";
1126     return false;
1127   }
1128   if (layer && layer->parentPlot() != mParentPlot)
1129   {
1130     qDebug() << Q_FUNC_INFO << "layer" << layer->name() << "is not in same QCustomPlot as this layerable";
1131     return false;
1132   }
1133   
1134   QCPLayer *oldLayer = mLayer;
1135   if (mLayer)
1136     mLayer->removeChild(this);
1137   mLayer = layer;
1138   if (mLayer)
1139     mLayer->addChild(this, prepend);
1140   if (mLayer != oldLayer)
1141     emit layerChanged(mLayer);
1142   return true;
1143 }
1144
1145 /*! \internal
1146
1147   Sets the QCPainter::setAntialiasing state on the provided \a painter, depending on the \a
1148   localAntialiased value as well as the overrides \ref QCustomPlot::setAntialiasedElements and \ref
1149   QCustomPlot::setNotAntialiasedElements. Which override enum this function takes into account is
1150   controlled via \a overrideElement.
1151 */
1152 void QCPLayerable::applyAntialiasingHint(QCPPainter *painter, bool localAntialiased, QCP::AntialiasedElement overrideElement) const
1153 {
1154   if (mParentPlot && mParentPlot->notAntialiasedElements().testFlag(overrideElement))
1155     painter->setAntialiasing(false);
1156   else if (mParentPlot && mParentPlot->antialiasedElements().testFlag(overrideElement))
1157     painter->setAntialiasing(true);
1158   else
1159     painter->setAntialiasing(localAntialiased);
1160 }
1161
1162 /*! \internal
1163
1164   This function is called by \ref initializeParentPlot, to allow subclasses to react on the setting
1165   of a parent plot. This is the case when 0 was passed as parent plot in the constructor, and the
1166   parent plot is set at a later time.
1167   
1168   For example, QCPLayoutElement/QCPLayout hierarchies may be created independently of any
1169   QCustomPlot at first. When they are then added to a layout inside the QCustomPlot, the top level
1170   element of the hierarchy gets its parent plot initialized with \ref initializeParentPlot. To
1171   propagate the parent plot to all the children of the hierarchy, the top level element then uses
1172   this function to pass the parent plot on to its child elements.
1173   
1174   The default implementation does nothing.
1175   
1176   \see initializeParentPlot
1177 */
1178 void QCPLayerable::parentPlotInitialized(QCustomPlot *parentPlot)
1179 {
1180    Q_UNUSED(parentPlot)
1181 }
1182
1183 /*! \internal
1184
1185   Returns the selection category this layerable shall belong to. The selection category is used in
1186   conjunction with \ref QCustomPlot::setInteractions to control which objects are selectable and
1187   which aren't.
1188   
1189   Subclasses that don't fit any of the normal \ref QCP::Interaction values can use \ref
1190   QCP::iSelectOther. This is what the default implementation returns.
1191   
1192   \see QCustomPlot::setInteractions
1193 */
1194 QCP::Interaction QCPLayerable::selectionCategory() const
1195 {
1196   return QCP::iSelectOther;
1197 }
1198
1199 /*! \internal
1200   
1201   Returns the clipping rectangle of this layerable object. By default, this is the viewport of the
1202   parent QCustomPlot. Specific subclasses may reimplement this function to provide different
1203   clipping rects.
1204   
1205   The returned clipping rect is set on the painter before the draw function of the respective
1206   object is called.
1207 */
1208 QRect QCPLayerable::clipRect() const
1209 {
1210   if (mParentPlot)
1211     return mParentPlot->viewport();
1212   else
1213     return QRect();
1214 }
1215
1216 /*! \internal
1217   
1218   This event is called when the layerable shall be selected, as a consequence of a click by the
1219   user. Subclasses should react to it by setting their selection state appropriately. The default
1220   implementation does nothing.
1221   
1222   \a event is the mouse event that caused the selection. \a additive indicates, whether the user
1223   was holding the multi-select-modifier while performing the selection (see \ref
1224   QCustomPlot::setMultiSelectModifier). if \a additive is true, the selection state must be toggled
1225   (i.e. become selected when unselected and unselected when selected).
1226   
1227   Every selectEvent is preceded by a call to \ref selectTest, which has returned positively (i.e.
1228   returned a value greater than 0 and less than the selection tolerance of the parent QCustomPlot).
1229   The \a details data you output from \ref selectTest is fed back via \a details here. You may
1230   use it to transport any kind of information from the selectTest to the possibly subsequent
1231   selectEvent. Usually \a details is used to transfer which part was clicked, if it is a layerable
1232   that has multiple individually selectable parts (like QCPAxis). This way selectEvent doesn't need
1233   to do the calculation again to find out which part was actually clicked.
1234   
1235   \a selectionStateChanged is an output parameter. If the pointer is non-null, this function must
1236   set the value either to true or false, depending on whether the selection state of this layerable
1237   was actually changed. For layerables that only are selectable as a whole and not in parts, this
1238   is simple: if \a additive is true, \a selectionStateChanged must also be set to true, because the
1239   selection toggles. If \a additive is false, \a selectionStateChanged is only set to true, if the
1240   layerable was previously unselected and now is switched to the selected state.
1241   
1242   \see selectTest, deselectEvent
1243 */
1244 void QCPLayerable::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged)
1245 {
1246   Q_UNUSED(event)
1247   Q_UNUSED(additive)
1248   Q_UNUSED(details)
1249   Q_UNUSED(selectionStateChanged)
1250 }
1251
1252 /*! \internal
1253   
1254   This event is called when the layerable shall be deselected, either as consequence of a user
1255   interaction or a call to \ref QCustomPlot::deselectAll. Subclasses should react to it by
1256   unsetting their selection appropriately.
1257   
1258   just as in \ref selectEvent, the output parameter \a selectionStateChanged (if non-null), must
1259   return true or false when the selection state of this layerable has changed or not changed,
1260   respectively.
1261   
1262   \see selectTest, selectEvent
1263 */
1264 void QCPLayerable::deselectEvent(bool *selectionStateChanged)
1265 {
1266   Q_UNUSED(selectionStateChanged)
1267 }
1268
1269
1270 ////////////////////////////////////////////////////////////////////////////////////////////////////
1271 //////////////////// QCPRange
1272 ////////////////////////////////////////////////////////////////////////////////////////////////////
1273 /*! \class QCPRange
1274   \brief Represents the range an axis is encompassing.
1275   
1276   contains a \a lower and \a upper double value and provides convenience input, output and
1277   modification functions.
1278   
1279   \see QCPAxis::setRange
1280 */
1281
1282 /*!
1283   Minimum range size (\a upper - \a lower) the range changing functions will accept. Smaller
1284   intervals would cause errors due to the 11-bit exponent of double precision numbers,
1285   corresponding to a minimum magnitude of roughly 1e-308.
1286   \see validRange, maxRange
1287 */
1288 const double QCPRange::minRange = 1e-280;
1289
1290 /*!
1291   Maximum values (negative and positive) the range will accept in range-changing functions.
1292   Larger absolute values would cause errors due to the 11-bit exponent of double precision numbers,
1293   corresponding to a maximum magnitude of roughly 1e308.
1294   Since the number of planck-volumes in the entire visible universe is only ~1e183, this should
1295   be enough.
1296   \see validRange, minRange
1297 */
1298 const double QCPRange::maxRange = 1e250;
1299
1300 /*!
1301   Constructs a range with \a lower and \a upper set to zero.
1302 */
1303 QCPRange::QCPRange() :
1304   lower(0),
1305   upper(0)
1306 {
1307 }
1308
1309 /*! \overload
1310   Constructs a range with the specified \a lower and \a upper values.
1311 */
1312 QCPRange::QCPRange(double lower, double upper) :
1313   lower(lower),
1314   upper(upper)
1315 {
1316   normalize();
1317 }
1318
1319 /*!
1320   Returns the size of the range, i.e. \a upper-\a lower
1321 */
1322 double QCPRange::size() const
1323 {
1324   return upper-lower;
1325 }
1326
1327 /*!
1328   Returns the center of the range, i.e. (\a upper+\a lower)*0.5
1329 */
1330 double QCPRange::center() const
1331 {
1332   return (upper+lower)*0.5;
1333 }
1334
1335 /*!
1336   Makes sure \a lower is numerically smaller than \a upper. If this is not the case, the values
1337   are swapped.
1338 */
1339 void QCPRange::normalize()
1340 {
1341   if (lower > upper)
1342     qSwap(lower, upper);
1343 }
1344
1345 /*!
1346   Expands this range such that \a otherRange is contained in the new range. It is assumed that both
1347   this range and \a otherRange are normalized (see \ref normalize).
1348   
1349   If \a otherRange is already inside the current range, this function does nothing.
1350   
1351   \see expanded
1352 */
1353 void QCPRange::expand(const QCPRange &otherRange)
1354 {
1355   if (lower > otherRange.lower)
1356     lower = otherRange.lower;
1357   if (upper < otherRange.upper)
1358     upper = otherRange.upper;
1359 }
1360
1361
1362 /*!
1363   Returns an expanded range that contains this and \a otherRange. It is assumed that both this
1364   range and \a otherRange are normalized (see \ref normalize).
1365   
1366   \see expand
1367 */
1368 QCPRange QCPRange::expanded(const QCPRange &otherRange) const
1369 {
1370   QCPRange result = *this;
1371   result.expand(otherRange);
1372   return result;
1373 }
1374
1375 /*!
1376   Returns a sanitized version of the range. Sanitized means for logarithmic scales, that
1377   the range won't span the positive and negative sign domain, i.e. contain zero. Further
1378   \a lower will always be numerically smaller (or equal) to \a upper.
1379   
1380   If the original range does span positive and negative sign domains or contains zero,
1381   the returned range will try to approximate the original range as good as possible.
1382   If the positive interval of the original range is wider than the negative interval, the
1383   returned range will only contain the positive interval, with lower bound set to \a rangeFac or
1384   \a rangeFac *\a upper, whichever is closer to zero. Same procedure is used if the negative interval
1385   is wider than the positive interval, this time by changing the \a upper bound.
1386 */
1387 QCPRange QCPRange::sanitizedForLogScale() const
1388 {
1389   double rangeFac = 1e-3;
1390   QCPRange sanitizedRange(lower, upper);
1391   sanitizedRange.normalize();
1392   // can't have range spanning negative and positive values in log plot, so change range to fix it
1393   //if (qFuzzyCompare(sanitizedRange.lower+1, 1) && !qFuzzyCompare(sanitizedRange.upper+1, 1))
1394   if (sanitizedRange.lower == 0.0 && sanitizedRange.upper != 0.0)
1395   {
1396     // case lower is 0
1397     if (rangeFac < sanitizedRange.upper*rangeFac)
1398       sanitizedRange.lower = rangeFac;
1399     else
1400       sanitizedRange.lower = sanitizedRange.upper*rangeFac;
1401   } //else if (!qFuzzyCompare(lower+1, 1) && qFuzzyCompare(upper+1, 1))
1402   else if (sanitizedRange.lower != 0.0 && sanitizedRange.upper == 0.0)
1403   {
1404     // case upper is 0
1405     if (-rangeFac > sanitizedRange.lower*rangeFac)
1406       sanitizedRange.upper = -rangeFac;
1407     else
1408       sanitizedRange.upper = sanitizedRange.lower*rangeFac;
1409   } else if (sanitizedRange.lower < 0 && sanitizedRange.upper > 0)
1410   {
1411     // find out whether negative or positive interval is wider to decide which sign domain will be chosen
1412     if (-sanitizedRange.lower > sanitizedRange.upper)
1413     {
1414       // negative is wider, do same as in case upper is 0
1415       if (-rangeFac > sanitizedRange.lower*rangeFac)
1416         sanitizedRange.upper = -rangeFac;
1417       else
1418         sanitizedRange.upper = sanitizedRange.lower*rangeFac;
1419     } else
1420     {
1421       // positive is wider, do same as in case lower is 0
1422       if (rangeFac < sanitizedRange.upper*rangeFac)
1423         sanitizedRange.lower = rangeFac;
1424       else
1425         sanitizedRange.lower = sanitizedRange.upper*rangeFac;
1426     }
1427   }
1428   // due to normalization, case lower>0 && upper<0 should never occur, because that implies upper<lower
1429   return sanitizedRange;
1430 }
1431
1432 /*!
1433   Returns a sanitized version of the range. Sanitized means for linear scales, that
1434   \a lower will always be numerically smaller (or equal) to \a upper.
1435 */
1436 QCPRange QCPRange::sanitizedForLinScale() const
1437 {
1438   QCPRange sanitizedRange(lower, upper);
1439   sanitizedRange.normalize();
1440   return sanitizedRange;
1441 }
1442
1443 /*!
1444   Returns true when \a value lies within or exactly on the borders of the range.
1445 */
1446 bool QCPRange::contains(double value) const
1447 {
1448   return value >= lower && value <= upper;
1449 }
1450
1451 /*!
1452   Checks, whether the specified range is within valid bounds, which are defined
1453   as QCPRange::maxRange and QCPRange::minRange.
1454   A valid range means:
1455   \li range bounds within -maxRange and maxRange
1456   \li range size above minRange
1457   \li range size below maxRange
1458 */
1459 bool QCPRange::validRange(double lower, double upper)
1460 {
1461   return (lower > -maxRange &&
1462           upper < maxRange &&
1463           qAbs(lower-upper) > minRange &&
1464           qAbs(lower-upper) < maxRange &&
1465           !(lower > 0 && qIsInf(upper/lower)) &&
1466           !(upper < 0 && qIsInf(lower/upper)));
1467 }
1468
1469 /*!
1470   \overload
1471   Checks, whether the specified range is within valid bounds, which are defined
1472   as QCPRange::maxRange and QCPRange::minRange.
1473   A valid range means:
1474   \li range bounds within -maxRange and maxRange
1475   \li range size above minRange
1476   \li range size below maxRange
1477 */
1478 bool QCPRange::validRange(const QCPRange &range)
1479 {
1480   return (range.lower > -maxRange &&
1481           range.upper < maxRange &&
1482           qAbs(range.lower-range.upper) > minRange &&
1483           qAbs(range.lower-range.upper) < maxRange &&
1484           !(range.lower > 0 && qIsInf(range.upper/range.lower)) &&
1485           !(range.upper < 0 && qIsInf(range.lower/range.upper)));
1486 }
1487
1488
1489 ////////////////////////////////////////////////////////////////////////////////////////////////////
1490 //////////////////// QCPMarginGroup
1491 ////////////////////////////////////////////////////////////////////////////////////////////////////
1492
1493 /*! \class QCPMarginGroup
1494   \brief A margin group allows synchronization of margin sides if working with multiple layout elements.
1495   
1496   QCPMarginGroup allows you to tie a margin side of two or more layout elements together, such that
1497   they will all have the same size, based on the largest required margin in the group.
1498   
1499   \n
1500   \image html QCPMarginGroup.png "Demonstration of QCPMarginGroup"
1501   \n
1502   
1503   In certain situations it is desirable that margins at specific sides are synchronized across
1504   layout elements. For example, if one QCPAxisRect is below another one in a grid layout, it will
1505   provide a cleaner look to the user if the left and right margins of the two axis rects are of the
1506   same size. The left axis of the top axis rect will then be at the same horizontal position as the
1507   left axis of the lower axis rect, making them appear aligned. The same applies for the right
1508   axes. This is what QCPMarginGroup makes possible.
1509   
1510   To add/remove a specific side of a layout element to/from a margin group, use the \ref
1511   QCPLayoutElement::setMarginGroup method. To completely break apart the margin group, either call
1512   \ref clear, or just delete the margin group.
1513   
1514   \section QCPMarginGroup-example Example
1515   
1516   First create a margin group:
1517   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpmargingroup-creation-1
1518   Then set this group on the layout element sides:
1519   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpmargingroup-creation-2
1520   Here, we've used the first two axis rects of the plot and synchronized their left margins with
1521   each other and their right margins with each other.
1522 */
1523
1524 /* start documentation of inline functions */
1525
1526 /*! \fn QList<QCPLayoutElement*> QCPMarginGroup::elements(QCP::MarginSide side) const
1527   
1528   Returns a list of all layout elements that have their margin \a side associated with this margin
1529   group.
1530 */
1531
1532 /* end documentation of inline functions */
1533
1534 /*!
1535   Creates a new QCPMarginGroup instance in \a parentPlot.
1536 */
1537 QCPMarginGroup::QCPMarginGroup(QCustomPlot *parentPlot) :
1538   QObject(parentPlot),
1539   mParentPlot(parentPlot)
1540 {
1541   mChildren.insert(QCP::msLeft, QList<QCPLayoutElement*>());
1542   mChildren.insert(QCP::msRight, QList<QCPLayoutElement*>());
1543   mChildren.insert(QCP::msTop, QList<QCPLayoutElement*>());
1544   mChildren.insert(QCP::msBottom, QList<QCPLayoutElement*>());
1545 }
1546
1547 QCPMarginGroup::~QCPMarginGroup()
1548 {
1549   clear();
1550 }
1551
1552 /*!
1553   Returns whether this margin group is empty. If this function returns true, no layout elements use
1554   this margin group to synchronize margin sides.
1555 */
1556 bool QCPMarginGroup::isEmpty() const
1557 {
1558   QHashIterator<QCP::MarginSide, QList<QCPLayoutElement*> > it(mChildren);
1559   while (it.hasNext())
1560   {
1561     it.next();
1562     if (!it.value().isEmpty())
1563       return false;
1564   }
1565   return true;
1566 }
1567
1568 /*!
1569   Clears this margin group. The synchronization of the margin sides that use this margin group is
1570   lifted and they will use their individual margin sizes again.
1571 */
1572 void QCPMarginGroup::clear()
1573 {
1574   // make all children remove themselves from this margin group:
1575   QHashIterator<QCP::MarginSide, QList<QCPLayoutElement*> > it(mChildren);
1576   while (it.hasNext())
1577   {
1578     it.next();
1579     const QList<QCPLayoutElement*> elements = it.value();
1580     for (int i=elements.size()-1; i>=0; --i)
1581       elements.at(i)->setMarginGroup(it.key(), 0); // removes itself from mChildren via removeChild
1582   }
1583 }
1584
1585 /*! \internal
1586   
1587   Returns the synchronized common margin for \a side. This is the margin value that will be used by
1588   the layout element on the respective side, if it is part of this margin group.
1589   
1590   The common margin is calculated by requesting the automatic margin (\ref
1591   QCPLayoutElement::calculateAutoMargin) of each element associated with \a side in this margin
1592   group, and choosing the largest returned value. (QCPLayoutElement::minimumMargins is taken into
1593   account, too.)
1594 */
1595 int QCPMarginGroup::commonMargin(QCP::MarginSide side) const
1596 {
1597   // query all automatic margins of the layout elements in this margin group side and find maximum:
1598   int result = 0;
1599   const QList<QCPLayoutElement*> elements = mChildren.value(side);
1600   for (int i=0; i<elements.size(); ++i)
1601   {
1602     if (!elements.at(i)->autoMargins().testFlag(side))
1603       continue;
1604     int m = qMax(elements.at(i)->calculateAutoMargin(side), QCP::getMarginValue(elements.at(i)->minimumMargins(), side));
1605     if (m > result)
1606       result = m;
1607   }
1608   return result;
1609 }
1610
1611 /*! \internal
1612   
1613   Adds \a element to the internal list of child elements, for the margin \a side.
1614   
1615   This function does not modify the margin group property of \a element.
1616 */
1617 void QCPMarginGroup::addChild(QCP::MarginSide side, QCPLayoutElement *element)
1618 {
1619   if (!mChildren[side].contains(element))
1620     mChildren[side].append(element);
1621   else
1622     qDebug() << Q_FUNC_INFO << "element is already child of this margin group side" << reinterpret_cast<quintptr>(element);
1623 }
1624
1625 /*! \internal
1626   
1627   Removes \a element from the internal list of child elements, for the margin \a side.
1628   
1629   This function does not modify the margin group property of \a element.
1630 */
1631 void QCPMarginGroup::removeChild(QCP::MarginSide side, QCPLayoutElement *element)
1632 {
1633   if (!mChildren[side].removeOne(element))
1634     qDebug() << Q_FUNC_INFO << "element is not child of this margin group side" << reinterpret_cast<quintptr>(element);
1635 }
1636
1637
1638 ////////////////////////////////////////////////////////////////////////////////////////////////////
1639 //////////////////// QCPLayoutElement
1640 ////////////////////////////////////////////////////////////////////////////////////////////////////
1641
1642 /*! \class QCPLayoutElement
1643   \brief The abstract base class for all objects that form \ref thelayoutsystem "the layout system".
1644   
1645   This is an abstract base class. As such, it can't be instantiated directly, rather use one of its subclasses.
1646   
1647   A Layout element is a rectangular object which can be placed in layouts. It has an outer rect
1648   (QCPLayoutElement::outerRect) and an inner rect (\ref QCPLayoutElement::rect). The difference
1649   between outer and inner rect is called its margin. The margin can either be set to automatic or
1650   manual (\ref setAutoMargins) on a per-side basis. If a side is set to manual, that margin can be
1651   set explicitly with \ref setMargins and will stay fixed at that value. If it's set to automatic,
1652   the layout element subclass will control the value itself (via \ref calculateAutoMargin).
1653   
1654   Layout elements can be placed in layouts (base class QCPLayout) like QCPLayoutGrid. The top level
1655   layout is reachable via \ref QCustomPlot::plotLayout, and is a \ref QCPLayoutGrid. Since \ref
1656   QCPLayout itself derives from \ref QCPLayoutElement, layouts can be nested.
1657   
1658   Thus in QCustomPlot one can divide layout elements into two categories: The ones that are
1659   invisible by themselves, because they don't draw anything. Their only purpose is to manage the
1660   position and size of other layout elements. This category of layout elements usually use
1661   QCPLayout as base class. Then there is the category of layout elements which actually draw
1662   something. For example, QCPAxisRect, QCPLegend and QCPPlotTitle are of this category. This does
1663   not necessarily mean that the latter category can't have child layout elements. QCPLegend for
1664   instance, actually derives from QCPLayoutGrid and the individual legend items are child layout
1665   elements in the grid layout.
1666 */
1667
1668 /* start documentation of inline functions */
1669
1670 /*! \fn QCPLayout *QCPLayoutElement::layout() const
1671   
1672   Returns the parent layout of this layout element.
1673 */
1674
1675 /*! \fn QRect QCPLayoutElement::rect() const
1676   
1677   Returns the inner rect of this layout element. The inner rect is the outer rect (\ref
1678   setOuterRect) shrinked by the margins (\ref setMargins, \ref setAutoMargins).
1679   
1680   In some cases, the area between outer and inner rect is left blank. In other cases the margin
1681   area is used to display peripheral graphics while the main content is in the inner rect. This is
1682   where automatic margin calculation becomes interesting because it allows the layout element to
1683   adapt the margins to the peripheral graphics it wants to draw. For example, \ref QCPAxisRect
1684   draws the axis labels and tick labels in the margin area, thus needs to adjust the margins (if
1685   \ref setAutoMargins is enabled) according to the space required by the labels of the axes.
1686 */
1687
1688 /*! \fn virtual void QCPLayoutElement::mousePressEvent(QMouseEvent *event)
1689   
1690   This event is called, if the mouse was pressed while being inside the outer rect of this layout
1691   element.
1692 */
1693
1694 /*! \fn virtual void QCPLayoutElement::mouseMoveEvent(QMouseEvent *event)
1695   
1696   This event is called, if the mouse is moved inside the outer rect of this layout element.
1697 */
1698
1699 /*! \fn virtual void QCPLayoutElement::mouseReleaseEvent(QMouseEvent *event)
1700   
1701   This event is called, if the mouse was previously pressed inside the outer rect of this layout
1702   element and is now released.
1703 */
1704
1705 /*! \fn virtual void QCPLayoutElement::mouseDoubleClickEvent(QMouseEvent *event)
1706   
1707   This event is called, if the mouse is double-clicked inside the outer rect of this layout
1708   element.
1709 */
1710
1711 /*! \fn virtual void QCPLayoutElement::wheelEvent(QWheelEvent *event)
1712   
1713   This event is called, if the mouse wheel is scrolled while the cursor is inside the rect of this
1714   layout element.
1715 */
1716
1717 /* end documentation of inline functions */
1718
1719 /*!
1720   Creates an instance of QCPLayoutElement and sets default values.
1721 */
1722 QCPLayoutElement::QCPLayoutElement(QCustomPlot *parentPlot) :
1723   QCPLayerable(parentPlot), // parenthood is changed as soon as layout element gets inserted into a layout (except for top level layout)
1724   mParentLayout(0),
1725   mMinimumSize(),
1726   mMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX),
1727   mRect(0, 0, 0, 0),
1728   mOuterRect(0, 0, 0, 0),
1729   mMargins(0, 0, 0, 0),
1730   mMinimumMargins(0, 0, 0, 0),
1731   mAutoMargins(QCP::msAll)
1732 {
1733 }
1734
1735 QCPLayoutElement::~QCPLayoutElement()
1736 {
1737   setMarginGroup(QCP::msAll, 0); // unregister at margin groups, if there are any
1738   // unregister at layout:
1739   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
1740     mParentLayout->take(this);
1741 }
1742
1743 /*!
1744   Sets the outer rect of this layout element. If the layout element is inside a layout, the layout
1745   sets the position and size of this layout element using this function.
1746   
1747   Calling this function externally has no effect, since the layout will overwrite any changes to
1748   the outer rect upon the next replot.
1749   
1750   The layout element will adapt its inner \ref rect by applying the margins inward to the outer rect.
1751   
1752   \see rect
1753 */
1754 void QCPLayoutElement::setOuterRect(const QRect &rect)
1755 {
1756   if (mOuterRect != rect)
1757   {
1758     mOuterRect = rect;
1759     mRect = mOuterRect.adjusted(mMargins.left(), mMargins.top(), -mMargins.right(), -mMargins.bottom());
1760   }
1761 }
1762
1763 /*!
1764   Sets the margins of this layout element. If \ref setAutoMargins is disabled for some or all
1765   sides, this function is used to manually set the margin on those sides. Sides that are still set
1766   to be handled automatically are ignored and may have any value in \a margins.
1767   
1768   The margin is the distance between the outer rect (controlled by the parent layout via \ref
1769   setOuterRect) and the inner \ref rect (which usually contains the main content of this layout
1770   element).
1771   
1772   \see setAutoMargins
1773 */
1774 void QCPLayoutElement::setMargins(const QMargins &margins)
1775 {
1776   if (mMargins != margins)
1777   {
1778     mMargins = margins;
1779     mRect = mOuterRect.adjusted(mMargins.left(), mMargins.top(), -mMargins.right(), -mMargins.bottom());
1780   }
1781 }
1782
1783 /*!
1784   If \ref setAutoMargins is enabled on some or all margins, this function is used to provide
1785   minimum values for those margins.
1786   
1787   The minimum values are not enforced on margin sides that were set to be under manual control via
1788   \ref setAutoMargins.
1789   
1790   \see setAutoMargins
1791 */
1792 void QCPLayoutElement::setMinimumMargins(const QMargins &margins)
1793 {
1794   if (mMinimumMargins != margins)
1795   {
1796     mMinimumMargins = margins;
1797   }
1798 }
1799
1800 /*!
1801   Sets on which sides the margin shall be calculated automatically. If a side is calculated
1802   automatically, a minimum margin value may be provided with \ref setMinimumMargins. If a side is
1803   set to be controlled manually, the value may be specified with \ref setMargins.
1804   
1805   Margin sides that are under automatic control may participate in a \ref QCPMarginGroup (see \ref
1806   setMarginGroup), to synchronize (align) it with other layout elements in the plot.
1807   
1808   \see setMinimumMargins, setMargins
1809 */
1810 void QCPLayoutElement::setAutoMargins(QCP::MarginSides sides)
1811 {
1812   mAutoMargins = sides;
1813 }
1814
1815 /*!
1816   Sets the minimum size for the inner \ref rect of this layout element. A parent layout tries to
1817   respect the \a size here by changing row/column sizes in the layout accordingly.
1818   
1819   If the parent layout size is not sufficient to satisfy all minimum size constraints of its child
1820   layout elements, the layout may set a size that is actually smaller than \a size. QCustomPlot
1821   propagates the layout's size constraints to the outside by setting its own minimum QWidget size
1822   accordingly, so violations of \a size should be exceptions.
1823 */
1824 void QCPLayoutElement::setMinimumSize(const QSize &size)
1825 {
1826   if (mMinimumSize != size)
1827   {
1828     mMinimumSize = size;
1829     if (mParentLayout)
1830       mParentLayout->sizeConstraintsChanged();
1831   }
1832 }
1833
1834 /*! \overload
1835   
1836   Sets the minimum size for the inner \ref rect of this layout element.
1837 */
1838 void QCPLayoutElement::setMinimumSize(int width, int height)
1839 {
1840   setMinimumSize(QSize(width, height));
1841 }
1842
1843 /*!
1844   Sets the maximum size for the inner \ref rect of this layout element. A parent layout tries to
1845   respect the \a size here by changing row/column sizes in the layout accordingly.
1846 */
1847 void QCPLayoutElement::setMaximumSize(const QSize &size)
1848 {
1849   if (mMaximumSize != size)
1850   {
1851     mMaximumSize = size;
1852     if (mParentLayout)
1853       mParentLayout->sizeConstraintsChanged();
1854   }
1855 }
1856
1857 /*! \overload
1858   
1859   Sets the maximum size for the inner \ref rect of this layout element.
1860 */
1861 void QCPLayoutElement::setMaximumSize(int width, int height)
1862 {
1863   setMaximumSize(QSize(width, height));
1864 }
1865
1866 /*!
1867   Sets the margin \a group of the specified margin \a sides.
1868   
1869   Margin groups allow synchronizing specified margins across layout elements, see the documentation
1870   of \ref QCPMarginGroup.
1871   
1872   To unset the margin group of \a sides, set \a group to 0.
1873   
1874   Note that margin groups only work for margin sides that are set to automatic (\ref
1875   setAutoMargins).
1876 */
1877 void QCPLayoutElement::setMarginGroup(QCP::MarginSides sides, QCPMarginGroup *group)
1878 {
1879   QVector<QCP::MarginSide> sideVector;
1880   if (sides.testFlag(QCP::msLeft)) sideVector.append(QCP::msLeft);
1881   if (sides.testFlag(QCP::msRight)) sideVector.append(QCP::msRight);
1882   if (sides.testFlag(QCP::msTop)) sideVector.append(QCP::msTop);
1883   if (sides.testFlag(QCP::msBottom)) sideVector.append(QCP::msBottom);
1884   
1885   for (int i=0; i<sideVector.size(); ++i)
1886   {
1887     QCP::MarginSide side = sideVector.at(i);
1888     if (marginGroup(side) != group)
1889     {
1890       QCPMarginGroup *oldGroup = marginGroup(side);
1891       if (oldGroup) // unregister at old group
1892         oldGroup->removeChild(side, this);
1893       
1894       if (!group) // if setting to 0, remove hash entry. Else set hash entry to new group and register there
1895       {
1896         mMarginGroups.remove(side);
1897       } else // setting to a new group
1898       {
1899         mMarginGroups[side] = group;
1900         group->addChild(side, this);
1901       }
1902     }
1903   }
1904 }
1905
1906 /*!
1907   Updates the layout element and sub-elements. This function is automatically called before every
1908   replot by the parent layout element. It is called multiple times, once for every \ref
1909   UpdatePhase. The phases are run through in the order of the enum values. For details about what
1910   happens at the different phases, see the documentation of \ref UpdatePhase.
1911   
1912   Layout elements that have child elements should call the \ref update method of their child
1913   elements, and pass the current \a phase unchanged.
1914   
1915   The default implementation executes the automatic margin mechanism in the \ref upMargins phase.
1916   Subclasses should make sure to call the base class implementation.
1917 */
1918 void QCPLayoutElement::update(UpdatePhase phase)
1919 {
1920   if (phase == upMargins)
1921   {
1922     if (mAutoMargins != QCP::msNone)
1923     {
1924       // set the margins of this layout element according to automatic margin calculation, either directly or via a margin group:
1925       QMargins newMargins = mMargins;
1926       QList<QCP::MarginSide> allMarginSides = QList<QCP::MarginSide>() << QCP::msLeft << QCP::msRight << QCP::msTop << QCP::msBottom;
1927       foreach (QCP::MarginSide side, allMarginSides)
1928       {
1929         if (mAutoMargins.testFlag(side)) // this side's margin shall be calculated automatically
1930         {
1931           if (mMarginGroups.contains(side))
1932             QCP::setMarginValue(newMargins, side, mMarginGroups[side]->commonMargin(side)); // this side is part of a margin group, so get the margin value from that group
1933           else
1934             QCP::setMarginValue(newMargins, side, calculateAutoMargin(side)); // this side is not part of a group, so calculate the value directly
1935           // apply minimum margin restrictions:
1936           if (QCP::getMarginValue(newMargins, side) < QCP::getMarginValue(mMinimumMargins, side))
1937             QCP::setMarginValue(newMargins, side, QCP::getMarginValue(mMinimumMargins, side));
1938         }
1939       }
1940       setMargins(newMargins);
1941     }
1942   }
1943 }
1944
1945 /*!
1946   Returns the minimum size this layout element (the inner \ref rect) may be compressed to.
1947   
1948   if a minimum size (\ref setMinimumSize) was not set manually, parent layouts consult this
1949   function to determine the minimum allowed size of this layout element. (A manual minimum size is
1950   considered set if it is non-zero.)
1951 */
1952 QSize QCPLayoutElement::minimumSizeHint() const
1953 {
1954   return mMinimumSize;
1955 }
1956
1957 /*!
1958   Returns the maximum size this layout element (the inner \ref rect) may be expanded to.
1959   
1960   if a maximum size (\ref setMaximumSize) was not set manually, parent layouts consult this
1961   function to determine the maximum allowed size of this layout element. (A manual maximum size is
1962   considered set if it is smaller than Qt's QWIDGETSIZE_MAX.)
1963 */
1964 QSize QCPLayoutElement::maximumSizeHint() const
1965 {
1966   return mMaximumSize;
1967 }
1968
1969 /*!
1970   Returns a list of all child elements in this layout element. If \a recursive is true, all
1971   sub-child elements are included in the list, too.
1972   
1973   \warning There may be entries with value 0 in the returned list. (For example, QCPLayoutGrid may have
1974   empty cells which yield 0 at the respective index.)
1975 */
1976 QList<QCPLayoutElement*> QCPLayoutElement::elements(bool recursive) const
1977 {
1978   Q_UNUSED(recursive)
1979   return QList<QCPLayoutElement*>();
1980 }
1981
1982 /*!
1983   Layout elements are sensitive to events inside their outer rect. If \a pos is within the outer
1984   rect, this method returns a value corresponding to 0.99 times the parent plot's selection
1985   tolerance. However, layout elements are not selectable by default. So if \a onlySelectable is
1986   true, -1.0 is returned.
1987   
1988   See \ref QCPLayerable::selectTest for a general explanation of this virtual method.
1989   
1990   QCPLayoutElement subclasses may reimplement this method to provide more specific selection test
1991   behaviour.
1992 */
1993 double QCPLayoutElement::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
1994 {
1995   Q_UNUSED(details)
1996   
1997   if (onlySelectable)
1998     return -1;
1999   
2000   if (QRectF(mOuterRect).contains(pos))
2001   {
2002     if (mParentPlot)
2003       return mParentPlot->selectionTolerance()*0.99;
2004     else
2005     {
2006       qDebug() << Q_FUNC_INFO << "parent plot not defined";
2007       return -1;
2008     }
2009   } else
2010     return -1;
2011 }
2012
2013 /*! \internal
2014   
2015   propagates the parent plot initialization to all child elements, by calling \ref
2016   QCPLayerable::initializeParentPlot on them.
2017 */
2018 void QCPLayoutElement::parentPlotInitialized(QCustomPlot *parentPlot)
2019 {
2020   foreach (QCPLayoutElement* el, elements(false))
2021   {
2022     if (!el->parentPlot())
2023       el->initializeParentPlot(parentPlot);
2024   }
2025 }
2026
2027 /*! \internal
2028   
2029   Returns the margin size for this \a side. It is used if automatic margins is enabled for this \a
2030   side (see \ref setAutoMargins). If a minimum margin was set with \ref setMinimumMargins, the
2031   returned value will not be smaller than the specified minimum margin.
2032   
2033   The default implementation just returns the respective manual margin (\ref setMargins) or the
2034   minimum margin, whichever is larger.
2035 */
2036 int QCPLayoutElement::calculateAutoMargin(QCP::MarginSide side)
2037 {
2038   return qMax(QCP::getMarginValue(mMargins, side), QCP::getMarginValue(mMinimumMargins, side));
2039 }
2040
2041 ////////////////////////////////////////////////////////////////////////////////////////////////////
2042 //////////////////// QCPLayout
2043 ////////////////////////////////////////////////////////////////////////////////////////////////////
2044
2045 /*! \class QCPLayout
2046   \brief The abstract base class for layouts
2047   
2048   This is an abstract base class for layout elements whose main purpose is to define the position
2049   and size of other child layout elements. In most cases, layouts don't draw anything themselves
2050   (but there are exceptions to this, e.g. QCPLegend).
2051   
2052   QCPLayout derives from QCPLayoutElement, and thus can itself be nested in other layouts.
2053   
2054   QCPLayout introduces a common interface for accessing and manipulating the child elements. Those
2055   functions are most notably \ref elementCount, \ref elementAt, \ref takeAt, \ref take, \ref
2056   simplify, \ref removeAt, \ref remove and \ref clear. Individual subclasses may add more functions
2057   to this interface which are more specialized to the form of the layout. For example, \ref
2058   QCPLayoutGrid adds functions that take row and column indices to access cells of the layout grid
2059   more conveniently.
2060   
2061   Since this is an abstract base class, you can't instantiate it directly. Rather use one of its
2062   subclasses like QCPLayoutGrid or QCPLayoutInset.
2063   
2064   For a general introduction to the layout system, see the dedicated documentation page \ref
2065   thelayoutsystem "The Layout System".
2066 */
2067
2068 /* start documentation of pure virtual functions */
2069
2070 /*! \fn virtual int QCPLayout::elementCount() const = 0
2071   
2072   Returns the number of elements/cells in the layout.
2073   
2074   \see elements, elementAt
2075 */
2076
2077 /*! \fn virtual QCPLayoutElement* QCPLayout::elementAt(int index) const = 0
2078   
2079   Returns the element in the cell with the given \a index. If \a index is invalid, returns 0.
2080   
2081   Note that even if \a index is valid, the respective cell may be empty in some layouts (e.g.
2082   QCPLayoutGrid), so this function may return 0 in those cases. You may use this function to check
2083   whether a cell is empty or not.
2084   
2085   \see elements, elementCount, takeAt
2086 */
2087
2088 /*! \fn virtual QCPLayoutElement* QCPLayout::takeAt(int index) = 0
2089   
2090   Removes the element with the given \a index from the layout and returns it.
2091   
2092   If the \a index is invalid or the cell with that index is empty, returns 0.
2093   
2094   Note that some layouts don't remove the respective cell right away but leave an empty cell after
2095   successful removal of the layout element. To collapse empty cells, use \ref simplify.
2096   
2097   \see elementAt, take
2098 */
2099
2100 /*! \fn virtual bool QCPLayout::take(QCPLayoutElement* element) = 0
2101   
2102   Removes the specified \a element from the layout and returns true on success.
2103   
2104   If the \a element isn't in this layout, returns false.
2105   
2106   Note that some layouts don't remove the respective cell right away but leave an empty cell after
2107   successful removal of the layout element. To collapse empty cells, use \ref simplify.
2108   
2109   \see takeAt
2110 */
2111
2112 /* end documentation of pure virtual functions */
2113
2114 /*!
2115   Creates an instance of QCPLayout and sets default values. Note that since QCPLayout
2116   is an abstract base class, it can't be instantiated directly.
2117 */
2118 QCPLayout::QCPLayout()
2119 {
2120 }
2121
2122 /*!
2123   First calls the QCPLayoutElement::update base class implementation to update the margins on this
2124   layout.
2125   
2126   Then calls \ref updateLayout which subclasses reimplement to reposition and resize their cells.
2127   
2128   Finally, \ref update is called on all child elements.
2129 */
2130 void QCPLayout::update(UpdatePhase phase)
2131 {
2132   QCPLayoutElement::update(phase);
2133   
2134   // set child element rects according to layout:
2135   if (phase == upLayout)
2136     updateLayout();
2137   
2138   // propagate update call to child elements:
2139   const int elCount = elementCount();
2140   for (int i=0; i<elCount; ++i)
2141   {
2142     if (QCPLayoutElement *el = elementAt(i))
2143       el->update(phase);
2144   }
2145 }
2146
2147 /* inherits documentation from base class */
2148 QList<QCPLayoutElement*> QCPLayout::elements(bool recursive) const
2149 {
2150   const int c = elementCount();
2151   QList<QCPLayoutElement*> result;
2152 #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
2153   result.reserve(c);
2154 #endif
2155   for (int i=0; i<c; ++i)
2156     result.append(elementAt(i));
2157   if (recursive)
2158   {
2159     for (int i=0; i<c; ++i)
2160     {
2161       if (result.at(i))
2162         result << result.at(i)->elements(recursive);
2163     }
2164   }
2165   return result;
2166 }
2167
2168 /*!
2169   Simplifies the layout by collapsing empty cells. The exact behavior depends on subclasses, the
2170   default implementation does nothing.
2171   
2172   Not all layouts need simplification. For example, QCPLayoutInset doesn't use explicit
2173   simplification while QCPLayoutGrid does.
2174 */
2175 void QCPLayout::simplify()
2176 {
2177 }
2178
2179 /*!
2180   Removes and deletes the element at the provided \a index. Returns true on success. If \a index is
2181   invalid or points to an empty cell, returns false.
2182   
2183   This function internally uses \ref takeAt to remove the element from the layout and then deletes
2184   the returned element. Note that some layouts don't remove the respective cell right away but leave an
2185   empty cell after successful removal of the layout element. To collapse empty cells, use \ref
2186   simplify.
2187   
2188   \see remove, takeAt
2189 */
2190 bool QCPLayout::removeAt(int index)
2191 {
2192   if (QCPLayoutElement *el = takeAt(index))
2193   {
2194     delete el;
2195     return true;
2196   } else
2197     return false;
2198 }
2199
2200 /*!
2201   Removes and deletes the provided \a element. Returns true on success. If \a element is not in the
2202   layout, returns false.
2203   
2204   This function internally uses \ref takeAt to remove the element from the layout and then deletes
2205   the element. Note that some layouts don't remove the respective cell right away but leave an
2206   empty cell after successful removal of the layout element. To collapse empty cells, use \ref
2207   simplify.
2208   
2209   \see removeAt, take
2210 */
2211 bool QCPLayout::remove(QCPLayoutElement *element)
2212 {
2213   if (take(element))
2214   {
2215     delete element;
2216     return true;
2217   } else
2218     return false;
2219 }
2220
2221 /*!
2222   Removes and deletes all layout elements in this layout. Finally calls \ref simplify to make sure
2223   all empty cells are collapsed.
2224   
2225   \see remove, removeAt
2226 */
2227 void QCPLayout::clear()
2228 {
2229   for (int i=elementCount()-1; i>=0; --i)
2230   {
2231     if (elementAt(i))
2232       removeAt(i);
2233   }
2234   simplify();
2235 }
2236
2237 /*!
2238   Subclasses call this method to report changed (minimum/maximum) size constraints.
2239   
2240   If the parent of this layout is again a QCPLayout, forwards the call to the parent's \ref
2241   sizeConstraintsChanged. If the parent is a QWidget (i.e. is the \ref QCustomPlot::plotLayout of
2242   QCustomPlot), calls QWidget::updateGeometry, so if the QCustomPlot widget is inside a Qt QLayout,
2243   it may update itself and resize cells accordingly.
2244 */
2245 void QCPLayout::sizeConstraintsChanged() const
2246 {
2247   if (QWidget *w = qobject_cast<QWidget*>(parent()))
2248     w->updateGeometry();
2249   else if (QCPLayout *l = qobject_cast<QCPLayout*>(parent()))
2250     l->sizeConstraintsChanged();
2251 }
2252
2253 /*! \internal
2254   
2255   Subclasses reimplement this method to update the position and sizes of the child elements/cells
2256   via calling their \ref QCPLayoutElement::setOuterRect. The default implementation does nothing.
2257   
2258   The geometry used as a reference is the inner \ref rect of this layout. Child elements should stay
2259   within that rect.
2260   
2261   \ref getSectionSizes may help with the reimplementation of this function.
2262   
2263   \see update
2264 */
2265 void QCPLayout::updateLayout()
2266 {
2267 }
2268
2269
2270 /*! \internal
2271   
2272   Associates \a el with this layout. This is done by setting the \ref QCPLayoutElement::layout, the
2273   \ref QCPLayerable::parentLayerable and the QObject parent to this layout.
2274   
2275   Further, if \a el didn't previously have a parent plot, calls \ref
2276   QCPLayerable::initializeParentPlot on \a el to set the paret plot.
2277   
2278   This method is used by subclass specific methods that add elements to the layout. Note that this
2279   method only changes properties in \a el. The removal from the old layout and the insertion into
2280   the new layout must be done additionally.
2281 */
2282 void QCPLayout::adoptElement(QCPLayoutElement *el)
2283 {
2284   if (el)
2285   {
2286     el->mParentLayout = this;
2287     el->setParentLayerable(this);
2288     el->setParent(this);
2289     if (!el->parentPlot())
2290       el->initializeParentPlot(mParentPlot);
2291   } else
2292     qDebug() << Q_FUNC_INFO << "Null element passed";
2293 }
2294
2295 /*! \internal
2296   
2297   Disassociates \a el from this layout. This is done by setting the \ref QCPLayoutElement::layout
2298   and the \ref QCPLayerable::parentLayerable to zero. The QObject parent is set to the parent
2299   QCustomPlot.
2300   
2301   This method is used by subclass specific methods that remove elements from the layout (e.g. \ref
2302   take or \ref takeAt). Note that this method only changes properties in \a el. The removal from
2303   the old layout must be done additionally.
2304 */
2305 void QCPLayout::releaseElement(QCPLayoutElement *el)
2306 {
2307   if (el)
2308   {
2309     el->mParentLayout = 0;
2310     el->setParentLayerable(0);
2311     el->setParent(mParentPlot);
2312     // Note: Don't initializeParentPlot(0) here, because layout element will stay in same parent plot
2313   } else
2314     qDebug() << Q_FUNC_INFO << "Null element passed";
2315 }
2316
2317 /*! \internal
2318   
2319   This is a helper function for the implementation of \ref updateLayout in subclasses.
2320   
2321   It calculates the sizes of one-dimensional sections with provided constraints on maximum section
2322   sizes, minimum section sizes, relative stretch factors and the final total size of all sections.
2323   
2324   The QVector entries refer to the sections. Thus all QVectors must have the same size.
2325   
2326   \a maxSizes gives the maximum allowed size of each section. If there shall be no maximum size
2327   imposed, set all vector values to Qt's QWIDGETSIZE_MAX.
2328   
2329   \a minSizes gives the minimum allowed size of each section. If there shall be no minimum size
2330   imposed, set all vector values to zero. If the \a minSizes entries add up to a value greater than
2331   \a totalSize, sections will be scaled smaller than the proposed minimum sizes. (In other words,
2332   not exceeding the allowed total size is taken to be more important than not going below minimum
2333   section sizes.)
2334   
2335   \a stretchFactors give the relative proportions of the sections to each other. If all sections
2336   shall be scaled equally, set all values equal. If the first section shall be double the size of
2337   each individual other section, set the first number of \a stretchFactors to double the value of
2338   the other individual values (e.g. {2, 1, 1, 1}).
2339   
2340   \a totalSize is the value that the final section sizes will add up to. Due to rounding, the
2341   actual sum may differ slightly. If you want the section sizes to sum up to exactly that value,
2342   you could distribute the remaining difference on the sections.
2343   
2344   The return value is a QVector containing the section sizes.
2345 */
2346 QVector<int> QCPLayout::getSectionSizes(QVector<int> maxSizes, QVector<int> minSizes, QVector<double> stretchFactors, int totalSize) const
2347 {
2348   if (maxSizes.size() != minSizes.size() || minSizes.size() != stretchFactors.size())
2349   {
2350     qDebug() << Q_FUNC_INFO << "Passed vector sizes aren't equal:" << maxSizes << minSizes << stretchFactors;
2351     return QVector<int>();
2352   }
2353   if (stretchFactors.isEmpty())
2354     return QVector<int>();
2355   int sectionCount = stretchFactors.size();
2356   QVector<double> sectionSizes(sectionCount);
2357   // if provided total size is forced smaller than total minimum size, ignore minimum sizes (squeeze sections):
2358   int minSizeSum = 0;
2359   for (int i=0; i<sectionCount; ++i)
2360     minSizeSum += minSizes.at(i);
2361   if (totalSize < minSizeSum)
2362   {
2363     // new stretch factors are minimum sizes and minimum sizes are set to zero:
2364     for (int i=0; i<sectionCount; ++i)
2365     {
2366       stretchFactors[i] = minSizes.at(i);
2367       minSizes[i] = 0;
2368     }
2369   }
2370   
2371   QList<int> minimumLockedSections;
2372   QList<int> unfinishedSections;
2373   for (int i=0; i<sectionCount; ++i)
2374     unfinishedSections.append(i);
2375   double freeSize = totalSize;
2376   
2377   int outerIterations = 0;
2378   while (!unfinishedSections.isEmpty() && outerIterations < sectionCount*2) // the iteration check ist just a failsafe in case something really strange happens
2379   {
2380     ++outerIterations;
2381     int innerIterations = 0;
2382     while (!unfinishedSections.isEmpty() && innerIterations < sectionCount*2) // the iteration check ist just a failsafe in case something really strange happens
2383     {
2384       ++innerIterations;
2385       // find section that hits its maximum next:
2386       int nextId = -1;
2387       double nextMax = 1e12;
2388       for (int i=0; i<unfinishedSections.size(); ++i)
2389       {
2390         int secId = unfinishedSections.at(i);
2391         double hitsMaxAt = (maxSizes.at(secId)-sectionSizes.at(secId))/stretchFactors.at(secId);
2392         if (hitsMaxAt < nextMax)
2393         {
2394           nextMax = hitsMaxAt;
2395           nextId = secId;
2396         }
2397       }
2398       // 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
2399       // actually hits its maximum, without exceeding the total size when we add up all sections)
2400       double stretchFactorSum = 0;
2401       for (int i=0; i<unfinishedSections.size(); ++i)
2402         stretchFactorSum += stretchFactors.at(unfinishedSections.at(i));
2403       double nextMaxLimit = freeSize/stretchFactorSum;
2404       if (nextMax < nextMaxLimit) // next maximum is actually hit, move forward to that point and fix the size of that section
2405       {
2406         for (int i=0; i<unfinishedSections.size(); ++i)
2407         {
2408           sectionSizes[unfinishedSections.at(i)] += nextMax*stretchFactors.at(unfinishedSections.at(i)); // increment all sections
2409           freeSize -= nextMax*stretchFactors.at(unfinishedSections.at(i));
2410         }
2411         unfinishedSections.removeOne(nextId); // exclude the section that is now at maximum from further changes
2412       } else // next maximum isn't hit, just distribute rest of free space on remaining sections
2413       {
2414         for (int i=0; i<unfinishedSections.size(); ++i)
2415           sectionSizes[unfinishedSections.at(i)] += nextMaxLimit*stretchFactors.at(unfinishedSections.at(i)); // increment all sections
2416         unfinishedSections.clear();
2417       }
2418     }
2419     if (innerIterations == sectionCount*2)
2420       qDebug() << Q_FUNC_INFO << "Exceeded maximum expected inner iteration count, layouting aborted. Input was:" << maxSizes << minSizes << stretchFactors << totalSize;
2421     
2422     // now check whether the resulting section sizes violate minimum restrictions:
2423     bool foundMinimumViolation = false;
2424     for (int i=0; i<sectionSizes.size(); ++i)
2425     {
2426       if (minimumLockedSections.contains(i))
2427         continue;
2428       if (sectionSizes.at(i) < minSizes.at(i)) // section violates minimum
2429       {
2430         sectionSizes[i] = minSizes.at(i); // set it to minimum
2431         foundMinimumViolation = true; // make sure we repeat the whole optimization process
2432         minimumLockedSections.append(i);
2433       }
2434     }
2435     if (foundMinimumViolation)
2436     {
2437       freeSize = totalSize;
2438       for (int i=0; i<sectionCount; ++i)
2439       {
2440         if (!minimumLockedSections.contains(i)) // only put sections that haven't hit their minimum back into the pool
2441           unfinishedSections.append(i);
2442         else
2443           freeSize -= sectionSizes.at(i); // remove size of minimum locked sections from available space in next round
2444       }
2445       // reset all section sizes to zero that are in unfinished sections (all others have been set to their minimum):
2446       for (int i=0; i<unfinishedSections.size(); ++i)
2447         sectionSizes[unfinishedSections.at(i)] = 0;
2448     }
2449   }
2450   if (outerIterations == sectionCount*2)
2451     qDebug() << Q_FUNC_INFO << "Exceeded maximum expected outer iteration count, layouting aborted. Input was:" << maxSizes << minSizes << stretchFactors << totalSize;
2452   
2453   QVector<int> result(sectionCount);
2454   for (int i=0; i<sectionCount; ++i)
2455     result[i] = qRound(sectionSizes.at(i));
2456   return result;
2457 }
2458
2459
2460 ////////////////////////////////////////////////////////////////////////////////////////////////////
2461 //////////////////// QCPLayoutGrid
2462 ////////////////////////////////////////////////////////////////////////////////////////////////////
2463
2464 /*! \class QCPLayoutGrid
2465   \brief A layout that arranges child elements in a grid
2466   
2467   Elements are laid out in a grid with configurable stretch factors (\ref setColumnStretchFactor,
2468   \ref setRowStretchFactor) and spacing (\ref setColumnSpacing, \ref setRowSpacing).
2469   
2470   Elements can be added to cells via \ref addElement. The grid is expanded if the specified row or
2471   column doesn't exist yet. Whether a cell contains a valid layout element can be checked with \ref
2472   hasElement, that element can be retrieved with \ref element. If rows and columns that only have
2473   empty cells shall be removed, call \ref simplify. Removal of elements is either done by just
2474   adding the element to a different layout or by using the QCPLayout interface \ref take or \ref
2475   remove.
2476   
2477   Row and column insertion can be performed with \ref insertRow and \ref insertColumn.
2478 */
2479
2480 /*!
2481   Creates an instance of QCPLayoutGrid and sets default values.
2482 */
2483 QCPLayoutGrid::QCPLayoutGrid() :
2484   mColumnSpacing(5),
2485   mRowSpacing(5)
2486 {
2487 }
2488
2489 QCPLayoutGrid::~QCPLayoutGrid()
2490 {
2491   // clear all child layout elements. This is important because only the specific layouts know how
2492   // to handle removing elements (clear calls virtual removeAt method to do that).
2493   clear();
2494 }
2495
2496 /*!
2497   Returns the element in the cell in \a row and \a column.
2498   
2499   Returns 0 if either the row/column is invalid or if the cell is empty. In those cases, a qDebug
2500   message is printed. To check whether a cell exists and isn't empty, use \ref hasElement.
2501   
2502   \see addElement, hasElement
2503 */
2504 QCPLayoutElement *QCPLayoutGrid::element(int row, int column) const
2505 {
2506   if (row >= 0 && row < mElements.size())
2507   {
2508     if (column >= 0 && column < mElements.first().size())
2509     {
2510       if (QCPLayoutElement *result = mElements.at(row).at(column))
2511         return result;
2512       else
2513         qDebug() << Q_FUNC_INFO << "Requested cell is empty. Row:" << row << "Column:" << column;
2514     } else
2515       qDebug() << Q_FUNC_INFO << "Invalid column. Row:" << row << "Column:" << column;
2516   } else
2517     qDebug() << Q_FUNC_INFO << "Invalid row. Row:" << row << "Column:" << column;
2518   return 0;
2519 }
2520
2521 /*!
2522   Returns the number of rows in the layout.
2523   
2524   \see columnCount
2525 */
2526 int QCPLayoutGrid::rowCount() const
2527 {
2528   return mElements.size();
2529 }
2530
2531 /*!
2532   Returns the number of columns in the layout.
2533   
2534   \see rowCount
2535 */
2536 int QCPLayoutGrid::columnCount() const
2537 {
2538   if (mElements.size() > 0)
2539     return mElements.first().size();
2540   else
2541     return 0;
2542 }
2543
2544 /*!
2545   Adds the \a element to cell with \a row and \a column. If \a element is already in a layout, it
2546   is first removed from there. If \a row or \a column don't exist yet, the layout is expanded
2547   accordingly.
2548   
2549   Returns true if the element was added successfully, i.e. if the cell at \a row and \a column
2550   didn't already have an element.
2551   
2552   \see element, hasElement, take, remove
2553 */
2554 bool QCPLayoutGrid::addElement(int row, int column, QCPLayoutElement *element)
2555 {
2556   if (element)
2557   {
2558     if (!hasElement(row, column))
2559     {
2560       if (element->layout()) // remove from old layout first
2561         element->layout()->take(element);
2562       expandTo(row+1, column+1);
2563       mElements[row][column] = element;
2564       adoptElement(element);
2565       return true;
2566     } else
2567       qDebug() << Q_FUNC_INFO << "There is already an element in the specified row/column:" << row << column;
2568   } else
2569     qDebug() << Q_FUNC_INFO << "Can't add null element to row/column:" << row << column;
2570   return false;
2571 }
2572
2573 /*!
2574   Returns whether the cell at \a row and \a column exists and contains a valid element, i.e. isn't
2575   empty.
2576   
2577   \see element
2578 */
2579 bool QCPLayoutGrid::hasElement(int row, int column)
2580 {
2581   if (row >= 0 && row < rowCount() && column >= 0 && column < columnCount())
2582     return mElements.at(row).at(column);
2583   else
2584     return false;
2585 }
2586
2587 /*!
2588   Sets the stretch \a factor of \a column.
2589   
2590   Stretch factors control the relative sizes of rows and columns. Cells will not be resized beyond
2591   their minimum and maximum widths/heights (\ref QCPLayoutElement::setMinimumSize, \ref
2592   QCPLayoutElement::setMaximumSize), regardless of the stretch factor.
2593   
2594   The default stretch factor of newly created rows/columns is 1.
2595   
2596   \see setColumnStretchFactors, setRowStretchFactor
2597 */
2598 void QCPLayoutGrid::setColumnStretchFactor(int column, double factor)
2599 {
2600   if (column >= 0 && column < columnCount())
2601   {
2602     if (factor > 0)
2603       mColumnStretchFactors[column] = factor;
2604     else
2605       qDebug() << Q_FUNC_INFO << "Invalid stretch factor, must be positive:" << factor;
2606   } else
2607     qDebug() << Q_FUNC_INFO << "Invalid column:" << column;
2608 }
2609
2610 /*!
2611   Sets the stretch \a factors of all columns. \a factors must have the size \ref columnCount.
2612   
2613   Stretch factors control the relative sizes of rows and columns. Cells will not be resized beyond
2614   their minimum and maximum widths/heights (\ref QCPLayoutElement::setMinimumSize, \ref
2615   QCPLayoutElement::setMaximumSize), regardless of the stretch factor.
2616   
2617   The default stretch factor of newly created rows/columns is 1.
2618   
2619   \see setColumnStretchFactor, setRowStretchFactors
2620 */
2621 void QCPLayoutGrid::setColumnStretchFactors(const QList<double> &factors)
2622 {
2623   if (factors.size() == mColumnStretchFactors.size())
2624   {
2625     mColumnStretchFactors = factors;
2626     for (int i=0; i<mColumnStretchFactors.size(); ++i)
2627     {
2628       if (mColumnStretchFactors.at(i) <= 0)
2629       {
2630         qDebug() << Q_FUNC_INFO << "Invalid stretch factor, must be positive:" << mColumnStretchFactors.at(i);
2631         mColumnStretchFactors[i] = 1;
2632       }
2633     }
2634   } else
2635     qDebug() << Q_FUNC_INFO << "Column count not equal to passed stretch factor count:" << factors;
2636 }
2637
2638 /*!
2639   Sets the stretch \a factor of \a row.
2640   
2641   Stretch factors control the relative sizes of rows and columns. Cells will not be resized beyond
2642   their minimum and maximum widths/heights (\ref QCPLayoutElement::setMinimumSize, \ref
2643   QCPLayoutElement::setMaximumSize), regardless of the stretch factor.
2644   
2645   The default stretch factor of newly created rows/columns is 1.
2646   
2647   \see setColumnStretchFactors, setRowStretchFactor
2648 */
2649 void QCPLayoutGrid::setRowStretchFactor(int row, double factor)
2650 {
2651   if (row >= 0 && row < rowCount())
2652   {
2653     if (factor > 0)
2654       mRowStretchFactors[row] = factor;
2655     else
2656       qDebug() << Q_FUNC_INFO << "Invalid stretch factor, must be positive:" << factor;
2657   } else
2658     qDebug() << Q_FUNC_INFO << "Invalid row:" << row;
2659 }
2660
2661 /*!
2662   Sets the stretch \a factors of all rows. \a factors must have the size \ref rowCount.
2663   
2664   Stretch factors control the relative sizes of rows and columns. Cells will not be resized beyond
2665   their minimum and maximum widths/heights (\ref QCPLayoutElement::setMinimumSize, \ref
2666   QCPLayoutElement::setMaximumSize), regardless of the stretch factor.
2667   
2668   The default stretch factor of newly created rows/columns is 1.
2669   
2670   \see setRowStretchFactor, setColumnStretchFactors
2671 */
2672 void QCPLayoutGrid::setRowStretchFactors(const QList<double> &factors)
2673 {
2674   if (factors.size() == mRowStretchFactors.size())
2675   {
2676     mRowStretchFactors = factors;
2677     for (int i=0; i<mRowStretchFactors.size(); ++i)
2678     {
2679       if (mRowStretchFactors.at(i) <= 0)
2680       {
2681         qDebug() << Q_FUNC_INFO << "Invalid stretch factor, must be positive:" << mRowStretchFactors.at(i);
2682         mRowStretchFactors[i] = 1;
2683       }
2684     }
2685   } else
2686     qDebug() << Q_FUNC_INFO << "Row count not equal to passed stretch factor count:" << factors;
2687 }
2688
2689 /*!
2690   Sets the gap that is left blank between columns to \a pixels.
2691   
2692   \see setRowSpacing
2693 */
2694 void QCPLayoutGrid::setColumnSpacing(int pixels)
2695 {
2696   mColumnSpacing = pixels;
2697 }
2698
2699 /*!
2700   Sets the gap that is left blank between rows to \a pixels.
2701   
2702   \see setColumnSpacing
2703 */
2704 void QCPLayoutGrid::setRowSpacing(int pixels)
2705 {
2706   mRowSpacing = pixels;
2707 }
2708
2709 /*!
2710   Expands the layout to have \a newRowCount rows and \a newColumnCount columns. So the last valid
2711   row index will be \a newRowCount-1, the last valid column index will be \a newColumnCount-1.
2712   
2713   If the current column/row count is already larger or equal to \a newColumnCount/\a newRowCount,
2714   this function does nothing in that dimension.
2715   
2716   Newly created cells are empty, new rows and columns have the stretch factor 1.
2717   
2718   Note that upon a call to \ref addElement, the layout is expanded automatically to contain the
2719   specified row and column, using this function.
2720   
2721   \see simplify
2722 */
2723 void QCPLayoutGrid::expandTo(int newRowCount, int newColumnCount)
2724 {
2725   // add rows as necessary:
2726   while (rowCount() < newRowCount)
2727   {
2728     mElements.append(QList<QCPLayoutElement*>());
2729     mRowStretchFactors.append(1);
2730   }
2731   // go through rows and expand columns as necessary:
2732   int newColCount = qMax(columnCount(), newColumnCount);
2733   for (int i=0; i<rowCount(); ++i)
2734   {
2735     while (mElements.at(i).size() < newColCount)
2736       mElements[i].append(0);
2737   }
2738   while (mColumnStretchFactors.size() < newColCount)
2739     mColumnStretchFactors.append(1);
2740 }
2741
2742 /*!
2743   Inserts a new row with empty cells at the row index \a newIndex. Valid values for \a newIndex
2744   range from 0 (inserts a row at the top) to \a rowCount (appends a row at the bottom).
2745   
2746   \see insertColumn
2747 */
2748 void QCPLayoutGrid::insertRow(int newIndex)
2749 {
2750   if (mElements.isEmpty() || mElements.first().isEmpty()) // if grid is completely empty, add first cell
2751   {
2752     expandTo(1, 1);
2753     return;
2754   }
2755   
2756   if (newIndex < 0)
2757     newIndex = 0;
2758   if (newIndex > rowCount())
2759     newIndex = rowCount();
2760   
2761   mRowStretchFactors.insert(newIndex, 1);
2762   QList<QCPLayoutElement*> newRow;
2763   for (int col=0; col<columnCount(); ++col)
2764     newRow.append((QCPLayoutElement*)0);
2765   mElements.insert(newIndex, newRow);
2766 }
2767
2768 /*!
2769   Inserts a new column with empty cells at the column index \a newIndex. Valid values for \a
2770   newIndex range from 0 (inserts a row at the left) to \a rowCount (appends a row at the right).
2771   
2772   \see insertRow
2773 */
2774 void QCPLayoutGrid::insertColumn(int newIndex)
2775 {
2776   if (mElements.isEmpty() || mElements.first().isEmpty()) // if grid is completely empty, add first cell
2777   {
2778     expandTo(1, 1);
2779     return;
2780   }
2781   
2782   if (newIndex < 0)
2783     newIndex = 0;
2784   if (newIndex > columnCount())
2785     newIndex = columnCount();
2786   
2787   mColumnStretchFactors.insert(newIndex, 1);
2788   for (int row=0; row<rowCount(); ++row)
2789     mElements[row].insert(newIndex, (QCPLayoutElement*)0);
2790 }
2791
2792 /* inherits documentation from base class */
2793 void QCPLayoutGrid::updateLayout()
2794 {
2795   QVector<int> minColWidths, minRowHeights, maxColWidths, maxRowHeights;
2796   getMinimumRowColSizes(&minColWidths, &minRowHeights);
2797   getMaximumRowColSizes(&maxColWidths, &maxRowHeights);
2798   
2799   int totalRowSpacing = (rowCount()-1) * mRowSpacing;
2800   int totalColSpacing = (columnCount()-1) * mColumnSpacing;
2801   QVector<int> colWidths = getSectionSizes(maxColWidths, minColWidths, mColumnStretchFactors.toVector(), mRect.width()-totalColSpacing);
2802   QVector<int> rowHeights = getSectionSizes(maxRowHeights, minRowHeights, mRowStretchFactors.toVector(), mRect.height()-totalRowSpacing);
2803   
2804   // go through cells and set rects accordingly:
2805   int yOffset = mRect.top();
2806   for (int row=0; row<rowCount(); ++row)
2807   {
2808     if (row > 0)
2809       yOffset += rowHeights.at(row-1)+mRowSpacing;
2810     int xOffset = mRect.left();
2811     for (int col=0; col<columnCount(); ++col)
2812     {
2813       if (col > 0)
2814         xOffset += colWidths.at(col-1)+mColumnSpacing;
2815       if (mElements.at(row).at(col))
2816         mElements.at(row).at(col)->setOuterRect(QRect(xOffset, yOffset, colWidths.at(col), rowHeights.at(row)));
2817     }
2818   }
2819 }
2820
2821 /* inherits documentation from base class */
2822 int QCPLayoutGrid::elementCount() const
2823 {
2824   return rowCount()*columnCount();
2825 }
2826
2827 /* inherits documentation from base class */
2828 QCPLayoutElement *QCPLayoutGrid::elementAt(int index) const
2829 {
2830   if (index >= 0 && index < elementCount())
2831     return mElements.at(index / columnCount()).at(index % columnCount());
2832   else
2833     return 0;
2834 }
2835
2836 /* inherits documentation from base class */
2837 QCPLayoutElement *QCPLayoutGrid::takeAt(int index)
2838 {
2839   if (QCPLayoutElement *el = elementAt(index))
2840   {
2841     releaseElement(el);
2842     mElements[index / columnCount()][index % columnCount()] = 0;
2843     return el;
2844   } else
2845   {
2846     qDebug() << Q_FUNC_INFO << "Attempt to take invalid index:" << index;
2847     return 0;
2848   }
2849 }
2850
2851 /* inherits documentation from base class */
2852 bool QCPLayoutGrid::take(QCPLayoutElement *element)
2853 {
2854   if (element)
2855   {
2856     for (int i=0; i<elementCount(); ++i)
2857     {
2858       if (elementAt(i) == element)
2859       {
2860         takeAt(i);
2861         return true;
2862       }
2863     }
2864     qDebug() << Q_FUNC_INFO << "Element not in this layout, couldn't take";
2865   } else
2866     qDebug() << Q_FUNC_INFO << "Can't take null element";
2867   return false;
2868 }
2869
2870 /* inherits documentation from base class */
2871 QList<QCPLayoutElement*> QCPLayoutGrid::elements(bool recursive) const
2872 {
2873   QList<QCPLayoutElement*> result;
2874   int colC = columnCount();
2875   int rowC = rowCount();
2876 #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
2877   result.reserve(colC*rowC);
2878 #endif
2879   for (int row=0; row<rowC; ++row)
2880   {
2881     for (int col=0; col<colC; ++col)
2882     {
2883       result.append(mElements.at(row).at(col));
2884     }
2885   }
2886   if (recursive)
2887   {
2888     int c = result.size();
2889     for (int i=0; i<c; ++i)
2890     {
2891       if (result.at(i))
2892         result << result.at(i)->elements(recursive);
2893     }
2894   }
2895   return result;
2896 }
2897
2898 /*!
2899   Simplifies the layout by collapsing rows and columns which only contain empty cells.
2900 */
2901 void QCPLayoutGrid::simplify()
2902 {
2903   // remove rows with only empty cells:
2904   for (int row=rowCount()-1; row>=0; --row)
2905   {
2906     bool hasElements = false;
2907     for (int col=0; col<columnCount(); ++col)
2908     {
2909       if (mElements.at(row).at(col))
2910       {
2911         hasElements = true;
2912         break;
2913       }
2914     }
2915     if (!hasElements)
2916     {
2917       mRowStretchFactors.removeAt(row);
2918       mElements.removeAt(row);
2919       if (mElements.isEmpty()) // removed last element, also remove stretch factor (wouldn't happen below because also columnCount changed to 0 now)
2920         mColumnStretchFactors.clear();
2921     }
2922   }
2923   
2924   // remove columns with only empty cells:
2925   for (int col=columnCount()-1; col>=0; --col)
2926   {
2927     bool hasElements = false;
2928     for (int row=0; row<rowCount(); ++row)
2929     {
2930       if (mElements.at(row).at(col))
2931       {
2932         hasElements = true;
2933         break;
2934       }
2935     }
2936     if (!hasElements)
2937     {
2938       mColumnStretchFactors.removeAt(col);
2939       for (int row=0; row<rowCount(); ++row)
2940         mElements[row].removeAt(col);
2941     }
2942   }
2943 }
2944
2945 /* inherits documentation from base class */
2946 QSize QCPLayoutGrid::minimumSizeHint() const
2947 {
2948   QVector<int> minColWidths, minRowHeights;
2949   getMinimumRowColSizes(&minColWidths, &minRowHeights);
2950   QSize result(0, 0);
2951   for (int i=0; i<minColWidths.size(); ++i)
2952     result.rwidth() += minColWidths.at(i);
2953   for (int i=0; i<minRowHeights.size(); ++i)
2954     result.rheight() += minRowHeights.at(i);
2955   result.rwidth() += qMax(0, columnCount()-1) * mColumnSpacing + mMargins.left() + mMargins.right();
2956   result.rheight() += qMax(0, rowCount()-1) * mRowSpacing + mMargins.top() + mMargins.bottom();
2957   return result;
2958 }
2959
2960 /* inherits documentation from base class */
2961 QSize QCPLayoutGrid::maximumSizeHint() const
2962 {
2963   QVector<int> maxColWidths, maxRowHeights;
2964   getMaximumRowColSizes(&maxColWidths, &maxRowHeights);
2965   
2966   QSize result(0, 0);
2967   for (int i=0; i<maxColWidths.size(); ++i)
2968     result.setWidth(qMin(result.width()+maxColWidths.at(i), QWIDGETSIZE_MAX));
2969   for (int i=0; i<maxRowHeights.size(); ++i)
2970     result.setHeight(qMin(result.height()+maxRowHeights.at(i), QWIDGETSIZE_MAX));
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 }
2975
2976 /*! \internal
2977   
2978   Places the minimum column widths and row heights into \a minColWidths and \a minRowHeights
2979   respectively.
2980   
2981   The minimum height of a row is the largest minimum height of any element in that row. The minimum
2982   width of a column is the largest minimum width of any element in that column.
2983   
2984   This is a helper function for \ref updateLayout.
2985   
2986   \see getMaximumRowColSizes
2987 */
2988 void QCPLayoutGrid::getMinimumRowColSizes(QVector<int> *minColWidths, QVector<int> *minRowHeights) const
2989 {
2990   *minColWidths = QVector<int>(columnCount(), 0);
2991   *minRowHeights = QVector<int>(rowCount(), 0);
2992   for (int row=0; row<rowCount(); ++row)
2993   {
2994     for (int col=0; col<columnCount(); ++col)
2995     {
2996       if (mElements.at(row).at(col))
2997       {
2998         QSize minHint = mElements.at(row).at(col)->minimumSizeHint();
2999         QSize min = mElements.at(row).at(col)->minimumSize();
3000         QSize final(min.width() > 0 ? min.width() : minHint.width(), min.height() > 0 ? min.height() : minHint.height());
3001         if (minColWidths->at(col) < final.width())
3002           (*minColWidths)[col] = final.width();
3003         if (minRowHeights->at(row) < final.height())
3004           (*minRowHeights)[row] = final.height();
3005       }
3006     }
3007   }
3008 }
3009
3010 /*! \internal
3011   
3012   Places the maximum column widths and row heights into \a maxColWidths and \a maxRowHeights
3013   respectively.
3014   
3015   The maximum height of a row is the smallest maximum height of any element in that row. The
3016   maximum width of a column is the smallest maximum width of any element in that column.
3017   
3018   This is a helper function for \ref updateLayout.
3019   
3020   \see getMinimumRowColSizes
3021 */
3022 void QCPLayoutGrid::getMaximumRowColSizes(QVector<int> *maxColWidths, QVector<int> *maxRowHeights) const
3023 {
3024   *maxColWidths = QVector<int>(columnCount(), QWIDGETSIZE_MAX);
3025   *maxRowHeights = QVector<int>(rowCount(), QWIDGETSIZE_MAX);
3026   for (int row=0; row<rowCount(); ++row)
3027   {
3028     for (int col=0; col<columnCount(); ++col)
3029     {
3030       if (mElements.at(row).at(col))
3031       {
3032         QSize maxHint = mElements.at(row).at(col)->maximumSizeHint();
3033         QSize max = mElements.at(row).at(col)->maximumSize();
3034         QSize final(max.width() < QWIDGETSIZE_MAX ? max.width() : maxHint.width(), max.height() < QWIDGETSIZE_MAX ? max.height() : maxHint.height());
3035         if (maxColWidths->at(col) > final.width())
3036           (*maxColWidths)[col] = final.width();
3037         if (maxRowHeights->at(row) > final.height())
3038           (*maxRowHeights)[row] = final.height();
3039       }
3040     }
3041   }
3042 }
3043
3044
3045 ////////////////////////////////////////////////////////////////////////////////////////////////////
3046 //////////////////// QCPLayoutInset
3047 ////////////////////////////////////////////////////////////////////////////////////////////////////
3048 /*! \class QCPLayoutInset
3049   \brief A layout that places child elements aligned to the border or arbitrarily positioned
3050   
3051   Elements are placed either aligned to the border or at arbitrary position in the area of the
3052   layout. Which placement applies is controlled with the \ref InsetPlacement (\ref
3053   setInsetPlacement).
3054
3055   Elements are added via \ref addElement(QCPLayoutElement *element, Qt::Alignment alignment) or
3056   addElement(QCPLayoutElement *element, const QRectF &rect). If the first method is used, the inset
3057   placement will default to \ref ipBorderAligned and the element will be aligned according to the
3058   \a alignment parameter. The second method defaults to \ref ipFree and allows placing elements at
3059   arbitrary position and size, defined by \a rect.
3060   
3061   The alignment or rect can be set via \ref setInsetAlignment or \ref setInsetRect, respectively.
3062   
3063   This is the layout that every QCPAxisRect has as \ref QCPAxisRect::insetLayout.
3064 */
3065
3066 /* start documentation of inline functions */
3067
3068 /*! \fn virtual void QCPLayoutInset::simplify()
3069   
3070   The QCPInsetLayout does not need simplification since it can never have empty cells due to its
3071   linear index structure. This method does nothing.
3072 */
3073
3074 /* end documentation of inline functions */
3075
3076 /*!
3077   Creates an instance of QCPLayoutInset and sets default values.
3078 */
3079 QCPLayoutInset::QCPLayoutInset()
3080 {
3081 }
3082
3083 QCPLayoutInset::~QCPLayoutInset()
3084 {
3085   // clear all child layout elements. This is important because only the specific layouts know how
3086   // to handle removing elements (clear calls virtual removeAt method to do that).
3087   clear();
3088 }
3089
3090 /*!
3091   Returns the placement type of the element with the specified \a index.
3092 */
3093 QCPLayoutInset::InsetPlacement QCPLayoutInset::insetPlacement(int index) const
3094 {
3095   if (elementAt(index))
3096     return mInsetPlacement.at(index);
3097   else
3098   {
3099     qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
3100     return ipFree;
3101   }
3102 }
3103
3104 /*!
3105   Returns the alignment of the element with the specified \a index. The alignment only has a
3106   meaning, if the inset placement (\ref setInsetPlacement) is \ref ipBorderAligned.
3107 */
3108 Qt::Alignment QCPLayoutInset::insetAlignment(int index) const
3109 {
3110   if (elementAt(index))
3111     return mInsetAlignment.at(index);
3112   else
3113   {
3114     qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
3115     return 0;
3116   }
3117 }
3118
3119 /*!
3120   Returns the rect of the element with the specified \a index. The rect only has a
3121   meaning, if the inset placement (\ref setInsetPlacement) is \ref ipFree.
3122 */
3123 QRectF QCPLayoutInset::insetRect(int index) const
3124 {
3125   if (elementAt(index))
3126     return mInsetRect.at(index);
3127   else
3128   {
3129     qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
3130     return QRectF();
3131   }
3132 }
3133
3134 /*!
3135   Sets the inset placement type of the element with the specified \a index to \a placement.
3136   
3137   \see InsetPlacement
3138 */
3139 void QCPLayoutInset::setInsetPlacement(int index, QCPLayoutInset::InsetPlacement placement)
3140 {
3141   if (elementAt(index))
3142     mInsetPlacement[index] = placement;
3143   else
3144     qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
3145 }
3146
3147 /*!
3148   If the inset placement (\ref setInsetPlacement) is \ref ipBorderAligned, this function
3149   is used to set the alignment of the element with the specified \a index to \a alignment.
3150   
3151   \a alignment is an or combination of the following alignment flags: Qt::AlignLeft,
3152   Qt::AlignHCenter, Qt::AlighRight, Qt::AlignTop, Qt::AlignVCenter, Qt::AlignBottom. Any other
3153   alignment flags will be ignored.
3154 */
3155 void QCPLayoutInset::setInsetAlignment(int index, Qt::Alignment alignment)
3156 {
3157   if (elementAt(index))
3158     mInsetAlignment[index] = alignment;
3159   else
3160     qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
3161 }
3162
3163 /*!
3164   If the inset placement (\ref setInsetPlacement) is \ref ipFree, this function is used to set the
3165   position and size of the element with the specified \a index to \a rect.
3166   
3167   \a rect is given in fractions of the whole inset layout rect. So an inset with rect (0, 0, 1, 1)
3168   will span the entire layout. An inset with rect (0.6, 0.1, 0.35, 0.35) will be in the top right
3169   corner of the layout, with 35% width and height of the parent layout.
3170   
3171   Note that the minimum and maximum sizes of the embedded element (\ref
3172   QCPLayoutElement::setMinimumSize, \ref QCPLayoutElement::setMaximumSize) are enforced.
3173 */
3174 void QCPLayoutInset::setInsetRect(int index, const QRectF &rect)
3175 {
3176   if (elementAt(index))
3177     mInsetRect[index] = rect;
3178   else
3179     qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
3180 }
3181
3182 /* inherits documentation from base class */
3183 void QCPLayoutInset::updateLayout()
3184 {
3185   for (int i=0; i<mElements.size(); ++i)
3186   {
3187     QRect insetRect;
3188     QSize finalMinSize, finalMaxSize;
3189     QSize minSizeHint = mElements.at(i)->minimumSizeHint();
3190     QSize maxSizeHint = mElements.at(i)->maximumSizeHint();
3191     finalMinSize.setWidth(mElements.at(i)->minimumSize().width() > 0 ? mElements.at(i)->minimumSize().width() : minSizeHint.width());
3192     finalMinSize.setHeight(mElements.at(i)->minimumSize().height() > 0 ? mElements.at(i)->minimumSize().height() : minSizeHint.height());
3193     finalMaxSize.setWidth(mElements.at(i)->maximumSize().width() < QWIDGETSIZE_MAX ? mElements.at(i)->maximumSize().width() : maxSizeHint.width());
3194     finalMaxSize.setHeight(mElements.at(i)->maximumSize().height() < QWIDGETSIZE_MAX ? mElements.at(i)->maximumSize().height() : maxSizeHint.height());
3195     if (mInsetPlacement.at(i) == ipFree)
3196     {
3197       insetRect = QRect(rect().x()+rect().width()*mInsetRect.at(i).x(),
3198                         rect().y()+rect().height()*mInsetRect.at(i).y(),
3199                         rect().width()*mInsetRect.at(i).width(),
3200                         rect().height()*mInsetRect.at(i).height());
3201       if (insetRect.size().width() < finalMinSize.width())
3202         insetRect.setWidth(finalMinSize.width());
3203       if (insetRect.size().height() < finalMinSize.height())
3204         insetRect.setHeight(finalMinSize.height());
3205       if (insetRect.size().width() > finalMaxSize.width())
3206         insetRect.setWidth(finalMaxSize.width());
3207       if (insetRect.size().height() > finalMaxSize.height())
3208         insetRect.setHeight(finalMaxSize.height());
3209     } else if (mInsetPlacement.at(i) == ipBorderAligned)
3210     {
3211       insetRect.setSize(finalMinSize);
3212       Qt::Alignment al = mInsetAlignment.at(i);
3213       if (al.testFlag(Qt::AlignLeft)) insetRect.moveLeft(rect().x());
3214       else if (al.testFlag(Qt::AlignRight)) insetRect.moveRight(rect().x()+rect().width());
3215       else insetRect.moveLeft(rect().x()+rect().width()*0.5-finalMinSize.width()*0.5); // default to Qt::AlignHCenter
3216       if (al.testFlag(Qt::AlignTop)) insetRect.moveTop(rect().y());
3217       else if (al.testFlag(Qt::AlignBottom)) insetRect.moveBottom(rect().y()+rect().height());
3218       else insetRect.moveTop(rect().y()+rect().height()*0.5-finalMinSize.height()*0.5); // default to Qt::AlignVCenter
3219     }
3220     mElements.at(i)->setOuterRect(insetRect);
3221   }
3222 }
3223
3224 /* inherits documentation from base class */
3225 int QCPLayoutInset::elementCount() const
3226 {
3227   return mElements.size();
3228 }
3229
3230 /* inherits documentation from base class */
3231 QCPLayoutElement *QCPLayoutInset::elementAt(int index) const
3232 {
3233   if (index >= 0 && index < mElements.size())
3234     return mElements.at(index);
3235   else
3236     return 0;
3237 }
3238
3239 /* inherits documentation from base class */
3240 QCPLayoutElement *QCPLayoutInset::takeAt(int index)
3241 {
3242   if (QCPLayoutElement *el = elementAt(index))
3243   {
3244     releaseElement(el);
3245     mElements.removeAt(index);
3246     mInsetPlacement.removeAt(index);
3247     mInsetAlignment.removeAt(index);
3248     mInsetRect.removeAt(index);
3249     return el;
3250   } else
3251   {
3252     qDebug() << Q_FUNC_INFO << "Attempt to take invalid index:" << index;
3253     return 0;
3254   }
3255 }
3256
3257 /* inherits documentation from base class */
3258 bool QCPLayoutInset::take(QCPLayoutElement *element)
3259 {
3260   if (element)
3261   {
3262     for (int i=0; i<elementCount(); ++i)
3263     {
3264       if (elementAt(i) == element)
3265       {
3266         takeAt(i);
3267         return true;
3268       }
3269     }
3270     qDebug() << Q_FUNC_INFO << "Element not in this layout, couldn't take";
3271   } else
3272     qDebug() << Q_FUNC_INFO << "Can't take null element";
3273   return false;
3274 }
3275
3276 /*!
3277   The inset layout is sensitive to events only at areas where its (visible) child elements are
3278   sensitive. If the selectTest method of any of the child elements returns a positive number for \a
3279   pos, this method returns a value corresponding to 0.99 times the parent plot's selection
3280   tolerance. The inset layout is not selectable itself by default. So if \a onlySelectable is true,
3281   -1.0 is returned.
3282   
3283   See \ref QCPLayerable::selectTest for a general explanation of this virtual method.
3284 */
3285 double QCPLayoutInset::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
3286 {
3287   Q_UNUSED(details)
3288   if (onlySelectable)
3289     return -1;
3290   
3291   for (int i=0; i<mElements.size(); ++i)
3292   {
3293     // inset layout shall only return positive selectTest, if actually an inset object is at pos
3294     // else it would block the entire underlying QCPAxisRect with its surface.
3295     if (mElements.at(i)->realVisibility() && mElements.at(i)->selectTest(pos, onlySelectable) >= 0)
3296       return mParentPlot->selectionTolerance()*0.99;
3297   }
3298   return -1;
3299 }
3300
3301 /*!
3302   Adds the specified \a element to the layout as an inset aligned at the border (\ref
3303   setInsetAlignment is initialized with \ref ipBorderAligned). The alignment is set to \a
3304   alignment.
3305   
3306   \a alignment is an or combination of the following alignment flags: Qt::AlignLeft,
3307   Qt::AlignHCenter, Qt::AlighRight, Qt::AlignTop, Qt::AlignVCenter, Qt::AlignBottom. Any other
3308   alignment flags will be ignored.
3309   
3310   \see addElement(QCPLayoutElement *element, const QRectF &rect)
3311 */
3312 void QCPLayoutInset::addElement(QCPLayoutElement *element, Qt::Alignment alignment)
3313 {
3314   if (element)
3315   {
3316     if (element->layout()) // remove from old layout first
3317       element->layout()->take(element);
3318     mElements.append(element);
3319     mInsetPlacement.append(ipBorderAligned);
3320     mInsetAlignment.append(alignment);
3321     mInsetRect.append(QRectF(0.6, 0.6, 0.4, 0.4));
3322     adoptElement(element);
3323   } else
3324     qDebug() << Q_FUNC_INFO << "Can't add null element";
3325 }
3326
3327 /*!
3328   Adds the specified \a element to the layout as an inset with free positioning/sizing (\ref
3329   setInsetAlignment is initialized with \ref ipFree). The position and size is set to \a
3330   rect.
3331   
3332   \a rect is given in fractions of the whole inset layout rect. So an inset with rect (0, 0, 1, 1)
3333   will span the entire layout. An inset with rect (0.6, 0.1, 0.35, 0.35) will be in the top right
3334   corner of the layout, with 35% width and height of the parent layout.
3335   
3336   \see addElement(QCPLayoutElement *element, Qt::Alignment alignment)
3337 */
3338 void QCPLayoutInset::addElement(QCPLayoutElement *element, const QRectF &rect)
3339 {
3340   if (element)
3341   {
3342     if (element->layout()) // remove from old layout first
3343       element->layout()->take(element);
3344     mElements.append(element);
3345     mInsetPlacement.append(ipFree);
3346     mInsetAlignment.append(Qt::AlignRight|Qt::AlignTop);
3347     mInsetRect.append(rect);
3348     adoptElement(element);
3349   } else
3350     qDebug() << Q_FUNC_INFO << "Can't add null element";
3351 }
3352
3353
3354 ////////////////////////////////////////////////////////////////////////////////////////////////////
3355 //////////////////// QCPLineEnding
3356 ////////////////////////////////////////////////////////////////////////////////////////////////////
3357
3358 /*! \class QCPLineEnding
3359   \brief Handles the different ending decorations for line-like items
3360   
3361   \image html QCPLineEnding.png "The various ending styles currently supported"
3362   
3363   For every ending a line-like item has, an instance of this class exists. For example, QCPItemLine
3364   has two endings which can be set with QCPItemLine::setHead and QCPItemLine::setTail.
3365  
3366   The styles themselves are defined via the enum QCPLineEnding::EndingStyle. Most decorations can
3367   be modified regarding width and length, see \ref setWidth and \ref setLength. The direction of
3368   the ending decoration (e.g. direction an arrow is pointing) is controlled by the line-like item.
3369   For example, when both endings of a QCPItemLine are set to be arrows, they will point to opposite
3370   directions, e.g. "outward". This can be changed by \ref setInverted, which would make the
3371   respective arrow point inward.
3372   
3373   Note that due to the overloaded QCPLineEnding constructor, you may directly specify a
3374   QCPLineEnding::EndingStyle where actually a QCPLineEnding is expected, e.g.
3375   \snippet documentation/doc-code-snippets/mainwindow.cpp qcplineending-sethead
3376 */
3377
3378 /*!
3379   Creates a QCPLineEnding instance with default values (style \ref esNone).
3380 */
3381 QCPLineEnding::QCPLineEnding() :
3382   mStyle(esNone),
3383   mWidth(8),
3384   mLength(10),
3385   mInverted(false)
3386 {
3387 }
3388
3389 /*!
3390   Creates a QCPLineEnding instance with the specified values.
3391 */
3392 QCPLineEnding::QCPLineEnding(QCPLineEnding::EndingStyle style, double width, double length, bool inverted) :
3393   mStyle(style),
3394   mWidth(width),
3395   mLength(length),
3396   mInverted(inverted)
3397 {
3398 }
3399
3400 /*!
3401   Sets the style of the ending decoration.
3402 */
3403 void QCPLineEnding::setStyle(QCPLineEnding::EndingStyle style)
3404 {
3405   mStyle = style;
3406 }
3407
3408 /*!
3409   Sets the width of the ending decoration, if the style supports it. On arrows, for example, the
3410   width defines the size perpendicular to the arrow's pointing direction.
3411   
3412   \see setLength
3413 */
3414 void QCPLineEnding::setWidth(double width)
3415 {
3416   mWidth = width;
3417 }
3418
3419 /*!
3420   Sets the length of the ending decoration, if the style supports it. On arrows, for example, the
3421   length defines the size in pointing direction.
3422   
3423   \see setWidth
3424 */
3425 void QCPLineEnding::setLength(double length)
3426 {
3427   mLength = length;
3428 }
3429
3430 /*!
3431   Sets whether the ending decoration shall be inverted. For example, an arrow decoration will point
3432   inward when \a inverted is set to true.
3433
3434   Note that also the \a width direction is inverted. For symmetrical ending styles like arrows or
3435   discs, this doesn't make a difference. However, asymmetric styles like \ref esHalfBar are
3436   affected by it, which can be used to control to which side the half bar points to.
3437 */
3438 void QCPLineEnding::setInverted(bool inverted)
3439 {
3440   mInverted = inverted;
3441 }
3442
3443 /*! \internal
3444   
3445   Returns the maximum pixel radius the ending decoration might cover, starting from the position
3446   the decoration is drawn at (typically a line ending/\ref QCPItemPosition of an item).
3447   
3448   This is relevant for clipping. Only omit painting of the decoration when the position where the
3449   decoration is supposed to be drawn is farther away from the clipping rect than the returned
3450   distance.
3451 */
3452 double QCPLineEnding::boundingDistance() const
3453 {
3454   switch (mStyle)
3455   {
3456     case esNone:
3457       return 0;
3458       
3459     case esFlatArrow:
3460     case esSpikeArrow:
3461     case esLineArrow:
3462     case esSkewedBar:
3463       return qSqrt(mWidth*mWidth+mLength*mLength); // items that have width and length
3464       
3465     case esDisc:
3466     case esSquare:
3467     case esDiamond:
3468     case esBar:
3469     case esHalfBar:
3470       return mWidth*1.42; // items that only have a width -> width*sqrt(2)
3471
3472   }
3473   return 0;
3474 }
3475
3476 /*!
3477   Starting from the origin of this line ending (which is style specific), returns the length
3478   covered by the line ending symbol, in backward direction.
3479   
3480   For example, the \ref esSpikeArrow has a shorter real length than a \ref esFlatArrow, even if
3481   both have the same \ref setLength value, because the spike arrow has an inward curved back, which
3482   reduces the length along its center axis (the drawing origin for arrows is at the tip).
3483   
3484   This function is used for precise, style specific placement of line endings, for example in
3485   QCPAxes.
3486 */
3487 double QCPLineEnding::realLength() const
3488 {
3489   switch (mStyle)
3490   {
3491     case esNone:
3492     case esLineArrow:
3493     case esSkewedBar:
3494     case esBar:
3495     case esHalfBar:
3496       return 0;
3497       
3498     case esFlatArrow:
3499       return mLength;
3500       
3501     case esDisc:
3502     case esSquare:
3503     case esDiamond:
3504       return mWidth*0.5;
3505       
3506     case esSpikeArrow:
3507       return mLength*0.8;
3508   }
3509   return 0;
3510 }
3511
3512 /*! \internal
3513   
3514   Draws the line ending with the specified \a painter at the position \a pos. The direction of the
3515   line ending is controlled with \a dir.
3516 */
3517 void QCPLineEnding::draw(QCPPainter *painter, const QVector2D &pos, const QVector2D &dir) const
3518 {
3519   if (mStyle == esNone)
3520     return;
3521   
3522   QVector2D lengthVec(dir.normalized());
3523   if (lengthVec.isNull())
3524     lengthVec = QVector2D(1, 0);
3525   QVector2D widthVec(-lengthVec.y(), lengthVec.x());
3526   lengthVec *= (float)(mLength*(mInverted ? -1 : 1));
3527   widthVec *= (float)(mWidth*0.5*(mInverted ? -1 : 1));
3528   
3529   QPen penBackup = painter->pen();
3530   QBrush brushBackup = painter->brush();
3531   QPen miterPen = penBackup;
3532   miterPen.setJoinStyle(Qt::MiterJoin); // to make arrow heads spikey
3533   QBrush brush(painter->pen().color(), Qt::SolidPattern);
3534   switch (mStyle)
3535   {
3536     case esNone: break;
3537     case esFlatArrow:
3538     {
3539       QPointF points[3] = {pos.toPointF(),
3540                            (pos-lengthVec+widthVec).toPointF(),
3541                            (pos-lengthVec-widthVec).toPointF()
3542                           };
3543       painter->setPen(miterPen);
3544       painter->setBrush(brush);
3545       painter->drawConvexPolygon(points, 3);
3546       painter->setBrush(brushBackup);
3547       painter->setPen(penBackup);
3548       break;
3549     }
3550     case esSpikeArrow:
3551     {
3552       QPointF points[4] = {pos.toPointF(),
3553                            (pos-lengthVec+widthVec).toPointF(),
3554                            (pos-lengthVec*0.8f).toPointF(),
3555                            (pos-lengthVec-widthVec).toPointF()
3556                           };
3557       painter->setPen(miterPen);
3558       painter->setBrush(brush);
3559       painter->drawConvexPolygon(points, 4);
3560       painter->setBrush(brushBackup);
3561       painter->setPen(penBackup);
3562       break;
3563     }
3564     case esLineArrow:
3565     {
3566       QPointF points[3] = {(pos-lengthVec+widthVec).toPointF(),
3567                            pos.toPointF(),
3568                            (pos-lengthVec-widthVec).toPointF()
3569                           };
3570       painter->setPen(miterPen);
3571       painter->drawPolyline(points, 3);
3572       painter->setPen(penBackup);
3573       break;
3574     }
3575     case esDisc:
3576     {
3577       painter->setBrush(brush);
3578       painter->drawEllipse(pos.toPointF(),  mWidth*0.5, mWidth*0.5);
3579       painter->setBrush(brushBackup);
3580       break;
3581     }
3582     case esSquare:
3583     {
3584       QVector2D widthVecPerp(-widthVec.y(), widthVec.x());
3585       QPointF points[4] = {(pos-widthVecPerp+widthVec).toPointF(),
3586                            (pos-widthVecPerp-widthVec).toPointF(),
3587                            (pos+widthVecPerp-widthVec).toPointF(),
3588                            (pos+widthVecPerp+widthVec).toPointF()
3589                           };
3590       painter->setPen(miterPen);
3591       painter->setBrush(brush);
3592       painter->drawConvexPolygon(points, 4);
3593       painter->setBrush(brushBackup);
3594       painter->setPen(penBackup);
3595       break;
3596     }
3597     case esDiamond:
3598     {
3599       QVector2D widthVecPerp(-widthVec.y(), widthVec.x());
3600       QPointF points[4] = {(pos-widthVecPerp).toPointF(),
3601                            (pos-widthVec).toPointF(),
3602                            (pos+widthVecPerp).toPointF(),
3603                            (pos+widthVec).toPointF()
3604                           };
3605       painter->setPen(miterPen);
3606       painter->setBrush(brush);
3607       painter->drawConvexPolygon(points, 4);
3608       painter->setBrush(brushBackup);
3609       painter->setPen(penBackup);
3610       break;
3611     }
3612     case esBar:
3613     {
3614       painter->drawLine((pos+widthVec).toPointF(), (pos-widthVec).toPointF());
3615       break;
3616     }
3617     case esHalfBar:
3618     {
3619       painter->drawLine((pos+widthVec).toPointF(), pos.toPointF());
3620       break;
3621     }
3622     case esSkewedBar:
3623     {
3624       if (qFuzzyIsNull(painter->pen().widthF()) && !painter->modes().testFlag(QCPPainter::pmNonCosmetic))
3625       {
3626         // if drawing with cosmetic pen (perfectly thin stroke, happens only in vector exports), draw bar exactly on tip of line
3627         painter->drawLine((pos+widthVec+lengthVec*0.2f*(mInverted?-1:1)).toPointF(),
3628                           (pos-widthVec-lengthVec*0.2f*(mInverted?-1:1)).toPointF());
3629       } else
3630       {
3631         // if drawing with thick (non-cosmetic) pen, shift bar a little in line direction to prevent line from sticking through bar slightly
3632         painter->drawLine((pos+widthVec+lengthVec*0.2f*(mInverted?-1:1)+dir.normalized()*qMax(1.0f, (float)painter->pen().widthF())*0.5f).toPointF(),
3633                           (pos-widthVec-lengthVec*0.2f*(mInverted?-1:1)+dir.normalized()*qMax(1.0f, (float)painter->pen().widthF())*0.5f).toPointF());
3634       }
3635       break;
3636     }
3637   }
3638 }
3639
3640 /*! \internal
3641   \overload
3642   
3643   Draws the line ending. The direction is controlled with the \a angle parameter in radians.
3644 */
3645 void QCPLineEnding::draw(QCPPainter *painter, const QVector2D &pos, double angle) const
3646 {
3647   draw(painter, pos, QVector2D(qCos(angle), qSin(angle)));
3648 }
3649
3650
3651 ////////////////////////////////////////////////////////////////////////////////////////////////////
3652 //////////////////// QCPGrid
3653 ////////////////////////////////////////////////////////////////////////////////////////////////////
3654
3655 /*! \class QCPGrid
3656   \brief Responsible for drawing the grid of a QCPAxis.
3657   
3658   This class is tightly bound to QCPAxis. Every axis owns a grid instance and uses it to draw the
3659   grid lines, sub grid lines and zero-line. You can interact with the grid of an axis via \ref
3660   QCPAxis::grid. Normally, you don't need to create an instance of QCPGrid yourself.
3661   
3662   The axis and grid drawing was split into two classes to allow them to be placed on different
3663   layers (both QCPAxis and QCPGrid inherit from QCPLayerable). Thus it is possible to have the grid
3664   in the background and the axes in the foreground, and any plottables/items in between. This
3665   described situation is the default setup, see the QCPLayer documentation.
3666 */
3667
3668 /*!
3669   Creates a QCPGrid instance and sets default values.
3670   
3671   You shouldn't instantiate grids on their own, since every QCPAxis brings its own QCPGrid.
3672 */
3673 QCPGrid::QCPGrid(QCPAxis *parentAxis) :
3674   QCPLayerable(parentAxis->parentPlot(), QString(), parentAxis),
3675   mParentAxis(parentAxis)
3676 {
3677   // warning: this is called in QCPAxis constructor, so parentAxis members should not be accessed/called
3678   setParent(parentAxis);
3679   setPen(QPen(QColor(200,200,200), 0, Qt::DotLine));
3680   setSubGridPen(QPen(QColor(220,220,220), 0, Qt::DotLine));
3681   setZeroLinePen(QPen(QColor(200,200,200), 0, Qt::SolidLine));
3682   setSubGridVisible(false);
3683   setAntialiased(false);
3684   setAntialiasedSubGrid(false);
3685   setAntialiasedZeroLine(false);
3686 }
3687
3688 /*!
3689   Sets whether grid lines at sub tick marks are drawn.
3690   
3691   \see setSubGridPen
3692 */
3693 void QCPGrid::setSubGridVisible(bool visible)
3694 {
3695   mSubGridVisible = visible;
3696 }
3697
3698 /*!
3699   Sets whether sub grid lines are drawn antialiased.
3700 */
3701 void QCPGrid::setAntialiasedSubGrid(bool enabled)
3702 {
3703   mAntialiasedSubGrid = enabled;
3704 }
3705
3706 /*!
3707   Sets whether zero lines are drawn antialiased.
3708 */
3709 void QCPGrid::setAntialiasedZeroLine(bool enabled)
3710 {
3711   mAntialiasedZeroLine = enabled;
3712 }
3713
3714 /*!
3715   Sets the pen with which (major) grid lines are drawn.
3716 */
3717 void QCPGrid::setPen(const QPen &pen)
3718 {
3719   mPen = pen;
3720 }
3721
3722 /*!
3723   Sets the pen with which sub grid lines are drawn.
3724 */
3725 void QCPGrid::setSubGridPen(const QPen &pen)
3726 {
3727   mSubGridPen = pen;
3728 }
3729
3730 /*!
3731   Sets the pen with which zero lines are drawn.
3732   
3733   Zero lines are lines at value coordinate 0 which may be drawn with a different pen than other grid
3734   lines. To disable zero lines and just draw normal grid lines at zero, set \a pen to Qt::NoPen.
3735 */
3736 void QCPGrid::setZeroLinePen(const QPen &pen)
3737 {
3738   mZeroLinePen = pen;
3739 }
3740
3741 /*! \internal
3742
3743   A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter
3744   before drawing the major grid lines.
3745
3746   This is the antialiasing state the painter passed to the \ref draw method is in by default.
3747   
3748   This function takes into account the local setting of the antialiasing flag as well as the
3749   overrides set with \ref QCustomPlot::setAntialiasedElements and \ref
3750   QCustomPlot::setNotAntialiasedElements.
3751   
3752   \see setAntialiased
3753 */
3754 void QCPGrid::applyDefaultAntialiasingHint(QCPPainter *painter) const
3755 {
3756   applyAntialiasingHint(painter, mAntialiased, QCP::aeGrid);
3757 }
3758
3759 /*! \internal
3760   
3761   Draws grid lines and sub grid lines at the positions of (sub) ticks of the parent axis, spanning
3762   over the complete axis rect. Also draws the zero line, if appropriate (\ref setZeroLinePen).
3763 */
3764 void QCPGrid::draw(QCPPainter *painter)
3765 {
3766   if (!mParentAxis) { qDebug() << Q_FUNC_INFO << "invalid parent axis"; return; }
3767   
3768   if (mSubGridVisible)
3769     drawSubGridLines(painter);
3770   drawGridLines(painter);
3771 }
3772
3773 /*! \internal
3774   
3775   Draws the main grid lines and possibly a zero line with the specified painter.
3776   
3777   This is a helper function called by \ref draw.
3778 */
3779 void QCPGrid::drawGridLines(QCPPainter *painter) const
3780 {
3781   if (!mParentAxis) { qDebug() << Q_FUNC_INFO << "invalid parent axis"; return; }
3782   
3783   int lowTick = mParentAxis->mLowestVisibleTick;
3784   int highTick = mParentAxis->mHighestVisibleTick;
3785   double t; // helper variable, result of coordinate-to-pixel transforms
3786   if (mParentAxis->orientation() == Qt::Horizontal)
3787   {
3788     // draw zeroline:
3789     int zeroLineIndex = -1;
3790     if (mZeroLinePen.style() != Qt::NoPen && mParentAxis->mRange.lower < 0 && mParentAxis->mRange.upper > 0)
3791     {
3792       applyAntialiasingHint(painter, mAntialiasedZeroLine, QCP::aeZeroLine);
3793       painter->setPen(mZeroLinePen);
3794       double epsilon = mParentAxis->range().size()*1E-6; // for comparing double to zero
3795       for (int i=lowTick; i <= highTick; ++i)
3796       {
3797         if (qAbs(mParentAxis->mTickVector.at(i)) < epsilon)
3798         {
3799           zeroLineIndex = i;
3800           t = mParentAxis->coordToPixel(mParentAxis->mTickVector.at(i)); // x
3801           painter->drawLine(QLineF(t, mParentAxis->mAxisRect->bottom(), t, mParentAxis->mAxisRect->top()));
3802           break;
3803         }
3804       }
3805     }
3806     // draw grid lines:
3807     applyDefaultAntialiasingHint(painter);
3808     painter->setPen(mPen);
3809     for (int i=lowTick; i <= highTick; ++i)
3810     {
3811       if (i == zeroLineIndex) continue; // don't draw a gridline on top of the zeroline
3812       t = mParentAxis->coordToPixel(mParentAxis->mTickVector.at(i)); // x
3813       painter->drawLine(QLineF(t, mParentAxis->mAxisRect->bottom(), t, mParentAxis->mAxisRect->top()));
3814     }
3815   } else
3816   {
3817     // draw zeroline:
3818     int zeroLineIndex = -1;
3819     if (mZeroLinePen.style() != Qt::NoPen && mParentAxis->mRange.lower < 0 && mParentAxis->mRange.upper > 0)
3820     {
3821       applyAntialiasingHint(painter, mAntialiasedZeroLine, QCP::aeZeroLine);
3822       painter->setPen(mZeroLinePen);
3823       double epsilon = mParentAxis->mRange.size()*1E-6; // for comparing double to zero
3824       for (int i=lowTick; i <= highTick; ++i)
3825       {
3826         if (qAbs(mParentAxis->mTickVector.at(i)) < epsilon)
3827         {
3828           zeroLineIndex = i;
3829           t = mParentAxis->coordToPixel(mParentAxis->mTickVector.at(i)); // y
3830           painter->drawLine(QLineF(mParentAxis->mAxisRect->left(), t, mParentAxis->mAxisRect->right(), t));
3831           break;
3832         }
3833       }
3834     }
3835     // draw grid lines:
3836     applyDefaultAntialiasingHint(painter);
3837     painter->setPen(mPen);
3838     for (int i=lowTick; i <= highTick; ++i)
3839     {
3840       if (i == zeroLineIndex) continue; // don't draw a gridline on top of the zeroline
3841       t = mParentAxis->coordToPixel(mParentAxis->mTickVector.at(i)); // y
3842       painter->drawLine(QLineF(mParentAxis->mAxisRect->left(), t, mParentAxis->mAxisRect->right(), t));
3843     }
3844   }
3845 }
3846
3847 /*! \internal
3848   
3849   Draws the sub grid lines with the specified painter.
3850   
3851   This is a helper function called by \ref draw.
3852 */
3853 void QCPGrid::drawSubGridLines(QCPPainter *painter) const
3854 {
3855   if (!mParentAxis) { qDebug() << Q_FUNC_INFO << "invalid parent axis"; return; }
3856   
3857   applyAntialiasingHint(painter, mAntialiasedSubGrid, QCP::aeSubGrid);
3858   double t; // helper variable, result of coordinate-to-pixel transforms
3859   painter->setPen(mSubGridPen);
3860   if (mParentAxis->orientation() == Qt::Horizontal)
3861   {
3862     for (int i=0; i<mParentAxis->mSubTickVector.size(); ++i)
3863     {
3864       t = mParentAxis->coordToPixel(mParentAxis->mSubTickVector.at(i)); // x
3865       painter->drawLine(QLineF(t, mParentAxis->mAxisRect->bottom(), t, mParentAxis->mAxisRect->top()));
3866     }
3867   } else
3868   {
3869     for (int i=0; i<mParentAxis->mSubTickVector.size(); ++i)
3870     {
3871       t = mParentAxis->coordToPixel(mParentAxis->mSubTickVector.at(i)); // y
3872       painter->drawLine(QLineF(mParentAxis->mAxisRect->left(), t, mParentAxis->mAxisRect->right(), t));
3873     }
3874   }
3875 }
3876
3877
3878 ////////////////////////////////////////////////////////////////////////////////////////////////////
3879 //////////////////// QCPAxis
3880 ////////////////////////////////////////////////////////////////////////////////////////////////////
3881
3882 /*! \class QCPAxis
3883   \brief Manages a single axis inside a QCustomPlot.
3884
3885   Usually doesn't need to be instantiated externally. Access %QCustomPlot's default four axes via
3886   QCustomPlot::xAxis (bottom), QCustomPlot::yAxis (left), QCustomPlot::xAxis2 (top) and
3887   QCustomPlot::yAxis2 (right).
3888   
3889   Axes are always part of an axis rect, see QCPAxisRect.
3890   \image html AxisNamesOverview.png
3891   <center>Naming convention of axis parts</center>
3892   \n
3893     
3894   \image html AxisRectSpacingOverview.png
3895   <center>Overview of the spacings and paddings that define the geometry of an axis. The dashed gray line
3896   on the left represents the QCustomPlot widget border.</center>
3897
3898 */
3899
3900 /* start of documentation of inline functions */
3901
3902 /*! \fn Qt::Orientation QCPAxis::orientation() const
3903   
3904   Returns the orientation of this axis. The axis orientation (horizontal or vertical) is deduced
3905   from the axis type (left, top, right or bottom).
3906   
3907   \see orientation(AxisType type)
3908 */
3909
3910 /*! \fn QCPGrid *QCPAxis::grid() const
3911   
3912   Returns the \ref QCPGrid instance belonging to this axis. Access it to set details about the way the
3913   grid is displayed.
3914 */
3915
3916 /*! \fn static Qt::Orientation QCPAxis::orientation(AxisType type)
3917   
3918   Returns the orientation of the specified axis type
3919   
3920   \see orientation()
3921 */
3922
3923 /* end of documentation of inline functions */
3924 /* start of documentation of signals */
3925
3926 /*! \fn void QCPAxis::ticksRequest()
3927   
3928   This signal is emitted when \ref setAutoTicks is false and the axis is about to generate tick
3929   labels for a replot.
3930   
3931   Modifying the tick positions can be done with \ref setTickVector. If you also want to control the
3932   tick labels, set \ref setAutoTickLabels to false and also provide the labels with \ref
3933   setTickVectorLabels.
3934   
3935   If you only want static ticks you probably don't need this signal, since you can just set the
3936   tick vector (and possibly tick label vector) once. However, if you want to provide ticks (and
3937   maybe labels) dynamically, e.g. depending on the current axis range, connect a slot to this
3938   signal and set the vector/vectors there.
3939 */
3940
3941 /*! \fn void QCPAxis::rangeChanged(const QCPRange &newRange)
3942
3943   This signal is emitted when the range of this axis has changed. You can connect it to the \ref
3944   setRange slot of another axis to communicate the new range to the other axis, in order for it to
3945   be synchronized.
3946   
3947   You may also manipulate/correct the range with \ref setRange in a slot connected to this signal.
3948   This is useful if for example a maximum range span shall not be exceeded, or if the lower/upper
3949   range shouldn't go beyond certain values. For example, the following slot would limit the x axis
3950   to only positive ranges:
3951   \code
3952   if (newRange.lower < 0)
3953     plot->xAxis->setRange(0, newRange.size());
3954   \endcode
3955 */
3956
3957 /*! \fn void QCPAxis::rangeChanged(const QCPRange &newRange, const QCPRange &oldRange)
3958   \overload
3959   
3960   Additionally to the new range, this signal also provides the previous range held by the axis as
3961   \a oldRange.
3962 */
3963
3964 /*! \fn void QCPAxis::scaleTypeChanged(QCPAxis::ScaleType scaleType);
3965   
3966   This signal is emitted when the scale type changes, by calls to \ref setScaleType
3967 */
3968
3969 /*! \fn void QCPAxis::selectionChanged(QCPAxis::SelectableParts selection)
3970   
3971   This signal is emitted when the selection state of this axis has changed, either by user interaction
3972   or by a direct call to \ref setSelectedParts.
3973 */
3974
3975 /*! \fn void QCPAxis::selectableChanged(const QCPAxis::SelectableParts &parts);
3976   
3977   This signal is emitted when the selectability changes, by calls to \ref setSelectableParts
3978 */
3979
3980 /* end of documentation of signals */
3981
3982 /*!
3983   Constructs an Axis instance of Type \a type for the axis rect \a parent.
3984   
3985   Usually it isn't necessary to instantiate axes directly, because you can let QCustomPlot create
3986   them for you with \ref QCPAxisRect::addAxis. If you want to use own QCPAxis-subclasses however,
3987   create them manually and then inject them also via \ref QCPAxisRect::addAxis.
3988 */
3989 QCPAxis::QCPAxis(QCPAxisRect *parent, AxisType type) :
3990   QCPLayerable(parent->parentPlot(), QString(), parent),
3991   // axis base:
3992   mAxisType(type),
3993   mAxisRect(parent),
3994   mPadding(5),
3995   mOrientation(orientation(type)),
3996   mSelectableParts(spAxis | spTickLabels | spAxisLabel),
3997   mSelectedParts(spNone),
3998   mBasePen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)),
3999   mSelectedBasePen(QPen(Qt::blue, 2)),
4000   // axis label:
4001   mLabel(),
4002   mLabelFont(mParentPlot->font()),
4003   mSelectedLabelFont(QFont(mLabelFont.family(), mLabelFont.pointSize(), QFont::Bold)),
4004   mLabelColor(Qt::black),
4005   mSelectedLabelColor(Qt::blue),
4006   // tick labels:
4007   mTickLabels(true),
4008   mAutoTickLabels(true),
4009   mTickLabelType(ltNumber),
4010   mTickLabelFont(mParentPlot->font()),
4011   mSelectedTickLabelFont(QFont(mTickLabelFont.family(), mTickLabelFont.pointSize(), QFont::Bold)),
4012   mTickLabelColor(Qt::black),
4013   mSelectedTickLabelColor(Qt::blue),
4014   mDateTimeFormat(QLatin1String("hh:mm:ss\ndd.MM.yy")),
4015   mDateTimeSpec(Qt::LocalTime),
4016   mNumberPrecision(6),
4017   mNumberFormatChar('g'),
4018   mNumberBeautifulPowers(true),
4019   // ticks and subticks:
4020   mTicks(true),
4021   mTickStep(1),
4022   mSubTickCount(4),
4023   mAutoTickCount(6),
4024   mAutoTicks(true),
4025   mAutoTickStep(true),
4026   mAutoSubTicks(true),
4027   mTickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)),
4028   mSelectedTickPen(QPen(Qt::blue, 2)),
4029   mSubTickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)),
4030   mSelectedSubTickPen(QPen(Qt::blue, 2)),
4031   // scale and range:
4032   mRange(0, 5),
4033   mRangeReversed(false),
4034   mScaleType(stLinear),
4035   mScaleLogBase(10),
4036   mScaleLogBaseLogInv(1.0/qLn(mScaleLogBase)),
4037   // internal members:
4038   mGrid(new QCPGrid(this)),
4039   mAxisPainter(new QCPAxisPainterPrivate(parent->parentPlot())),
4040   mLowestVisibleTick(0),
4041   mHighestVisibleTick(-1),
4042   mCachedMarginValid(false),
4043   mCachedMargin(0)
4044 {
4045   setParent(parent);
4046   mGrid->setVisible(false);
4047   setAntialiased(false);
4048   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
4049   
4050   if (type == atTop)
4051   {
4052     setTickLabelPadding(3);
4053     setLabelPadding(6);
4054   } else if (type == atRight)
4055   {
4056     setTickLabelPadding(7);
4057     setLabelPadding(12);
4058   } else if (type == atBottom)
4059   {
4060     setTickLabelPadding(3);
4061     setLabelPadding(3);
4062   } else if (type == atLeft)
4063   {
4064     setTickLabelPadding(5);
4065     setLabelPadding(10);
4066   }
4067 }
4068
4069 QCPAxis::~QCPAxis()
4070 {
4071   delete mAxisPainter;
4072   delete mGrid; // delete grid here instead of via parent ~QObject for better defined deletion order
4073 }
4074
4075 /* No documentation as it is a property getter */
4076 int QCPAxis::tickLabelPadding() const
4077 {
4078   return mAxisPainter->tickLabelPadding;
4079 }
4080
4081 /* No documentation as it is a property getter */
4082 double QCPAxis::tickLabelRotation() const
4083 {
4084   return mAxisPainter->tickLabelRotation;
4085 }
4086
4087 /* No documentation as it is a property getter */
4088 QCPAxis::LabelSide QCPAxis::tickLabelSide() const
4089 {
4090   return mAxisPainter->tickLabelSide;
4091 }
4092
4093 /* No documentation as it is a property getter */
4094 QString QCPAxis::numberFormat() const
4095 {
4096   QString result;
4097   result.append(mNumberFormatChar);
4098   if (mNumberBeautifulPowers)
4099   {
4100     result.append(QLatin1Char('b'));
4101     if (mAxisPainter->numberMultiplyCross)
4102       result.append(QLatin1Char('c'));
4103   }
4104   return result;
4105 }
4106
4107 /* No documentation as it is a property getter */
4108 int QCPAxis::tickLengthIn() const
4109 {
4110   return mAxisPainter->tickLengthIn;
4111 }
4112
4113 /* No documentation as it is a property getter */
4114 int QCPAxis::tickLengthOut() const
4115 {
4116   return mAxisPainter->tickLengthOut;
4117 }
4118
4119 /* No documentation as it is a property getter */
4120 int QCPAxis::subTickLengthIn() const
4121 {
4122   return mAxisPainter->subTickLengthIn;
4123 }
4124
4125 /* No documentation as it is a property getter */
4126 int QCPAxis::subTickLengthOut() const
4127 {
4128   return mAxisPainter->subTickLengthOut;
4129 }
4130
4131 /* No documentation as it is a property getter */
4132 int QCPAxis::labelPadding() const
4133 {
4134   return mAxisPainter->labelPadding;
4135 }
4136
4137 /* No documentation as it is a property getter */
4138 int QCPAxis::offset() const
4139 {
4140   return mAxisPainter->offset;
4141 }
4142
4143 /* No documentation as it is a property getter */
4144 QCPLineEnding QCPAxis::lowerEnding() const
4145 {
4146   return mAxisPainter->lowerEnding;
4147 }
4148
4149 /* No documentation as it is a property getter */
4150 QCPLineEnding QCPAxis::upperEnding() const
4151 {
4152   return mAxisPainter->upperEnding;
4153 }
4154
4155 /*!
4156   Sets whether the axis uses a linear scale or a logarithmic scale. If \a type is set to \ref
4157   stLogarithmic, the logarithm base can be set with \ref setScaleLogBase. In logarithmic axis
4158   scaling, major tick marks appear at all powers of the logarithm base. Properties like tick step
4159   (\ref setTickStep) don't apply in logarithmic scaling. If you wish a decimal base but less major
4160   ticks, consider choosing a logarithm base of 100, 1000 or even higher.
4161   
4162   If \a type is \ref stLogarithmic and the number format (\ref setNumberFormat) uses the 'b' option
4163   (beautifully typeset decimal powers), the display usually is "1 [multiplication sign] 10
4164   [superscript] n", which looks unnatural for logarithmic scaling (the "1 [multiplication sign]"
4165   part). To only display the decimal power, set the number precision to zero with
4166   \ref setNumberPrecision.
4167 */
4168 void QCPAxis::setScaleType(QCPAxis::ScaleType type)
4169 {
4170   if (mScaleType != type)
4171   {
4172     mScaleType = type;
4173     if (mScaleType == stLogarithmic)
4174       setRange(mRange.sanitizedForLogScale());
4175     mCachedMarginValid = false;
4176     emit scaleTypeChanged(mScaleType);
4177   }
4178 }
4179
4180 /*!
4181   If \ref setScaleType is set to \ref stLogarithmic, \a base will be the logarithm base of the
4182   scaling. In logarithmic axis scaling, major tick marks appear at all powers of \a base.
4183   
4184   Properties like tick step (\ref setTickStep) don't apply in logarithmic scaling. If you wish a decimal base but
4185   less major ticks, consider choosing \a base 100, 1000 or even higher.
4186 */
4187 void QCPAxis::setScaleLogBase(double base)
4188 {
4189   if (base > 1)
4190   {
4191     mScaleLogBase = base;
4192     mScaleLogBaseLogInv = 1.0/qLn(mScaleLogBase); // buffer for faster baseLog() calculation
4193     mCachedMarginValid = false;
4194   } else
4195     qDebug() << Q_FUNC_INFO << "Invalid logarithmic scale base (must be greater 1):" << base;
4196 }
4197
4198 /*!
4199   Sets the range of the axis.
4200   
4201   This slot may be connected with the \ref rangeChanged signal of another axis so this axis
4202   is always synchronized with the other axis range, when it changes.
4203   
4204   To invert the direction of an axis, use \ref setRangeReversed.
4205 */
4206 void QCPAxis::setRange(const QCPRange &range)
4207 {
4208   if (range.lower == mRange.lower && range.upper == mRange.upper)
4209     return;
4210   
4211   if (!QCPRange::validRange(range)) return;
4212   QCPRange oldRange = mRange;
4213   if (mScaleType == stLogarithmic)
4214   {
4215     mRange = range.sanitizedForLogScale();
4216   } else
4217   {
4218     mRange = range.sanitizedForLinScale();
4219   }
4220   mCachedMarginValid = false;
4221   emit rangeChanged(mRange);
4222   emit rangeChanged(mRange, oldRange);
4223 }
4224
4225 /*!
4226   Sets whether the user can (de-)select the parts in \a selectable by clicking on the QCustomPlot surface.
4227   (When \ref QCustomPlot::setInteractions contains iSelectAxes.)
4228   
4229   However, even when \a selectable is set to a value not allowing the selection of a specific part,
4230   it is still possible to set the selection of this part manually, by calling \ref setSelectedParts
4231   directly.
4232   
4233   \see SelectablePart, setSelectedParts
4234 */
4235 void QCPAxis::setSelectableParts(const SelectableParts &selectable)
4236 {
4237   if (mSelectableParts != selectable)
4238   {
4239     mSelectableParts = selectable;
4240     emit selectableChanged(mSelectableParts);
4241   }
4242 }
4243
4244 /*!
4245   Sets the selected state of the respective axis parts described by \ref SelectablePart. When a part
4246   is selected, it uses a different pen/font.
4247   
4248   The entire selection mechanism for axes is handled automatically when \ref
4249   QCustomPlot::setInteractions contains iSelectAxes. You only need to call this function when you
4250   wish to change the selection state manually.
4251   
4252   This function can change the selection state of a part, independent of the \ref setSelectableParts setting.
4253   
4254   emits the \ref selectionChanged signal when \a selected is different from the previous selection state.
4255   
4256   \see SelectablePart, setSelectableParts, selectTest, setSelectedBasePen, setSelectedTickPen, setSelectedSubTickPen,
4257   setSelectedTickLabelFont, setSelectedLabelFont, setSelectedTickLabelColor, setSelectedLabelColor
4258 */
4259 void QCPAxis::setSelectedParts(const SelectableParts &selected)
4260 {
4261   if (mSelectedParts != selected)
4262   {
4263     mSelectedParts = selected;
4264     emit selectionChanged(mSelectedParts);
4265   }
4266 }
4267
4268 /*!
4269   \overload
4270   
4271   Sets the lower and upper bound of the axis range.
4272   
4273   To invert the direction of an axis, use \ref setRangeReversed.
4274   
4275   There is also a slot to set a range, see \ref setRange(const QCPRange &range).
4276 */
4277 void QCPAxis::setRange(double lower, double upper)
4278 {
4279   if (lower == mRange.lower && upper == mRange.upper)
4280     return;
4281   
4282   if (!QCPRange::validRange(lower, upper)) return;
4283   QCPRange oldRange = mRange;
4284   mRange.lower = lower;
4285   mRange.upper = upper;
4286   if (mScaleType == stLogarithmic)
4287   {
4288     mRange = mRange.sanitizedForLogScale();
4289   } else
4290   {
4291     mRange = mRange.sanitizedForLinScale();
4292   }
4293   mCachedMarginValid = false;
4294   emit rangeChanged(mRange);
4295   emit rangeChanged(mRange, oldRange);
4296 }
4297
4298 /*!
4299   \overload
4300   
4301   Sets the range of the axis.
4302   
4303   The \a position coordinate indicates together with the \a alignment parameter, where the new
4304   range will be positioned. \a size defines the size of the new axis range. \a alignment may be
4305   Qt::AlignLeft, Qt::AlignRight or Qt::AlignCenter. This will cause the left border, right border,
4306   or center of the range to be aligned with \a position. Any other values of \a alignment will
4307   default to Qt::AlignCenter.
4308 */
4309 void QCPAxis::setRange(double position, double size, Qt::AlignmentFlag alignment)
4310 {
4311   if (alignment == Qt::AlignLeft)
4312     setRange(position, position+size);
4313   else if (alignment == Qt::AlignRight)
4314     setRange(position-size, position);
4315   else // alignment == Qt::AlignCenter
4316     setRange(position-size/2.0, position+size/2.0);
4317 }
4318
4319 /*!
4320   Sets the lower bound of the axis range. The upper bound is not changed.
4321   \see setRange
4322 */
4323 void QCPAxis::setRangeLower(double lower)
4324 {
4325   if (mRange.lower == lower)
4326     return;
4327   
4328   QCPRange oldRange = mRange;
4329   mRange.lower = lower;
4330   if (mScaleType == stLogarithmic)
4331   {
4332     mRange = mRange.sanitizedForLogScale();
4333   } else
4334   {
4335     mRange = mRange.sanitizedForLinScale();
4336   }
4337   mCachedMarginValid = false;
4338   emit rangeChanged(mRange);
4339   emit rangeChanged(mRange, oldRange);
4340 }
4341
4342 /*!
4343   Sets the upper bound of the axis range. The lower bound is not changed.
4344   \see setRange
4345 */
4346 void QCPAxis::setRangeUpper(double upper)
4347 {
4348   if (mRange.upper == upper)
4349     return;
4350   
4351   QCPRange oldRange = mRange;
4352   mRange.upper = upper;
4353   if (mScaleType == stLogarithmic)
4354   {
4355     mRange = mRange.sanitizedForLogScale();
4356   } else
4357   {
4358     mRange = mRange.sanitizedForLinScale();
4359   }
4360   mCachedMarginValid = false;
4361   emit rangeChanged(mRange);
4362   emit rangeChanged(mRange, oldRange);
4363 }
4364
4365 /*!
4366   Sets whether the axis range (direction) is displayed reversed. Normally, the values on horizontal
4367   axes increase left to right, on vertical axes bottom to top. When \a reversed is set to true, the
4368   direction of increasing values is inverted.
4369
4370   Note that the range and data interface stays the same for reversed axes, e.g. the \a lower part
4371   of the \ref setRange interface will still reference the mathematically smaller number than the \a
4372   upper part.
4373 */
4374 void QCPAxis::setRangeReversed(bool reversed)
4375 {
4376   if (mRangeReversed != reversed)
4377   {
4378     mRangeReversed = reversed;
4379     mCachedMarginValid = false;
4380   }
4381 }
4382
4383 /*!
4384   Sets whether the tick positions should be calculated automatically (either from an automatically
4385   generated tick step or a tick step provided manually via \ref setTickStep, see \ref setAutoTickStep).
4386   
4387   If \a on is set to false, you must provide the tick positions manually via \ref setTickVector.
4388   For these manual ticks you may let QCPAxis generate the appropriate labels automatically by
4389   leaving \ref setAutoTickLabels set to true. If you also wish to control the displayed labels
4390   manually, set \ref setAutoTickLabels to false and provide the label strings with \ref
4391   setTickVectorLabels.
4392   
4393   If you need dynamically calculated tick vectors (and possibly tick label vectors), set the
4394   vectors in a slot connected to the \ref ticksRequest signal.
4395   
4396   \see setAutoTickLabels, setAutoSubTicks, setAutoTickCount, setAutoTickStep
4397 */
4398 void QCPAxis::setAutoTicks(bool on)
4399 {
4400   if (mAutoTicks != on)
4401   {
4402     mAutoTicks = on;
4403     mCachedMarginValid = false;
4404   }
4405 }
4406
4407 /*!
4408   When \ref setAutoTickStep is true, \a approximateCount determines how many ticks should be
4409   generated in the visible range, approximately.
4410   
4411   It's not guaranteed that this number of ticks is met exactly, but approximately within a
4412   tolerance of about two.
4413   
4414   Only values greater than zero are accepted as \a approximateCount.
4415   
4416   \see setAutoTickStep, setAutoTicks, setAutoSubTicks
4417 */
4418 void QCPAxis::setAutoTickCount(int approximateCount)
4419 {
4420   if (mAutoTickCount != approximateCount)
4421   {
4422     if (approximateCount > 0)
4423     {
4424       mAutoTickCount = approximateCount;
4425       mCachedMarginValid = false;
4426     } else
4427       qDebug() << Q_FUNC_INFO << "approximateCount must be greater than zero:" << approximateCount;
4428   }
4429 }
4430
4431 /*!
4432   Sets whether the tick labels are generated automatically. Depending on the tick label type (\ref
4433   ltNumber or \ref ltDateTime), the labels will either show the coordinate as floating point
4434   number (\ref setNumberFormat), or a date/time formatted according to \ref setDateTimeFormat.
4435   
4436   If \a on is set to false, you should provide the tick labels via \ref setTickVectorLabels. This
4437   is usually used in a combination with \ref setAutoTicks set to false for complete control over
4438   tick positions and labels, e.g. when the ticks should be at multiples of pi and show "2pi", "3pi"
4439   etc. as tick labels.
4440   
4441   If you need dynamically calculated tick vectors (and possibly tick label vectors), set the
4442   vectors in a slot connected to the \ref ticksRequest signal.
4443   
4444   \see setAutoTicks
4445 */
4446 void QCPAxis::setAutoTickLabels(bool on)
4447 {
4448   if (mAutoTickLabels != on)
4449   {
4450     mAutoTickLabels = on;
4451     mCachedMarginValid = false;
4452   }
4453 }
4454
4455 /*!
4456   Sets whether the tick step, i.e. the interval between two (major) ticks, is calculated
4457   automatically. If \a on is set to true, the axis finds a tick step that is reasonable for human
4458   readable plots.
4459
4460   The number of ticks the algorithm aims for within the visible range can be specified with \ref
4461   setAutoTickCount.
4462   
4463   If \a on is set to false, you may set the tick step manually with \ref setTickStep.
4464   
4465   \see setAutoTicks, setAutoSubTicks, setAutoTickCount
4466 */
4467 void QCPAxis::setAutoTickStep(bool on)
4468 {
4469   if (mAutoTickStep != on)
4470   {
4471     mAutoTickStep = on;
4472     mCachedMarginValid = false;
4473   }
4474 }
4475
4476 /*!
4477   Sets whether the number of sub ticks in one tick interval is determined automatically. This
4478   works, as long as the tick step mantissa is a multiple of 0.5. When \ref setAutoTickStep is
4479   enabled, this is always the case.
4480   
4481   When \a on is set to false, you may set the sub tick count with \ref setSubTickCount manually.
4482   
4483   \see setAutoTickCount, setAutoTicks, setAutoTickStep
4484 */
4485 void QCPAxis::setAutoSubTicks(bool on)
4486 {
4487   if (mAutoSubTicks != on)
4488   {
4489     mAutoSubTicks = on;
4490     mCachedMarginValid = false;
4491   }
4492 }
4493
4494 /*!
4495   Sets whether tick marks are displayed.
4496
4497   Note that setting \a show to false does not imply that tick labels are invisible, too. To achieve
4498   that, see \ref setTickLabels.
4499 */
4500 void QCPAxis::setTicks(bool show)
4501 {
4502   if (mTicks != show)
4503   {
4504     mTicks = show;
4505     mCachedMarginValid = false;
4506   }
4507 }
4508
4509 /*!
4510   Sets whether tick labels are displayed. Tick labels are the numbers drawn next to tick marks.
4511 */
4512 void QCPAxis::setTickLabels(bool show)
4513 {
4514   if (mTickLabels != show)
4515   {
4516     mTickLabels = show;
4517     mCachedMarginValid = false;
4518   }
4519 }
4520
4521 /*!
4522   Sets the distance between the axis base line (including any outward ticks) and the tick labels.
4523   \see setLabelPadding, setPadding
4524 */
4525 void QCPAxis::setTickLabelPadding(int padding)
4526 {
4527   if (mAxisPainter->tickLabelPadding != padding)
4528   {
4529     mAxisPainter->tickLabelPadding = padding;
4530     mCachedMarginValid = false;
4531   }
4532 }
4533
4534 /*!
4535   Sets whether the tick labels display numbers or dates/times.
4536   
4537   If \a type is set to \ref ltNumber, the format specifications of \ref setNumberFormat apply.
4538   
4539   If \a type is set to \ref ltDateTime, the format specifications of \ref setDateTimeFormat apply.
4540   
4541   In QCustomPlot, date/time coordinates are <tt>double</tt> numbers representing the seconds since
4542   1970-01-01T00:00:00 UTC. This format can be retrieved from QDateTime objects with the
4543   QDateTime::toTime_t() function. Since this only gives a resolution of one second, there is also
4544   the QDateTime::toMSecsSinceEpoch() function which returns the timespan described above in
4545   milliseconds. Divide its return value by 1000.0 to get a value with the format needed for
4546   date/time plotting, with a resolution of one millisecond.
4547   
4548   Using the toMSecsSinceEpoch function allows dates that go back to 2nd January 4713 B.C.
4549   (represented by a negative number), unlike the toTime_t function, which works with unsigned
4550   integers and thus only goes back to 1st January 1970. So both for range and accuracy, use of
4551   toMSecsSinceEpoch()/1000.0 should be preferred as key coordinate for date/time axes.
4552   
4553   \see setTickLabels
4554 */
4555 void QCPAxis::setTickLabelType(LabelType type)
4556 {
4557   if (mTickLabelType != type)
4558   {
4559     mTickLabelType = type;
4560     mCachedMarginValid = false;
4561   }
4562 }
4563
4564 /*!
4565   Sets the font of the tick labels.
4566   
4567   \see setTickLabels, setTickLabelColor
4568 */
4569 void QCPAxis::setTickLabelFont(const QFont &font)
4570 {
4571   if (font != mTickLabelFont)
4572   {
4573     mTickLabelFont = font;
4574     mCachedMarginValid = false;
4575   }
4576 }
4577
4578 /*!
4579   Sets the color of the tick labels.
4580   
4581   \see setTickLabels, setTickLabelFont
4582 */
4583 void QCPAxis::setTickLabelColor(const QColor &color)
4584 {
4585   if (color != mTickLabelColor)
4586   {
4587     mTickLabelColor = color;
4588     mCachedMarginValid = false;
4589   }
4590 }
4591
4592 /*!
4593   Sets the rotation of the tick labels. If \a degrees is zero, the labels are drawn normally. Else,
4594   the tick labels are drawn rotated by \a degrees clockwise. The specified angle is bound to values
4595   from -90 to 90 degrees.
4596   
4597   If \a degrees is exactly -90, 0 or 90, the tick labels are centered on the tick coordinate. For
4598   other angles, the label is drawn with an offset such that it seems to point toward or away from
4599   the tick mark.
4600 */
4601 void QCPAxis::setTickLabelRotation(double degrees)
4602 {
4603   if (!qFuzzyIsNull(degrees-mAxisPainter->tickLabelRotation))
4604   {
4605     mAxisPainter->tickLabelRotation = qBound(-90.0, degrees, 90.0);
4606     mCachedMarginValid = false;
4607   }
4608 }
4609
4610 /*!
4611   Sets whether the tick labels (numbers) shall appear inside or outside the axis rect.
4612   
4613   The usual and default setting is \ref lsOutside. Very compact plots sometimes require tick labels
4614   to be inside the axis rect, to save space. If \a side is set to \ref lsInside, the tick labels
4615   appear on the inside are additionally clipped to the axis rect.
4616 */
4617 void QCPAxis::setTickLabelSide(LabelSide side)
4618 {
4619   mAxisPainter->tickLabelSide = side;
4620   mCachedMarginValid = false;
4621 }
4622
4623 /*!
4624   Sets the format in which dates and times are displayed as tick labels, if \ref setTickLabelType is \ref ltDateTime.
4625   for details about the \a format string, see the documentation of QDateTime::toString().
4626   
4627   Newlines can be inserted with "\n".
4628   
4629   \see setDateTimeSpec
4630 */
4631 void QCPAxis::setDateTimeFormat(const QString &format)
4632 {
4633   if (mDateTimeFormat != format)
4634   {
4635     mDateTimeFormat = format;
4636     mCachedMarginValid = false;
4637   }
4638 }
4639
4640 /*!
4641   Sets the time spec that is used for the date time values when \ref setTickLabelType is \ref
4642   ltDateTime.
4643
4644   The default value of QDateTime objects (and also QCustomPlot) is <tt>Qt::LocalTime</tt>. However,
4645   if the date time values passed to QCustomPlot are given in the UTC spec, set \a
4646   timeSpec to <tt>Qt::UTC</tt> to get the correct axis labels.
4647   
4648   \see setDateTimeFormat
4649 */
4650 void QCPAxis::setDateTimeSpec(const Qt::TimeSpec &timeSpec)
4651 {
4652   mDateTimeSpec = timeSpec;
4653 }
4654
4655 /*!
4656   Sets the number format for the numbers drawn as tick labels (if tick label type is \ref
4657   ltNumber). This \a formatCode is an extended version of the format code used e.g. by
4658   QString::number() and QLocale::toString(). For reference about that, see the "Argument Formats"
4659   section in the detailed description of the QString class. \a formatCode is a string of one, two
4660   or three characters. The first character is identical to the normal format code used by Qt. In
4661   short, this means: 'e'/'E' scientific format, 'f' fixed format, 'g'/'G' scientific or fixed,
4662   whichever is shorter.
4663   
4664   The second and third characters are optional and specific to QCustomPlot:\n
4665   If the first char was 'e' or 'g', numbers are/might be displayed in the scientific format, e.g.
4666   "5.5e9", which is ugly in a plot. So when the second char of \a formatCode is set to 'b' (for
4667   "beautiful"), those exponential numbers are formatted in a more natural way, i.e. "5.5
4668   [multiplication sign] 10 [superscript] 9". By default, the multiplication sign is a centered dot.
4669   If instead a cross should be shown (as is usual in the USA), the third char of \a formatCode can
4670   be set to 'c'. The inserted multiplication signs are the UTF-8 characters 215 (0xD7) for the
4671   cross and 183 (0xB7) for the dot.
4672   
4673   If the scale type (\ref setScaleType) is \ref stLogarithmic and the \a formatCode uses the 'b'
4674   option (beautifully typeset decimal powers), the display usually is "1 [multiplication sign] 10
4675   [superscript] n", which looks unnatural for logarithmic scaling (the "1 [multiplication sign]"
4676   part). To only display the decimal power, set the number precision to zero with \ref
4677   setNumberPrecision.
4678   
4679   Examples for \a formatCode:
4680   \li \c g normal format code behaviour. If number is small, fixed format is used, if number is large,
4681   normal scientific format is used
4682   \li \c gb If number is small, fixed format is used, if number is large, scientific format is used with
4683   beautifully typeset decimal powers and a dot as multiplication sign
4684   \li \c ebc All numbers are in scientific format with beautifully typeset decimal power and a cross as
4685   multiplication sign
4686   \li \c fb illegal format code, since fixed format doesn't support (or need) beautifully typeset decimal
4687   powers. Format code will be reduced to 'f'.
4688   \li \c hello illegal format code, since first char is not 'e', 'E', 'f', 'g' or 'G'. Current format
4689   code will not be changed.
4690 */
4691 void QCPAxis::setNumberFormat(const QString &formatCode)
4692 {
4693   if (formatCode.isEmpty())
4694   {
4695     qDebug() << Q_FUNC_INFO << "Passed formatCode is empty";
4696     return;
4697   }
4698   mCachedMarginValid = false;
4699   
4700   // interpret first char as number format char:
4701   QString allowedFormatChars(QLatin1String("eEfgG"));
4702   if (allowedFormatChars.contains(formatCode.at(0)))
4703   {
4704     mNumberFormatChar = QLatin1Char(formatCode.at(0).toLatin1());
4705   } else
4706   {
4707     qDebug() << Q_FUNC_INFO << "Invalid number format code (first char not in 'eEfgG'):" << formatCode;
4708     return;
4709   }
4710   if (formatCode.length() < 2)
4711   {
4712     mNumberBeautifulPowers = false;
4713     mAxisPainter->numberMultiplyCross = false;
4714     return;
4715   }
4716   
4717   // interpret second char as indicator for beautiful decimal powers:
4718   if (formatCode.at(1) == QLatin1Char('b') && (mNumberFormatChar == QLatin1Char('e') || mNumberFormatChar == QLatin1Char('g')))
4719   {
4720     mNumberBeautifulPowers = true;
4721   } else
4722   {
4723     qDebug() << Q_FUNC_INFO << "Invalid number format code (second char not 'b' or first char neither 'e' nor 'g'):" << formatCode;
4724     return;
4725   }
4726   if (formatCode.length() < 3)
4727   {
4728     mAxisPainter->numberMultiplyCross = false;
4729     return;
4730   }
4731   
4732   // interpret third char as indicator for dot or cross multiplication symbol:
4733   if (formatCode.at(2) == QLatin1Char('c'))
4734   {
4735     mAxisPainter->numberMultiplyCross = true;
4736   } else if (formatCode.at(2) == QLatin1Char('d'))
4737   {
4738     mAxisPainter->numberMultiplyCross = false;
4739   } else
4740   {
4741     qDebug() << Q_FUNC_INFO << "Invalid number format code (third char neither 'c' nor 'd'):" << formatCode;
4742     return;
4743   }
4744 }
4745
4746 /*!
4747   Sets the precision of the tick label numbers. See QLocale::toString(double i, char f, int prec)
4748   for details. The effect of precisions are most notably for number Formats starting with 'e', see
4749   \ref setNumberFormat
4750
4751   If the scale type (\ref setScaleType) is \ref stLogarithmic and the number format (\ref
4752   setNumberFormat) uses the 'b' format code (beautifully typeset decimal powers), the display
4753   usually is "1 [multiplication sign] 10 [superscript] n", which looks unnatural for logarithmic
4754   scaling (the redundant "1 [multiplication sign]" part). To only display the decimal power "10
4755   [superscript] n", set \a precision to zero.
4756 */
4757 void QCPAxis::setNumberPrecision(int precision)
4758 {
4759   if (mNumberPrecision != precision)
4760   {
4761     mNumberPrecision = precision;
4762     mCachedMarginValid = false;
4763   }
4764 }
4765
4766 /*!
4767   If \ref setAutoTickStep is set to false, use this function to set the tick step manually.
4768   The tick step is the interval between (major) ticks, in plot coordinates.
4769   \see setSubTickCount
4770 */
4771 void QCPAxis::setTickStep(double step)
4772 {
4773   if (mTickStep != step)
4774   {
4775     mTickStep = step;
4776     mCachedMarginValid = false;
4777   }
4778 }
4779
4780 /*!
4781   If you want full control over what ticks (and possibly labels) the axes show, this function is
4782   used to set the coordinates at which ticks will appear.\ref setAutoTicks must be disabled, else
4783   the provided tick vector will be overwritten with automatically generated tick coordinates upon
4784   replot. The labels of the ticks can be generated automatically when \ref setAutoTickLabels is
4785   left enabled. If it is disabled, you can set the labels manually with \ref setTickVectorLabels.
4786   
4787   \a vec is a vector containing the positions of the ticks, in plot coordinates.
4788   
4789   \warning \a vec must be sorted in ascending order, no additional checks are made to ensure this.
4790
4791   \see setTickVectorLabels
4792 */
4793 void QCPAxis::setTickVector(const QVector<double> &vec)
4794 {
4795   // don't check whether mTickVector != vec here, because it takes longer than we would save
4796   mTickVector = vec;
4797   mCachedMarginValid = false;
4798 }
4799
4800 /*!
4801   If you want full control over what ticks and labels the axes show, this function is used to set a
4802   number of QStrings that will be displayed at the tick positions which you need to provide with
4803   \ref setTickVector. These two vectors should have the same size. (Note that you need to disable
4804   \ref setAutoTicks and \ref setAutoTickLabels first.)
4805   
4806   \a vec is a vector containing the labels of the ticks. The entries correspond to the respective
4807   indices in the tick vector, passed via \ref setTickVector.
4808   
4809   \see setTickVector
4810 */
4811 void QCPAxis::setTickVectorLabels(const QVector<QString> &vec)
4812 {
4813   // don't check whether mTickVectorLabels != vec here, because it takes longer than we would save
4814   mTickVectorLabels = vec;
4815   mCachedMarginValid = false;
4816 }
4817
4818 /*!
4819   Sets the length of the ticks in pixels. \a inside is the length the ticks will reach inside the
4820   plot and \a outside is the length they will reach outside the plot. If \a outside is greater than
4821   zero, the tick labels and axis label will increase their distance to the axis accordingly, so
4822   they won't collide with the ticks.
4823   
4824   \see setSubTickLength, setTickLengthIn, setTickLengthOut
4825 */
4826 void QCPAxis::setTickLength(int inside, int outside)
4827 {
4828   setTickLengthIn(inside);
4829   setTickLengthOut(outside);
4830 }
4831
4832 /*!
4833   Sets the length of the inward ticks in pixels. \a inside is the length the ticks will reach
4834   inside the plot.
4835   
4836   \see setTickLengthOut, setTickLength, setSubTickLength
4837 */
4838 void QCPAxis::setTickLengthIn(int inside)
4839 {
4840   if (mAxisPainter->tickLengthIn != inside)
4841   {
4842     mAxisPainter->tickLengthIn = inside;
4843   }
4844 }
4845
4846 /*!
4847   Sets the length of the outward ticks in pixels. \a outside is the length the ticks will reach
4848   outside the plot. If \a outside is greater than zero, the tick labels and axis label will
4849   increase their distance to the axis accordingly, so they won't collide with the ticks.
4850   
4851   \see setTickLengthIn, setTickLength, setSubTickLength
4852 */
4853 void QCPAxis::setTickLengthOut(int outside)
4854 {
4855   if (mAxisPainter->tickLengthOut != outside)
4856   {
4857     mAxisPainter->tickLengthOut = outside;
4858     mCachedMarginValid = false; // only outside tick length can change margin
4859   }
4860 }
4861
4862 /*!
4863   Sets the number of sub ticks in one (major) tick step. A sub tick count of three for example,
4864   divides the tick intervals in four sub intervals.
4865   
4866   By default, the number of sub ticks is chosen automatically in a reasonable manner as long as the
4867   mantissa of the tick step is a multiple of 0.5. When \ref setAutoTickStep is enabled, this is
4868   always the case.
4869
4870   If you want to disable automatic sub tick count and use this function to set the count manually,
4871   see \ref setAutoSubTicks.
4872 */
4873 void QCPAxis::setSubTickCount(int count)
4874 {
4875   mSubTickCount = count;
4876 }
4877
4878 /*!
4879   Sets the length of the subticks in pixels. \a inside is the length the subticks will reach inside
4880   the plot and \a outside is the length they will reach outside the plot. If \a outside is greater
4881   than zero, the tick labels and axis label will increase their distance to the axis accordingly,
4882   so they won't collide with the ticks.
4883   
4884   \see setTickLength, setSubTickLengthIn, setSubTickLengthOut
4885 */
4886 void QCPAxis::setSubTickLength(int inside, int outside)
4887 {
4888   setSubTickLengthIn(inside);
4889   setSubTickLengthOut(outside);
4890 }
4891
4892 /*!
4893   Sets the length of the inward subticks in pixels. \a inside is the length the subticks will reach inside
4894   the plot.
4895   
4896   \see setSubTickLengthOut, setSubTickLength, setTickLength
4897 */
4898 void QCPAxis::setSubTickLengthIn(int inside)
4899 {
4900   if (mAxisPainter->subTickLengthIn != inside)
4901   {
4902     mAxisPainter->subTickLengthIn = inside;
4903   }
4904 }
4905
4906 /*!
4907   Sets the length of the outward subticks in pixels. \a outside is the length the subticks will reach
4908   outside the plot. If \a outside is greater than zero, the tick labels will increase their
4909   distance to the axis accordingly, so they won't collide with the ticks.
4910   
4911   \see setSubTickLengthIn, setSubTickLength, setTickLength
4912 */
4913 void QCPAxis::setSubTickLengthOut(int outside)
4914 {
4915   if (mAxisPainter->subTickLengthOut != outside)
4916   {
4917     mAxisPainter->subTickLengthOut = outside;
4918     mCachedMarginValid = false; // only outside tick length can change margin
4919   }
4920 }
4921
4922 /*!
4923   Sets the pen, the axis base line is drawn with.
4924   
4925   \see setTickPen, setSubTickPen
4926 */
4927 void QCPAxis::setBasePen(const QPen &pen)
4928 {
4929   mBasePen = pen;
4930 }
4931
4932 /*!
4933   Sets the pen, tick marks will be drawn with.
4934   
4935   \see setTickLength, setBasePen
4936 */
4937 void QCPAxis::setTickPen(const QPen &pen)
4938 {
4939   mTickPen = pen;
4940 }
4941
4942 /*!
4943   Sets the pen, subtick marks will be drawn with.
4944   
4945   \see setSubTickCount, setSubTickLength, setBasePen
4946 */
4947 void QCPAxis::setSubTickPen(const QPen &pen)
4948 {
4949   mSubTickPen = pen;
4950 }
4951
4952 /*!
4953   Sets the font of the axis label.
4954   
4955   \see setLabelColor
4956 */
4957 void QCPAxis::setLabelFont(const QFont &font)
4958 {
4959   if (mLabelFont != font)
4960   {
4961     mLabelFont = font;
4962     mCachedMarginValid = false;
4963   }
4964 }
4965
4966 /*!
4967   Sets the color of the axis label.
4968   
4969   \see setLabelFont
4970 */
4971 void QCPAxis::setLabelColor(const QColor &color)
4972 {
4973   mLabelColor = color;
4974 }
4975
4976 /*!
4977   Sets the text of the axis label that will be shown below/above or next to the axis, depending on
4978   its orientation. To disable axis labels, pass an empty string as \a str.
4979 */
4980 void QCPAxis::setLabel(const QString &str)
4981 {
4982   if (mLabel != str)
4983   {
4984     mLabel = str;
4985     mCachedMarginValid = false;
4986   }
4987 }
4988
4989 /*!
4990   Sets the distance between the tick labels and the axis label.
4991   
4992   \see setTickLabelPadding, setPadding
4993 */
4994 void QCPAxis::setLabelPadding(int padding)
4995 {
4996   if (mAxisPainter->labelPadding != padding)
4997   {
4998     mAxisPainter->labelPadding = padding;
4999     mCachedMarginValid = false;
5000   }
5001 }
5002
5003 /*!
5004   Sets the padding of the axis.
5005
5006   When \ref QCPAxisRect::setAutoMargins is enabled, the padding is the additional outer most space,
5007   that is left blank.
5008   
5009   The axis padding has no meaning if \ref QCPAxisRect::setAutoMargins is disabled.
5010   
5011   \see setLabelPadding, setTickLabelPadding
5012 */
5013 void QCPAxis::setPadding(int padding)
5014 {
5015   if (mPadding != padding)
5016   {
5017     mPadding = padding;
5018     mCachedMarginValid = false;
5019   }
5020 }
5021
5022 /*!
5023   Sets the offset the axis has to its axis rect side.
5024   
5025   If an axis rect side has multiple axes and automatic margin calculation is enabled for that side,
5026   only the offset of the inner most axis has meaning (even if it is set to be invisible). The
5027   offset of the other, outer axes is controlled automatically, to place them at appropriate
5028   positions.
5029 */
5030 void QCPAxis::setOffset(int offset)
5031 {
5032   mAxisPainter->offset = offset;
5033 }
5034
5035 /*!
5036   Sets the font that is used for tick labels when they are selected.
5037   
5038   \see setTickLabelFont, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions
5039 */
5040 void QCPAxis::setSelectedTickLabelFont(const QFont &font)
5041 {
5042   if (font != mSelectedTickLabelFont)
5043   {
5044     mSelectedTickLabelFont = font;
5045     // don't set mCachedMarginValid to false here because margin calculation is always done with non-selected fonts
5046   }
5047 }
5048
5049 /*!
5050   Sets the font that is used for the axis label when it is selected.
5051   
5052   \see setLabelFont, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions
5053 */
5054 void QCPAxis::setSelectedLabelFont(const QFont &font)
5055 {
5056   mSelectedLabelFont = font;
5057   // don't set mCachedMarginValid to false here because margin calculation is always done with non-selected fonts
5058 }
5059
5060 /*!
5061   Sets the color that is used for tick labels when they are selected.
5062   
5063   \see setTickLabelColor, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions
5064 */
5065 void QCPAxis::setSelectedTickLabelColor(const QColor &color)
5066 {
5067   if (color != mSelectedTickLabelColor)
5068   {
5069     mSelectedTickLabelColor = color;
5070   }
5071 }
5072
5073 /*!
5074   Sets the color that is used for the axis label when it is selected.
5075   
5076   \see setLabelColor, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions
5077 */
5078 void QCPAxis::setSelectedLabelColor(const QColor &color)
5079 {
5080   mSelectedLabelColor = color;
5081 }
5082
5083 /*!
5084   Sets the pen that is used to draw the axis base line when selected.
5085   
5086   \see setBasePen, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions
5087 */
5088 void QCPAxis::setSelectedBasePen(const QPen &pen)
5089 {
5090   mSelectedBasePen = pen;
5091 }
5092
5093 /*!
5094   Sets the pen that is used to draw the (major) ticks when selected.
5095   
5096   \see setTickPen, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions
5097 */
5098 void QCPAxis::setSelectedTickPen(const QPen &pen)
5099 {
5100   mSelectedTickPen = pen;
5101 }
5102
5103 /*!
5104   Sets the pen that is used to draw the subticks when selected.
5105   
5106   \see setSubTickPen, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions
5107 */
5108 void QCPAxis::setSelectedSubTickPen(const QPen &pen)
5109 {
5110   mSelectedSubTickPen = pen;
5111 }
5112
5113 /*!
5114   Sets the style for the lower axis ending. See the documentation of QCPLineEnding for available
5115   styles.
5116   
5117   For horizontal axes, this method refers to the left ending, for vertical axes the bottom ending.
5118   Note that this meaning does not change when the axis range is reversed with \ref
5119   setRangeReversed.
5120   
5121   \see setUpperEnding
5122 */
5123 void QCPAxis::setLowerEnding(const QCPLineEnding &ending)
5124 {
5125   mAxisPainter->lowerEnding = ending;
5126 }
5127
5128 /*!
5129   Sets the style for the upper axis ending. See the documentation of QCPLineEnding for available
5130   styles.
5131   
5132   For horizontal axes, this method refers to the right ending, for vertical axes the top ending.
5133   Note that this meaning does not change when the axis range is reversed with \ref
5134   setRangeReversed.
5135   
5136   \see setLowerEnding
5137 */
5138 void QCPAxis::setUpperEnding(const QCPLineEnding &ending)
5139 {
5140   mAxisPainter->upperEnding = ending;
5141 }
5142
5143 /*!
5144   If the scale type (\ref setScaleType) is \ref stLinear, \a diff is added to the lower and upper
5145   bounds of the range. The range is simply moved by \a diff.
5146   
5147   If the scale type is \ref stLogarithmic, the range bounds are multiplied by \a diff. This
5148   corresponds to an apparent "linear" move in logarithmic scaling by a distance of log(diff).
5149 */
5150 void QCPAxis::moveRange(double diff)
5151 {
5152   QCPRange oldRange = mRange;
5153   if (mScaleType == stLinear)
5154   {
5155     mRange.lower += diff;
5156     mRange.upper += diff;
5157   } else // mScaleType == stLogarithmic
5158   {
5159     mRange.lower *= diff;
5160     mRange.upper *= diff;
5161   }
5162   mCachedMarginValid = false;
5163   emit rangeChanged(mRange);
5164   emit rangeChanged(mRange, oldRange);
5165 }
5166
5167 /*!
5168   Scales the range of this axis by \a factor around the coordinate \a center. For example, if \a
5169   factor is 2.0, \a center is 1.0, then the axis range will double its size, and the point at
5170   coordinate 1.0 won't have changed its position in the QCustomPlot widget (i.e. coordinates
5171   around 1.0 will have moved symmetrically closer to 1.0).
5172 */
5173 void QCPAxis::scaleRange(double factor, double center)
5174 {
5175   QCPRange oldRange = mRange;
5176   if (mScaleType == stLinear)
5177   {
5178     QCPRange newRange;
5179     newRange.lower = (mRange.lower-center)*factor + center;
5180     newRange.upper = (mRange.upper-center)*factor + center;
5181     if (QCPRange::validRange(newRange))
5182       mRange = newRange.sanitizedForLinScale();
5183   } else // mScaleType == stLogarithmic
5184   {
5185     if ((mRange.upper < 0 && center < 0) || (mRange.upper > 0 && center > 0)) // make sure center has same sign as range
5186     {
5187       QCPRange newRange;
5188       newRange.lower = qPow(mRange.lower/center, factor)*center;
5189       newRange.upper = qPow(mRange.upper/center, factor)*center;
5190       if (QCPRange::validRange(newRange))
5191         mRange = newRange.sanitizedForLogScale();
5192     } else
5193       qDebug() << Q_FUNC_INFO << "Center of scaling operation doesn't lie in same logarithmic sign domain as range:" << center;
5194   }
5195   mCachedMarginValid = false;
5196   emit rangeChanged(mRange);
5197   emit rangeChanged(mRange, oldRange);
5198 }
5199
5200 /*!
5201   Scales the range of this axis to have a certain scale \a ratio to \a otherAxis. The scaling will
5202   be done around the center of the current axis range.
5203
5204   For example, if \a ratio is 1, this axis is the \a yAxis and \a otherAxis is \a xAxis, graphs
5205   plotted with those axes will appear in a 1:1 aspect ratio, independent of the aspect ratio the
5206   axis rect has.
5207
5208   This is an operation that changes the range of this axis once, it doesn't fix the scale ratio
5209   indefinitely. Note that calling this function in the constructor of the QCustomPlot's parent
5210   won't have the desired effect, since the widget dimensions aren't defined yet, and a resizeEvent
5211   will follow.
5212 */
5213 void QCPAxis::setScaleRatio(const QCPAxis *otherAxis, double ratio)
5214 {
5215   int otherPixelSize, ownPixelSize;
5216   
5217   if (otherAxis->orientation() == Qt::Horizontal)
5218     otherPixelSize = otherAxis->axisRect()->width();
5219   else
5220     otherPixelSize = otherAxis->axisRect()->height();
5221   
5222   if (orientation() == Qt::Horizontal)
5223     ownPixelSize = axisRect()->width();
5224   else
5225     ownPixelSize = axisRect()->height();
5226   
5227   double newRangeSize = ratio*otherAxis->range().size()*ownPixelSize/(double)otherPixelSize;
5228   setRange(range().center(), newRangeSize, Qt::AlignCenter);
5229 }
5230
5231 /*!
5232   Changes the axis range such that all plottables associated with this axis are fully visible in
5233   that dimension.
5234   
5235   \see QCPAbstractPlottable::rescaleAxes, QCustomPlot::rescaleAxes
5236 */
5237 void QCPAxis::rescale(bool onlyVisiblePlottables)
5238 {
5239   QList<QCPAbstractPlottable*> p = plottables();
5240   QCPRange newRange;
5241   bool haveRange = false;
5242   for (int i=0; i<p.size(); ++i)
5243   {
5244     if (!p.at(i)->realVisibility() && onlyVisiblePlottables)
5245       continue;
5246     QCPRange plottableRange;
5247     bool currentFoundRange;
5248     QCPAbstractPlottable::SignDomain signDomain = QCPAbstractPlottable::sdBoth;
5249     if (mScaleType == stLogarithmic)
5250       signDomain = (mRange.upper < 0 ? QCPAbstractPlottable::sdNegative : QCPAbstractPlottable::sdPositive);
5251     if (p.at(i)->keyAxis() == this)
5252       plottableRange = p.at(i)->getKeyRange(currentFoundRange, signDomain);
5253     else
5254       plottableRange = p.at(i)->getValueRange(currentFoundRange, signDomain);
5255     if (currentFoundRange)
5256     {
5257       if (!haveRange)
5258         newRange = plottableRange;
5259       else
5260         newRange.expand(plottableRange);
5261       haveRange = true;
5262     }
5263   }
5264   if (haveRange)
5265   {
5266     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
5267     {
5268       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
5269       if (mScaleType == stLinear)
5270       {
5271         newRange.lower = center-mRange.size()/2.0;
5272         newRange.upper = center+mRange.size()/2.0;
5273       } else // mScaleType == stLogarithmic
5274       {
5275         newRange.lower = center/qSqrt(mRange.upper/mRange.lower);
5276         newRange.upper = center*qSqrt(mRange.upper/mRange.lower);
5277       }
5278     }
5279     setRange(newRange);
5280   }
5281 }
5282
5283 /*!
5284   Transforms \a value, in pixel coordinates of the QCustomPlot widget, to axis coordinates.
5285 */
5286 double QCPAxis::pixelToCoord(double value) const
5287 {
5288   if (orientation() == Qt::Horizontal)
5289   {
5290     if (mScaleType == stLinear)
5291     {
5292       if (!mRangeReversed)
5293         return (value-mAxisRect->left())/(double)mAxisRect->width()*mRange.size()+mRange.lower;
5294       else
5295         return -(value-mAxisRect->left())/(double)mAxisRect->width()*mRange.size()+mRange.upper;
5296     } else // mScaleType == stLogarithmic
5297     {
5298       if (!mRangeReversed)
5299         return qPow(mRange.upper/mRange.lower, (value-mAxisRect->left())/(double)mAxisRect->width())*mRange.lower;
5300       else
5301         return qPow(mRange.upper/mRange.lower, (mAxisRect->left()-value)/(double)mAxisRect->width())*mRange.upper;
5302     }
5303   } else // orientation() == Qt::Vertical
5304   {
5305     if (mScaleType == stLinear)
5306     {
5307       if (!mRangeReversed)
5308         return (mAxisRect->bottom()-value)/(double)mAxisRect->height()*mRange.size()+mRange.lower;
5309       else
5310         return -(mAxisRect->bottom()-value)/(double)mAxisRect->height()*mRange.size()+mRange.upper;
5311     } else // mScaleType == stLogarithmic
5312     {
5313       if (!mRangeReversed)
5314         return qPow(mRange.upper/mRange.lower, (mAxisRect->bottom()-value)/(double)mAxisRect->height())*mRange.lower;
5315       else
5316         return qPow(mRange.upper/mRange.lower, (value-mAxisRect->bottom())/(double)mAxisRect->height())*mRange.upper;
5317     }
5318   }
5319 }
5320
5321 /*!
5322   Transforms \a value, in coordinates of the axis, to pixel coordinates of the QCustomPlot widget.
5323 */
5324 double QCPAxis::coordToPixel(double value) const
5325 {
5326   if (orientation() == Qt::Horizontal)
5327   {
5328     if (mScaleType == stLinear)
5329     {
5330       if (!mRangeReversed)
5331         return (value-mRange.lower)/mRange.size()*mAxisRect->width()+mAxisRect->left();
5332       else
5333         return (mRange.upper-value)/mRange.size()*mAxisRect->width()+mAxisRect->left();
5334     } else // mScaleType == stLogarithmic
5335     {
5336       if (value >= 0 && mRange.upper < 0) // invalid value for logarithmic scale, just draw it outside visible range
5337         return !mRangeReversed ? mAxisRect->right()+200 : mAxisRect->left()-200;
5338       else if (value <= 0 && mRange.upper > 0) // invalid value for logarithmic scale, just draw it outside visible range
5339         return !mRangeReversed ? mAxisRect->left()-200 : mAxisRect->right()+200;
5340       else
5341       {
5342         if (!mRangeReversed)
5343           return baseLog(value/mRange.lower)/baseLog(mRange.upper/mRange.lower)*mAxisRect->width()+mAxisRect->left();
5344         else
5345           return baseLog(mRange.upper/value)/baseLog(mRange.upper/mRange.lower)*mAxisRect->width()+mAxisRect->left();
5346       }
5347     }
5348   } else // orientation() == Qt::Vertical
5349   {
5350     if (mScaleType == stLinear)
5351     {
5352       if (!mRangeReversed)
5353         return mAxisRect->bottom()-(value-mRange.lower)/mRange.size()*mAxisRect->height();
5354       else
5355         return mAxisRect->bottom()-(mRange.upper-value)/mRange.size()*mAxisRect->height();
5356     } else // mScaleType == stLogarithmic
5357     {
5358       if (value >= 0 && mRange.upper < 0) // invalid value for logarithmic scale, just draw it outside visible range
5359         return !mRangeReversed ? mAxisRect->top()-200 : mAxisRect->bottom()+200;
5360       else if (value <= 0 && mRange.upper > 0) // invalid value for logarithmic scale, just draw it outside visible range
5361         return !mRangeReversed ? mAxisRect->bottom()+200 : mAxisRect->top()-200;
5362       else
5363       {
5364         if (!mRangeReversed)
5365           return mAxisRect->bottom()-baseLog(value/mRange.lower)/baseLog(mRange.upper/mRange.lower)*mAxisRect->height();
5366         else
5367           return mAxisRect->bottom()-baseLog(mRange.upper/value)/baseLog(mRange.upper/mRange.lower)*mAxisRect->height();
5368       }
5369     }
5370   }
5371 }
5372
5373 /*!
5374   Returns the part of the axis that is hit by \a pos (in pixels). The return value of this function
5375   is independent of the user-selectable parts defined with \ref setSelectableParts. Further, this
5376   function does not change the current selection state of the axis.
5377   
5378   If the axis is not visible (\ref setVisible), this function always returns \ref spNone.
5379   
5380   \see setSelectedParts, setSelectableParts, QCustomPlot::setInteractions
5381 */
5382 QCPAxis::SelectablePart QCPAxis::getPartAt(const QPointF &pos) const
5383 {
5384   if (!mVisible)
5385     return spNone;
5386   
5387   if (mAxisPainter->axisSelectionBox().contains(pos.toPoint()))
5388     return spAxis;
5389   else if (mAxisPainter->tickLabelsSelectionBox().contains(pos.toPoint()))
5390     return spTickLabels;
5391   else if (mAxisPainter->labelSelectionBox().contains(pos.toPoint()))
5392     return spAxisLabel;
5393   else
5394     return spNone;
5395 }
5396
5397 /* inherits documentation from base class */
5398 double QCPAxis::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
5399 {
5400   if (!mParentPlot) return -1;
5401   SelectablePart part = getPartAt(pos);
5402   if ((onlySelectable && !mSelectableParts.testFlag(part)) || part == spNone)
5403     return -1;
5404   
5405   if (details)
5406     details->setValue(part);
5407   return mParentPlot->selectionTolerance()*0.99;
5408 }
5409
5410 /*!
5411   Returns a list of all the plottables that have this axis as key or value axis.
5412   
5413   If you are only interested in plottables of type QCPGraph, see \ref graphs.
5414   
5415   \see graphs, items
5416 */
5417 QList<QCPAbstractPlottable*> QCPAxis::plottables() const
5418 {
5419   QList<QCPAbstractPlottable*> result;
5420   if (!mParentPlot) return result;
5421   
5422   for (int i=0; i<mParentPlot->mPlottables.size(); ++i)
5423   {
5424     if (mParentPlot->mPlottables.at(i)->keyAxis() == this ||mParentPlot->mPlottables.at(i)->valueAxis() == this)
5425       result.append(mParentPlot->mPlottables.at(i));
5426   }
5427   return result;
5428 }
5429
5430 /*!
5431   Returns a list of all the graphs that have this axis as key or value axis.
5432   
5433   \see plottables, items
5434 */
5435 QList<QCPGraph*> QCPAxis::graphs() const
5436 {
5437   QList<QCPGraph*> result;
5438   if (!mParentPlot) return result;
5439   
5440   for (int i=0; i<mParentPlot->mGraphs.size(); ++i)
5441   {
5442     if (mParentPlot->mGraphs.at(i)->keyAxis() == this || mParentPlot->mGraphs.at(i)->valueAxis() == this)
5443       result.append(mParentPlot->mGraphs.at(i));
5444   }
5445   return result;
5446 }
5447
5448 /*!
5449   Returns a list of all the items that are associated with this axis. An item is considered
5450   associated with an axis if at least one of its positions uses the axis as key or value axis.
5451   
5452   \see plottables, graphs
5453 */
5454 QList<QCPAbstractItem*> QCPAxis::items() const
5455 {
5456   QList<QCPAbstractItem*> result;
5457   if (!mParentPlot) return result;
5458   
5459   for (int itemId=0; itemId<mParentPlot->mItems.size(); ++itemId)
5460   {
5461     QList<QCPItemPosition*> positions = mParentPlot->mItems.at(itemId)->positions();
5462     for (int posId=0; posId<positions.size(); ++posId)
5463     {
5464       if (positions.at(posId)->keyAxis() == this || positions.at(posId)->valueAxis() == this)
5465       {
5466         result.append(mParentPlot->mItems.at(itemId));
5467         break;
5468       }
5469     }
5470   }
5471   return result;
5472 }
5473
5474 /*!
5475   Transforms a margin side to the logically corresponding axis type. (QCP::msLeft to
5476   QCPAxis::atLeft, QCP::msRight to QCPAxis::atRight, etc.)
5477 */
5478 QCPAxis::AxisType QCPAxis::marginSideToAxisType(QCP::MarginSide side)
5479 {
5480   switch (side)
5481   {
5482     case QCP::msLeft: return atLeft;
5483     case QCP::msRight: return atRight;
5484     case QCP::msTop: return atTop;
5485     case QCP::msBottom: return atBottom;
5486     default: break;
5487   }
5488   qDebug() << Q_FUNC_INFO << "Invalid margin side passed:" << (int)side;
5489   return atLeft;
5490 }
5491
5492 /*!
5493   Returns the axis type that describes the opposite axis of an axis with the specified \a type.
5494 */
5495 QCPAxis::AxisType QCPAxis::opposite(QCPAxis::AxisType type)
5496 {
5497   switch (type)
5498   {
5499     case atLeft: return atRight; break;
5500     case atRight: return atLeft; break;
5501     case atBottom: return atTop; break;
5502     case atTop: return atBottom; break;
5503     default: qDebug() << Q_FUNC_INFO << "invalid axis type"; return atLeft; break;
5504   }
5505 }
5506
5507 /*! \internal
5508   
5509   This function is called to prepare the tick vector, sub tick vector and tick label vector. If
5510   \ref setAutoTicks is set to true, appropriate tick values are determined automatically via \ref
5511   generateAutoTicks. If it's set to false, the signal ticksRequest is emitted, which can be used to
5512   provide external tick positions. Then the sub tick vectors and tick label vectors are created.
5513 */
5514 void QCPAxis::setupTickVectors()
5515 {
5516   if (!mParentPlot) return;
5517   if ((!mTicks && !mTickLabels && !mGrid->visible()) || mRange.size() <= 0) return;
5518   
5519   // fill tick vectors, either by auto generating or by notifying user to fill the vectors himself
5520   if (mAutoTicks)
5521   {
5522     generateAutoTicks();
5523   } else
5524   {
5525     emit ticksRequest();
5526   }
5527   
5528   visibleTickBounds(mLowestVisibleTick, mHighestVisibleTick);
5529   if (mTickVector.isEmpty())
5530   {
5531     mSubTickVector.clear();
5532     return;
5533   }
5534   
5535   // generate subticks between ticks:
5536   mSubTickVector.resize((mTickVector.size()-1)*mSubTickCount);
5537   if (mSubTickCount > 0)
5538   {
5539     double subTickStep = 0;
5540     double subTickPosition = 0;
5541     int subTickIndex = 0;
5542     bool done = false;
5543     int lowTick = mLowestVisibleTick > 0 ? mLowestVisibleTick-1 : mLowestVisibleTick;
5544     int highTick = mHighestVisibleTick < mTickVector.size()-1 ? mHighestVisibleTick+1 : mHighestVisibleTick;
5545     for (int i=lowTick+1; i<=highTick; ++i)
5546     {
5547       subTickStep = (mTickVector.at(i)-mTickVector.at(i-1))/(double)(mSubTickCount+1);
5548       for (int k=1; k<=mSubTickCount; ++k)
5549       {
5550         subTickPosition = mTickVector.at(i-1) + k*subTickStep;
5551         if (subTickPosition < mRange.lower)
5552           continue;
5553         if (subTickPosition > mRange.upper)
5554         {
5555           done = true;
5556           break;
5557         }
5558         mSubTickVector[subTickIndex] = subTickPosition;
5559         subTickIndex++;
5560       }
5561       if (done) break;
5562     }
5563     mSubTickVector.resize(subTickIndex);
5564   }
5565
5566   // generate tick labels according to tick positions:
5567   if (mAutoTickLabels)
5568   {
5569     int vecsize = mTickVector.size();
5570     mTickVectorLabels.resize(vecsize);
5571     if (mTickLabelType == ltNumber)
5572     {
5573       for (int i=mLowestVisibleTick; i<=mHighestVisibleTick; ++i)
5574         mTickVectorLabels[i] = mParentPlot->locale().toString(mTickVector.at(i), mNumberFormatChar.toLatin1(), mNumberPrecision);
5575     } else if (mTickLabelType == ltDateTime)
5576     {
5577       for (int i=mLowestVisibleTick; i<=mHighestVisibleTick; ++i)
5578       {
5579 #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")
5580         mTickVectorLabels[i] = mParentPlot->locale().toString(QDateTime::fromTime_t(mTickVector.at(i)).toTimeSpec(mDateTimeSpec), mDateTimeFormat);
5581 #else
5582         mTickVectorLabels[i] = mParentPlot->locale().toString(QDateTime::fromMSecsSinceEpoch(mTickVector.at(i)*1000).toTimeSpec(mDateTimeSpec), mDateTimeFormat);
5583 #endif
5584       }
5585     }
5586   } else // mAutoTickLabels == false
5587   {
5588     if (mAutoTicks) // ticks generated automatically, but not ticklabels, so emit ticksRequest here for labels
5589     {
5590       emit ticksRequest();
5591     }
5592     // make sure provided tick label vector has correct (minimal) length:
5593     if (mTickVectorLabels.size() < mTickVector.size())
5594       mTickVectorLabels.resize(mTickVector.size());
5595   }
5596 }
5597
5598 /*! \internal
5599   
5600   If \ref setAutoTicks is set to true, this function is called by \ref setupTickVectors to
5601   generate reasonable tick positions (and subtick count). The algorithm tries to create
5602   approximately <tt>mAutoTickCount</tt> ticks (set via \ref setAutoTickCount).
5603  
5604   If the scale is logarithmic, \ref setAutoTickCount is ignored, and one tick is generated at every
5605   power of the current logarithm base, set via \ref setScaleLogBase.
5606 */
5607 void QCPAxis::generateAutoTicks()
5608 {
5609   if (mScaleType == stLinear)
5610   {
5611     if (mAutoTickStep)
5612     {
5613       // Generate tick positions according to linear scaling:
5614       mTickStep = mRange.size()/(double)(mAutoTickCount+1e-10); // mAutoTickCount ticks on average, the small addition is to prevent jitter on exact integers
5615       double magnitudeFactor = qPow(10.0, qFloor(qLn(mTickStep)/qLn(10.0))); // get magnitude factor e.g. 0.01, 1, 10, 1000 etc.
5616       double tickStepMantissa = mTickStep/magnitudeFactor;
5617       if (tickStepMantissa < 5)
5618       {
5619         // round digit after decimal point to 0.5
5620         mTickStep = (int)(tickStepMantissa*2)/2.0*magnitudeFactor;
5621       } else
5622       {
5623         // round to first digit in multiples of 2
5624         mTickStep = (int)(tickStepMantissa/2.0)*2.0*magnitudeFactor;
5625       }
5626     }
5627     if (mAutoSubTicks)
5628       mSubTickCount = calculateAutoSubTickCount(mTickStep);
5629     // Generate tick positions according to mTickStep:
5630     qint64 firstStep = floor(mRange.lower/mTickStep); // do not use qFloor here, or we'll lose 64 bit precision
5631     qint64 lastStep = ceil(mRange.upper/mTickStep); // do not use qCeil here, or we'll lose 64 bit precision
5632     int tickcount = lastStep-firstStep+1;
5633     if (tickcount < 0) tickcount = 0;
5634     mTickVector.resize(tickcount);
5635     for (int i=0; i<tickcount; ++i)
5636       mTickVector[i] = (firstStep+i)*mTickStep;
5637   } else // mScaleType == stLogarithmic
5638   {
5639     // Generate tick positions according to logbase scaling:
5640     if (mRange.lower > 0 && mRange.upper > 0) // positive range
5641     {
5642       double lowerMag = basePow(qFloor(baseLog(mRange.lower)));
5643       double currentMag = lowerMag;
5644       mTickVector.clear();
5645       mTickVector.append(currentMag);
5646       while (currentMag < mRange.upper && currentMag > 0) // currentMag might be zero for ranges ~1e-300, just cancel in that case
5647       {
5648         currentMag *= mScaleLogBase;
5649         mTickVector.append(currentMag);
5650       }
5651     } else if (mRange.lower < 0 && mRange.upper < 0) // negative range
5652     {
5653       double lowerMag = -basePow(qCeil(baseLog(-mRange.lower)));
5654       double currentMag = lowerMag;
5655       mTickVector.clear();
5656       mTickVector.append(currentMag);
5657       while (currentMag < mRange.upper && currentMag < 0) // currentMag might be zero for ranges ~1e-300, just cancel in that case
5658       {
5659         currentMag /= mScaleLogBase;
5660         mTickVector.append(currentMag);
5661       }
5662     } else // invalid range for logarithmic scale, because lower and upper have different sign
5663     {
5664       mTickVector.clear();
5665       qDebug() << Q_FUNC_INFO << "Invalid range for logarithmic plot: " << mRange.lower << "-" << mRange.upper;
5666     }
5667   }
5668 }
5669
5670 /*! \internal
5671   
5672   Called by generateAutoTicks when \ref setAutoSubTicks is set to true. Depending on the \a
5673   tickStep between two major ticks on the axis, a different number of sub ticks is appropriate. For
5674   Example taking 4 sub ticks for a \a tickStep of 1 makes more sense than taking 5 sub ticks,
5675   because this corresponds to a sub tick step of 0.2, instead of the less intuitive 0.16667. Note
5676   that a subtick count of 4 means dividing the major tick step into 5 sections.
5677   
5678   This is implemented by a hand made lookup for integer tick steps as well as fractional tick steps
5679   with a fractional part of (approximately) 0.5. If a tick step is different (i.e. has no
5680   fractional part close to 0.5), the currently set sub tick count (\ref setSubTickCount) is
5681   returned.
5682 */
5683 int QCPAxis::calculateAutoSubTickCount(double tickStep) const
5684 {
5685   int result = mSubTickCount; // default to current setting, if no proper value can be found
5686   
5687   // get mantissa of tickstep:
5688   double magnitudeFactor = qPow(10.0, qFloor(qLn(tickStep)/qLn(10.0))); // get magnitude factor e.g. 0.01, 1, 10, 1000 etc.
5689   double tickStepMantissa = tickStep/magnitudeFactor;
5690   
5691   // separate integer and fractional part of mantissa:
5692   double epsilon = 0.01;
5693   double intPartf;
5694   int intPart;
5695   double fracPart = modf(tickStepMantissa, &intPartf);
5696   intPart = intPartf;
5697   
5698   // handle cases with (almost) integer mantissa:
5699   if (fracPart < epsilon || 1.0-fracPart < epsilon)
5700   {
5701     if (1.0-fracPart < epsilon)
5702       ++intPart;
5703     switch (intPart)
5704     {
5705       case 1: result = 4; break; // 1.0 -> 0.2 substep
5706       case 2: result = 3; break; // 2.0 -> 0.5 substep
5707       case 3: result = 2; break; // 3.0 -> 1.0 substep
5708       case 4: result = 3; break; // 4.0 -> 1.0 substep
5709       case 5: result = 4; break; // 5.0 -> 1.0 substep
5710       case 6: result = 2; break; // 6.0 -> 2.0 substep
5711       case 7: result = 6; break; // 7.0 -> 1.0 substep
5712       case 8: result = 3; break; // 8.0 -> 2.0 substep
5713       case 9: result = 2; break; // 9.0 -> 3.0 substep
5714     }
5715   } else
5716   {
5717     // handle cases with significantly fractional mantissa:
5718     if (qAbs(fracPart-0.5) < epsilon) // *.5 mantissa
5719     {
5720       switch (intPart)
5721       {
5722         case 1: result = 2; break; // 1.5 -> 0.5 substep
5723         case 2: result = 4; break; // 2.5 -> 0.5 substep
5724         case 3: result = 4; break; // 3.5 -> 0.7 substep
5725         case 4: result = 2; break; // 4.5 -> 1.5 substep
5726         case 5: result = 4; break; // 5.5 -> 1.1 substep (won't occur with autoTickStep from here on)
5727         case 6: result = 4; break; // 6.5 -> 1.3 substep
5728         case 7: result = 2; break; // 7.5 -> 2.5 substep
5729         case 8: result = 4; break; // 8.5 -> 1.7 substep
5730         case 9: result = 4; break; // 9.5 -> 1.9 substep
5731       }
5732     }
5733     // if mantissa fraction isnt 0.0 or 0.5, don't bother finding good sub tick marks, leave default
5734   }
5735   
5736   return result;
5737 }
5738
5739 /* inherits documentation from base class */
5740 void QCPAxis::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged)
5741 {
5742   Q_UNUSED(event)
5743   SelectablePart part = details.value<SelectablePart>();
5744   if (mSelectableParts.testFlag(part))
5745   {
5746     SelectableParts selBefore = mSelectedParts;
5747     setSelectedParts(additive ? mSelectedParts^part : part);
5748     if (selectionStateChanged)
5749       *selectionStateChanged = mSelectedParts != selBefore;
5750   }
5751 }
5752
5753 /* inherits documentation from base class */
5754 void QCPAxis::deselectEvent(bool *selectionStateChanged)
5755 {
5756   SelectableParts selBefore = mSelectedParts;
5757   setSelectedParts(mSelectedParts & ~mSelectableParts);
5758   if (selectionStateChanged)
5759     *selectionStateChanged = mSelectedParts != selBefore;
5760 }
5761
5762 /*! \internal
5763
5764   A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter
5765   before drawing axis lines.
5766
5767   This is the antialiasing state the painter passed to the \ref draw method is in by default.
5768   
5769   This function takes into account the local setting of the antialiasing flag as well as the
5770   overrides set with \ref QCustomPlot::setAntialiasedElements and \ref
5771   QCustomPlot::setNotAntialiasedElements.
5772   
5773   \see setAntialiased
5774 */
5775 void QCPAxis::applyDefaultAntialiasingHint(QCPPainter *painter) const
5776 {
5777   applyAntialiasingHint(painter, mAntialiased, QCP::aeAxes);
5778 }
5779
5780 /*! \internal
5781   
5782   Draws the axis with the specified \a painter, using the internal QCPAxisPainterPrivate instance.
5783
5784 */
5785 void QCPAxis::draw(QCPPainter *painter)
5786 {
5787   const int lowTick = mLowestVisibleTick;
5788   const int highTick = mHighestVisibleTick;
5789   QVector<double> subTickPositions; // the final coordToPixel transformed vector passed to QCPAxisPainter
5790   QVector<double> tickPositions; // the final coordToPixel transformed vector passed to QCPAxisPainter
5791   QVector<QString> tickLabels; // the final vector passed to QCPAxisPainter
5792   tickPositions.reserve(highTick-lowTick+1);
5793   tickLabels.reserve(highTick-lowTick+1);
5794   subTickPositions.reserve(mSubTickVector.size());
5795   
5796   if (mTicks)
5797   {
5798     for (int i=lowTick; i<=highTick; ++i)
5799     {
5800       tickPositions.append(coordToPixel(mTickVector.at(i)));
5801       if (mTickLabels)
5802         tickLabels.append(mTickVectorLabels.at(i));
5803     }
5804     
5805     if (mSubTickCount > 0)
5806     {
5807       const int subTickCount = mSubTickVector.size();
5808       for (int i=0; i<subTickCount; ++i) // no need to check bounds because subticks are always only created inside current mRange
5809         subTickPositions.append(coordToPixel(mSubTickVector.at(i)));
5810     }
5811   }
5812   // transfer all properties of this axis to QCPAxisPainterPrivate which it needs to draw the axis.
5813   // Note that some axis painter properties are already set by direct feed-through with QCPAxis setters
5814   mAxisPainter->type = mAxisType;
5815   mAxisPainter->basePen = getBasePen();
5816   mAxisPainter->labelFont = getLabelFont();
5817   mAxisPainter->labelColor = getLabelColor();
5818   mAxisPainter->label = mLabel;
5819   mAxisPainter->substituteExponent = mAutoTickLabels && mNumberBeautifulPowers && mTickLabelType == ltNumber;
5820   mAxisPainter->tickPen = getTickPen();
5821   mAxisPainter->subTickPen = getSubTickPen();
5822   mAxisPainter->tickLabelFont = getTickLabelFont();
5823   mAxisPainter->tickLabelColor = getTickLabelColor();
5824   mAxisPainter->axisRect = mAxisRect->rect();
5825   mAxisPainter->viewportRect = mParentPlot->viewport();
5826   mAxisPainter->abbreviateDecimalPowers = mScaleType == stLogarithmic;
5827   mAxisPainter->reversedEndings = mRangeReversed;
5828   mAxisPainter->tickPositions = tickPositions;
5829   mAxisPainter->tickLabels = tickLabels;
5830   mAxisPainter->subTickPositions = subTickPositions;
5831   mAxisPainter->draw(painter);
5832 }
5833
5834 /*! \internal
5835   
5836   Returns via \a lowIndex and \a highIndex, which ticks in the current tick vector are visible in
5837   the current range. The return values are indices of the tick vector, not the positions of the
5838   ticks themselves.
5839   
5840   The actual use of this function is when an external tick vector is provided, since it might
5841   exceed far beyond the currently displayed range, and would cause unnecessary calculations e.g. of
5842   subticks.
5843   
5844   If all ticks are outside the axis range, an inverted range is returned, i.e. highIndex will be
5845   smaller than lowIndex. There is one case, where this function returns indices that are not really
5846   visible in the current axis range: When the tick spacing is larger than the axis range size and
5847   one tick is below the axis range and the next tick is already above the axis range. Because in
5848   such cases it is usually desirable to know the tick pair, to draw proper subticks.
5849 */
5850 void QCPAxis::visibleTickBounds(int &lowIndex, int &highIndex) const
5851 {
5852   bool lowFound = false;
5853   bool highFound = false;
5854   lowIndex = 0;
5855   highIndex = -1;
5856   
5857   for (int i=0; i < mTickVector.size(); ++i)
5858   {
5859     if (mTickVector.at(i) >= mRange.lower)
5860     {
5861       lowFound = true;
5862       lowIndex = i;
5863       break;
5864     }
5865   }
5866   for (int i=mTickVector.size()-1; i >= 0; --i)
5867   {
5868     if (mTickVector.at(i) <= mRange.upper)
5869     {
5870       highFound = true;
5871       highIndex = i;
5872       break;
5873     }
5874   }
5875   
5876   if (!lowFound && highFound)
5877     lowIndex = highIndex+1;
5878   else if (lowFound && !highFound)
5879     highIndex = lowIndex-1;
5880 }
5881
5882 /*! \internal
5883   
5884   A log function with the base mScaleLogBase, used mostly for coordinate transforms in logarithmic
5885   scales with arbitrary log base. Uses the buffered mScaleLogBaseLogInv for faster calculation.
5886   This is set to <tt>1.0/qLn(mScaleLogBase)</tt> in \ref setScaleLogBase.
5887   
5888   \see basePow, setScaleLogBase, setScaleType
5889 */
5890 double QCPAxis::baseLog(double value) const
5891 {
5892   return qLn(value)*mScaleLogBaseLogInv;
5893 }
5894
5895 /*! \internal
5896   
5897   A power function with the base mScaleLogBase, used mostly for coordinate transforms in
5898   logarithmic scales with arbitrary log base.
5899   
5900   \see baseLog, setScaleLogBase, setScaleType
5901 */
5902 double QCPAxis::basePow(double value) const
5903 {
5904   return qPow(mScaleLogBase, value);
5905 }
5906
5907 /*! \internal
5908   
5909   Returns the pen that is used to draw the axis base line. Depending on the selection state, this
5910   is either mSelectedBasePen or mBasePen.
5911 */
5912 QPen QCPAxis::getBasePen() const
5913 {
5914   return mSelectedParts.testFlag(spAxis) ? mSelectedBasePen : mBasePen;
5915 }
5916
5917 /*! \internal
5918   
5919   Returns the pen that is used to draw the (major) ticks. Depending on the selection state, this
5920   is either mSelectedTickPen or mTickPen.
5921 */
5922 QPen QCPAxis::getTickPen() const
5923 {
5924   return mSelectedParts.testFlag(spAxis) ? mSelectedTickPen : mTickPen;
5925 }
5926
5927 /*! \internal
5928   
5929   Returns the pen that is used to draw the subticks. Depending on the selection state, this
5930   is either mSelectedSubTickPen or mSubTickPen.
5931 */
5932 QPen QCPAxis::getSubTickPen() const
5933 {
5934   return mSelectedParts.testFlag(spAxis) ? mSelectedSubTickPen : mSubTickPen;
5935 }
5936
5937 /*! \internal
5938   
5939   Returns the font that is used to draw the tick labels. Depending on the selection state, this
5940   is either mSelectedTickLabelFont or mTickLabelFont.
5941 */
5942 QFont QCPAxis::getTickLabelFont() const
5943 {
5944   return mSelectedParts.testFlag(spTickLabels) ? mSelectedTickLabelFont : mTickLabelFont;
5945 }
5946
5947 /*! \internal
5948   
5949   Returns the font that is used to draw the axis label. Depending on the selection state, this
5950   is either mSelectedLabelFont or mLabelFont.
5951 */
5952 QFont QCPAxis::getLabelFont() const
5953 {
5954   return mSelectedParts.testFlag(spAxisLabel) ? mSelectedLabelFont : mLabelFont;
5955 }
5956
5957 /*! \internal
5958   
5959   Returns the color that is used to draw the tick labels. Depending on the selection state, this
5960   is either mSelectedTickLabelColor or mTickLabelColor.
5961 */
5962 QColor QCPAxis::getTickLabelColor() const
5963 {
5964   return mSelectedParts.testFlag(spTickLabels) ? mSelectedTickLabelColor : mTickLabelColor;
5965 }
5966
5967 /*! \internal
5968   
5969   Returns the color that is used to draw the axis label. Depending on the selection state, this
5970   is either mSelectedLabelColor or mLabelColor.
5971 */
5972 QColor QCPAxis::getLabelColor() const
5973 {
5974   return mSelectedParts.testFlag(spAxisLabel) ? mSelectedLabelColor : mLabelColor;
5975 }
5976
5977 /*! \internal
5978   
5979   Returns the appropriate outward margin for this axis. It is needed if \ref
5980   QCPAxisRect::setAutoMargins is set to true on the parent axis rect. An axis with axis type \ref
5981   atLeft will return an appropriate left margin, \ref atBottom will return an appropriate bottom
5982   margin and so forth. For the calculation, this function goes through similar steps as \ref draw,
5983   so changing one function likely requires the modification of the other one as well.
5984   
5985   The margin consists of the outward tick length, tick label padding, tick label size, label
5986   padding, label size, and padding.
5987   
5988   The margin is cached internally, so repeated calls while leaving the axis range, fonts, etc.
5989   unchanged are very fast.
5990 */
5991 int QCPAxis::calculateMargin()
5992 {
5993   if (!mVisible) // if not visible, directly return 0, don't cache 0 because we can't react to setVisible in QCPAxis
5994     return 0;
5995   
5996   if (mCachedMarginValid)
5997     return mCachedMargin;
5998   
5999   // run through similar steps as QCPAxis::draw, and caluclate margin needed to fit axis and its labels
6000   int margin = 0;
6001   
6002   int lowTick, highTick;
6003   visibleTickBounds(lowTick, highTick);
6004   QVector<double> tickPositions; // the final coordToPixel transformed vector passed to QCPAxisPainter
6005   QVector<QString> tickLabels; // the final vector passed to QCPAxisPainter
6006   tickPositions.reserve(highTick-lowTick+1);
6007   tickLabels.reserve(highTick-lowTick+1);
6008   if (mTicks)
6009   {
6010     for (int i=lowTick; i<=highTick; ++i)
6011     {
6012       tickPositions.append(coordToPixel(mTickVector.at(i)));
6013       if (mTickLabels)
6014         tickLabels.append(mTickVectorLabels.at(i));
6015     }
6016   }
6017   // transfer all properties of this axis to QCPAxisPainterPrivate which it needs to calculate the size.
6018   // Note that some axis painter properties are already set by direct feed-through with QCPAxis setters
6019   mAxisPainter->type = mAxisType;
6020   mAxisPainter->labelFont = getLabelFont();
6021   mAxisPainter->label = mLabel;
6022   mAxisPainter->tickLabelFont = mTickLabelFont;
6023   mAxisPainter->axisRect = mAxisRect->rect();
6024   mAxisPainter->viewportRect = mParentPlot->viewport();
6025   mAxisPainter->tickPositions = tickPositions;
6026   mAxisPainter->tickLabels = tickLabels;
6027   margin += mAxisPainter->size();
6028   margin += mPadding;
6029
6030   mCachedMargin = margin;
6031   mCachedMarginValid = true;
6032   return margin;
6033 }
6034
6035 /* inherits documentation from base class */
6036 QCP::Interaction QCPAxis::selectionCategory() const
6037 {
6038   return QCP::iSelectAxes;
6039 }
6040
6041
6042 ////////////////////////////////////////////////////////////////////////////////////////////////////
6043 //////////////////// QCPAxisPainterPrivate
6044 ////////////////////////////////////////////////////////////////////////////////////////////////////
6045
6046 /*! \class QCPAxisPainterPrivate
6047
6048   \internal
6049   \brief (Private)
6050   
6051   This is a private class and not part of the public QCustomPlot interface.
6052   
6053   It is used by QCPAxis to do the low-level drawing of axis backbone, tick marks, tick labels and
6054   axis label. It also buffers the labels to reduce replot times. The parameters are configured by
6055   directly accessing the public member variables.
6056 */
6057
6058 /*!
6059   Constructs a QCPAxisPainterPrivate instance. Make sure to not create a new instance on every
6060   redraw, to utilize the caching mechanisms.
6061 */
6062 QCPAxisPainterPrivate::QCPAxisPainterPrivate(QCustomPlot *parentPlot) :
6063   type(QCPAxis::atLeft),
6064   basePen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)),
6065   lowerEnding(QCPLineEnding::esNone),
6066   upperEnding(QCPLineEnding::esNone),
6067   labelPadding(0),
6068   tickLabelPadding(0),
6069   tickLabelRotation(0),
6070   tickLabelSide(QCPAxis::lsOutside),
6071   substituteExponent(true),
6072   numberMultiplyCross(false),
6073   tickLengthIn(5),
6074   tickLengthOut(0),
6075   subTickLengthIn(2),
6076   subTickLengthOut(0),
6077   tickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)),
6078   subTickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)),
6079   offset(0),
6080   abbreviateDecimalPowers(false),
6081   reversedEndings(false),
6082   mParentPlot(parentPlot),
6083   mLabelCache(16) // cache at most 16 (tick) labels
6084 {
6085 }
6086
6087 QCPAxisPainterPrivate::~QCPAxisPainterPrivate()
6088 {
6089 }
6090
6091 /*! \internal
6092   
6093   Draws the axis with the specified \a painter.
6094   
6095   The selection boxes (mAxisSelectionBox, mTickLabelsSelectionBox, mLabelSelectionBox) are set
6096   here, too.
6097 */
6098 void QCPAxisPainterPrivate::draw(QCPPainter *painter)
6099 {
6100   QByteArray newHash = generateLabelParameterHash();
6101   if (newHash != mLabelParameterHash)
6102   {
6103     mLabelCache.clear();
6104     mLabelParameterHash = newHash;
6105   }
6106   
6107   QPoint origin;
6108   switch (type)
6109   {
6110     case QCPAxis::atLeft:   origin = axisRect.bottomLeft() +QPoint(-offset, 0); break;
6111     case QCPAxis::atRight:  origin = axisRect.bottomRight()+QPoint(+offset, 0); break;
6112     case QCPAxis::atTop:    origin = axisRect.topLeft()    +QPoint(0, -offset); break;
6113     case QCPAxis::atBottom: origin = axisRect.bottomLeft() +QPoint(0, +offset); break;
6114   }
6115
6116   double xCor = 0, yCor = 0; // paint system correction, for pixel exact matches (affects baselines and ticks of top/right axes)
6117   switch (type)
6118   {
6119     case QCPAxis::atTop: yCor = -1; break;
6120     case QCPAxis::atRight: xCor = 1; break;
6121     default: break;
6122   }
6123   int margin = 0;
6124   // draw baseline:
6125   QLineF baseLine;
6126   painter->setPen(basePen);
6127   if (QCPAxis::orientation(type) == Qt::Horizontal)
6128     baseLine.setPoints(origin+QPointF(xCor, yCor), origin+QPointF(axisRect.width()+xCor, yCor));
6129   else
6130     baseLine.setPoints(origin+QPointF(xCor, yCor), origin+QPointF(xCor, -axisRect.height()+yCor));
6131   if (reversedEndings)
6132     baseLine = QLineF(baseLine.p2(), baseLine.p1()); // won't make a difference for line itself, but for line endings later
6133   painter->drawLine(baseLine);
6134   
6135   // draw ticks:
6136   if (!tickPositions.isEmpty())
6137   {
6138     painter->setPen(tickPen);
6139     int tickDir = (type == QCPAxis::atBottom || type == QCPAxis::atRight) ? -1 : 1; // direction of ticks ("inward" is right for left axis and left for right axis)
6140     if (QCPAxis::orientation(type) == Qt::Horizontal)
6141     {
6142       for (int i=0; i<tickPositions.size(); ++i)
6143         painter->drawLine(QLineF(tickPositions.at(i)+xCor, origin.y()-tickLengthOut*tickDir+yCor, tickPositions.at(i)+xCor, origin.y()+tickLengthIn*tickDir+yCor));
6144     } else
6145     {
6146       for (int i=0; i<tickPositions.size(); ++i)
6147         painter->drawLine(QLineF(origin.x()-tickLengthOut*tickDir+xCor, tickPositions.at(i)+yCor, origin.x()+tickLengthIn*tickDir+xCor, tickPositions.at(i)+yCor));
6148     }
6149   }
6150   
6151   // draw subticks:
6152   if (!subTickPositions.isEmpty())
6153   {
6154     painter->setPen(subTickPen);
6155     // direction of ticks ("inward" is right for left axis and left for right axis)
6156     int tickDir = (type == QCPAxis::atBottom || type == QCPAxis::atRight) ? -1 : 1;
6157     if (QCPAxis::orientation(type) == Qt::Horizontal)
6158     {
6159       for (int i=0; i<subTickPositions.size(); ++i)
6160         painter->drawLine(QLineF(subTickPositions.at(i)+xCor, origin.y()-subTickLengthOut*tickDir+yCor, subTickPositions.at(i)+xCor, origin.y()+subTickLengthIn*tickDir+yCor));
6161     } else
6162     {
6163       for (int i=0; i<subTickPositions.size(); ++i)
6164         painter->drawLine(QLineF(origin.x()-subTickLengthOut*tickDir+xCor, subTickPositions.at(i)+yCor, origin.x()+subTickLengthIn*tickDir+xCor, subTickPositions.at(i)+yCor));
6165     }
6166   }
6167   margin += qMax(0, qMax(tickLengthOut, subTickLengthOut));
6168   
6169   // draw axis base endings:
6170   bool antialiasingBackup = painter->antialiasing();
6171   painter->setAntialiasing(true); // always want endings to be antialiased, even if base and ticks themselves aren't
6172   painter->setBrush(QBrush(basePen.color()));
6173   QVector2D baseLineVector(baseLine.dx(), baseLine.dy());
6174   if (lowerEnding.style() != QCPLineEnding::esNone)
6175     lowerEnding.draw(painter, QVector2D(baseLine.p1())-baseLineVector.normalized()*lowerEnding.realLength()*(lowerEnding.inverted()?-1:1), -baseLineVector);
6176   if (upperEnding.style() != QCPLineEnding::esNone)
6177     upperEnding.draw(painter, QVector2D(baseLine.p2())+baseLineVector.normalized()*upperEnding.realLength()*(upperEnding.inverted()?-1:1), baseLineVector);
6178   painter->setAntialiasing(antialiasingBackup);
6179   
6180   // tick labels:
6181   QRect oldClipRect;
6182   if (tickLabelSide == QCPAxis::lsInside) // if using inside labels, clip them to the axis rect
6183   {
6184     oldClipRect = painter->clipRegion().boundingRect();
6185     painter->setClipRect(axisRect);
6186   }
6187   QSize tickLabelsSize(0, 0); // size of largest tick label, for offset calculation of axis label
6188   if (!tickLabels.isEmpty())
6189   {
6190     if (tickLabelSide == QCPAxis::lsOutside)
6191       margin += tickLabelPadding;
6192     painter->setFont(tickLabelFont);
6193     painter->setPen(QPen(tickLabelColor));
6194     const int maxLabelIndex = qMin(tickPositions.size(), tickLabels.size());
6195     int distanceToAxis = margin;
6196     if (tickLabelSide == QCPAxis::lsInside)
6197       distanceToAxis = -(qMax(tickLengthIn, subTickLengthIn)+tickLabelPadding);
6198     for (int i=0; i<maxLabelIndex; ++i)
6199       placeTickLabel(painter, tickPositions.at(i), distanceToAxis, tickLabels.at(i), &tickLabelsSize);
6200     if (tickLabelSide == QCPAxis::lsOutside)
6201       margin += (QCPAxis::orientation(type) == Qt::Horizontal) ? tickLabelsSize.height() : tickLabelsSize.width();
6202   }
6203   if (tickLabelSide == QCPAxis::lsInside)
6204     painter->setClipRect(oldClipRect);
6205   
6206   // axis label:
6207   QRect labelBounds;
6208   if (!label.isEmpty())
6209   {
6210     margin += labelPadding;
6211     painter->setFont(labelFont);
6212     painter->setPen(QPen(labelColor));
6213     labelBounds = painter->fontMetrics().boundingRect(0, 0, 0, 0, Qt::TextDontClip, label);
6214     if (type == QCPAxis::atLeft)
6215     {
6216       QTransform oldTransform = painter->transform();
6217       painter->translate((origin.x()-margin-labelBounds.height()), origin.y());
6218       painter->rotate(-90);
6219       painter->drawText(0, 0, axisRect.height(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, label);
6220       painter->setTransform(oldTransform);
6221     }
6222     else if (type == QCPAxis::atRight)
6223     {
6224       QTransform oldTransform = painter->transform();
6225       painter->translate((origin.x()+margin+labelBounds.height()), origin.y()-axisRect.height());
6226       painter->rotate(90);
6227       painter->drawText(0, 0, axisRect.height(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, label);
6228       painter->setTransform(oldTransform);
6229     }
6230     else if (type == QCPAxis::atTop)
6231       painter->drawText(origin.x(), origin.y()-margin-labelBounds.height(), axisRect.width(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, label);
6232     else if (type == QCPAxis::atBottom)
6233       painter->drawText(origin.x(), origin.y()+margin, axisRect.width(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, label);
6234   }
6235   
6236   // set selection boxes:
6237   int selectionTolerance = 0;
6238   if (mParentPlot)
6239     selectionTolerance = mParentPlot->selectionTolerance();
6240   else
6241     qDebug() << Q_FUNC_INFO << "mParentPlot is null";
6242   int selAxisOutSize = qMax(qMax(tickLengthOut, subTickLengthOut), selectionTolerance);
6243   int selAxisInSize = selectionTolerance;
6244   int selTickLabelSize;
6245   int selTickLabelOffset;
6246   if (tickLabelSide == QCPAxis::lsOutside)
6247   {
6248     selTickLabelSize = (QCPAxis::orientation(type) == Qt::Horizontal ? tickLabelsSize.height() : tickLabelsSize.width());
6249     selTickLabelOffset = qMax(tickLengthOut, subTickLengthOut)+tickLabelPadding;
6250   } else
6251   {
6252     selTickLabelSize = -(QCPAxis::orientation(type) == Qt::Horizontal ? tickLabelsSize.height() : tickLabelsSize.width());
6253     selTickLabelOffset = -(qMax(tickLengthIn, subTickLengthIn)+tickLabelPadding);
6254   }
6255   int selLabelSize = labelBounds.height();
6256   int selLabelOffset = qMax(tickLengthOut, subTickLengthOut)+(!tickLabels.isEmpty() && tickLabelSide == QCPAxis::lsOutside ? tickLabelPadding+selTickLabelSize : 0)+labelPadding;
6257   if (type == QCPAxis::atLeft)
6258   {
6259     mAxisSelectionBox.setCoords(origin.x()-selAxisOutSize, axisRect.top(), origin.x()+selAxisInSize, axisRect.bottom());
6260     mTickLabelsSelectionBox.setCoords(origin.x()-selTickLabelOffset-selTickLabelSize, axisRect.top(), origin.x()-selTickLabelOffset, axisRect.bottom());
6261     mLabelSelectionBox.setCoords(origin.x()-selLabelOffset-selLabelSize, axisRect.top(), origin.x()-selLabelOffset, axisRect.bottom());
6262   } else if (type == QCPAxis::atRight)
6263   {
6264     mAxisSelectionBox.setCoords(origin.x()-selAxisInSize, axisRect.top(), origin.x()+selAxisOutSize, axisRect.bottom());
6265     mTickLabelsSelectionBox.setCoords(origin.x()+selTickLabelOffset+selTickLabelSize, axisRect.top(), origin.x()+selTickLabelOffset, axisRect.bottom());
6266     mLabelSelectionBox.setCoords(origin.x()+selLabelOffset+selLabelSize, axisRect.top(), origin.x()+selLabelOffset, axisRect.bottom());
6267   } else if (type == QCPAxis::atTop)
6268   {
6269     mAxisSelectionBox.setCoords(axisRect.left(), origin.y()-selAxisOutSize, axisRect.right(), origin.y()+selAxisInSize);
6270     mTickLabelsSelectionBox.setCoords(axisRect.left(), origin.y()-selTickLabelOffset-selTickLabelSize, axisRect.right(), origin.y()-selTickLabelOffset);
6271     mLabelSelectionBox.setCoords(axisRect.left(), origin.y()-selLabelOffset-selLabelSize, axisRect.right(), origin.y()-selLabelOffset);
6272   } else if (type == QCPAxis::atBottom)
6273   {
6274     mAxisSelectionBox.setCoords(axisRect.left(), origin.y()-selAxisInSize, axisRect.right(), origin.y()+selAxisOutSize);
6275     mTickLabelsSelectionBox.setCoords(axisRect.left(), origin.y()+selTickLabelOffset+selTickLabelSize, axisRect.right(), origin.y()+selTickLabelOffset);
6276     mLabelSelectionBox.setCoords(axisRect.left(), origin.y()+selLabelOffset+selLabelSize, axisRect.right(), origin.y()+selLabelOffset);
6277   }
6278   mAxisSelectionBox = mAxisSelectionBox.normalized();
6279   mTickLabelsSelectionBox = mTickLabelsSelectionBox.normalized();
6280   mLabelSelectionBox = mLabelSelectionBox.normalized();
6281   // draw hitboxes for debug purposes:
6282   //painter->setBrush(Qt::NoBrush);
6283   //painter->drawRects(QVector<QRect>() << mAxisSelectionBox << mTickLabelsSelectionBox << mLabelSelectionBox);
6284 }
6285
6286 /*! \internal
6287   
6288   Returns the size ("margin" in QCPAxisRect context, so measured perpendicular to the axis backbone
6289   direction) needed to fit the axis.
6290 */
6291 int QCPAxisPainterPrivate::size() const
6292 {
6293   int result = 0;
6294   
6295   // get length of tick marks pointing outwards:
6296   if (!tickPositions.isEmpty())
6297     result += qMax(0, qMax(tickLengthOut, subTickLengthOut));
6298   
6299   // calculate size of tick labels:
6300   if (tickLabelSide == QCPAxis::lsOutside)
6301   {
6302     QSize tickLabelsSize(0, 0);
6303     if (!tickLabels.isEmpty())
6304     {
6305       for (int i=0; i<tickLabels.size(); ++i)
6306         getMaxTickLabelSize(tickLabelFont, tickLabels.at(i), &tickLabelsSize);
6307       result += QCPAxis::orientation(type) == Qt::Horizontal ? tickLabelsSize.height() : tickLabelsSize.width();
6308     result += tickLabelPadding;
6309     }
6310   }
6311   
6312   // calculate size of axis label (only height needed, because left/right labels are rotated by 90 degrees):
6313   if (!label.isEmpty())
6314   {
6315     QFontMetrics fontMetrics(labelFont);
6316     QRect bounds;
6317     bounds = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip | Qt::AlignHCenter | Qt::AlignVCenter, label);
6318     result += bounds.height() + labelPadding;
6319   }
6320   
6321   return result;
6322 }
6323
6324 /*! \internal
6325   
6326   Clears the internal label cache. Upon the next \ref draw, all labels will be created new. This
6327   method is called automatically in \ref draw, if any parameters have changed that invalidate the
6328   cached labels, such as font, color, etc.
6329 */
6330 void QCPAxisPainterPrivate::clearCache()
6331 {
6332   mLabelCache.clear();
6333 }
6334
6335 /*! \internal
6336   
6337   Returns a hash that allows uniquely identifying whether the label parameters have changed such
6338   that the cached labels must be refreshed (\ref clearCache). It is used in \ref draw. If the
6339   return value of this method hasn't changed since the last redraw, the respective label parameters
6340   haven't changed and cached labels may be used.
6341 */
6342 QByteArray QCPAxisPainterPrivate::generateLabelParameterHash() const
6343 {
6344   QByteArray result;
6345   result.append(QByteArray::number(tickLabelRotation));
6346   result.append(QByteArray::number((int)tickLabelSide));
6347   result.append(QByteArray::number((int)substituteExponent));
6348   result.append(QByteArray::number((int)numberMultiplyCross));
6349   result.append(tickLabelColor.name().toLatin1()+QByteArray::number(tickLabelColor.alpha(), 16));
6350   result.append(tickLabelFont.toString().toLatin1());
6351   return result;
6352 }
6353
6354 /*! \internal
6355   
6356   Draws a single tick label with the provided \a painter, utilizing the internal label cache to
6357   significantly speed up drawing of labels that were drawn in previous calls. The tick label is
6358   always bound to an axis, the distance to the axis is controllable via \a distanceToAxis in
6359   pixels. The pixel position in the axis direction is passed in the \a position parameter. Hence
6360   for the bottom axis, \a position would indicate the horizontal pixel position (not coordinate),
6361   at which the label should be drawn.
6362   
6363   In order to later draw the axis label in a place that doesn't overlap with the tick labels, the
6364   largest tick label size is needed. This is acquired by passing a \a tickLabelsSize to the \ref
6365   drawTickLabel calls during the process of drawing all tick labels of one axis. In every call, \a
6366   tickLabelsSize is expanded, if the drawn label exceeds the value \a tickLabelsSize currently
6367   holds.
6368   
6369   The label is drawn with the font and pen that are currently set on the \a painter. To draw
6370   superscripted powers, the font is temporarily made smaller by a fixed factor (see \ref
6371   getTickLabelData).
6372 */
6373 void QCPAxisPainterPrivate::placeTickLabel(QCPPainter *painter, double position, int distanceToAxis, const QString &text, QSize *tickLabelsSize)
6374 {
6375   // warning: if you change anything here, also adapt getMaxTickLabelSize() accordingly!
6376   if (text.isEmpty()) return;
6377   QSize finalSize;
6378   QPointF labelAnchor;
6379   switch (type)
6380   {
6381     case QCPAxis::atLeft:   labelAnchor = QPointF(axisRect.left()-distanceToAxis-offset, position); break;
6382     case QCPAxis::atRight:  labelAnchor = QPointF(axisRect.right()+distanceToAxis+offset, position); break;
6383     case QCPAxis::atTop:    labelAnchor = QPointF(position, axisRect.top()-distanceToAxis-offset); break;
6384     case QCPAxis::atBottom: labelAnchor = QPointF(position, axisRect.bottom()+distanceToAxis+offset); break;
6385   }
6386   if (mParentPlot->plottingHints().testFlag(QCP::phCacheLabels) && !painter->modes().testFlag(QCPPainter::pmNoCaching)) // label caching enabled
6387   {
6388     CachedLabel *cachedLabel = mLabelCache.take(text); // attempt to get label from cache
6389     if (!cachedLabel)  // no cached label existed, create it
6390     {
6391       cachedLabel = new CachedLabel;
6392       TickLabelData labelData = getTickLabelData(painter->font(), text);
6393       cachedLabel->offset = getTickLabelDrawOffset(labelData)+labelData.rotatedTotalBounds.topLeft();
6394       cachedLabel->pixmap = QPixmap(labelData.rotatedTotalBounds.size());
6395       cachedLabel->pixmap.fill(Qt::transparent);
6396       QCPPainter cachePainter(&cachedLabel->pixmap);
6397       cachePainter.setPen(painter->pen());
6398       drawTickLabel(&cachePainter, -labelData.rotatedTotalBounds.topLeft().x(), -labelData.rotatedTotalBounds.topLeft().y(), labelData);
6399     }
6400     // if label would be partly clipped by widget border on sides, don't draw it (only for outside tick labels):
6401     bool labelClippedByBorder = false;
6402     if (tickLabelSide == QCPAxis::lsOutside)
6403     {
6404       if (QCPAxis::orientation(type) == Qt::Horizontal)
6405         labelClippedByBorder = labelAnchor.x()+cachedLabel->offset.x()+cachedLabel->pixmap.width() > viewportRect.right() || labelAnchor.x()+cachedLabel->offset.x() < viewportRect.left();
6406       else
6407         labelClippedByBorder = labelAnchor.y()+cachedLabel->offset.y()+cachedLabel->pixmap.height() > viewportRect.bottom() || labelAnchor.y()+cachedLabel->offset.y() < viewportRect.top();
6408     }
6409     if (!labelClippedByBorder)
6410     {
6411       painter->drawPixmap(labelAnchor+cachedLabel->offset, cachedLabel->pixmap);
6412       finalSize = cachedLabel->pixmap.size();
6413     }
6414     mLabelCache.insert(text, cachedLabel); // return label to cache or insert for the first time if newly created
6415   } else // label caching disabled, draw text directly on surface:
6416   {
6417     TickLabelData labelData = getTickLabelData(painter->font(), text);
6418     QPointF finalPosition = labelAnchor + getTickLabelDrawOffset(labelData);
6419     // if label would be partly clipped by widget border on sides, don't draw it (only for outside tick labels):
6420      bool labelClippedByBorder = false;
6421     if (tickLabelSide == QCPAxis::lsOutside)
6422     {
6423       if (QCPAxis::orientation(type) == Qt::Horizontal)
6424         labelClippedByBorder = finalPosition.x()+(labelData.rotatedTotalBounds.width()+labelData.rotatedTotalBounds.left()) > viewportRect.right() || finalPosition.x()+labelData.rotatedTotalBounds.left() < viewportRect.left();
6425       else
6426         labelClippedByBorder = finalPosition.y()+(labelData.rotatedTotalBounds.height()+labelData.rotatedTotalBounds.top()) > viewportRect.bottom() || finalPosition.y()+labelData.rotatedTotalBounds.top() < viewportRect.top();
6427     }
6428     if (!labelClippedByBorder)
6429     {
6430       drawTickLabel(painter, finalPosition.x(), finalPosition.y(), labelData);
6431       finalSize = labelData.rotatedTotalBounds.size();
6432     }
6433   }
6434   
6435   // expand passed tickLabelsSize if current tick label is larger:
6436   if (finalSize.width() > tickLabelsSize->width())
6437     tickLabelsSize->setWidth(finalSize.width());
6438   if (finalSize.height() > tickLabelsSize->height())
6439     tickLabelsSize->setHeight(finalSize.height());
6440 }
6441
6442 /*! \internal
6443   
6444   This is a \ref placeTickLabel helper function.
6445   
6446   Draws the tick label specified in \a labelData with \a painter at the pixel positions \a x and \a
6447   y. This function is used by \ref placeTickLabel to create new tick labels for the cache, or to
6448   directly draw the labels on the QCustomPlot surface when label caching is disabled, i.e. when
6449   QCP::phCacheLabels plotting hint is not set.
6450 */
6451 void QCPAxisPainterPrivate::drawTickLabel(QCPPainter *painter, double x, double y, const TickLabelData &labelData) const
6452 {
6453   // backup painter settings that we're about to change:
6454   QTransform oldTransform = painter->transform();
6455   QFont oldFont = painter->font();
6456   
6457   // transform painter to position/rotation:
6458   painter->translate(x, y);
6459   if (!qFuzzyIsNull(tickLabelRotation))
6460     painter->rotate(tickLabelRotation);
6461   
6462   // draw text:
6463   if (!labelData.expPart.isEmpty()) // indicator that beautiful powers must be used
6464   {
6465     painter->setFont(labelData.baseFont);
6466     painter->drawText(0, 0, 0, 0, Qt::TextDontClip, labelData.basePart);
6467     painter->setFont(labelData.expFont);
6468     painter->drawText(labelData.baseBounds.width()+1, 0, labelData.expBounds.width(), labelData.expBounds.height(), Qt::TextDontClip,  labelData.expPart);
6469   } else
6470   {
6471     painter->setFont(labelData.baseFont);
6472     painter->drawText(0, 0, labelData.totalBounds.width(), labelData.totalBounds.height(), Qt::TextDontClip | Qt::AlignHCenter, labelData.basePart);
6473   }
6474   
6475   // reset painter settings to what it was before:
6476   painter->setTransform(oldTransform);
6477   painter->setFont(oldFont);
6478 }
6479
6480 /*! \internal
6481   
6482   This is a \ref placeTickLabel helper function.
6483   
6484   Transforms the passed \a text and \a font to a tickLabelData structure that can then be further
6485   processed by \ref getTickLabelDrawOffset and \ref drawTickLabel. It splits the text into base and
6486   exponent if necessary (member substituteExponent) and calculates appropriate bounding boxes.
6487 */
6488 QCPAxisPainterPrivate::TickLabelData QCPAxisPainterPrivate::getTickLabelData(const QFont &font, const QString &text) const
6489 {
6490   TickLabelData result;
6491   
6492   // determine whether beautiful decimal powers should be used
6493   bool useBeautifulPowers = false;
6494   int ePos = -1; // first index of exponent part, text before that will be basePart, text until eLast will be expPart
6495   int eLast = -1; // last index of exponent part, rest of text after this will be suffixPart
6496   if (substituteExponent)
6497   {
6498     ePos = text.indexOf(QLatin1Char('e'));
6499     if (ePos > 0 && text.at(ePos-1).isDigit())
6500     {
6501       eLast = ePos;
6502       while (eLast+1 < text.size() && (text.at(eLast+1) == QLatin1Char('+') || text.at(eLast+1) == QLatin1Char('-') || text.at(eLast+1).isDigit()))
6503         ++eLast;
6504       if (eLast > ePos) // only if also to right of 'e' is a digit/+/- interpret it as beautifiable power
6505         useBeautifulPowers = true;
6506     }
6507   }
6508   
6509   // calculate text bounding rects and do string preparation for beautiful decimal powers:
6510   result.baseFont = font;
6511   if (result.baseFont.pointSizeF() > 0) // might return -1 if specified with setPixelSize, in that case we can't do correction in next line
6512     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
6513   if (useBeautifulPowers)
6514   {
6515     // split text into parts of number/symbol that will be drawn normally and part that will be drawn as exponent:
6516     result.basePart = text.left(ePos);
6517     // in log scaling, we want to turn "1*10^n" into "10^n", else add multiplication sign and decimal base:
6518     if (abbreviateDecimalPowers && result.basePart == QLatin1String("1"))
6519       result.basePart = QLatin1String("10");
6520     else
6521       result.basePart += (numberMultiplyCross ? QString(QChar(215)) : QString(QChar(183))) + QLatin1String("10");
6522     result.expPart = text.mid(ePos+1);
6523     // clip "+" and leading zeros off expPart:
6524     while (result.expPart.length() > 2 && result.expPart.at(1) == QLatin1Char('0')) // length > 2 so we leave one zero when numberFormatChar is 'e'
6525       result.expPart.remove(1, 1);
6526     if (!result.expPart.isEmpty() && result.expPart.at(0) == QLatin1Char('+'))
6527       result.expPart.remove(0, 1);
6528     // prepare smaller font for exponent:
6529     result.expFont = font;
6530     if (result.expFont.pointSize() > 0)
6531       result.expFont.setPointSize(result.expFont.pointSize()*0.75);
6532     else
6533       result.expFont.setPixelSize(result.expFont.pixelSize()*0.75);
6534     // calculate bounding rects of base part, exponent part and total one:
6535     result.baseBounds = QFontMetrics(result.baseFont).boundingRect(0, 0, 0, 0, Qt::TextDontClip, result.basePart);
6536     result.expBounds = QFontMetrics(result.expFont).boundingRect(0, 0, 0, 0, Qt::TextDontClip, result.expPart);
6537     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
6538   } else // useBeautifulPowers == false
6539   {
6540     result.basePart = text;
6541     result.totalBounds = QFontMetrics(result.baseFont).boundingRect(0, 0, 0, 0, Qt::TextDontClip | Qt::AlignHCenter, result.basePart);
6542   }
6543   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
6544   
6545   // calculate possibly different bounding rect after rotation:
6546   result.rotatedTotalBounds = result.totalBounds;
6547   if (!qFuzzyIsNull(tickLabelRotation))
6548   {
6549     QTransform transform;
6550     transform.rotate(tickLabelRotation);
6551     result.rotatedTotalBounds = transform.mapRect(result.rotatedTotalBounds);
6552   }
6553   
6554   return result;
6555 }
6556
6557 /*! \internal
6558   
6559   This is a \ref placeTickLabel helper function.
6560   
6561   Calculates the offset at which the top left corner of the specified tick label shall be drawn.
6562   The offset is relative to a point right next to the tick the label belongs to.
6563   
6564   This function is thus responsible for e.g. centering tick labels under ticks and positioning them
6565   appropriately when they are rotated.
6566 */
6567 QPointF QCPAxisPainterPrivate::getTickLabelDrawOffset(const TickLabelData &labelData) const
6568 {
6569   /*
6570     calculate label offset from base point at tick (non-trivial, for best visual appearance): short
6571     explanation for bottom axis: The anchor, i.e. the point in the label that is placed
6572     horizontally under the corresponding tick is always on the label side that is closer to the
6573     axis (e.g. the left side of the text when we're rotating clockwise). On that side, the height
6574     is halved and the resulting point is defined the anchor. This way, a 90 degree rotated text
6575     will be centered under the tick (i.e. displaced horizontally by half its height). At the same
6576     time, a 45 degree rotated text will "point toward" its tick, as is typical for rotated tick
6577     labels.
6578   */
6579   bool doRotation = !qFuzzyIsNull(tickLabelRotation);
6580   bool flip = qFuzzyCompare(qAbs(tickLabelRotation), 90.0); // perfect +/-90 degree flip. Indicates vertical label centering on vertical axes.
6581   double radians = tickLabelRotation/180.0*M_PI;
6582   int x=0, y=0;
6583   if ((type == QCPAxis::atLeft && tickLabelSide == QCPAxis::lsOutside) || (type == QCPAxis::atRight && tickLabelSide == QCPAxis::lsInside)) // Anchor at right side of tick label
6584   {
6585     if (doRotation)
6586     {
6587       if (tickLabelRotation > 0)
6588       {
6589         x = -qCos(radians)*labelData.totalBounds.width();
6590         y = flip ? -labelData.totalBounds.width()/2.0 : -qSin(radians)*labelData.totalBounds.width()-qCos(radians)*labelData.totalBounds.height()/2.0;
6591       } else
6592       {
6593         x = -qCos(-radians)*labelData.totalBounds.width()-qSin(-radians)*labelData.totalBounds.height();
6594         y = flip ? +labelData.totalBounds.width()/2.0 : +qSin(-radians)*labelData.totalBounds.width()-qCos(-radians)*labelData.totalBounds.height()/2.0;
6595       }
6596     } else
6597     {
6598       x = -labelData.totalBounds.width();
6599       y = -labelData.totalBounds.height()/2.0;
6600     }
6601   } else if ((type == QCPAxis::atRight && tickLabelSide == QCPAxis::lsOutside) || (type == QCPAxis::atLeft && tickLabelSide == QCPAxis::lsInside)) // Anchor at left side of tick label
6602   {
6603     if (doRotation)
6604     {
6605       if (tickLabelRotation > 0)
6606       {
6607         x = +qSin(radians)*labelData.totalBounds.height();
6608         y = flip ? -labelData.totalBounds.width()/2.0 : -qCos(radians)*labelData.totalBounds.height()/2.0;
6609       } else
6610       {
6611         x = 0;
6612         y = flip ? +labelData.totalBounds.width()/2.0 : -qCos(-radians)*labelData.totalBounds.height()/2.0;
6613       }
6614     } else
6615     {
6616       x = 0;
6617       y = -labelData.totalBounds.height()/2.0;
6618     }
6619   } else if ((type == QCPAxis::atTop && tickLabelSide == QCPAxis::lsOutside) || (type == QCPAxis::atBottom && tickLabelSide == QCPAxis::lsInside)) // Anchor at bottom side of tick label
6620   {
6621     if (doRotation)
6622     {
6623       if (tickLabelRotation > 0)
6624       {
6625         x = -qCos(radians)*labelData.totalBounds.width()+qSin(radians)*labelData.totalBounds.height()/2.0;
6626         y = -qSin(radians)*labelData.totalBounds.width()-qCos(radians)*labelData.totalBounds.height();
6627       } else
6628       {
6629         x = -qSin(-radians)*labelData.totalBounds.height()/2.0;
6630         y = -qCos(-radians)*labelData.totalBounds.height();
6631       }
6632     } else
6633     {
6634       x = -labelData.totalBounds.width()/2.0;
6635       y = -labelData.totalBounds.height();
6636     }
6637   } else if ((type == QCPAxis::atBottom && tickLabelSide == QCPAxis::lsOutside) || (type == QCPAxis::atTop && tickLabelSide == QCPAxis::lsInside)) // Anchor at top side of tick label
6638   {
6639     if (doRotation)
6640     {
6641       if (tickLabelRotation > 0)
6642       {
6643         x = +qSin(radians)*labelData.totalBounds.height()/2.0;
6644         y = 0;
6645       } else
6646       {
6647         x = -qCos(-radians)*labelData.totalBounds.width()-qSin(-radians)*labelData.totalBounds.height()/2.0;
6648         y = +qSin(-radians)*labelData.totalBounds.width();
6649       }
6650     } else
6651     {
6652       x = -labelData.totalBounds.width()/2.0;
6653       y = 0;
6654     }
6655   }
6656   
6657   return QPointF(x, y);
6658 }
6659
6660 /*! \internal
6661   
6662   Simulates the steps done by \ref placeTickLabel by calculating bounding boxes of the text label
6663   to be drawn, depending on number format etc. Since only the largest tick label is wanted for the
6664   margin calculation, the passed \a tickLabelsSize is only expanded, if it's currently set to a
6665   smaller width/height.
6666 */
6667 void QCPAxisPainterPrivate::getMaxTickLabelSize(const QFont &font, const QString &text,  QSize *tickLabelsSize) const
6668 {
6669   // note: this function must return the same tick label sizes as the placeTickLabel function.
6670   QSize finalSize;
6671   if (mParentPlot->plottingHints().testFlag(QCP::phCacheLabels) && mLabelCache.contains(text)) // label caching enabled and have cached label
6672   {
6673     const CachedLabel *cachedLabel = mLabelCache.object(text);
6674     finalSize = cachedLabel->pixmap.size();
6675   } else // label caching disabled or no label with this text cached:
6676   {
6677     TickLabelData labelData = getTickLabelData(font, text);
6678     finalSize = labelData.rotatedTotalBounds.size();
6679   }
6680   
6681   // expand passed tickLabelsSize if current tick label is larger:
6682   if (finalSize.width() > tickLabelsSize->width())
6683     tickLabelsSize->setWidth(finalSize.width());
6684   if (finalSize.height() > tickLabelsSize->height())
6685     tickLabelsSize->setHeight(finalSize.height());
6686 }
6687
6688
6689 ////////////////////////////////////////////////////////////////////////////////////////////////////
6690 //////////////////// QCPAbstractPlottable
6691 ////////////////////////////////////////////////////////////////////////////////////////////////////
6692
6693 /*! \class QCPAbstractPlottable
6694   \brief The abstract base class for all data representing objects in a plot.
6695
6696   It defines a very basic interface like name, pen, brush, visibility etc. Since this class is
6697   abstract, it can't be instantiated. Use one of the subclasses or create a subclass yourself to
6698   create new ways of displaying data (see "Creating own plottables" below).
6699   
6700   All further specifics are in the subclasses, for example:
6701   \li A normal graph with possibly a line, scatter points and error bars: \ref QCPGraph
6702   (typically created with \ref QCustomPlot::addGraph)
6703   \li A parametric curve: \ref QCPCurve
6704   \li A bar chart: \ref QCPBars
6705   \li A statistical box plot: \ref QCPStatisticalBox
6706   \li A color encoded two-dimensional map: \ref QCPColorMap
6707   \li An OHLC/Candlestick chart: \ref QCPFinancial
6708   
6709   \section plottables-subclassing Creating own plottables
6710   
6711   To create an own plottable, you implement a subclass of QCPAbstractPlottable. These are the pure
6712   virtual functions, you must implement:
6713   \li \ref clearData
6714   \li \ref selectTest
6715   \li \ref draw
6716   \li \ref drawLegendIcon
6717   \li \ref getKeyRange
6718   \li \ref getValueRange
6719   
6720   See the documentation of those functions for what they need to do.
6721   
6722   For drawing your plot, you can use the \ref coordsToPixels functions to translate a point in plot
6723   coordinates to pixel coordinates. This function is quite convenient, because it takes the
6724   orientation of the key and value axes into account for you (x and y are swapped when the key axis
6725   is vertical and the value axis horizontal). If you are worried about performance (i.e. you need
6726   to translate many points in a loop like QCPGraph), you can directly use \ref
6727   QCPAxis::coordToPixel. However, you must then take care about the orientation of the axis
6728   yourself.
6729   
6730   Here are some important members you inherit from QCPAbstractPlottable:
6731   <table>
6732   <tr>
6733     <td>QCustomPlot *\b mParentPlot</td>
6734     <td>A pointer to the parent QCustomPlot instance. The parent plot is inferred from the axes that are passed in the constructor.</td>
6735   </tr><tr>
6736     <td>QString \b mName</td>
6737     <td>The name of the plottable.</td>
6738   </tr><tr>
6739     <td>QPen \b mPen</td>
6740     <td>The generic pen of the plottable. You should use this pen for the most prominent data representing lines in the plottable (e.g QCPGraph uses this pen for its graph lines and scatters)</td>
6741   </tr><tr>
6742     <td>QPen \b mSelectedPen</td>
6743     <td>The generic pen that should be used when the plottable is selected (hint: \ref mainPen gives you the right pen, depending on selection state).</td>
6744   </tr><tr>
6745     <td>QBrush \b mBrush</td>
6746     <td>The generic brush of the plottable. You should use this brush for the most prominent fillable structures in the plottable (e.g. QCPGraph uses this brush to control filling under the graph)</td>
6747   </tr><tr>
6748     <td>QBrush \b mSelectedBrush</td>
6749     <td>The generic brush that should be used when the plottable is selected (hint: \ref mainBrush gives you the right brush, depending on selection state).</td>
6750   </tr><tr>
6751     <td>QPointer<QCPAxis>\b mKeyAxis, \b mValueAxis</td>
6752     <td>The key and value axes this plottable is attached to. Call their QCPAxis::coordToPixel functions to translate coordinates to pixels in either the key or value dimension.
6753         Make sure to check whether the pointer is null before using it. If one of the axes is null, don't draw the plottable.</td>
6754   </tr><tr>
6755     <td>bool \b mSelected</td>
6756     <td>indicates whether the plottable is selected or not.</td>
6757   </tr>
6758   </table>
6759 */
6760
6761 /* start of documentation of pure virtual functions */
6762
6763 /*! \fn void QCPAbstractPlottable::clearData() = 0
6764   Clears all data in the plottable.
6765 */
6766
6767 /*! \fn void QCPAbstractPlottable::drawLegendIcon(QCPPainter *painter, const QRect &rect) const = 0
6768   \internal
6769   
6770   called by QCPLegend::draw (via QCPPlottableLegendItem::draw) to create a graphical representation
6771   of this plottable inside \a rect, next to the plottable name.
6772   
6773   The passed \a painter has its cliprect set to \a rect, so painting outside of \a rect won't
6774   appear outside the legend icon border.
6775 */
6776
6777 /*! \fn QCPRange QCPAbstractPlottable::getKeyRange(bool &foundRange, SignDomain inSignDomain) const = 0
6778   \internal
6779   
6780   called by rescaleAxes functions to get the full data key bounds. For logarithmic plots, one can
6781   set \a inSignDomain to either \ref sdNegative or \ref sdPositive in order to restrict the
6782   returned range to that sign domain. E.g. when only negative range is wanted, set \a inSignDomain
6783   to \ref sdNegative and all positive points will be ignored for range calculation. For no
6784   restriction, just set \a inSignDomain to \ref sdBoth (default). \a foundRange is an output
6785   parameter that indicates whether a range could be found or not. If this is false, you shouldn't
6786   use the returned range (e.g. no points in data).
6787
6788   Note that \a foundRange is not the same as \ref QCPRange::validRange, since the range returned by
6789   this function may have size zero, which wouldn't count as a valid range.
6790   
6791   \see rescaleAxes, getValueRange
6792 */
6793
6794 /*! \fn QCPRange QCPAbstractPlottable::getValueRange(bool &foundRange, SignDomain inSignDomain) const = 0
6795   \internal
6796   
6797   called by rescaleAxes functions to get the full data value bounds. For logarithmic plots, one can
6798   set \a inSignDomain to either \ref sdNegative or \ref sdPositive in order to restrict the
6799   returned range to that sign domain. E.g. when only negative range is wanted, set \a inSignDomain
6800   to \ref sdNegative and all positive points will be ignored for range calculation. For no
6801   restriction, just set \a inSignDomain to \ref sdBoth (default). \a foundRange is an output
6802   parameter that indicates whether a range could be found or not. If this is false, you shouldn't
6803   use the returned range (e.g. no points in data).
6804
6805   Note that \a foundRange is not the same as \ref QCPRange::validRange, since the range returned by
6806   this function may have size zero, which wouldn't count as a valid range.
6807   
6808   \see rescaleAxes, getKeyRange
6809 */
6810
6811 /* end of documentation of pure virtual functions */
6812 /* start of documentation of signals */
6813
6814 /*! \fn void QCPAbstractPlottable::selectionChanged(bool selected)
6815   
6816   This signal is emitted when the selection state of this plottable has changed, either by user
6817   interaction or by a direct call to \ref setSelected.
6818 */
6819
6820 /*! \fn void QCPAbstractPlottable::selectableChanged(bool selectable);
6821   
6822   This signal is emitted when the selectability of this plottable has changed.
6823   
6824   \see setSelectable
6825 */
6826
6827 /* end of documentation of signals */
6828
6829 /*!
6830   Constructs an abstract plottable which uses \a keyAxis as its key axis ("x") and \a valueAxis as
6831   its value axis ("y"). \a keyAxis and \a valueAxis must reside in the same QCustomPlot instance
6832   and have perpendicular orientations. If either of these restrictions is violated, a corresponding
6833   message is printed to the debug output (qDebug), the construction is not aborted, though.
6834   
6835   Since QCPAbstractPlottable is an abstract class that defines the basic interface to plottables,
6836   it can't be directly instantiated.
6837   
6838   You probably want one of the subclasses like \ref QCPGraph or \ref QCPCurve instead.
6839 */
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.";
6859 }
6860
6861 /*!
6862    The name is the textual representation of this plottable as it is displayed in the legend
6863    (\ref QCPLegend). It may contain any UTF-8 characters, including newlines.
6864 */
6865 void QCPAbstractPlottable::setName(const QString &name)
6866 {
6867   mName = name;
6868 }
6869
6870 /*!
6871   Sets whether fills of this plottable are drawn antialiased or not.
6872   
6873   Note that this setting may be overridden by \ref QCustomPlot::setAntialiasedElements and \ref
6874   QCustomPlot::setNotAntialiasedElements.
6875 */
6876 void QCPAbstractPlottable::setAntialiasedFill(bool enabled)
6877 {
6878   mAntialiasedFill = enabled;
6879 }
6880
6881 /*!
6882   Sets whether the scatter symbols of this plottable are drawn antialiased or not.
6883   
6884   Note that this setting may be overridden by \ref QCustomPlot::setAntialiasedElements and \ref
6885   QCustomPlot::setNotAntialiasedElements.
6886 */
6887 void QCPAbstractPlottable::setAntialiasedScatters(bool enabled)
6888 {
6889   mAntialiasedScatters = enabled;
6890 }
6891
6892 /*!
6893   Sets whether the error bars of this plottable are drawn antialiased or not.
6894   
6895   Note that this setting may be overridden by \ref QCustomPlot::setAntialiasedElements and \ref
6896   QCustomPlot::setNotAntialiasedElements.
6897 */
6898 void QCPAbstractPlottable::setAntialiasedErrorBars(bool enabled)
6899 {
6900   mAntialiasedErrorBars = enabled;
6901 }
6902
6903
6904 /*!
6905   The pen is used to draw basic lines that make up the plottable representation in the
6906   plot.
6907   
6908   For example, the \ref QCPGraph subclass draws its graph lines with this pen.
6909
6910   \see setBrush
6911 */
6912 void QCPAbstractPlottable::setPen(const QPen &pen)
6913 {
6914   mPen = pen;
6915 }
6916
6917 /*!
6918   When the plottable is selected, this pen is used to draw basic lines instead of the normal
6919   pen set via \ref setPen.
6920
6921   \see setSelected, setSelectable, setSelectedBrush, selectTest
6922 */
6923 void QCPAbstractPlottable::setSelectedPen(const QPen &pen)
6924 {
6925   mSelectedPen = pen;
6926 }
6927
6928 /*!
6929   The brush is used to draw basic fills of the plottable representation in the
6930   plot. The Fill can be a color, gradient or texture, see the usage of QBrush.
6931   
6932   For example, the \ref QCPGraph subclass draws the fill under the graph with this brush, when
6933   it's not set to Qt::NoBrush.
6934
6935   \see setPen
6936 */
6937 void QCPAbstractPlottable::setBrush(const QBrush &brush)
6938 {
6939   mBrush = brush;
6940 }
6941
6942 /*!
6943   When the plottable is selected, this brush is used to draw fills instead of the normal
6944   brush set via \ref setBrush.
6945
6946   \see setSelected, setSelectable, setSelectedPen, selectTest
6947 */
6948 void QCPAbstractPlottable::setSelectedBrush(const QBrush &brush)
6949 {
6950   mSelectedBrush = brush;
6951 }
6952
6953 /*!
6954   The key axis of a plottable can be set to any axis of a QCustomPlot, as long as it is orthogonal
6955   to the plottable's value axis. This function performs no checks to make sure this is the case.
6956   The typical mathematical choice is to use the x-axis (QCustomPlot::xAxis) as key axis and the
6957   y-axis (QCustomPlot::yAxis) as value axis.
6958   
6959   Normally, the key and value axes are set in the constructor of the plottable (or \ref
6960   QCustomPlot::addGraph when working with QCPGraphs through the dedicated graph interface).
6961
6962   \see setValueAxis
6963 */
6964 void QCPAbstractPlottable::setKeyAxis(QCPAxis *axis)
6965 {
6966   mKeyAxis = axis;
6967 }
6968
6969 /*!
6970   The value axis of a plottable can be set to any axis of a QCustomPlot, as long as it is
6971   orthogonal to the plottable's key axis. This function performs no checks to make sure this is the
6972   case. The typical mathematical choice is to use the x-axis (QCustomPlot::xAxis) as key axis and
6973   the y-axis (QCustomPlot::yAxis) as value axis.
6974
6975   Normally, the key and value axes are set in the constructor of the plottable (or \ref
6976   QCustomPlot::addGraph when working with QCPGraphs through the dedicated graph interface).
6977   
6978   \see setKeyAxis
6979 */
6980 void QCPAbstractPlottable::setValueAxis(QCPAxis *axis)
6981 {
6982   mValueAxis = axis;
6983 }
6984
6985 /*!
6986   Sets whether the user can (de-)select this plottable by clicking on the QCustomPlot surface.
6987   (When \ref QCustomPlot::setInteractions contains iSelectPlottables.)
6988   
6989   However, even when \a selectable was set to false, it is possible to set the selection manually,
6990   by calling \ref setSelected directly.
6991   
6992   \see setSelected
6993 */
6994 void QCPAbstractPlottable::setSelectable(bool selectable)
6995 {
6996   if (mSelectable != selectable)
6997   {
6998     mSelectable = selectable;
6999     emit selectableChanged(mSelectable);
7000   }
7001 }
7002
7003 /*!
7004   Sets whether this plottable is selected or not. When selected, it uses a different pen and brush
7005   to draw its lines and fills, see \ref setSelectedPen and \ref setSelectedBrush.
7006
7007   The entire selection mechanism for plottables is handled automatically when \ref
7008   QCustomPlot::setInteractions contains iSelectPlottables. You only need to call this function when
7009   you wish to change the selection state manually.
7010   
7011   This function can change the selection state even when \ref setSelectable was set to false.
7012   
7013   emits the \ref selectionChanged signal when \a selected is different from the previous selection state.
7014   
7015   \see setSelectable, selectTest
7016 */
7017 void QCPAbstractPlottable::setSelected(bool selected)
7018 {
7019   if (mSelected != selected)
7020   {
7021     mSelected = selected;
7022     emit selectionChanged(mSelected);
7023   }
7024 }
7025
7026 /*!
7027   Rescales the key and value axes associated with this plottable to contain all displayed data, so
7028   the whole plottable is visible. If the scaling of an axis is logarithmic, rescaleAxes will make
7029   sure not to rescale to an illegal range i.e. a range containing different signs and/or zero.
7030   Instead it will stay in the current sign domain and ignore all parts of the plottable that lie
7031   outside of that domain.
7032   
7033   \a onlyEnlarge makes sure the ranges are only expanded, never reduced. So it's possible to show
7034   multiple plottables in their entirety by multiple calls to rescaleAxes where the first call has
7035   \a onlyEnlarge set to false (the default), and all subsequent set to true.
7036   
7037   \see rescaleKeyAxis, rescaleValueAxis, QCustomPlot::rescaleAxes, QCPAxis::rescale
7038 */
7039 void QCPAbstractPlottable::rescaleAxes(bool onlyEnlarge) const
7040 {
7041   rescaleKeyAxis(onlyEnlarge);
7042   rescaleValueAxis(onlyEnlarge);
7043 }
7044
7045 /*!
7046   Rescales the key axis of the plottable so the whole plottable is visible.
7047   
7048   See \ref rescaleAxes for detailed behaviour.
7049 */
7050 void QCPAbstractPlottable::rescaleKeyAxis(bool onlyEnlarge) const
7051 {
7052   QCPAxis *keyAxis = mKeyAxis.data();
7053   if (!keyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
7054   
7055   SignDomain signDomain = sdBoth;
7056   if (keyAxis->scaleType() == QCPAxis::stLogarithmic)
7057     signDomain = (keyAxis->range().upper < 0 ? sdNegative : sdPositive);
7058   
7059   bool foundRange;
7060   QCPRange newRange = getKeyRange(foundRange, signDomain);
7061   if (foundRange)
7062   {
7063     if (onlyEnlarge)
7064       newRange.expand(keyAxis->range());
7065     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
7066     {
7067       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
7068       if (keyAxis->scaleType() == QCPAxis::stLinear)
7069       {
7070         newRange.lower = center-keyAxis->range().size()/2.0;
7071         newRange.upper = center+keyAxis->range().size()/2.0;
7072       } else // scaleType() == stLogarithmic
7073       {
7074         newRange.lower = center/qSqrt(keyAxis->range().upper/keyAxis->range().lower);
7075         newRange.upper = center*qSqrt(keyAxis->range().upper/keyAxis->range().lower);
7076       }
7077     }
7078     keyAxis->setRange(newRange);
7079   }
7080 }
7081
7082 /*!
7083   Rescales the value axis of the plottable so the whole plottable is visible.
7084   
7085   Returns true if the axis was actually scaled. This might not be the case if this plottable has an
7086   invalid range, e.g. because it has no data points.
7087   
7088   See \ref rescaleAxes for detailed behaviour.
7089 */
7090 void QCPAbstractPlottable::rescaleValueAxis(bool onlyEnlarge) const
7091 {
7092   QCPAxis *valueAxis = mValueAxis.data();
7093   if (!valueAxis) { qDebug() << Q_FUNC_INFO << "invalid value axis"; return; }
7094   
7095   SignDomain signDomain = sdBoth;
7096   if (valueAxis->scaleType() == QCPAxis::stLogarithmic)
7097     signDomain = (valueAxis->range().upper < 0 ? sdNegative : sdPositive);
7098   
7099   bool foundRange;
7100   QCPRange newRange = getValueRange(foundRange, signDomain);
7101   if (foundRange)
7102   {
7103     if (onlyEnlarge)
7104       newRange.expand(valueAxis->range());
7105     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
7106     {
7107       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
7108       if (valueAxis->scaleType() == QCPAxis::stLinear)
7109       {
7110         newRange.lower = center-valueAxis->range().size()/2.0;
7111         newRange.upper = center+valueAxis->range().size()/2.0;
7112       } else // scaleType() == stLogarithmic
7113       {
7114         newRange.lower = center/qSqrt(valueAxis->range().upper/valueAxis->range().lower);
7115         newRange.upper = center*qSqrt(valueAxis->range().upper/valueAxis->range().lower);
7116       }
7117     }
7118     valueAxis->setRange(newRange);
7119   }
7120 }
7121
7122 /*!
7123   Adds this plottable to the legend of the parent QCustomPlot (QCustomPlot::legend).
7124     
7125   Normally, a QCPPlottableLegendItem is created and inserted into the legend. If the plottable
7126   needs a more specialized representation in the legend, this function will take this into account
7127   and instead create the specialized subclass of QCPAbstractLegendItem.
7128     
7129   Returns true on success, i.e. when the legend exists and a legend item associated with this plottable isn't already in
7130   the legend.
7131     
7132   \see removeFromLegend, QCPLegend::addItem
7133 */
7134 bool QCPAbstractPlottable::addToLegend()
7135 {
7136   if (!mParentPlot || !mParentPlot->legend)
7137     return false;
7138   
7139   if (!mParentPlot->legend->hasItemWithPlottable(this))
7140   {
7141     mParentPlot->legend->addItem(new QCPPlottableLegendItem(mParentPlot->legend, this));
7142     return true;
7143   } else
7144     return false;
7145 }
7146
7147 /*!
7148   Removes the plottable from the legend of the parent QCustomPlot. This means the
7149   QCPAbstractLegendItem (usually a QCPPlottableLegendItem) that is associated with this plottable
7150   is removed.
7151     
7152   Returns true on success, i.e. if the legend exists and a legend item associated with this
7153   plottable was found and removed.
7154     
7155   \see addToLegend, QCPLegend::removeItem
7156 */
7157 bool QCPAbstractPlottable::removeFromLegend() const
7158 {
7159   if (!mParentPlot->legend)
7160     return false;
7161   
7162   if (QCPPlottableLegendItem *lip = mParentPlot->legend->itemWithPlottable(this))
7163     return mParentPlot->legend->removeItem(lip);
7164   else
7165     return false;
7166 }
7167
7168 /* inherits documentation from base class */
7169 QRect QCPAbstractPlottable::clipRect() const
7170 {
7171   if (mKeyAxis && mValueAxis)
7172     return mKeyAxis.data()->axisRect()->rect() & mValueAxis.data()->axisRect()->rect();
7173   else
7174     return QRect();
7175 }
7176
7177 /* inherits documentation from base class */
7178 QCP::Interaction QCPAbstractPlottable::selectionCategory() const
7179 {
7180   return QCP::iSelectPlottables;
7181 }
7182
7183 /*! \internal
7184   
7185   Convenience function for transforming a key/value pair to pixels on the QCustomPlot surface,
7186   taking the orientations of the axes associated with this plottable into account (e.g. whether key
7187   represents x or y).
7188   
7189   \a key and \a value are transformed to the coodinates in pixels and are written to \a x and \a y.
7190     
7191   \see pixelsToCoords, QCPAxis::coordToPixel
7192 */
7193 void QCPAbstractPlottable::coordsToPixels(double key, double value, double &x, double &y) const
7194 {
7195   QCPAxis *keyAxis = mKeyAxis.data();
7196   QCPAxis *valueAxis = mValueAxis.data();
7197   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
7198   
7199   if (keyAxis->orientation() == Qt::Horizontal)
7200   {
7201     x = keyAxis->coordToPixel(key);
7202     y = valueAxis->coordToPixel(value);
7203   } else
7204   {
7205     y = keyAxis->coordToPixel(key);
7206     x = valueAxis->coordToPixel(value);
7207   }
7208 }
7209
7210 /*! \internal
7211   \overload
7212   
7213   Returns the input as pixel coordinates in a QPointF.
7214 */
7215 const QPointF QCPAbstractPlottable::coordsToPixels(double key, double value) const
7216 {
7217   QCPAxis *keyAxis = mKeyAxis.data();
7218   QCPAxis *valueAxis = mValueAxis.data();
7219   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return QPointF(); }
7220   
7221   if (keyAxis->orientation() == Qt::Horizontal)
7222     return QPointF(keyAxis->coordToPixel(key), valueAxis->coordToPixel(value));
7223   else
7224     return QPointF(valueAxis->coordToPixel(value), keyAxis->coordToPixel(key));
7225 }
7226
7227 /*! \internal
7228   
7229   Convenience function for transforming a x/y pixel pair on the QCustomPlot surface to plot coordinates,
7230   taking the orientations of the axes associated with this plottable into account (e.g. whether key
7231   represents x or y).
7232   
7233   \a x and \a y are transformed to the plot coodinates and are written to \a key and \a value.
7234     
7235   \see coordsToPixels, QCPAxis::coordToPixel
7236 */
7237 void QCPAbstractPlottable::pixelsToCoords(double x, double y, double &key, double &value) const
7238 {
7239   QCPAxis *keyAxis = mKeyAxis.data();
7240   QCPAxis *valueAxis = mValueAxis.data();
7241   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
7242   
7243   if (keyAxis->orientation() == Qt::Horizontal)
7244   {
7245     key = keyAxis->pixelToCoord(x);
7246     value = valueAxis->pixelToCoord(y);
7247   } else
7248   {
7249     key = keyAxis->pixelToCoord(y);
7250     value = valueAxis->pixelToCoord(x);
7251   }
7252 }
7253
7254 /*! \internal
7255   \overload
7256
7257   Returns the pixel input \a pixelPos as plot coordinates \a key and \a value.
7258 */
7259 void QCPAbstractPlottable::pixelsToCoords(const QPointF &pixelPos, double &key, double &value) const
7260 {
7261   pixelsToCoords(pixelPos.x(), pixelPos.y(), key, value);
7262 }
7263
7264 /*! \internal
7265
7266   Returns the pen that should be used for drawing lines of the plottable. Returns mPen when the
7267   graph is not selected and mSelectedPen when it is.
7268 */
7269 QPen QCPAbstractPlottable::mainPen() const
7270 {
7271   return mSelected ? mSelectedPen : mPen;
7272 }
7273
7274 /*! \internal
7275
7276   Returns the brush that should be used for drawing fills of the plottable. Returns mBrush when the
7277   graph is not selected and mSelectedBrush when it is.
7278 */
7279 QBrush QCPAbstractPlottable::mainBrush() const
7280 {
7281   return mSelected ? mSelectedBrush : mBrush;
7282 }
7283
7284 /*! \internal
7285
7286   A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter
7287   before drawing plottable lines.
7288
7289   This is the antialiasing state the painter passed to the \ref draw method is in by default.
7290   
7291   This function takes into account the local setting of the antialiasing flag as well as the
7292   overrides set with \ref QCustomPlot::setAntialiasedElements and \ref
7293   QCustomPlot::setNotAntialiasedElements.
7294   
7295   \see setAntialiased, applyFillAntialiasingHint, applyScattersAntialiasingHint, applyErrorBarsAntialiasingHint
7296 */
7297 void QCPAbstractPlottable::applyDefaultAntialiasingHint(QCPPainter *painter) const
7298 {
7299   applyAntialiasingHint(painter, mAntialiased, QCP::aePlottables);
7300 }
7301
7302 /*! \internal
7303
7304   A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter
7305   before drawing plottable fills.
7306   
7307   This function takes into account the local setting of the antialiasing flag as well as the
7308   overrides set with \ref QCustomPlot::setAntialiasedElements and \ref
7309   QCustomPlot::setNotAntialiasedElements.
7310   
7311   \see setAntialiased, applyDefaultAntialiasingHint, applyScattersAntialiasingHint, applyErrorBarsAntialiasingHint
7312 */
7313 void QCPAbstractPlottable::applyFillAntialiasingHint(QCPPainter *painter) const
7314 {
7315   applyAntialiasingHint(painter, mAntialiasedFill, QCP::aeFills);
7316 }
7317
7318 /*! \internal
7319
7320   A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter
7321   before drawing plottable scatter points.
7322   
7323   This function takes into account the local setting of the antialiasing flag as well as the
7324   overrides set with \ref QCustomPlot::setAntialiasedElements and \ref
7325   QCustomPlot::setNotAntialiasedElements.
7326   
7327   \see setAntialiased, applyFillAntialiasingHint, applyDefaultAntialiasingHint, applyErrorBarsAntialiasingHint
7328 */
7329 void QCPAbstractPlottable::applyScattersAntialiasingHint(QCPPainter *painter) const
7330 {
7331   applyAntialiasingHint(painter, mAntialiasedScatters, QCP::aeScatters);
7332 }
7333
7334 /*! \internal
7335
7336   A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter
7337   before drawing plottable error bars.
7338   
7339   This function takes into account the local setting of the antialiasing flag as well as the
7340   overrides set with \ref QCustomPlot::setAntialiasedElements and \ref
7341   QCustomPlot::setNotAntialiasedElements.
7342   
7343   \see setAntialiased, applyFillAntialiasingHint, applyScattersAntialiasingHint, applyDefaultAntialiasingHint
7344 */
7345 void QCPAbstractPlottable::applyErrorBarsAntialiasingHint(QCPPainter *painter) const
7346 {
7347   applyAntialiasingHint(painter, mAntialiasedErrorBars, QCP::aeErrorBars);
7348 }
7349
7350 /*! \internal
7351
7352   Finds the shortest squared distance of \a point to the line segment defined by \a start and \a
7353   end.
7354   
7355   This function may be used to help with the implementation of the \ref selectTest function for
7356   specific plottables.
7357   
7358   \note This function is identical to QCPAbstractItem::distSqrToLine
7359 */
7360 double QCPAbstractPlottable::distSqrToLine(const QPointF &start, const QPointF &end, const QPointF &point) const
7361 {
7362   QVector2D a(start);
7363   QVector2D b(end);
7364   QVector2D p(point);
7365   QVector2D v(b-a);
7366   
7367   double vLengthSqr = v.lengthSquared();
7368   if (!qFuzzyIsNull(vLengthSqr))
7369   {
7370     double mu = QVector2D::dotProduct(p-a, v)/vLengthSqr;
7371     if (mu < 0)
7372       return (a-p).lengthSquared();
7373     else if (mu > 1)
7374       return (b-p).lengthSquared();
7375     else
7376       return ((a + mu*v)-p).lengthSquared();
7377   } else
7378     return (a-p).lengthSquared();
7379 }
7380
7381 /* inherits documentation from base class */
7382 void QCPAbstractPlottable::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged)
7383 {
7384   Q_UNUSED(event)
7385   Q_UNUSED(details)
7386   if (mSelectable)
7387   {
7388     bool selBefore = mSelected;
7389     setSelected(additive ? !mSelected : true);
7390     if (selectionStateChanged)
7391       *selectionStateChanged = mSelected != selBefore;
7392   }
7393 }
7394
7395 /* inherits documentation from base class */
7396 void QCPAbstractPlottable::deselectEvent(bool *selectionStateChanged)
7397 {
7398   if (mSelectable)
7399   {
7400     bool selBefore = mSelected;
7401     setSelected(false);
7402     if (selectionStateChanged)
7403       *selectionStateChanged = mSelected != selBefore;
7404   }
7405 }
7406
7407
7408 ////////////////////////////////////////////////////////////////////////////////////////////////////
7409 //////////////////// QCPItemAnchor
7410 ////////////////////////////////////////////////////////////////////////////////////////////////////
7411
7412 /*! \class QCPItemAnchor
7413   \brief An anchor of an item to which positions can be attached to.
7414   
7415   An item (QCPAbstractItem) may have one or more anchors. Unlike QCPItemPosition, an anchor doesn't
7416   control anything on its item, but provides a way to tie other items via their positions to the
7417   anchor.
7418
7419   For example, a QCPItemRect is defined by its positions \a topLeft and \a bottomRight.
7420   Additionally it has various anchors like \a top, \a topRight or \a bottomLeft etc. So you can
7421   attach the \a start (which is a QCPItemPosition) of a QCPItemLine to one of the anchors by
7422   calling QCPItemPosition::setParentAnchor on \a start, passing the wanted anchor of the
7423   QCPItemRect. This way the start of the line will now always follow the respective anchor location
7424   on the rect item.
7425   
7426   Note that QCPItemPosition derives from QCPItemAnchor, so every position can also serve as an
7427   anchor to other positions.
7428   
7429   To learn how to provide anchors in your own item subclasses, see the subclassing section of the
7430   QCPAbstractItem documentation.
7431 */
7432
7433 /* start documentation of inline functions */
7434
7435 /*! \fn virtual QCPItemPosition *QCPItemAnchor::toQCPItemPosition()
7436   
7437   Returns 0 if this instance is merely a QCPItemAnchor, and a valid pointer of type QCPItemPosition* if
7438   it actually is a QCPItemPosition (which is a subclass of QCPItemAnchor).
7439   
7440   This safe downcast functionality could also be achieved with a dynamic_cast. However, QCustomPlot avoids
7441   dynamic_cast to work with projects that don't have RTTI support enabled (e.g. -fno-rtti flag with
7442   gcc compiler).
7443 */
7444
7445 /* end documentation of inline functions */
7446
7447 /*!
7448   Creates a new QCPItemAnchor. You shouldn't create QCPItemAnchor instances directly, even if
7449   you want to make a new item subclass. Use \ref QCPAbstractItem::createAnchor instead, as
7450   explained in the subclassing section of the QCPAbstractItem documentation.
7451 */
7452 QCPItemAnchor::QCPItemAnchor(QCustomPlot *parentPlot, QCPAbstractItem *parentItem, const QString name, int anchorId) :
7453   mName(name),
7454   mParentPlot(parentPlot),
7455   mParentItem(parentItem),
7456   mAnchorId(anchorId)
7457 {
7458 }
7459
7460 QCPItemAnchor::~QCPItemAnchor()
7461 {
7462   // unregister as parent at children:
7463   foreach (QCPItemPosition *child, mChildrenX.toList())
7464   {
7465     if (child->parentAnchorX() == this)
7466       child->setParentAnchorX(0); // this acts back on this anchor and child removes itself from mChildrenX
7467   }
7468   foreach (QCPItemPosition *child, mChildrenY.toList())
7469   {
7470     if (child->parentAnchorY() == this)
7471       child->setParentAnchorY(0); // this acts back on this anchor and child removes itself from mChildrenY
7472   }
7473 }
7474
7475 /*!
7476   Returns the final absolute pixel position of the QCPItemAnchor on the QCustomPlot surface.
7477   
7478   The pixel information is internally retrieved via QCPAbstractItem::anchorPixelPosition of the
7479   parent item, QCPItemAnchor is just an intermediary.
7480 */
7481 QPointF QCPItemAnchor::pixelPoint() const
7482 {
7483   if (mParentItem)
7484   {
7485     if (mAnchorId > -1)
7486     {
7487       return mParentItem->anchorPixelPoint(mAnchorId);
7488     } else
7489     {
7490       qDebug() << Q_FUNC_INFO << "no valid anchor id set:" << mAnchorId;
7491       return QPointF();
7492     }
7493   } else
7494   {
7495     qDebug() << Q_FUNC_INFO << "no parent item set";
7496     return QPointF();
7497   }
7498 }
7499
7500 /*! \internal
7501
7502   Adds \a pos to the childX list of this anchor, which keeps track of which children use this
7503   anchor as parent anchor for the respective coordinate. This is necessary to notify the children
7504   prior to destruction of the anchor.
7505   
7506   Note that this function does not change the parent setting in \a pos.
7507 */
7508 void QCPItemAnchor::addChildX(QCPItemPosition *pos)
7509 {
7510   if (!mChildrenX.contains(pos))
7511     mChildrenX.insert(pos);
7512   else
7513     qDebug() << Q_FUNC_INFO << "provided pos is child already" << reinterpret_cast<quintptr>(pos);
7514 }
7515
7516 /*! \internal
7517
7518   Removes \a pos from the childX list of this anchor.
7519   
7520   Note that this function does not change the parent setting in \a pos.
7521 */
7522 void QCPItemAnchor::removeChildX(QCPItemPosition *pos)
7523 {
7524   if (!mChildrenX.remove(pos))
7525     qDebug() << Q_FUNC_INFO << "provided pos isn't child" << reinterpret_cast<quintptr>(pos);
7526 }
7527
7528 /*! \internal
7529
7530   Adds \a pos to the childY list of this anchor, which keeps track of which children use this
7531   anchor as parent anchor for the respective coordinate. This is necessary to notify the children
7532   prior to destruction of the anchor.
7533   
7534   Note that this function does not change the parent setting in \a pos.
7535 */
7536 void QCPItemAnchor::addChildY(QCPItemPosition *pos)
7537 {
7538   if (!mChildrenY.contains(pos))
7539     mChildrenY.insert(pos);
7540   else
7541     qDebug() << Q_FUNC_INFO << "provided pos is child already" << reinterpret_cast<quintptr>(pos);
7542 }
7543
7544 /*! \internal
7545
7546   Removes \a pos from the childY list of this anchor.
7547   
7548   Note that this function does not change the parent setting in \a pos.
7549 */
7550 void QCPItemAnchor::removeChildY(QCPItemPosition *pos)
7551 {
7552   if (!mChildrenY.remove(pos))
7553     qDebug() << Q_FUNC_INFO << "provided pos isn't child" << reinterpret_cast<quintptr>(pos);
7554 }
7555
7556
7557 ////////////////////////////////////////////////////////////////////////////////////////////////////
7558 //////////////////// QCPItemPosition
7559 ////////////////////////////////////////////////////////////////////////////////////////////////////
7560
7561 /*! \class QCPItemPosition
7562   \brief Manages the position of an item.
7563   
7564   Every item has at least one public QCPItemPosition member pointer which provides ways to position the
7565   item on the QCustomPlot surface. Some items have multiple positions, for example QCPItemRect has two:
7566   \a topLeft and \a bottomRight.
7567
7568   QCPItemPosition has a type (\ref PositionType) that can be set with \ref setType. This type
7569   defines how coordinates passed to \ref setCoords are to be interpreted, e.g. as absolute pixel
7570   coordinates, as plot coordinates of certain axes, etc. For more advanced plots it is also
7571   possible to assign different types per X/Y coordinate of the position (see \ref setTypeX, \ref
7572   setTypeY). This way an item could be positioned at a fixed pixel distance from the top in the Y
7573   direction, while following a plot coordinate in the X direction.
7574
7575   A QCPItemPosition may have a parent QCPItemAnchor, see \ref setParentAnchor. This way you can tie
7576   multiple items together. If the QCPItemPosition has a parent, its coordinates (\ref setCoords)
7577   are considered to be absolute pixels in the reference frame of the parent anchor, where (0, 0)
7578   means directly ontop of the parent anchor. For example, You could attach the \a start position of
7579   a QCPItemLine to the \a bottom anchor of a QCPItemText to make the starting point of the line
7580   always be centered under the text label, no matter where the text is moved to. For more advanced
7581   plots, it is possible to assign different parent anchors per X/Y coordinate of the position, see
7582   \ref setParentAnchorX, \ref setParentAnchorY. This way an item could follow another item in the X
7583   direction but stay at a fixed position in the Y direction. Or even follow item A in X, and item B
7584   in Y.
7585
7586   Note that every QCPItemPosition inherits from QCPItemAnchor and thus can itself be used as parent
7587   anchor for other positions.
7588
7589   To set the apparent pixel position on the QCustomPlot surface directly, use \ref setPixelPoint. This
7590   works no matter what type this QCPItemPosition is or what parent-child situation it is in, as \ref
7591   setPixelPoint transforms the coordinates appropriately, to make the position appear at the specified
7592   pixel values.
7593 */
7594
7595 /* start documentation of inline functions */
7596
7597 /*! \fn QCPItemPosition::PositionType *QCPItemPosition::type() const
7598   
7599   Returns the current position type.
7600   
7601   If different types were set for X and Y (\ref setTypeX, \ref setTypeY), this method returns the
7602   type of the X coordinate. In that case rather use \a typeX() and \a typeY().
7603   
7604   \see setType
7605 */
7606
7607 /*! \fn QCPItemAnchor *QCPItemPosition::parentAnchor() const
7608   
7609   Returns the current parent anchor.
7610   
7611   If different parent anchors were set for X and Y (\ref setParentAnchorX, \ref setParentAnchorY),
7612   this method returns the parent anchor of the Y coordinate. In that case rather use \a
7613   parentAnchorX() and \a parentAnchorY().
7614   
7615   \see setParentAnchor
7616 */
7617
7618 /* end documentation of inline functions */
7619
7620 /*!
7621   Creates a new QCPItemPosition. You shouldn't create QCPItemPosition instances directly, even if
7622   you want to make a new item subclass. Use \ref QCPAbstractItem::createPosition instead, as
7623   explained in the subclassing section of the QCPAbstractItem documentation.
7624 */
7625 QCPItemPosition::QCPItemPosition(QCustomPlot *parentPlot, QCPAbstractItem *parentItem, const QString name) :
7626   QCPItemAnchor(parentPlot, parentItem, name),
7627   mPositionTypeX(ptAbsolute),
7628   mPositionTypeY(ptAbsolute),
7629   mKey(0),
7630   mValue(0),
7631   mParentAnchorX(0),
7632   mParentAnchorY(0)
7633 {
7634 }
7635
7636 QCPItemPosition::~QCPItemPosition()
7637 {
7638   // unregister as parent at children:
7639   // Note: this is done in ~QCPItemAnchor again, but it's important QCPItemPosition does it itself, because only then
7640   //       the setParentAnchor(0) call the correct QCPItemPosition::pixelPoint function instead of QCPItemAnchor::pixelPoint
7641   foreach (QCPItemPosition *child, mChildrenX.toList())
7642   {
7643     if (child->parentAnchorX() == this)
7644       child->setParentAnchorX(0); // this acts back on this anchor and child removes itself from mChildrenX
7645   }
7646   foreach (QCPItemPosition *child, mChildrenY.toList())
7647   {
7648     if (child->parentAnchorY() == this)
7649       child->setParentAnchorY(0); // this acts back on this anchor and child removes itself from mChildrenY
7650   }
7651   // unregister as child in parent:
7652   if (mParentAnchorX)
7653     mParentAnchorX->removeChildX(this);
7654   if (mParentAnchorY)
7655     mParentAnchorY->removeChildY(this);
7656 }
7657
7658 /* can't make this a header inline function, because QPointer breaks with forward declared types, see QTBUG-29588 */
7659 QCPAxisRect *QCPItemPosition::axisRect() const
7660 {
7661   return mAxisRect.data();
7662 }
7663
7664 /*!
7665   Sets the type of the position. The type defines how the coordinates passed to \ref setCoords
7666   should be handled and how the QCPItemPosition should behave in the plot.
7667   
7668   The possible values for \a type can be separated in two main categories:
7669
7670   \li The position is regarded as a point in plot coordinates. This corresponds to \ref ptPlotCoords
7671   and requires two axes that define the plot coordinate system. They can be specified with \ref setAxes.
7672   By default, the QCustomPlot's x- and yAxis are used.
7673   
7674   \li The position is fixed on the QCustomPlot surface, i.e. independent of axis ranges. This
7675   corresponds to all other types, i.e. \ref ptAbsolute, \ref ptViewportRatio and \ref
7676   ptAxisRectRatio. They differ only in the way the absolute position is described, see the
7677   documentation of \ref PositionType for details. For \ref ptAxisRectRatio, note that you can specify
7678   the axis rect with \ref setAxisRect. By default this is set to the main axis rect.
7679   
7680   Note that the position type \ref ptPlotCoords is only available (and sensible) when the position
7681   has no parent anchor (\ref setParentAnchor).
7682   
7683   If the type is changed, the apparent pixel position on the plot is preserved. This means
7684   the coordinates as retrieved with coords() and set with \ref setCoords may change in the process.
7685   
7686   This method sets the type for both X and Y directions. It is also possible to set different types
7687   for X and Y, see \ref setTypeX, \ref setTypeY.
7688 */
7689 void QCPItemPosition::setType(QCPItemPosition::PositionType type)
7690 {
7691   setTypeX(type);
7692   setTypeY(type);
7693 }
7694
7695 /*!
7696   This method sets the position type of the X coordinate to \a type.
7697   
7698   For a detailed description of what a position type is, see the documentation of \ref setType.
7699   
7700   \see setType, setTypeY
7701 */
7702 void QCPItemPosition::setTypeX(QCPItemPosition::PositionType type)
7703 {
7704   if (mPositionTypeX != type)
7705   {
7706     // if switching from or to coordinate type that isn't valid (e.g. because axes or axis rect
7707     // were deleted), don't try to recover the pixelPoint() because it would output a qDebug warning.
7708     bool retainPixelPosition = true;
7709     if ((mPositionTypeX == ptPlotCoords || type == ptPlotCoords) && (!mKeyAxis || !mValueAxis))
7710       retainPixelPosition = false;
7711     if ((mPositionTypeX == ptAxisRectRatio || type == ptAxisRectRatio) && (!mAxisRect))
7712       retainPixelPosition = false;
7713     
7714     QPointF pixel;
7715     if (retainPixelPosition)
7716       pixel = pixelPoint();
7717     
7718     mPositionTypeX = type;
7719     
7720     if (retainPixelPosition)
7721       setPixelPoint(pixel);
7722   }
7723 }
7724
7725 /*!
7726   This method sets the position type of the Y coordinate to \a type.
7727   
7728   For a detailed description of what a position type is, see the documentation of \ref setType.
7729   
7730   \see setType, setTypeX
7731 */
7732 void QCPItemPosition::setTypeY(QCPItemPosition::PositionType type)
7733 {
7734   if (mPositionTypeY != type)
7735   {
7736     // if switching from or to coordinate type that isn't valid (e.g. because axes or axis rect
7737     // were deleted), don't try to recover the pixelPoint() because it would output a qDebug warning.
7738     bool retainPixelPosition = true;
7739     if ((mPositionTypeY == ptPlotCoords || type == ptPlotCoords) && (!mKeyAxis || !mValueAxis))
7740       retainPixelPosition = false;
7741     if ((mPositionTypeY == ptAxisRectRatio || type == ptAxisRectRatio) && (!mAxisRect))
7742       retainPixelPosition = false;
7743     
7744     QPointF pixel;
7745     if (retainPixelPosition)
7746       pixel = pixelPoint();
7747     
7748     mPositionTypeY = type;
7749     
7750     if (retainPixelPosition)
7751       setPixelPoint(pixel);
7752   }
7753 }
7754
7755 /*!
7756   Sets the parent of this QCPItemPosition to \a parentAnchor. This means the position will now
7757   follow any position changes of the anchor. The local coordinate system of positions with a parent
7758   anchor always is absolute pixels, with (0, 0) being exactly on top of the parent anchor. (Hence
7759   the type shouldn't be set to \ref ptPlotCoords for positions with parent anchors.)
7760   
7761   if \a keepPixelPosition is true, the current pixel position of the QCPItemPosition is preserved
7762   during reparenting. If it's set to false, the coordinates are set to (0, 0), i.e. the position
7763   will be exactly on top of the parent anchor.
7764   
7765   To remove this QCPItemPosition from any parent anchor, set \a parentAnchor to 0.
7766   
7767   If the QCPItemPosition previously had no parent and the type is \ref ptPlotCoords, the type is
7768   set to \ref ptAbsolute, to keep the position in a valid state.
7769   
7770   This method sets the parent anchor for both X and Y directions. It is also possible to set
7771   different parents for X and Y, see \ref setParentAnchorX, \ref setParentAnchorY.
7772 */
7773 bool QCPItemPosition::setParentAnchor(QCPItemAnchor *parentAnchor, bool keepPixelPosition)
7774 {
7775   bool successX = setParentAnchorX(parentAnchor, keepPixelPosition);
7776   bool successY = setParentAnchorY(parentAnchor, keepPixelPosition);
7777   return successX && successY;
7778 }
7779
7780 /*!
7781   This method sets the parent anchor of the X coordinate to \a parentAnchor.
7782   
7783   For a detailed description of what a parent anchor is, see the documentation of \ref setParentAnchor.
7784   
7785   \see setParentAnchor, setParentAnchorY
7786 */
7787 bool QCPItemPosition::setParentAnchorX(QCPItemAnchor *parentAnchor, bool keepPixelPosition)
7788 {
7789   // make sure self is not assigned as parent:
7790   if (parentAnchor == this)
7791   {
7792     qDebug() << Q_FUNC_INFO << "can't set self as parent anchor" << reinterpret_cast<quintptr>(parentAnchor);
7793     return false;
7794   }
7795   // make sure no recursive parent-child-relationships are created:
7796   QCPItemAnchor *currentParent = parentAnchor;
7797   while (currentParent)
7798   {
7799     if (QCPItemPosition *currentParentPos = currentParent->toQCPItemPosition())
7800     {
7801       // is a QCPItemPosition, might have further parent, so keep iterating
7802       if (currentParentPos == this)
7803       {
7804         qDebug() << Q_FUNC_INFO << "can't create recursive parent-child-relationship" << reinterpret_cast<quintptr>(parentAnchor);
7805         return false;
7806       }
7807       currentParent = currentParentPos->parentAnchorX();
7808     } else
7809     {
7810       // is a QCPItemAnchor, can't have further parent. Now make sure the parent items aren't the
7811       // same, to prevent a position being child of an anchor which itself depends on the position,
7812       // because they're both on the same item:
7813       if (currentParent->mParentItem == mParentItem)
7814       {
7815         qDebug() << Q_FUNC_INFO << "can't set parent to be an anchor which itself depends on this position" << reinterpret_cast<quintptr>(parentAnchor);
7816         return false;
7817       }
7818       break;
7819     }
7820   }
7821   
7822   // if previously no parent set and PosType is still ptPlotCoords, set to ptAbsolute:
7823   if (!mParentAnchorX && mPositionTypeX == ptPlotCoords)
7824     setTypeX(ptAbsolute);
7825   
7826   // save pixel position:
7827   QPointF pixelP;
7828   if (keepPixelPosition)
7829     pixelP = pixelPoint();
7830   // unregister at current parent anchor:
7831   if (mParentAnchorX)
7832     mParentAnchorX->removeChildX(this);
7833   // register at new parent anchor:
7834   if (parentAnchor)
7835     parentAnchor->addChildX(this);
7836   mParentAnchorX = parentAnchor;
7837   // restore pixel position under new parent:
7838   if (keepPixelPosition)
7839     setPixelPoint(pixelP);
7840   else
7841     setCoords(0, coords().y());
7842   return true;
7843 }
7844
7845 /*!
7846   This method sets the parent anchor of the Y coordinate to \a parentAnchor.
7847   
7848   For a detailed description of what a parent anchor is, see the documentation of \ref setParentAnchor.
7849   
7850   \see setParentAnchor, setParentAnchorX
7851 */
7852 bool QCPItemPosition::setParentAnchorY(QCPItemAnchor *parentAnchor, bool keepPixelPosition)
7853 {
7854   // make sure self is not assigned as parent:
7855   if (parentAnchor == this)
7856   {
7857     qDebug() << Q_FUNC_INFO << "can't set self as parent anchor" << reinterpret_cast<quintptr>(parentAnchor);
7858     return false;
7859   }
7860   // make sure no recursive parent-child-relationships are created:
7861   QCPItemAnchor *currentParent = parentAnchor;
7862   while (currentParent)
7863   {
7864     if (QCPItemPosition *currentParentPos = currentParent->toQCPItemPosition())
7865     {
7866       // is a QCPItemPosition, might have further parent, so keep iterating
7867       if (currentParentPos == this)
7868       {
7869         qDebug() << Q_FUNC_INFO << "can't create recursive parent-child-relationship" << reinterpret_cast<quintptr>(parentAnchor);
7870         return false;
7871       }
7872       currentParent = currentParentPos->parentAnchorY();
7873     } else
7874     {
7875       // is a QCPItemAnchor, can't have further parent. Now make sure the parent items aren't the
7876       // same, to prevent a position being child of an anchor which itself depends on the position,
7877       // because they're both on the same item:
7878       if (currentParent->mParentItem == mParentItem)
7879       {
7880         qDebug() << Q_FUNC_INFO << "can't set parent to be an anchor which itself depends on this position" << reinterpret_cast<quintptr>(parentAnchor);
7881         return false;
7882       }
7883       break;
7884     }
7885   }
7886   
7887   // if previously no parent set and PosType is still ptPlotCoords, set to ptAbsolute:
7888   if (!mParentAnchorY && mPositionTypeY == ptPlotCoords)
7889     setTypeY(ptAbsolute);
7890   
7891   // save pixel position:
7892   QPointF pixelP;
7893   if (keepPixelPosition)
7894     pixelP = pixelPoint();
7895   // unregister at current parent anchor:
7896   if (mParentAnchorY)
7897     mParentAnchorY->removeChildY(this);
7898   // register at new parent anchor:
7899   if (parentAnchor)
7900     parentAnchor->addChildY(this);
7901   mParentAnchorY = parentAnchor;
7902   // restore pixel position under new parent:
7903   if (keepPixelPosition)
7904     setPixelPoint(pixelP);
7905   else
7906     setCoords(coords().x(), 0);
7907   return true;
7908 }
7909
7910 /*!
7911   Sets the coordinates of this QCPItemPosition. What the coordinates mean, is defined by the type
7912   (\ref setType, \ref setTypeX, \ref setTypeY).
7913   
7914   For example, if the type is \ref ptAbsolute, \a key and \a value mean the x and y pixel position
7915   on the QCustomPlot surface. In that case the origin (0, 0) is in the top left corner of the
7916   QCustomPlot viewport. If the type is \ref ptPlotCoords, \a key and \a value mean a point in the
7917   plot coordinate system defined by the axes set by \ref setAxes. By default those are the
7918   QCustomPlot's xAxis and yAxis. See the documentation of \ref setType for other available
7919   coordinate types and their meaning.
7920   
7921   If different types were configured for X and Y (\ref setTypeX, \ref setTypeY), \a key and \a
7922   value must also be provided in the different coordinate systems. Here, the X type refers to \a
7923   key, and the Y type refers to \a value.
7924
7925   \see setPixelPoint
7926 */
7927 void QCPItemPosition::setCoords(double key, double value)
7928 {
7929   mKey = key;
7930   mValue = value;
7931 }
7932
7933 /*! \overload
7934
7935   Sets the coordinates as a QPointF \a pos where pos.x has the meaning of \a key and pos.y the
7936   meaning of \a value of the \ref setCoords(double key, double value) method.
7937 */
7938 void QCPItemPosition::setCoords(const QPointF &pos)
7939 {
7940   setCoords(pos.x(), pos.y());
7941 }
7942
7943 /*!
7944   Returns the final absolute pixel position of the QCPItemPosition on the QCustomPlot surface. It
7945   includes all effects of type (\ref setType) and possible parent anchors (\ref setParentAnchor).
7946
7947   \see setPixelPoint
7948 */
7949 QPointF QCPItemPosition::pixelPoint() const
7950 {
7951   QPointF result;
7952   
7953   // determine X:
7954   switch (mPositionTypeX)
7955   {
7956     case ptAbsolute:
7957     {
7958       result.rx() = mKey;
7959       if (mParentAnchorX)
7960         result.rx() += mParentAnchorX->pixelPoint().x();
7961       break;
7962     }
7963     case ptViewportRatio:
7964     {
7965       result.rx() = mKey*mParentPlot->viewport().width();
7966       if (mParentAnchorX)
7967         result.rx() += mParentAnchorX->pixelPoint().x();
7968       else
7969         result.rx() += mParentPlot->viewport().left();
7970       break;
7971     }
7972     case ptAxisRectRatio:
7973     {
7974       if (mAxisRect)
7975       {
7976         result.rx() = mKey*mAxisRect.data()->width();
7977         if (mParentAnchorX)
7978           result.rx() += mParentAnchorX->pixelPoint().x();
7979         else
7980           result.rx() += mAxisRect.data()->left();
7981       } else
7982         qDebug() << Q_FUNC_INFO << "Item position type x is ptAxisRectRatio, but no axis rect was defined";
7983       break;
7984     }
7985     case ptPlotCoords:
7986     {
7987       if (mKeyAxis && mKeyAxis.data()->orientation() == Qt::Horizontal)
7988         result.rx() = mKeyAxis.data()->coordToPixel(mKey);
7989       else if (mValueAxis && mValueAxis.data()->orientation() == Qt::Horizontal)
7990         result.rx() = mValueAxis.data()->coordToPixel(mValue);
7991       else
7992         qDebug() << Q_FUNC_INFO << "Item position type x is ptPlotCoords, but no axes were defined";
7993       break;
7994     }
7995   }
7996   
7997   // determine Y:
7998   switch (mPositionTypeY)
7999   {
8000     case ptAbsolute:
8001     {
8002       result.ry() = mValue;
8003       if (mParentAnchorY)
8004         result.ry() += mParentAnchorY->pixelPoint().y();
8005       break;
8006     }
8007     case ptViewportRatio:
8008     {
8009       result.ry() = mValue*mParentPlot->viewport().height();
8010       if (mParentAnchorY)
8011         result.ry() += mParentAnchorY->pixelPoint().y();
8012       else
8013         result.ry() += mParentPlot->viewport().top();
8014       break;
8015     }
8016     case ptAxisRectRatio:
8017     {
8018       if (mAxisRect)
8019       {
8020         result.ry() = mValue*mAxisRect.data()->height();
8021         if (mParentAnchorY)
8022           result.ry() += mParentAnchorY->pixelPoint().y();
8023         else
8024           result.ry() += mAxisRect.data()->top();
8025       } else
8026         qDebug() << Q_FUNC_INFO << "Item position type y is ptAxisRectRatio, but no axis rect was defined";
8027       break;
8028     }
8029     case ptPlotCoords:
8030     {
8031       if (mKeyAxis && mKeyAxis.data()->orientation() == Qt::Vertical)
8032         result.ry() = mKeyAxis.data()->coordToPixel(mKey);
8033       else if (mValueAxis && mValueAxis.data()->orientation() == Qt::Vertical)
8034         result.ry() = mValueAxis.data()->coordToPixel(mValue);
8035       else
8036         qDebug() << Q_FUNC_INFO << "Item position type y is ptPlotCoords, but no axes were defined";
8037       break;
8038     }
8039   }
8040   
8041   return result;
8042 }
8043
8044 /*!
8045   When \ref setType is \ref ptPlotCoords, this function may be used to specify the axes the
8046   coordinates set with \ref setCoords relate to. By default they are set to the initial xAxis and
8047   yAxis of the QCustomPlot.
8048 */
8049 void QCPItemPosition::setAxes(QCPAxis *keyAxis, QCPAxis *valueAxis)
8050 {
8051   mKeyAxis = keyAxis;
8052   mValueAxis = valueAxis;
8053 }
8054
8055 /*!
8056   When \ref setType is \ref ptAxisRectRatio, this function may be used to specify the axis rect the
8057   coordinates set with \ref setCoords relate to. By default this is set to the main axis rect of
8058   the QCustomPlot.
8059 */
8060 void QCPItemPosition::setAxisRect(QCPAxisRect *axisRect)
8061 {
8062   mAxisRect = axisRect;
8063 }
8064
8065 /*!
8066   Sets the apparent pixel position. This works no matter what type (\ref setType) this
8067   QCPItemPosition is or what parent-child situation it is in, as coordinates are transformed
8068   appropriately, to make the position finally appear at the specified pixel values.
8069
8070   Only if the type is \ref ptAbsolute and no parent anchor is set, this function's effect is
8071   identical to that of \ref setCoords.
8072
8073   \see pixelPoint, setCoords
8074 */
8075 void QCPItemPosition::setPixelPoint(const QPointF &pixelPoint)
8076 {
8077   double x = pixelPoint.x();
8078   double y = pixelPoint.y();
8079   
8080   switch (mPositionTypeX)
8081   {
8082     case ptAbsolute:
8083     {
8084       if (mParentAnchorX)
8085         x -= mParentAnchorX->pixelPoint().x();
8086       break;
8087     }
8088     case ptViewportRatio:
8089     {
8090       if (mParentAnchorX)
8091         x -= mParentAnchorX->pixelPoint().x();
8092       else
8093         x -= mParentPlot->viewport().left();
8094       x /= (double)mParentPlot->viewport().width();
8095       break;
8096     }
8097     case ptAxisRectRatio:
8098     {
8099       if (mAxisRect)
8100       {
8101         if (mParentAnchorX)
8102           x -= mParentAnchorX->pixelPoint().x();
8103         else
8104           x -= mAxisRect.data()->left();
8105         x /= (double)mAxisRect.data()->width();
8106       } else
8107         qDebug() << Q_FUNC_INFO << "Item position type x is ptAxisRectRatio, but no axis rect was defined";
8108       break;
8109     }
8110     case ptPlotCoords:
8111     {
8112       if (mKeyAxis && mKeyAxis.data()->orientation() == Qt::Horizontal)
8113         x = mKeyAxis.data()->pixelToCoord(x);
8114       else if (mValueAxis && mValueAxis.data()->orientation() == Qt::Horizontal)
8115         y = mValueAxis.data()->pixelToCoord(x);
8116       else
8117         qDebug() << Q_FUNC_INFO << "Item position type x is ptPlotCoords, but no axes were defined";
8118       break;
8119     }
8120   }
8121   
8122   switch (mPositionTypeY)
8123   {
8124     case ptAbsolute:
8125     {
8126       if (mParentAnchorY)
8127         y -= mParentAnchorY->pixelPoint().y();
8128       break;
8129     }
8130     case ptViewportRatio:
8131     {
8132       if (mParentAnchorY)
8133         y -= mParentAnchorY->pixelPoint().y();
8134       else
8135         y -= mParentPlot->viewport().top();
8136       y /= (double)mParentPlot->viewport().height();
8137       break;
8138     }
8139     case ptAxisRectRatio:
8140     {
8141       if (mAxisRect)
8142       {
8143         if (mParentAnchorY)
8144           y -= mParentAnchorY->pixelPoint().y();
8145         else
8146           y -= mAxisRect.data()->top();
8147         y /= (double)mAxisRect.data()->height();
8148       } else
8149         qDebug() << Q_FUNC_INFO << "Item position type y is ptAxisRectRatio, but no axis rect was defined";
8150       break;
8151     }
8152     case ptPlotCoords:
8153     {
8154       if (mKeyAxis && mKeyAxis.data()->orientation() == Qt::Vertical)
8155         x = mKeyAxis.data()->pixelToCoord(y);
8156       else if (mValueAxis && mValueAxis.data()->orientation() == Qt::Vertical)
8157         y = mValueAxis.data()->pixelToCoord(y);
8158       else
8159         qDebug() << Q_FUNC_INFO << "Item position type y is ptPlotCoords, but no axes were defined";
8160       break;
8161     }
8162   }
8163   
8164   setCoords(x, y);
8165 }
8166
8167
8168 ////////////////////////////////////////////////////////////////////////////////////////////////////
8169 //////////////////// QCPAbstractItem
8170 ////////////////////////////////////////////////////////////////////////////////////////////////////
8171
8172 /*! \class QCPAbstractItem
8173   \brief The abstract base class for all items in a plot.
8174   
8175   In QCustomPlot, items are supplemental graphical elements that are neither plottables
8176   (QCPAbstractPlottable) nor axes (QCPAxis). While plottables are always tied to two axes and thus
8177   plot coordinates, items can also be placed in absolute coordinates independent of any axes. Each
8178   specific item has at least one QCPItemPosition member which controls the positioning. Some items
8179   are defined by more than one coordinate and thus have two or more QCPItemPosition members (For
8180   example, QCPItemRect has \a topLeft and \a bottomRight).
8181   
8182   This abstract base class defines a very basic interface like visibility and clipping. Since this
8183   class is abstract, it can't be instantiated. Use one of the subclasses or create a subclass
8184   yourself to create new items.
8185   
8186   The built-in items are:
8187   <table>
8188   <tr><td>QCPItemLine</td><td>A line defined by a start and an end point. May have different ending styles on each side (e.g. arrows).</td></tr>
8189   <tr><td>QCPItemStraightLine</td><td>A straight line defined by a start and a direction point. Unlike QCPItemLine, the straight line is infinitely long and has no endings.</td></tr>
8190   <tr><td>QCPItemCurve</td><td>A curve defined by start, end and two intermediate control points. May have different ending styles on each side (e.g. arrows).</td></tr>
8191   <tr><td>QCPItemRect</td><td>A rectangle</td></tr>
8192   <tr><td>QCPItemEllipse</td><td>An ellipse</td></tr>
8193   <tr><td>QCPItemPixmap</td><td>An arbitrary pixmap</td></tr>
8194   <tr><td>QCPItemText</td><td>A text label</td></tr>
8195   <tr><td>QCPItemBracket</td><td>A bracket which may be used to reference/highlight certain parts in the plot.</td></tr>
8196   <tr><td>QCPItemTracer</td><td>An item that can be attached to a QCPGraph and sticks to its data points, given a key coordinate.</td></tr>
8197   </table>
8198   
8199   \section items-clipping Clipping
8200
8201   Items are by default clipped to the main axis rect (they are only visible inside the axis rect).
8202   To make an item visible outside that axis rect, disable clipping via \ref setClipToAxisRect
8203   "setClipToAxisRect(false)".
8204
8205   On the other hand if you want the item to be clipped to a different axis rect, specify it via
8206   \ref setClipAxisRect. This clipAxisRect property of an item is only used for clipping behaviour, and
8207   in principle is independent of the coordinate axes the item might be tied to via its position
8208   members (\ref QCPItemPosition::setAxes). However, it is common that the axis rect for clipping
8209   also contains the axes used for the item positions.
8210   
8211   \section items-using Using items
8212   
8213   First you instantiate the item you want to use and add it to the plot:
8214   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpitemline-creation-1
8215   by default, the positions of the item are bound to the x- and y-Axis of the plot. So we can just
8216   set the plot coordinates where the line should start/end:
8217   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpitemline-creation-2
8218   If we don't want the line to be positioned in plot coordinates but a different coordinate system,
8219   e.g. absolute pixel positions on the QCustomPlot surface, we need to change the position type like this:
8220   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpitemline-creation-3
8221   Then we can set the coordinates, this time in pixels:
8222   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpitemline-creation-4
8223   and make the line visible on the entire QCustomPlot, by disabling clipping to the axis rect:
8224   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpitemline-creation-5
8225   
8226   For more advanced plots, it is even possible to set different types and parent anchors per X/Y
8227   coordinate of an item position, using for example \ref QCPItemPosition::setTypeX or \ref
8228   QCPItemPosition::setParentAnchorX. For details, see the documentation of \ref QCPItemPosition.
8229   
8230   \section items-subclassing Creating own items
8231   
8232   To create an own item, you implement a subclass of QCPAbstractItem. These are the pure
8233   virtual functions, you must implement:
8234   \li \ref selectTest
8235   \li \ref draw
8236   
8237   See the documentation of those functions for what they need to do.
8238   
8239   \subsection items-positioning Allowing the item to be positioned
8240   
8241   As mentioned, item positions are represented by QCPItemPosition members. Let's assume the new item shall
8242   have only one point as its position (as opposed to two like a rect or multiple like a polygon). You then add
8243   a public member of type QCPItemPosition like so:
8244   
8245   \code QCPItemPosition * const myPosition;\endcode
8246   
8247   the const makes sure the pointer itself can't be modified from the user of your new item (the QCPItemPosition
8248   instance it points to, can be modified, of course).
8249   The initialization of this pointer is made easy with the \ref createPosition function. Just assign
8250   the return value of this function to each QCPItemPosition in the constructor of your item. \ref createPosition
8251   takes a string which is the name of the position, typically this is identical to the variable name.
8252   For example, the constructor of QCPItemExample could look like this:
8253   
8254   \code
8255   QCPItemExample::QCPItemExample(QCustomPlot *parentPlot) :
8256     QCPAbstractItem(parentPlot),
8257     myPosition(createPosition("myPosition"))
8258   {
8259     // other constructor code
8260   }
8261   \endcode
8262   
8263   \subsection items-drawing The draw function
8264   
8265   To give your item a visual representation, reimplement the \ref draw function and use the passed
8266   QCPPainter to draw the item. You can retrieve the item position in pixel coordinates from the
8267   position member(s) via \ref QCPItemPosition::pixelPoint.
8268
8269   To optimize performance you should calculate a bounding rect first (don't forget to take the pen
8270   width into account), check whether it intersects the \ref clipRect, and only draw the item at all
8271   if this is the case.
8272   
8273   \subsection items-selection The selectTest function
8274   
8275   Your implementation of the \ref selectTest function may use the helpers \ref distSqrToLine and
8276   \ref rectSelectTest. With these, the implementation of the selection test becomes significantly
8277   simpler for most items. See the documentation of \ref selectTest for what the function parameters
8278   mean and what the function should return.
8279   
8280   \subsection anchors Providing anchors
8281   
8282   Providing anchors (QCPItemAnchor) starts off like adding a position. First you create a public
8283   member, e.g.
8284   
8285   \code QCPItemAnchor * const bottom;\endcode
8286
8287   and create it in the constructor with the \ref createAnchor function, assigning it a name and an
8288   anchor id (an integer enumerating all anchors on the item, you may create an own enum for this).
8289   Since anchors can be placed anywhere, relative to the item's position(s), your item needs to
8290   provide the position of every anchor with the reimplementation of the \ref anchorPixelPoint(int
8291   anchorId) function.
8292   
8293   In essence the QCPItemAnchor is merely an intermediary that itself asks your item for the pixel
8294   position when anything attached to the anchor needs to know the coordinates.
8295 */
8296
8297 /* start of documentation of inline functions */
8298
8299 /*! \fn QList<QCPItemPosition*> QCPAbstractItem::positions() const
8300   
8301   Returns all positions of the item in a list.
8302   
8303   \see anchors, position
8304 */
8305
8306 /*! \fn QList<QCPItemAnchor*> QCPAbstractItem::anchors() const
8307   
8308   Returns all anchors of the item in a list. Note that since a position (QCPItemPosition) is always
8309   also an anchor, the list will also contain the positions of this item.
8310   
8311   \see positions, anchor
8312 */
8313
8314 /* end of documentation of inline functions */
8315 /* start documentation of pure virtual functions */
8316
8317 /*! \fn void QCPAbstractItem::draw(QCPPainter *painter) = 0
8318   \internal
8319   
8320   Draws this item with the provided \a painter.
8321   
8322   The cliprect of the provided painter is set to the rect returned by \ref clipRect before this
8323   function is called. The clipRect depends on the clipping settings defined by \ref
8324   setClipToAxisRect and \ref setClipAxisRect.
8325 */
8326
8327 /* end documentation of pure virtual functions */
8328 /* start documentation of signals */
8329
8330 /*! \fn void QCPAbstractItem::selectionChanged(bool selected)
8331   This signal is emitted when the selection state of this item has changed, either by user interaction
8332   or by a direct call to \ref setSelected.
8333 */
8334
8335 /* end documentation of signals */
8336
8337 /*!
8338   Base class constructor which initializes base class members.
8339 */
8340 QCPAbstractItem::QCPAbstractItem(QCustomPlot *parentPlot) :
8341   QCPLayerable(parentPlot),
8342   mClipToAxisRect(false),
8343   mSelectable(true),
8344   mSelected(false)
8345 {
8346   QList<QCPAxisRect*> rects = parentPlot->axisRects();
8347   if (rects.size() > 0)
8348   {
8349     setClipToAxisRect(true);
8350     setClipAxisRect(rects.first());
8351   }
8352 }
8353
8354 QCPAbstractItem::~QCPAbstractItem()
8355 {
8356   // don't delete mPositions because every position is also an anchor and thus in mAnchors
8357   qDeleteAll(mAnchors);
8358 }
8359
8360 /* can't make this a header inline function, because QPointer breaks with forward declared types, see QTBUG-29588 */
8361 QCPAxisRect *QCPAbstractItem::clipAxisRect() const
8362 {
8363   return mClipAxisRect.data();
8364 }
8365
8366 /*!
8367   Sets whether the item shall be clipped to an axis rect or whether it shall be visible on the
8368   entire QCustomPlot. The axis rect can be set with \ref setClipAxisRect.
8369   
8370   \see setClipAxisRect
8371 */
8372 void QCPAbstractItem::setClipToAxisRect(bool clip)
8373 {
8374   mClipToAxisRect = clip;
8375   if (mClipToAxisRect)
8376     setParentLayerable(mClipAxisRect.data());
8377 }
8378
8379 /*!
8380   Sets the clip axis rect. It defines the rect that will be used to clip the item when \ref
8381   setClipToAxisRect is set to true.
8382   
8383   \see setClipToAxisRect
8384 */
8385 void QCPAbstractItem::setClipAxisRect(QCPAxisRect *rect)
8386 {
8387   mClipAxisRect = rect;
8388   if (mClipToAxisRect)
8389     setParentLayerable(mClipAxisRect.data());
8390 }
8391
8392 /*!
8393   Sets whether the user can (de-)select this item by clicking on the QCustomPlot surface.
8394   (When \ref QCustomPlot::setInteractions contains QCustomPlot::iSelectItems.)
8395   
8396   However, even when \a selectable was set to false, it is possible to set the selection manually,
8397   by calling \ref setSelected.
8398   
8399   \see QCustomPlot::setInteractions, setSelected
8400 */
8401 void QCPAbstractItem::setSelectable(bool selectable)
8402 {
8403   if (mSelectable != selectable)
8404   {
8405     mSelectable = selectable;
8406     emit selectableChanged(mSelectable);
8407   }
8408 }
8409
8410 /*!
8411   Sets whether this item is selected or not. When selected, it might use a different visual
8412   appearance (e.g. pen and brush), this depends on the specific item though.
8413
8414   The entire selection mechanism for items is handled automatically when \ref
8415   QCustomPlot::setInteractions contains QCustomPlot::iSelectItems. You only need to call this
8416   function when you wish to change the selection state manually.
8417   
8418   This function can change the selection state even when \ref setSelectable was set to false.
8419   
8420   emits the \ref selectionChanged signal when \a selected is different from the previous selection state.
8421   
8422   \see setSelectable, selectTest
8423 */
8424 void QCPAbstractItem::setSelected(bool selected)
8425 {
8426   if (mSelected != selected)
8427   {
8428     mSelected = selected;
8429     emit selectionChanged(mSelected);
8430   }
8431 }
8432
8433 /*!
8434   Returns the QCPItemPosition with the specified \a name. If this item doesn't have a position by
8435   that name, returns 0.
8436   
8437   This function provides an alternative way to access item positions. Normally, you access
8438   positions direcly by their member pointers (which typically have the same variable name as \a
8439   name).
8440   
8441   \see positions, anchor
8442 */
8443 QCPItemPosition *QCPAbstractItem::position(const QString &name) const
8444 {
8445   for (int i=0; i<mPositions.size(); ++i)
8446   {
8447     if (mPositions.at(i)->name() == name)
8448       return mPositions.at(i);
8449   }
8450   qDebug() << Q_FUNC_INFO << "position with name not found:" << name;
8451   return 0;
8452 }
8453
8454 /*!
8455   Returns the QCPItemAnchor with the specified \a name. If this item doesn't have an anchor by
8456   that name, returns 0.
8457   
8458   This function provides an alternative way to access item anchors. Normally, you access
8459   anchors direcly by their member pointers (which typically have the same variable name as \a
8460   name).
8461   
8462   \see anchors, position
8463 */
8464 QCPItemAnchor *QCPAbstractItem::anchor(const QString &name) const
8465 {
8466   for (int i=0; i<mAnchors.size(); ++i)
8467   {
8468     if (mAnchors.at(i)->name() == name)
8469       return mAnchors.at(i);
8470   }
8471   qDebug() << Q_FUNC_INFO << "anchor with name not found:" << name;
8472   return 0;
8473 }
8474
8475 /*!
8476   Returns whether this item has an anchor with the specified \a name.
8477   
8478   Note that you can check for positions with this function, too. This is because every position is
8479   also an anchor (QCPItemPosition inherits from QCPItemAnchor).
8480   
8481   \see anchor, position
8482 */
8483 bool QCPAbstractItem::hasAnchor(const QString &name) const
8484 {
8485   for (int i=0; i<mAnchors.size(); ++i)
8486   {
8487     if (mAnchors.at(i)->name() == name)
8488       return true;
8489   }
8490   return false;
8491 }
8492
8493 /*! \internal
8494   
8495   Returns the rect the visual representation of this item is clipped to. This depends on the
8496   current setting of \ref setClipToAxisRect as well as the axis rect set with \ref setClipAxisRect.
8497   
8498   If the item is not clipped to an axis rect, the \ref QCustomPlot::viewport rect is returned.
8499   
8500   \see draw
8501 */
8502 QRect QCPAbstractItem::clipRect() const
8503 {
8504   if (mClipToAxisRect && mClipAxisRect)
8505     return mClipAxisRect.data()->rect();
8506   else
8507     return mParentPlot->viewport();
8508 }
8509
8510 /*! \internal
8511
8512   A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter
8513   before drawing item lines.
8514
8515   This is the antialiasing state the painter passed to the \ref draw method is in by default.
8516   
8517   This function takes into account the local setting of the antialiasing flag as well as the
8518   overrides set with \ref QCustomPlot::setAntialiasedElements and \ref
8519   QCustomPlot::setNotAntialiasedElements.
8520   
8521   \see setAntialiased
8522 */
8523 void QCPAbstractItem::applyDefaultAntialiasingHint(QCPPainter *painter) const
8524 {
8525   applyAntialiasingHint(painter, mAntialiased, QCP::aeItems);
8526 }
8527
8528 /*! \internal
8529
8530   Finds the shortest squared distance of \a point to the line segment defined by \a start and \a
8531   end.
8532   
8533   This function may be used to help with the implementation of the \ref selectTest function for
8534   specific items.
8535   
8536   \note This function is identical to QCPAbstractPlottable::distSqrToLine
8537   
8538   \see rectSelectTest
8539 */
8540 double QCPAbstractItem::distSqrToLine(const QPointF &start, const QPointF &end, const QPointF &point) const
8541 {
8542   QVector2D a(start);
8543   QVector2D b(end);
8544   QVector2D p(point);
8545   QVector2D v(b-a);
8546   
8547   double vLengthSqr = v.lengthSquared();
8548   if (!qFuzzyIsNull(vLengthSqr))
8549   {
8550     double mu = QVector2D::dotProduct(p-a, v)/vLengthSqr;
8551     if (mu < 0)
8552       return (a-p).lengthSquared();
8553     else if (mu > 1)
8554       return (b-p).lengthSquared();
8555     else
8556       return ((a + mu*v)-p).lengthSquared();
8557   } else
8558     return (a-p).lengthSquared();
8559 }
8560
8561 /*! \internal
8562
8563   A convenience function which returns the selectTest value for a specified \a rect and a specified
8564   click position \a pos. \a filledRect defines whether a click inside the rect should also be
8565   considered a hit or whether only the rect border is sensitive to hits.
8566   
8567   This function may be used to help with the implementation of the \ref selectTest function for
8568   specific items.
8569   
8570   For example, if your item consists of four rects, call this function four times, once for each
8571   rect, in your \ref selectTest reimplementation. Finally, return the minimum of all four returned
8572   values.
8573   
8574   \see distSqrToLine
8575 */
8576 double QCPAbstractItem::rectSelectTest(const QRectF &rect, const QPointF &pos, bool filledRect) const
8577 {
8578   double result = -1;
8579
8580   // distance to border:
8581   QList<QLineF> lines;
8582   lines << QLineF(rect.topLeft(), rect.topRight()) << QLineF(rect.bottomLeft(), rect.bottomRight())
8583         << QLineF(rect.topLeft(), rect.bottomLeft()) << QLineF(rect.topRight(), rect.bottomRight());
8584   double minDistSqr = std::numeric_limits<double>::max();
8585   for (int i=0; i<lines.size(); ++i)
8586   {
8587     double distSqr = distSqrToLine(lines.at(i).p1(), lines.at(i).p2(), pos);
8588     if (distSqr < minDistSqr)
8589       minDistSqr = distSqr;
8590   }
8591   result = qSqrt(minDistSqr);
8592   
8593   // filled rect, allow click inside to count as hit:
8594   if (filledRect && result > mParentPlot->selectionTolerance()*0.99)
8595   {
8596     if (rect.contains(pos))
8597       result = mParentPlot->selectionTolerance()*0.99;
8598   }
8599   return result;
8600 }
8601
8602 /*! \internal
8603
8604   Returns the pixel position of the anchor with Id \a anchorId. This function must be reimplemented in
8605   item subclasses if they want to provide anchors (QCPItemAnchor).
8606   
8607   For example, if the item has two anchors with id 0 and 1, this function takes one of these anchor
8608   ids and returns the respective pixel points of the specified anchor.
8609   
8610   \see createAnchor
8611 */
8612 QPointF QCPAbstractItem::anchorPixelPoint(int anchorId) const
8613 {
8614   qDebug() << Q_FUNC_INFO << "called on item which shouldn't have any anchors (this method not reimplemented). anchorId" << anchorId;
8615   return QPointF();
8616 }
8617
8618 /*! \internal
8619
8620   Creates a QCPItemPosition, registers it with this item and returns a pointer to it. The specified
8621   \a name must be a unique string that is usually identical to the variable name of the position
8622   member (This is needed to provide the name-based \ref position access to positions).
8623   
8624   Don't delete positions created by this function manually, as the item will take care of it.
8625   
8626   Use this function in the constructor (initialization list) of the specific item subclass to
8627   create each position member. Don't create QCPItemPositions with \b new yourself, because they
8628   won't be registered with the item properly.
8629   
8630   \see createAnchor
8631 */
8632 QCPItemPosition *QCPAbstractItem::createPosition(const QString &name)
8633 {
8634   if (hasAnchor(name))
8635     qDebug() << Q_FUNC_INFO << "anchor/position with name exists already:" << name;
8636   QCPItemPosition *newPosition = new QCPItemPosition(mParentPlot, this, name);
8637   mPositions.append(newPosition);
8638   mAnchors.append(newPosition); // every position is also an anchor
8639   newPosition->setAxes(mParentPlot->xAxis, mParentPlot->yAxis);
8640   newPosition->setType(QCPItemPosition::ptPlotCoords);
8641   if (mParentPlot->axisRect())
8642     newPosition->setAxisRect(mParentPlot->axisRect());
8643   newPosition->setCoords(0, 0);
8644   return newPosition;
8645 }
8646
8647 /*! \internal
8648
8649   Creates a QCPItemAnchor, registers it with this item and returns a pointer to it. The specified
8650   \a name must be a unique string that is usually identical to the variable name of the anchor
8651   member (This is needed to provide the name based \ref anchor access to anchors).
8652   
8653   The \a anchorId must be a number identifying the created anchor. It is recommended to create an
8654   enum (e.g. "AnchorIndex") for this on each item that uses anchors. This id is used by the anchor
8655   to identify itself when it calls QCPAbstractItem::anchorPixelPoint. That function then returns
8656   the correct pixel coordinates for the passed anchor id.
8657   
8658   Don't delete anchors created by this function manually, as the item will take care of it.
8659   
8660   Use this function in the constructor (initialization list) of the specific item subclass to
8661   create each anchor member. Don't create QCPItemAnchors with \b new yourself, because then they
8662   won't be registered with the item properly.
8663   
8664   \see createPosition
8665 */
8666 QCPItemAnchor *QCPAbstractItem::createAnchor(const QString &name, int anchorId)
8667 {
8668   if (hasAnchor(name))
8669     qDebug() << Q_FUNC_INFO << "anchor/position with name exists already:" << name;
8670   QCPItemAnchor *newAnchor = new QCPItemAnchor(mParentPlot, this, name, anchorId);
8671   mAnchors.append(newAnchor);
8672   return newAnchor;
8673 }
8674
8675 /* inherits documentation from base class */
8676 void QCPAbstractItem::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged)
8677 {
8678   Q_UNUSED(event)
8679   Q_UNUSED(details)
8680   if (mSelectable)
8681   {
8682     bool selBefore = mSelected;
8683     setSelected(additive ? !mSelected : true);
8684     if (selectionStateChanged)
8685       *selectionStateChanged = mSelected != selBefore;
8686   }
8687 }
8688
8689 /* inherits documentation from base class */
8690 void QCPAbstractItem::deselectEvent(bool *selectionStateChanged)
8691 {
8692   if (mSelectable)
8693   {
8694     bool selBefore = mSelected;
8695     setSelected(false);
8696     if (selectionStateChanged)
8697       *selectionStateChanged = mSelected != selBefore;
8698   }
8699 }
8700
8701 /* inherits documentation from base class */
8702 QCP::Interaction QCPAbstractItem::selectionCategory() const
8703 {
8704   return QCP::iSelectItems;
8705 }
8706
8707
8708 /*! \file */
8709
8710
8711
8712 ////////////////////////////////////////////////////////////////////////////////////////////////////
8713 //////////////////// QCustomPlot
8714 ////////////////////////////////////////////////////////////////////////////////////////////////////
8715
8716 /*! \class QCustomPlot
8717   
8718   \brief The central class of the library. This is the QWidget which displays the plot and
8719   interacts with the user.
8720   
8721   For tutorials on how to use QCustomPlot, see the website\n
8722   http://www.qcustomplot.com/
8723 */
8724
8725 /* start of documentation of inline functions */
8726
8727 /*! \fn QRect QCustomPlot::viewport() const
8728   
8729   Returns the viewport rect of this QCustomPlot instance. The viewport is the area the plot is
8730   drawn in, all mechanisms, e.g. margin caluclation take the viewport to be the outer border of the
8731   plot. The viewport normally is the rect() of the QCustomPlot widget, i.e. a rect with top left
8732   (0, 0) and size of the QCustomPlot widget.
8733   
8734   Don't confuse the viewport with the axis rect (QCustomPlot::axisRect). An axis rect is typically
8735   an area enclosed by four axes, where the graphs/plottables are drawn in. The viewport is larger
8736   and contains also the axes themselves, their tick numbers, their labels, the plot title etc.
8737   
8738   Only when saving to a file (see \ref savePng, \ref savePdf etc.) the viewport is temporarily
8739   modified to allow saving plots with sizes independent of the current widget size.
8740 */
8741
8742 /*! \fn QCPLayoutGrid *QCustomPlot::plotLayout() const
8743   
8744   Returns the top level layout of this QCustomPlot instance. It is a \ref QCPLayoutGrid, initially containing just
8745   one cell with the main QCPAxisRect inside.
8746 */
8747
8748 /* end of documentation of inline functions */
8749 /* start of documentation of signals */
8750
8751 /*! \fn void QCustomPlot::mouseDoubleClick(QMouseEvent *event)
8752
8753   This signal is emitted when the QCustomPlot receives a mouse double click event.
8754 */
8755
8756 /*! \fn void QCustomPlot::mousePress(QMouseEvent *event)
8757
8758   This signal is emitted when the QCustomPlot receives a mouse press event.
8759   
8760   It is emitted before QCustomPlot handles any other mechanism like range dragging. So a slot
8761   connected to this signal can still influence the behaviour e.g. with \ref QCPAxisRect::setRangeDrag or \ref
8762   QCPAxisRect::setRangeDragAxes.
8763 */
8764
8765 /*! \fn void QCustomPlot::mouseMove(QMouseEvent *event)
8766
8767   This signal is emitted when the QCustomPlot receives a mouse move event.
8768   
8769   It is emitted before QCustomPlot handles any other mechanism like range dragging. So a slot
8770   connected to this signal can still influence the behaviour e.g. with \ref QCPAxisRect::setRangeDrag or \ref
8771   QCPAxisRect::setRangeDragAxes.
8772   
8773   \warning It is discouraged to change the drag-axes with \ref QCPAxisRect::setRangeDragAxes here,
8774   because the dragging starting point was saved the moment the mouse was pressed. Thus it only has
8775   a meaning for the range drag axes that were set at that moment. If you want to change the drag
8776   axes, consider doing this in the \ref mousePress signal instead.
8777 */
8778
8779 /*! \fn void QCustomPlot::mouseRelease(QMouseEvent *event)
8780
8781   This signal is emitted when the QCustomPlot receives a mouse release event.
8782   
8783   It is emitted before QCustomPlot handles any other mechanisms like object selection. So a
8784   slot connected to this signal can still influence the behaviour e.g. with \ref setInteractions or
8785   \ref QCPAbstractPlottable::setSelectable.
8786 */
8787
8788 /*! \fn void QCustomPlot::mouseWheel(QMouseEvent *event)
8789
8790   This signal is emitted when the QCustomPlot receives a mouse wheel event.
8791   
8792   It is emitted before QCustomPlot handles any other mechanisms like range zooming. So a slot
8793   connected to this signal can still influence the behaviour e.g. with \ref QCPAxisRect::setRangeZoom, \ref
8794   QCPAxisRect::setRangeZoomAxes or \ref QCPAxisRect::setRangeZoomFactor.
8795 */
8796
8797 /*! \fn void QCustomPlot::plottableClick(QCPAbstractPlottable *plottable, QMouseEvent *event)
8798   
8799   This signal is emitted when a plottable is clicked.
8800
8801   \a event is the mouse event that caused the click and \a plottable is the plottable that received
8802   the click.
8803   
8804   \see plottableDoubleClick
8805 */
8806
8807 /*! \fn void QCustomPlot::plottableDoubleClick(QCPAbstractPlottable *plottable, QMouseEvent *event)
8808   
8809   This signal is emitted when a plottable is double clicked.
8810   
8811   \a event is the mouse event that caused the click and \a plottable is the plottable that received
8812   the click.
8813   
8814   \see plottableClick
8815 */
8816
8817 /*! \fn void QCustomPlot::itemClick(QCPAbstractItem *item, QMouseEvent *event)
8818   
8819   This signal is emitted when an item is clicked.
8820
8821   \a event is the mouse event that caused the click and \a item is the item that received the
8822   click.
8823   
8824   \see itemDoubleClick
8825 */
8826
8827 /*! \fn void QCustomPlot::itemDoubleClick(QCPAbstractItem *item, QMouseEvent *event)
8828   
8829   This signal is emitted when an item is double clicked.
8830   
8831   \a event is the mouse event that caused the click and \a item is the item that received the
8832   click.
8833   
8834   \see itemClick
8835 */
8836
8837 /*! \fn void QCustomPlot::axisClick(QCPAxis *axis, QCPAxis::SelectablePart part, QMouseEvent *event)
8838   
8839   This signal is emitted when an axis is clicked.
8840   
8841   \a event is the mouse event that caused the click, \a axis is the axis that received the click and
8842   \a part indicates the part of the axis that was clicked.
8843   
8844   \see axisDoubleClick
8845 */
8846
8847 /*! \fn void QCustomPlot::axisDoubleClick(QCPAxis *axis, QCPAxis::SelectablePart part, QMouseEvent *event)
8848
8849   This signal is emitted when an axis is double clicked.
8850   
8851   \a event is the mouse event that caused the click, \a axis is the axis that received the click and
8852   \a part indicates the part of the axis that was clicked.
8853   
8854   \see axisClick
8855 */
8856
8857 /*! \fn void QCustomPlot::legendClick(QCPLegend *legend, QCPAbstractLegendItem *item, QMouseEvent *event)
8858
8859   This signal is emitted when a legend (item) is clicked.
8860   
8861   \a event is the mouse event that caused the click, \a legend is the legend that received the
8862   click and \a item is the legend item that received the click. If only the legend and no item is
8863   clicked, \a item is 0. This happens for a click inside the legend padding or the space between
8864   two items.
8865   
8866   \see legendDoubleClick
8867 */
8868
8869 /*! \fn void QCustomPlot::legendDoubleClick(QCPLegend *legend,  QCPAbstractLegendItem *item, QMouseEvent *event)
8870
8871   This signal is emitted when a legend (item) is double clicked.
8872   
8873   \a event is the mouse event that caused the click, \a legend is the legend that received the
8874   click and \a item is the legend item that received the click. If only the legend and no item is
8875   clicked, \a item is 0. This happens for a click inside the legend padding or the space between
8876   two items.
8877   
8878   \see legendClick
8879 */
8880
8881 /*! \fn void QCustomPlot:: titleClick(QMouseEvent *event, QCPPlotTitle *title)
8882
8883   This signal is emitted when a plot title is clicked.
8884   
8885   \a event is the mouse event that caused the click and \a title is the plot title that received
8886   the click.
8887   
8888   \see titleDoubleClick
8889 */
8890
8891 /*! \fn void QCustomPlot::titleDoubleClick(QMouseEvent *event, QCPPlotTitle *title)
8892
8893   This signal is emitted when a plot title is double clicked.
8894   
8895   \a event is the mouse event that caused the click and \a title is the plot title that received
8896   the click.
8897   
8898   \see titleClick
8899 */
8900
8901 /*! \fn void QCustomPlot::selectionChangedByUser()
8902   
8903   This signal is emitted after the user has changed the selection in the QCustomPlot, e.g. by
8904   clicking. It is not emitted when the selection state of an object has changed programmatically by
8905   a direct call to setSelected() on an object or by calling \ref deselectAll.
8906   
8907   In addition to this signal, selectable objects also provide individual signals, for example
8908   QCPAxis::selectionChanged or QCPAbstractPlottable::selectionChanged. Note that those signals are
8909   emitted even if the selection state is changed programmatically.
8910   
8911   See the documentation of \ref setInteractions for details about the selection mechanism.
8912   
8913   \see selectedPlottables, selectedGraphs, selectedItems, selectedAxes, selectedLegends
8914 */
8915
8916 /*! \fn void QCustomPlot::beforeReplot()
8917   
8918   This signal is emitted immediately before a replot takes place (caused by a call to the slot \ref
8919   replot).
8920   
8921   It is safe to mutually connect the replot slot with this signal on two QCustomPlots to make them
8922   replot synchronously, it won't cause an infinite recursion.
8923   
8924   \see replot, afterReplot
8925 */
8926
8927 /*! \fn void QCustomPlot::afterReplot()
8928   
8929   This signal is emitted immediately after a replot has taken place (caused by a call to the slot \ref
8930   replot).
8931   
8932   It is safe to mutually connect the replot slot with this signal on two QCustomPlots to make them
8933   replot synchronously, it won't cause an infinite recursion.
8934   
8935   \see replot, beforeReplot
8936 */
8937
8938 /* end of documentation of signals */
8939 /* start of documentation of public members */
8940
8941 /*! \var QCPAxis *QCustomPlot::xAxis
8942
8943   A pointer to the primary x Axis (bottom) of the main axis rect of the plot.
8944   
8945   QCustomPlot offers convenient pointers to the axes (\ref xAxis, \ref yAxis, \ref xAxis2, \ref
8946   yAxis2) and the \ref legend. They make it very easy working with plots that only have a single
8947   axis rect and at most one axis at each axis rect side. If you use \link thelayoutsystem the
8948   layout system\endlink to add multiple axis rects or multiple axes to one side, use the \ref
8949   QCPAxisRect::axis interface to access the new axes. If one of the four default axes or the
8950   default legend is removed due to manipulation of the layout system (e.g. by removing the main
8951   axis rect), the corresponding pointers become 0.
8952 */
8953
8954 /*! \var QCPAxis *QCustomPlot::yAxis
8955
8956   A pointer to the primary y Axis (left) of the main axis rect of the plot.
8957   
8958   QCustomPlot offers convenient pointers to the axes (\ref xAxis, \ref yAxis, \ref xAxis2, \ref
8959   yAxis2) and the \ref legend. They make it very easy working with plots that only have a single
8960   axis rect and at most one axis at each axis rect side. If you use \link thelayoutsystem the
8961   layout system\endlink to add multiple axis rects or multiple axes to one side, use the \ref
8962   QCPAxisRect::axis interface to access the new axes. If one of the four default axes or the
8963   default legend is removed due to manipulation of the layout system (e.g. by removing the main
8964   axis rect), the corresponding pointers become 0.
8965 */
8966
8967 /*! \var QCPAxis *QCustomPlot::xAxis2
8968
8969   A pointer to the secondary x Axis (top) of the main axis rect of the plot. Secondary axes are
8970   invisible by default. Use QCPAxis::setVisible to change this (or use \ref
8971   QCPAxisRect::setupFullAxesBox).
8972   
8973   QCustomPlot offers convenient pointers to the axes (\ref xAxis, \ref yAxis, \ref xAxis2, \ref
8974   yAxis2) and the \ref legend. They make it very easy working with plots that only have a single
8975   axis rect and at most one axis at each axis rect side. If you use \link thelayoutsystem the
8976   layout system\endlink to add multiple axis rects or multiple axes to one side, use the \ref
8977   QCPAxisRect::axis interface to access the new axes. If one of the four default axes or the
8978   default legend is removed due to manipulation of the layout system (e.g. by removing the main
8979   axis rect), the corresponding pointers become 0.
8980 */
8981
8982 /*! \var QCPAxis *QCustomPlot::yAxis2
8983
8984   A pointer to the secondary y Axis (right) of the main axis rect of the plot. Secondary axes are
8985   invisible by default. Use QCPAxis::setVisible to change this (or use \ref
8986   QCPAxisRect::setupFullAxesBox).
8987   
8988   QCustomPlot offers convenient pointers to the axes (\ref xAxis, \ref yAxis, \ref xAxis2, \ref
8989   yAxis2) and the \ref legend. They make it very easy working with plots that only have a single
8990   axis rect and at most one axis at each axis rect side. If you use \link thelayoutsystem the
8991   layout system\endlink to add multiple axis rects or multiple axes to one side, use the \ref
8992   QCPAxisRect::axis interface to access the new axes. If one of the four default axes or the
8993   default legend is removed due to manipulation of the layout system (e.g. by removing the main
8994   axis rect), the corresponding pointers become 0.
8995 */
8996
8997 /*! \var QCPLegend *QCustomPlot::legend
8998
8999   A pointer to the default legend of the main axis rect. The legend is invisible by default. Use
9000   QCPLegend::setVisible to change this.
9001   
9002   QCustomPlot offers convenient pointers to the axes (\ref xAxis, \ref yAxis, \ref xAxis2, \ref
9003   yAxis2) and the \ref legend. They make it very easy working with plots that only have a single
9004   axis rect and at most one axis at each axis rect side. If you use \link thelayoutsystem the
9005   layout system\endlink to add multiple legends to the plot, use the layout system interface to
9006   access the new legend. For example, legends can be placed inside an axis rect's \ref
9007   QCPAxisRect::insetLayout "inset layout", and must then also be accessed via the inset layout. If
9008   the default legend is removed due to manipulation of the layout system (e.g. by removing the main
9009   axis rect), the corresponding pointer becomes 0.
9010 */
9011
9012 /* end of documentation of public members */
9013
9014 /*!
9015   Constructs a QCustomPlot and sets reasonable default values.
9016 */
9017 QCustomPlot::QCustomPlot(QWidget *parent) :
9018   QWidget(parent),
9019   xAxis(0),
9020   yAxis(0),
9021   xAxis2(0),
9022   yAxis2(0),
9023   legend(0),
9024   mPlotLayout(0),
9025   mAutoAddPlottableToLegend(true),
9026   mAntialiasedElements(QCP::aeNone),
9027   mNotAntialiasedElements(QCP::aeNone),
9028   mInteractions(0),
9029   mSelectionTolerance(8),
9030   mNoAntialiasingOnDrag(false),
9031   mBackgroundBrush(Qt::white, Qt::SolidPattern),
9032   mBackgroundScaled(true),
9033   mBackgroundScaledMode(Qt::KeepAspectRatioByExpanding),
9034   mCurrentLayer(0),
9035   mPlottingHints(QCP::phCacheLabels|QCP::phForceRepaint),
9036   mMultiSelectModifier(Qt::ControlModifier),
9037   mPaintBuffer(size()),
9038   mMouseEventElement(0),
9039   mReplotting(false)
9040 {
9041   setAttribute(Qt::WA_NoMousePropagation);
9042   setAttribute(Qt::WA_OpaquePaintEvent);
9043   setMouseTracking(true);
9044   QLocale currentLocale = locale();
9045   currentLocale.setNumberOptions(QLocale::OmitGroupSeparator);
9046   setLocale(currentLocale);
9047   
9048   // create initial layers:
9049   mLayers.append(new QCPLayer(this, QLatin1String("background")));
9050   mLayers.append(new QCPLayer(this, QLatin1String("grid")));
9051   mLayers.append(new QCPLayer(this, QLatin1String("main")));
9052   mLayers.append(new QCPLayer(this, QLatin1String("axes")));
9053   mLayers.append(new QCPLayer(this, QLatin1String("legend")));
9054   updateLayerIndices();
9055   setCurrentLayer(QLatin1String("main"));
9056   
9057   // create initial layout, axis rect and legend:
9058   mPlotLayout = new QCPLayoutGrid;
9059   mPlotLayout->initializeParentPlot(this);
9060   mPlotLayout->setParent(this); // important because if parent is QWidget, QCPLayout::sizeConstraintsChanged will call QWidget::updateGeometry
9061   mPlotLayout->setLayer(QLatin1String("main"));
9062   QCPAxisRect *defaultAxisRect = new QCPAxisRect(this, true);
9063   mPlotLayout->addElement(0, 0, defaultAxisRect);
9064   xAxis = defaultAxisRect->axis(QCPAxis::atBottom);
9065   yAxis = defaultAxisRect->axis(QCPAxis::atLeft);
9066   xAxis2 = defaultAxisRect->axis(QCPAxis::atTop);
9067   yAxis2 = defaultAxisRect->axis(QCPAxis::atRight);
9068   legend = new QCPLegend;
9069   legend->setVisible(false);
9070   defaultAxisRect->insetLayout()->addElement(legend, Qt::AlignRight|Qt::AlignTop);
9071   defaultAxisRect->insetLayout()->setMargins(QMargins(12, 12, 12, 12));
9072   
9073   defaultAxisRect->setLayer(QLatin1String("background"));
9074   xAxis->setLayer(QLatin1String("axes"));
9075   yAxis->setLayer(QLatin1String("axes"));
9076   xAxis2->setLayer(QLatin1String("axes"));
9077   yAxis2->setLayer(QLatin1String("axes"));
9078   xAxis->grid()->setLayer(QLatin1String("grid"));
9079   yAxis->grid()->setLayer(QLatin1String("grid"));
9080   xAxis2->grid()->setLayer(QLatin1String("grid"));
9081   yAxis2->grid()->setLayer(QLatin1String("grid"));
9082   legend->setLayer(QLatin1String("legend"));
9083   
9084   setViewport(rect()); // needs to be called after mPlotLayout has been created
9085   
9086   replot();
9087 }
9088
9089 QCustomPlot::~QCustomPlot()
9090 {
9091   clearPlottables();
9092   clearItems();
9093
9094   if (mPlotLayout)
9095   {
9096     delete mPlotLayout;
9097     mPlotLayout = 0;
9098   }
9099   
9100   mCurrentLayer = 0;
9101   qDeleteAll(mLayers); // don't use removeLayer, because it would prevent the last layer to be removed
9102   mLayers.clear();
9103 }
9104
9105 /*!
9106   Sets which elements are forcibly drawn antialiased as an \a or combination of QCP::AntialiasedElement.
9107   
9108   This overrides the antialiasing settings for whole element groups, normally controlled with the
9109   \a setAntialiasing function on the individual elements. If an element is neither specified in
9110   \ref setAntialiasedElements nor in \ref setNotAntialiasedElements, the antialiasing setting on
9111   each individual element instance is used.
9112   
9113   For example, if \a antialiasedElements contains \ref QCP::aePlottables, all plottables will be
9114   drawn antialiased, no matter what the specific QCPAbstractPlottable::setAntialiased value was set
9115   to.
9116   
9117   if an element in \a antialiasedElements is already set in \ref setNotAntialiasedElements, it is
9118   removed from there.
9119   
9120   \see setNotAntialiasedElements
9121 */
9122 void QCustomPlot::setAntialiasedElements(const QCP::AntialiasedElements &antialiasedElements)
9123 {
9124   mAntialiasedElements = antialiasedElements;
9125   
9126   // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously:
9127   if ((mNotAntialiasedElements & mAntialiasedElements) != 0)
9128     mNotAntialiasedElements |= ~mAntialiasedElements;
9129 }
9130
9131 /*!
9132   Sets whether the specified \a antialiasedElement is forcibly drawn antialiased.
9133   
9134   See \ref setAntialiasedElements for details.
9135   
9136   \see setNotAntialiasedElement
9137 */
9138 void QCustomPlot::setAntialiasedElement(QCP::AntialiasedElement antialiasedElement, bool enabled)
9139 {
9140   if (!enabled && mAntialiasedElements.testFlag(antialiasedElement))
9141     mAntialiasedElements &= ~antialiasedElement;
9142   else if (enabled && !mAntialiasedElements.testFlag(antialiasedElement))
9143     mAntialiasedElements |= antialiasedElement;
9144   
9145   // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously:
9146   if ((mNotAntialiasedElements & mAntialiasedElements) != 0)
9147     mNotAntialiasedElements |= ~mAntialiasedElements;
9148 }
9149
9150 /*!
9151   Sets which elements are forcibly drawn not antialiased as an \a or combination of
9152   QCP::AntialiasedElement.
9153   
9154   This overrides the antialiasing settings for whole element groups, normally controlled with the
9155   \a setAntialiasing function on the individual elements. If an element is neither specified in
9156   \ref setAntialiasedElements nor in \ref setNotAntialiasedElements, the antialiasing setting on
9157   each individual element instance is used.
9158   
9159   For example, if \a notAntialiasedElements contains \ref QCP::aePlottables, no plottables will be
9160   drawn antialiased, no matter what the specific QCPAbstractPlottable::setAntialiased value was set
9161   to.
9162   
9163   if an element in \a notAntialiasedElements is already set in \ref setAntialiasedElements, it is
9164   removed from there.
9165   
9166   \see setAntialiasedElements
9167 */
9168 void QCustomPlot::setNotAntialiasedElements(const QCP::AntialiasedElements &notAntialiasedElements)
9169 {
9170   mNotAntialiasedElements = notAntialiasedElements;
9171   
9172   // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously:
9173   if ((mNotAntialiasedElements & mAntialiasedElements) != 0)
9174     mAntialiasedElements |= ~mNotAntialiasedElements;
9175 }
9176
9177 /*!
9178   Sets whether the specified \a notAntialiasedElement is forcibly drawn not antialiased.
9179   
9180   See \ref setNotAntialiasedElements for details.
9181   
9182   \see setAntialiasedElement
9183 */
9184 void QCustomPlot::setNotAntialiasedElement(QCP::AntialiasedElement notAntialiasedElement, bool enabled)
9185 {
9186   if (!enabled && mNotAntialiasedElements.testFlag(notAntialiasedElement))
9187     mNotAntialiasedElements &= ~notAntialiasedElement;
9188   else if (enabled && !mNotAntialiasedElements.testFlag(notAntialiasedElement))
9189     mNotAntialiasedElements |= notAntialiasedElement;
9190   
9191   // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously:
9192   if ((mNotAntialiasedElements & mAntialiasedElements) != 0)
9193     mAntialiasedElements |= ~mNotAntialiasedElements;
9194 }
9195
9196 /*!
9197   If set to true, adding a plottable (e.g. a graph) to the QCustomPlot automatically also adds the
9198   plottable to the legend (QCustomPlot::legend).
9199   
9200   \see addPlottable, addGraph, QCPLegend::addItem
9201 */
9202 void QCustomPlot::setAutoAddPlottableToLegend(bool on)
9203 {
9204   mAutoAddPlottableToLegend = on;
9205 }
9206
9207 /*!
9208   Sets the possible interactions of this QCustomPlot as an or-combination of \ref QCP::Interaction
9209   enums. There are the following types of interactions:
9210   
9211   <b>Axis range manipulation</b> is controlled via \ref QCP::iRangeDrag and \ref QCP::iRangeZoom. When the
9212   respective interaction is enabled, the user may drag axes ranges and zoom with the mouse wheel.
9213   For details how to control which axes the user may drag/zoom and in what orientations, see \ref
9214   QCPAxisRect::setRangeDrag, \ref QCPAxisRect::setRangeZoom, \ref QCPAxisRect::setRangeDragAxes,
9215   \ref QCPAxisRect::setRangeZoomAxes.
9216   
9217   <b>Plottable selection</b> is controlled by \ref QCP::iSelectPlottables. If \ref QCP::iSelectPlottables is
9218   set, the user may select plottables (graphs, curves, bars,...) by clicking on them or in their
9219   vicinity (\ref setSelectionTolerance). Whether the user can actually select a plottable can
9220   further be restricted with the \ref QCPAbstractPlottable::setSelectable function on the specific
9221   plottable. To find out whether a specific plottable is selected, call
9222   QCPAbstractPlottable::selected(). To retrieve a list of all currently selected plottables, call
9223   \ref selectedPlottables. If you're only interested in QCPGraphs, you may use the convenience
9224   function \ref selectedGraphs.
9225   
9226   <b>Item selection</b> is controlled by \ref QCP::iSelectItems. If \ref QCP::iSelectItems is set, the user
9227   may select items (QCPItemLine, QCPItemText,...) by clicking on them or in their vicinity. To find
9228   out whether a specific item is selected, call QCPAbstractItem::selected(). To retrieve a list of
9229   all currently selected items, call \ref selectedItems.
9230   
9231   <b>Axis selection</b> is controlled with \ref QCP::iSelectAxes. If \ref QCP::iSelectAxes is set, the user
9232   may select parts of the axes by clicking on them. What parts exactly (e.g. Axis base line, tick
9233   labels, axis label) are selectable can be controlled via \ref QCPAxis::setSelectableParts for
9234   each axis. To retrieve a list of all axes that currently contain selected parts, call \ref
9235   selectedAxes. Which parts of an axis are selected, can be retrieved with QCPAxis::selectedParts().
9236   
9237   <b>Legend selection</b> is controlled with \ref QCP::iSelectLegend. If this is set, the user may
9238   select the legend itself or individual items by clicking on them. What parts exactly are
9239   selectable can be controlled via \ref QCPLegend::setSelectableParts. To find out whether the
9240   legend or any of its child items are selected, check the value of QCPLegend::selectedParts. To
9241   find out which child items are selected, call \ref QCPLegend::selectedItems.
9242   
9243   <b>All other selectable elements</b> The selection of all other selectable objects (e.g.
9244   QCPPlotTitle, or your own layerable subclasses) is controlled with \ref QCP::iSelectOther. If set, the
9245   user may select those objects by clicking on them. To find out which are currently selected, you
9246   need to check their selected state explicitly.
9247   
9248   If the selection state has changed by user interaction, the \ref selectionChangedByUser signal is
9249   emitted. Each selectable object additionally emits an individual selectionChanged signal whenever
9250   their selection state has changed, i.e. not only by user interaction.
9251   
9252   To allow multiple objects to be selected by holding the selection modifier (\ref
9253   setMultiSelectModifier), set the flag \ref QCP::iMultiSelect.
9254   
9255   \note In addition to the selection mechanism presented here, QCustomPlot always emits
9256   corresponding signals, when an object is clicked or double clicked. see \ref plottableClick and
9257   \ref plottableDoubleClick for example.
9258   
9259   \see setInteraction, setSelectionTolerance
9260 */
9261 void QCustomPlot::setInteractions(const QCP::Interactions &interactions)
9262 {
9263   mInteractions = interactions;
9264 }
9265
9266 /*!
9267   Sets the single \a interaction of this QCustomPlot to \a enabled.
9268   
9269   For details about the interaction system, see \ref setInteractions.
9270   
9271   \see setInteractions
9272 */
9273 void QCustomPlot::setInteraction(const QCP::Interaction &interaction, bool enabled)
9274 {
9275   if (!enabled && mInteractions.testFlag(interaction))
9276     mInteractions &= ~interaction;
9277   else if (enabled && !mInteractions.testFlag(interaction))
9278     mInteractions |= interaction;
9279 }
9280
9281 /*!
9282   Sets the tolerance that is used to decide whether a click selects an object (e.g. a plottable) or
9283   not.
9284   
9285   If the user clicks in the vicinity of the line of e.g. a QCPGraph, it's only regarded as a
9286   potential selection when the minimum distance between the click position and the graph line is
9287   smaller than \a pixels. Objects that are defined by an area (e.g. QCPBars) only react to clicks
9288   directly inside the area and ignore this selection tolerance. In other words, it only has meaning
9289   for parts of objects that are too thin to exactly hit with a click and thus need such a
9290   tolerance.
9291   
9292   \see setInteractions, QCPLayerable::selectTest
9293 */
9294 void QCustomPlot::setSelectionTolerance(int pixels)
9295 {
9296   mSelectionTolerance = pixels;
9297 }
9298
9299 /*!
9300   Sets whether antialiasing is disabled for this QCustomPlot while the user is dragging axes
9301   ranges. If many objects, especially plottables, are drawn antialiased, this greatly improves
9302   performance during dragging. Thus it creates a more responsive user experience. As soon as the
9303   user stops dragging, the last replot is done with normal antialiasing, to restore high image
9304   quality.
9305   
9306   \see setAntialiasedElements, setNotAntialiasedElements
9307 */
9308 void QCustomPlot::setNoAntialiasingOnDrag(bool enabled)
9309 {
9310   mNoAntialiasingOnDrag = enabled;
9311 }
9312
9313 /*!
9314   Sets the plotting hints for this QCustomPlot instance as an \a or combination of QCP::PlottingHint.
9315   
9316   \see setPlottingHint
9317 */
9318 void QCustomPlot::setPlottingHints(const QCP::PlottingHints &hints)
9319 {
9320   mPlottingHints = hints;
9321 }
9322
9323 /*!
9324   Sets the specified plotting \a hint to \a enabled.
9325   
9326   \see setPlottingHints
9327 */
9328 void QCustomPlot::setPlottingHint(QCP::PlottingHint hint, bool enabled)
9329 {
9330   QCP::PlottingHints newHints = mPlottingHints;
9331   if (!enabled)
9332     newHints &= ~hint;
9333   else
9334     newHints |= hint;
9335   
9336   if (newHints != mPlottingHints)
9337     setPlottingHints(newHints);
9338 }
9339
9340 /*!
9341   Sets the keyboard modifier that will be recognized as multi-select-modifier.
9342   
9343   If \ref QCP::iMultiSelect is specified in \ref setInteractions, the user may select multiple objects
9344   by clicking on them one after the other while holding down \a modifier.
9345   
9346   By default the multi-select-modifier is set to Qt::ControlModifier.
9347   
9348   \see setInteractions
9349 */
9350 void QCustomPlot::setMultiSelectModifier(Qt::KeyboardModifier modifier)
9351 {
9352   mMultiSelectModifier = modifier;
9353 }
9354
9355 /*!
9356   Sets the viewport of this QCustomPlot. The Viewport is the area that the top level layout
9357   (QCustomPlot::plotLayout()) uses as its rect. Normally, the viewport is the entire widget rect.
9358   
9359   This function is used to allow arbitrary size exports with \ref toPixmap, \ref savePng, \ref
9360   savePdf, etc. by temporarily changing the viewport size.
9361 */
9362 void QCustomPlot::setViewport(const QRect &rect)
9363 {
9364   mViewport = rect;
9365   if (mPlotLayout)
9366     mPlotLayout->setOuterRect(mViewport);
9367 }
9368
9369 /*!
9370   Sets \a pm as the viewport background pixmap (see \ref setViewport). The pixmap is always drawn
9371   below all other objects in the plot.
9372
9373   For cases where the provided pixmap doesn't have the same size as the viewport, scaling can be
9374   enabled with \ref setBackgroundScaled and the scaling mode (whether and how the aspect ratio is
9375   preserved) can be set with \ref setBackgroundScaledMode. To set all these options in one call,
9376   consider using the overloaded version of this function.
9377   
9378   If a background brush was set with \ref setBackground(const QBrush &brush), the viewport will
9379   first be filled with that brush, before drawing the background pixmap. This can be useful for
9380   background pixmaps with translucent areas.
9381
9382   \see setBackgroundScaled, setBackgroundScaledMode
9383 */
9384 void QCustomPlot::setBackground(const QPixmap &pm)
9385 {
9386   mBackgroundPixmap = pm;
9387   mScaledBackgroundPixmap = QPixmap();
9388 }
9389
9390 /*!
9391   Sets the background brush of the viewport (see \ref setViewport).
9392
9393   Before drawing everything else, the background is filled with \a brush. If a background pixmap
9394   was set with \ref setBackground(const QPixmap &pm), this brush will be used to fill the viewport
9395   before the background pixmap is drawn. This can be useful for background pixmaps with translucent
9396   areas.
9397   
9398   Set \a brush to Qt::NoBrush or Qt::Transparent to leave background transparent. This can be
9399   useful for exporting to image formats which support transparency, e.g. \ref savePng.
9400
9401   \see setBackgroundScaled, setBackgroundScaledMode
9402 */
9403 void QCustomPlot::setBackground(const QBrush &brush)
9404 {
9405   mBackgroundBrush = brush;
9406 }
9407
9408 /*! \overload
9409   
9410   Allows setting the background pixmap of the viewport, whether it shall be scaled and how it
9411   shall be scaled in one call.
9412
9413   \see setBackground(const QPixmap &pm), setBackgroundScaled, setBackgroundScaledMode
9414 */
9415 void QCustomPlot::setBackground(const QPixmap &pm, bool scaled, Qt::AspectRatioMode mode)
9416 {
9417   mBackgroundPixmap = pm;
9418   mScaledBackgroundPixmap = QPixmap();
9419   mBackgroundScaled = scaled;
9420   mBackgroundScaledMode = mode;
9421 }
9422
9423 /*!
9424   Sets whether the viewport background pixmap shall be scaled to fit the viewport. If \a scaled is
9425   set to true, control whether and how the aspect ratio of the original pixmap is preserved with
9426   \ref setBackgroundScaledMode.
9427   
9428   Note that the scaled version of the original pixmap is buffered, so there is no performance
9429   penalty on replots. (Except when the viewport dimensions are changed continuously.)
9430   
9431   \see setBackground, setBackgroundScaledMode
9432 */
9433 void QCustomPlot::setBackgroundScaled(bool scaled)
9434 {
9435   mBackgroundScaled = scaled;
9436 }
9437
9438 /*!
9439   If scaling of the viewport background pixmap is enabled (\ref setBackgroundScaled), use this
9440   function to define whether and how the aspect ratio of the original pixmap is preserved.
9441   
9442   \see setBackground, setBackgroundScaled
9443 */
9444 void QCustomPlot::setBackgroundScaledMode(Qt::AspectRatioMode mode)
9445 {
9446   mBackgroundScaledMode = mode;
9447 }
9448
9449 /*!
9450   Returns the plottable with \a index. If the index is invalid, returns 0.
9451   
9452   There is an overloaded version of this function with no parameter which returns the last added
9453   plottable, see QCustomPlot::plottable()
9454   
9455   \see plottableCount, addPlottable
9456 */
9457 QCPAbstractPlottable *QCustomPlot::plottable(int index)
9458 {
9459   if (index >= 0 && index < mPlottables.size())
9460   {
9461     return mPlottables.at(index);
9462   } else
9463   {
9464     qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
9465     return 0;
9466   }
9467 }
9468
9469 /*! \overload
9470   
9471   Returns the last plottable that was added with \ref addPlottable. If there are no plottables in
9472   the plot, returns 0.
9473   
9474   \see plottableCount, addPlottable
9475 */
9476 QCPAbstractPlottable *QCustomPlot::plottable()
9477 {
9478   if (!mPlottables.isEmpty())
9479   {
9480     return mPlottables.last();
9481   } else
9482     return 0;
9483 }
9484
9485 /*!
9486   Adds the specified plottable to the plot and, if \ref setAutoAddPlottableToLegend is enabled, to
9487   the legend (QCustomPlot::legend). QCustomPlot takes ownership of the plottable.
9488   
9489   Returns true on success, i.e. when \a plottable isn't already in the plot and the parent plot of
9490   \a plottable is this QCustomPlot (the latter is controlled by what axes were passed in the
9491   plottable's constructor).
9492   
9493   \see plottable, plottableCount, removePlottable, clearPlottables
9494 */
9495 bool QCustomPlot::addPlottable(QCPAbstractPlottable *plottable)
9496 {
9497   if (mPlottables.contains(plottable))
9498   {
9499     qDebug() << Q_FUNC_INFO << "plottable already added to this QCustomPlot:" << reinterpret_cast<quintptr>(plottable);
9500     return false;
9501   }
9502   if (plottable->parentPlot() != this)
9503   {
9504     qDebug() << Q_FUNC_INFO << "plottable not created with this QCustomPlot as parent:" << reinterpret_cast<quintptr>(plottable);
9505     return false;
9506   }
9507   
9508   mPlottables.append(plottable);
9509   // possibly add plottable to legend:
9510   if (mAutoAddPlottableToLegend)
9511     plottable->addToLegend();
9512   // special handling for QCPGraphs to maintain the simple graph interface:
9513   if (QCPGraph *graph = qobject_cast<QCPGraph*>(plottable))
9514     mGraphs.append(graph);
9515   if (!plottable->layer()) // usually the layer is already set in the constructor of the plottable (via QCPLayerable constructor)
9516     plottable->setLayer(currentLayer());
9517   return true;
9518 }
9519
9520 /*!
9521   Removes the specified plottable from the plot and, if necessary, from the legend (QCustomPlot::legend).
9522   
9523   Returns true on success.
9524   
9525   \see addPlottable, clearPlottables
9526 */
9527 bool QCustomPlot::removePlottable(QCPAbstractPlottable *plottable)
9528 {
9529   if (!mPlottables.contains(plottable))
9530   {
9531     qDebug() << Q_FUNC_INFO << "plottable not in list:" << reinterpret_cast<quintptr>(plottable);
9532     return false;
9533   }
9534   
9535   // remove plottable from legend:
9536   plottable->removeFromLegend();
9537   // special handling for QCPGraphs to maintain the simple graph interface:
9538   if (QCPGraph *graph = qobject_cast<QCPGraph*>(plottable))
9539     mGraphs.removeOne(graph);
9540   // remove plottable:
9541   delete plottable;
9542   mPlottables.removeOne(plottable);
9543   return true;
9544 }
9545
9546 /*! \overload
9547   
9548   Removes the plottable by its \a index.
9549 */
9550 bool QCustomPlot::removePlottable(int index)
9551 {
9552   if (index >= 0 && index < mPlottables.size())
9553     return removePlottable(mPlottables[index]);
9554   else
9555   {
9556     qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
9557     return false;
9558   }
9559 }
9560
9561 /*!
9562   Removes all plottables from the plot (and the QCustomPlot::legend, if necessary).
9563   
9564   Returns the number of plottables removed.
9565   
9566   \see removePlottable
9567 */
9568 int QCustomPlot::clearPlottables()
9569 {
9570   int c = mPlottables.size();
9571   for (int i=c-1; i >= 0; --i)
9572     removePlottable(mPlottables[i]);
9573   return c;
9574 }
9575
9576 /*!
9577   Returns the number of currently existing plottables in the plot
9578   
9579   \see plottable, addPlottable
9580 */
9581 int QCustomPlot::plottableCount() const
9582 {
9583   return mPlottables.size();
9584 }
9585
9586 /*!
9587   Returns a list of the selected plottables. If no plottables are currently selected, the list is empty.
9588   
9589   There is a convenience function if you're only interested in selected graphs, see \ref selectedGraphs.
9590   
9591   \see setInteractions, QCPAbstractPlottable::setSelectable, QCPAbstractPlottable::setSelected
9592 */
9593 QList<QCPAbstractPlottable*> QCustomPlot::selectedPlottables() const
9594 {
9595   QList<QCPAbstractPlottable*> result;
9596   foreach (QCPAbstractPlottable *plottable, mPlottables)
9597   {
9598     if (plottable->selected())
9599       result.append(plottable);
9600   }
9601   return result;
9602 }
9603
9604 /*!
9605   Returns the plottable at the pixel position \a pos. Plottables that only consist of single lines
9606   (like graphs) have a tolerance band around them, see \ref setSelectionTolerance. If multiple
9607   plottables come into consideration, the one closest to \a pos is returned.
9608   
9609   If \a onlySelectable is true, only plottables that are selectable
9610   (QCPAbstractPlottable::setSelectable) are considered.
9611   
9612   If there is no plottable at \a pos, the return value is 0.
9613   
9614   \see itemAt, layoutElementAt
9615 */
9616 QCPAbstractPlottable *QCustomPlot::plottableAt(const QPointF &pos, bool onlySelectable) const
9617 {
9618   QCPAbstractPlottable *resultPlottable = 0;
9619   double resultDistance = mSelectionTolerance; // only regard clicks with distances smaller than mSelectionTolerance as selections, so initialize with that value
9620   
9621   foreach (QCPAbstractPlottable *plottable, mPlottables)
9622   {
9623     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
9624       continue;
9625     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
9626     {
9627       double currentDistance = plottable->selectTest(pos, false);
9628       if (currentDistance >= 0 && currentDistance < resultDistance)
9629       {
9630         resultPlottable = plottable;
9631         resultDistance = currentDistance;
9632       }
9633     }
9634   }
9635   
9636   return resultPlottable;
9637 }
9638
9639 /*!
9640   Returns whether this QCustomPlot instance contains the \a plottable.
9641   
9642   \see addPlottable
9643 */
9644 bool QCustomPlot::hasPlottable(QCPAbstractPlottable *plottable) const
9645 {
9646   return mPlottables.contains(plottable);
9647 }
9648
9649 /*!
9650   Returns the graph with \a index. If the index is invalid, returns 0.
9651   
9652   There is an overloaded version of this function with no parameter which returns the last created
9653   graph, see QCustomPlot::graph()
9654   
9655   \see graphCount, addGraph
9656 */
9657 QCPGraph *QCustomPlot::graph(int index) const
9658 {
9659   if (index >= 0 && index < mGraphs.size())
9660   {
9661     return mGraphs.at(index);
9662   } else
9663   {
9664     qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
9665     return 0;
9666   }
9667 }
9668
9669 /*! \overload
9670   
9671   Returns the last graph, that was created with \ref addGraph. If there are no graphs in the plot,
9672   returns 0.
9673   
9674   \see graphCount, addGraph
9675 */
9676 QCPGraph *QCustomPlot::graph() const
9677 {
9678   if (!mGraphs.isEmpty())
9679   {
9680     return mGraphs.last();
9681   } else
9682     return 0;
9683 }
9684
9685 /*!
9686   Creates a new graph inside the plot. If \a keyAxis and \a valueAxis are left unspecified (0), the
9687   bottom (xAxis) is used as key and the left (yAxis) is used as value axis. If specified, \a
9688   keyAxis and \a valueAxis must reside in this QCustomPlot.
9689   
9690   \a keyAxis will be used as key axis (typically "x") and \a valueAxis as value axis (typically
9691   "y") for the graph.
9692   
9693   Returns a pointer to the newly created graph, or 0 if adding the graph failed.
9694   
9695   \see graph, graphCount, removeGraph, clearGraphs
9696 */
9697 QCPGraph *QCustomPlot::addGraph(QCPAxis *keyAxis, QCPAxis *valueAxis)
9698 {
9699   if (!keyAxis) keyAxis = xAxis;
9700   if (!valueAxis) valueAxis = yAxis;
9701   if (!keyAxis || !valueAxis)
9702   {
9703     qDebug() << Q_FUNC_INFO << "can't use default QCustomPlot xAxis or yAxis, because at least one is invalid (has been deleted)";
9704     return 0;
9705   }
9706   if (keyAxis->parentPlot() != this || valueAxis->parentPlot() != this)
9707   {
9708     qDebug() << Q_FUNC_INFO << "passed keyAxis or valueAxis doesn't have this QCustomPlot as parent";
9709     return 0;
9710   }
9711   
9712   QCPGraph *newGraph = new QCPGraph(keyAxis, valueAxis);
9713   if (addPlottable(newGraph))
9714   {
9715     newGraph->setName(QLatin1String("Graph ")+QString::number(mGraphs.size()));
9716     return newGraph;
9717   } else
9718   {
9719     delete newGraph;
9720     return 0;
9721   }
9722 }
9723
9724 /*!
9725   Removes the specified \a graph from the plot and, if necessary, from the QCustomPlot::legend. If
9726   any other graphs in the plot have a channel fill set towards the removed graph, the channel fill
9727   property of those graphs is reset to zero (no channel fill).
9728   
9729   Returns true on success.
9730   
9731   \see clearGraphs
9732 */
9733 bool QCustomPlot::removeGraph(QCPGraph *graph)
9734 {
9735   return removePlottable(graph);
9736 }
9737
9738 /*! \overload
9739   
9740   Removes the graph by its \a index.
9741 */
9742 bool QCustomPlot::removeGraph(int index)
9743 {
9744   if (index >= 0 && index < mGraphs.size())
9745     return removeGraph(mGraphs[index]);
9746   else
9747     return false;
9748 }
9749
9750 /*!
9751   Removes all graphs from the plot (and the QCustomPlot::legend, if necessary).
9752
9753   Returns the number of graphs removed.
9754   
9755   \see removeGraph
9756 */
9757 int QCustomPlot::clearGraphs()
9758 {
9759   int c = mGraphs.size();
9760   for (int i=c-1; i >= 0; --i)
9761     removeGraph(mGraphs[i]);
9762   return c;
9763 }
9764
9765 /*!
9766   Returns the number of currently existing graphs in the plot
9767   
9768   \see graph, addGraph
9769 */
9770 int QCustomPlot::graphCount() const
9771 {
9772   return mGraphs.size();
9773 }
9774
9775 /*!
9776   Returns a list of the selected graphs. If no graphs are currently selected, the list is empty.
9777   
9778   If you are not only interested in selected graphs but other plottables like QCPCurve, QCPBars,
9779   etc., use \ref selectedPlottables.
9780   
9781   \see setInteractions, selectedPlottables, QCPAbstractPlottable::setSelectable, QCPAbstractPlottable::setSelected
9782 */
9783 QList<QCPGraph*> QCustomPlot::selectedGraphs() const
9784 {
9785   QList<QCPGraph*> result;
9786   foreach (QCPGraph *graph, mGraphs)
9787   {
9788     if (graph->selected())
9789       result.append(graph);
9790   }
9791   return result;
9792 }
9793
9794 /*!
9795   Returns the item with \a index. If the index is invalid, returns 0.
9796   
9797   There is an overloaded version of this function with no parameter which returns the last added
9798   item, see QCustomPlot::item()
9799   
9800   \see itemCount, addItem
9801 */
9802 QCPAbstractItem *QCustomPlot::item(int index) const
9803 {
9804   if (index >= 0 && index < mItems.size())
9805   {
9806     return mItems.at(index);
9807   } else
9808   {
9809     qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
9810     return 0;
9811   }
9812 }
9813
9814 /*! \overload
9815   
9816   Returns the last item, that was added with \ref addItem. If there are no items in the plot,
9817   returns 0.
9818   
9819   \see itemCount, addItem
9820 */
9821 QCPAbstractItem *QCustomPlot::item() const
9822 {
9823   if (!mItems.isEmpty())
9824   {
9825     return mItems.last();
9826   } else
9827     return 0;
9828 }
9829
9830 /*!
9831   Adds the specified item to the plot. QCustomPlot takes ownership of the item.
9832   
9833   Returns true on success, i.e. when \a item wasn't already in the plot and the parent plot of \a
9834   item is this QCustomPlot.
9835   
9836   \see item, itemCount, removeItem, clearItems
9837 */
9838 bool QCustomPlot::addItem(QCPAbstractItem *item)
9839 {
9840   if (!mItems.contains(item) && item->parentPlot() == this)
9841   {
9842     mItems.append(item);
9843     return true;
9844   } else
9845   {
9846     qDebug() << Q_FUNC_INFO << "item either already in list or not created with this QCustomPlot as parent:" << reinterpret_cast<quintptr>(item);
9847     return false;
9848   }
9849 }
9850
9851 /*!
9852   Removes the specified item from the plot.
9853   
9854   Returns true on success.
9855   
9856   \see addItem, clearItems
9857 */
9858 bool QCustomPlot::removeItem(QCPAbstractItem *item)
9859 {
9860   if (mItems.contains(item))
9861   {
9862     delete item;
9863     mItems.removeOne(item);
9864     return true;
9865   } else
9866   {
9867     qDebug() << Q_FUNC_INFO << "item not in list:" << reinterpret_cast<quintptr>(item);
9868     return false;
9869   }
9870 }
9871
9872 /*! \overload
9873   
9874   Removes the item by its \a index.
9875 */
9876 bool QCustomPlot::removeItem(int index)
9877 {
9878   if (index >= 0 && index < mItems.size())
9879     return removeItem(mItems[index]);
9880   else
9881   {
9882     qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
9883     return false;
9884   }
9885 }
9886
9887 /*!
9888   Removes all items from the plot.
9889   
9890   Returns the number of items removed.
9891   
9892   \see removeItem
9893 */
9894 int QCustomPlot::clearItems()
9895 {
9896   int c = mItems.size();
9897   for (int i=c-1; i >= 0; --i)
9898     removeItem(mItems[i]);
9899   return c;
9900 }
9901
9902 /*!
9903   Returns the number of currently existing items in the plot
9904   
9905   \see item, addItem
9906 */
9907 int QCustomPlot::itemCount() const
9908 {
9909   return mItems.size();
9910 }
9911
9912 /*!
9913   Returns a list of the selected items. If no items are currently selected, the list is empty.
9914   
9915   \see setInteractions, QCPAbstractItem::setSelectable, QCPAbstractItem::setSelected
9916 */
9917 QList<QCPAbstractItem*> QCustomPlot::selectedItems() const
9918 {
9919   QList<QCPAbstractItem*> result;
9920   foreach (QCPAbstractItem *item, mItems)
9921   {
9922     if (item->selected())
9923       result.append(item);
9924   }
9925   return result;
9926 }
9927
9928 /*!
9929   Returns the item at the pixel position \a pos. Items that only consist of single lines (e.g. \ref
9930   QCPItemLine or \ref QCPItemCurve) have a tolerance band around them, see \ref
9931   setSelectionTolerance. If multiple items come into consideration, the one closest to \a pos is
9932   returned.
9933   
9934   If \a onlySelectable is true, only items that are selectable (QCPAbstractItem::setSelectable) are
9935   considered.
9936   
9937   If there is no item at \a pos, the return value is 0.
9938   
9939   \see plottableAt, layoutElementAt
9940 */
9941 QCPAbstractItem *QCustomPlot::itemAt(const QPointF &pos, bool onlySelectable) const
9942 {
9943   QCPAbstractItem *resultItem = 0;
9944   double resultDistance = mSelectionTolerance; // only regard clicks with distances smaller than mSelectionTolerance as selections, so initialize with that value
9945   
9946   foreach (QCPAbstractItem *item, mItems)
9947   {
9948     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
9949       continue;
9950     if (!item->clipToAxisRect() || item->clipRect().contains(pos.toPoint())) // only consider clicks inside axis cliprect of the item if actually clipped to it
9951     {
9952       double currentDistance = item->selectTest(pos, false);
9953       if (currentDistance >= 0 && currentDistance < resultDistance)
9954       {
9955         resultItem = item;
9956         resultDistance = currentDistance;
9957       }
9958     }
9959   }
9960   
9961   return resultItem;
9962 }
9963
9964 /*!
9965   Returns whether this QCustomPlot contains the \a item.
9966   
9967   \see addItem
9968 */
9969 bool QCustomPlot::hasItem(QCPAbstractItem *item) const
9970 {
9971   return mItems.contains(item);
9972 }
9973
9974 /*!
9975   Returns the layer with the specified \a name. If there is no layer with the specified name, 0 is
9976   returned.
9977   
9978   Layer names are case-sensitive.
9979   
9980   \see addLayer, moveLayer, removeLayer
9981 */
9982 QCPLayer *QCustomPlot::layer(const QString &name) const
9983 {
9984   foreach (QCPLayer *layer, mLayers)
9985   {
9986     if (layer->name() == name)
9987       return layer;
9988   }
9989   return 0;
9990 }
9991
9992 /*! \overload
9993   
9994   Returns the layer by \a index. If the index is invalid, 0 is returned.
9995   
9996   \see addLayer, moveLayer, removeLayer
9997 */
9998 QCPLayer *QCustomPlot::layer(int index) const
9999 {
10000   if (index >= 0 && index < mLayers.size())
10001   {
10002     return mLayers.at(index);
10003   } else
10004   {
10005     qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
10006     return 0;
10007   }
10008 }
10009
10010 /*!
10011   Returns the layer that is set as current layer (see \ref setCurrentLayer).
10012 */
10013 QCPLayer *QCustomPlot::currentLayer() const
10014 {
10015   return mCurrentLayer;
10016 }
10017
10018 /*!
10019   Sets the layer with the specified \a name to be the current layer. All layerables (\ref
10020   QCPLayerable), e.g. plottables and items, are created on the current layer.
10021   
10022   Returns true on success, i.e. if there is a layer with the specified \a name in the QCustomPlot.
10023   
10024   Layer names are case-sensitive.
10025   
10026   \see addLayer, moveLayer, removeLayer, QCPLayerable::setLayer
10027 */
10028 bool QCustomPlot::setCurrentLayer(const QString &name)
10029 {
10030   if (QCPLayer *newCurrentLayer = layer(name))
10031   {
10032     return setCurrentLayer(newCurrentLayer);
10033   } else
10034   {
10035     qDebug() << Q_FUNC_INFO << "layer with name doesn't exist:" << name;
10036     return false;
10037   }
10038 }
10039
10040 /*! \overload
10041   
10042   Sets the provided \a layer to be the current layer.
10043   
10044   Returns true on success, i.e. when \a layer is a valid layer in the QCustomPlot.
10045   
10046   \see addLayer, moveLayer, removeLayer
10047 */
10048 bool QCustomPlot::setCurrentLayer(QCPLayer *layer)
10049 {
10050   if (!mLayers.contains(layer))
10051   {
10052     qDebug() << Q_FUNC_INFO << "layer not a layer of this QCustomPlot:" << reinterpret_cast<quintptr>(layer);
10053     return false;
10054   }
10055   
10056   mCurrentLayer = layer;
10057   return true;
10058 }
10059
10060 /*!
10061   Returns the number of currently existing layers in the plot
10062   
10063   \see layer, addLayer
10064 */
10065 int QCustomPlot::layerCount() const
10066 {
10067   return mLayers.size();
10068 }
10069
10070 /*!
10071   Adds a new layer to this QCustomPlot instance. The new layer will have the name \a name, which
10072   must be unique. Depending on \a insertMode, it is positioned either below or above \a otherLayer.
10073   
10074   Returns true on success, i.e. if there is no other layer named \a name and \a otherLayer is a
10075   valid layer inside this QCustomPlot.
10076   
10077   If \a otherLayer is 0, the highest layer in the QCustomPlot will be used.
10078   
10079   For an explanation of what layers are in QCustomPlot, see the documentation of \ref QCPLayer.
10080   
10081   \see layer, moveLayer, removeLayer
10082 */
10083 bool QCustomPlot::addLayer(const QString &name, QCPLayer *otherLayer, QCustomPlot::LayerInsertMode insertMode)
10084 {
10085   if (!otherLayer)
10086     otherLayer = mLayers.last();
10087   if (!mLayers.contains(otherLayer))
10088   {
10089     qDebug() << Q_FUNC_INFO << "otherLayer not a layer of this QCustomPlot:" << reinterpret_cast<quintptr>(otherLayer);
10090     return false;
10091   }
10092   if (layer(name))
10093   {
10094     qDebug() << Q_FUNC_INFO << "A layer exists already with the name" << name;
10095     return false;
10096   }
10097     
10098   QCPLayer *newLayer = new QCPLayer(this, name);
10099   mLayers.insert(otherLayer->index() + (insertMode==limAbove ? 1:0), newLayer);
10100   updateLayerIndices();
10101   return true;
10102 }
10103
10104 /*!
10105   Removes the specified \a layer and returns true on success.
10106   
10107   All layerables (e.g. plottables and items) on the removed layer will be moved to the layer below
10108   \a layer. If \a layer is the bottom layer, the layerables are moved to the layer above. In both
10109   cases, the total rendering order of all layerables in the QCustomPlot is preserved.
10110   
10111   If \a layer is the current layer (\ref setCurrentLayer), the layer below (or above, if bottom
10112   layer) becomes the new current layer.
10113   
10114   It is not possible to remove the last layer of the plot.
10115   
10116   \see layer, addLayer, moveLayer
10117 */
10118 bool QCustomPlot::removeLayer(QCPLayer *layer)
10119 {
10120   if (!mLayers.contains(layer))
10121   {
10122     qDebug() << Q_FUNC_INFO << "layer not a layer of this QCustomPlot:" << reinterpret_cast<quintptr>(layer);
10123     return false;
10124   }
10125   if (mLayers.size() < 2)
10126   {
10127     qDebug() << Q_FUNC_INFO << "can't remove last layer";
10128     return false;
10129   }
10130   
10131   // append all children of this layer to layer below (if this is lowest layer, prepend to layer above)
10132   int removedIndex = layer->index();
10133   bool isFirstLayer = removedIndex==0;
10134   QCPLayer *targetLayer = isFirstLayer ? mLayers.at(removedIndex+1) : mLayers.at(removedIndex-1);
10135   QList<QCPLayerable*> children = layer->children();
10136   if (isFirstLayer) // prepend in reverse order (so order relative to each other stays the same)
10137   {
10138     for (int i=children.size()-1; i>=0; --i)
10139       children.at(i)->moveToLayer(targetLayer, true);
10140   } else  // append normally
10141   {
10142     for (int i=0; i<children.size(); ++i)
10143       children.at(i)->moveToLayer(targetLayer, false);
10144   }
10145   // if removed layer is current layer, change current layer to layer below/above:
10146   if (layer == mCurrentLayer)
10147     setCurrentLayer(targetLayer);
10148   // remove layer:
10149   delete layer;
10150   mLayers.removeOne(layer);
10151   updateLayerIndices();
10152   return true;
10153 }
10154
10155 /*!
10156   Moves the specified \a layer either above or below \a otherLayer. Whether it's placed above or
10157   below is controlled with \a insertMode.
10158   
10159   Returns true on success, i.e. when both \a layer and \a otherLayer are valid layers in the
10160   QCustomPlot.
10161   
10162   \see layer, addLayer, moveLayer
10163 */
10164 bool QCustomPlot::moveLayer(QCPLayer *layer, QCPLayer *otherLayer, QCustomPlot::LayerInsertMode insertMode)
10165 {
10166   if (!mLayers.contains(layer))
10167   {
10168     qDebug() << Q_FUNC_INFO << "layer not a layer of this QCustomPlot:" << reinterpret_cast<quintptr>(layer);
10169     return false;
10170   }
10171   if (!mLayers.contains(otherLayer))
10172   {
10173     qDebug() << Q_FUNC_INFO << "otherLayer not a layer of this QCustomPlot:" << reinterpret_cast<quintptr>(otherLayer);
10174     return false;
10175   }
10176   
10177   if (layer->index() > otherLayer->index())
10178     mLayers.move(layer->index(), otherLayer->index() + (insertMode==limAbove ? 1:0));
10179   else if (layer->index() < otherLayer->index())
10180     mLayers.move(layer->index(), otherLayer->index() + (insertMode==limAbove ? 0:-1));
10181   
10182   updateLayerIndices();
10183   return true;
10184 }
10185
10186 /*!
10187   Returns the number of axis rects in the plot.
10188   
10189   All axis rects can be accessed via QCustomPlot::axisRect().
10190   
10191   Initially, only one axis rect exists in the plot.
10192   
10193   \see axisRect, axisRects
10194 */
10195 int QCustomPlot::axisRectCount() const
10196 {
10197   return axisRects().size();
10198 }
10199
10200 /*!
10201   Returns the axis rect with \a index.
10202   
10203   Initially, only one axis rect (with index 0) exists in the plot. If multiple axis rects were
10204   added, all of them may be accessed with this function in a linear fashion (even when they are
10205   nested in a layout hierarchy or inside other axis rects via QCPAxisRect::insetLayout).
10206   
10207   \see axisRectCount, axisRects
10208 */
10209 QCPAxisRect *QCustomPlot::axisRect(int index) const
10210 {
10211   const QList<QCPAxisRect*> rectList = axisRects();
10212   if (index >= 0 && index < rectList.size())
10213   {
10214     return rectList.at(index);
10215   } else
10216   {
10217     qDebug() << Q_FUNC_INFO << "invalid axis rect index" << index;
10218     return 0;
10219   }
10220 }
10221
10222 /*!
10223   Returns all axis rects in the plot.
10224   
10225   \see axisRectCount, axisRect
10226 */
10227 QList<QCPAxisRect*> QCustomPlot::axisRects() const
10228 {
10229   QList<QCPAxisRect*> result;
10230   QStack<QCPLayoutElement*> elementStack;
10231   if (mPlotLayout)
10232     elementStack.push(mPlotLayout);
10233   
10234   while (!elementStack.isEmpty())
10235   {
10236     foreach (QCPLayoutElement *element, elementStack.pop()->elements(false))
10237     {
10238       if (element)
10239       {
10240         elementStack.push(element);
10241         if (QCPAxisRect *ar = qobject_cast<QCPAxisRect*>(element))
10242           result.append(ar);
10243       }
10244     }
10245   }
10246   
10247   return result;
10248 }
10249
10250 /*!
10251   Returns the layout element at pixel position \a pos. If there is no element at that position,
10252   returns 0.
10253   
10254   Only visible elements are used. If \ref QCPLayoutElement::setVisible on the element itself or on
10255   any of its parent elements is set to false, it will not be considered.
10256   
10257   \see itemAt, plottableAt
10258 */
10259 QCPLayoutElement *QCustomPlot::layoutElementAt(const QPointF &pos) const
10260 {
10261   QCPLayoutElement *currentElement = mPlotLayout;
10262   bool searchSubElements = true;
10263   while (searchSubElements && currentElement)
10264   {
10265     searchSubElements = false;
10266     foreach (QCPLayoutElement *subElement, currentElement->elements(false))
10267     {
10268       if (subElement && subElement->realVisibility() && subElement->selectTest(pos, false) >= 0)
10269       {
10270         currentElement = subElement;
10271         searchSubElements = true;
10272         break;
10273       }
10274     }
10275   }
10276   return currentElement;
10277 }
10278
10279 /*!
10280   Returns the axes that currently have selected parts, i.e. whose selection state is not \ref
10281   QCPAxis::spNone.
10282   
10283   \see selectedPlottables, selectedLegends, setInteractions, QCPAxis::setSelectedParts,
10284   QCPAxis::setSelectableParts
10285 */
10286 QList<QCPAxis*> QCustomPlot::selectedAxes() const
10287 {
10288   QList<QCPAxis*> result, allAxes;
10289   foreach (QCPAxisRect *rect, axisRects())
10290     allAxes << rect->axes();
10291   
10292   foreach (QCPAxis *axis, allAxes)
10293   {
10294     if (axis->selectedParts() != QCPAxis::spNone)
10295       result.append(axis);
10296   }
10297   
10298   return result;
10299 }
10300
10301 /*!
10302   Returns the legends that currently have selected parts, i.e. whose selection state is not \ref
10303   QCPLegend::spNone.
10304   
10305   \see selectedPlottables, selectedAxes, setInteractions, QCPLegend::setSelectedParts,
10306   QCPLegend::setSelectableParts, QCPLegend::selectedItems
10307 */
10308 QList<QCPLegend*> QCustomPlot::selectedLegends() const
10309 {
10310   QList<QCPLegend*> result;
10311   
10312   QStack<QCPLayoutElement*> elementStack;
10313   if (mPlotLayout)
10314     elementStack.push(mPlotLayout);
10315   
10316   while (!elementStack.isEmpty())
10317   {
10318     foreach (QCPLayoutElement *subElement, elementStack.pop()->elements(false))
10319     {
10320       if (subElement)
10321       {
10322         elementStack.push(subElement);
10323         if (QCPLegend *leg = qobject_cast<QCPLegend*>(subElement))
10324         {
10325           if (leg->selectedParts() != QCPLegend::spNone)
10326             result.append(leg);
10327         }
10328       }
10329     }
10330   }
10331   
10332   return result;
10333 }
10334
10335 /*!
10336   Deselects all layerables (plottables, items, axes, legends,...) of the QCustomPlot.
10337   
10338   Since calling this function is not a user interaction, this does not emit the \ref
10339   selectionChangedByUser signal. The individual selectionChanged signals are emitted though, if the
10340   objects were previously selected.
10341   
10342   \see setInteractions, selectedPlottables, selectedItems, selectedAxes, selectedLegends
10343 */
10344 void QCustomPlot::deselectAll()
10345 {
10346   foreach (QCPLayer *layer, mLayers)
10347   {
10348     foreach (QCPLayerable *layerable, layer->children())
10349       layerable->deselectEvent(0);
10350   }
10351 }
10352
10353 /*!
10354   Causes a complete replot into the internal buffer. Finally, update() is called, to redraw the
10355   buffer on the QCustomPlot widget surface. This is the method that must be called to make changes,
10356   for example on the axis ranges or data points of graphs, visible.
10357   
10358   Under a few circumstances, QCustomPlot causes a replot by itself. Those are resize events of the
10359   QCustomPlot widget and user interactions (object selection and range dragging/zooming).
10360   
10361   Before the replot happens, the signal \ref beforeReplot is emitted. After the replot, \ref
10362   afterReplot is emitted. It is safe to mutually connect the replot slot with any of those two
10363   signals on two QCustomPlots to make them replot synchronously, it won't cause an infinite
10364   recursion.
10365 */
10366 void QCustomPlot::replot(QCustomPlot::RefreshPriority refreshPriority)
10367 {
10368   if (mReplotting) // incase signals loop back to replot slot
10369     return;
10370   mReplotting = true;
10371   emit beforeReplot();
10372   
10373   mPaintBuffer.fill(mBackgroundBrush.style() == Qt::SolidPattern ? mBackgroundBrush.color() : Qt::transparent);
10374   QCPPainter painter;
10375   painter.begin(&mPaintBuffer);
10376   if (painter.isActive())
10377   {
10378     painter.setRenderHint(QPainter::HighQualityAntialiasing); // to make Antialiasing look good if using the OpenGL graphicssystem
10379     if (mBackgroundBrush.style() != Qt::SolidPattern && mBackgroundBrush.style() != Qt::NoBrush)
10380       painter.fillRect(mViewport, mBackgroundBrush);
10381     draw(&painter);
10382     painter.end();
10383     if ((refreshPriority == rpHint && mPlottingHints.testFlag(QCP::phForceRepaint)) || refreshPriority==rpImmediate)
10384       repaint();
10385     else
10386       update();
10387   } else // might happen if QCustomPlot has width or height zero
10388     qDebug() << Q_FUNC_INFO << "Couldn't activate painter on buffer. This usually happens because QCustomPlot has width or height zero.";
10389   
10390   emit afterReplot();
10391   mReplotting = false;
10392 }
10393
10394 /*!
10395   Rescales the axes such that all plottables (like graphs) in the plot are fully visible.
10396   
10397   if \a onlyVisiblePlottables is set to true, only the plottables that have their visibility set to true
10398   (QCPLayerable::setVisible), will be used to rescale the axes.
10399   
10400   \see QCPAbstractPlottable::rescaleAxes, QCPAxis::rescale
10401 */
10402 void QCustomPlot::rescaleAxes(bool onlyVisiblePlottables)
10403 {
10404   QList<QCPAxis*> allAxes;
10405   foreach (QCPAxisRect *rect, axisRects())
10406     allAxes << rect->axes();
10407   
10408   foreach (QCPAxis *axis, allAxes)
10409     axis->rescale(onlyVisiblePlottables);
10410 }
10411
10412 /*!
10413   Saves a PDF with the vectorized plot to the file \a fileName. The axis ratio as well as the scale
10414   of texts and lines will be derived from the specified \a width and \a height. This means, the
10415   output will look like the normal on-screen output of a QCustomPlot widget with the corresponding
10416   pixel width and height. If either \a width or \a height is zero, the exported image will have the
10417   same dimensions as the QCustomPlot widget currently has.
10418
10419   \a noCosmeticPen disables the use of cosmetic pens when drawing to the PDF file. Cosmetic pens
10420   are pens with numerical width 0, which are always drawn as a one pixel wide line, no matter what
10421   zoom factor is set in the PDF-Viewer. For more information about cosmetic pens, see the QPainter
10422   and QPen documentation.
10423   
10424   The objects of the plot will appear in the current selection state. If you don't want any
10425   selected objects to be painted in their selected look, deselect everything with \ref deselectAll
10426   before calling this function.
10427
10428   Returns true on success.
10429   
10430   \warning
10431   \li If you plan on editing the exported PDF file with a vector graphics editor like
10432   Inkscape, it is advised to set \a noCosmeticPen to true to avoid losing those cosmetic lines
10433   (which might be quite many, because cosmetic pens are the default for e.g. axes and tick marks).
10434   \li If calling this function inside the constructor of the parent of the QCustomPlot widget
10435   (i.e. the MainWindow constructor, if QCustomPlot is inside the MainWindow), always provide
10436   explicit non-zero widths and heights. If you leave \a width or \a height as 0 (default), this
10437   function uses the current width and height of the QCustomPlot widget. However, in Qt, these
10438   aren't defined yet inside the constructor, so you would get an image that has strange
10439   widths/heights.
10440   
10441   \a pdfCreator and \a pdfTitle may be used to set the according metadata fields in the resulting
10442   PDF file.
10443   
10444   \note On Android systems, this method does nothing and issues an according qDebug warning
10445   message. This is also the case if for other reasons the define flag QT_NO_PRINTER is set.
10446   
10447   \see savePng, saveBmp, saveJpg, saveRastered
10448 */
10449 bool QCustomPlot::savePdf(const QString &fileName, bool noCosmeticPen, int width, int height, const QString &pdfCreator, const QString &pdfTitle)
10450 {
10451   bool success = false;
10452 #ifdef QT_NO_PRINTER
10453   Q_UNUSED(fileName)
10454   Q_UNUSED(noCosmeticPen)
10455   Q_UNUSED(width)
10456   Q_UNUSED(height)
10457   Q_UNUSED(pdfCreator)
10458   Q_UNUSED(pdfTitle)
10459   qDebug() << Q_FUNC_INFO << "Qt was built without printer support (QT_NO_PRINTER). PDF not created.";
10460 #else
10461   int newWidth, newHeight;
10462   if (width == 0 || height == 0)
10463   {
10464     newWidth = this->width();
10465     newHeight = this->height();
10466   } else
10467   {
10468     newWidth = width;
10469     newHeight = height;
10470   }
10471   
10472   QPrinter printer(QPrinter::ScreenResolution);
10473   printer.setOutputFileName(fileName);
10474   printer.setOutputFormat(QPrinter::PdfFormat);
10475   printer.setColorMode(QPrinter::Color);
10476   printer.printEngine()->setProperty(QPrintEngine::PPK_Creator, pdfCreator);
10477   printer.printEngine()->setProperty(QPrintEngine::PPK_DocumentName, pdfTitle);
10478   QRect oldViewport = viewport();
10479   setViewport(QRect(0, 0, newWidth, newHeight));
10480 #if QT_VERSION < QT_VERSION_CHECK(5, 3, 0)
10481   printer.setFullPage(true);
10482   printer.setPaperSize(viewport().size(), QPrinter::DevicePixel);
10483 #else
10484   QPageLayout pageLayout;
10485   pageLayout.setMode(QPageLayout::FullPageMode);
10486   pageLayout.setOrientation(QPageLayout::Portrait);
10487   pageLayout.setMargins(QMarginsF(0, 0, 0, 0));
10488   pageLayout.setPageSize(QPageSize(viewport().size(), QPageSize::Point, QString(), QPageSize::ExactMatch));
10489   printer.setPageLayout(pageLayout);
10490 #endif
10491   QCPPainter printpainter;
10492   if (printpainter.begin(&printer))
10493   {
10494     printpainter.setMode(QCPPainter::pmVectorized);
10495     printpainter.setMode(QCPPainter::pmNoCaching);
10496     printpainter.setMode(QCPPainter::pmNonCosmetic, noCosmeticPen);
10497     printpainter.setWindow(mViewport);
10498     if (mBackgroundBrush.style() != Qt::NoBrush &&
10499         mBackgroundBrush.color() != Qt::white &&
10500         mBackgroundBrush.color() != Qt::transparent &&
10501         mBackgroundBrush.color().alpha() > 0) // draw pdf background color if not white/transparent
10502       printpainter.fillRect(viewport(), mBackgroundBrush);
10503     draw(&printpainter);
10504     printpainter.end();
10505     success = true;
10506   }
10507   setViewport(oldViewport);
10508 #endif // QT_NO_PRINTER
10509   return success;
10510 }
10511
10512 /*!
10513   Saves a PNG image file to \a fileName on disc. The output plot will have the dimensions \a width
10514   and \a height in pixels. If either \a width or \a height is zero, the exported image will have
10515   the same dimensions as the QCustomPlot widget currently has. Line widths and texts etc. are not
10516   scaled up when larger widths/heights are used. If you want that effect, use the \a scale parameter.
10517
10518   For example, if you set both \a width and \a height to 100 and \a scale to 2, you will end up with an
10519   image file of size 200*200 in which all graphical elements are scaled up by factor 2 (line widths,
10520   texts, etc.). This scaling is not done by stretching a 100*100 image, the result will have full
10521   200*200 pixel resolution.
10522   
10523   If you use a high scaling factor, it is recommended to enable antialiasing for all elements via
10524   temporarily setting \ref QCustomPlot::setAntialiasedElements to \ref QCP::aeAll as this allows
10525   QCustomPlot to place objects with sub-pixel accuracy.
10526
10527   \warning If calling this function inside the constructor of the parent of the QCustomPlot widget
10528   (i.e. the MainWindow constructor, if QCustomPlot is inside the MainWindow), always provide
10529   explicit non-zero widths and heights. If you leave \a width or \a height as 0 (default), this
10530   function uses the current width and height of the QCustomPlot widget. However, in Qt, these
10531   aren't defined yet inside the constructor, so you would get an image that has strange
10532   widths/heights.
10533   
10534   The objects of the plot will appear in the current selection state. If you don't want any selected
10535   objects to be painted in their selected look, deselect everything with \ref deselectAll before calling
10536   this function.
10537
10538   If you want the PNG to have a transparent background, call \ref setBackground(const QBrush
10539   &brush) with no brush (Qt::NoBrush) or a transparent color (Qt::transparent), before saving.
10540
10541   PNG compression can be controlled with the \a quality parameter which must be between 0 and 100 or
10542   -1 to use the default setting.
10543   
10544   Returns true on success. If this function fails, most likely the PNG format isn't supported by
10545   the system, see Qt docs about QImageWriter::supportedImageFormats().
10546
10547   \see savePdf, saveBmp, saveJpg, saveRastered
10548 */
10549 bool QCustomPlot::savePng(const QString &fileName, int width, int height, double scale, int quality)
10550 {
10551   return saveRastered(fileName, width, height, scale, "PNG", quality);
10552 }
10553
10554 /*!
10555   Saves a JPG image file to \a fileName on disc. The output plot will have the dimensions \a width
10556   and \a height in pixels. If either \a width or \a height is zero, the exported image will have
10557   the same dimensions as the QCustomPlot widget currently has. Line widths and texts etc. are not
10558   scaled up when larger widths/heights are used. If you want that effect, use the \a scale parameter.
10559
10560   For example, if you set both \a width and \a height to 100 and \a scale to 2, you will end up with an
10561   image file of size 200*200 in which all graphical elements are scaled up by factor 2 (line widths,
10562   texts, etc.). This scaling is not done by stretching a 100*100 image, the result will have full
10563   200*200 pixel resolution.
10564   
10565   If you use a high scaling factor, it is recommended to enable antialiasing for all elements via
10566   temporarily setting \ref QCustomPlot::setAntialiasedElements to \ref QCP::aeAll as this allows
10567   QCustomPlot to place objects with sub-pixel accuracy.
10568
10569   \warning If calling this function inside the constructor of the parent of the QCustomPlot widget
10570   (i.e. the MainWindow constructor, if QCustomPlot is inside the MainWindow), always provide
10571   explicit non-zero widths and heights. If you leave \a width or \a height as 0 (default), this
10572   function uses the current width and height of the QCustomPlot widget. However, in Qt, these
10573   aren't defined yet inside the constructor, so you would get an image that has strange
10574   widths/heights.
10575
10576   The objects of the plot will appear in the current selection state. If you don't want any selected
10577   objects to be painted in their selected look, deselect everything with \ref deselectAll before calling
10578   this function.
10579
10580   JPG compression can be controlled with the \a quality parameter which must be between 0 and 100 or
10581   -1 to use the default setting.
10582   
10583   Returns true on success. If this function fails, most likely the JPG format isn't supported by
10584   the system, see Qt docs about QImageWriter::supportedImageFormats().
10585
10586   \see savePdf, savePng, saveBmp, saveRastered
10587 */
10588 bool QCustomPlot::saveJpg(const QString &fileName, int width, int height, double scale, int quality)
10589 {
10590   return saveRastered(fileName, width, height, scale, "JPG", quality);
10591 }
10592
10593 /*!
10594   Saves a BMP image file to \a fileName on disc. The output plot will have the dimensions \a width
10595   and \a height in pixels. If either \a width or \a height is zero, the exported image will have
10596   the same dimensions as the QCustomPlot widget currently has. Line widths and texts etc. are not
10597   scaled up when larger widths/heights are used. If you want that effect, use the \a scale parameter.
10598
10599   For example, if you set both \a width and \a height to 100 and \a scale to 2, you will end up with an
10600   image file of size 200*200 in which all graphical elements are scaled up by factor 2 (line widths,
10601   texts, etc.). This scaling is not done by stretching a 100*100 image, the result will have full
10602   200*200 pixel resolution.
10603   
10604   If you use a high scaling factor, it is recommended to enable antialiasing for all elements via
10605   temporarily setting \ref QCustomPlot::setAntialiasedElements to \ref QCP::aeAll as this allows
10606   QCustomPlot to place objects with sub-pixel accuracy.
10607
10608   \warning If calling this function inside the constructor of the parent of the QCustomPlot widget
10609   (i.e. the MainWindow constructor, if QCustomPlot is inside the MainWindow), always provide
10610   explicit non-zero widths and heights. If you leave \a width or \a height as 0 (default), this
10611   function uses the current width and height of the QCustomPlot widget. However, in Qt, these
10612   aren't defined yet inside the constructor, so you would get an image that has strange
10613   widths/heights.
10614
10615   The objects of the plot will appear in the current selection state. If you don't want any selected
10616   objects to be painted in their selected look, deselect everything with \ref deselectAll before calling
10617   this function.
10618   
10619   Returns true on success. If this function fails, most likely the BMP format isn't supported by
10620   the system, see Qt docs about QImageWriter::supportedImageFormats().
10621
10622   \see savePdf, savePng, saveJpg, saveRastered
10623 */
10624 bool QCustomPlot::saveBmp(const QString &fileName, int width, int height, double scale)
10625 {
10626   return saveRastered(fileName, width, height, scale, "BMP");
10627 }
10628
10629 /*! \internal
10630   
10631   Returns a minimum size hint that corresponds to the minimum size of the top level layout
10632   (\ref plotLayout). To prevent QCustomPlot from being collapsed to size/width zero, set a minimum
10633   size (setMinimumSize) either on the whole QCustomPlot or on any layout elements inside the plot.
10634   This is especially important, when placed in a QLayout where other components try to take in as
10635   much space as possible (e.g. QMdiArea).
10636 */
10637 QSize QCustomPlot::minimumSizeHint() const
10638 {
10639   return mPlotLayout->minimumSizeHint();
10640 }
10641
10642 /*! \internal
10643   
10644   Returns a size hint that is the same as \ref minimumSizeHint.
10645   
10646 */
10647 QSize QCustomPlot::sizeHint() const
10648 {
10649   return mPlotLayout->minimumSizeHint();
10650 }
10651
10652 /*! \internal
10653   
10654   Event handler for when the QCustomPlot widget needs repainting. This does not cause a \ref replot, but
10655   draws the internal buffer on the widget surface.
10656 */
10657 void QCustomPlot::paintEvent(QPaintEvent *event)
10658 {
10659   Q_UNUSED(event);
10660   QPainter painter(this);
10661   painter.drawPixmap(0, 0, mPaintBuffer);
10662 }
10663
10664 /*! \internal
10665   
10666   Event handler for a resize of the QCustomPlot widget. Causes the internal buffer to be resized to
10667   the new size. The viewport (which becomes the outer rect of mPlotLayout) is resized
10668   appropriately. Finally a \ref replot is performed.
10669 */
10670 void QCustomPlot::resizeEvent(QResizeEvent *event)
10671 {
10672   // resize and repaint the buffer:
10673   mPaintBuffer = QPixmap(event->size());
10674   setViewport(rect());
10675   replot(rpQueued); // queued update is important here, to prevent painting issues in some contexts
10676 }
10677
10678 /*! \internal
10679   
10680  Event handler for when a double click occurs. Emits the \ref mouseDoubleClick signal, then emits
10681  the specialized signals when certain objecs are clicked (e.g. \ref plottableDoubleClick, \ref
10682  axisDoubleClick, etc.). Finally determines the affected layout element and forwards the event to
10683  it.
10684  
10685  \see mousePressEvent, mouseReleaseEvent
10686 */
10687 void QCustomPlot::mouseDoubleClickEvent(QMouseEvent *event)
10688 {
10689   emit mouseDoubleClick(event);
10690   
10691   QVariant details;
10692   QCPLayerable *clickedLayerable = layerableAt(event->pos(), false, &details);
10693   
10694   // emit specialized object double click signals:
10695   if (QCPAbstractPlottable *ap = qobject_cast<QCPAbstractPlottable*>(clickedLayerable))
10696     emit plottableDoubleClick(ap, event);
10697   else if (QCPAxis *ax = qobject_cast<QCPAxis*>(clickedLayerable))
10698     emit axisDoubleClick(ax, details.value<QCPAxis::SelectablePart>(), event);
10699   else if (QCPAbstractItem *ai = qobject_cast<QCPAbstractItem*>(clickedLayerable))
10700     emit itemDoubleClick(ai, event);
10701   else if (QCPLegend *lg = qobject_cast<QCPLegend*>(clickedLayerable))
10702     emit legendDoubleClick(lg, 0, event);
10703   else if (QCPAbstractLegendItem *li = qobject_cast<QCPAbstractLegendItem*>(clickedLayerable))
10704     emit legendDoubleClick(li->parentLegend(), li, event);
10705   else if (QCPPlotTitle *pt = qobject_cast<QCPPlotTitle*>(clickedLayerable))
10706     emit titleDoubleClick(event, pt);
10707   
10708   // call double click event of affected layout element:
10709   if (QCPLayoutElement *el = layoutElementAt(event->pos()))
10710     el->mouseDoubleClickEvent(event);
10711   
10712   // call release event of affected layout element (as in mouseReleaseEvent, since the mouseDoubleClick replaces the second release event in double click case):
10713   if (mMouseEventElement)
10714   {
10715     mMouseEventElement->mouseReleaseEvent(event);
10716     mMouseEventElement = 0;
10717   }
10718   
10719   //QWidget::mouseDoubleClickEvent(event); don't call base class implementation because it would just cause a mousePress/ReleaseEvent, which we don't want.
10720 }
10721
10722 /*! \internal
10723   
10724   Event handler for when a mouse button is pressed. Emits the mousePress signal. Then determines
10725   the affected layout element and forwards the event to it.
10726   
10727   \see mouseMoveEvent, mouseReleaseEvent
10728 */
10729 void QCustomPlot::mousePressEvent(QMouseEvent *event)
10730 {
10731   emit mousePress(event);
10732   mMousePressPos = event->pos(); // need this to determine in releaseEvent whether it was a click (no position change between press and release)
10733   
10734   // call event of affected layout element:
10735   mMouseEventElement = layoutElementAt(event->pos());
10736   if (mMouseEventElement)
10737     mMouseEventElement->mousePressEvent(event);
10738   
10739   QWidget::mousePressEvent(event);
10740 }
10741
10742 /*! \internal
10743   
10744   Event handler for when the cursor is moved. Emits the \ref mouseMove signal.
10745
10746   If a layout element has mouse capture focus (a mousePressEvent happened on top of the layout
10747   element before), the mouseMoveEvent is forwarded to that element.
10748   
10749   \see mousePressEvent, mouseReleaseEvent
10750 */
10751 void QCustomPlot::mouseMoveEvent(QMouseEvent *event)
10752 {
10753   emit mouseMove(event);
10754
10755   // call event of affected layout element:
10756   if (mMouseEventElement)
10757     mMouseEventElement->mouseMoveEvent(event);
10758   
10759   QWidget::mouseMoveEvent(event);
10760 }
10761
10762 /*! \internal
10763   
10764   Event handler for when a mouse button is released. Emits the \ref mouseRelease signal.
10765   
10766   If the mouse was moved less than a certain threshold in any direction since the \ref
10767   mousePressEvent, it is considered a click which causes the selection mechanism (if activated via
10768   \ref setInteractions) to possibly change selection states accordingly. Further, specialized mouse
10769   click signals are emitted (e.g. \ref plottableClick, \ref axisClick, etc.)
10770   
10771   If a layout element has mouse capture focus (a \ref mousePressEvent happened on top of the layout
10772   element before), the \ref mouseReleaseEvent is forwarded to that element.
10773   
10774   \see mousePressEvent, mouseMoveEvent
10775 */
10776 void QCustomPlot::mouseReleaseEvent(QMouseEvent *event)
10777 {
10778   emit mouseRelease(event);
10779   bool doReplot = false;
10780   
10781   if ((mMousePressPos-event->pos()).manhattanLength() < 5) // determine whether it was a click operation
10782   {
10783     if (event->button() == Qt::LeftButton)
10784     {
10785       // handle selection mechanism:
10786       QVariant details;
10787       QCPLayerable *clickedLayerable = layerableAt(event->pos(), true, &details);
10788       bool selectionStateChanged = false;
10789       bool additive = mInteractions.testFlag(QCP::iMultiSelect) && event->modifiers().testFlag(mMultiSelectModifier);
10790       // deselect all other layerables if not additive selection:
10791       if (!additive)
10792       {
10793         foreach (QCPLayer *layer, mLayers)
10794         {
10795           foreach (QCPLayerable *layerable, layer->children())
10796           {
10797             if (layerable != clickedLayerable && mInteractions.testFlag(layerable->selectionCategory()))
10798             {
10799               bool selChanged = false;
10800               layerable->deselectEvent(&selChanged);
10801               selectionStateChanged |= selChanged;
10802             }
10803           }
10804         }
10805       }
10806       if (clickedLayerable && mInteractions.testFlag(clickedLayerable->selectionCategory()))
10807       {
10808         // a layerable was actually clicked, call its selectEvent:
10809         bool selChanged = false;
10810         clickedLayerable->selectEvent(event, additive, details, &selChanged);
10811         selectionStateChanged |= selChanged;
10812       }
10813       if (selectionStateChanged)
10814       {
10815         doReplot = true;
10816         emit selectionChangedByUser();
10817       }
10818     }
10819     
10820     // emit specialized object click signals:
10821     QVariant details;
10822     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
10823     if (QCPAbstractPlottable *ap = qobject_cast<QCPAbstractPlottable*>(clickedLayerable))
10824       emit plottableClick(ap, event);
10825     else if (QCPAxis *ax = qobject_cast<QCPAxis*>(clickedLayerable))
10826       emit axisClick(ax, details.value<QCPAxis::SelectablePart>(), event);
10827     else if (QCPAbstractItem *ai = qobject_cast<QCPAbstractItem*>(clickedLayerable))
10828       emit itemClick(ai, event);
10829     else if (QCPLegend *lg = qobject_cast<QCPLegend*>(clickedLayerable))
10830       emit legendClick(lg, 0, event);
10831     else if (QCPAbstractLegendItem *li = qobject_cast<QCPAbstractLegendItem*>(clickedLayerable))
10832       emit legendClick(li->parentLegend(), li, event);
10833     else if (QCPPlotTitle *pt = qobject_cast<QCPPlotTitle*>(clickedLayerable))
10834       emit titleClick(event, pt);
10835   }
10836   
10837   // call event of affected layout element:
10838   if (mMouseEventElement)
10839   {
10840     mMouseEventElement->mouseReleaseEvent(event);
10841     mMouseEventElement = 0;
10842   }
10843   
10844   if (doReplot || noAntialiasingOnDrag())
10845     replot();
10846   
10847   QWidget::mouseReleaseEvent(event);
10848 }
10849
10850 /*! \internal
10851   
10852   Event handler for mouse wheel events. First, the \ref mouseWheel signal is emitted. Then
10853   determines the affected layout element and forwards the event to it.
10854   
10855 */
10856 void QCustomPlot::wheelEvent(QWheelEvent *event)
10857 {
10858   emit mouseWheel(event);
10859   
10860   // call event of affected layout element:
10861   if (QCPLayoutElement *el = layoutElementAt(event->pos()))
10862     el->wheelEvent(event);
10863   
10864   QWidget::wheelEvent(event);
10865 }
10866
10867 /*! \internal
10868   
10869   This is the main draw function. It draws the entire plot, including background pixmap, with the
10870   specified \a painter. Note that it does not fill the background with the background brush (as the
10871   user may specify with \ref setBackground(const QBrush &brush)), this is up to the respective
10872   functions calling this method (e.g. \ref replot, \ref toPixmap and \ref toPainter).
10873 */
10874 void QCustomPlot::draw(QCPPainter *painter)
10875 {
10876   // run through layout phases:
10877   mPlotLayout->update(QCPLayoutElement::upPreparation);
10878   mPlotLayout->update(QCPLayoutElement::upMargins);
10879   mPlotLayout->update(QCPLayoutElement::upLayout);
10880   
10881   // draw viewport background pixmap:
10882   drawBackground(painter);
10883
10884   // draw all layered objects (grid, axes, plottables, items, legend,...):
10885   foreach (QCPLayer *layer, mLayers)
10886   {
10887     foreach (QCPLayerable *child, layer->children())
10888     {
10889       if (child->realVisibility())
10890       {
10891         painter->save();
10892         painter->setClipRect(child->clipRect().translated(0, -1));
10893         child->applyDefaultAntialiasingHint(painter);
10894         child->draw(painter);
10895         painter->restore();
10896       }
10897     }
10898   }
10899   
10900   /* Debug code to draw all layout element rects
10901   foreach (QCPLayoutElement* el, findChildren<QCPLayoutElement*>())
10902   {
10903     painter->setBrush(Qt::NoBrush);
10904     painter->setPen(QPen(QColor(0, 0, 0, 100), 0, Qt::DashLine));
10905     painter->drawRect(el->rect());
10906     painter->setPen(QPen(QColor(255, 0, 0, 100), 0, Qt::DashLine));
10907     painter->drawRect(el->outerRect());
10908   }
10909   */
10910 }
10911
10912 /*! \internal
10913   
10914   Draws the viewport background pixmap of the plot.
10915   
10916   If a pixmap was provided via \ref setBackground, this function buffers the scaled version
10917   depending on \ref setBackgroundScaled and \ref setBackgroundScaledMode and then draws it inside
10918   the viewport with the provided \a painter. The scaled version is buffered in
10919   mScaledBackgroundPixmap to prevent expensive rescaling at every redraw. It is only updated, when
10920   the axis rect has changed in a way that requires a rescale of the background pixmap (this is
10921   dependent on the \ref setBackgroundScaledMode), or when a differend axis background pixmap was
10922   set.
10923   
10924   Note that this function does not draw a fill with the background brush (\ref setBackground(const
10925   QBrush &brush)) beneath the pixmap.
10926   
10927   \see setBackground, setBackgroundScaled, setBackgroundScaledMode
10928 */
10929 void QCustomPlot::drawBackground(QCPPainter *painter)
10930 {
10931   // Note: background color is handled in individual replot/save functions
10932
10933   // draw background pixmap (on top of fill, if brush specified):
10934   if (!mBackgroundPixmap.isNull())
10935   {
10936     if (mBackgroundScaled)
10937     {
10938       // check whether mScaledBackground needs to be updated:
10939       QSize scaledSize(mBackgroundPixmap.size());
10940       scaledSize.scale(mViewport.size(), mBackgroundScaledMode);
10941       if (mScaledBackgroundPixmap.size() != scaledSize)
10942         mScaledBackgroundPixmap = mBackgroundPixmap.scaled(mViewport.size(), mBackgroundScaledMode, Qt::SmoothTransformation);
10943       painter->drawPixmap(mViewport.topLeft(), mScaledBackgroundPixmap, QRect(0, 0, mViewport.width(), mViewport.height()) & mScaledBackgroundPixmap.rect());
10944     } else
10945     {
10946       painter->drawPixmap(mViewport.topLeft(), mBackgroundPixmap, QRect(0, 0, mViewport.width(), mViewport.height()));
10947     }
10948   }
10949 }
10950
10951
10952 /*! \internal
10953   
10954   This method is used by \ref QCPAxisRect::removeAxis to report removed axes to the QCustomPlot
10955   so it may clear its QCustomPlot::xAxis, yAxis, xAxis2 and yAxis2 members accordingly.
10956 */
10957 void QCustomPlot::axisRemoved(QCPAxis *axis)
10958 {
10959   if (xAxis == axis)
10960     xAxis = 0;
10961   if (xAxis2 == axis)
10962     xAxis2 = 0;
10963   if (yAxis == axis)
10964     yAxis = 0;
10965   if (yAxis2 == axis)
10966     yAxis2 = 0;
10967   
10968   // Note: No need to take care of range drag axes and range zoom axes, because they are stored in smart pointers
10969 }
10970
10971 /*! \internal
10972   
10973   This method is used by the QCPLegend destructor to report legend removal to the QCustomPlot so
10974   it may clear its QCustomPlot::legend member accordingly.
10975 */
10976 void QCustomPlot::legendRemoved(QCPLegend *legend)
10977 {
10978   if (this->legend == legend)
10979     this->legend = 0;
10980 }
10981
10982 /*! \internal
10983   
10984   Assigns all layers their index (QCPLayer::mIndex) in the mLayers list. This method is thus called
10985   after every operation that changes the layer indices, like layer removal, layer creation, layer
10986   moving.
10987 */
10988 void QCustomPlot::updateLayerIndices() const
10989 {
10990   for (int i=0; i<mLayers.size(); ++i)
10991     mLayers.at(i)->mIndex = i;
10992 }
10993
10994 /*! \internal
10995   
10996   Returns the layerable at pixel position \a pos. If \a onlySelectable is set to true, only those
10997   layerables that are selectable will be considered. (Layerable subclasses communicate their
10998   selectability via the QCPLayerable::selectTest method, by returning -1.)
10999
11000   \a selectionDetails is an output parameter that contains selection specifics of the affected
11001   layerable. This is useful if the respective layerable shall be given a subsequent
11002   QCPLayerable::selectEvent (like in \ref mouseReleaseEvent). \a selectionDetails usually contains
11003   information about which part of the layerable was hit, in multi-part layerables (e.g.
11004   QCPAxis::SelectablePart).
11005 */
11006 QCPLayerable *QCustomPlot::layerableAt(const QPointF &pos, bool onlySelectable, QVariant *selectionDetails) const
11007 {
11008   for (int layerIndex=mLayers.size()-1; layerIndex>=0; --layerIndex)
11009   {
11010     const QList<QCPLayerable*> layerables = mLayers.at(layerIndex)->children();
11011     double minimumDistance = selectionTolerance()*1.1;
11012     QCPLayerable *minimumDistanceLayerable = 0;
11013     for (int i=layerables.size()-1; i>=0; --i)
11014     {
11015       if (!layerables.at(i)->realVisibility())
11016         continue;
11017       QVariant details;
11018       double dist = layerables.at(i)->selectTest(pos, onlySelectable, &details);
11019       if (dist >= 0 && dist < minimumDistance)
11020       {
11021         minimumDistance = dist;
11022         minimumDistanceLayerable = layerables.at(i);
11023         if (selectionDetails) *selectionDetails = details;
11024       }
11025     }
11026     if (minimumDistance < selectionTolerance())
11027       return minimumDistanceLayerable;
11028   }
11029   return 0;
11030 }
11031
11032 /*!
11033   Saves the plot to a rastered image file \a fileName in the image format \a format. The plot is
11034   sized to \a width and \a height in pixels and scaled with \a scale. (width 100 and scale 2.0 lead
11035   to a full resolution file with width 200.) If the \a format supports compression, \a quality may
11036   be between 0 and 100 to control it.
11037   
11038   Returns true on success. If this function fails, most likely the given \a format isn't supported
11039   by the system, see Qt docs about QImageWriter::supportedImageFormats().
11040   
11041   \see saveBmp, saveJpg, savePng, savePdf
11042 */
11043 bool QCustomPlot::saveRastered(const QString &fileName, int width, int height, double scale, const char *format, int quality)
11044 {
11045   QPixmap buffer = toPixmap(width, height, scale);
11046   if (!buffer.isNull())
11047     return buffer.save(fileName, format, quality);
11048   else
11049     return false;
11050 }
11051
11052 /*!
11053   Renders the plot to a pixmap and returns it.
11054   
11055   The plot is sized to \a width and \a height in pixels and scaled with \a scale. (width 100 and
11056   scale 2.0 lead to a full resolution pixmap with width 200.)
11057   
11058   \see toPainter, saveRastered, saveBmp, savePng, saveJpg, savePdf
11059 */
11060 QPixmap QCustomPlot::toPixmap(int width, int height, double scale)
11061 {
11062   // this method is somewhat similar to toPainter. Change something here, and a change in toPainter might be necessary, too.
11063   int newWidth, newHeight;
11064   if (width == 0 || height == 0)
11065   {
11066     newWidth = this->width();
11067     newHeight = this->height();
11068   } else
11069   {
11070     newWidth = width;
11071     newHeight = height;
11072   }
11073   int scaledWidth = qRound(scale*newWidth);
11074   int scaledHeight = qRound(scale*newHeight);
11075
11076   QPixmap result(scaledWidth, scaledHeight);
11077   result.fill(mBackgroundBrush.style() == Qt::SolidPattern ? mBackgroundBrush.color() : Qt::transparent); // if using non-solid pattern, make transparent now and draw brush pattern later
11078   QCPPainter painter;
11079   painter.begin(&result);
11080   if (painter.isActive())
11081   {
11082     QRect oldViewport = viewport();
11083     setViewport(QRect(0, 0, newWidth, newHeight));
11084     painter.setMode(QCPPainter::pmNoCaching);
11085     if (!qFuzzyCompare(scale, 1.0))
11086     {
11087       if (scale > 1.0) // for scale < 1 we always want cosmetic pens where possible, because else lines might disappear for very small scales
11088         painter.setMode(QCPPainter::pmNonCosmetic);
11089       painter.scale(scale, scale);
11090     }
11091     if (mBackgroundBrush.style() != Qt::SolidPattern && mBackgroundBrush.style() != Qt::NoBrush) // solid fills were done a few lines above with QPixmap::fill
11092       painter.fillRect(mViewport, mBackgroundBrush);
11093     draw(&painter);
11094     setViewport(oldViewport);
11095     painter.end();
11096   } else // might happen if pixmap has width or height zero
11097   {
11098     qDebug() << Q_FUNC_INFO << "Couldn't activate painter on pixmap";
11099     return QPixmap();
11100   }
11101   return result;
11102 }
11103
11104 /*!
11105   Renders the plot using the passed \a painter.
11106   
11107   The plot is sized to \a width and \a height in pixels. If the \a painter's scale is not 1.0, the resulting plot will
11108   appear scaled accordingly.
11109   
11110   \note If you are restricted to using a QPainter (instead of QCPPainter), create a temporary QPicture and open a QCPPainter
11111   on it. Then call \ref toPainter with this QCPPainter. After ending the paint operation on the picture, draw it with
11112   the QPainter. This will reproduce the painter actions the QCPPainter took, with a QPainter.
11113   
11114   \see toPixmap
11115 */
11116 void QCustomPlot::toPainter(QCPPainter *painter, int width, int height)
11117 {
11118   // this method is somewhat similar to toPixmap. Change something here, and a change in toPixmap might be necessary, too.
11119   int newWidth, newHeight;
11120   if (width == 0 || height == 0)
11121   {
11122     newWidth = this->width();
11123     newHeight = this->height();
11124   } else
11125   {
11126     newWidth = width;
11127     newHeight = height;
11128   }
11129
11130   if (painter->isActive())
11131   {
11132     QRect oldViewport = viewport();
11133     setViewport(QRect(0, 0, newWidth, newHeight));
11134     painter->setMode(QCPPainter::pmNoCaching);
11135     if (mBackgroundBrush.style() != Qt::NoBrush) // unlike in toPixmap, we can't do QPixmap::fill for Qt::SolidPattern brush style, so we also draw solid fills with fillRect here
11136       painter->fillRect(mViewport, mBackgroundBrush);
11137     draw(painter);
11138     setViewport(oldViewport);
11139   } else
11140     qDebug() << Q_FUNC_INFO << "Passed painter is not active";
11141 }
11142
11143
11144 ////////////////////////////////////////////////////////////////////////////////////////////////////
11145 //////////////////// QCPColorGradient
11146 ////////////////////////////////////////////////////////////////////////////////////////////////////
11147
11148 /*! \class QCPColorGradient
11149   \brief Defines a color gradient for use with e.g. \ref QCPColorMap
11150   
11151   This class describes a color gradient which can be used to encode data with color. For example,
11152   QCPColorMap and QCPColorScale have \ref QCPColorMap::setGradient "setGradient" methods which
11153   take an instance of this class. Colors are set with \ref setColorStopAt(double position, const QColor &color)
11154   with a \a position from 0 to 1. In between these defined color positions, the
11155   color will be interpolated linearly either in RGB or HSV space, see \ref setColorInterpolation.
11156
11157   Alternatively, load one of the preset color gradients shown in the image below, with \ref
11158   loadPreset, or by directly specifying the preset in the constructor.
11159   
11160   \image html QCPColorGradient.png
11161   
11162   The fact that the \ref QCPColorGradient(GradientPreset preset) constructor allows directly
11163   converting a \ref GradientPreset to a QCPColorGradient, you can also directly pass \ref
11164   GradientPreset to all the \a setGradient methods, e.g.:
11165   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpcolorgradient-setgradient
11166   
11167   The total number of levels used in the gradient can be set with \ref setLevelCount. Whether the
11168   color gradient shall be applied periodically (wrapping around) to data values that lie outside
11169   the data range specified on the plottable instance can be controlled with \ref setPeriodic.
11170 */
11171
11172 /*!
11173   Constructs a new QCPColorGradient initialized with the colors and color interpolation according
11174   to \a preset.
11175   
11176   The color level count is initialized to 350.
11177 */
11178 QCPColorGradient::QCPColorGradient(GradientPreset preset) :
11179   mLevelCount(350),
11180   mColorInterpolation(ciRGB),
11181   mPeriodic(false),
11182   mColorBufferInvalidated(true)
11183 {
11184   mColorBuffer.fill(qRgb(0, 0, 0), mLevelCount);
11185   loadPreset(preset);
11186 }
11187
11188 /* undocumented operator */
11189 bool QCPColorGradient::operator==(const QCPColorGradient &other) const
11190 {
11191   return ((other.mLevelCount == this->mLevelCount) &&
11192           (other.mColorInterpolation == this->mColorInterpolation) &&
11193           (other.mPeriodic == this->mPeriodic) &&
11194           (other.mColorStops == this->mColorStops));
11195 }
11196
11197 /*!
11198   Sets the number of discretization levels of the color gradient to \a n. The default is 350 which
11199   is typically enough to create a smooth appearance.
11200   
11201   \image html QCPColorGradient-levelcount.png
11202 */
11203 void QCPColorGradient::setLevelCount(int n)
11204 {
11205   if (n < 2)
11206   {
11207     qDebug() << Q_FUNC_INFO << "n must be greater or equal 2 but was" << n;
11208     n = 2;
11209   }
11210   if (n != mLevelCount)
11211   {
11212     mLevelCount = n;
11213     mColorBufferInvalidated = true;
11214   }
11215 }
11216
11217 /*!
11218   Sets at which positions from 0 to 1 which color shall occur. The positions are the keys, the
11219   colors are the values of the passed QMap \a colorStops. In between these color stops, the color
11220   is interpolated according to \ref setColorInterpolation.
11221   
11222   A more convenient way to create a custom gradient may be to clear all color stops with \ref
11223   clearColorStops and then adding them one by one with \ref setColorStopAt.
11224   
11225   \see clearColorStops
11226 */
11227 void QCPColorGradient::setColorStops(const QMap<double, QColor> &colorStops)
11228 {
11229   mColorStops = colorStops;
11230   mColorBufferInvalidated = true;
11231 }
11232
11233 /*!
11234   Sets the \a color the gradient will have at the specified \a position (from 0 to 1). In between
11235   these color stops, the color is interpolated according to \ref setColorInterpolation.
11236   
11237   \see setColorStops, clearColorStops
11238 */
11239 void QCPColorGradient::setColorStopAt(double position, const QColor &color)
11240 {
11241   mColorStops.insert(position, color);
11242   mColorBufferInvalidated = true;
11243 }
11244
11245 /*!
11246   Sets whether the colors in between the configured color stops (see \ref setColorStopAt) shall be
11247   interpolated linearly in RGB or in HSV color space.
11248   
11249   For example, a sweep in RGB space from red to green will have a muddy brown intermediate color,
11250   whereas in HSV space the intermediate color is yellow.
11251 */
11252 void QCPColorGradient::setColorInterpolation(QCPColorGradient::ColorInterpolation interpolation)
11253 {
11254   if (interpolation != mColorInterpolation)
11255   {
11256     mColorInterpolation = interpolation;
11257     mColorBufferInvalidated = true;
11258   }
11259 }
11260
11261 /*!
11262   Sets whether data points that are outside the configured data range (e.g. \ref
11263   QCPColorMap::setDataRange) are colored by periodically repeating the color gradient or whether
11264   they all have the same color, corresponding to the respective gradient boundary color.
11265   
11266   \image html QCPColorGradient-periodic.png
11267   
11268   As shown in the image above, gradients that have the same start and end color are especially
11269   suitable for a periodic gradient mapping, since they produce smooth color transitions throughout
11270   the color map. A preset that has this property is \ref gpHues.
11271   
11272   In practice, using periodic color gradients makes sense when the data corresponds to a periodic
11273   dimension, such as an angle or a phase. If this is not the case, the color encoding might become
11274   ambiguous, because multiple different data values are shown as the same color.
11275 */
11276 void QCPColorGradient::setPeriodic(bool enabled)
11277 {
11278   mPeriodic = enabled;
11279 }
11280
11281 /*!
11282   This method is used to quickly convert a \a data array to colors. The colors will be output in
11283   the array \a scanLine. Both \a data and \a scanLine must have the length \a n when passed to this
11284   function. The data range that shall be used for mapping the data value to the gradient is passed
11285   in \a range. \a logarithmic indicates whether the data values shall be mapped to colors
11286   logarithmically.
11287   
11288   if \a data actually contains 2D-data linearized via <tt>[row*columnCount + column]</tt>, you can
11289   set \a dataIndexFactor to <tt>columnCount</tt> to convert a column instead of a row of the data
11290   array, in \a scanLine. \a scanLine will remain a regular (1D) array. This works because \a data
11291   is addressed <tt>data[i*dataIndexFactor]</tt>.
11292 */
11293 void QCPColorGradient::colorize(const double *data, const QCPRange &range, QRgb *scanLine, int n, int dataIndexFactor, bool logarithmic)
11294 {
11295   // If you change something here, make sure to also adapt ::color()
11296   if (!data)
11297   {
11298     qDebug() << Q_FUNC_INFO << "null pointer given as data";
11299     return;
11300   }
11301   if (!scanLine)
11302   {
11303     qDebug() << Q_FUNC_INFO << "null pointer given as scanLine";
11304     return;
11305   }
11306   if (mColorBufferInvalidated)
11307     updateColorBuffer();
11308   
11309   if (!logarithmic)
11310   {
11311     const double posToIndexFactor = (mLevelCount-1)/range.size();
11312     if (mPeriodic)
11313     {
11314       for (int i=0; i<n; ++i)
11315       {
11316         int index = (int)((data[dataIndexFactor*i]-range.lower)*posToIndexFactor) % mLevelCount;
11317         if (index < 0)
11318           index += mLevelCount;
11319         scanLine[i] = mColorBuffer.at(index);
11320       }
11321     } else
11322     {
11323       for (int i=0; i<n; ++i)
11324       {
11325         int index = (data[dataIndexFactor*i]-range.lower)*posToIndexFactor;
11326         if (index < 0)
11327           index = 0;
11328         else if (index >= mLevelCount)
11329           index = mLevelCount-1;
11330         scanLine[i] = mColorBuffer.at(index);
11331       }
11332     }
11333   } else // logarithmic == true
11334   {
11335     if (mPeriodic)
11336     {
11337       for (int i=0; i<n; ++i)
11338       {
11339         int index = (int)(qLn(data[dataIndexFactor*i]/range.lower)/qLn(range.upper/range.lower)*(mLevelCount-1)) % mLevelCount;
11340         if (index < 0)
11341           index += mLevelCount;
11342         scanLine[i] = mColorBuffer.at(index);
11343       }
11344     } else
11345     {
11346       for (int i=0; i<n; ++i)
11347       {
11348         int index = qLn(data[dataIndexFactor*i]/range.lower)/qLn(range.upper/range.lower)*(mLevelCount-1);
11349         if (index < 0)
11350           index = 0;
11351         else if (index >= mLevelCount)
11352           index = mLevelCount-1;
11353         scanLine[i] = mColorBuffer.at(index);
11354       }
11355     }
11356   }
11357 }
11358
11359 /*! \internal
11360   
11361   This method is used to colorize a single data value given in \a position, to colors. The data
11362   range that shall be used for mapping the data value to the gradient is passed in \a range. \a
11363   logarithmic indicates whether the data value shall be mapped to a color logarithmically.
11364   
11365   If an entire array of data values shall be converted, rather use \ref colorize, for better
11366   performance.
11367 */
11368 QRgb QCPColorGradient::color(double position, const QCPRange &range, bool logarithmic)
11369 {
11370   // If you change something here, make sure to also adapt ::colorize()
11371   if (mColorBufferInvalidated)
11372     updateColorBuffer();
11373   int index = 0;
11374   if (!logarithmic)
11375     index = (position-range.lower)*(mLevelCount-1)/range.size();
11376   else
11377     index = qLn(position/range.lower)/qLn(range.upper/range.lower)*(mLevelCount-1);
11378   if (mPeriodic)
11379   {
11380     index = index % mLevelCount;
11381     if (index < 0)
11382       index += mLevelCount;
11383   } else
11384   {
11385     if (index < 0)
11386       index = 0;
11387     else if (index >= mLevelCount)
11388       index = mLevelCount-1;
11389   }
11390   return mColorBuffer.at(index);
11391 }
11392
11393 /*!
11394   Clears the current color stops and loads the specified \a preset. A preset consists of predefined
11395   color stops and the corresponding color interpolation method.
11396   
11397   The available presets are:
11398   \image html QCPColorGradient.png
11399 */
11400 void QCPColorGradient::loadPreset(GradientPreset preset)
11401 {
11402   clearColorStops();
11403   switch (preset)
11404   {
11405     case gpGrayscale:
11406       setColorInterpolation(ciRGB);
11407       setColorStopAt(0, Qt::black);
11408       setColorStopAt(1, Qt::white);
11409       break;
11410     case gpHot:
11411       setColorInterpolation(ciRGB);
11412       setColorStopAt(0, QColor(50, 0, 0));
11413       setColorStopAt(0.2, QColor(180, 10, 0));
11414       setColorStopAt(0.4, QColor(245, 50, 0));
11415       setColorStopAt(0.6, QColor(255, 150, 10));
11416       setColorStopAt(0.8, QColor(255, 255, 50));
11417       setColorStopAt(1, QColor(255, 255, 255));
11418       break;
11419     case gpCold:
11420       setColorInterpolation(ciRGB);
11421       setColorStopAt(0, QColor(0, 0, 50));
11422       setColorStopAt(0.2, QColor(0, 10, 180));
11423       setColorStopAt(0.4, QColor(0, 50, 245));
11424       setColorStopAt(0.6, QColor(10, 150, 255));
11425       setColorStopAt(0.8, QColor(50, 255, 255));
11426       setColorStopAt(1, QColor(255, 255, 255));
11427       break;
11428     case gpNight:
11429       setColorInterpolation(ciHSV);
11430       setColorStopAt(0, QColor(10, 20, 30));
11431       setColorStopAt(1, QColor(250, 255, 250));
11432       break;
11433     case gpCandy:
11434       setColorInterpolation(ciHSV);
11435       setColorStopAt(0, QColor(0, 0, 255));
11436       setColorStopAt(1, QColor(255, 250, 250));
11437       break;
11438     case gpGeography:
11439       setColorInterpolation(ciRGB);
11440       setColorStopAt(0, QColor(70, 170, 210));
11441       setColorStopAt(0.20, QColor(90, 160, 180));
11442       setColorStopAt(0.25, QColor(45, 130, 175));
11443       setColorStopAt(0.30, QColor(100, 140, 125));
11444       setColorStopAt(0.5, QColor(100, 140, 100));
11445       setColorStopAt(0.6, QColor(130, 145, 120));
11446       setColorStopAt(0.7, QColor(140, 130, 120));
11447       setColorStopAt(0.9, QColor(180, 190, 190));
11448       setColorStopAt(1, QColor(210, 210, 230));
11449       break;
11450     case gpIon:
11451       setColorInterpolation(ciHSV);
11452       setColorStopAt(0, QColor(50, 10, 10));
11453       setColorStopAt(0.45, QColor(0, 0, 255));
11454       setColorStopAt(0.8, QColor(0, 255, 255));
11455       setColorStopAt(1, QColor(0, 255, 0));
11456       break;
11457     case gpThermal:
11458       setColorInterpolation(ciRGB);
11459       setColorStopAt(0, QColor(0, 0, 50));
11460       setColorStopAt(0.15, QColor(20, 0, 120));
11461       setColorStopAt(0.33, QColor(200, 30, 140));
11462       setColorStopAt(0.6, QColor(255, 100, 0));
11463       setColorStopAt(0.85, QColor(255, 255, 40));
11464       setColorStopAt(1, QColor(255, 255, 255));
11465       break;
11466     case gpPolar:
11467       setColorInterpolation(ciRGB);
11468       setColorStopAt(0, QColor(50, 255, 255));
11469       setColorStopAt(0.18, QColor(10, 70, 255));
11470       setColorStopAt(0.28, QColor(10, 10, 190));
11471       setColorStopAt(0.5, QColor(0, 0, 0));
11472       setColorStopAt(0.72, QColor(190, 10, 10));
11473       setColorStopAt(0.82, QColor(255, 70, 10));
11474       setColorStopAt(1, QColor(255, 255, 50));
11475       break;
11476     case gpSpectrum:
11477       setColorInterpolation(ciHSV);
11478       setColorStopAt(0, QColor(50, 0, 50));
11479       setColorStopAt(0.15, QColor(0, 0, 255));
11480       setColorStopAt(0.35, QColor(0, 255, 255));
11481       setColorStopAt(0.6, QColor(255, 255, 0));
11482       setColorStopAt(0.75, QColor(255, 30, 0));
11483       setColorStopAt(1, QColor(50, 0, 0));
11484       break;
11485     case gpJet:
11486       setColorInterpolation(ciRGB);
11487       setColorStopAt(0, QColor(0, 0, 100));
11488       setColorStopAt(0.15, QColor(0, 50, 255));
11489       setColorStopAt(0.35, QColor(0, 255, 255));
11490       setColorStopAt(0.65, QColor(255, 255, 0));
11491       setColorStopAt(0.85, QColor(255, 30, 0));
11492       setColorStopAt(1, QColor(100, 0, 0));
11493       break;
11494     case gpHues:
11495       setColorInterpolation(ciHSV);
11496       setColorStopAt(0, QColor(255, 0, 0));
11497       setColorStopAt(1.0/3.0, QColor(0, 0, 255));
11498       setColorStopAt(2.0/3.0, QColor(0, 255, 0));
11499       setColorStopAt(1, QColor(255, 0, 0));
11500       break;
11501   }
11502 }
11503
11504 /*!
11505   Clears all color stops.
11506   
11507   \see setColorStops, setColorStopAt
11508 */
11509 void QCPColorGradient::clearColorStops()
11510 {
11511   mColorStops.clear();
11512   mColorBufferInvalidated = true;
11513 }
11514
11515 /*!
11516   Returns an inverted gradient. The inverted gradient has all properties as this \ref
11517   QCPColorGradient, but the order of the color stops is inverted.
11518   
11519   \see setColorStops, setColorStopAt
11520 */
11521 QCPColorGradient QCPColorGradient::inverted() const
11522 {
11523   QCPColorGradient result(*this);
11524   result.clearColorStops();
11525   for (QMap<double, QColor>::const_iterator it=mColorStops.constBegin(); it!=mColorStops.constEnd(); ++it)
11526     result.setColorStopAt(1.0-it.key(), it.value());
11527   return result;
11528 }
11529
11530 /*! \internal
11531   
11532   Updates the internal color buffer which will be used by \ref colorize and \ref color, to quickly
11533   convert positions to colors. This is where the interpolation between color stops is calculated.
11534 */
11535 void QCPColorGradient::updateColorBuffer()
11536 {
11537   if (mColorBuffer.size() != mLevelCount)
11538     mColorBuffer.resize(mLevelCount);
11539   if (mColorStops.size() > 1)
11540   {
11541     double indexToPosFactor = 1.0/(double)(mLevelCount-1);
11542     for (int i=0; i<mLevelCount; ++i)
11543     {
11544       double position = i*indexToPosFactor;
11545       QMap<double, QColor>::const_iterator it = mColorStops.lowerBound(position);
11546       if (it == mColorStops.constEnd()) // position is on or after last stop, use color of last stop
11547       {
11548         mColorBuffer[i] = (it-1).value().rgb();
11549       } else if (it == mColorStops.constBegin()) // position is on or before first stop, use color of first stop
11550       {
11551         mColorBuffer[i] = it.value().rgb();
11552       } else // position is in between stops (or on an intermediate stop), interpolate color
11553       {
11554         QMap<double, QColor>::const_iterator high = it;
11555         QMap<double, QColor>::const_iterator low = it-1;
11556         double t = (position-low.key())/(high.key()-low.key()); // interpolation factor 0..1
11557         switch (mColorInterpolation)
11558         {
11559           case ciRGB:
11560           {
11561             mColorBuffer[i] = qRgb((1-t)*low.value().red() + t*high.value().red(),
11562                                    (1-t)*low.value().green() + t*high.value().green(),
11563                                    (1-t)*low.value().blue() + t*high.value().blue());
11564             break;
11565           }
11566           case ciHSV:
11567           {
11568             QColor lowHsv = low.value().toHsv();
11569             QColor highHsv = high.value().toHsv();
11570             double hue = 0;
11571             double hueDiff = highHsv.hueF()-lowHsv.hueF();
11572             if (hueDiff > 0.5)
11573               hue = lowHsv.hueF() - t*(1.0-hueDiff);
11574             else if (hueDiff < -0.5)
11575               hue = lowHsv.hueF() + t*(1.0+hueDiff);
11576             else
11577               hue = lowHsv.hueF() + t*hueDiff;
11578             if (hue < 0) hue += 1.0;
11579             else if (hue >= 1.0) hue -= 1.0;
11580             mColorBuffer[i] = QColor::fromHsvF(hue, (1-t)*lowHsv.saturationF() + t*highHsv.saturationF(), (1-t)*lowHsv.valueF() + t*highHsv.valueF()).rgb();
11581             break;
11582           }
11583         }
11584       }
11585     }
11586   } else if (mColorStops.size() == 1)
11587   {
11588     mColorBuffer.fill(mColorStops.constBegin().value().rgb());
11589   } else // mColorStops is empty, fill color buffer with black
11590   {
11591     mColorBuffer.fill(qRgb(0, 0, 0));
11592   }
11593   mColorBufferInvalidated = false;
11594 }
11595
11596
11597 ////////////////////////////////////////////////////////////////////////////////////////////////////
11598 //////////////////// QCPAxisRect
11599 ////////////////////////////////////////////////////////////////////////////////////////////////////
11600
11601 /*! \class QCPAxisRect
11602   \brief Holds multiple axes and arranges them in a rectangular shape.
11603   
11604   This class represents an axis rect, a rectangular area that is bounded on all sides with an
11605   arbitrary number of axes.
11606   
11607   Initially QCustomPlot has one axis rect, accessible via QCustomPlot::axisRect(). However, the
11608   layout system allows to have multiple axis rects, e.g. arranged in a grid layout
11609   (QCustomPlot::plotLayout).
11610   
11611   By default, QCPAxisRect comes with four axes, at bottom, top, left and right. They can be
11612   accessed via \ref axis by providing the respective axis type (\ref QCPAxis::AxisType) and index.
11613   If you need all axes in the axis rect, use \ref axes. The top and right axes are set to be
11614   invisible initially (QCPAxis::setVisible). To add more axes to a side, use \ref addAxis or \ref
11615   addAxes. To remove an axis, use \ref removeAxis.
11616   
11617   The axis rect layerable itself only draws a background pixmap or color, if specified (\ref
11618   setBackground). It is placed on the "background" layer initially (see \ref QCPLayer for an
11619   explanation of the QCustomPlot layer system). The axes that are held by the axis rect can be
11620   placed on other layers, independently of the axis rect.
11621   
11622   Every axis rect has a child layout of type \ref QCPLayoutInset. It is accessible via \ref
11623   insetLayout and can be used to have other layout elements (or even other layouts with multiple
11624   elements) hovering inside the axis rect.
11625   
11626   If an axis rect is clicked and dragged, it processes this by moving certain axis ranges. The
11627   behaviour can be controlled with \ref setRangeDrag and \ref setRangeDragAxes. If the mouse wheel
11628   is scrolled while the cursor is on the axis rect, certain axes are scaled. This is controllable
11629   via \ref setRangeZoom, \ref setRangeZoomAxes and \ref setRangeZoomFactor. These interactions are
11630   only enabled if \ref QCustomPlot::setInteractions contains \ref QCP::iRangeDrag and \ref
11631   QCP::iRangeZoom.
11632   
11633   \image html AxisRectSpacingOverview.png
11634   <center>Overview of the spacings and paddings that define the geometry of an axis. The dashed
11635   line on the far left indicates the viewport/widget border.</center>
11636 */
11637
11638 /* start documentation of inline functions */
11639
11640 /*! \fn QCPLayoutInset *QCPAxisRect::insetLayout() const
11641   
11642   Returns the inset layout of this axis rect. It can be used to place other layout elements (or
11643   even layouts with multiple other elements) inside/on top of an axis rect.
11644   
11645   \see QCPLayoutInset
11646 */
11647
11648 /*! \fn int QCPAxisRect::left() const
11649   
11650   Returns the pixel position of the left border of this axis rect. Margins are not taken into
11651   account here, so the returned value is with respect to the inner \ref rect.
11652 */
11653
11654 /*! \fn int QCPAxisRect::right() const
11655   
11656   Returns the pixel position of the right border of this axis rect. Margins are not taken into
11657   account here, so the returned value is with respect to the inner \ref rect.
11658 */
11659
11660 /*! \fn int QCPAxisRect::top() const
11661   
11662   Returns the pixel position of the top border of this axis rect. Margins are not taken into
11663   account here, so the returned value is with respect to the inner \ref rect.
11664 */
11665
11666 /*! \fn int QCPAxisRect::bottom() const
11667   
11668   Returns the pixel position of the bottom border of this axis rect. Margins are not taken into
11669   account here, so the returned value is with respect to the inner \ref rect.
11670 */
11671
11672 /*! \fn int QCPAxisRect::width() const
11673   
11674   Returns the pixel width of this axis rect. Margins are not taken into account here, so the
11675   returned value is with respect to the inner \ref rect.
11676 */
11677
11678 /*! \fn int QCPAxisRect::height() const
11679   
11680   Returns the pixel height of this axis rect. Margins are not taken into account here, so the
11681   returned value is with respect to the inner \ref rect.
11682 */
11683
11684 /*! \fn QSize QCPAxisRect::size() const
11685   
11686   Returns the pixel size of this axis rect. Margins are not taken into account here, so the
11687   returned value is with respect to the inner \ref rect.
11688 */
11689
11690 /*! \fn QPoint QCPAxisRect::topLeft() const
11691   
11692   Returns the top left corner of this axis rect in pixels. Margins are not taken into account here,
11693   so the returned value is with respect to the inner \ref rect.
11694 */
11695
11696 /*! \fn QPoint QCPAxisRect::topRight() const
11697   
11698   Returns the top right corner of this axis rect in pixels. Margins are not taken into account
11699   here, so the returned value is with respect to the inner \ref rect.
11700 */
11701
11702 /*! \fn QPoint QCPAxisRect::bottomLeft() const
11703   
11704   Returns the bottom left corner of this axis rect in pixels. Margins are not taken into account
11705   here, so the returned value is with respect to the inner \ref rect.
11706 */
11707
11708 /*! \fn QPoint QCPAxisRect::bottomRight() const
11709   
11710   Returns the bottom right corner of this axis rect in pixels. Margins are not taken into account
11711   here, so the returned value is with respect to the inner \ref rect.
11712 */
11713
11714 /*! \fn QPoint QCPAxisRect::center() const
11715   
11716   Returns the center of this axis rect in pixels. Margins are not taken into account here, so the
11717   returned value is with respect to the inner \ref rect.
11718 */
11719
11720 /* end documentation of inline functions */
11721
11722 /*!
11723   Creates a QCPAxisRect instance and sets default values. An axis is added for each of the four
11724   sides, the top and right axes are set invisible initially.
11725 */
11726 QCPAxisRect::QCPAxisRect(QCustomPlot *parentPlot, bool setupDefaultAxes) :
11727   QCPLayoutElement(parentPlot),
11728   mBackgroundBrush(Qt::NoBrush),
11729   mBackgroundScaled(true),
11730   mBackgroundScaledMode(Qt::KeepAspectRatioByExpanding),
11731   mInsetLayout(new QCPLayoutInset),
11732   mRangeDrag(Qt::Horizontal|Qt::Vertical),
11733   mRangeZoom(Qt::Horizontal|Qt::Vertical),
11734   mRangeZoomFactorHorz(0.85),
11735   mRangeZoomFactorVert(0.85),
11736   mDragging(false)
11737 {
11738   mInsetLayout->initializeParentPlot(mParentPlot);
11739   mInsetLayout->setParentLayerable(this);
11740   mInsetLayout->setParent(this);
11741   
11742   setMinimumSize(50, 50);
11743   setMinimumMargins(QMargins(15, 15, 15, 15));
11744   mAxes.insert(QCPAxis::atLeft, QList<QCPAxis*>());
11745   mAxes.insert(QCPAxis::atRight, QList<QCPAxis*>());
11746   mAxes.insert(QCPAxis::atTop, QList<QCPAxis*>());
11747   mAxes.insert(QCPAxis::atBottom, QList<QCPAxis*>());
11748   
11749   if (setupDefaultAxes)
11750   {
11751     QCPAxis *xAxis = addAxis(QCPAxis::atBottom);
11752     QCPAxis *yAxis = addAxis(QCPAxis::atLeft);
11753     QCPAxis *xAxis2 = addAxis(QCPAxis::atTop);
11754     QCPAxis *yAxis2 = addAxis(QCPAxis::atRight);
11755     setRangeDragAxes(xAxis, yAxis);
11756     setRangeZoomAxes(xAxis, yAxis);
11757     xAxis2->setVisible(false);
11758     yAxis2->setVisible(false);
11759     xAxis->grid()->setVisible(true);
11760     yAxis->grid()->setVisible(true);
11761     xAxis2->grid()->setVisible(false);
11762     yAxis2->grid()->setVisible(false);
11763     xAxis2->grid()->setZeroLinePen(Qt::NoPen);
11764     yAxis2->grid()->setZeroLinePen(Qt::NoPen);
11765     xAxis2->grid()->setVisible(false);
11766     yAxis2->grid()->setVisible(false);
11767   }
11768 }
11769
11770 QCPAxisRect::~QCPAxisRect()
11771 {
11772   delete mInsetLayout;
11773   mInsetLayout = 0;
11774   
11775   QList<QCPAxis*> axesList = axes();
11776   for (int i=0; i<axesList.size(); ++i)
11777     removeAxis(axesList.at(i));
11778 }
11779
11780 /*!
11781   Returns the number of axes on the axis rect side specified with \a type.
11782   
11783   \see axis
11784 */
11785 int QCPAxisRect::axisCount(QCPAxis::AxisType type) const
11786 {
11787   return mAxes.value(type).size();
11788 }
11789
11790 /*!
11791   Returns the axis with the given \a index on the axis rect side specified with \a type.
11792   
11793   \see axisCount, axes
11794 */
11795 QCPAxis *QCPAxisRect::axis(QCPAxis::AxisType type, int index) const
11796 {
11797   QList<QCPAxis*> ax(mAxes.value(type));
11798   if (index >= 0 && index < ax.size())
11799   {
11800     return ax.at(index);
11801   } else
11802   {
11803     qDebug() << Q_FUNC_INFO << "Axis index out of bounds:" << index;
11804     return 0;
11805   }
11806 }
11807
11808 /*!
11809   Returns all axes on the axis rect sides specified with \a types.
11810   
11811   \a types may be a single \ref QCPAxis::AxisType or an <tt>or</tt>-combination, to get the axes of
11812   multiple sides.
11813   
11814   \see axis
11815 */
11816 QList<QCPAxis*> QCPAxisRect::axes(QCPAxis::AxisTypes types) const
11817 {
11818   QList<QCPAxis*> result;
11819   if (types.testFlag(QCPAxis::atLeft))
11820     result << mAxes.value(QCPAxis::atLeft);
11821   if (types.testFlag(QCPAxis::atRight))
11822     result << mAxes.value(QCPAxis::atRight);
11823   if (types.testFlag(QCPAxis::atTop))
11824     result << mAxes.value(QCPAxis::atTop);
11825   if (types.testFlag(QCPAxis::atBottom))
11826     result << mAxes.value(QCPAxis::atBottom);
11827   return result;
11828 }
11829
11830 /*! \overload
11831   
11832   Returns all axes of this axis rect.
11833 */
11834 QList<QCPAxis*> QCPAxisRect::axes() const
11835 {
11836   QList<QCPAxis*> result;
11837   QHashIterator<QCPAxis::AxisType, QList<QCPAxis*> > it(mAxes);
11838   while (it.hasNext())
11839   {
11840     it.next();
11841     result << it.value();
11842   }
11843   return result;
11844 }
11845
11846 /*!
11847   Adds a new axis to the axis rect side specified with \a type, and returns it. If \a axis is 0, a
11848   new QCPAxis instance is created internally.
11849
11850   You may inject QCPAxis instances (or sublasses of QCPAxis) by setting \a axis to an axis that was
11851   previously created outside QCustomPlot. It is important to note that QCustomPlot takes ownership
11852   of the axis, so you may not delete it afterwards. Further, the \a axis must have been created
11853   with this axis rect as parent and with the same axis type as specified in \a type. If this is not
11854   the case, a debug output is generated, the axis is not added, and the method returns 0.
11855   
11856   This method can not be used to move \a axis between axis rects. The same \a axis instance must
11857   not be added multiple times to the same or different axis rects.
11858   
11859   If an axis rect side already contains one or more axes, the lower and upper endings of the new
11860   axis (\ref QCPAxis::setLowerEnding, \ref QCPAxis::setUpperEnding) are set to \ref
11861   QCPLineEnding::esHalfBar.
11862   
11863   \see addAxes, setupFullAxesBox
11864 */
11865 QCPAxis *QCPAxisRect::addAxis(QCPAxis::AxisType type, QCPAxis *axis)
11866 {
11867   QCPAxis *newAxis = axis;
11868   if (!newAxis)
11869   {
11870     newAxis = new QCPAxis(this, type);
11871   } else // user provided existing axis instance, do some sanity checks
11872   {
11873     if (newAxis->axisType() != type)
11874     {
11875       qDebug() << Q_FUNC_INFO << "passed axis has different axis type than specified in type parameter";
11876       return 0;
11877     }
11878     if (newAxis->axisRect() != this)
11879     {
11880       qDebug() << Q_FUNC_INFO << "passed axis doesn't have this axis rect as parent axis rect";
11881       return 0;
11882     }
11883     if (axes().contains(newAxis))
11884     {
11885       qDebug() << Q_FUNC_INFO << "passed axis is already owned by this axis rect";
11886       return 0;
11887     }
11888   }
11889   if (mAxes[type].size() > 0) // multiple axes on one side, add half-bar axis ending to additional axes with offset
11890   {
11891     bool invert = (type == QCPAxis::atRight) || (type == QCPAxis::atBottom);
11892     newAxis->setLowerEnding(QCPLineEnding(QCPLineEnding::esHalfBar, 6, 10, !invert));
11893     newAxis->setUpperEnding(QCPLineEnding(QCPLineEnding::esHalfBar, 6, 10, invert));
11894   }
11895   mAxes[type].append(newAxis);
11896   return newAxis;
11897 }
11898
11899 /*!
11900   Adds a new axis with \ref addAxis to each axis rect side specified in \a types. This may be an
11901   <tt>or</tt>-combination of QCPAxis::AxisType, so axes can be added to multiple sides at once.
11902   
11903   Returns a list of the added axes.
11904   
11905   \see addAxis, setupFullAxesBox
11906 */
11907 QList<QCPAxis*> QCPAxisRect::addAxes(QCPAxis::AxisTypes types)
11908 {
11909   QList<QCPAxis*> result;
11910   if (types.testFlag(QCPAxis::atLeft))
11911     result << addAxis(QCPAxis::atLeft);
11912   if (types.testFlag(QCPAxis::atRight))
11913     result << addAxis(QCPAxis::atRight);
11914   if (types.testFlag(QCPAxis::atTop))
11915     result << addAxis(QCPAxis::atTop);
11916   if (types.testFlag(QCPAxis::atBottom))
11917     result << addAxis(QCPAxis::atBottom);
11918   return result;
11919 }
11920
11921 /*!
11922   Removes the specified \a axis from the axis rect and deletes it.
11923   
11924   Returns true on success, i.e. if \a axis was a valid axis in this axis rect.
11925   
11926   \see addAxis
11927 */
11928 bool QCPAxisRect::removeAxis(QCPAxis *axis)
11929 {
11930   // don't access axis->axisType() to provide safety when axis is an invalid pointer, rather go through all axis containers:
11931   QHashIterator<QCPAxis::AxisType, QList<QCPAxis*> > it(mAxes);
11932   while (it.hasNext())
11933   {
11934     it.next();
11935     if (it.value().contains(axis))
11936     {
11937       mAxes[it.key()].removeOne(axis);
11938       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)
11939         parentPlot()->axisRemoved(axis);
11940       delete axis;
11941       return true;
11942     }
11943   }
11944   qDebug() << Q_FUNC_INFO << "Axis isn't in axis rect:" << reinterpret_cast<quintptr>(axis);
11945   return false;
11946 }
11947
11948 /*!
11949   Convenience function to create an axis on each side that doesn't have any axes yet and set their
11950   visibility to true. Further, the top/right axes are assigned the following properties of the
11951   bottom/left axes:
11952   
11953   \li range (\ref QCPAxis::setRange)
11954   \li range reversed (\ref QCPAxis::setRangeReversed)
11955   \li scale type (\ref QCPAxis::setScaleType)
11956   \li scale log base  (\ref QCPAxis::setScaleLogBase)
11957   \li ticks (\ref QCPAxis::setTicks)
11958   \li auto (major) tick count (\ref QCPAxis::setAutoTickCount)
11959   \li sub tick count (\ref QCPAxis::setSubTickCount)
11960   \li auto sub ticks (\ref QCPAxis::setAutoSubTicks)
11961   \li tick step (\ref QCPAxis::setTickStep)
11962   \li auto tick step (\ref QCPAxis::setAutoTickStep)
11963   \li number format (\ref QCPAxis::setNumberFormat)
11964   \li number precision (\ref QCPAxis::setNumberPrecision)
11965   \li tick label type (\ref QCPAxis::setTickLabelType)
11966   \li date time format (\ref QCPAxis::setDateTimeFormat)
11967   \li date time spec (\ref QCPAxis::setDateTimeSpec)
11968   
11969   Tick labels (\ref QCPAxis::setTickLabels) of the right and top axes are set to false.
11970
11971   If \a connectRanges is true, the \ref QCPAxis::rangeChanged "rangeChanged" signals of the bottom
11972   and left axes are connected to the \ref QCPAxis::setRange slots of the top and right axes.
11973 */
11974 void QCPAxisRect::setupFullAxesBox(bool connectRanges)
11975 {
11976   QCPAxis *xAxis, *yAxis, *xAxis2, *yAxis2;
11977   if (axisCount(QCPAxis::atBottom) == 0)
11978     xAxis = addAxis(QCPAxis::atBottom);
11979   else
11980     xAxis = axis(QCPAxis::atBottom);
11981   
11982   if (axisCount(QCPAxis::atLeft) == 0)
11983     yAxis = addAxis(QCPAxis::atLeft);
11984   else
11985     yAxis = axis(QCPAxis::atLeft);
11986   
11987   if (axisCount(QCPAxis::atTop) == 0)
11988     xAxis2 = addAxis(QCPAxis::atTop);
11989   else
11990     xAxis2 = axis(QCPAxis::atTop);
11991   
11992   if (axisCount(QCPAxis::atRight) == 0)
11993     yAxis2 = addAxis(QCPAxis::atRight);
11994   else
11995     yAxis2 = axis(QCPAxis::atRight);
11996   
11997   xAxis->setVisible(true);
11998   yAxis->setVisible(true);
11999   xAxis2->setVisible(true);
12000   yAxis2->setVisible(true);
12001   xAxis2->setTickLabels(false);
12002   yAxis2->setTickLabels(false);
12003   
12004   xAxis2->setRange(xAxis->range());
12005   xAxis2->setRangeReversed(xAxis->rangeReversed());
12006   xAxis2->setScaleType(xAxis->scaleType());
12007   xAxis2->setScaleLogBase(xAxis->scaleLogBase());
12008   xAxis2->setTicks(xAxis->ticks());
12009   xAxis2->setAutoTickCount(xAxis->autoTickCount());
12010   xAxis2->setSubTickCount(xAxis->subTickCount());
12011   xAxis2->setAutoSubTicks(xAxis->autoSubTicks());
12012   xAxis2->setTickStep(xAxis->tickStep());
12013   xAxis2->setAutoTickStep(xAxis->autoTickStep());
12014   xAxis2->setNumberFormat(xAxis->numberFormat());
12015   xAxis2->setNumberPrecision(xAxis->numberPrecision());
12016   xAxis2->setTickLabelType(xAxis->tickLabelType());
12017   xAxis2->setDateTimeFormat(xAxis->dateTimeFormat());
12018   xAxis2->setDateTimeSpec(xAxis->dateTimeSpec());
12019
12020   yAxis2->setRange(yAxis->range());
12021   yAxis2->setRangeReversed(yAxis->rangeReversed());
12022   yAxis2->setScaleType(yAxis->scaleType());
12023   yAxis2->setScaleLogBase(yAxis->scaleLogBase());
12024   yAxis2->setTicks(yAxis->ticks());
12025   yAxis2->setAutoTickCount(yAxis->autoTickCount());
12026   yAxis2->setSubTickCount(yAxis->subTickCount());
12027   yAxis2->setAutoSubTicks(yAxis->autoSubTicks());
12028   yAxis2->setTickStep(yAxis->tickStep());
12029   yAxis2->setAutoTickStep(yAxis->autoTickStep());
12030   yAxis2->setNumberFormat(yAxis->numberFormat());
12031   yAxis2->setNumberPrecision(yAxis->numberPrecision());
12032   yAxis2->setTickLabelType(yAxis->tickLabelType());
12033   yAxis2->setDateTimeFormat(yAxis->dateTimeFormat());
12034   yAxis2->setDateTimeSpec(yAxis->dateTimeSpec());
12035   
12036   if (connectRanges)
12037   {
12038     connect(xAxis, SIGNAL(rangeChanged(QCPRange)), xAxis2, SLOT(setRange(QCPRange)));
12039     connect(yAxis, SIGNAL(rangeChanged(QCPRange)), yAxis2, SLOT(setRange(QCPRange)));
12040   }
12041 }
12042
12043 /*!
12044   Returns a list of all the plottables that are associated with this axis rect.
12045   
12046   A plottable is considered associated with an axis rect if its key or value axis (or both) is in
12047   this axis rect.
12048   
12049   \see graphs, items
12050 */
12051 QList<QCPAbstractPlottable*> QCPAxisRect::plottables() const
12052 {
12053   // Note: don't append all QCPAxis::plottables() into a list, because we might get duplicate entries
12054   QList<QCPAbstractPlottable*> result;
12055   for (int i=0; i<mParentPlot->mPlottables.size(); ++i)
12056   {
12057     if (mParentPlot->mPlottables.at(i)->keyAxis()->axisRect() == this ||mParentPlot->mPlottables.at(i)->valueAxis()->axisRect() == this)
12058       result.append(mParentPlot->mPlottables.at(i));
12059   }
12060   return result;
12061 }
12062
12063 /*!
12064   Returns a list of all the graphs that are associated with this axis rect.
12065   
12066   A graph is considered associated with an axis rect if its key or value axis (or both) is in
12067   this axis rect.
12068   
12069   \see plottables, items
12070 */
12071 QList<QCPGraph*> QCPAxisRect::graphs() const
12072 {
12073   // Note: don't append all QCPAxis::graphs() into a list, because we might get duplicate entries
12074   QList<QCPGraph*> result;
12075   for (int i=0; i<mParentPlot->mGraphs.size(); ++i)
12076   {
12077     if (mParentPlot->mGraphs.at(i)->keyAxis()->axisRect() == this || mParentPlot->mGraphs.at(i)->valueAxis()->axisRect() == this)
12078       result.append(mParentPlot->mGraphs.at(i));
12079   }
12080   return result;
12081 }
12082
12083 /*!
12084   Returns a list of all the items that are associated with this axis rect.
12085   
12086   An item is considered associated with an axis rect if any of its positions has key or value axis
12087   set to an axis that is in this axis rect, or if any of its positions has \ref
12088   QCPItemPosition::setAxisRect set to the axis rect, or if the clip axis rect (\ref
12089   QCPAbstractItem::setClipAxisRect) is set to this axis rect.
12090   
12091   \see plottables, graphs
12092 */
12093 QList<QCPAbstractItem *> QCPAxisRect::items() const
12094 {
12095   // Note: don't just append all QCPAxis::items() into a list, because we might get duplicate entries
12096   //       and miss those items that have this axis rect as clipAxisRect.
12097   QList<QCPAbstractItem*> result;
12098   for (int itemId=0; itemId<mParentPlot->mItems.size(); ++itemId)
12099   {
12100     if (mParentPlot->mItems.at(itemId)->clipAxisRect() == this)
12101     {
12102       result.append(mParentPlot->mItems.at(itemId));
12103       continue;
12104     }
12105     QList<QCPItemPosition*> positions = mParentPlot->mItems.at(itemId)->positions();
12106     for (int posId=0; posId<positions.size(); ++posId)
12107     {
12108       if (positions.at(posId)->axisRect() == this ||
12109           positions.at(posId)->keyAxis()->axisRect() == this ||
12110           positions.at(posId)->valueAxis()->axisRect() == this)
12111       {
12112         result.append(mParentPlot->mItems.at(itemId));
12113         break;
12114       }
12115     }
12116   }
12117   return result;
12118 }
12119
12120 /*!
12121   This method is called automatically upon replot and doesn't need to be called by users of
12122   QCPAxisRect.
12123   
12124   Calls the base class implementation to update the margins (see \ref QCPLayoutElement::update),
12125   and finally passes the \ref rect to the inset layout (\ref insetLayout) and calls its
12126   QCPInsetLayout::update function.
12127 */
12128 void QCPAxisRect::update(UpdatePhase phase)
12129 {
12130   QCPLayoutElement::update(phase);
12131   
12132   switch (phase)
12133   {
12134     case upPreparation:
12135     {
12136       QList<QCPAxis*> allAxes = axes();
12137       for (int i=0; i<allAxes.size(); ++i)
12138         allAxes.at(i)->setupTickVectors();
12139       break;
12140     }
12141     case upLayout:
12142     {
12143       mInsetLayout->setOuterRect(rect());
12144       break;
12145     }
12146     default: break;
12147   }
12148   
12149   // pass update call on to inset layout (doesn't happen automatically, because QCPAxisRect doesn't derive from QCPLayout):
12150   mInsetLayout->update(phase);
12151 }
12152
12153 /* inherits documentation from base class */
12154 QList<QCPLayoutElement*> QCPAxisRect::elements(bool recursive) const
12155 {
12156   QList<QCPLayoutElement*> result;
12157   if (mInsetLayout)
12158   {
12159     result << mInsetLayout;
12160     if (recursive)
12161       result << mInsetLayout->elements(recursive);
12162   }
12163   return result;
12164 }
12165
12166 /* inherits documentation from base class */
12167 void QCPAxisRect::applyDefaultAntialiasingHint(QCPPainter *painter) const
12168 {
12169   painter->setAntialiasing(false);
12170 }
12171
12172 /* inherits documentation from base class */
12173 void QCPAxisRect::draw(QCPPainter *painter)
12174 {
12175   drawBackground(painter);
12176 }
12177
12178 /*!
12179   Sets \a pm as the axis background pixmap. The axis background pixmap will be drawn inside the
12180   axis rect. Since axis rects place themselves on the "background" layer by default, the axis rect
12181   backgrounds are usually drawn below everything else.
12182
12183   For cases where the provided pixmap doesn't have the same size as the axis rect, scaling can be
12184   enabled with \ref setBackgroundScaled and the scaling mode (i.e. whether and how the aspect ratio
12185   is preserved) can be set with \ref setBackgroundScaledMode. To set all these options in one call,
12186   consider using the overloaded version of this function.
12187
12188   Below the pixmap, the axis rect may be optionally filled with a brush, if specified with \ref
12189   setBackground(const QBrush &brush).
12190   
12191   \see setBackgroundScaled, setBackgroundScaledMode, setBackground(const QBrush &brush)
12192 */
12193 void QCPAxisRect::setBackground(const QPixmap &pm)
12194 {
12195   mBackgroundPixmap = pm;
12196   mScaledBackgroundPixmap = QPixmap();
12197 }
12198
12199 /*! \overload
12200   
12201   Sets \a brush as the background brush. The axis rect background will be filled with this brush.
12202   Since axis rects place themselves on the "background" layer by default, the axis rect backgrounds
12203   are usually drawn below everything else.
12204
12205   The brush will be drawn before (under) any background pixmap, which may be specified with \ref
12206   setBackground(const QPixmap &pm).
12207
12208   To disable drawing of a background brush, set \a brush to Qt::NoBrush.
12209   
12210   \see setBackground(const QPixmap &pm)
12211 */
12212 void QCPAxisRect::setBackground(const QBrush &brush)
12213 {
12214   mBackgroundBrush = brush;
12215 }
12216
12217 /*! \overload
12218   
12219   Allows setting the background pixmap of the axis rect, whether it shall be scaled and how it
12220   shall be scaled in one call.
12221
12222   \see setBackground(const QPixmap &pm), setBackgroundScaled, setBackgroundScaledMode
12223 */
12224 void QCPAxisRect::setBackground(const QPixmap &pm, bool scaled, Qt::AspectRatioMode mode)
12225 {
12226   mBackgroundPixmap = pm;
12227   mScaledBackgroundPixmap = QPixmap();
12228   mBackgroundScaled = scaled;
12229   mBackgroundScaledMode = mode;
12230 }
12231
12232 /*!
12233   Sets whether the axis background pixmap shall be scaled to fit the axis rect or not. If \a scaled
12234   is set to true, you may control whether and how the aspect ratio of the original pixmap is
12235   preserved with \ref setBackgroundScaledMode.
12236   
12237   Note that the scaled version of the original pixmap is buffered, so there is no performance
12238   penalty on replots. (Except when the axis rect dimensions are changed continuously.)
12239   
12240   \see setBackground, setBackgroundScaledMode
12241 */
12242 void QCPAxisRect::setBackgroundScaled(bool scaled)
12243 {
12244   mBackgroundScaled = scaled;
12245 }
12246
12247 /*!
12248   If scaling of the axis background pixmap is enabled (\ref setBackgroundScaled), use this function to
12249   define whether and how the aspect ratio of the original pixmap passed to \ref setBackground is preserved.
12250   \see setBackground, setBackgroundScaled
12251 */
12252 void QCPAxisRect::setBackgroundScaledMode(Qt::AspectRatioMode mode)
12253 {
12254   mBackgroundScaledMode = mode;
12255 }
12256
12257 /*!
12258   Returns the range drag axis of the \a orientation provided.
12259   
12260   \see setRangeDragAxes
12261 */
12262 QCPAxis *QCPAxisRect::rangeDragAxis(Qt::Orientation orientation)
12263 {
12264   return (orientation == Qt::Horizontal ? mRangeDragHorzAxis.data() : mRangeDragVertAxis.data());
12265 }
12266
12267 /*!
12268   Returns the range zoom axis of the \a orientation provided.
12269   
12270   \see setRangeZoomAxes
12271 */
12272 QCPAxis *QCPAxisRect::rangeZoomAxis(Qt::Orientation orientation)
12273 {
12274   return (orientation == Qt::Horizontal ? mRangeZoomHorzAxis.data() : mRangeZoomVertAxis.data());
12275 }
12276
12277 /*!
12278   Returns the range zoom factor of the \a orientation provided.
12279   
12280   \see setRangeZoomFactor
12281 */
12282 double QCPAxisRect::rangeZoomFactor(Qt::Orientation orientation)
12283 {
12284   return (orientation == Qt::Horizontal ? mRangeZoomFactorHorz : mRangeZoomFactorVert);
12285 }
12286
12287 /*!
12288   Sets which axis orientation may be range dragged by the user with mouse interaction.
12289   What orientation corresponds to which specific axis can be set with
12290   \ref setRangeDragAxes(QCPAxis *horizontal, QCPAxis *vertical). By
12291   default, the horizontal axis is the bottom axis (xAxis) and the vertical axis
12292   is the left axis (yAxis).
12293   
12294   To disable range dragging entirely, pass 0 as \a orientations or remove \ref QCP::iRangeDrag from \ref
12295   QCustomPlot::setInteractions. To enable range dragging for both directions, pass <tt>Qt::Horizontal |
12296   Qt::Vertical</tt> as \a orientations.
12297   
12298   In addition to setting \a orientations to a non-zero value, make sure \ref QCustomPlot::setInteractions
12299   contains \ref QCP::iRangeDrag to enable the range dragging interaction.
12300   
12301   \see setRangeZoom, setRangeDragAxes, QCustomPlot::setNoAntialiasingOnDrag
12302 */
12303 void QCPAxisRect::setRangeDrag(Qt::Orientations orientations)
12304 {
12305   mRangeDrag = orientations;
12306 }
12307
12308 /*!
12309   Sets which axis orientation may be zoomed by the user with the mouse wheel. What orientation
12310   corresponds to which specific axis can be set with \ref setRangeZoomAxes(QCPAxis *horizontal,
12311   QCPAxis *vertical). By default, the horizontal axis is the bottom axis (xAxis) and the vertical
12312   axis is the left axis (yAxis).
12313
12314   To disable range zooming entirely, pass 0 as \a orientations or remove \ref QCP::iRangeZoom from \ref
12315   QCustomPlot::setInteractions. To enable range zooming for both directions, pass <tt>Qt::Horizontal |
12316   Qt::Vertical</tt> as \a orientations.
12317   
12318   In addition to setting \a orientations to a non-zero value, make sure \ref QCustomPlot::setInteractions
12319   contains \ref QCP::iRangeZoom to enable the range zooming interaction.
12320   
12321   \see setRangeZoomFactor, setRangeZoomAxes, setRangeDrag
12322 */
12323 void QCPAxisRect::setRangeZoom(Qt::Orientations orientations)
12324 {
12325   mRangeZoom = orientations;
12326 }
12327
12328 /*!
12329   Sets the axes whose range will be dragged when \ref setRangeDrag enables mouse range dragging
12330   on the QCustomPlot widget.
12331   
12332   \see setRangeZoomAxes
12333 */
12334 void QCPAxisRect::setRangeDragAxes(QCPAxis *horizontal, QCPAxis *vertical)
12335 {
12336   mRangeDragHorzAxis = horizontal;
12337   mRangeDragVertAxis = vertical;
12338 }
12339
12340 /*!
12341   Sets the axes whose range will be zoomed when \ref setRangeZoom enables mouse wheel zooming on the
12342   QCustomPlot widget. The two axes can be zoomed with different strengths, when different factors
12343   are passed to \ref setRangeZoomFactor(double horizontalFactor, double verticalFactor).
12344   
12345   \see setRangeDragAxes
12346 */
12347 void QCPAxisRect::setRangeZoomAxes(QCPAxis *horizontal, QCPAxis *vertical)
12348 {
12349   mRangeZoomHorzAxis = horizontal;
12350   mRangeZoomVertAxis = vertical;
12351 }
12352
12353 /*!
12354   Sets how strong one rotation step of the mouse wheel zooms, when range zoom was activated with
12355   \ref setRangeZoom. The two parameters \a horizontalFactor and \a verticalFactor provide a way to
12356   let the horizontal axis zoom at different rates than the vertical axis. Which axis is horizontal
12357   and which is vertical, can be set with \ref setRangeZoomAxes.
12358
12359   When the zoom factor is greater than one, scrolling the mouse wheel backwards (towards the user)
12360   will zoom in (make the currently visible range smaller). For zoom factors smaller than one, the
12361   same scrolling direction will zoom out.
12362 */
12363 void QCPAxisRect::setRangeZoomFactor(double horizontalFactor, double verticalFactor)
12364 {
12365   mRangeZoomFactorHorz = horizontalFactor;
12366   mRangeZoomFactorVert = verticalFactor;
12367 }
12368
12369 /*! \overload
12370   
12371   Sets both the horizontal and vertical zoom \a factor.
12372 */
12373 void QCPAxisRect::setRangeZoomFactor(double factor)
12374 {
12375   mRangeZoomFactorHorz = factor;
12376   mRangeZoomFactorVert = factor;
12377 }
12378
12379 /*! \internal
12380   
12381   Draws the background of this axis rect. It may consist of a background fill (a QBrush) and a
12382   pixmap.
12383   
12384   If a brush was given via \ref setBackground(const QBrush &brush), this function first draws an
12385   according filling inside the axis rect with the provided \a painter.
12386   
12387   Then, if a pixmap was provided via \ref setBackground, this function buffers the scaled version
12388   depending on \ref setBackgroundScaled and \ref setBackgroundScaledMode and then draws it inside
12389   the axis rect with the provided \a painter. The scaled version is buffered in
12390   mScaledBackgroundPixmap to prevent expensive rescaling at every redraw. It is only updated, when
12391   the axis rect has changed in a way that requires a rescale of the background pixmap (this is
12392   dependant on the \ref setBackgroundScaledMode), or when a differend axis backgroud pixmap was
12393   set.
12394   
12395   \see setBackground, setBackgroundScaled, setBackgroundScaledMode
12396 */
12397 void QCPAxisRect::drawBackground(QCPPainter *painter)
12398 {
12399   // draw background fill:
12400   if (mBackgroundBrush != Qt::NoBrush)
12401     painter->fillRect(mRect, mBackgroundBrush);
12402   
12403   // draw background pixmap (on top of fill, if brush specified):
12404   if (!mBackgroundPixmap.isNull())
12405   {
12406     if (mBackgroundScaled)
12407     {
12408       // check whether mScaledBackground needs to be updated:
12409       QSize scaledSize(mBackgroundPixmap.size());
12410       scaledSize.scale(mRect.size(), mBackgroundScaledMode);
12411       if (mScaledBackgroundPixmap.size() != scaledSize)
12412         mScaledBackgroundPixmap = mBackgroundPixmap.scaled(mRect.size(), mBackgroundScaledMode, Qt::SmoothTransformation);
12413       painter->drawPixmap(mRect.topLeft()+QPoint(0, -1), mScaledBackgroundPixmap, QRect(0, 0, mRect.width(), mRect.height()) & mScaledBackgroundPixmap.rect());
12414     } else
12415     {
12416       painter->drawPixmap(mRect.topLeft()+QPoint(0, -1), mBackgroundPixmap, QRect(0, 0, mRect.width(), mRect.height()));
12417     }
12418   }
12419 }
12420
12421 /*! \internal
12422   
12423   This function makes sure multiple axes on the side specified with \a type don't collide, but are
12424   distributed according to their respective space requirement (QCPAxis::calculateMargin).
12425   
12426   It does this by setting an appropriate offset (\ref QCPAxis::setOffset) on all axes except the
12427   one with index zero.
12428   
12429   This function is called by \ref calculateAutoMargin.
12430 */
12431 void QCPAxisRect::updateAxesOffset(QCPAxis::AxisType type)
12432 {
12433   const QList<QCPAxis*> axesList = mAxes.value(type);
12434   if (axesList.isEmpty())
12435     return;
12436   
12437   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
12438   for (int i=1; i<axesList.size(); ++i)
12439   {
12440     int offset = axesList.at(i-1)->offset() + axesList.at(i-1)->calculateMargin();
12441     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)
12442     {
12443       if (!isFirstVisible)
12444         offset += axesList.at(i)->tickLengthIn();
12445       isFirstVisible = false;
12446     }
12447     axesList.at(i)->setOffset(offset);
12448   }
12449 }
12450
12451 /* inherits documentation from base class */
12452 int QCPAxisRect::calculateAutoMargin(QCP::MarginSide side)
12453 {
12454   if (!mAutoMargins.testFlag(side))
12455     qDebug() << Q_FUNC_INFO << "Called with side that isn't specified as auto margin";
12456   
12457   updateAxesOffset(QCPAxis::marginSideToAxisType(side));
12458   
12459   // note: only need to look at the last (outer most) axis to determine the total margin, due to updateAxisOffset call
12460   const QList<QCPAxis*> axesList = mAxes.value(QCPAxis::marginSideToAxisType(side));
12461   if (axesList.size() > 0)
12462     return axesList.last()->offset() + axesList.last()->calculateMargin();
12463   else
12464     return 0;
12465 }
12466
12467 /*! \internal
12468   
12469   Event handler for when a mouse button is pressed on the axis rect. If the left mouse button is
12470   pressed, the range dragging interaction is initialized (the actual range manipulation happens in
12471   the \ref mouseMoveEvent).
12472
12473   The mDragging flag is set to true and some anchor points are set that are needed to determine the
12474   distance the mouse was dragged in the mouse move/release events later.
12475   
12476   \see mouseMoveEvent, mouseReleaseEvent
12477 */
12478 void QCPAxisRect::mousePressEvent(QMouseEvent *event)
12479 {
12480   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)
12481   if (event->buttons() & Qt::LeftButton)
12482   {
12483     mDragging = true;
12484     // initialize antialiasing backup in case we start dragging:
12485     if (mParentPlot->noAntialiasingOnDrag())
12486     {
12487       mAADragBackup = mParentPlot->antialiasedElements();
12488       mNotAADragBackup = mParentPlot->notAntialiasedElements();
12489     }
12490     // Mouse range dragging interaction:
12491     if (mParentPlot->interactions().testFlag(QCP::iRangeDrag))
12492     {
12493       if (mRangeDragHorzAxis)
12494         mDragStartHorzRange = mRangeDragHorzAxis.data()->range();
12495       if (mRangeDragVertAxis)
12496         mDragStartVertRange = mRangeDragVertAxis.data()->range();
12497     }
12498   }
12499 }
12500
12501 /*! \internal
12502   
12503   Event handler for when the mouse is moved on the axis rect. If range dragging was activated in a
12504   preceding \ref mousePressEvent, the range is moved accordingly.
12505   
12506   \see mousePressEvent, mouseReleaseEvent
12507 */
12508 void QCPAxisRect::mouseMoveEvent(QMouseEvent *event)
12509 {
12510   // Mouse range dragging interaction:
12511   if (mDragging && mParentPlot->interactions().testFlag(QCP::iRangeDrag))
12512   {
12513     if (mRangeDrag.testFlag(Qt::Horizontal))
12514     {
12515       if (QCPAxis *rangeDragHorzAxis = mRangeDragHorzAxis.data())
12516       {
12517         if (rangeDragHorzAxis->mScaleType == QCPAxis::stLinear)
12518         {
12519           double diff = rangeDragHorzAxis->pixelToCoord(mDragStart.x()) - rangeDragHorzAxis->pixelToCoord(event->pos().x());
12520           rangeDragHorzAxis->setRange(mDragStartHorzRange.lower+diff, mDragStartHorzRange.upper+diff);
12521         } else if (rangeDragHorzAxis->mScaleType == QCPAxis::stLogarithmic)
12522         {
12523           double diff = rangeDragHorzAxis->pixelToCoord(mDragStart.x()) / rangeDragHorzAxis->pixelToCoord(event->pos().x());
12524           rangeDragHorzAxis->setRange(mDragStartHorzRange.lower*diff, mDragStartHorzRange.upper*diff);
12525         }
12526       }
12527     }
12528     if (mRangeDrag.testFlag(Qt::Vertical))
12529     {
12530       if (QCPAxis *rangeDragVertAxis = mRangeDragVertAxis.data())
12531       {
12532         if (rangeDragVertAxis->mScaleType == QCPAxis::stLinear)
12533         {
12534           double diff = rangeDragVertAxis->pixelToCoord(mDragStart.y()) - rangeDragVertAxis->pixelToCoord(event->pos().y());
12535           rangeDragVertAxis->setRange(mDragStartVertRange.lower+diff, mDragStartVertRange.upper+diff);
12536         } else if (rangeDragVertAxis->mScaleType == QCPAxis::stLogarithmic)
12537         {
12538           double diff = rangeDragVertAxis->pixelToCoord(mDragStart.y()) / rangeDragVertAxis->pixelToCoord(event->pos().y());
12539           rangeDragVertAxis->setRange(mDragStartVertRange.lower*diff, mDragStartVertRange.upper*diff);
12540         }
12541       }
12542     }
12543     if (mRangeDrag != 0) // if either vertical or horizontal drag was enabled, do a replot
12544     {
12545       if (mParentPlot->noAntialiasingOnDrag())
12546         mParentPlot->setNotAntialiasedElements(QCP::aeAll);
12547       mParentPlot->replot();
12548     }
12549   }
12550 }
12551
12552 /* inherits documentation from base class */
12553 void QCPAxisRect::mouseReleaseEvent(QMouseEvent *event)
12554 {
12555   Q_UNUSED(event)
12556   mDragging = false;
12557   if (mParentPlot->noAntialiasingOnDrag())
12558   {
12559     mParentPlot->setAntialiasedElements(mAADragBackup);
12560     mParentPlot->setNotAntialiasedElements(mNotAADragBackup);
12561   }
12562 }
12563
12564 /*! \internal
12565   
12566   Event handler for mouse wheel events. If rangeZoom is Qt::Horizontal, Qt::Vertical or both, the
12567   ranges of the axes defined as rangeZoomHorzAxis and rangeZoomVertAxis are scaled. The center of
12568   the scaling operation is the current cursor position inside the axis rect. The scaling factor is
12569   dependant on the mouse wheel delta (which direction the wheel was rotated) to provide a natural
12570   zooming feel. The Strength of the zoom can be controlled via \ref setRangeZoomFactor.
12571   
12572   Note, that event->delta() is usually +/-120 for single rotation steps. However, if the mouse
12573   wheel is turned rapidly, many steps may bunch up to one event, so the event->delta() may then be
12574   multiples of 120. This is taken into account here, by calculating \a wheelSteps and using it as
12575   exponent of the range zoom factor. This takes care of the wheel direction automatically, by
12576   inverting the factor, when the wheel step is negative (f^-1 = 1/f).
12577 */
12578 void QCPAxisRect::wheelEvent(QWheelEvent *event)
12579 {
12580   // Mouse range zooming interaction:
12581   if (mParentPlot->interactions().testFlag(QCP::iRangeZoom))
12582   {
12583     if (mRangeZoom != 0)
12584     {
12585       double factor;
12586       double wheelSteps = event->delta()/120.0; // a single step delta is +/-120 usually
12587       if (mRangeZoom.testFlag(Qt::Horizontal))
12588       {
12589         factor = qPow(mRangeZoomFactorHorz, wheelSteps);
12590         if (mRangeZoomHorzAxis.data())
12591           mRangeZoomHorzAxis.data()->scaleRange(factor, mRangeZoomHorzAxis.data()->pixelToCoord(event->pos().x()));
12592       }
12593       if (mRangeZoom.testFlag(Qt::Vertical))
12594       {
12595         factor = qPow(mRangeZoomFactorVert, wheelSteps);
12596         if (mRangeZoomVertAxis.data())
12597           mRangeZoomVertAxis.data()->scaleRange(factor, mRangeZoomVertAxis.data()->pixelToCoord(event->pos().y()));
12598       }
12599       mParentPlot->replot();
12600     }
12601   }
12602 }
12603
12604
12605 ////////////////////////////////////////////////////////////////////////////////////////////////////
12606 //////////////////// QCPAbstractLegendItem
12607 ////////////////////////////////////////////////////////////////////////////////////////////////////
12608
12609 /*! \class QCPAbstractLegendItem
12610   \brief The abstract base class for all entries in a QCPLegend.
12611   
12612   It defines a very basic interface for entries in a QCPLegend. For representing plottables in the
12613   legend, the subclass \ref QCPPlottableLegendItem is more suitable.
12614   
12615   Only derive directly from this class when you need absolute freedom (e.g. a custom legend entry
12616   that's not even associated with a plottable).
12617
12618   You must implement the following pure virtual functions:
12619   \li \ref draw (from QCPLayerable)
12620   
12621   You inherit the following members you may use:
12622   <table>
12623     <tr>
12624       <td>QCPLegend *\b mParentLegend</td>
12625       <td>A pointer to the parent QCPLegend.</td>
12626     </tr><tr>
12627       <td>QFont \b mFont</td>
12628       <td>The generic font of the item. You should use this font for all or at least the most prominent text of the item.</td>
12629     </tr>
12630   </table>
12631 */
12632
12633 /* start of documentation of signals */
12634
12635 /*! \fn void QCPAbstractLegendItem::selectionChanged(bool selected)
12636   
12637   This signal is emitted when the selection state of this legend item has changed, either by user
12638   interaction or by a direct call to \ref setSelected.
12639 */
12640
12641 /* end of documentation of signals */
12642
12643 /*!
12644   Constructs a QCPAbstractLegendItem and associates it with the QCPLegend \a parent. This does not
12645   cause the item to be added to \a parent, so \ref QCPLegend::addItem must be called separately.
12646 */
12647 QCPAbstractLegendItem::QCPAbstractLegendItem(QCPLegend *parent) :
12648   QCPLayoutElement(parent->parentPlot()),
12649   mParentLegend(parent),
12650   mFont(parent->font()),
12651   mTextColor(parent->textColor()),
12652   mSelectedFont(parent->selectedFont()),
12653   mSelectedTextColor(parent->selectedTextColor()),
12654   mSelectable(true),
12655   mSelected(false)
12656 {
12657   setLayer(QLatin1String("legend"));
12658   setMargins(QMargins(8, 2, 8, 2));
12659 }
12660
12661 /*!
12662   Sets the default font of this specific legend item to \a font.
12663   
12664   \see setTextColor, QCPLegend::setFont
12665 */
12666 void QCPAbstractLegendItem::setFont(const QFont &font)
12667 {
12668   mFont = font;
12669 }
12670
12671 /*!
12672   Sets the default text color of this specific legend item to \a color.
12673   
12674   \see setFont, QCPLegend::setTextColor
12675 */
12676 void QCPAbstractLegendItem::setTextColor(const QColor &color)
12677 {
12678   mTextColor = color;
12679 }
12680
12681 /*!
12682   When this legend item is selected, \a font is used to draw generic text, instead of the normal
12683   font set with \ref setFont.
12684   
12685   \see setFont, QCPLegend::setSelectedFont
12686 */
12687 void QCPAbstractLegendItem::setSelectedFont(const QFont &font)
12688 {
12689   mSelectedFont = font;
12690 }
12691
12692 /*!
12693   When this legend item is selected, \a color is used to draw generic text, instead of the normal
12694   color set with \ref setTextColor.
12695   
12696   \see setTextColor, QCPLegend::setSelectedTextColor
12697 */
12698 void QCPAbstractLegendItem::setSelectedTextColor(const QColor &color)
12699 {
12700   mSelectedTextColor = color;
12701 }
12702
12703 /*!
12704   Sets whether this specific legend item is selectable.
12705   
12706   \see setSelectedParts, QCustomPlot::setInteractions
12707 */
12708 void QCPAbstractLegendItem::setSelectable(bool selectable)
12709 {
12710   if (mSelectable != selectable)
12711   {
12712     mSelectable = selectable;
12713     emit selectableChanged(mSelectable);
12714   }
12715 }
12716
12717 /*!
12718   Sets whether this specific legend item is selected.
12719   
12720   It is possible to set the selection state of this item by calling this function directly, even if
12721   setSelectable is set to false.
12722   
12723   \see setSelectableParts, QCustomPlot::setInteractions
12724 */
12725 void QCPAbstractLegendItem::setSelected(bool selected)
12726 {
12727   if (mSelected != selected)
12728   {
12729     mSelected = selected;
12730     emit selectionChanged(mSelected);
12731   }
12732 }
12733
12734 /* inherits documentation from base class */
12735 double QCPAbstractLegendItem::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
12736 {
12737   Q_UNUSED(details)
12738   if (!mParentPlot) return -1;
12739   if (onlySelectable && (!mSelectable || !mParentLegend->selectableParts().testFlag(QCPLegend::spItems)))
12740     return -1;
12741   
12742   if (mRect.contains(pos.toPoint()))
12743     return mParentPlot->selectionTolerance()*0.99;
12744   else
12745     return -1;
12746 }
12747
12748 /* inherits documentation from base class */
12749 void QCPAbstractLegendItem::applyDefaultAntialiasingHint(QCPPainter *painter) const
12750 {
12751   applyAntialiasingHint(painter, mAntialiased, QCP::aeLegendItems);
12752 }
12753
12754 /* inherits documentation from base class */
12755 QRect QCPAbstractLegendItem::clipRect() const
12756 {
12757   return mOuterRect;
12758 }
12759
12760 /* inherits documentation from base class */
12761 void QCPAbstractLegendItem::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged)
12762 {
12763   Q_UNUSED(event)
12764   Q_UNUSED(details)
12765   if (mSelectable && mParentLegend->selectableParts().testFlag(QCPLegend::spItems))
12766   {
12767     bool selBefore = mSelected;
12768     setSelected(additive ? !mSelected : true);
12769     if (selectionStateChanged)
12770       *selectionStateChanged = mSelected != selBefore;
12771   }
12772 }
12773
12774 /* inherits documentation from base class */
12775 void QCPAbstractLegendItem::deselectEvent(bool *selectionStateChanged)
12776 {
12777   if (mSelectable && mParentLegend->selectableParts().testFlag(QCPLegend::spItems))
12778   {
12779     bool selBefore = mSelected;
12780     setSelected(false);
12781     if (selectionStateChanged)
12782       *selectionStateChanged = mSelected != selBefore;
12783   }
12784 }
12785
12786 ////////////////////////////////////////////////////////////////////////////////////////////////////
12787 //////////////////// QCPPlottableLegendItem
12788 ////////////////////////////////////////////////////////////////////////////////////////////////////
12789
12790 /*! \class QCPPlottableLegendItem
12791   \brief A legend item representing a plottable with an icon and the plottable name.
12792   
12793   This is the standard legend item for plottables. It displays an icon of the plottable next to the
12794   plottable name. The icon is drawn by the respective plottable itself (\ref
12795   QCPAbstractPlottable::drawLegendIcon), and tries to give an intuitive symbol for the plottable.
12796   For example, the QCPGraph draws a centered horizontal line and/or a single scatter point in the
12797   middle.
12798   
12799   Legend items of this type are always associated with one plottable (retrievable via the
12800   plottable() function and settable with the constructor). You may change the font of the plottable
12801   name with \ref setFont. Icon padding and border pen is taken from the parent QCPLegend, see \ref
12802   QCPLegend::setIconBorderPen and \ref QCPLegend::setIconTextPadding.
12803
12804   The function \ref QCPAbstractPlottable::addToLegend/\ref QCPAbstractPlottable::removeFromLegend
12805   creates/removes legend items of this type in the default implementation. However, these functions
12806   may be reimplemented such that a different kind of legend item (e.g a direct subclass of
12807   QCPAbstractLegendItem) is used for that plottable.
12808   
12809   Since QCPLegend is based on QCPLayoutGrid, a legend item itself is just a subclass of
12810   QCPLayoutElement. While it could be added to a legend (or any other layout) via the normal layout
12811   interface, QCPLegend has specialized functions for handling legend items conveniently, see the
12812   documentation of \ref QCPLegend.
12813 */
12814
12815 /*!
12816   Creates a new legend item associated with \a plottable.
12817   
12818   Once it's created, it can be added to the legend via \ref QCPLegend::addItem.
12819   
12820   A more convenient way of adding/removing a plottable to/from the legend is via the functions \ref
12821   QCPAbstractPlottable::addToLegend and \ref QCPAbstractPlottable::removeFromLegend.
12822 */
12823 QCPPlottableLegendItem::QCPPlottableLegendItem(QCPLegend *parent, QCPAbstractPlottable *plottable) :
12824   QCPAbstractLegendItem(parent),
12825   mPlottable(plottable)
12826 {
12827 }
12828
12829 /*! \internal
12830   
12831   Returns the pen that shall be used to draw the icon border, taking into account the selection
12832   state of this item.
12833 */
12834 QPen QCPPlottableLegendItem::getIconBorderPen() const
12835 {
12836   return mSelected ? mParentLegend->selectedIconBorderPen() : mParentLegend->iconBorderPen();
12837 }
12838
12839 /*! \internal
12840   
12841   Returns the text color that shall be used to draw text, taking into account the selection state
12842   of this item.
12843 */
12844 QColor QCPPlottableLegendItem::getTextColor() const
12845 {
12846   return mSelected ? mSelectedTextColor : mTextColor;
12847 }
12848
12849 /*! \internal
12850   
12851   Returns the font that shall be used to draw text, taking into account the selection state of this
12852   item.
12853 */
12854 QFont QCPPlottableLegendItem::getFont() const
12855 {
12856   return mSelected ? mSelectedFont : mFont;
12857 }
12858
12859 /*! \internal
12860   
12861   Draws the item with \a painter. The size and position of the drawn legend item is defined by the
12862   parent layout (typically a \ref QCPLegend) and the \ref minimumSizeHint and \ref maximumSizeHint
12863   of this legend item.
12864 */
12865 void QCPPlottableLegendItem::draw(QCPPainter *painter)
12866 {
12867   if (!mPlottable) return;
12868   painter->setFont(getFont());
12869   painter->setPen(QPen(getTextColor()));
12870   QSizeF iconSize = mParentLegend->iconSize();
12871   QRectF textRect = painter->fontMetrics().boundingRect(0, 0, 0, iconSize.height(), Qt::TextDontClip, mPlottable->name());
12872   QRectF iconRect(mRect.topLeft(), iconSize);
12873   int textHeight = qMax(textRect.height(), iconSize.height());  // if text has smaller height than icon, center text vertically in icon height, else align tops
12874   painter->drawText(mRect.x()+iconSize.width()+mParentLegend->iconTextPadding(), mRect.y(), textRect.width(), textHeight, Qt::TextDontClip, mPlottable->name());
12875   // draw icon:
12876   painter->save();
12877   painter->setClipRect(iconRect, Qt::IntersectClip);
12878   mPlottable->drawLegendIcon(painter, iconRect);
12879   painter->restore();
12880   // draw icon border:
12881   if (getIconBorderPen().style() != Qt::NoPen)
12882   {
12883     painter->setPen(getIconBorderPen());
12884     painter->setBrush(Qt::NoBrush);
12885     painter->drawRect(iconRect);
12886   }
12887 }
12888
12889 /*! \internal
12890   
12891   Calculates and returns the size of this item. This includes the icon, the text and the padding in
12892   between.
12893 */
12894 QSize QCPPlottableLegendItem::minimumSizeHint() const
12895 {
12896   if (!mPlottable) return QSize();
12897   QSize result(0, 0);
12898   QRect textRect;
12899   QFontMetrics fontMetrics(getFont());
12900   QSize iconSize = mParentLegend->iconSize();
12901   textRect = fontMetrics.boundingRect(0, 0, 0, iconSize.height(), Qt::TextDontClip, mPlottable->name());
12902   result.setWidth(iconSize.width() + mParentLegend->iconTextPadding() + textRect.width() + mMargins.left() + mMargins.right());
12903   result.setHeight(qMax(textRect.height(), iconSize.height()) + mMargins.top() + mMargins.bottom());
12904   return result;
12905 }
12906
12907
12908 ////////////////////////////////////////////////////////////////////////////////////////////////////
12909 //////////////////// QCPLegend
12910 ////////////////////////////////////////////////////////////////////////////////////////////////////
12911
12912 /*! \class QCPLegend
12913   \brief Manages a legend inside a QCustomPlot.
12914
12915   A legend is a small box somewhere in the plot which lists plottables with their name and icon.
12916   
12917   Normally, the legend is populated by calling \ref QCPAbstractPlottable::addToLegend. The
12918   respective legend item can be removed with \ref QCPAbstractPlottable::removeFromLegend. However,
12919   QCPLegend also offers an interface to add and manipulate legend items directly: \ref item, \ref
12920   itemWithPlottable, \ref itemCount, \ref addItem, \ref removeItem, etc.
12921   
12922   The QCPLegend derives from QCPLayoutGrid and as such can be placed in any position a
12923   QCPLayoutElement may be positioned. The legend items are themselves QCPLayoutElements which are
12924   placed in the grid layout of the legend. QCPLegend only adds an interface specialized for
12925   handling child elements of type QCPAbstractLegendItem, as mentioned above. In principle, any
12926   other layout elements may also be added to a legend via the normal \ref QCPLayoutGrid interface.
12927   However, the QCPAbstractLegendItem-Interface will ignore those elements (e.g. \ref itemCount will
12928   only return the number of items with QCPAbstractLegendItems type).
12929
12930   By default, every QCustomPlot has one legend (QCustomPlot::legend) which is placed in the inset
12931   layout of the main axis rect (\ref QCPAxisRect::insetLayout). To move the legend to another
12932   position inside the axis rect, use the methods of the \ref QCPLayoutInset. To move the legend
12933   outside of the axis rect, place it anywhere else with the QCPLayout/QCPLayoutElement interface.
12934 */
12935
12936 /* start of documentation of signals */
12937
12938 /*! \fn void QCPLegend::selectionChanged(QCPLegend::SelectableParts selection);
12939
12940   This signal is emitted when the selection state of this legend has changed.
12941   
12942   \see setSelectedParts, setSelectableParts
12943 */
12944
12945 /* end of documentation of signals */
12946
12947 /*!
12948   Constructs a new QCPLegend instance with \a parentPlot as the containing plot and default values.
12949   
12950   Note that by default, QCustomPlot already contains a legend ready to be used as
12951   QCustomPlot::legend
12952 */
12953 QCPLegend::QCPLegend()
12954 {
12955   setRowSpacing(0);
12956   setColumnSpacing(10);
12957   setMargins(QMargins(2, 3, 2, 2));
12958   setAntialiased(false);
12959   setIconSize(32, 18);
12960   
12961   setIconTextPadding(7);
12962   
12963   setSelectableParts(spLegendBox | spItems);
12964   setSelectedParts(spNone);
12965   
12966   setBorderPen(QPen(Qt::black));
12967   setSelectedBorderPen(QPen(Qt::blue, 2));
12968   setIconBorderPen(Qt::NoPen);
12969   setSelectedIconBorderPen(QPen(Qt::blue, 2));
12970   setBrush(Qt::white);
12971   setSelectedBrush(Qt::white);
12972   setTextColor(Qt::black);
12973   setSelectedTextColor(Qt::blue);
12974 }
12975
12976 QCPLegend::~QCPLegend()
12977 {
12978   clearItems();
12979   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)
12980     mParentPlot->legendRemoved(this);
12981 }
12982
12983 /* no doc for getter, see setSelectedParts */
12984 QCPLegend::SelectableParts QCPLegend::selectedParts() const
12985 {
12986   // check whether any legend elements selected, if yes, add spItems to return value
12987   bool hasSelectedItems = false;
12988   for (int i=0; i<itemCount(); ++i)
12989   {
12990     if (item(i) && item(i)->selected())
12991     {
12992       hasSelectedItems = true;
12993       break;
12994     }
12995   }
12996   if (hasSelectedItems)
12997     return mSelectedParts | spItems;
12998   else
12999     return mSelectedParts & ~spItems;
13000 }
13001
13002 /*!
13003   Sets the pen, the border of the entire legend is drawn with.
13004 */
13005 void QCPLegend::setBorderPen(const QPen &pen)
13006 {
13007   mBorderPen = pen;
13008 }
13009
13010 /*!
13011   Sets the brush of the legend background.
13012 */
13013 void QCPLegend::setBrush(const QBrush &brush)
13014 {
13015   mBrush = brush;
13016 }
13017
13018 /*!
13019   Sets the default font of legend text. Legend items that draw text (e.g. the name of a graph) will
13020   use this font by default. However, a different font can be specified on a per-item-basis by
13021   accessing the specific legend item.
13022   
13023   This function will also set \a font on all already existing legend items.
13024   
13025   \see QCPAbstractLegendItem::setFont
13026 */
13027 void QCPLegend::setFont(const QFont &font)
13028 {
13029   mFont = font;
13030   for (int i=0; i<itemCount(); ++i)
13031   {
13032     if (item(i))
13033       item(i)->setFont(mFont);
13034   }
13035 }
13036
13037 /*!
13038   Sets the default color of legend text. Legend items that draw text (e.g. the name of a graph)
13039   will use this color by default. However, a different colors can be specified on a per-item-basis
13040   by accessing the specific legend item.
13041   
13042   This function will also set \a color on all already existing legend items.
13043   
13044   \see QCPAbstractLegendItem::setTextColor
13045 */
13046 void QCPLegend::setTextColor(const QColor &color)
13047 {
13048   mTextColor = color;
13049   for (int i=0; i<itemCount(); ++i)
13050   {
13051     if (item(i))
13052       item(i)->setTextColor(color);
13053   }
13054 }
13055
13056 /*!
13057   Sets the size of legend icons. Legend items that draw an icon (e.g. a visual
13058   representation of the graph) will use this size by default.
13059 */
13060 void QCPLegend::setIconSize(const QSize &size)
13061 {
13062   mIconSize = size;
13063 }
13064
13065 /*! \overload
13066 */
13067 void QCPLegend::setIconSize(int width, int height)
13068 {
13069   mIconSize.setWidth(width);
13070   mIconSize.setHeight(height);
13071 }
13072
13073 /*!
13074   Sets the horizontal space in pixels between the legend icon and the text next to it.
13075   Legend items that draw an icon (e.g. a visual representation of the graph) and text (e.g. the
13076   name of the graph) will use this space by default.
13077 */
13078 void QCPLegend::setIconTextPadding(int padding)
13079 {
13080   mIconTextPadding = padding;
13081 }
13082
13083 /*!
13084   Sets the pen used to draw a border around each legend icon. Legend items that draw an
13085   icon (e.g. a visual representation of the graph) will use this pen by default.
13086   
13087   If no border is wanted, set this to \a Qt::NoPen.
13088 */
13089 void QCPLegend::setIconBorderPen(const QPen &pen)
13090 {
13091   mIconBorderPen = pen;
13092 }
13093
13094 /*!
13095   Sets whether the user can (de-)select the parts in \a selectable by clicking on the QCustomPlot surface.
13096   (When \ref QCustomPlot::setInteractions contains \ref QCP::iSelectLegend.)
13097   
13098   However, even when \a selectable is set to a value not allowing the selection of a specific part,
13099   it is still possible to set the selection of this part manually, by calling \ref setSelectedParts
13100   directly.
13101   
13102   \see SelectablePart, setSelectedParts
13103 */
13104 void QCPLegend::setSelectableParts(const SelectableParts &selectable)
13105 {
13106   if (mSelectableParts != selectable)
13107   {
13108     mSelectableParts = selectable;
13109     emit selectableChanged(mSelectableParts);
13110   }
13111 }
13112
13113 /*!
13114   Sets the selected state of the respective legend parts described by \ref SelectablePart. When a part
13115   is selected, it uses a different pen/font and brush. If some legend items are selected and \a selected
13116   doesn't contain \ref spItems, those items become deselected.
13117   
13118   The entire selection mechanism is handled automatically when \ref QCustomPlot::setInteractions
13119   contains iSelectLegend. You only need to call this function when you wish to change the selection
13120   state manually.
13121   
13122   This function can change the selection state of a part even when \ref setSelectableParts was set to a
13123   value that actually excludes the part.
13124   
13125   emits the \ref selectionChanged signal when \a selected is different from the previous selection state.
13126   
13127   Note that it doesn't make sense to set the selected state \ref spItems here when it wasn't set
13128   before, because there's no way to specify which exact items to newly select. Do this by calling
13129   \ref QCPAbstractLegendItem::setSelected directly on the legend item you wish to select.
13130   
13131   \see SelectablePart, setSelectableParts, selectTest, setSelectedBorderPen, setSelectedIconBorderPen, setSelectedBrush,
13132   setSelectedFont
13133 */
13134 void QCPLegend::setSelectedParts(const SelectableParts &selected)
13135 {
13136   SelectableParts newSelected = selected;
13137   mSelectedParts = this->selectedParts(); // update mSelectedParts in case item selection changed
13138
13139   if (mSelectedParts != newSelected)
13140   {
13141     if (!mSelectedParts.testFlag(spItems) && newSelected.testFlag(spItems)) // attempt to set spItems flag (can't do that)
13142     {
13143       qDebug() << Q_FUNC_INFO << "spItems flag can not be set, it can only be unset with this function";
13144       newSelected &= ~spItems;
13145     }
13146     if (mSelectedParts.testFlag(spItems) && !newSelected.testFlag(spItems)) // spItems flag was unset, so clear item selection
13147     {
13148       for (int i=0; i<itemCount(); ++i)
13149       {
13150         if (item(i))
13151           item(i)->setSelected(false);
13152       }
13153     }
13154     mSelectedParts = newSelected;
13155     emit selectionChanged(mSelectedParts);
13156   }
13157 }
13158
13159 /*!
13160   When the legend box is selected, this pen is used to draw the border instead of the normal pen
13161   set via \ref setBorderPen.
13162
13163   \see setSelectedParts, setSelectableParts, setSelectedBrush
13164 */
13165 void QCPLegend::setSelectedBorderPen(const QPen &pen)
13166 {
13167   mSelectedBorderPen = pen;
13168 }
13169
13170 /*!
13171   Sets the pen legend items will use to draw their icon borders, when they are selected.
13172
13173   \see setSelectedParts, setSelectableParts, setSelectedFont
13174 */
13175 void QCPLegend::setSelectedIconBorderPen(const QPen &pen)
13176 {
13177   mSelectedIconBorderPen = pen;
13178 }
13179
13180 /*!
13181   When the legend box is selected, this brush is used to draw the legend background instead of the normal brush
13182   set via \ref setBrush.
13183
13184   \see setSelectedParts, setSelectableParts, setSelectedBorderPen
13185 */
13186 void QCPLegend::setSelectedBrush(const QBrush &brush)
13187 {
13188   mSelectedBrush = brush;
13189 }
13190
13191 /*!
13192   Sets the default font that is used by legend items when they are selected.
13193   
13194   This function will also set \a font on all already existing legend items.
13195
13196   \see setFont, QCPAbstractLegendItem::setSelectedFont
13197 */
13198 void QCPLegend::setSelectedFont(const QFont &font)
13199 {
13200   mSelectedFont = font;
13201   for (int i=0; i<itemCount(); ++i)
13202   {
13203     if (item(i))
13204       item(i)->setSelectedFont(font);
13205   }
13206 }
13207
13208 /*!
13209   Sets the default text color that is used by legend items when they are selected.
13210   
13211   This function will also set \a color on all already existing legend items.
13212
13213   \see setTextColor, QCPAbstractLegendItem::setSelectedTextColor
13214 */
13215 void QCPLegend::setSelectedTextColor(const QColor &color)
13216 {
13217   mSelectedTextColor = color;
13218   for (int i=0; i<itemCount(); ++i)
13219   {
13220     if (item(i))
13221       item(i)->setSelectedTextColor(color);
13222   }
13223 }
13224
13225 /*!
13226   Returns the item with index \a i.
13227   
13228   \see itemCount
13229 */
13230 QCPAbstractLegendItem *QCPLegend::item(int index) const
13231 {
13232   return qobject_cast<QCPAbstractLegendItem*>(elementAt(index));
13233 }
13234
13235 /*!
13236   Returns the QCPPlottableLegendItem which is associated with \a plottable (e.g. a \ref QCPGraph*).
13237   If such an item isn't in the legend, returns 0.
13238   
13239   \see hasItemWithPlottable
13240 */
13241 QCPPlottableLegendItem *QCPLegend::itemWithPlottable(const QCPAbstractPlottable *plottable) const
13242 {
13243   for (int i=0; i<itemCount(); ++i)
13244   {
13245     if (QCPPlottableLegendItem *pli = qobject_cast<QCPPlottableLegendItem*>(item(i)))
13246     {
13247       if (pli->plottable() == plottable)
13248         return pli;
13249     }
13250   }
13251   return 0;
13252 }
13253
13254 /*!
13255   Returns the number of items currently in the legend.
13256   \see item
13257 */
13258 int QCPLegend::itemCount() const
13259 {
13260   return elementCount();
13261 }
13262
13263 /*!
13264   Returns whether the legend contains \a itm.
13265 */
13266 bool QCPLegend::hasItem(QCPAbstractLegendItem *item) const
13267 {
13268   for (int i=0; i<itemCount(); ++i)
13269   {
13270     if (item == this->item(i))
13271         return true;
13272   }
13273   return false;
13274 }
13275
13276 /*!
13277   Returns whether the legend contains a QCPPlottableLegendItem which is associated with \a plottable (e.g. a \ref QCPGraph*).
13278   If such an item isn't in the legend, returns false.
13279   
13280   \see itemWithPlottable
13281 */
13282 bool QCPLegend::hasItemWithPlottable(const QCPAbstractPlottable *plottable) const
13283 {
13284   return itemWithPlottable(plottable);
13285 }
13286
13287 /*!
13288   Adds \a item to the legend, if it's not present already.
13289   
13290   Returns true on sucess, i.e. if the item wasn't in the list already and has been successfuly added.
13291   
13292   The legend takes ownership of the item.
13293 */
13294 bool QCPLegend::addItem(QCPAbstractLegendItem *item)
13295 {
13296   if (!hasItem(item))
13297   {
13298     return addElement(rowCount(), 0, item);
13299   } else
13300     return false;
13301 }
13302
13303 /*!
13304   Removes the item with index \a index from the legend.
13305
13306   Returns true, if successful.
13307   
13308   \see itemCount, clearItems
13309 */
13310 bool QCPLegend::removeItem(int index)
13311 {
13312   if (QCPAbstractLegendItem *ali = item(index))
13313   {
13314     bool success = remove(ali);
13315     simplify();
13316     return success;
13317   } else
13318     return false;
13319 }
13320
13321 /*! \overload
13322   
13323   Removes \a item from the legend.
13324
13325   Returns true, if successful.
13326   
13327   \see clearItems
13328 */
13329 bool QCPLegend::removeItem(QCPAbstractLegendItem *item)
13330 {
13331   bool success = remove(item);
13332   simplify();
13333   return success;
13334 }
13335
13336 /*!
13337   Removes all items from the legend.
13338 */
13339 void QCPLegend::clearItems()
13340 {
13341   for (int i=itemCount()-1; i>=0; --i)
13342     removeItem(i);
13343 }
13344
13345 /*!
13346   Returns the legend items that are currently selected. If no items are selected,
13347   the list is empty.
13348   
13349   \see QCPAbstractLegendItem::setSelected, setSelectable
13350 */
13351 QList<QCPAbstractLegendItem *> QCPLegend::selectedItems() const
13352 {
13353   QList<QCPAbstractLegendItem*> result;
13354   for (int i=0; i<itemCount(); ++i)
13355   {
13356     if (QCPAbstractLegendItem *ali = item(i))
13357     {
13358       if (ali->selected())
13359         result.append(ali);
13360     }
13361   }
13362   return result;
13363 }
13364
13365 /*! \internal
13366
13367   A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter
13368   before drawing main legend elements.
13369
13370   This is the antialiasing state the painter passed to the \ref draw method is in by default.
13371   
13372   This function takes into account the local setting of the antialiasing flag as well as the
13373   overrides set with \ref QCustomPlot::setAntialiasedElements and \ref
13374   QCustomPlot::setNotAntialiasedElements.
13375   
13376   \see setAntialiased
13377 */
13378 void QCPLegend::applyDefaultAntialiasingHint(QCPPainter *painter) const
13379 {
13380   applyAntialiasingHint(painter, mAntialiased, QCP::aeLegend);
13381 }
13382
13383 /*! \internal
13384   
13385   Returns the pen used to paint the border of the legend, taking into account the selection state
13386   of the legend box.
13387 */
13388 QPen QCPLegend::getBorderPen() const
13389 {
13390   return mSelectedParts.testFlag(spLegendBox) ? mSelectedBorderPen : mBorderPen;
13391 }
13392
13393 /*! \internal
13394   
13395   Returns the brush used to paint the background of the legend, taking into account the selection
13396   state of the legend box.
13397 */
13398 QBrush QCPLegend::getBrush() const
13399 {
13400   return mSelectedParts.testFlag(spLegendBox) ? mSelectedBrush : mBrush;
13401 }
13402
13403 /*! \internal
13404   
13405   Draws the legend box with the provided \a painter. The individual legend items are layerables
13406   themselves, thus are drawn independently.
13407 */
13408 void QCPLegend::draw(QCPPainter *painter)
13409 {
13410   // draw background rect:
13411   painter->setBrush(getBrush());
13412   painter->setPen(getBorderPen());
13413   painter->drawRect(mOuterRect);
13414 }
13415
13416 /* inherits documentation from base class */
13417 double QCPLegend::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
13418 {
13419   if (!mParentPlot) return -1;
13420   if (onlySelectable && !mSelectableParts.testFlag(spLegendBox))
13421     return -1;
13422   
13423   if (mOuterRect.contains(pos.toPoint()))
13424   {
13425     if (details) details->setValue(spLegendBox);
13426     return mParentPlot->selectionTolerance()*0.99;
13427   }
13428   return -1;
13429 }
13430
13431 /* inherits documentation from base class */
13432 void QCPLegend::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged)
13433 {
13434   Q_UNUSED(event)
13435   mSelectedParts = selectedParts(); // in case item selection has changed
13436   if (details.value<SelectablePart>() == spLegendBox && mSelectableParts.testFlag(spLegendBox))
13437   {
13438     SelectableParts selBefore = mSelectedParts;
13439     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)
13440     if (selectionStateChanged)
13441       *selectionStateChanged = mSelectedParts != selBefore;
13442   }
13443 }
13444
13445 /* inherits documentation from base class */
13446 void QCPLegend::deselectEvent(bool *selectionStateChanged)
13447 {
13448   mSelectedParts = selectedParts(); // in case item selection has changed
13449   if (mSelectableParts.testFlag(spLegendBox))
13450   {
13451     SelectableParts selBefore = mSelectedParts;
13452     setSelectedParts(selectedParts() & ~spLegendBox);
13453     if (selectionStateChanged)
13454       *selectionStateChanged = mSelectedParts != selBefore;
13455   }
13456 }
13457
13458 /* inherits documentation from base class */
13459 QCP::Interaction QCPLegend::selectionCategory() const
13460 {
13461   return QCP::iSelectLegend;
13462 }
13463
13464 /* inherits documentation from base class */
13465 QCP::Interaction QCPAbstractLegendItem::selectionCategory() const
13466 {
13467   return QCP::iSelectLegend;
13468 }
13469
13470 /* inherits documentation from base class */
13471 void QCPLegend::parentPlotInitialized(QCustomPlot *parentPlot)
13472 {
13473   Q_UNUSED(parentPlot)
13474 }
13475
13476
13477 ////////////////////////////////////////////////////////////////////////////////////////////////////
13478 //////////////////// QCPPlotTitle
13479 ////////////////////////////////////////////////////////////////////////////////////////////////////
13480
13481 /*! \class QCPPlotTitle
13482   \brief A layout element displaying a plot title text
13483   
13484   The text may be specified with \ref setText, theformatting can be controlled with \ref setFont
13485   and \ref setTextColor.
13486   
13487   A plot title can be added as follows:
13488   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpplottitle-creation
13489   
13490   Since a plot title is a common requirement, QCustomPlot offers specialized selection signals for
13491   easy interaction with QCPPlotTitle. If a layout element of type QCPPlotTitle is clicked, the
13492   signal \ref QCustomPlot::titleClick is emitted. A double click emits the \ref
13493   QCustomPlot::titleDoubleClick signal.
13494 */
13495
13496 /* start documentation of signals */
13497
13498 /*! \fn void QCPPlotTitle::selectionChanged(bool selected)
13499   
13500   This signal is emitted when the selection state has changed to \a selected, either by user
13501   interaction or by a direct call to \ref setSelected.
13502   
13503   \see setSelected, setSelectable
13504 */
13505
13506 /* end documentation of signals */
13507
13508 /*!
13509   Creates a new QCPPlotTitle instance and sets default values. The initial text is empty (\ref setText).
13510   
13511   To set the title text in the constructor, rather use \ref QCPPlotTitle(QCustomPlot *parentPlot, const QString &text).
13512 */
13513 QCPPlotTitle::QCPPlotTitle(QCustomPlot *parentPlot) :
13514   QCPLayoutElement(parentPlot),
13515   mFont(QFont(QLatin1String("sans serif"), 13*1.5, QFont::Bold)),
13516   mTextColor(Qt::black),
13517   mSelectedFont(QFont(QLatin1String("sans serif"), 13*1.6, QFont::Bold)),
13518   mSelectedTextColor(Qt::blue),
13519   mSelectable(false),
13520   mSelected(false)
13521 {
13522   if (parentPlot)
13523   {
13524     setLayer(parentPlot->currentLayer());
13525     mFont = QFont(parentPlot->font().family(), parentPlot->font().pointSize()*1.5, QFont::Bold);
13526     mSelectedFont = QFont(parentPlot->font().family(), parentPlot->font().pointSize()*1.6, QFont::Bold);
13527   }
13528   setMargins(QMargins(5, 5, 5, 0));
13529 }
13530
13531 /*! \overload
13532   
13533   Creates a new QCPPlotTitle instance and sets default values. The initial text is set to \a text.
13534 */
13535 QCPPlotTitle::QCPPlotTitle(QCustomPlot *parentPlot, const QString &text) :
13536   QCPLayoutElement(parentPlot),
13537   mText(text),
13538   mFont(QFont(parentPlot->font().family(), parentPlot->font().pointSize()*1.5, QFont::Bold)),
13539   mTextColor(Qt::black),
13540   mSelectedFont(QFont(parentPlot->font().family(), parentPlot->font().pointSize()*1.6, QFont::Bold)),
13541   mSelectedTextColor(Qt::blue),
13542   mSelectable(false),
13543   mSelected(false)
13544 {
13545   setLayer(QLatin1String("axes"));
13546   setMargins(QMargins(5, 5, 5, 0));
13547 }
13548
13549 /*!
13550   Sets the text that will be displayed to \a text. Multiple lines can be created by insertion of "\n".
13551   
13552   \see setFont, setTextColor
13553 */
13554 void QCPPlotTitle::setText(const QString &text)
13555 {
13556   mText = text;
13557 }
13558
13559 /*!
13560   Sets the \a font of the title text.
13561   
13562   \see setTextColor, setSelectedFont
13563 */
13564 void QCPPlotTitle::setFont(const QFont &font)
13565 {
13566   mFont = font;
13567 }
13568
13569 /*!
13570   Sets the \a color of the title text.
13571   
13572   \see setFont, setSelectedTextColor
13573 */
13574 void QCPPlotTitle::setTextColor(const QColor &color)
13575 {
13576   mTextColor = color;
13577 }
13578
13579 /*!
13580   Sets the \a font of the title text that will be used if the plot title is selected (\ref setSelected).
13581   
13582   \see setFont
13583 */
13584 void QCPPlotTitle::setSelectedFont(const QFont &font)
13585 {
13586   mSelectedFont = font;
13587 }
13588
13589 /*!
13590   Sets the \a color of the title text that will be used if the plot title is selected (\ref setSelected).
13591   
13592   \see setTextColor
13593 */
13594 void QCPPlotTitle::setSelectedTextColor(const QColor &color)
13595 {
13596   mSelectedTextColor = color;
13597 }
13598
13599 /*!
13600   Sets whether the user may select this plot title to \a selectable.
13601
13602   Note that even when \a selectable is set to <tt>false</tt>, the selection state may be changed
13603   programmatically via \ref setSelected.
13604 */
13605 void QCPPlotTitle::setSelectable(bool selectable)
13606 {
13607   if (mSelectable != selectable)
13608   {
13609     mSelectable = selectable;
13610     emit selectableChanged(mSelectable);
13611   }
13612 }
13613
13614 /*!
13615   Sets the selection state of this plot title to \a selected. If the selection has changed, \ref
13616   selectionChanged is emitted.
13617   
13618   Note that this function can change the selection state independently of the current \ref
13619   setSelectable state.
13620 */
13621 void QCPPlotTitle::setSelected(bool selected)
13622 {
13623   if (mSelected != selected)
13624   {
13625     mSelected = selected;
13626     emit selectionChanged(mSelected);
13627   }
13628 }
13629
13630 /* inherits documentation from base class */
13631 void QCPPlotTitle::applyDefaultAntialiasingHint(QCPPainter *painter) const
13632 {
13633   applyAntialiasingHint(painter, mAntialiased, QCP::aeNone);
13634 }
13635
13636 /* inherits documentation from base class */
13637 void QCPPlotTitle::draw(QCPPainter *painter)
13638 {
13639   painter->setFont(mainFont());
13640   painter->setPen(QPen(mainTextColor()));
13641   painter->drawText(mRect, Qt::AlignCenter, mText, &mTextBoundingRect);
13642 }
13643
13644 /* inherits documentation from base class */
13645 QSize QCPPlotTitle::minimumSizeHint() const
13646 {
13647   QFontMetrics metrics(mFont);
13648   QSize result = metrics.boundingRect(0, 0, 0, 0, Qt::AlignCenter, mText).size();
13649   result.rwidth() += mMargins.left() + mMargins.right();
13650   result.rheight() += mMargins.top() + mMargins.bottom();
13651   return result;
13652 }
13653
13654 /* inherits documentation from base class */
13655 QSize QCPPlotTitle::maximumSizeHint() const
13656 {
13657   QFontMetrics metrics(mFont);
13658   QSize result = metrics.boundingRect(0, 0, 0, 0, Qt::AlignCenter, mText).size();
13659   result.rheight() += mMargins.top() + mMargins.bottom();
13660   result.setWidth(QWIDGETSIZE_MAX);
13661   return result;
13662 }
13663
13664 /* inherits documentation from base class */
13665 void QCPPlotTitle::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged)
13666 {
13667   Q_UNUSED(event)
13668   Q_UNUSED(details)
13669   if (mSelectable)
13670   {
13671     bool selBefore = mSelected;
13672     setSelected(additive ? !mSelected : true);
13673     if (selectionStateChanged)
13674       *selectionStateChanged = mSelected != selBefore;
13675   }
13676 }
13677
13678 /* inherits documentation from base class */
13679 void QCPPlotTitle::deselectEvent(bool *selectionStateChanged)
13680 {
13681   if (mSelectable)
13682   {
13683     bool selBefore = mSelected;
13684     setSelected(false);
13685     if (selectionStateChanged)
13686       *selectionStateChanged = mSelected != selBefore;
13687   }
13688 }
13689
13690 /* inherits documentation from base class */
13691 double QCPPlotTitle::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
13692 {
13693   Q_UNUSED(details)
13694   if (onlySelectable && !mSelectable)
13695     return -1;
13696   
13697   if (mTextBoundingRect.contains(pos.toPoint()))
13698     return mParentPlot->selectionTolerance()*0.99;
13699   else
13700     return -1;
13701 }
13702
13703 /*! \internal
13704   
13705   Returns the main font to be used. This is mSelectedFont if \ref setSelected is set to
13706   <tt>true</tt>, else mFont is returned.
13707 */
13708 QFont QCPPlotTitle::mainFont() const
13709 {
13710   return mSelected ? mSelectedFont : mFont;
13711 }
13712
13713 /*! \internal
13714   
13715   Returns the main color to be used. This is mSelectedTextColor if \ref setSelected is set to
13716   <tt>true</tt>, else mTextColor is returned.
13717 */
13718 QColor QCPPlotTitle::mainTextColor() const
13719 {
13720   return mSelected ? mSelectedTextColor : mTextColor;
13721 }
13722
13723
13724 ////////////////////////////////////////////////////////////////////////////////////////////////////
13725 //////////////////// QCPColorScale
13726 ////////////////////////////////////////////////////////////////////////////////////////////////////
13727
13728 /*! \class QCPColorScale
13729   \brief A color scale for use with color coding data such as QCPColorMap
13730   
13731   This layout element can be placed on the plot to correlate a color gradient with data values. It
13732   is usually used in combination with one or multiple \ref QCPColorMap "QCPColorMaps".
13733
13734   \image html QCPColorScale.png
13735   
13736   The color scale can be either horizontal or vertical, as shown in the image above. The
13737   orientation and the side where the numbers appear is controlled with \ref setType.
13738   
13739   Use \ref QCPColorMap::setColorScale to connect a color map with a color scale. Once they are
13740   connected, they share their gradient, data range and data scale type (\ref setGradient, \ref
13741   setDataRange, \ref setDataScaleType). Multiple color maps may be associated with a single color
13742   scale, to make them all synchronize these properties.
13743   
13744   To have finer control over the number display and axis behaviour, you can directly access the
13745   \ref axis. See the documentation of QCPAxis for details about configuring axes. For example, if
13746   you want to change the number of automatically generated ticks, call
13747   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpcolorscale-autotickcount
13748   
13749   Placing a color scale next to the main axis rect works like with any other layout element:
13750   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpcolorscale-creation
13751   In this case we have placed it to the right of the default axis rect, so it wasn't necessary to
13752   call \ref setType, since \ref QCPAxis::atRight is already the default. The text next to the color
13753   scale can be set with \ref setLabel.
13754   
13755   For optimum appearance (like in the image above), it may be desirable to line up the axis rect and
13756   the borders of the color scale. Use a \ref QCPMarginGroup to achieve this:
13757   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpcolorscale-margingroup
13758   
13759   Color scales are initialized with a non-zero minimum top and bottom margin (\ref
13760   setMinimumMargins), because vertical color scales are most common and the minimum top/bottom
13761   margin makes sure it keeps some distance to the top/bottom widget border. So if you change to a
13762   horizontal color scale by setting \ref setType to \ref QCPAxis::atBottom or \ref QCPAxis::atTop, you
13763   might want to also change the minimum margins accordingly, e.g. <tt>setMinimumMargins(QMargins(6, 0, 6, 0))</tt>.
13764 */
13765
13766 /* start documentation of inline functions */
13767
13768 /*! \fn QCPAxis *QCPColorScale::axis() const
13769   
13770   Returns the internal \ref QCPAxis instance of this color scale. You can access it to alter the
13771   appearance and behaviour of the axis. \ref QCPColorScale duplicates some properties in its
13772   interface for convenience. Those are \ref setDataRange (\ref QCPAxis::setRange), \ref
13773   setDataScaleType (\ref QCPAxis::setScaleType), and the method \ref setLabel (\ref
13774   QCPAxis::setLabel). As they each are connected, it does not matter whether you use the method on
13775   the QCPColorScale or on its QCPAxis.
13776   
13777   If the type of the color scale is changed with \ref setType, the axis returned by this method
13778   will change, too, to either the left, right, bottom or top axis, depending on which type was set.
13779 */
13780
13781 /* end documentation of signals */
13782 /* start documentation of signals */
13783
13784 /*! \fn void QCPColorScale::dataRangeChanged(QCPRange newRange);
13785   
13786   This signal is emitted when the data range changes.
13787   
13788   \see setDataRange
13789 */
13790
13791 /*! \fn void QCPColorScale::dataScaleTypeChanged(QCPAxis::ScaleType scaleType);
13792   
13793   This signal is emitted when the data scale type changes.
13794   
13795   \see setDataScaleType
13796 */
13797
13798 /*! \fn void QCPColorScale::gradientChanged(QCPColorGradient newGradient);
13799   
13800   This signal is emitted when the gradient changes.
13801   
13802   \see setGradient
13803 */
13804
13805 /* end documentation of signals */
13806
13807 /*!
13808   Constructs a new QCPColorScale.
13809 */
13810 QCPColorScale::QCPColorScale(QCustomPlot *parentPlot) :
13811   QCPLayoutElement(parentPlot),
13812   mType(QCPAxis::atTop), // set to atTop such that setType(QCPAxis::atRight) below doesn't skip work because it thinks it's already atRight
13813   mDataScaleType(QCPAxis::stLinear),
13814   mBarWidth(20),
13815   mAxisRect(new QCPColorScaleAxisRectPrivate(this))
13816 {
13817   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)
13818   setType(QCPAxis::atRight);
13819   setDataRange(QCPRange(0, 6));
13820 }
13821
13822 QCPColorScale::~QCPColorScale()
13823 {
13824   delete mAxisRect;
13825 }
13826
13827 /* undocumented getter */
13828 QString QCPColorScale::label() const
13829 {
13830   if (!mColorAxis)
13831   {
13832     qDebug() << Q_FUNC_INFO << "internal color axis undefined";
13833     return QString();
13834   }
13835   
13836   return mColorAxis.data()->label();
13837 }
13838
13839 /* undocumented getter */
13840 bool QCPColorScale::rangeDrag() const
13841 {
13842   if (!mAxisRect)
13843   {
13844     qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
13845     return false;
13846   }
13847   
13848   return mAxisRect.data()->rangeDrag().testFlag(QCPAxis::orientation(mType)) &&
13849       mAxisRect.data()->rangeDragAxis(QCPAxis::orientation(mType)) &&
13850       mAxisRect.data()->rangeDragAxis(QCPAxis::orientation(mType))->orientation() == QCPAxis::orientation(mType);
13851 }
13852
13853 /* undocumented getter */
13854 bool QCPColorScale::rangeZoom() const
13855 {
13856   if (!mAxisRect)
13857   {
13858     qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
13859     return false;
13860   }
13861   
13862   return mAxisRect.data()->rangeZoom().testFlag(QCPAxis::orientation(mType)) &&
13863       mAxisRect.data()->rangeZoomAxis(QCPAxis::orientation(mType)) &&
13864       mAxisRect.data()->rangeZoomAxis(QCPAxis::orientation(mType))->orientation() == QCPAxis::orientation(mType);
13865 }
13866
13867 /*!
13868   Sets at which side of the color scale the axis is placed, and thus also its orientation.
13869   
13870   Note that after setting \a type to a different value, the axis returned by \ref axis() will
13871   be a different one. The new axis will adopt the following properties from the previous axis: The
13872   range, scale type, log base and label.
13873 */
13874 void QCPColorScale::setType(QCPAxis::AxisType type)
13875 {
13876   if (!mAxisRect)
13877   {
13878     qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
13879     return;
13880   }
13881   if (mType != type)
13882   {
13883     mType = type;
13884     QCPRange rangeTransfer(0, 6);
13885     double logBaseTransfer = 10;
13886     QString labelTransfer;
13887     // revert some settings on old axis:
13888     if (mColorAxis)
13889     {
13890       rangeTransfer = mColorAxis.data()->range();
13891       labelTransfer = mColorAxis.data()->label();
13892       logBaseTransfer = mColorAxis.data()->scaleLogBase();
13893       mColorAxis.data()->setLabel(QString());
13894       disconnect(mColorAxis.data(), SIGNAL(rangeChanged(QCPRange)), this, SLOT(setDataRange(QCPRange)));
13895       disconnect(mColorAxis.data(), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), this, SLOT(setDataScaleType(QCPAxis::ScaleType)));
13896     }
13897     QList<QCPAxis::AxisType> allAxisTypes = QList<QCPAxis::AxisType>() << QCPAxis::atLeft << QCPAxis::atRight << QCPAxis::atBottom << QCPAxis::atTop;
13898     foreach (QCPAxis::AxisType atype, allAxisTypes)
13899     {
13900       mAxisRect.data()->axis(atype)->setTicks(atype == mType);
13901       mAxisRect.data()->axis(atype)->setTickLabels(atype== mType);
13902     }
13903     // set new mColorAxis pointer:
13904     mColorAxis = mAxisRect.data()->axis(mType);
13905     // transfer settings to new axis:
13906     mColorAxis.data()->setRange(rangeTransfer); // transfer range of old axis to new one (necessary if axis changes from vertical to horizontal or vice versa)
13907     mColorAxis.data()->setLabel(labelTransfer);
13908     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
13909     connect(mColorAxis.data(), SIGNAL(rangeChanged(QCPRange)), this, SLOT(setDataRange(QCPRange)));
13910     connect(mColorAxis.data(), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), this, SLOT(setDataScaleType(QCPAxis::ScaleType)));
13911     mAxisRect.data()->setRangeDragAxes(QCPAxis::orientation(mType) == Qt::Horizontal ? mColorAxis.data() : 0,
13912                                        QCPAxis::orientation(mType) == Qt::Vertical ? mColorAxis.data() : 0);
13913   }
13914 }
13915
13916 /*!
13917   Sets the range spanned by the color gradient and that is shown by the axis in the color scale.
13918   
13919   It is equivalent to calling QCPColorMap::setDataRange on any of the connected color maps. It is
13920   also equivalent to directly accessing the \ref axis and setting its range with \ref
13921   QCPAxis::setRange.
13922   
13923   \see setDataScaleType, setGradient, rescaleDataRange
13924 */
13925 void QCPColorScale::setDataRange(const QCPRange &dataRange)
13926 {
13927   if (mDataRange.lower != dataRange.lower || mDataRange.upper != dataRange.upper)
13928   {
13929     mDataRange = dataRange;
13930     if (mColorAxis)
13931       mColorAxis.data()->setRange(mDataRange);
13932     emit dataRangeChanged(mDataRange);
13933   }
13934 }
13935
13936 /*!
13937   Sets the scale type of the color scale, i.e. whether values are linearly associated with colors
13938   or logarithmically.
13939   
13940   It is equivalent to calling QCPColorMap::setDataScaleType on any of the connected color maps. It is
13941   also equivalent to directly accessing the \ref axis and setting its scale type with \ref
13942   QCPAxis::setScaleType.
13943   
13944   \see setDataRange, setGradient
13945 */
13946 void QCPColorScale::setDataScaleType(QCPAxis::ScaleType scaleType)
13947 {
13948   if (mDataScaleType != scaleType)
13949   {
13950     mDataScaleType = scaleType;
13951     if (mColorAxis)
13952       mColorAxis.data()->setScaleType(mDataScaleType);
13953     if (mDataScaleType == QCPAxis::stLogarithmic)
13954       setDataRange(mDataRange.sanitizedForLogScale());
13955     emit dataScaleTypeChanged(mDataScaleType);
13956   }
13957 }
13958
13959 /*!
13960   Sets the color gradient that will be used to represent data values.
13961   
13962   It is equivalent to calling QCPColorMap::setGradient on any of the connected color maps.
13963   
13964   \see setDataRange, setDataScaleType
13965 */
13966 void QCPColorScale::setGradient(const QCPColorGradient &gradient)
13967 {
13968   if (mGradient != gradient)
13969   {
13970     mGradient = gradient;
13971     if (mAxisRect)
13972       mAxisRect.data()->mGradientImageInvalidated = true;
13973     emit gradientChanged(mGradient);
13974   }
13975 }
13976
13977 /*!
13978   Sets the axis label of the color scale. This is equivalent to calling \ref QCPAxis::setLabel on
13979   the internal \ref axis.
13980 */
13981 void QCPColorScale::setLabel(const QString &str)
13982 {
13983   if (!mColorAxis)
13984   {
13985     qDebug() << Q_FUNC_INFO << "internal color axis undefined";
13986     return;
13987   }
13988   
13989   mColorAxis.data()->setLabel(str);
13990 }
13991
13992 /*!
13993   Sets the width (or height, for horizontal color scales) the bar where the gradient is displayed
13994   will have.
13995 */
13996 void QCPColorScale::setBarWidth(int width)
13997 {
13998   mBarWidth = width;
13999 }
14000
14001 /*!
14002   Sets whether the user can drag the data range (\ref setDataRange).
14003   
14004   Note that \ref QCP::iRangeDrag must be in the QCustomPlot's interactions (\ref
14005   QCustomPlot::setInteractions) to allow range dragging.
14006 */
14007 void QCPColorScale::setRangeDrag(bool enabled)
14008 {
14009   if (!mAxisRect)
14010   {
14011     qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14012     return;
14013   }
14014   
14015   if (enabled)
14016     mAxisRect.data()->setRangeDrag(QCPAxis::orientation(mType));
14017   else
14018     mAxisRect.data()->setRangeDrag(0);
14019 }
14020
14021 /*!
14022   Sets whether the user can zoom the data range (\ref setDataRange) by scrolling the mouse wheel.
14023   
14024   Note that \ref QCP::iRangeZoom must be in the QCustomPlot's interactions (\ref
14025   QCustomPlot::setInteractions) to allow range dragging.
14026 */
14027 void QCPColorScale::setRangeZoom(bool enabled)
14028 {
14029   if (!mAxisRect)
14030   {
14031     qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14032     return;
14033   }
14034   
14035   if (enabled)
14036     mAxisRect.data()->setRangeZoom(QCPAxis::orientation(mType));
14037   else
14038     mAxisRect.data()->setRangeZoom(0);
14039 }
14040
14041 /*!
14042   Returns a list of all the color maps associated with this color scale.
14043 */
14044 QList<QCPColorMap*> QCPColorScale::colorMaps() const
14045 {
14046   QList<QCPColorMap*> result;
14047   for (int i=0; i<mParentPlot->plottableCount(); ++i)
14048   {
14049     if (QCPColorMap *cm = qobject_cast<QCPColorMap*>(mParentPlot->plottable(i)))
14050       if (cm->colorScale() == this)
14051         result.append(cm);
14052   }
14053   return result;
14054 }
14055
14056 /*!
14057   Changes the data range such that all color maps associated with this color scale are fully mapped
14058   to the gradient in the data dimension.
14059   
14060   \see setDataRange
14061 */
14062 void QCPColorScale::rescaleDataRange(bool onlyVisibleMaps)
14063 {
14064   QList<QCPColorMap*> maps = colorMaps();
14065   QCPRange newRange;
14066   bool haveRange = false;
14067   int sign = 0; // TODO: should change this to QCPAbstractPlottable::SignDomain later (currently is protected, maybe move to QCP namespace)
14068   if (mDataScaleType == QCPAxis::stLogarithmic)
14069     sign = (mDataRange.upper < 0 ? -1 : 1);
14070   for (int i=0; i<maps.size(); ++i)
14071   {
14072     if (!maps.at(i)->realVisibility() && onlyVisibleMaps)
14073       continue;
14074     QCPRange mapRange;
14075     if (maps.at(i)->colorScale() == this)
14076     {
14077       bool currentFoundRange = true;
14078       mapRange = maps.at(i)->data()->dataBounds();
14079       if (sign == 1)
14080       {
14081         if (mapRange.lower <= 0 && mapRange.upper > 0)
14082           mapRange.lower = mapRange.upper*1e-3;
14083         else if (mapRange.lower <= 0 && mapRange.upper <= 0)
14084           currentFoundRange = false;
14085       } else if (sign == -1)
14086       {
14087         if (mapRange.upper >= 0 && mapRange.lower < 0)
14088           mapRange.upper = mapRange.lower*1e-3;
14089         else if (mapRange.upper >= 0 && mapRange.lower >= 0)
14090           currentFoundRange = false;
14091       }
14092       if (currentFoundRange)
14093       {
14094         if (!haveRange)
14095           newRange = mapRange;
14096         else
14097           newRange.expand(mapRange);
14098         haveRange = true;
14099       }
14100     }
14101   }
14102   if (haveRange)
14103   {
14104     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
14105     {
14106       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
14107       if (mDataScaleType == QCPAxis::stLinear)
14108       {
14109         newRange.lower = center-mDataRange.size()/2.0;
14110         newRange.upper = center+mDataRange.size()/2.0;
14111       } else // mScaleType == stLogarithmic
14112       {
14113         newRange.lower = center/qSqrt(mDataRange.upper/mDataRange.lower);
14114         newRange.upper = center*qSqrt(mDataRange.upper/mDataRange.lower);
14115       }
14116     }
14117     setDataRange(newRange);
14118   }
14119 }
14120
14121 /* inherits documentation from base class */
14122 void QCPColorScale::update(UpdatePhase phase)
14123 {
14124   QCPLayoutElement::update(phase);
14125   if (!mAxisRect)
14126   {
14127     qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14128     return;
14129   }
14130   
14131   mAxisRect.data()->update(phase);
14132   
14133   switch (phase)
14134   {
14135     case upMargins:
14136     {
14137       if (mType == QCPAxis::atBottom || mType == QCPAxis::atTop)
14138       {
14139         setMaximumSize(QWIDGETSIZE_MAX, mBarWidth+mAxisRect.data()->margins().top()+mAxisRect.data()->margins().bottom()+margins().top()+margins().bottom());
14140         setMinimumSize(0,               mBarWidth+mAxisRect.data()->margins().top()+mAxisRect.data()->margins().bottom()+margins().top()+margins().bottom());
14141       } else
14142       {
14143         setMaximumSize(mBarWidth+mAxisRect.data()->margins().left()+mAxisRect.data()->margins().right()+margins().left()+margins().right(), QWIDGETSIZE_MAX);
14144         setMinimumSize(mBarWidth+mAxisRect.data()->margins().left()+mAxisRect.data()->margins().right()+margins().left()+margins().right(), 0);
14145       }
14146       break;
14147     }
14148     case upLayout:
14149     {
14150       mAxisRect.data()->setOuterRect(rect());
14151       break;
14152     }
14153     default: break;
14154   }
14155 }
14156
14157 /* inherits documentation from base class */
14158 void QCPColorScale::applyDefaultAntialiasingHint(QCPPainter *painter) const
14159 {
14160   painter->setAntialiasing(false);
14161 }
14162
14163 /* inherits documentation from base class */
14164 void QCPColorScale::mousePressEvent(QMouseEvent *event)
14165 {
14166   if (!mAxisRect)
14167   {
14168     qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14169     return;
14170   }
14171   mAxisRect.data()->mousePressEvent(event);
14172 }
14173
14174 /* inherits documentation from base class */
14175 void QCPColorScale::mouseMoveEvent(QMouseEvent *event)
14176 {
14177   if (!mAxisRect)
14178   {
14179     qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14180     return;
14181   }
14182   mAxisRect.data()->mouseMoveEvent(event);
14183 }
14184
14185 /* inherits documentation from base class */
14186 void QCPColorScale::mouseReleaseEvent(QMouseEvent *event)
14187 {
14188   if (!mAxisRect)
14189   {
14190     qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14191     return;
14192   }
14193   mAxisRect.data()->mouseReleaseEvent(event);
14194 }
14195
14196 /* inherits documentation from base class */
14197 void QCPColorScale::wheelEvent(QWheelEvent *event)
14198 {
14199   if (!mAxisRect)
14200   {
14201     qDebug() << Q_FUNC_INFO << "internal axis rect was deleted";
14202     return;
14203   }
14204   mAxisRect.data()->wheelEvent(event);
14205 }
14206
14207 ////////////////////////////////////////////////////////////////////////////////////////////////////
14208 //////////////////// QCPColorScaleAxisRectPrivate
14209 ////////////////////////////////////////////////////////////////////////////////////////////////////
14210
14211 /*! \class QCPColorScaleAxisRectPrivate
14212
14213   \internal
14214   \brief An axis rect subclass for use in a QCPColorScale
14215   
14216   This is a private class and not part of the public QCustomPlot interface.
14217   
14218   It provides the axis rect functionality for the QCPColorScale class.
14219 */
14220
14221
14222 /*!
14223   Creates a new instance, as a child of \a parentColorScale.
14224 */
14225 QCPColorScaleAxisRectPrivate::QCPColorScaleAxisRectPrivate(QCPColorScale *parentColorScale) :
14226   QCPAxisRect(parentColorScale->parentPlot(), true),
14227   mParentColorScale(parentColorScale),
14228   mGradientImageInvalidated(true)
14229 {
14230   setParentLayerable(parentColorScale);
14231   setMinimumMargins(QMargins(0, 0, 0, 0));
14232   QList<QCPAxis::AxisType> allAxisTypes = QList<QCPAxis::AxisType>() << QCPAxis::atBottom << QCPAxis::atTop << QCPAxis::atLeft << QCPAxis::atRight;
14233   foreach (QCPAxis::AxisType type, allAxisTypes)
14234   {
14235     axis(type)->setVisible(true);
14236     axis(type)->grid()->setVisible(false);
14237     axis(type)->setPadding(0);
14238     connect(axis(type), SIGNAL(selectionChanged(QCPAxis::SelectableParts)), this, SLOT(axisSelectionChanged(QCPAxis::SelectableParts)));
14239     connect(axis(type), SIGNAL(selectableChanged(QCPAxis::SelectableParts)), this, SLOT(axisSelectableChanged(QCPAxis::SelectableParts)));
14240   }
14241
14242   connect(axis(QCPAxis::atLeft), SIGNAL(rangeChanged(QCPRange)), axis(QCPAxis::atRight), SLOT(setRange(QCPRange)));
14243   connect(axis(QCPAxis::atRight), SIGNAL(rangeChanged(QCPRange)), axis(QCPAxis::atLeft), SLOT(setRange(QCPRange)));
14244   connect(axis(QCPAxis::atBottom), SIGNAL(rangeChanged(QCPRange)), axis(QCPAxis::atTop), SLOT(setRange(QCPRange)));
14245   connect(axis(QCPAxis::atTop), SIGNAL(rangeChanged(QCPRange)), axis(QCPAxis::atBottom), SLOT(setRange(QCPRange)));
14246   connect(axis(QCPAxis::atLeft), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), axis(QCPAxis::atRight), SLOT(setScaleType(QCPAxis::ScaleType)));
14247   connect(axis(QCPAxis::atRight), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), axis(QCPAxis::atLeft), SLOT(setScaleType(QCPAxis::ScaleType)));
14248   connect(axis(QCPAxis::atBottom), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), axis(QCPAxis::atTop), SLOT(setScaleType(QCPAxis::ScaleType)));
14249   connect(axis(QCPAxis::atTop), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), axis(QCPAxis::atBottom), SLOT(setScaleType(QCPAxis::ScaleType)));
14250   
14251   // make layer transfers of color scale transfer to axis rect and axes
14252   // the axes must be set after axis rect, such that they appear above color gradient drawn by axis rect:
14253   connect(parentColorScale, SIGNAL(layerChanged(QCPLayer*)), this, SLOT(setLayer(QCPLayer*)));
14254   foreach (QCPAxis::AxisType type, allAxisTypes)
14255     connect(parentColorScale, SIGNAL(layerChanged(QCPLayer*)), axis(type), SLOT(setLayer(QCPLayer*)));
14256 }
14257
14258 /*! \internal
14259   Updates the color gradient image if necessary, by calling \ref updateGradientImage, then draws
14260   it. Then the axes are drawn by calling the \ref QCPAxisRect::draw base class implementation.
14261 */
14262 void QCPColorScaleAxisRectPrivate::draw(QCPPainter *painter)
14263 {
14264   if (mGradientImageInvalidated)
14265     updateGradientImage();
14266   
14267   bool mirrorHorz = false;
14268   bool mirrorVert = false;
14269   if (mParentColorScale->mColorAxis)
14270   {
14271     mirrorHorz = mParentColorScale->mColorAxis.data()->rangeReversed() && (mParentColorScale->type() == QCPAxis::atBottom || mParentColorScale->type() == QCPAxis::atTop);
14272     mirrorVert = mParentColorScale->mColorAxis.data()->rangeReversed() && (mParentColorScale->type() == QCPAxis::atLeft || mParentColorScale->type() == QCPAxis::atRight);
14273   }
14274   
14275   painter->drawImage(rect().adjusted(0, -1, 0, -1), mGradientImage.mirrored(mirrorHorz, mirrorVert));
14276   QCPAxisRect::draw(painter);
14277 }
14278
14279 /*! \internal
14280
14281   Uses the current gradient of the parent \ref QCPColorScale (specified in the constructor) to
14282   generate a gradient image. This gradient image will be used in the \ref draw method.
14283 */
14284 void QCPColorScaleAxisRectPrivate::updateGradientImage()
14285 {
14286   if (rect().isEmpty())
14287     return;
14288   
14289   int n = mParentColorScale->mGradient.levelCount();
14290   int w, h;
14291   QVector<double> data(n);
14292   for (int i=0; i<n; ++i)
14293     data[i] = i;
14294   if (mParentColorScale->mType == QCPAxis::atBottom || mParentColorScale->mType == QCPAxis::atTop)
14295   {
14296     w = n;
14297     h = rect().height();
14298     mGradientImage = QImage(w, h, QImage::Format_RGB32);
14299     QVector<QRgb*> pixels;
14300     for (int y=0; y<h; ++y)
14301       pixels.append(reinterpret_cast<QRgb*>(mGradientImage.scanLine(y)));
14302     mParentColorScale->mGradient.colorize(data.constData(), QCPRange(0, n-1), pixels.first(), n);
14303     for (int y=1; y<h; ++y)
14304       memcpy(pixels.at(y), pixels.first(), n*sizeof(QRgb));
14305   } else
14306   {
14307     w = rect().width();
14308     h = n;
14309     mGradientImage = QImage(w, h, QImage::Format_RGB32);
14310     for (int y=0; y<h; ++y)
14311     {
14312       QRgb *pixels = reinterpret_cast<QRgb*>(mGradientImage.scanLine(y));
14313       const QRgb lineColor = mParentColorScale->mGradient.color(data[h-1-y], QCPRange(0, n-1));
14314       for (int x=0; x<w; ++x)
14315         pixels[x] = lineColor;
14316     }
14317   }
14318   mGradientImageInvalidated = false;
14319 }
14320
14321 /*! \internal
14322
14323   This slot is connected to the selectionChanged signals of the four axes in the constructor. It
14324   synchronizes the selection state of the axes.
14325 */
14326 void QCPColorScaleAxisRectPrivate::axisSelectionChanged(QCPAxis::SelectableParts selectedParts)
14327 {
14328   // axis bases of four axes shall always (de-)selected synchronously:
14329   QList<QCPAxis::AxisType> allAxisTypes = QList<QCPAxis::AxisType>() << QCPAxis::atBottom << QCPAxis::atTop << QCPAxis::atLeft << QCPAxis::atRight;
14330   foreach (QCPAxis::AxisType type, allAxisTypes)
14331   {
14332     if (QCPAxis *senderAxis = qobject_cast<QCPAxis*>(sender()))
14333       if (senderAxis->axisType() == type)
14334         continue;
14335     
14336     if (axis(type)->selectableParts().testFlag(QCPAxis::spAxis))
14337     {
14338       if (selectedParts.testFlag(QCPAxis::spAxis))
14339         axis(type)->setSelectedParts(axis(type)->selectedParts() | QCPAxis::spAxis);
14340       else
14341         axis(type)->setSelectedParts(axis(type)->selectedParts() & ~QCPAxis::spAxis);
14342     }
14343   }
14344 }
14345
14346 /*! \internal
14347
14348   This slot is connected to the selectableChanged signals of the four axes in the constructor. It
14349   synchronizes the selectability of the axes.
14350 */
14351 void QCPColorScaleAxisRectPrivate::axisSelectableChanged(QCPAxis::SelectableParts selectableParts)
14352 {
14353   // synchronize axis base selectability:
14354   QList<QCPAxis::AxisType> allAxisTypes = QList<QCPAxis::AxisType>() << QCPAxis::atBottom << QCPAxis::atTop << QCPAxis::atLeft << QCPAxis::atRight;
14355   foreach (QCPAxis::AxisType type, allAxisTypes)
14356   {
14357     if (QCPAxis *senderAxis = qobject_cast<QCPAxis*>(sender()))
14358       if (senderAxis->axisType() == type)
14359         continue;
14360     
14361     if (axis(type)->selectableParts().testFlag(QCPAxis::spAxis))
14362     {
14363       if (selectableParts.testFlag(QCPAxis::spAxis))
14364         axis(type)->setSelectableParts(axis(type)->selectableParts() | QCPAxis::spAxis);
14365       else
14366         axis(type)->setSelectableParts(axis(type)->selectableParts() & ~QCPAxis::spAxis);
14367     }
14368   }
14369 }
14370
14371
14372 ////////////////////////////////////////////////////////////////////////////////////////////////////
14373 //////////////////// QCPData
14374 ////////////////////////////////////////////////////////////////////////////////////////////////////
14375
14376 /*! \class QCPData
14377   \brief Holds the data of one single data point for QCPGraph.
14378   
14379   The container for storing multiple data points is \ref QCPDataMap.
14380   
14381   The stored data is:
14382   \li \a key: coordinate on the key axis of this data point
14383   \li \a value: coordinate on the value axis of this data point
14384   \li \a keyErrorMinus: negative error in the key dimension (for error bars)
14385   \li \a keyErrorPlus: positive error in the key dimension (for error bars)
14386   \li \a valueErrorMinus: negative error in the value dimension (for error bars)
14387   \li \a valueErrorPlus: positive error in the value dimension (for error bars)
14388   
14389   \see QCPDataMap
14390 */
14391
14392 /*!
14393   Constructs a data point with key, value and all errors set to zero.
14394 */
14395 QCPData::QCPData() :
14396   key(0),
14397   value(0),
14398   keyErrorPlus(0),
14399   keyErrorMinus(0),
14400   valueErrorPlus(0),
14401   valueErrorMinus(0)
14402 {
14403 }
14404
14405 /*!
14406   Constructs a data point with the specified \a key and \a value. All errors are set to zero.
14407 */
14408 QCPData::QCPData(double key, double value) :
14409   key(key),
14410   value(value),
14411   keyErrorPlus(0),
14412   keyErrorMinus(0),
14413   valueErrorPlus(0),
14414   valueErrorMinus(0)
14415 {
14416 }
14417
14418
14419 ////////////////////////////////////////////////////////////////////////////////////////////////////
14420 //////////////////// QCPGraph
14421 ////////////////////////////////////////////////////////////////////////////////////////////////////
14422
14423 /*! \class QCPGraph
14424   \brief A plottable representing a graph in a plot.
14425
14426   \image html QCPGraph.png
14427   
14428   Usually you create new graphs by calling QCustomPlot::addGraph. The resulting instance can be
14429   accessed via QCustomPlot::graph.
14430
14431   To plot data, assign it with the \ref setData or \ref addData functions. Alternatively, you can
14432   also access and modify the graph's data via the \ref data method, which returns a pointer to the
14433   internal \ref QCPDataMap.
14434   
14435   Graphs are used to display single-valued data. Single-valued means that there should only be one
14436   data point per unique key coordinate. In other words, the graph can't have \a loops. If you do
14437   want to plot non-single-valued curves, rather use the QCPCurve plottable.
14438   
14439   Gaps in the graph line can be created by adding data points with NaN as value
14440   (<tt>qQNaN()</tt> or <tt>std::numeric_limits<double>::quiet_NaN()</tt>) in between the two data points that shall be
14441   separated.
14442   
14443   \section appearance Changing the appearance
14444   
14445   The appearance of the graph is mainly determined by the line style, scatter style, brush and pen
14446   of the graph (\ref setLineStyle, \ref setScatterStyle, \ref setBrush, \ref setPen).
14447   
14448   \subsection filling Filling under or between graphs
14449   
14450   QCPGraph knows two types of fills: Normal graph fills towards the zero-value-line parallel to
14451   the key axis of the graph, and fills between two graphs, called channel fills. To enable a fill,
14452   just set a brush with \ref setBrush which is neither Qt::NoBrush nor fully transparent.
14453   
14454   By default, a normal fill towards the zero-value-line will be drawn. To set up a channel fill
14455   between this graph and another one, call \ref setChannelFillGraph with the other graph as
14456   parameter.
14457
14458   \see QCustomPlot::addGraph, QCustomPlot::graph
14459 */
14460
14461 /* start of documentation of inline functions */
14462
14463 /*! \fn QCPDataMap *QCPGraph::data() const
14464   
14465   Returns a pointer to the internal data storage of type \ref QCPDataMap. You may use it to
14466   directly manipulate the data, which may be more convenient and faster than using the regular \ref
14467   setData or \ref addData methods, in certain situations.
14468 */
14469
14470 /* end of documentation of inline functions */
14471
14472 /*!
14473   Constructs a graph which uses \a keyAxis as its key axis ("x") and \a valueAxis as its value
14474   axis ("y"). \a keyAxis and \a valueAxis must reside in the same QCustomPlot instance and not have
14475   the same orientation. If either of these restrictions is violated, a corresponding message is
14476   printed to the debug output (qDebug), the construction is not aborted, though.
14477   
14478   The constructed QCPGraph can be added to the plot with QCustomPlot::addPlottable, QCustomPlot
14479   then takes ownership of the graph.
14480   
14481   To directly create a graph inside a plot, you can also use the simpler QCustomPlot::addGraph function.
14482 */
14483 QCPGraph::QCPGraph(QCPAxis *keyAxis, QCPAxis *valueAxis) :
14484   QCPAbstractPlottable(keyAxis, valueAxis)
14485 {
14486   mData = new QCPDataMap;
14487   
14488   setPen(QPen(Qt::blue, 0));
14489   setErrorPen(QPen(Qt::black));
14490   setBrush(Qt::NoBrush);
14491   setSelectedPen(QPen(QColor(80, 80, 255), 2.5));
14492   setSelectedBrush(Qt::NoBrush);
14493   
14494   setLineStyle(lsLine);
14495   setErrorType(etNone);
14496   setErrorBarSize(6);
14497   setErrorBarSkipSymbol(true);
14498   setChannelFillGraph(0);
14499   setAdaptiveSampling(true);
14500 }
14501
14502 QCPGraph::~QCPGraph()
14503 {
14504   delete mData;
14505 }
14506
14507 /*!
14508   Replaces the current data with the provided \a data.
14509   
14510   If \a copy is set to true, data points in \a data will only be copied. if false, the graph
14511   takes ownership of the passed data and replaces the internal data pointer with it. This is
14512   significantly faster than copying for large datasets.
14513   
14514   Alternatively, you can also access and modify the graph's data via the \ref data method, which
14515   returns a pointer to the internal \ref QCPDataMap.
14516 */
14517 void QCPGraph::setData(QCPDataMap *data, bool copy)
14518 {
14519   if (mData == data)
14520   {
14521     qDebug() << Q_FUNC_INFO << "The data pointer is already in (and owned by) this plottable" << reinterpret_cast<quintptr>(data);
14522     return;
14523   }
14524   if (copy)
14525   {
14526     *mData = *data;
14527   } else
14528   {
14529     delete mData;
14530     mData = data;
14531   }
14532 }
14533
14534 /*! \overload
14535   
14536   Replaces the current data with the provided points in \a key and \a value pairs. The provided
14537   vectors should have equal length. Else, the number of added points will be the size of the
14538   smallest vector.
14539 */
14540 void QCPGraph::setData(const QVector<double> &key, const QVector<double> &value)
14541 {
14542   mData->clear();
14543   int n = key.size();
14544   n = qMin(n, value.size());
14545   QCPData newData;
14546   for (int i=0; i<n; ++i)
14547   {
14548     newData.key = key[i];
14549     newData.value = value[i];
14550     mData->insertMulti(newData.key, newData);
14551   }
14552 }
14553
14554 /*!
14555   Replaces the current data with the provided points in \a key and \a value pairs. Additionally the
14556   symmetrical value error of the data points are set to the values in \a valueError.
14557   For error bars to show appropriately, see \ref setErrorType.
14558   The provided vectors should have equal length. Else, the number of added points will be the size of the
14559   smallest vector.
14560   
14561   For asymmetrical errors (plus different from minus), see the overloaded version of this function.
14562 */
14563 void QCPGraph::setDataValueError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &valueError)
14564 {
14565   mData->clear();
14566   int n = key.size();
14567   n = qMin(n, value.size());
14568   n = qMin(n, valueError.size());
14569   QCPData newData;
14570   for (int i=0; i<n; ++i)
14571   {
14572     newData.key = key[i];
14573     newData.value = value[i];
14574     newData.valueErrorMinus = valueError[i];
14575     newData.valueErrorPlus = valueError[i];
14576     mData->insertMulti(key[i], newData);
14577   }
14578 }
14579
14580 /*!
14581   \overload
14582   Replaces the current data with the provided points in \a key and \a value pairs. Additionally the
14583   negative value error of the data points are set to the values in \a valueErrorMinus, the positive
14584   value error to \a valueErrorPlus.
14585   For error bars to show appropriately, see \ref setErrorType.
14586   The provided vectors should have equal length. Else, the number of added points will be the size of the
14587   smallest vector.
14588 */
14589 void QCPGraph::setDataValueError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &valueErrorMinus, const QVector<double> &valueErrorPlus)
14590 {
14591   mData->clear();
14592   int n = key.size();
14593   n = qMin(n, value.size());
14594   n = qMin(n, valueErrorMinus.size());
14595   n = qMin(n, valueErrorPlus.size());
14596   QCPData newData;
14597   for (int i=0; i<n; ++i)
14598   {
14599     newData.key = key[i];
14600     newData.value = value[i];
14601     newData.valueErrorMinus = valueErrorMinus[i];
14602     newData.valueErrorPlus = valueErrorPlus[i];
14603     mData->insertMulti(key[i], newData);
14604   }
14605 }
14606
14607 /*!
14608   Replaces the current data with the provided points in \a key and \a value pairs. Additionally the
14609   symmetrical key error of the data points are set to the values in \a keyError.
14610   For error bars to show appropriately, see \ref setErrorType.
14611   The provided vectors should have equal length. Else, the number of added points will be the size of the
14612   smallest vector.
14613   
14614   For asymmetrical errors (plus different from minus), see the overloaded version of this function.
14615 */
14616 void QCPGraph::setDataKeyError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyError)
14617 {
14618   mData->clear();
14619   int n = key.size();
14620   n = qMin(n, value.size());
14621   n = qMin(n, keyError.size());
14622   QCPData newData;
14623   for (int i=0; i<n; ++i)
14624   {
14625     newData.key = key[i];
14626     newData.value = value[i];
14627     newData.keyErrorMinus = keyError[i];
14628     newData.keyErrorPlus = keyError[i];
14629     mData->insertMulti(key[i], newData);
14630   }
14631 }
14632
14633 /*!
14634   \overload
14635   Replaces the current data with the provided points in \a key and \a value pairs. Additionally the
14636   negative key error of the data points are set to the values in \a keyErrorMinus, the positive
14637   key error to \a keyErrorPlus.
14638   For error bars to show appropriately, see \ref setErrorType.
14639   The provided vectors should have equal length. Else, the number of added points will be the size of the
14640   smallest vector.
14641 */
14642 void QCPGraph::setDataKeyError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyErrorMinus, const QVector<double> &keyErrorPlus)
14643 {
14644   mData->clear();
14645   int n = key.size();
14646   n = qMin(n, value.size());
14647   n = qMin(n, keyErrorMinus.size());
14648   n = qMin(n, keyErrorPlus.size());
14649   QCPData newData;
14650   for (int i=0; i<n; ++i)
14651   {
14652     newData.key = key[i];
14653     newData.value = value[i];
14654     newData.keyErrorMinus = keyErrorMinus[i];
14655     newData.keyErrorPlus = keyErrorPlus[i];
14656     mData->insertMulti(key[i], newData);
14657   }
14658 }
14659
14660 /*!
14661   Replaces the current data with the provided points in \a key and \a value pairs. Additionally the
14662   symmetrical key and value errors of the data points are set to the values in \a keyError and \a valueError.
14663   For error bars to show appropriately, see \ref setErrorType.
14664   The provided vectors should have equal length. Else, the number of added points will be the size of the
14665   smallest vector.
14666   
14667   For asymmetrical errors (plus different from minus), see the overloaded version of this function.
14668 */
14669 void QCPGraph::setDataBothError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyError, const QVector<double> &valueError)
14670 {
14671   mData->clear();
14672   int n = key.size();
14673   n = qMin(n, value.size());
14674   n = qMin(n, valueError.size());
14675   n = qMin(n, keyError.size());
14676   QCPData newData;
14677   for (int i=0; i<n; ++i)
14678   {
14679     newData.key = key[i];
14680     newData.value = value[i];
14681     newData.keyErrorMinus = keyError[i];
14682     newData.keyErrorPlus = keyError[i];
14683     newData.valueErrorMinus = valueError[i];
14684     newData.valueErrorPlus = valueError[i];
14685     mData->insertMulti(key[i], newData);
14686   }
14687 }
14688
14689 /*!
14690   \overload
14691   Replaces the current data with the provided points in \a key and \a value pairs. Additionally the
14692   negative key and value errors of the data points are set to the values in \a keyErrorMinus and \a valueErrorMinus. The positive
14693   key and value errors are set to the values in \a keyErrorPlus \a valueErrorPlus.
14694   For error bars to show appropriately, see \ref setErrorType.
14695   The provided vectors should have equal length. Else, the number of added points will be the size of the
14696   smallest vector.
14697 */
14698 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)
14699 {
14700   mData->clear();
14701   int n = key.size();
14702   n = qMin(n, value.size());
14703   n = qMin(n, valueErrorMinus.size());
14704   n = qMin(n, valueErrorPlus.size());
14705   n = qMin(n, keyErrorMinus.size());
14706   n = qMin(n, keyErrorPlus.size());
14707   QCPData newData;
14708   for (int i=0; i<n; ++i)
14709   {
14710     newData.key = key[i];
14711     newData.value = value[i];
14712     newData.keyErrorMinus = keyErrorMinus[i];
14713     newData.keyErrorPlus = keyErrorPlus[i];
14714     newData.valueErrorMinus = valueErrorMinus[i];
14715     newData.valueErrorPlus = valueErrorPlus[i];
14716     mData->insertMulti(key[i], newData);
14717   }
14718 }
14719
14720
14721 /*!
14722   Sets how the single data points are connected in the plot. For scatter-only plots, set \a ls to
14723   \ref lsNone and \ref setScatterStyle to the desired scatter style.
14724   
14725   \see setScatterStyle
14726 */
14727 void QCPGraph::setLineStyle(LineStyle ls)
14728 {
14729   mLineStyle = ls;
14730 }
14731
14732 /*!
14733   Sets the visual appearance of single data points in the plot. If set to \ref QCPScatterStyle::ssNone, no scatter points
14734   are drawn (e.g. for line-only-plots with appropriate line style).
14735   
14736   \see QCPScatterStyle, setLineStyle
14737 */
14738 void QCPGraph::setScatterStyle(const QCPScatterStyle &style)
14739 {
14740   mScatterStyle = style;
14741 }
14742
14743 /*!
14744   Sets which kind of error bars (Key Error, Value Error or both) should be drawn on each data
14745   point. If you set \a errorType to something other than \ref etNone, make sure to actually pass
14746   error data via the specific setData functions along with the data points (e.g. \ref
14747   setDataValueError, \ref setDataKeyError, \ref setDataBothError).
14748
14749   \see ErrorType
14750 */
14751 void QCPGraph::setErrorType(ErrorType errorType)
14752 {
14753   mErrorType = errorType;
14754 }
14755
14756 /*!
14757   Sets the pen with which the error bars will be drawn.
14758   \see setErrorBarSize, setErrorType
14759 */
14760 void QCPGraph::setErrorPen(const QPen &pen)
14761 {
14762   mErrorPen = pen;
14763 }
14764
14765 /*!
14766   Sets the width of the handles at both ends of an error bar in pixels.
14767 */
14768 void QCPGraph::setErrorBarSize(double size)
14769 {
14770   mErrorBarSize = size;
14771 }
14772
14773 /*!
14774   If \a enabled is set to true, the error bar will not be drawn as a solid line under the scatter symbol but
14775   leave some free space around the symbol.
14776   
14777   This feature uses the current scatter size (\ref QCPScatterStyle::setSize) to determine the size
14778   of the area to leave blank. So when drawing Pixmaps as scatter points (\ref
14779   QCPScatterStyle::ssPixmap), the scatter size must be set manually to a value corresponding to the
14780   size of the Pixmap, if the error bars should leave gaps to its boundaries.
14781   
14782   \ref setErrorType, setErrorBarSize, setScatterStyle
14783 */
14784 void QCPGraph::setErrorBarSkipSymbol(bool enabled)
14785 {
14786   mErrorBarSkipSymbol = enabled;
14787 }
14788
14789 /*!
14790   Sets the target graph for filling the area between this graph and \a targetGraph with the current
14791   brush (\ref setBrush).
14792   
14793   When \a targetGraph is set to 0, a normal graph fill to the zero-value-line will be shown. To
14794   disable any filling, set the brush to Qt::NoBrush.
14795
14796   \see setBrush
14797 */
14798 void QCPGraph::setChannelFillGraph(QCPGraph *targetGraph)
14799 {
14800   // prevent setting channel target to this graph itself:
14801   if (targetGraph == this)
14802   {
14803     qDebug() << Q_FUNC_INFO << "targetGraph is this graph itself";
14804     mChannelFillGraph = 0;
14805     return;
14806   }
14807   // prevent setting channel target to a graph not in the plot:
14808   if (targetGraph && targetGraph->mParentPlot != mParentPlot)
14809   {
14810     qDebug() << Q_FUNC_INFO << "targetGraph not in same plot";
14811     mChannelFillGraph = 0;
14812     return;
14813   }
14814   
14815   mChannelFillGraph = targetGraph;
14816 }
14817
14818 /*!
14819   Sets whether adaptive sampling shall be used when plotting this graph. QCustomPlot's adaptive
14820   sampling technique can drastically improve the replot performance for graphs with a larger number
14821   of points (e.g. above 10,000), without notably changing the appearance of the graph.
14822   
14823   By default, adaptive sampling is enabled. Even if enabled, QCustomPlot decides whether adaptive
14824   sampling shall actually be used on a per-graph basis. So leaving adaptive sampling enabled has no
14825   disadvantage in almost all cases.
14826   
14827   \image html adaptive-sampling-line.png "A line plot of 500,000 points without and with adaptive sampling"
14828   
14829   As can be seen, line plots experience no visual degradation from adaptive sampling. Outliers are
14830   reproduced reliably, as well as the overall shape of the data set. The replot time reduces
14831   dramatically though. This allows QCustomPlot to display large amounts of data in realtime.
14832   
14833   \image html adaptive-sampling-scatter.png "A scatter plot of 100,000 points without and with adaptive sampling"
14834   
14835   Care must be taken when using high-density scatter plots in combination with adaptive sampling.
14836   The adaptive sampling algorithm treats scatter plots more carefully than line plots which still
14837   gives a significant reduction of replot times, but not quite as much as for line plots. This is
14838   because scatter plots inherently need more data points to be preserved in order to still resemble
14839   the original, non-adaptive-sampling plot. As shown above, the results still aren't quite
14840   identical, as banding occurs for the outer data points. This is in fact intentional, such that
14841   the boundaries of the data cloud stay visible to the viewer. How strong the banding appears,
14842   depends on the point density, i.e. the number of points in the plot.
14843   
14844   For some situations with scatter plots it might thus be desirable to manually turn adaptive
14845   sampling off. For example, when saving the plot to disk. This can be achieved by setting \a
14846   enabled to false before issuing a command like \ref QCustomPlot::savePng, and setting \a enabled
14847   back to true afterwards.
14848 */
14849 void QCPGraph::setAdaptiveSampling(bool enabled)
14850 {
14851   mAdaptiveSampling = enabled;
14852 }
14853
14854 /*!
14855   Adds the provided data points in \a dataMap to the current data.
14856   
14857   Alternatively, you can also access and modify the graph's data via the \ref data method, which
14858   returns a pointer to the internal \ref QCPDataMap.
14859   
14860   \see removeData
14861 */
14862 void QCPGraph::addData(const QCPDataMap &dataMap)
14863 {
14864   mData->unite(dataMap);
14865 }
14866
14867 /*! \overload
14868   Adds the provided single data point in \a data to the current data.
14869   
14870   Alternatively, you can also access and modify the graph's data via the \ref data method, which
14871   returns a pointer to the internal \ref QCPDataMap.
14872   
14873   \see removeData
14874 */
14875 void QCPGraph::addData(const QCPData &data)
14876 {
14877   mData->insertMulti(data.key, data);
14878 }
14879
14880 /*! \overload
14881   Adds the provided single data point as \a key and \a value pair to the current data.
14882   
14883   Alternatively, you can also access and modify the graph's data via the \ref data method, which
14884   returns a pointer to the internal \ref QCPDataMap.
14885   
14886   \see removeData
14887 */
14888 void QCPGraph::addData(double key, double value)
14889 {
14890   QCPData newData;
14891   newData.key = key;
14892   newData.value = value;
14893   mData->insertMulti(newData.key, newData);
14894 }
14895
14896 /*! \overload
14897   Adds the provided data points as \a key and \a value pairs to the current data.
14898   
14899   Alternatively, you can also access and modify the graph's data via the \ref data method, which
14900   returns a pointer to the internal \ref QCPDataMap.
14901   
14902   \see removeData
14903 */
14904 void QCPGraph::addData(const QVector<double> &keys, const QVector<double> &values)
14905 {
14906   int n = qMin(keys.size(), values.size());
14907   QCPData newData;
14908   for (int i=0; i<n; ++i)
14909   {
14910     newData.key = keys[i];
14911     newData.value = values[i];
14912     mData->insertMulti(newData.key, newData);
14913   }
14914 }
14915
14916 /*!
14917   Removes all data points with keys smaller than \a key.
14918   \see addData, clearData
14919 */
14920 void QCPGraph::removeDataBefore(double key)
14921 {
14922   QCPDataMap::iterator it = mData->begin();
14923   while (it != mData->end() && it.key() < key)
14924     it = mData->erase(it);
14925 }
14926
14927 /*!
14928   Removes all data points with keys greater than \a key.
14929   \see addData, clearData
14930 */
14931 void QCPGraph::removeDataAfter(double key)
14932 {
14933   if (mData->isEmpty()) return;
14934   QCPDataMap::iterator it = mData->upperBound(key);
14935   while (it != mData->end())
14936     it = mData->erase(it);
14937 }
14938
14939 /*!
14940   Removes all data points with keys between \a fromKey and \a toKey.
14941   if \a fromKey is greater or equal to \a toKey, the function does nothing. To remove
14942   a single data point with known key, use \ref removeData(double key).
14943   
14944   \see addData, clearData
14945 */
14946 void QCPGraph::removeData(double fromKey, double toKey)
14947 {
14948   if (fromKey >= toKey || mData->isEmpty()) return;
14949   QCPDataMap::iterator it = mData->upperBound(fromKey);
14950   QCPDataMap::iterator itEnd = mData->upperBound(toKey);
14951   while (it != itEnd)
14952     it = mData->erase(it);
14953 }
14954
14955 /*! \overload
14956   
14957   Removes a single data point at \a key. If the position is not known with absolute precision,
14958   consider using \ref removeData(double fromKey, double toKey) with a small fuzziness interval around
14959   the suspected position, depeding on the precision with which the key is known.
14960
14961   \see addData, clearData
14962 */
14963 void QCPGraph::removeData(double key)
14964 {
14965   mData->remove(key);
14966 }
14967
14968 /*!
14969   Removes all data points.
14970   \see removeData, removeDataAfter, removeDataBefore
14971 */
14972 void QCPGraph::clearData()
14973 {
14974   mData->clear();
14975 }
14976
14977 /* inherits documentation from base class */
14978 double QCPGraph::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
14979 {
14980   Q_UNUSED(details)
14981   if ((onlySelectable && !mSelectable) || mData->isEmpty())
14982     return -1;
14983   if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
14984   
14985   if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()))
14986     return pointDistance(pos);
14987   else
14988     return -1;
14989 }
14990
14991 /*! \overload
14992   
14993   Allows to define whether error bars are taken into consideration when determining the new axis
14994   range.
14995   
14996   \see rescaleKeyAxis, rescaleValueAxis, QCPAbstractPlottable::rescaleAxes, QCustomPlot::rescaleAxes
14997 */
14998 void QCPGraph::rescaleAxes(bool onlyEnlarge, bool includeErrorBars) const
14999 {
15000   rescaleKeyAxis(onlyEnlarge, includeErrorBars);
15001   rescaleValueAxis(onlyEnlarge, includeErrorBars);
15002 }
15003
15004 /*! \overload
15005   
15006   Allows to define whether error bars (of kind \ref QCPGraph::etKey) are taken into consideration
15007   when determining the new axis range.
15008   
15009   \see rescaleAxes, QCPAbstractPlottable::rescaleKeyAxis
15010 */
15011 void QCPGraph::rescaleKeyAxis(bool onlyEnlarge, bool includeErrorBars) const
15012 {
15013   // this code is a copy of QCPAbstractPlottable::rescaleKeyAxis with the only change
15014   // that getKeyRange is passed the includeErrorBars value.
15015   if (mData->isEmpty()) return;
15016   
15017   QCPAxis *keyAxis = mKeyAxis.data();
15018   if (!keyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
15019
15020   SignDomain signDomain = sdBoth;
15021   if (keyAxis->scaleType() == QCPAxis::stLogarithmic)
15022     signDomain = (keyAxis->range().upper < 0 ? sdNegative : sdPositive);
15023   
15024   bool foundRange;
15025   QCPRange newRange = getKeyRange(foundRange, signDomain, includeErrorBars);
15026   
15027   if (foundRange)
15028   {
15029     if (onlyEnlarge)
15030     {
15031       if (keyAxis->range().lower < newRange.lower)
15032         newRange.lower = keyAxis->range().lower;
15033       if (keyAxis->range().upper > newRange.upper)
15034         newRange.upper = keyAxis->range().upper;
15035     }
15036     keyAxis->setRange(newRange);
15037   }
15038 }
15039
15040 /*! \overload
15041   
15042   Allows to define whether error bars (of kind \ref QCPGraph::etValue) are taken into consideration
15043   when determining the new axis range.
15044   
15045   \see rescaleAxes, QCPAbstractPlottable::rescaleValueAxis
15046 */
15047 void QCPGraph::rescaleValueAxis(bool onlyEnlarge, bool includeErrorBars) const
15048 {
15049   // this code is a copy of QCPAbstractPlottable::rescaleValueAxis with the only change
15050   // is that getValueRange is passed the includeErrorBars value.
15051   if (mData->isEmpty()) return;
15052   
15053   QCPAxis *valueAxis = mValueAxis.data();
15054   if (!valueAxis) { qDebug() << Q_FUNC_INFO << "invalid value axis"; return; }
15055
15056   SignDomain signDomain = sdBoth;
15057   if (valueAxis->scaleType() == QCPAxis::stLogarithmic)
15058     signDomain = (valueAxis->range().upper < 0 ? sdNegative : sdPositive);
15059   
15060   bool foundRange;
15061   QCPRange newRange = getValueRange(foundRange, signDomain, includeErrorBars);
15062   
15063   if (foundRange)
15064   {
15065     if (onlyEnlarge)
15066     {
15067       if (valueAxis->range().lower < newRange.lower)
15068         newRange.lower = valueAxis->range().lower;
15069       if (valueAxis->range().upper > newRange.upper)
15070         newRange.upper = valueAxis->range().upper;
15071     }
15072     valueAxis->setRange(newRange);
15073   }
15074 }
15075
15076 /* inherits documentation from base class */
15077 void QCPGraph::draw(QCPPainter *painter)
15078 {
15079   if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15080   if (mKeyAxis.data()->range().size() <= 0 || mData->isEmpty()) return;
15081   if (mLineStyle == lsNone && mScatterStyle.isNone()) return;
15082   
15083   // allocate line and (if necessary) point vectors:
15084   QVector<QPointF> *lineData = new QVector<QPointF>;
15085   QVector<QCPData> *scatterData = 0;
15086   if (!mScatterStyle.isNone())
15087     scatterData = new QVector<QCPData>;
15088   
15089   // fill vectors with data appropriate to plot style:
15090   getPlotData(lineData, scatterData);
15091   
15092   // check data validity if flag set:
15093 #ifdef QCUSTOMPLOT_CHECK_DATA
15094   QCPDataMap::const_iterator it;
15095   for (it = mData->constBegin(); it != mData->constEnd(); ++it)
15096   {
15097     if (QCP::isInvalidData(it.value().key, it.value().value) ||
15098         QCP::isInvalidData(it.value().keyErrorPlus, it.value().keyErrorMinus) ||
15099         QCP::isInvalidData(it.value().valueErrorPlus, it.value().valueErrorPlus))
15100       qDebug() << Q_FUNC_INFO << "Data point at" << it.key() << "invalid." << "Plottable name:" << name();
15101   }
15102 #endif
15103
15104   // draw fill of graph:
15105   if (mLineStyle != lsNone)
15106     drawFill(painter, lineData);
15107   
15108   // draw line:
15109   if (mLineStyle == lsImpulse)
15110     drawImpulsePlot(painter, lineData);
15111   else if (mLineStyle != lsNone)
15112     drawLinePlot(painter, lineData); // also step plots can be drawn as a line plot
15113   
15114   // draw scatters:
15115   if (scatterData)
15116     drawScatterPlot(painter, scatterData);
15117   
15118   // free allocated line and point vectors:
15119   delete lineData;
15120   if (scatterData)
15121     delete scatterData;
15122 }
15123
15124 /* inherits documentation from base class */
15125 void QCPGraph::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const
15126 {
15127   // draw fill:
15128   if (mBrush.style() != Qt::NoBrush)
15129   {
15130     applyFillAntialiasingHint(painter);
15131     painter->fillRect(QRectF(rect.left(), rect.top()+rect.height()/2.0, rect.width(), rect.height()/3.0), mBrush);
15132   }
15133   // draw line vertically centered:
15134   if (mLineStyle != lsNone)
15135   {
15136     applyDefaultAntialiasingHint(painter);
15137     painter->setPen(mPen);
15138     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
15139   }
15140   // draw scatter symbol:
15141   if (!mScatterStyle.isNone())
15142   {
15143     applyScattersAntialiasingHint(painter);
15144     // scale scatter pixmap if it's too large to fit in legend icon rect:
15145     if (mScatterStyle.shape() == QCPScatterStyle::ssPixmap && (mScatterStyle.pixmap().size().width() > rect.width() || mScatterStyle.pixmap().size().height() > rect.height()))
15146     {
15147       QCPScatterStyle scaledStyle(mScatterStyle);
15148       scaledStyle.setPixmap(scaledStyle.pixmap().scaled(rect.size().toSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
15149       scaledStyle.applyTo(painter, mPen);
15150       scaledStyle.drawShape(painter, QRectF(rect).center());
15151     } else
15152     {
15153       mScatterStyle.applyTo(painter, mPen);
15154       mScatterStyle.drawShape(painter, QRectF(rect).center());
15155     }
15156   }
15157 }
15158
15159 /*! \internal
15160
15161   This function branches out to the line style specific "get(...)PlotData" functions, according to
15162   the line style of the graph.
15163   
15164   \a lineData will be filled with raw points that will be drawn with the according draw functions,
15165   e.g. \ref drawLinePlot and \ref drawImpulsePlot. These aren't necessarily the original data
15166   points, since for step plots for example, additional points are needed for drawing lines that
15167   make up steps. If the line style of the graph is \ref lsNone, the \a lineData vector will be left
15168   untouched.
15169   
15170   \a scatterData will be filled with the original data points so \ref drawScatterPlot can draw the
15171   scatter symbols accordingly. If no scatters need to be drawn, i.e. the scatter style's shape is
15172   \ref QCPScatterStyle::ssNone, pass 0 as \a scatterData, and this step will be skipped.
15173   
15174   \see getScatterPlotData, getLinePlotData, getStepLeftPlotData, getStepRightPlotData,
15175   getStepCenterPlotData, getImpulsePlotData
15176 */
15177 void QCPGraph::getPlotData(QVector<QPointF> *lineData, QVector<QCPData> *scatterData) const
15178 {
15179   switch(mLineStyle)
15180   {
15181     case lsNone: getScatterPlotData(scatterData); break;
15182     case lsLine: getLinePlotData(lineData, scatterData); break;
15183     case lsStepLeft: getStepLeftPlotData(lineData, scatterData); break;
15184     case lsStepRight: getStepRightPlotData(lineData, scatterData); break;
15185     case lsStepCenter: getStepCenterPlotData(lineData, scatterData); break;
15186     case lsImpulse: getImpulsePlotData(lineData, scatterData); break;
15187   }
15188 }
15189
15190 /*! \internal
15191   
15192   If line style is \ref lsNone and the scatter style's shape is not \ref QCPScatterStyle::ssNone,
15193   this function serves at providing the visible data points in \a scatterData, so the \ref
15194   drawScatterPlot function can draw the scatter points accordingly.
15195   
15196   If line style is not \ref lsNone, this function is not called and the data for the scatter points
15197   are (if needed) calculated inside the corresponding other "get(...)PlotData" functions.
15198   
15199   \see drawScatterPlot
15200 */
15201 void QCPGraph::getScatterPlotData(QVector<QCPData> *scatterData) const
15202 {
15203   getPreparedData(0, scatterData);
15204 }
15205
15206 /*! \internal
15207   
15208   Places the raw data points needed for a normal linearly connected graph in \a linePixelData.
15209
15210   As for all plot data retrieval functions, \a scatterData just contains all unaltered data (scatter)
15211   points that are visible for drawing scatter points, if necessary. If drawing scatter points is
15212   disabled (i.e. the scatter style's shape is \ref QCPScatterStyle::ssNone), pass 0 as \a
15213   scatterData, and the function will skip filling the vector.
15214   
15215   \see drawLinePlot
15216 */
15217 void QCPGraph::getLinePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const
15218 {
15219   QCPAxis *keyAxis = mKeyAxis.data();
15220   QCPAxis *valueAxis = mValueAxis.data();
15221   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15222   if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as linePixelData"; return; }
15223   
15224   QVector<QCPData> lineData;
15225   getPreparedData(&lineData, scatterData);
15226   linePixelData->reserve(lineData.size()+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill
15227   linePixelData->resize(lineData.size());
15228   
15229   // transform lineData points to pixels:
15230   if (keyAxis->orientation() == Qt::Vertical)
15231   {
15232     for (int i=0; i<lineData.size(); ++i)
15233     {
15234       (*linePixelData)[i].setX(valueAxis->coordToPixel(lineData.at(i).value));
15235       (*linePixelData)[i].setY(keyAxis->coordToPixel(lineData.at(i).key));
15236     }
15237   } else // key axis is horizontal
15238   {
15239     for (int i=0; i<lineData.size(); ++i)
15240     {
15241       (*linePixelData)[i].setX(keyAxis->coordToPixel(lineData.at(i).key));
15242       (*linePixelData)[i].setY(valueAxis->coordToPixel(lineData.at(i).value));
15243     }
15244   }
15245 }
15246
15247 /*!
15248   \internal
15249   Places the raw data points needed for a step plot with left oriented steps in \a lineData.
15250
15251   As for all plot data retrieval functions, \a scatterData just contains all unaltered data (scatter)
15252   points that are visible for drawing scatter points, if necessary. If drawing scatter points is
15253   disabled (i.e. the scatter style's shape is \ref QCPScatterStyle::ssNone), pass 0 as \a
15254   scatterData, and the function will skip filling the vector.
15255   
15256   \see drawLinePlot
15257 */
15258 void QCPGraph::getStepLeftPlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const
15259 {
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 lineData"; return; }
15264   
15265   QVector<QCPData> lineData;
15266   getPreparedData(&lineData, scatterData);
15267   linePixelData->reserve(lineData.size()*2+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill
15268   linePixelData->resize(lineData.size()*2);
15269   
15270   // calculate steps from lineData and transform to pixel coordinates:
15271   if (keyAxis->orientation() == Qt::Vertical)
15272   {
15273     double lastValue = valueAxis->coordToPixel(lineData.first().value);
15274     double key;
15275     for (int i=0; i<lineData.size(); ++i)
15276     {
15277       key = keyAxis->coordToPixel(lineData.at(i).key);
15278       (*linePixelData)[i*2+0].setX(lastValue);
15279       (*linePixelData)[i*2+0].setY(key);
15280       lastValue = valueAxis->coordToPixel(lineData.at(i).value);
15281       (*linePixelData)[i*2+1].setX(lastValue);
15282       (*linePixelData)[i*2+1].setY(key);
15283     }
15284   } else // key axis is horizontal
15285   {
15286     double lastValue = valueAxis->coordToPixel(lineData.first().value);
15287     double key;
15288     for (int i=0; i<lineData.size(); ++i)
15289     {
15290       key = keyAxis->coordToPixel(lineData.at(i).key);
15291       (*linePixelData)[i*2+0].setX(key);
15292       (*linePixelData)[i*2+0].setY(lastValue);
15293       lastValue = valueAxis->coordToPixel(lineData.at(i).value);
15294       (*linePixelData)[i*2+1].setX(key);
15295       (*linePixelData)[i*2+1].setY(lastValue);
15296     }
15297   }
15298 }
15299
15300 /*!
15301   \internal
15302   Places the raw data points needed for a step plot with right oriented steps in \a lineData.
15303
15304   As for all plot data retrieval functions, \a scatterData just contains all unaltered data (scatter)
15305   points that are visible for drawing scatter points, if necessary. If drawing scatter points is
15306   disabled (i.e. the scatter style's shape is \ref QCPScatterStyle::ssNone), pass 0 as \a
15307   scatterData, and the function will skip filling the vector.
15308   
15309   \see drawLinePlot
15310 */
15311 void QCPGraph::getStepRightPlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const
15312 {
15313   QCPAxis *keyAxis = mKeyAxis.data();
15314   QCPAxis *valueAxis = mValueAxis.data();
15315   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15316   if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as lineData"; return; }
15317   
15318   QVector<QCPData> lineData;
15319   getPreparedData(&lineData, scatterData);
15320   linePixelData->reserve(lineData.size()*2+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill
15321   linePixelData->resize(lineData.size()*2);
15322   
15323   // calculate steps from lineData and transform to pixel coordinates:
15324   if (keyAxis->orientation() == Qt::Vertical)
15325   {
15326     double lastKey = keyAxis->coordToPixel(lineData.first().key);
15327     double value;
15328     for (int i=0; i<lineData.size(); ++i)
15329     {
15330       value = valueAxis->coordToPixel(lineData.at(i).value);
15331       (*linePixelData)[i*2+0].setX(value);
15332       (*linePixelData)[i*2+0].setY(lastKey);
15333       lastKey = keyAxis->coordToPixel(lineData.at(i).key);
15334       (*linePixelData)[i*2+1].setX(value);
15335       (*linePixelData)[i*2+1].setY(lastKey);
15336     }
15337   } else // key axis is horizontal
15338   {
15339     double lastKey = keyAxis->coordToPixel(lineData.first().key);
15340     double value;
15341     for (int i=0; i<lineData.size(); ++i)
15342     {
15343       value = valueAxis->coordToPixel(lineData.at(i).value);
15344       (*linePixelData)[i*2+0].setX(lastKey);
15345       (*linePixelData)[i*2+0].setY(value);
15346       lastKey = keyAxis->coordToPixel(lineData.at(i).key);
15347       (*linePixelData)[i*2+1].setX(lastKey);
15348       (*linePixelData)[i*2+1].setY(value);
15349     }
15350   }
15351 }
15352
15353 /*!
15354   \internal
15355   Places the raw data points needed for a step plot with centered steps in \a lineData.
15356
15357   As for all plot data retrieval functions, \a scatterData just contains all unaltered data (scatter)
15358   points that are visible for drawing scatter points, if necessary. If drawing scatter points is
15359   disabled (i.e. the scatter style's shape is \ref QCPScatterStyle::ssNone), pass 0 as \a
15360   scatterData, and the function will skip filling the vector.
15361   
15362   \see drawLinePlot
15363 */
15364 void QCPGraph::getStepCenterPlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const
15365 {
15366   QCPAxis *keyAxis = mKeyAxis.data();
15367   QCPAxis *valueAxis = mValueAxis.data();
15368   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15369   if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as lineData"; return; }
15370   
15371   QVector<QCPData> lineData;
15372   getPreparedData(&lineData, scatterData);
15373   linePixelData->reserve(lineData.size()*2+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill
15374   linePixelData->resize(lineData.size()*2);
15375   // calculate steps from lineData and transform to pixel coordinates:
15376   if (keyAxis->orientation() == Qt::Vertical)
15377   {
15378     double lastKey = keyAxis->coordToPixel(lineData.first().key);
15379     double lastValue = valueAxis->coordToPixel(lineData.first().value);
15380     double key;
15381     (*linePixelData)[0].setX(lastValue);
15382     (*linePixelData)[0].setY(lastKey);
15383     for (int i=1; i<lineData.size(); ++i)
15384     {
15385       key = (keyAxis->coordToPixel(lineData.at(i).key)+lastKey)*0.5;
15386       (*linePixelData)[i*2-1].setX(lastValue);
15387       (*linePixelData)[i*2-1].setY(key);
15388       lastValue = valueAxis->coordToPixel(lineData.at(i).value);
15389       lastKey = keyAxis->coordToPixel(lineData.at(i).key);
15390       (*linePixelData)[i*2+0].setX(lastValue);
15391       (*linePixelData)[i*2+0].setY(key);
15392     }
15393     (*linePixelData)[lineData.size()*2-1].setX(lastValue);
15394     (*linePixelData)[lineData.size()*2-1].setY(lastKey);
15395   } else // key axis is horizontal
15396   {
15397     double lastKey = keyAxis->coordToPixel(lineData.first().key);
15398     double lastValue = valueAxis->coordToPixel(lineData.first().value);
15399     double key;
15400     (*linePixelData)[0].setX(lastKey);
15401     (*linePixelData)[0].setY(lastValue);
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(key);
15406       (*linePixelData)[i*2-1].setY(lastValue);
15407       lastValue = valueAxis->coordToPixel(lineData.at(i).value);
15408       lastKey = keyAxis->coordToPixel(lineData.at(i).key);
15409       (*linePixelData)[i*2+0].setX(key);
15410       (*linePixelData)[i*2+0].setY(lastValue);
15411     }
15412     (*linePixelData)[lineData.size()*2-1].setX(lastKey);
15413     (*linePixelData)[lineData.size()*2-1].setY(lastValue);
15414   }
15415
15416 }
15417
15418 /*!
15419   \internal
15420   Places the raw data points needed for an impulse plot in \a lineData.
15421
15422   As for all plot data retrieval functions, \a scatterData just contains all unaltered data (scatter)
15423   points that are visible for drawing scatter points, if necessary. If drawing scatter points is
15424   disabled (i.e. the scatter style's shape is \ref QCPScatterStyle::ssNone), pass 0 as \a
15425   scatterData, and the function will skip filling the vector.
15426   
15427   \see drawImpulsePlot
15428 */
15429 void QCPGraph::getImpulsePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const
15430 {
15431   QCPAxis *keyAxis = mKeyAxis.data();
15432   QCPAxis *valueAxis = mValueAxis.data();
15433   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15434   if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as linePixelData"; return; }
15435   
15436   QVector<QCPData> lineData;
15437   getPreparedData(&lineData, scatterData);
15438   linePixelData->resize(lineData.size()*2); // no need to reserve 2 extra points because impulse plot has no fill
15439   
15440   // transform lineData points to pixels:
15441   if (keyAxis->orientation() == Qt::Vertical)
15442   {
15443     double zeroPointX = valueAxis->coordToPixel(0);
15444     double key;
15445     for (int i=0; i<lineData.size(); ++i)
15446     {
15447       key = keyAxis->coordToPixel(lineData.at(i).key);
15448       (*linePixelData)[i*2+0].setX(zeroPointX);
15449       (*linePixelData)[i*2+0].setY(key);
15450       (*linePixelData)[i*2+1].setX(valueAxis->coordToPixel(lineData.at(i).value));
15451       (*linePixelData)[i*2+1].setY(key);
15452     }
15453   } else // key axis is horizontal
15454   {
15455     double zeroPointY = valueAxis->coordToPixel(0);
15456     double key;
15457     for (int i=0; i<lineData.size(); ++i)
15458     {
15459       key = keyAxis->coordToPixel(lineData.at(i).key);
15460       (*linePixelData)[i*2+0].setX(key);
15461       (*linePixelData)[i*2+0].setY(zeroPointY);
15462       (*linePixelData)[i*2+1].setX(key);
15463       (*linePixelData)[i*2+1].setY(valueAxis->coordToPixel(lineData.at(i).value));
15464     }
15465   }
15466 }
15467
15468 /*! \internal
15469   
15470   Draws the fill of the graph with the specified brush.
15471
15472   If the fill is a normal fill towards the zero-value-line, only the \a lineData is required (and
15473   two extra points at the zero-value-line, which are added by \ref addFillBasePoints and removed by
15474   \ref removeFillBasePoints after the fill drawing is done).
15475   
15476   If the fill is a channel fill between this QCPGraph and another QCPGraph (mChannelFillGraph), the
15477   more complex polygon is calculated with the \ref getChannelFillPolygon function.
15478   
15479   \see drawLinePlot
15480 */
15481 void QCPGraph::drawFill(QCPPainter *painter, QVector<QPointF> *lineData) const
15482 {
15483   if (mLineStyle == lsImpulse) return; // fill doesn't make sense for impulse plot
15484   if (mainBrush().style() == Qt::NoBrush || mainBrush().color().alpha() == 0) return;
15485   
15486   applyFillAntialiasingHint(painter);
15487   if (!mChannelFillGraph)
15488   {
15489     // draw base fill under graph, fill goes all the way to the zero-value-line:
15490     addFillBasePoints(lineData);
15491     painter->setPen(Qt::NoPen);
15492     painter->setBrush(mainBrush());
15493     painter->drawPolygon(QPolygonF(*lineData));
15494     removeFillBasePoints(lineData);
15495   } else
15496   {
15497     // draw channel fill between this graph and mChannelFillGraph:
15498     painter->setPen(Qt::NoPen);
15499     painter->setBrush(mainBrush());
15500     painter->drawPolygon(getChannelFillPolygon(lineData));
15501   }
15502 }
15503
15504 /*! \internal
15505   
15506   Draws scatter symbols at every data point passed in \a scatterData. scatter symbols are independent
15507   of the line style and are always drawn if the scatter style's shape is not \ref
15508   QCPScatterStyle::ssNone. Hence, the \a scatterData vector is outputted by all "get(...)PlotData"
15509   functions, together with the (line style dependent) line data.
15510   
15511   \see drawLinePlot, drawImpulsePlot
15512 */
15513 void QCPGraph::drawScatterPlot(QCPPainter *painter, QVector<QCPData> *scatterData) const
15514 {
15515   QCPAxis *keyAxis = mKeyAxis.data();
15516   QCPAxis *valueAxis = mValueAxis.data();
15517   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15518   
15519   // draw error bars:
15520   if (mErrorType != etNone)
15521   {
15522     applyErrorBarsAntialiasingHint(painter);
15523     painter->setPen(mErrorPen);
15524     if (keyAxis->orientation() == Qt::Vertical)
15525     {
15526       for (int i=0; i<scatterData->size(); ++i)
15527         drawError(painter, valueAxis->coordToPixel(scatterData->at(i).value), keyAxis->coordToPixel(scatterData->at(i).key), scatterData->at(i));
15528     } else
15529     {
15530       for (int i=0; i<scatterData->size(); ++i)
15531         drawError(painter, keyAxis->coordToPixel(scatterData->at(i).key), valueAxis->coordToPixel(scatterData->at(i).value), scatterData->at(i));
15532     }
15533   }
15534   
15535   // draw scatter point symbols:
15536   applyScattersAntialiasingHint(painter);
15537   mScatterStyle.applyTo(painter, mPen);
15538   if (keyAxis->orientation() == Qt::Vertical)
15539   {
15540     for (int i=0; i<scatterData->size(); ++i)
15541       if (!qIsNaN(scatterData->at(i).value))
15542         mScatterStyle.drawShape(painter, valueAxis->coordToPixel(scatterData->at(i).value), keyAxis->coordToPixel(scatterData->at(i).key));
15543   } else
15544   {
15545     for (int i=0; i<scatterData->size(); ++i)
15546       if (!qIsNaN(scatterData->at(i).value))
15547         mScatterStyle.drawShape(painter, keyAxis->coordToPixel(scatterData->at(i).key), valueAxis->coordToPixel(scatterData->at(i).value));
15548   }
15549 }
15550
15551 /*!  \internal
15552   
15553   Draws line graphs from the provided data. It connects all points in \a lineData, which was
15554   created by one of the "get(...)PlotData" functions for line styles that require simple line
15555   connections between the point vector they create. These are for example \ref getLinePlotData,
15556   \ref getStepLeftPlotData, \ref getStepRightPlotData and \ref getStepCenterPlotData.
15557   
15558   \see drawScatterPlot, drawImpulsePlot
15559 */
15560 void QCPGraph::drawLinePlot(QCPPainter *painter, QVector<QPointF> *lineData) const
15561 {
15562   // draw line of graph:
15563   if (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0)
15564   {
15565     applyDefaultAntialiasingHint(painter);
15566     painter->setPen(mainPen());
15567     painter->setBrush(Qt::NoBrush);
15568     
15569     /* Draws polyline in batches, currently not used:
15570     int p = 0;
15571     while (p < lineData->size())
15572     {
15573       int batch = qMin(25, lineData->size()-p);
15574       if (p != 0)
15575       {
15576         ++batch;
15577         --p; // to draw the connection lines between two batches
15578       }
15579       painter->drawPolyline(lineData->constData()+p, batch);
15580       p += batch;
15581     }
15582     */
15583     
15584     // if drawing solid line and not in PDF, use much faster line drawing instead of polyline:
15585     if (mParentPlot->plottingHints().testFlag(QCP::phFastPolylines) &&
15586         painter->pen().style() == Qt::SolidLine &&
15587         !painter->modes().testFlag(QCPPainter::pmVectorized) &&
15588         !painter->modes().testFlag(QCPPainter::pmNoCaching))
15589     {
15590       int i = 0;
15591       bool lastIsNan = false;
15592       const int lineDataSize = lineData->size();
15593       while (i < lineDataSize && (qIsNaN(lineData->at(i).y()) || qIsNaN(lineData->at(i).x()))) // make sure first point is not NaN
15594         ++i;
15595       ++i; // because drawing works in 1 point retrospect
15596       while (i < lineDataSize)
15597       {
15598         if (!qIsNaN(lineData->at(i).y()) && !qIsNaN(lineData->at(i).x())) // NaNs create a gap in the line
15599         {
15600           if (!lastIsNan)
15601             painter->drawLine(lineData->at(i-1), lineData->at(i));
15602           else
15603             lastIsNan = false;
15604         } else
15605           lastIsNan = true;
15606         ++i;
15607       }
15608     } else
15609     {
15610       int segmentStart = 0;
15611       int i = 0;
15612       const int lineDataSize = lineData->size();
15613       while (i < lineDataSize)
15614      {
15615         if (qIsNaN(lineData->at(i).y()) || qIsNaN(lineData->at(i).x()) || qIsInf(lineData->at(i).y())) // NaNs create a gap in the line. Also filter Infs which make drawPolyline block
15616         {
15617           painter->drawPolyline(lineData->constData()+segmentStart, i-segmentStart); // i, because we don't want to include the current NaN point
15618           segmentStart = i+1;
15619         }
15620         ++i;
15621       }
15622       // draw last segment:
15623       painter->drawPolyline(lineData->constData()+segmentStart, lineDataSize-segmentStart);
15624     }
15625   }
15626 }
15627
15628 /*! \internal
15629   
15630   Draws impulses from the provided data, i.e. it connects all line pairs in \a lineData, which was
15631   created by \ref getImpulsePlotData.
15632   
15633   \see drawScatterPlot, drawLinePlot
15634 */
15635 void QCPGraph::drawImpulsePlot(QCPPainter *painter, QVector<QPointF> *lineData) const
15636 {
15637   // draw impulses:
15638   if (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0)
15639   {
15640     applyDefaultAntialiasingHint(painter);
15641     QPen pen = mainPen();
15642     pen.setCapStyle(Qt::FlatCap); // so impulse line doesn't reach beyond zero-line
15643     painter->setPen(pen);
15644     painter->setBrush(Qt::NoBrush);
15645     painter->drawLines(*lineData);
15646   }
15647 }
15648
15649 /*! \internal
15650   
15651   Returns the \a lineData and \a scatterData that need to be plotted for this graph taking into
15652   consideration the current axis ranges and, if \ref setAdaptiveSampling is enabled, local point
15653   densities.
15654   
15655   0 may be passed as \a lineData or \a scatterData to indicate that the respective dataset isn't
15656   needed. For example, if the scatter style (\ref setScatterStyle) is \ref QCPScatterStyle::ssNone, \a
15657   scatterData should be 0 to prevent unnecessary calculations.
15658   
15659   This method is used by the various "get(...)PlotData" methods to get the basic working set of data.
15660 */
15661 void QCPGraph::getPreparedData(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const
15662 {
15663   QCPAxis *keyAxis = mKeyAxis.data();
15664   QCPAxis *valueAxis = mValueAxis.data();
15665   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15666   // get visible data range:
15667   QCPDataMap::const_iterator lower, upper; // note that upper is the actual upper point, and not 1 step after the upper point
15668   getVisibleDataBounds(lower, upper);
15669   if (lower == mData->constEnd() || upper == mData->constEnd())
15670     return;
15671   
15672   // count points in visible range, taking into account that we only need to count to the limit maxCount if using adaptive sampling:
15673   int maxCount = std::numeric_limits<int>::max();
15674   if (mAdaptiveSampling)
15675   {
15676     int keyPixelSpan = qAbs(keyAxis->coordToPixel(lower.key())-keyAxis->coordToPixel(upper.key()));
15677     maxCount = 2*keyPixelSpan+2;
15678   }
15679   int dataCount = countDataInBounds(lower, upper, maxCount);
15680   
15681   if (mAdaptiveSampling && dataCount >= maxCount) // use adaptive sampling only if there are at least two points per pixel on average
15682   {
15683     if (lineData)
15684     {
15685       QCPDataMap::const_iterator it = lower;
15686       QCPDataMap::const_iterator upperEnd = upper+1;
15687       double minValue = it.value().value;
15688       double maxValue = it.value().value;
15689       QCPDataMap::const_iterator currentIntervalFirstPoint = it;
15690       int reversedFactor = keyAxis->rangeReversed() != (keyAxis->orientation()==Qt::Vertical) ? -1 : 1; // is used to calculate keyEpsilon pixel into the correct direction
15691       int reversedRound = keyAxis->rangeReversed() != (keyAxis->orientation()==Qt::Vertical) ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey
15692       double currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel(lower.key())+reversedRound));
15693       double lastIntervalEndKey = currentIntervalStartKey;
15694       double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates
15695       bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes)
15696       int intervalDataCount = 1;
15697       ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect
15698       while (it != upperEnd)
15699       {
15700         if (it.key() < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this cluster if necessary
15701         {
15702           if (it.value().value < minValue)
15703             minValue = it.value().value;
15704           else if (it.value().value > maxValue)
15705             maxValue = it.value().value;
15706           ++intervalDataCount;
15707         } else // new pixel interval started
15708         {
15709           if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster
15710           {
15711             if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point is further away, so first point of this cluster must be at a real data point
15712               lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.2, currentIntervalFirstPoint.value().value));
15713             lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue));
15714             lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue));
15715             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
15716               lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.8, (it-1).value().value));
15717           } else
15718             lineData->append(QCPData(currentIntervalFirstPoint.key(), currentIntervalFirstPoint.value().value));
15719           lastIntervalEndKey = (it-1).value().key;
15720           minValue = it.value().value;
15721           maxValue = it.value().value;
15722           currentIntervalFirstPoint = it;
15723           currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel(it.key())+reversedRound));
15724           if (keyEpsilonVariable)
15725             keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor));
15726           intervalDataCount = 1;
15727         }
15728         ++it;
15729       }
15730       // handle last interval:
15731       if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster
15732       {
15733         if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point wasn't a cluster, so first point of this cluster must be at a real data point
15734           lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.2, currentIntervalFirstPoint.value().value));
15735         lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue));
15736         lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue));
15737       } else
15738         lineData->append(QCPData(currentIntervalFirstPoint.key(), currentIntervalFirstPoint.value().value));
15739     }
15740     
15741     if (scatterData)
15742     {
15743       double valueMaxRange = valueAxis->range().upper;
15744       double valueMinRange = valueAxis->range().lower;
15745       QCPDataMap::const_iterator it = lower;
15746       QCPDataMap::const_iterator upperEnd = upper+1;
15747       double minValue = it.value().value;
15748       double maxValue = it.value().value;
15749       QCPDataMap::const_iterator minValueIt = it;
15750       QCPDataMap::const_iterator maxValueIt = it;
15751       QCPDataMap::const_iterator currentIntervalStart = it;
15752       int reversedFactor = keyAxis->rangeReversed() ? -1 : 1; // is used to calculate keyEpsilon pixel into the correct direction
15753       int reversedRound = keyAxis->rangeReversed() ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey
15754       double currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel(lower.key())+reversedRound));
15755       double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates
15756       bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes)
15757       int intervalDataCount = 1;
15758       ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect
15759       while (it != upperEnd)
15760       {
15761         if (it.key() < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this pixel if necessary
15762         {
15763           if (it.value().value < minValue && it.value().value > valueMinRange && it.value().value < valueMaxRange)
15764           {
15765             minValue = it.value().value;
15766             minValueIt = it;
15767           } else if (it.value().value > maxValue && it.value().value > valueMinRange && it.value().value < valueMaxRange)
15768           {
15769             maxValue = it.value().value;
15770             maxValueIt = it;
15771           }
15772           ++intervalDataCount;
15773         } else // new pixel started
15774         {
15775           if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them
15776           {
15777             // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot):
15778             double valuePixelSpan = qAbs(valueAxis->coordToPixel(minValue)-valueAxis->coordToPixel(maxValue));
15779             int dataModulo = qMax(1, qRound(intervalDataCount/(valuePixelSpan/4.0))); // approximately every 4 value pixels one data point on average
15780             QCPDataMap::const_iterator intervalIt = currentIntervalStart;
15781             int c = 0;
15782             while (intervalIt != it)
15783             {
15784               if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && intervalIt.value().value > valueMinRange && intervalIt.value().value < valueMaxRange)
15785                 scatterData->append(intervalIt.value());
15786               ++c;
15787               ++intervalIt;
15788             }
15789           } else if (currentIntervalStart.value().value > valueMinRange && currentIntervalStart.value().value < valueMaxRange)
15790             scatterData->append(currentIntervalStart.value());
15791           minValue = it.value().value;
15792           maxValue = it.value().value;
15793           currentIntervalStart = it;
15794           currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel(it.key())+reversedRound));
15795           if (keyEpsilonVariable)
15796             keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor));
15797           intervalDataCount = 1;
15798         }
15799         ++it;
15800       }
15801       // handle last interval:
15802       if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them
15803       {
15804         // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot):
15805         double valuePixelSpan = qAbs(valueAxis->coordToPixel(minValue)-valueAxis->coordToPixel(maxValue));
15806         int dataModulo = qMax(1, qRound(intervalDataCount/(valuePixelSpan/4.0))); // approximately every 4 value pixels one data point on average
15807         QCPDataMap::const_iterator intervalIt = currentIntervalStart;
15808         int c = 0;
15809         while (intervalIt != it)
15810         {
15811           if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && intervalIt.value().value > valueMinRange && intervalIt.value().value < valueMaxRange)
15812             scatterData->append(intervalIt.value());
15813           ++c;
15814           ++intervalIt;
15815         }
15816       } else if (currentIntervalStart.value().value > valueMinRange && currentIntervalStart.value().value < valueMaxRange)
15817         scatterData->append(currentIntervalStart.value());
15818     }
15819   } else // don't use adaptive sampling algorithm, transfer points one-to-one from the map into the output parameters
15820   {
15821     QVector<QCPData> *dataVector = 0;
15822     if (lineData)
15823       dataVector = lineData;
15824     else if (scatterData)
15825       dataVector = scatterData;
15826     if (dataVector)
15827     {
15828       QCPDataMap::const_iterator it = lower;
15829       QCPDataMap::const_iterator upperEnd = upper+1;
15830       dataVector->reserve(dataCount+2); // +2 for possible fill end points
15831       while (it != upperEnd)
15832       {
15833         dataVector->append(it.value());
15834         ++it;
15835       }
15836     }
15837     if (lineData && scatterData)
15838       *scatterData = *dataVector;
15839   }
15840 }
15841
15842 /*!  \internal
15843   
15844   called by the scatter drawing function (\ref drawScatterPlot) to draw the error bars on one data
15845   point. \a x and \a y pixel positions of the data point are passed since they are already known in
15846   pixel coordinates in the drawing function, so we save some extra coordToPixel transforms here. \a
15847   data is therefore only used for the errors, not key and value.
15848 */
15849 void QCPGraph::drawError(QCPPainter *painter, double x, double y, const QCPData &data) const
15850 {
15851   if (qIsNaN(data.value))
15852     return;
15853   QCPAxis *keyAxis = mKeyAxis.data();
15854   QCPAxis *valueAxis = mValueAxis.data();
15855   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15856   
15857   double a, b; // positions of error bar bounds in pixels
15858   double barWidthHalf = mErrorBarSize*0.5;
15859   double skipSymbolMargin = mScatterStyle.size(); // pixels left blank per side, when mErrorBarSkipSymbol is true
15860
15861   if (keyAxis->orientation() == Qt::Vertical)
15862   {
15863     // draw key error vertically and value error horizontally
15864     if (mErrorType == etKey || mErrorType == etBoth)
15865     {
15866       a = keyAxis->coordToPixel(data.key-data.keyErrorMinus);
15867       b = keyAxis->coordToPixel(data.key+data.keyErrorPlus);
15868       if (keyAxis->rangeReversed())
15869         qSwap(a,b);
15870       // draw spine:
15871       if (mErrorBarSkipSymbol)
15872       {
15873         if (a-y > skipSymbolMargin) // don't draw spine if error is so small it's within skipSymbolmargin
15874           painter->drawLine(QLineF(x, a, x, y+skipSymbolMargin));
15875         if (y-b > skipSymbolMargin)
15876           painter->drawLine(QLineF(x, y-skipSymbolMargin, x, b));
15877       } else
15878         painter->drawLine(QLineF(x, a, x, b));
15879       // draw handles:
15880       painter->drawLine(QLineF(x-barWidthHalf, a, x+barWidthHalf, a));
15881       painter->drawLine(QLineF(x-barWidthHalf, b, x+barWidthHalf, b));
15882     }
15883     if (mErrorType == etValue || mErrorType == etBoth)
15884     {
15885       a = valueAxis->coordToPixel(data.value-data.valueErrorMinus);
15886       b = valueAxis->coordToPixel(data.value+data.valueErrorPlus);
15887       if (valueAxis->rangeReversed())
15888         qSwap(a,b);
15889       // draw spine:
15890       if (mErrorBarSkipSymbol)
15891       {
15892         if (x-a > skipSymbolMargin) // don't draw spine if error is so small it's within skipSymbolmargin
15893           painter->drawLine(QLineF(a, y, x-skipSymbolMargin, y));
15894         if (b-x > skipSymbolMargin)
15895           painter->drawLine(QLineF(x+skipSymbolMargin, y, b, y));
15896       } else
15897         painter->drawLine(QLineF(a, y, b, y));
15898       // draw handles:
15899       painter->drawLine(QLineF(a, y-barWidthHalf, a, y+barWidthHalf));
15900       painter->drawLine(QLineF(b, y-barWidthHalf, b, y+barWidthHalf));
15901     }
15902   } else // mKeyAxis->orientation() is Qt::Horizontal
15903   {
15904     // draw value error vertically and key error horizontally
15905     if (mErrorType == etKey || mErrorType == etBoth)
15906     {
15907       a = keyAxis->coordToPixel(data.key-data.keyErrorMinus);
15908       b = keyAxis->coordToPixel(data.key+data.keyErrorPlus);
15909       if (keyAxis->rangeReversed())
15910         qSwap(a,b);
15911       // draw spine:
15912       if (mErrorBarSkipSymbol)
15913       {
15914         if (x-a > skipSymbolMargin) // don't draw spine if error is so small it's within skipSymbolmargin
15915           painter->drawLine(QLineF(a, y, x-skipSymbolMargin, y));
15916         if (b-x > skipSymbolMargin)
15917           painter->drawLine(QLineF(x+skipSymbolMargin, y, b, y));
15918       } else
15919         painter->drawLine(QLineF(a, y, b, y));
15920       // draw handles:
15921       painter->drawLine(QLineF(a, y-barWidthHalf, a, y+barWidthHalf));
15922       painter->drawLine(QLineF(b, y-barWidthHalf, b, y+barWidthHalf));
15923     }
15924     if (mErrorType == etValue || mErrorType == etBoth)
15925     {
15926       a = valueAxis->coordToPixel(data.value-data.valueErrorMinus);
15927       b = valueAxis->coordToPixel(data.value+data.valueErrorPlus);
15928       if (valueAxis->rangeReversed())
15929         qSwap(a,b);
15930       // draw spine:
15931       if (mErrorBarSkipSymbol)
15932       {
15933         if (a-y > skipSymbolMargin) // don't draw spine if error is so small it's within skipSymbolmargin
15934           painter->drawLine(QLineF(x, a, x, y+skipSymbolMargin));
15935         if (y-b > skipSymbolMargin)
15936           painter->drawLine(QLineF(x, y-skipSymbolMargin, x, b));
15937       } else
15938         painter->drawLine(QLineF(x, a, x, b));
15939       // draw handles:
15940       painter->drawLine(QLineF(x-barWidthHalf, a, x+barWidthHalf, a));
15941       painter->drawLine(QLineF(x-barWidthHalf, b, x+barWidthHalf, b));
15942     }
15943   }
15944 }
15945
15946 /*!  \internal
15947   
15948   called by \ref getPreparedData to determine which data (key) range is visible at the current key
15949   axis range setting, so only that needs to be processed.
15950   
15951   \a lower returns an iterator to the lowest data point that needs to be taken into account when
15952   plotting. Note that in order to get a clean plot all the way to the edge of the axis rect, \a
15953   lower may still be just outside the visible range.
15954   
15955   \a upper returns an iterator to the highest data point. Same as before, \a upper may also lie
15956   just outside of the visible range.
15957   
15958   if the graph contains no data, both \a lower and \a upper point to constEnd.
15959 */
15960 void QCPGraph::getVisibleDataBounds(QCPDataMap::const_iterator &lower, QCPDataMap::const_iterator &upper) const
15961 {
15962   if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
15963   if (mData->isEmpty())
15964   {
15965     lower = mData->constEnd();
15966     upper = mData->constEnd();
15967     return;
15968   }
15969   
15970   // get visible data range as QMap iterators
15971   QCPDataMap::const_iterator lbound = mData->lowerBound(mKeyAxis.data()->range().lower);
15972   QCPDataMap::const_iterator ubound = mData->upperBound(mKeyAxis.data()->range().upper);
15973   bool lowoutlier = lbound != mData->constBegin(); // indicates whether there exist points below axis range
15974   bool highoutlier = ubound != mData->constEnd(); // indicates whether there exist points above axis range
15975   
15976   lower = (lowoutlier ? lbound-1 : lbound); // data point range that will be actually drawn
15977   upper = (highoutlier ? ubound : ubound-1); // data point range that will be actually drawn
15978 }
15979
15980 /*!  \internal
15981   
15982   Counts the number of data points between \a lower and \a upper (including them), up to a maximum
15983   of \a maxCount.
15984   
15985   This function is used by \ref getPreparedData to determine whether adaptive sampling shall be
15986   used (if enabled via \ref setAdaptiveSampling) or not. This is also why counting of data points
15987   only needs to be done until \a maxCount is reached, which should be set to the number of data
15988   points at which adaptive sampling sets in.
15989 */
15990 int QCPGraph::countDataInBounds(const QCPDataMap::const_iterator &lower, const QCPDataMap::const_iterator &upper, int maxCount) const
15991 {
15992   if (upper == mData->constEnd() && lower == mData->constEnd())
15993     return 0;
15994   QCPDataMap::const_iterator it = lower;
15995   int count = 1;
15996   while (it != upper && count < maxCount)
15997   {
15998     ++it;
15999     ++count;
16000   }
16001   return count;
16002 }
16003
16004 /*! \internal
16005   
16006   The line data vector generated by e.g. getLinePlotData contains only the line that connects the
16007   data points. If the graph needs to be filled, two additional points need to be added at the
16008   value-zero-line in the lower and upper key positions of the graph. This function calculates these
16009   points and adds them to the end of \a lineData. Since the fill is typically drawn before the line
16010   stroke, these added points need to be removed again after the fill is done, with the
16011   removeFillBasePoints function.
16012   
16013   The expanding of \a lineData by two points will not cause unnecessary memory reallocations,
16014   because the data vector generation functions (getLinePlotData etc.) reserve two extra points when
16015   they allocate memory for \a lineData.
16016   
16017   \see removeFillBasePoints, lowerFillBasePoint, upperFillBasePoint
16018 */
16019 void QCPGraph::addFillBasePoints(QVector<QPointF> *lineData) const
16020 {
16021   if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
16022   if (!lineData) { qDebug() << Q_FUNC_INFO << "passed null as lineData"; return; }
16023   if (lineData->isEmpty()) return;
16024   
16025   // append points that close the polygon fill at the key axis:
16026   if (mKeyAxis.data()->orientation() == Qt::Vertical)
16027   {
16028     *lineData << upperFillBasePoint(lineData->last().y());
16029     *lineData << lowerFillBasePoint(lineData->first().y());
16030   } else
16031   {
16032     *lineData << upperFillBasePoint(lineData->last().x());
16033     *lineData << lowerFillBasePoint(lineData->first().x());
16034   }
16035 }
16036
16037 /*! \internal
16038   
16039   removes the two points from \a lineData that were added by \ref addFillBasePoints.
16040   
16041   \see addFillBasePoints, lowerFillBasePoint, upperFillBasePoint
16042 */
16043 void QCPGraph::removeFillBasePoints(QVector<QPointF> *lineData) const
16044 {
16045   if (!lineData) { qDebug() << Q_FUNC_INFO << "passed null as lineData"; return; }
16046   if (lineData->isEmpty()) return;
16047   
16048   lineData->remove(lineData->size()-2, 2);
16049 }
16050
16051 /*! \internal
16052   
16053   called by \ref addFillBasePoints to conveniently assign the point which closes the fill polygon
16054   on the lower side of the zero-value-line parallel to the key axis. The logarithmic axis scale
16055   case is a bit special, since the zero-value-line in pixel coordinates is in positive or negative
16056   infinity. So this case is handled separately by just closing the fill polygon on the axis which
16057   lies in the direction towards the zero value.
16058   
16059   \a lowerKey will be the the key (in pixels) of the returned point. Depending on whether the key
16060   axis is horizontal or vertical, \a lowerKey will end up as the x or y value of the returned
16061   point, respectively.
16062   
16063   \see upperFillBasePoint, addFillBasePoints
16064 */
16065 QPointF QCPGraph::lowerFillBasePoint(double lowerKey) const
16066 {
16067   QCPAxis *keyAxis = mKeyAxis.data();
16068   QCPAxis *valueAxis = mValueAxis.data();
16069   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return QPointF(); }
16070   
16071   QPointF point;
16072   if (valueAxis->scaleType() == QCPAxis::stLinear)
16073   {
16074     if (keyAxis->axisType() == QCPAxis::atLeft)
16075     {
16076       point.setX(valueAxis->coordToPixel(0));
16077       point.setY(lowerKey);
16078     } else if (keyAxis->axisType() == QCPAxis::atRight)
16079     {
16080       point.setX(valueAxis->coordToPixel(0));
16081       point.setY(lowerKey);
16082     } else if (keyAxis->axisType() == QCPAxis::atTop)
16083     {
16084       point.setX(lowerKey);
16085       point.setY(valueAxis->coordToPixel(0));
16086     } else if (keyAxis->axisType() == QCPAxis::atBottom)
16087     {
16088       point.setX(lowerKey);
16089       point.setY(valueAxis->coordToPixel(0));
16090     }
16091   } else // valueAxis->mScaleType == QCPAxis::stLogarithmic
16092   {
16093     // In logarithmic scaling we can't just draw to value zero so we just fill all the way
16094     // to the axis which is in the direction towards zero
16095     if (keyAxis->orientation() == Qt::Vertical)
16096     {
16097       if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed()) ||
16098           (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is negative, zero is on opposite side of key axis
16099         point.setX(keyAxis->axisRect()->right());
16100       else
16101         point.setX(keyAxis->axisRect()->left());
16102       point.setY(lowerKey);
16103     } else if (keyAxis->axisType() == QCPAxis::atTop || keyAxis->axisType() == QCPAxis::atBottom)
16104     {
16105       point.setX(lowerKey);
16106       if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed()) ||
16107           (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is negative, zero is on opposite side of key axis
16108         point.setY(keyAxis->axisRect()->top());
16109       else
16110         point.setY(keyAxis->axisRect()->bottom());
16111     }
16112   }
16113   return point;
16114 }
16115
16116 /*! \internal
16117   
16118   called by \ref addFillBasePoints to conveniently assign the point which closes the fill
16119   polygon on the upper side of the zero-value-line parallel to the key axis. The logarithmic axis
16120   scale case is a bit special, since the zero-value-line in pixel coordinates is in positive or
16121   negative infinity. So this case is handled separately by just closing the fill polygon on the
16122   axis which lies in the direction towards the zero value.
16123
16124   \a upperKey will be the the key (in pixels) of the returned point. Depending on whether the key
16125   axis is horizontal or vertical, \a upperKey will end up as the x or y value of the returned
16126   point, respectively.
16127   
16128   \see lowerFillBasePoint, addFillBasePoints
16129 */
16130 QPointF QCPGraph::upperFillBasePoint(double upperKey) const
16131 {
16132   QCPAxis *keyAxis = mKeyAxis.data();
16133   QCPAxis *valueAxis = mValueAxis.data();
16134   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return QPointF(); }
16135   
16136   QPointF point;
16137   if (valueAxis->scaleType() == QCPAxis::stLinear)
16138   {
16139     if (keyAxis->axisType() == QCPAxis::atLeft)
16140     {
16141       point.setX(valueAxis->coordToPixel(0));
16142       point.setY(upperKey);
16143     } else if (keyAxis->axisType() == QCPAxis::atRight)
16144     {
16145       point.setX(valueAxis->coordToPixel(0));
16146       point.setY(upperKey);
16147     } else if (keyAxis->axisType() == QCPAxis::atTop)
16148     {
16149       point.setX(upperKey);
16150       point.setY(valueAxis->coordToPixel(0));
16151     } else if (keyAxis->axisType() == QCPAxis::atBottom)
16152     {
16153       point.setX(upperKey);
16154       point.setY(valueAxis->coordToPixel(0));
16155     }
16156   } else // valueAxis->mScaleType == QCPAxis::stLogarithmic
16157   {
16158     // In logarithmic scaling we can't just draw to value 0 so we just fill all the way
16159     // to the axis which is in the direction towards 0
16160     if (keyAxis->orientation() == Qt::Vertical)
16161     {
16162       if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed()) ||
16163           (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is negative, zero is on opposite side of key axis
16164         point.setX(keyAxis->axisRect()->right());
16165       else
16166         point.setX(keyAxis->axisRect()->left());
16167       point.setY(upperKey);
16168     } else if (keyAxis->axisType() == QCPAxis::atTop || keyAxis->axisType() == QCPAxis::atBottom)
16169     {
16170       point.setX(upperKey);
16171       if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed()) ||
16172           (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is negative, zero is on opposite side of key axis
16173         point.setY(keyAxis->axisRect()->top());
16174       else
16175         point.setY(keyAxis->axisRect()->bottom());
16176     }
16177   }
16178   return point;
16179 }
16180
16181 /*! \internal
16182   
16183   Generates the polygon needed for drawing channel fills between this graph (data passed via \a
16184   lineData) and the graph specified by mChannelFillGraph (data generated by calling its \ref
16185   getPlotData function). May return an empty polygon if the key ranges have no overlap or fill
16186   target graph and this graph don't have same orientation (i.e. both key axes horizontal or both
16187   key axes vertical). For increased performance (due to implicit sharing), keep the returned
16188   QPolygonF const.
16189 */
16190 const QPolygonF QCPGraph::getChannelFillPolygon(const QVector<QPointF> *lineData) const
16191 {
16192   if (!mChannelFillGraph)
16193     return QPolygonF();
16194   
16195   QCPAxis *keyAxis = mKeyAxis.data();
16196   QCPAxis *valueAxis = mValueAxis.data();
16197   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return QPolygonF(); }
16198   if (!mChannelFillGraph.data()->mKeyAxis) { qDebug() << Q_FUNC_INFO << "channel fill target key axis invalid"; return QPolygonF(); }
16199   
16200   if (mChannelFillGraph.data()->mKeyAxis.data()->orientation() != keyAxis->orientation())
16201     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)
16202   
16203   if (lineData->isEmpty()) return QPolygonF();
16204   QVector<QPointF> otherData;
16205   mChannelFillGraph.data()->getPlotData(&otherData, 0);
16206   if (otherData.isEmpty()) return QPolygonF();
16207   QVector<QPointF> thisData;
16208   thisData.reserve(lineData->size()+otherData.size()); // because we will join both vectors at end of this function
16209   for (int i=0; i<lineData->size(); ++i) // don't use the vector<<(vector),  it squeezes internally, which ruins the performance tuning with reserve()
16210     thisData << lineData->at(i);
16211   
16212   // pointers to be able to swap them, depending which data range needs cropping:
16213   QVector<QPointF> *staticData = &thisData;
16214   QVector<QPointF> *croppedData = &otherData;
16215   
16216   // crop both vectors to ranges in which the keys overlap (which coord is key, depends on axisType):
16217   if (keyAxis->orientation() == Qt::Horizontal)
16218   {
16219     // x is key
16220     // if an axis range is reversed, the data point keys will be descending. Reverse them, since following algorithm assumes ascending keys:
16221     if (staticData->first().x() > staticData->last().x())
16222     {
16223       int size = staticData->size();
16224       for (int i=0; i<size/2; ++i)
16225         qSwap((*staticData)[i], (*staticData)[size-1-i]);
16226     }
16227     if (croppedData->first().x() > croppedData->last().x())
16228     {
16229       int size = croppedData->size();
16230       for (int i=0; i<size/2; ++i)
16231         qSwap((*croppedData)[i], (*croppedData)[size-1-i]);
16232     }
16233     // crop lower bound:
16234     if (staticData->first().x() < croppedData->first().x()) // other one must be cropped
16235       qSwap(staticData, croppedData);
16236     int lowBound = findIndexBelowX(croppedData, staticData->first().x());
16237     if (lowBound == -1) return QPolygonF(); // key ranges have no overlap
16238     croppedData->remove(0, lowBound);
16239     // set lowest point of cropped data to fit exactly key position of first static data
16240     // point via linear interpolation:
16241     if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation
16242     double slope;
16243     if (croppedData->at(1).x()-croppedData->at(0).x() != 0)
16244       slope = (croppedData->at(1).y()-croppedData->at(0).y())/(croppedData->at(1).x()-croppedData->at(0).x());
16245     else
16246       slope = 0;
16247     (*croppedData)[0].setY(croppedData->at(0).y()+slope*(staticData->first().x()-croppedData->at(0).x()));
16248     (*croppedData)[0].setX(staticData->first().x());
16249     
16250     // crop upper bound:
16251     if (staticData->last().x() > croppedData->last().x()) // other one must be cropped
16252       qSwap(staticData, croppedData);
16253     int highBound = findIndexAboveX(croppedData, staticData->last().x());
16254     if (highBound == -1) return QPolygonF(); // key ranges have no overlap
16255     croppedData->remove(highBound+1, croppedData->size()-(highBound+1));
16256     // set highest point of cropped data to fit exactly key position of last static data
16257     // point via linear interpolation:
16258     if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation
16259     int li = croppedData->size()-1; // last index
16260     if (croppedData->at(li).x()-croppedData->at(li-1).x() != 0)
16261       slope = (croppedData->at(li).y()-croppedData->at(li-1).y())/(croppedData->at(li).x()-croppedData->at(li-1).x());
16262     else
16263       slope = 0;
16264     (*croppedData)[li].setY(croppedData->at(li-1).y()+slope*(staticData->last().x()-croppedData->at(li-1).x()));
16265     (*croppedData)[li].setX(staticData->last().x());
16266   } else // mKeyAxis->orientation() == Qt::Vertical
16267   {
16268     // y is key
16269     // similar to "x is key" but switched x,y. Further, lower/upper meaning is inverted compared to x,
16270     // because in pixel coordinates, y increases from top to bottom, not bottom to top like data coordinate.
16271     // if an axis range is reversed, the data point keys will be descending. Reverse them, since following algorithm assumes ascending keys:
16272     if (staticData->first().y() < staticData->last().y())
16273     {
16274       int size = staticData->size();
16275       for (int i=0; i<size/2; ++i)
16276         qSwap((*staticData)[i], (*staticData)[size-1-i]);
16277     }
16278     if (croppedData->first().y() < croppedData->last().y())
16279     {
16280       int size = croppedData->size();
16281       for (int i=0; i<size/2; ++i)
16282         qSwap((*croppedData)[i], (*croppedData)[size-1-i]);
16283     }
16284     // crop lower bound:
16285     if (staticData->first().y() > croppedData->first().y()) // other one must be cropped
16286       qSwap(staticData, croppedData);
16287     int lowBound = findIndexAboveY(croppedData, staticData->first().y());
16288     if (lowBound == -1) return QPolygonF(); // key ranges have no overlap
16289     croppedData->remove(0, lowBound);
16290     // set lowest point of cropped data to fit exactly key position of first static data
16291     // point via linear interpolation:
16292     if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation
16293     double slope;
16294     if (croppedData->at(1).y()-croppedData->at(0).y() != 0) // avoid division by zero in step plots
16295       slope = (croppedData->at(1).x()-croppedData->at(0).x())/(croppedData->at(1).y()-croppedData->at(0).y());
16296     else
16297       slope = 0;
16298     (*croppedData)[0].setX(croppedData->at(0).x()+slope*(staticData->first().y()-croppedData->at(0).y()));
16299     (*croppedData)[0].setY(staticData->first().y());
16300     
16301     // crop upper bound:
16302     if (staticData->last().y() < croppedData->last().y()) // other one must be cropped
16303       qSwap(staticData, croppedData);
16304     int highBound = findIndexBelowY(croppedData, staticData->last().y());
16305     if (highBound == -1) return QPolygonF(); // key ranges have no overlap
16306     croppedData->remove(highBound+1, croppedData->size()-(highBound+1));
16307     // set highest point of cropped data to fit exactly key position of last static data
16308     // point via linear interpolation:
16309     if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation
16310     int li = croppedData->size()-1; // last index
16311     if (croppedData->at(li).y()-croppedData->at(li-1).y() != 0) // avoid division by zero in step plots
16312       slope = (croppedData->at(li).x()-croppedData->at(li-1).x())/(croppedData->at(li).y()-croppedData->at(li-1).y());
16313     else
16314       slope = 0;
16315     (*croppedData)[li].setX(croppedData->at(li-1).x()+slope*(staticData->last().y()-croppedData->at(li-1).y()));
16316     (*croppedData)[li].setY(staticData->last().y());
16317   }
16318   
16319   // return joined:
16320   for (int i=otherData.size()-1; i>=0; --i) // insert reversed, otherwise the polygon will be twisted
16321     thisData << otherData.at(i);
16322   return QPolygonF(thisData);
16323 }
16324
16325 /*! \internal
16326   
16327   Finds the smallest index of \a data, whose points x value is just above \a x. Assumes x values in
16328   \a data points are ordered ascending, as is the case when plotting with horizontal key axis.
16329
16330   Used to calculate the channel fill polygon, see \ref getChannelFillPolygon.
16331 */
16332 int QCPGraph::findIndexAboveX(const QVector<QPointF> *data, double x) const
16333 {
16334   for (int i=data->size()-1; i>=0; --i)
16335   {
16336     if (data->at(i).x() < x)
16337     {
16338       if (i<data->size()-1)
16339         return i+1;
16340       else
16341         return data->size()-1;
16342     }
16343   }
16344   return -1;
16345 }
16346
16347 /*! \internal
16348   
16349   Finds the highest index of \a data, whose points x value is just below \a x. Assumes x values in
16350   \a data points are ordered ascending, as is the case when plotting with horizontal key axis.
16351   
16352   Used to calculate the channel fill polygon, see \ref getChannelFillPolygon.
16353 */
16354 int QCPGraph::findIndexBelowX(const QVector<QPointF> *data, double x) const
16355 {
16356   for (int i=0; i<data->size(); ++i)
16357   {
16358     if (data->at(i).x() > x)
16359     {
16360       if (i>0)
16361         return i-1;
16362       else
16363         return 0;
16364     }
16365   }
16366   return -1;
16367 }
16368
16369 /*! \internal
16370   
16371   Finds the smallest index of \a data, whose points y value is just above \a y. Assumes y values in
16372   \a data points are ordered descending, as is the case when plotting with vertical key axis.
16373   
16374   Used to calculate the channel fill polygon, see \ref getChannelFillPolygon.
16375 */
16376 int QCPGraph::findIndexAboveY(const QVector<QPointF> *data, double y) const
16377 {
16378   for (int i=0; i<data->size(); ++i)
16379   {
16380     if (data->at(i).y() < y)
16381     {
16382       if (i>0)
16383         return i-1;
16384       else
16385         return 0;
16386     }
16387   }
16388   return -1;
16389 }
16390
16391 /*! \internal
16392   
16393   Calculates the (minimum) distance (in pixels) the graph's representation has from the given \a
16394   pixelPoint in pixels. This is used to determine whether the graph was clicked or not, e.g. in
16395   \ref selectTest.
16396   
16397   If either the graph has no data or if the line style is \ref lsNone and the scatter style's shape
16398   is \ref QCPScatterStyle::ssNone (i.e. there is no visual representation of the graph), returns -1.0.
16399 */
16400 double QCPGraph::pointDistance(const QPointF &pixelPoint) const
16401 {
16402   if (mData->isEmpty())
16403     return -1.0;
16404   if (mLineStyle == lsNone && mScatterStyle.isNone())
16405     return -1.0;
16406   
16407   // calculate minimum distances to graph representation:
16408   if (mLineStyle == lsNone)
16409   {
16410     // no line displayed, only calculate distance to scatter points:
16411     QVector<QCPData> scatterData;
16412     getScatterPlotData(&scatterData);
16413     if (scatterData.size() > 0)
16414     {
16415       double minDistSqr = std::numeric_limits<double>::max();
16416       for (int i=0; i<scatterData.size(); ++i)
16417       {
16418         double currentDistSqr = QVector2D(coordsToPixels(scatterData.at(i).key, scatterData.at(i).value)-pixelPoint).lengthSquared();
16419         if (currentDistSqr < minDistSqr)
16420           minDistSqr = currentDistSqr;
16421       }
16422       return qSqrt(minDistSqr);
16423     } else // no data available in view to calculate distance to
16424       return -1.0;
16425   } else
16426   {
16427     // line displayed, calculate distance to line segments:
16428     QVector<QPointF> lineData;
16429     getPlotData(&lineData, 0); // unlike with getScatterPlotData we get pixel coordinates here
16430     if (lineData.size() > 1) // at least one line segment, compare distance to line segments
16431     {
16432       double minDistSqr = std::numeric_limits<double>::max();
16433       if (mLineStyle == lsImpulse)
16434       {
16435         // impulse plot differs from other line styles in that the lineData points are only pairwise connected:
16436         for (int i=0; i<lineData.size()-1; i+=2) // iterate pairs
16437         {
16438           double currentDistSqr = distSqrToLine(lineData.at(i), lineData.at(i+1), pixelPoint);
16439           if (currentDistSqr < minDistSqr)
16440             minDistSqr = currentDistSqr;
16441         }
16442       } else
16443       {
16444         // all other line plots (line and step) connect points directly:
16445         for (int i=0; i<lineData.size()-1; ++i)
16446         {
16447           double currentDistSqr = distSqrToLine(lineData.at(i), lineData.at(i+1), pixelPoint);
16448           if (currentDistSqr < minDistSqr)
16449             minDistSqr = currentDistSqr;
16450         }
16451       }
16452       return qSqrt(minDistSqr);
16453     } else if (lineData.size() > 0) // only single data point, calculate distance to that point
16454     {
16455       return QVector2D(lineData.at(0)-pixelPoint).length();
16456     } else // no data available in view to calculate distance to
16457       return -1.0;
16458   }
16459 }
16460
16461 /*! \internal
16462   
16463   Finds the highest index of \a data, whose points y value is just below \a y. Assumes y values in
16464   \a data points are ordered descending, as is the case when plotting with vertical key axis (since
16465   keys are ordered ascending).
16466
16467   Used to calculate the channel fill polygon, see \ref getChannelFillPolygon.
16468 */
16469 int QCPGraph::findIndexBelowY(const QVector<QPointF> *data, double y) const
16470 {
16471   for (int i=data->size()-1; i>=0; --i)
16472   {
16473     if (data->at(i).y() > y)
16474     {
16475       if (i<data->size()-1)
16476         return i+1;
16477       else
16478         return data->size()-1;
16479     }
16480   }
16481   return -1;
16482 }
16483
16484 /* inherits documentation from base class */
16485 QCPRange QCPGraph::getKeyRange(bool &foundRange, SignDomain inSignDomain) const
16486 {
16487   // just call the specialized version which takes an additional argument whether error bars
16488   // should also be taken into consideration for range calculation. We set this to true here.
16489   return getKeyRange(foundRange, inSignDomain, true);
16490 }
16491
16492 /* inherits documentation from base class */
16493 QCPRange QCPGraph::getValueRange(bool &foundRange, SignDomain inSignDomain) const
16494 {
16495   // just call the specialized version which takes an additional argument whether error bars
16496   // should also be taken into consideration for range calculation. We set this to true here.
16497   return getValueRange(foundRange, inSignDomain, true);
16498 }
16499
16500 /*! \overload
16501   
16502   Allows to specify whether the error bars should be included in the range calculation.
16503   
16504   \see getKeyRange(bool &foundRange, SignDomain inSignDomain)
16505 */
16506 QCPRange QCPGraph::getKeyRange(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const
16507 {
16508   QCPRange range;
16509   bool haveLower = false;
16510   bool haveUpper = false;
16511   
16512   double current, currentErrorMinus, currentErrorPlus;
16513   
16514   if (inSignDomain == sdBoth) // range may be anywhere
16515   {
16516     QCPDataMap::const_iterator it = mData->constBegin();
16517     while (it != mData->constEnd())
16518     {
16519       if (!qIsNaN(it.value().value))
16520       {
16521         current = it.value().key;
16522         currentErrorMinus = (includeErrors ? it.value().keyErrorMinus : 0);
16523         currentErrorPlus = (includeErrors ? it.value().keyErrorPlus : 0);
16524         if (current-currentErrorMinus < range.lower || !haveLower)
16525         {
16526           range.lower = current-currentErrorMinus;
16527           haveLower = true;
16528         }
16529         if (current+currentErrorPlus > range.upper || !haveUpper)
16530         {
16531           range.upper = current+currentErrorPlus;
16532           haveUpper = true;
16533         }
16534       }
16535       ++it;
16536     }
16537   } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain
16538   {
16539     QCPDataMap::const_iterator it = mData->constBegin();
16540     while (it != mData->constEnd())
16541     {
16542       if (!qIsNaN(it.value().value))
16543       {
16544         current = it.value().key;
16545         currentErrorMinus = (includeErrors ? it.value().keyErrorMinus : 0);
16546         currentErrorPlus = (includeErrors ? it.value().keyErrorPlus : 0);
16547         if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0)
16548         {
16549           range.lower = current-currentErrorMinus;
16550           haveLower = true;
16551         }
16552         if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0)
16553         {
16554           range.upper = current+currentErrorPlus;
16555           haveUpper = true;
16556         }
16557         if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point.
16558         {
16559           if ((current < range.lower || !haveLower) && current < 0)
16560           {
16561             range.lower = current;
16562             haveLower = true;
16563           }
16564           if ((current > range.upper || !haveUpper) && current < 0)
16565           {
16566             range.upper = current;
16567             haveUpper = true;
16568           }
16569         }
16570       }
16571       ++it;
16572     }
16573   } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain
16574   {
16575     QCPDataMap::const_iterator it = mData->constBegin();
16576     while (it != mData->constEnd())
16577     {
16578       if (!qIsNaN(it.value().value))
16579       {
16580         current = it.value().key;
16581         currentErrorMinus = (includeErrors ? it.value().keyErrorMinus : 0);
16582         currentErrorPlus = (includeErrors ? it.value().keyErrorPlus : 0);
16583         if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0)
16584         {
16585           range.lower = current-currentErrorMinus;
16586           haveLower = true;
16587         }
16588         if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0)
16589         {
16590           range.upper = current+currentErrorPlus;
16591           haveUpper = true;
16592         }
16593         if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point.
16594         {
16595           if ((current < range.lower || !haveLower) && current > 0)
16596           {
16597             range.lower = current;
16598             haveLower = true;
16599           }
16600           if ((current > range.upper || !haveUpper) && current > 0)
16601           {
16602             range.upper = current;
16603             haveUpper = true;
16604           }
16605         }
16606       }
16607       ++it;
16608     }
16609   }
16610   
16611   foundRange = haveLower && haveUpper;
16612   return range;
16613 }
16614
16615 /*! \overload
16616   
16617   Allows to specify whether the error bars should be included in the range calculation.
16618   
16619   \see getValueRange(bool &foundRange, SignDomain inSignDomain)
16620 */
16621 QCPRange QCPGraph::getValueRange(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const
16622 {
16623   QCPRange range;
16624   bool haveLower = false;
16625   bool haveUpper = false;
16626   
16627   double current, currentErrorMinus, currentErrorPlus;
16628   
16629   if (inSignDomain == sdBoth) // range may be anywhere
16630   {
16631     QCPDataMap::const_iterator it = mData->constBegin();
16632     while (it != mData->constEnd())
16633     {
16634       current = it.value().value;
16635       if (!qIsNaN(current))
16636       {
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       }
16650       ++it;
16651     }
16652   } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain
16653   {
16654     QCPDataMap::const_iterator it = mData->constBegin();
16655     while (it != mData->constEnd())
16656     {
16657       current = it.value().value;
16658       if (!qIsNaN(current))
16659       {
16660         currentErrorMinus = (includeErrors ? it.value().valueErrorMinus : 0);
16661         currentErrorPlus = (includeErrors ? it.value().valueErrorPlus : 0);
16662         if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0)
16663         {
16664           range.lower = current-currentErrorMinus;
16665           haveLower = true;
16666         }
16667         if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0)
16668         {
16669           range.upper = current+currentErrorPlus;
16670           haveUpper = true;
16671         }
16672         if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point.
16673         {
16674           if ((current < range.lower || !haveLower) && current < 0)
16675           {
16676             range.lower = current;
16677             haveLower = true;
16678           }
16679           if ((current > range.upper || !haveUpper) && current < 0)
16680           {
16681             range.upper = current;
16682             haveUpper = true;
16683           }
16684         }
16685       }
16686       ++it;
16687     }
16688   } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain
16689   {
16690     QCPDataMap::const_iterator it = mData->constBegin();
16691     while (it != mData->constEnd())
16692     {
16693       current = it.value().value;
16694       if (!qIsNaN(current))
16695       {
16696         currentErrorMinus = (includeErrors ? it.value().valueErrorMinus : 0);
16697         currentErrorPlus = (includeErrors ? it.value().valueErrorPlus : 0);
16698         if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0)
16699         {
16700           range.lower = current-currentErrorMinus;
16701           haveLower = true;
16702         }
16703         if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0)
16704         {
16705           range.upper = current+currentErrorPlus;
16706           haveUpper = true;
16707         }
16708         if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point.
16709         {
16710           if ((current < range.lower || !haveLower) && current > 0)
16711           {
16712             range.lower = current;
16713             haveLower = true;
16714           }
16715           if ((current > range.upper || !haveUpper) && current > 0)
16716           {
16717             range.upper = current;
16718             haveUpper = true;
16719           }
16720         }
16721       }
16722       ++it;
16723     }
16724   }
16725   
16726   foundRange = haveLower && haveUpper;
16727   return range;
16728 }
16729
16730
16731 ////////////////////////////////////////////////////////////////////////////////////////////////////
16732 //////////////////// QCPCurveData
16733 ////////////////////////////////////////////////////////////////////////////////////////////////////
16734
16735 /*! \class QCPCurveData
16736   \brief Holds the data of one single data point for QCPCurve.
16737   
16738   The container for storing multiple data points is \ref QCPCurveDataMap.
16739   
16740   The stored data is:
16741   \li \a t: the free parameter of the curve at this curve point (cp. the mathematical vector <em>(x(t), y(t))</em>)
16742   \li \a key: coordinate on the key axis of this curve point
16743   \li \a value: coordinate on the value axis of this curve point
16744   
16745   \see QCPCurveDataMap
16746 */
16747
16748 /*!
16749   Constructs a curve data point with t, key and value set to zero.
16750 */
16751 QCPCurveData::QCPCurveData() :
16752   t(0),
16753   key(0),
16754   value(0)
16755 {
16756 }
16757
16758 /*!
16759   Constructs a curve data point with the specified \a t, \a key and \a value.
16760 */
16761 QCPCurveData::QCPCurveData(double t, double key, double value) :
16762   t(t),
16763   key(key),
16764   value(value)
16765 {
16766 }
16767
16768
16769 ////////////////////////////////////////////////////////////////////////////////////////////////////
16770 //////////////////// QCPCurve
16771 ////////////////////////////////////////////////////////////////////////////////////////////////////
16772
16773 /*! \class QCPCurve
16774   \brief A plottable representing a parametric curve in a plot.
16775   
16776   \image html QCPCurve.png
16777   
16778   Unlike QCPGraph, plottables of this type may have multiple points with the same key coordinate,
16779   so their visual representation can have \a loops. This is realized by introducing a third
16780   coordinate \a t, which defines the order of the points described by the other two coordinates \a
16781   x and \a y.
16782
16783   To plot data, assign it with the \ref setData or \ref addData functions.
16784   
16785   Gaps in the curve can be created by adding data points with NaN as key and value
16786   (<tt>qQNaN()</tt> or <tt>std::numeric_limits<double>::quiet_NaN()</tt>) in between the two data points that shall be
16787   separated.
16788   
16789   \section appearance Changing the appearance
16790   
16791   The appearance of the curve is determined by the pen and the brush (\ref setPen, \ref setBrush).
16792   \section usage Usage
16793   
16794   Like all data representing objects in QCustomPlot, the QCPCurve is a plottable (QCPAbstractPlottable). So
16795   the plottable-interface of QCustomPlot applies (QCustomPlot::plottable, QCustomPlot::addPlottable, QCustomPlot::removePlottable, etc.)
16796   
16797   Usually, you first create an instance and add it to the customPlot:
16798   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpcurve-creation-1
16799   and then modify the properties of the newly created plottable, e.g.:
16800   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpcurve-creation-2
16801 */
16802
16803 /*!
16804   Constructs a curve which uses \a keyAxis as its key axis ("x") and \a valueAxis as its value
16805   axis ("y"). \a keyAxis and \a valueAxis must reside in the same QCustomPlot instance and not have
16806   the same orientation. If either of these restrictions is violated, a corresponding message is
16807   printed to the debug output (qDebug), the construction is not aborted, though.
16808   
16809   The constructed QCPCurve can be added to the plot with QCustomPlot::addPlottable, QCustomPlot
16810   then takes ownership of the graph.
16811 */
16812 QCPCurve::QCPCurve(QCPAxis *keyAxis, QCPAxis *valueAxis) :
16813   QCPAbstractPlottable(keyAxis, valueAxis)
16814 {
16815   mData = new QCPCurveDataMap;
16816   mPen.setColor(Qt::blue);
16817   mPen.setStyle(Qt::SolidLine);
16818   mBrush.setColor(Qt::blue);
16819   mBrush.setStyle(Qt::NoBrush);
16820   mSelectedPen = mPen;
16821   mSelectedPen.setWidthF(2.5);
16822   mSelectedPen.setColor(QColor(80, 80, 255)); // lighter than Qt::blue of mPen
16823   mSelectedBrush = mBrush;
16824   
16825   setScatterStyle(QCPScatterStyle());
16826   setLineStyle(lsLine);
16827 }
16828
16829 QCPCurve::~QCPCurve()
16830 {
16831   delete mData;
16832 }
16833
16834 /*!
16835   Replaces the current data with the provided \a data.
16836   
16837   If \a copy is set to true, data points in \a data will only be copied. if false, the plottable
16838   takes ownership of the passed data and replaces the internal data pointer with it. This is
16839   significantly faster than copying for large datasets.
16840 */
16841 void QCPCurve::setData(QCPCurveDataMap *data, bool copy)
16842 {
16843   if (mData == data)
16844   {
16845     qDebug() << Q_FUNC_INFO << "The data pointer is already in (and owned by) this plottable" << reinterpret_cast<quintptr>(data);
16846     return;
16847   }
16848   if (copy)
16849   {
16850     *mData = *data;
16851   } else
16852   {
16853     delete mData;
16854     mData = data;
16855   }
16856 }
16857
16858 /*! \overload
16859   
16860   Replaces the current data with the provided points in \a t, \a key and \a value tuples. The
16861   provided vectors should have equal length. Else, the number of added points will be the size of
16862   the smallest vector.
16863 */
16864 void QCPCurve::setData(const QVector<double> &t, const QVector<double> &key, const QVector<double> &value)
16865 {
16866   mData->clear();
16867   int n = t.size();
16868   n = qMin(n, key.size());
16869   n = qMin(n, value.size());
16870   QCPCurveData newData;
16871   for (int i=0; i<n; ++i)
16872   {
16873     newData.t = t[i];
16874     newData.key = key[i];
16875     newData.value = value[i];
16876     mData->insertMulti(newData.t, newData);
16877   }
16878 }
16879
16880 /*! \overload
16881   
16882   Replaces the current data with the provided \a key and \a value pairs. The t parameter
16883   of each data point will be set to the integer index of the respective key/value pair.
16884 */
16885 void QCPCurve::setData(const QVector<double> &key, const QVector<double> &value)
16886 {
16887   mData->clear();
16888   int n = key.size();
16889   n = qMin(n, value.size());
16890   QCPCurveData newData;
16891   for (int i=0; i<n; ++i)
16892   {
16893     newData.t = i; // no t vector given, so we assign t the index of the key/value pair
16894     newData.key = key[i];
16895     newData.value = value[i];
16896     mData->insertMulti(newData.t, newData);
16897   }
16898 }
16899
16900 /*!
16901   Sets the visual appearance of single data points in the plot. If set to \ref
16902   QCPScatterStyle::ssNone, no scatter points are drawn (e.g. for line-only plots with appropriate
16903   line style).
16904   
16905   \see QCPScatterStyle, setLineStyle
16906 */
16907 void QCPCurve::setScatterStyle(const QCPScatterStyle &style)
16908 {
16909   mScatterStyle = style;
16910 }
16911
16912 /*!
16913   Sets how the single data points are connected in the plot or how they are represented visually
16914   apart from the scatter symbol. For scatter-only plots, set \a style to \ref lsNone and \ref
16915   setScatterStyle to the desired scatter style.
16916   
16917   \see setScatterStyle
16918 */
16919 void QCPCurve::setLineStyle(QCPCurve::LineStyle style)
16920 {
16921   mLineStyle = style;
16922 }
16923
16924 /*!
16925   Adds the provided data points in \a dataMap to the current data.
16926   \see removeData
16927 */
16928 void QCPCurve::addData(const QCPCurveDataMap &dataMap)
16929 {
16930   mData->unite(dataMap);
16931 }
16932
16933 /*! \overload
16934   Adds the provided single data point in \a data to the current data.
16935   \see removeData
16936 */
16937 void QCPCurve::addData(const QCPCurveData &data)
16938 {
16939   mData->insertMulti(data.t, data);
16940 }
16941
16942 /*! \overload
16943   Adds the provided single data point as \a t, \a key and \a value tuple to the current data
16944   \see removeData
16945 */
16946 void QCPCurve::addData(double t, double key, double value)
16947 {
16948   QCPCurveData newData;
16949   newData.t = t;
16950   newData.key = key;
16951   newData.value = value;
16952   mData->insertMulti(newData.t, newData);
16953 }
16954
16955 /*! \overload
16956   
16957   Adds the provided single data point as \a key and \a value pair to the current data The t
16958   parameter of the data point is set to the t of the last data point plus 1. If there is no last
16959   data point, t will be set to 0.
16960   
16961   \see removeData
16962 */
16963 void QCPCurve::addData(double key, double value)
16964 {
16965   QCPCurveData newData;
16966   if (!mData->isEmpty())
16967     newData.t = (mData->constEnd()-1).key()+1;
16968   else
16969     newData.t = 0;
16970   newData.key = key;
16971   newData.value = value;
16972   mData->insertMulti(newData.t, newData);
16973 }
16974
16975 /*! \overload
16976   Adds the provided data points as \a t, \a key and \a value tuples to the current data.
16977   \see removeData
16978 */
16979 void QCPCurve::addData(const QVector<double> &ts, const QVector<double> &keys, const QVector<double> &values)
16980 {
16981   int n = ts.size();
16982   n = qMin(n, keys.size());
16983   n = qMin(n, values.size());
16984   QCPCurveData newData;
16985   for (int i=0; i<n; ++i)
16986   {
16987     newData.t = ts[i];
16988     newData.key = keys[i];
16989     newData.value = values[i];
16990     mData->insertMulti(newData.t, newData);
16991   }
16992 }
16993
16994 /*!
16995   Removes all data points with curve parameter t smaller than \a t.
16996   \see addData, clearData
16997 */
16998 void QCPCurve::removeDataBefore(double t)
16999 {
17000   QCPCurveDataMap::iterator it = mData->begin();
17001   while (it != mData->end() && it.key() < t)
17002     it = mData->erase(it);
17003 }
17004
17005 /*!
17006   Removes all data points with curve parameter t greater than \a t.
17007   \see addData, clearData
17008 */
17009 void QCPCurve::removeDataAfter(double t)
17010 {
17011   if (mData->isEmpty()) return;
17012   QCPCurveDataMap::iterator it = mData->upperBound(t);
17013   while (it != mData->end())
17014     it = mData->erase(it);
17015 }
17016
17017 /*!
17018   Removes all data points with curve parameter t between \a fromt and \a tot. if \a fromt is
17019   greater or equal to \a tot, the function does nothing. To remove a single data point with known
17020   t, use \ref removeData(double t).
17021   
17022   \see addData, clearData
17023 */
17024 void QCPCurve::removeData(double fromt, double tot)
17025 {
17026   if (fromt >= tot || mData->isEmpty()) return;
17027   QCPCurveDataMap::iterator it = mData->upperBound(fromt);
17028   QCPCurveDataMap::iterator itEnd = mData->upperBound(tot);
17029   while (it != itEnd)
17030     it = mData->erase(it);
17031 }
17032
17033 /*! \overload
17034   
17035   Removes a single data point at curve parameter \a t. If the position is not known with absolute
17036   precision, consider using \ref removeData(double fromt, double tot) with a small fuzziness
17037   interval around the suspected position, depeding on the precision with which the curve parameter
17038   is known.
17039   
17040   \see addData, clearData
17041 */
17042 void QCPCurve::removeData(double t)
17043 {
17044   mData->remove(t);
17045 }
17046
17047 /*!
17048   Removes all data points.
17049   \see removeData, removeDataAfter, removeDataBefore
17050 */
17051 void QCPCurve::clearData()
17052 {
17053   mData->clear();
17054 }
17055
17056 /* inherits documentation from base class */
17057 double QCPCurve::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
17058 {
17059   Q_UNUSED(details)
17060   if ((onlySelectable && !mSelectable) || mData->isEmpty())
17061     return -1;
17062   if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
17063   
17064   if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()))
17065     return pointDistance(pos);
17066   else
17067     return -1;
17068 }
17069
17070 /* inherits documentation from base class */
17071 void QCPCurve::draw(QCPPainter *painter)
17072 {
17073   if (mData->isEmpty()) return;
17074   
17075   // allocate line vector:
17076   QVector<QPointF> *lineData = new QVector<QPointF>;
17077   
17078   // fill with curve data:
17079   getCurveData(lineData);
17080   
17081   // check data validity if flag set:
17082 #ifdef QCUSTOMPLOT_CHECK_DATA
17083   QCPCurveDataMap::const_iterator it;
17084   for (it = mData->constBegin(); it != mData->constEnd(); ++it)
17085   {
17086     if (QCP::isInvalidData(it.value().t) ||
17087         QCP::isInvalidData(it.value().key, it.value().value))
17088       qDebug() << Q_FUNC_INFO << "Data point at" << it.key() << "invalid." << "Plottable name:" << name();
17089   }
17090 #endif
17091   
17092   // draw curve fill:
17093   if (mainBrush().style() != Qt::NoBrush && mainBrush().color().alpha() != 0)
17094   {
17095     applyFillAntialiasingHint(painter);
17096     painter->setPen(Qt::NoPen);
17097     painter->setBrush(mainBrush());
17098     painter->drawPolygon(QPolygonF(*lineData));
17099   }
17100   
17101   // draw curve line:
17102   if (mLineStyle != lsNone && mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0)
17103   {
17104     applyDefaultAntialiasingHint(painter);
17105     painter->setPen(mainPen());
17106     painter->setBrush(Qt::NoBrush);
17107     // if drawing solid line and not in PDF, use much faster line drawing instead of polyline:
17108     if (mParentPlot->plottingHints().testFlag(QCP::phFastPolylines) &&
17109         painter->pen().style() == Qt::SolidLine &&
17110         !painter->modes().testFlag(QCPPainter::pmVectorized) &&
17111         !painter->modes().testFlag(QCPPainter::pmNoCaching))
17112     {
17113       int i = 0;
17114       bool lastIsNan = false;
17115       const int lineDataSize = lineData->size();
17116       while (i < lineDataSize && (qIsNaN(lineData->at(i).y()) || qIsNaN(lineData->at(i).x()))) // make sure first point is not NaN
17117         ++i;
17118       ++i; // because drawing works in 1 point retrospect
17119       while (i < lineDataSize)
17120       {
17121         if (!qIsNaN(lineData->at(i).y()) && !qIsNaN(lineData->at(i).x())) // NaNs create a gap in the line
17122         {
17123           if (!lastIsNan)
17124             painter->drawLine(lineData->at(i-1), lineData->at(i));
17125           else
17126             lastIsNan = false;
17127         } else
17128           lastIsNan = true;
17129         ++i;
17130       }
17131     } else
17132     {
17133       int segmentStart = 0;
17134       int i = 0;
17135       const int lineDataSize = lineData->size();
17136       while (i < lineDataSize)
17137       {
17138         if (qIsNaN(lineData->at(i).y()) || qIsNaN(lineData->at(i).x())) // NaNs create a gap in the line
17139         {
17140           painter->drawPolyline(lineData->constData()+segmentStart, i-segmentStart); // i, because we don't want to include the current NaN point
17141           segmentStart = i+1;
17142         }
17143         ++i;
17144       }
17145       // draw last segment:
17146       painter->drawPolyline(lineData->constData()+segmentStart, lineDataSize-segmentStart);
17147     }
17148   }
17149   
17150   // draw scatters:
17151   if (!mScatterStyle.isNone())
17152     drawScatterPlot(painter, lineData);
17153   
17154   // free allocated line data:
17155   delete lineData;
17156 }
17157
17158 /* inherits documentation from base class */
17159 void QCPCurve::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const
17160 {
17161   // draw fill:
17162   if (mBrush.style() != Qt::NoBrush)
17163   {
17164     applyFillAntialiasingHint(painter);
17165     painter->fillRect(QRectF(rect.left(), rect.top()+rect.height()/2.0, rect.width(), rect.height()/3.0), mBrush);
17166   }
17167   // draw line vertically centered:
17168   if (mLineStyle != lsNone)
17169   {
17170     applyDefaultAntialiasingHint(painter);
17171     painter->setPen(mPen);
17172     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
17173   }
17174   // draw scatter symbol:
17175   if (!mScatterStyle.isNone())
17176   {
17177     applyScattersAntialiasingHint(painter);
17178     // scale scatter pixmap if it's too large to fit in legend icon rect:
17179     if (mScatterStyle.shape() == QCPScatterStyle::ssPixmap && (mScatterStyle.pixmap().size().width() > rect.width() || mScatterStyle.pixmap().size().height() > rect.height()))
17180     {
17181       QCPScatterStyle scaledStyle(mScatterStyle);
17182       scaledStyle.setPixmap(scaledStyle.pixmap().scaled(rect.size().toSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
17183       scaledStyle.applyTo(painter, mPen);
17184       scaledStyle.drawShape(painter, QRectF(rect).center());
17185     } else
17186     {
17187       mScatterStyle.applyTo(painter, mPen);
17188       mScatterStyle.drawShape(painter, QRectF(rect).center());
17189     }
17190   }
17191 }
17192
17193 /*! \internal
17194   
17195   Draws scatter symbols at every data point passed in \a pointData. scatter symbols are independent of
17196   the line style and are always drawn if scatter shape is not \ref QCPScatterStyle::ssNone.
17197 */
17198 void QCPCurve::drawScatterPlot(QCPPainter *painter, const QVector<QPointF> *pointData) const
17199 {
17200   // draw scatter point symbols:
17201   applyScattersAntialiasingHint(painter);
17202   mScatterStyle.applyTo(painter, mPen);
17203   for (int i=0; i<pointData->size(); ++i)
17204     if (!qIsNaN(pointData->at(i).x()) && !qIsNaN(pointData->at(i).y()))
17205       mScatterStyle.drawShape(painter,  pointData->at(i));
17206 }
17207
17208 /*! \internal
17209   
17210   called by QCPCurve::draw to generate a point vector (in pixel coordinates) which represents the
17211   line of the curve.
17212
17213   Line segments that aren't visible in the current axis rect are handled in an optimized way. They
17214   are projected onto a rectangle slightly larger than the visible axis rect and simplified
17215   regarding point count. The algorithm makes sure to preserve appearance of lines and fills inside
17216   the visible axis rect by generating new temporary points on the outer rect if necessary.
17217   
17218   Methods that are also involved in the algorithm are: \ref getRegion, \ref getOptimizedPoint, \ref
17219   getOptimizedCornerPoints \ref mayTraverse, \ref getTraverse, \ref getTraverseCornerPoints.
17220 */
17221 void QCPCurve::getCurveData(QVector<QPointF> *lineData) const
17222 {
17223   QCPAxis *keyAxis = mKeyAxis.data();
17224   QCPAxis *valueAxis = mValueAxis.data();
17225   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
17226   
17227   // add margins to rect to compensate for stroke width
17228   double strokeMargin = qMax(qreal(1.0), qreal(mainPen().widthF()*0.75)); // stroke radius + 50% safety
17229   if (!mScatterStyle.isNone())
17230     strokeMargin = qMax(strokeMargin, mScatterStyle.size());
17231   double rectLeft = keyAxis->pixelToCoord(keyAxis->coordToPixel(keyAxis->range().lower)-strokeMargin*((keyAxis->orientation()==Qt::Vertical)!=keyAxis->rangeReversed()?-1:1));
17232   double rectRight = keyAxis->pixelToCoord(keyAxis->coordToPixel(keyAxis->range().upper)+strokeMargin*((keyAxis->orientation()==Qt::Vertical)!=keyAxis->rangeReversed()?-1:1));
17233   double rectBottom = valueAxis->pixelToCoord(valueAxis->coordToPixel(valueAxis->range().lower)+strokeMargin*((valueAxis->orientation()==Qt::Horizontal)!=valueAxis->rangeReversed()?-1:1));
17234   double rectTop = valueAxis->pixelToCoord(valueAxis->coordToPixel(valueAxis->range().upper)-strokeMargin*((valueAxis->orientation()==Qt::Horizontal)!=valueAxis->rangeReversed()?-1:1));
17235   int currentRegion;
17236   QCPCurveDataMap::const_iterator it = mData->constBegin();
17237   QCPCurveDataMap::const_iterator prevIt = mData->constEnd()-1;
17238   int prevRegion = getRegion(prevIt.value().key, prevIt.value().value, rectLeft, rectTop, rectRight, rectBottom);
17239   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)
17240   while (it != mData->constEnd())
17241   {
17242     currentRegion = getRegion(it.value().key, it.value().value, rectLeft, rectTop, rectRight, rectBottom);
17243     if (currentRegion != prevRegion) // changed region, possibly need to add some optimized edge points or original points if entering R
17244     {
17245       if (currentRegion != 5) // segment doesn't end in R, so it's a candidate for removal
17246       {
17247         QPointF crossA, crossB;
17248         if (prevRegion == 5) // we're coming from R, so add this point optimized
17249         {
17250           lineData->append(getOptimizedPoint(currentRegion, it.value().key, it.value().value, prevIt.value().key, prevIt.value().value, rectLeft, rectTop, rectRight, rectBottom));
17251           // 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
17252           *lineData << getOptimizedCornerPoints(prevRegion, currentRegion, prevIt.value().key, prevIt.value().value, it.value().key, it.value().value, rectLeft, rectTop, rectRight, rectBottom);
17253         } else if (mayTraverse(prevRegion, currentRegion) &&
17254                    getTraverse(prevIt.value().key, prevIt.value().value, it.value().key, it.value().value, rectLeft, rectTop, rectRight, rectBottom, crossA, crossB))
17255         {
17256           // add the two cross points optimized if segment crosses R and if segment isn't virtual zeroth segment between last and first curve point:
17257           QVector<QPointF> beforeTraverseCornerPoints, afterTraverseCornerPoints;
17258           getTraverseCornerPoints(prevRegion, currentRegion, rectLeft, rectTop, rectRight, rectBottom, beforeTraverseCornerPoints, afterTraverseCornerPoints);
17259           if (it != mData->constBegin())
17260           {
17261             *lineData << beforeTraverseCornerPoints;
17262             lineData->append(crossA);
17263             lineData->append(crossB);
17264             *lineData << afterTraverseCornerPoints;
17265           } else
17266           {
17267             lineData->append(crossB);
17268             *lineData << afterTraverseCornerPoints;
17269             trailingPoints << beforeTraverseCornerPoints << crossA ;
17270           }
17271         } 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)
17272         {
17273           *lineData << getOptimizedCornerPoints(prevRegion, currentRegion, prevIt.value().key, prevIt.value().value, it.value().key, it.value().value, rectLeft, rectTop, rectRight, rectBottom);
17274         }
17275       } else // segment does end in R, so we add previous point optimized and this point at original position
17276       {
17277         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
17278           trailingPoints << getOptimizedPoint(prevRegion, prevIt.value().key, prevIt.value().value, it.value().key, it.value().value, rectLeft, rectTop, rectRight, rectBottom);
17279         else
17280           lineData->append(getOptimizedPoint(prevRegion, prevIt.value().key, prevIt.value().value, it.value().key, it.value().value, rectLeft, rectTop, rectRight, rectBottom));
17281         lineData->append(coordsToPixels(it.value().key, it.value().value));
17282       }
17283     } else // region didn't change
17284     {
17285       if (currentRegion == 5) // still in R, keep adding original points
17286       {
17287         lineData->append(coordsToPixels(it.value().key, it.value().value));
17288       } else // still outside R, no need to add anything
17289       {
17290         // see how this is not doing anything? That's the main optimization...
17291       }
17292     }
17293     prevIt = it;
17294     prevRegion = currentRegion;
17295     ++it;
17296   }
17297   *lineData << trailingPoints;
17298 }
17299
17300 /*! \internal
17301   
17302   This function is part of the curve optimization algorithm of \ref getCurveData.
17303   
17304   It returns the region of the given point (\a x, \a y) with respect to a rectangle defined by \a
17305   rectLeft, \a rectTop, \a rectRight, and \a rectBottom.
17306   
17307   The regions are enumerated from top to bottom and left to right:
17308   
17309   <table style="width:10em; text-align:center">
17310     <tr><td>1</td><td>4</td><td>7</td></tr>
17311     <tr><td>2</td><td style="border:1px solid black">5</td><td>8</td></tr>
17312     <tr><td>3</td><td>6</td><td>9</td></tr>
17313   </table>
17314   
17315   With the rectangle being region 5, and the outer regions extending infinitely outwards. In the
17316   curve optimization algorithm, region 5 is considered to be the visible portion of the plot.
17317 */
17318 int QCPCurve::getRegion(double x, double y, double rectLeft, double rectTop, double rectRight, double rectBottom) const
17319 {
17320   if (x < rectLeft) // region 123
17321   {
17322     if (y > rectTop)
17323       return 1;
17324     else if (y < rectBottom)
17325       return 3;
17326     else
17327       return 2;
17328   } else if (x > rectRight) // region 789
17329   {
17330     if (y > rectTop)
17331       return 7;
17332     else if (y < rectBottom)
17333       return 9;
17334     else
17335       return 8;
17336   } else // region 456
17337   {
17338     if (y > rectTop)
17339       return 4;
17340     else if (y < rectBottom)
17341       return 6;
17342     else
17343       return 5;
17344   }
17345 }
17346
17347 /*! \internal
17348   
17349   This function is part of the curve optimization algorithm of \ref getCurveData.
17350   
17351   This method is used in case the current segment passes from inside the visible rect (region 5,
17352   see \ref getRegion) to any of the outer regions (\a otherRegion). The current segment is given by
17353   the line connecting (\a key, \a value) with (\a otherKey, \a otherValue).
17354   
17355   It returns the intersection point of the segment with the border of region 5.
17356   
17357   For this function it doesn't matter whether (\a key, \a value) is the point inside region 5 or
17358   whether it's (\a otherKey, \a otherValue), i.e. whether the segment is coming from region 5 or
17359   leaving it. It is important though that \a otherRegion correctly identifies the other region not
17360   equal to 5.
17361 */
17362 QPointF QCPCurve::getOptimizedPoint(int otherRegion, double otherKey, double otherValue, double key, double value, double rectLeft, double rectTop, double rectRight, double rectBottom) const
17363 {
17364   double intersectKey = rectLeft; // initial value is just fail-safe
17365   double intersectValue = rectTop; // initial value is just fail-safe
17366   switch (otherRegion)
17367   {
17368     case 1: // top and left edge
17369     {
17370       intersectValue = rectTop;
17371       intersectKey = otherKey + (key-otherKey)/(value-otherValue)*(intersectValue-otherValue);
17372       if (intersectKey < rectLeft || intersectKey > rectRight) // doesn't intersect, so must intersect other:
17373       {
17374         intersectKey = rectLeft;
17375         intersectValue = otherValue + (value-otherValue)/(key-otherKey)*(intersectKey-otherKey);
17376       }
17377       break;
17378     }
17379     case 2: // left edge
17380     {
17381       intersectKey = rectLeft;
17382       intersectValue = otherValue + (value-otherValue)/(key-otherKey)*(intersectKey-otherKey);
17383       break;
17384     }
17385     case 3: // bottom and left edge
17386     {
17387       intersectValue = rectBottom;
17388       intersectKey = otherKey + (key-otherKey)/(value-otherValue)*(intersectValue-otherValue);
17389       if (intersectKey < rectLeft || intersectKey > rectRight) // doesn't intersect, so must intersect other:
17390       {
17391         intersectKey = rectLeft;
17392         intersectValue = otherValue + (value-otherValue)/(key-otherKey)*(intersectKey-otherKey);
17393       }
17394       break;
17395     }
17396     case 4: // top edge
17397     {
17398       intersectValue = rectTop;
17399       intersectKey = otherKey + (key-otherKey)/(value-otherValue)*(intersectValue-otherValue);
17400       break;
17401     }
17402     case 5:
17403     {
17404       break; // case 5 shouldn't happen for this function but we add it anyway to prevent potential discontinuity in branch table
17405     }
17406     case 6: // bottom edge
17407     {
17408       intersectValue = rectBottom;
17409       intersectKey = otherKey + (key-otherKey)/(value-otherValue)*(intersectValue-otherValue);
17410       break;
17411     }
17412     case 7: // top and right edge
17413     {
17414       intersectValue = rectTop;
17415       intersectKey = otherKey + (key-otherKey)/(value-otherValue)*(intersectValue-otherValue);
17416       if (intersectKey < rectLeft || intersectKey > rectRight) // doesn't intersect, so must intersect other:
17417       {
17418         intersectKey = rectRight;
17419         intersectValue = otherValue + (value-otherValue)/(key-otherKey)*(intersectKey-otherKey);
17420       }
17421       break;
17422     }
17423     case 8: // right edge
17424     {
17425       intersectKey = rectRight;
17426       intersectValue = otherValue + (value-otherValue)/(key-otherKey)*(intersectKey-otherKey);
17427       break;
17428     }
17429     case 9: // bottom and right edge
17430     {
17431       intersectValue = rectBottom;
17432       intersectKey = otherKey + (key-otherKey)/(value-otherValue)*(intersectValue-otherValue);
17433       if (intersectKey < rectLeft || intersectKey > rectRight) // doesn't intersect, so must intersect other:
17434       {
17435         intersectKey = rectRight;
17436         intersectValue = otherValue + (value-otherValue)/(key-otherKey)*(intersectKey-otherKey);
17437       }
17438       break;
17439     }
17440   }
17441   return coordsToPixels(intersectKey, intersectValue);
17442 }
17443
17444 /*! \internal
17445   
17446   This function is part of the curve optimization algorithm of \ref getCurveData.
17447   
17448   In situations where a single segment skips over multiple regions it might become necessary to add
17449   extra points at the corners of region 5 (see \ref getRegion) such that the optimized segment
17450   doesn't unintentionally cut through the visible area of the axis rect and create plot artifacts.
17451   This method provides these points that must be added, assuming the original segment doesn't
17452   start, end, or traverse region 5. (Corner points where region 5 is traversed are calculated by
17453   \ref getTraverseCornerPoints.)
17454   
17455   For example, consider a segment which directly goes from region 4 to 2 but originally is far out
17456   to the top left such that it doesn't cross region 5. Naively optimizing these points by
17457   projecting them on the top and left borders of region 5 will create a segment that surely crosses
17458   5, creating a visual artifact in the plot. This method prevents this by providing extra points at
17459   the top left corner, making the optimized curve correctly pass from region 4 to 1 to 2 without
17460   traversing 5.
17461 */
17462 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
17463 {
17464   QVector<QPointF> result;
17465   switch (prevRegion)
17466   {
17467     case 1:
17468     {
17469       switch (currentRegion)
17470       {
17471         case 2: { result << coordsToPixels(rectLeft, rectTop); break; }
17472         case 4: { result << coordsToPixels(rectLeft, rectTop); break; }
17473         case 3: { result << coordsToPixels(rectLeft, rectTop) << coordsToPixels(rectLeft, rectBottom); break; }
17474         case 7: { result << coordsToPixels(rectLeft, rectTop) << coordsToPixels(rectRight, rectTop); break; }
17475         case 6: { result << coordsToPixels(rectLeft, rectTop) << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); break; }
17476         case 8: { result << coordsToPixels(rectLeft, rectTop) << coordsToPixels(rectRight, rectTop); result.append(result.last()); break; }
17477         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
17478           if ((value-prevValue)/(key-prevKey)*(rectLeft-key)+value < rectBottom) // segment passes below R
17479           { result << coordsToPixels(rectLeft, rectTop) << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); result << coordsToPixels(rectRight, rectBottom); }
17480           else
17481           { result << coordsToPixels(rectLeft, rectTop) << coordsToPixels(rectRight, rectTop); result.append(result.last()); result << coordsToPixels(rectRight, rectBottom); }
17482           break;
17483         }
17484       }
17485       break;
17486     }
17487     case 2:
17488     {
17489       switch (currentRegion)
17490       {
17491         case 1: { result << coordsToPixels(rectLeft, rectTop); break; }
17492         case 3: { result << coordsToPixels(rectLeft, rectBottom); break; }
17493         case 4: { result << coordsToPixels(rectLeft, rectTop); result.append(result.last()); break; }
17494         case 6: { result << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); break; }
17495         case 7: { result << coordsToPixels(rectLeft, rectTop); result.append(result.last()); result << coordsToPixels(rectRight, rectTop); break; }
17496         case 9: { result << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); result << coordsToPixels(rectRight, rectBottom); break; }
17497       }
17498       break;
17499     }
17500     case 3:
17501     {
17502       switch (currentRegion)
17503       {
17504         case 2: { result << coordsToPixels(rectLeft, rectBottom); break; }
17505         case 6: { result << coordsToPixels(rectLeft, rectBottom); break; }
17506         case 1: { result << coordsToPixels(rectLeft, rectBottom) << coordsToPixels(rectLeft, rectTop); break; }
17507         case 9: { result << coordsToPixels(rectLeft, rectBottom) << coordsToPixels(rectRight, rectBottom); break; }
17508         case 4: { result << coordsToPixels(rectLeft, rectBottom) << coordsToPixels(rectLeft, rectTop); result.append(result.last()); break; }
17509         case 8: { result << coordsToPixels(rectLeft, rectBottom) << coordsToPixels(rectRight, rectBottom); result.append(result.last()); break; }
17510         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
17511           if ((value-prevValue)/(key-prevKey)*(rectRight-key)+value < rectBottom) // segment passes below R
17512           { result << coordsToPixels(rectLeft, rectBottom) << coordsToPixels(rectRight, rectBottom); result.append(result.last()); result << coordsToPixels(rectRight, rectTop); }
17513           else
17514           { result << coordsToPixels(rectLeft, rectBottom) << coordsToPixels(rectLeft, rectTop); result.append(result.last()); result << coordsToPixels(rectRight, rectTop); }
17515           break;
17516         }
17517       }
17518       break;
17519     }
17520     case 4:
17521     {
17522       switch (currentRegion)
17523       {
17524         case 1: { result << coordsToPixels(rectLeft, rectTop); break; }
17525         case 7: { result << coordsToPixels(rectRight, rectTop); break; }
17526         case 2: { result << coordsToPixels(rectLeft, rectTop); result.append(result.last()); break; }
17527         case 8: { result << coordsToPixels(rectRight, rectTop); result.append(result.last()); break; }
17528         case 3: { result << coordsToPixels(rectLeft, rectTop); result.append(result.last()); result << coordsToPixels(rectLeft, rectBottom); break; }
17529         case 9: { result << coordsToPixels(rectRight, rectTop); result.append(result.last()); result << coordsToPixels(rectRight, rectBottom); break; }
17530       }
17531       break;
17532     }
17533     case 5:
17534     {
17535       switch (currentRegion)
17536       {
17537         case 1: { result << coordsToPixels(rectLeft, rectTop); break; }
17538         case 7: { result << coordsToPixels(rectRight, rectTop); break; }
17539         case 9: { result << coordsToPixels(rectRight, rectBottom); break; }
17540         case 3: { result << coordsToPixels(rectLeft, rectBottom); break; }
17541       }
17542       break;
17543     }
17544     case 6:
17545     {
17546       switch (currentRegion)
17547       {
17548         case 3: { result << coordsToPixels(rectLeft, rectBottom); break; }
17549         case 9: { result << coordsToPixels(rectRight, rectBottom); break; }
17550         case 2: { result << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); break; }
17551         case 8: { result << coordsToPixels(rectRight, rectBottom); result.append(result.last()); break; }
17552         case 1: { result << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); result << coordsToPixels(rectLeft, rectTop); break; }
17553         case 7: { result << coordsToPixels(rectRight, rectBottom); result.append(result.last()); result << coordsToPixels(rectRight, rectTop); break; }
17554       }
17555       break;
17556     }
17557     case 7:
17558     {
17559       switch (currentRegion)
17560       {
17561         case 4: { result << coordsToPixels(rectRight, rectTop); break; }
17562         case 8: { result << coordsToPixels(rectRight, rectTop); break; }
17563         case 1: { result << coordsToPixels(rectRight, rectTop) << coordsToPixels(rectLeft, rectTop); break; }
17564         case 9: { result << coordsToPixels(rectRight, rectTop) << coordsToPixels(rectRight, rectBottom); break; }
17565         case 2: { result << coordsToPixels(rectRight, rectTop) << coordsToPixels(rectLeft, rectTop); result.append(result.last()); break; }
17566         case 6: { result << coordsToPixels(rectRight, rectTop) << coordsToPixels(rectRight, rectBottom); result.append(result.last()); break; }
17567         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
17568           if ((value-prevValue)/(key-prevKey)*(rectRight-key)+value < rectBottom) // segment passes below R
17569           { result << coordsToPixels(rectRight, rectTop) << coordsToPixels(rectRight, rectBottom); result.append(result.last()); result << coordsToPixels(rectLeft, rectBottom); }
17570           else
17571           { result << coordsToPixels(rectRight, rectTop) << coordsToPixels(rectLeft, rectTop); result.append(result.last()); result << coordsToPixels(rectLeft, rectBottom); }
17572           break;
17573         }
17574       }
17575       break;
17576     }
17577     case 8:
17578     {
17579       switch (currentRegion)
17580       {
17581         case 7: { result << coordsToPixels(rectRight, rectTop); break; }
17582         case 9: { result << coordsToPixels(rectRight, rectBottom); break; }
17583         case 4: { result << coordsToPixels(rectRight, rectTop); result.append(result.last()); break; }
17584         case 6: { result << coordsToPixels(rectRight, rectBottom); result.append(result.last()); break; }
17585         case 1: { result << coordsToPixels(rectRight, rectTop); result.append(result.last()); result << coordsToPixels(rectLeft, rectTop); break; }
17586         case 3: { result << coordsToPixels(rectRight, rectBottom); result.append(result.last()); result << coordsToPixels(rectLeft, rectBottom); break; }
17587       }
17588       break;
17589     }
17590     case 9:
17591     {
17592       switch (currentRegion)
17593       {
17594         case 6: { result << coordsToPixels(rectRight, rectBottom); break; }
17595         case 8: { result << coordsToPixels(rectRight, rectBottom); break; }
17596         case 3: { result << coordsToPixels(rectRight, rectBottom) << coordsToPixels(rectLeft, rectBottom); break; }
17597         case 7: { result << coordsToPixels(rectRight, rectBottom) << coordsToPixels(rectRight, rectTop); break; }
17598         case 2: { result << coordsToPixels(rectRight, rectBottom) << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); break; }
17599         case 4: { result << coordsToPixels(rectRight, rectBottom) << coordsToPixels(rectRight, rectTop); result.append(result.last()); break; }
17600         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
17601           if ((value-prevValue)/(key-prevKey)*(rectLeft-key)+value < rectBottom) // segment passes below R
17602           { result << coordsToPixels(rectRight, rectBottom) << coordsToPixels(rectLeft, rectBottom); result.append(result.last()); result << coordsToPixels(rectLeft, rectTop); }
17603           else
17604           { result << coordsToPixels(rectRight, rectBottom) << coordsToPixels(rectRight, rectTop); result.append(result.last()); result << coordsToPixels(rectLeft, rectTop); }
17605           break;
17606         }
17607       }
17608       break;
17609     }
17610   }
17611   return result;
17612 }
17613
17614 /*! \internal
17615   
17616   This function is part of the curve optimization algorithm of \ref getCurveData.
17617   
17618   This method returns whether a segment going from \a prevRegion to \a currentRegion (see \ref
17619   getRegion) may traverse the visible region 5. This function assumes that neither \a prevRegion
17620   nor \a currentRegion is 5 itself.
17621   
17622   If this method returns false, the segment for sure doesn't pass region 5. If it returns true, the
17623   segment may or may not pass region 5 and a more fine-grained calculation must be used (\ref
17624   getTraverse).
17625 */
17626 bool QCPCurve::mayTraverse(int prevRegion, int currentRegion) const
17627 {
17628   switch (prevRegion)
17629   {
17630     case 1:
17631     {
17632       switch (currentRegion)
17633       {
17634         case 4:
17635         case 7:
17636         case 2:
17637         case 3: return false;
17638         default: return true;
17639       }
17640     }
17641     case 2:
17642     {
17643       switch (currentRegion)
17644       {
17645         case 1:
17646         case 3: return false;
17647         default: return true;
17648       }
17649     }
17650     case 3:
17651     {
17652       switch (currentRegion)
17653       {
17654         case 1:
17655         case 2:
17656         case 6:
17657         case 9: return false;
17658         default: return true;
17659       }
17660     }
17661     case 4:
17662     {
17663       switch (currentRegion)
17664       {
17665         case 1:
17666         case 7: return false;
17667         default: return true;
17668       }
17669     }
17670     case 5: return false; // should never occur
17671     case 6:
17672     {
17673       switch (currentRegion)
17674       {
17675         case 3:
17676         case 9: return false;
17677         default: return true;
17678       }
17679     }
17680     case 7:
17681     {
17682       switch (currentRegion)
17683       {
17684         case 1:
17685         case 4:
17686         case 8:
17687         case 9: return false;
17688         default: return true;
17689       }
17690     }
17691     case 8:
17692     {
17693       switch (currentRegion)
17694       {
17695         case 7:
17696         case 9: return false;
17697         default: return true;
17698       }
17699     }
17700     case 9:
17701     {
17702       switch (currentRegion)
17703       {
17704         case 3:
17705         case 6:
17706         case 8:
17707         case 7: return false;
17708         default: return true;
17709       }
17710     }
17711     default: return true;
17712   }
17713 }
17714
17715
17716 /*! \internal
17717   
17718   This function is part of the curve optimization algorithm of \ref getCurveData.
17719   
17720   This method assumes that the \ref mayTraverse test has returned true, so there is a chance the
17721   segment defined by (\a prevKey, \a prevValue) and (\a key, \a value) goes through the visible
17722   region 5.
17723   
17724   The return value of this method indicates whether the segment actually traverses region 5 or not.
17725   
17726   If the segment traverses 5, the output parameters \a crossA and \a crossB indicate the entry and
17727   exit points of region 5. They will become the optimized points for that segment.
17728 */
17729 bool QCPCurve::getTraverse(double prevKey, double prevValue, double key, double value, double rectLeft, double rectTop, double rectRight, double rectBottom, QPointF &crossA, QPointF &crossB) const
17730 {
17731   QList<QPointF> intersections; // x of QPointF corresponds to key and y to value
17732   if (qFuzzyIsNull(key-prevKey)) // line is parallel to value axis
17733   {
17734     // due to region filter in mayTraverseR(), if line is parallel to value or key axis, R is traversed here
17735     intersections.append(QPointF(key, rectBottom)); // direction will be taken care of at end of method
17736     intersections.append(QPointF(key, rectTop));
17737   } else if (qFuzzyIsNull(value-prevValue)) // line is parallel to key axis
17738   {
17739     // due to region filter in mayTraverseR(), if line is parallel to value or key axis, R is traversed here
17740     intersections.append(QPointF(rectLeft, value)); // direction will be taken care of at end of method
17741     intersections.append(QPointF(rectRight, value));
17742   } else // line is skewed
17743   {
17744     double gamma;
17745     double keyPerValue = (key-prevKey)/(value-prevValue);
17746     // check top of rect:
17747     gamma = prevKey + (rectTop-prevValue)*keyPerValue;
17748     if (gamma >= rectLeft && gamma <= rectRight)
17749       intersections.append(QPointF(gamma, rectTop));
17750     // check bottom of rect:
17751     gamma = prevKey + (rectBottom-prevValue)*keyPerValue;
17752     if (gamma >= rectLeft && gamma <= rectRight)
17753       intersections.append(QPointF(gamma, rectBottom));
17754     double valuePerKey = 1.0/keyPerValue;
17755     // check left of rect:
17756     gamma = prevValue + (rectLeft-prevKey)*valuePerKey;
17757     if (gamma >= rectBottom && gamma <= rectTop)
17758       intersections.append(QPointF(rectLeft, gamma));
17759     // check right of rect:
17760     gamma = prevValue + (rectRight-prevKey)*valuePerKey;
17761     if (gamma >= rectBottom && gamma <= rectTop)
17762       intersections.append(QPointF(rectRight, gamma));
17763   }
17764   
17765   // handle cases where found points isn't exactly 2:
17766   if (intersections.size() > 2)
17767   {
17768     // line probably goes through corner of rect, and we got duplicate points there. single out the point pair with greatest distance in between:
17769     double distSqrMax = 0;
17770     QPointF pv1, pv2;
17771     for (int i=0; i<intersections.size()-1; ++i)
17772     {
17773       for (int k=i+1; k<intersections.size(); ++k)
17774       {
17775         QPointF distPoint = intersections.at(i)-intersections.at(k);
17776         double distSqr = distPoint.x()*distPoint.x()+distPoint.y()+distPoint.y();
17777         if (distSqr > distSqrMax)
17778         {
17779           pv1 = intersections.at(i);
17780           pv2 = intersections.at(k);
17781           distSqrMax = distSqr;
17782         }
17783       }
17784     }
17785     intersections = QList<QPointF>() << pv1 << pv2;
17786   } else if (intersections.size() != 2)
17787   {
17788     // one or even zero points found (shouldn't happen unless line perfectly tangent to corner), no need to draw segment
17789     return false;
17790   }
17791   
17792   // possibly re-sort points so optimized point segment has same direction as original segment:
17793   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
17794     intersections.move(0, 1);
17795   crossA = coordsToPixels(intersections.at(0).x(), intersections.at(0).y());
17796   crossB = coordsToPixels(intersections.at(1).x(), intersections.at(1).y());
17797   return true;
17798 }
17799
17800 /*! \internal
17801   
17802   This function is part of the curve optimization algorithm of \ref getCurveData.
17803   
17804   This method assumes that the \ref getTraverse test has returned true, so the segment definitely
17805   traverses the visible region 5 when going from \a prevRegion to \a currentRegion.
17806   
17807   In certain situations it is not sufficient to merely generate the entry and exit points of the
17808   segment into/out of region 5, as \ref getTraverse provides. It may happen that a single segment, in
17809   addition to traversing region 5, skips another region outside of region 5, which makes it
17810   necessary to add an optimized corner point there (very similar to the job \ref
17811   getOptimizedCornerPoints does for segments that are completely in outside regions and don't
17812   traverse 5).
17813   
17814   As an example, consider a segment going from region 1 to region 6, traversing the lower left
17815   corner of region 5. In this configuration, the segment additionally crosses the border between
17816   region 1 and 2 before entering region 5. This makes it necessary to add an additional point in
17817   the top left corner, before adding the optimized traverse points. So in this case, the output
17818   parameter \a beforeTraverse will contain the top left corner point, and \a afterTraverse will be
17819   empty.
17820   
17821   In some cases, such as when going from region 1 to 9, it may even be necessary to add additional
17822   corner points before and after the traverse. Then both \a beforeTraverse and \a afterTraverse
17823   return the respective corner points.
17824 */
17825 void QCPCurve::getTraverseCornerPoints(int prevRegion, int currentRegion, double rectLeft, double rectTop, double rectRight, double rectBottom, QVector<QPointF> &beforeTraverse, QVector<QPointF> &afterTraverse) const
17826 {
17827   switch (prevRegion)
17828   {
17829     case 1:
17830     {
17831       switch (currentRegion)
17832       {
17833         case 6: { beforeTraverse << coordsToPixels(rectLeft, rectTop); break; }
17834         case 9: { beforeTraverse << coordsToPixels(rectLeft, rectTop); afterTraverse << coordsToPixels(rectRight, rectBottom); break; }
17835         case 8: { beforeTraverse << coordsToPixels(rectLeft, rectTop); break; }
17836       }
17837       break;
17838     }
17839     case 2:
17840     {
17841       switch (currentRegion)
17842       {
17843         case 7: { afterTraverse << coordsToPixels(rectRight, rectTop); break; }
17844         case 9: { afterTraverse << coordsToPixels(rectRight, rectBottom); break; }
17845       }
17846       break;
17847     }
17848     case 3:
17849     {
17850       switch (currentRegion)
17851       {
17852         case 4: { beforeTraverse << coordsToPixels(rectLeft, rectBottom); break; }
17853         case 7: { beforeTraverse << coordsToPixels(rectLeft, rectBottom); afterTraverse << coordsToPixels(rectRight, rectTop); break; }
17854         case 8: { beforeTraverse << coordsToPixels(rectLeft, rectBottom); break; }
17855       }
17856       break;
17857     }
17858     case 4:
17859     {
17860       switch (currentRegion)
17861       {
17862         case 3: { afterTraverse << coordsToPixels(rectLeft, rectBottom); break; }
17863         case 9: { afterTraverse << coordsToPixels(rectRight, rectBottom); break; }
17864       }
17865       break;
17866     }
17867     case 5: { break; } // shouldn't happen because this method only handles full traverses
17868     case 6:
17869     {
17870       switch (currentRegion)
17871       {
17872         case 1: { afterTraverse << coordsToPixels(rectLeft, rectTop); break; }
17873         case 7: { afterTraverse << coordsToPixels(rectRight, rectTop); break; }
17874       }
17875       break;
17876     }
17877     case 7:
17878     {
17879       switch (currentRegion)
17880       {
17881         case 2: { beforeTraverse << coordsToPixels(rectRight, rectTop); break; }
17882         case 3: { beforeTraverse << coordsToPixels(rectRight, rectTop); afterTraverse << coordsToPixels(rectLeft, rectBottom); break; }
17883         case 6: { beforeTraverse << coordsToPixels(rectRight, rectTop); break; }
17884       }
17885       break;
17886     }
17887     case 8:
17888     {
17889       switch (currentRegion)
17890       {
17891         case 1: { afterTraverse << coordsToPixels(rectLeft, rectTop); break; }
17892         case 3: { afterTraverse << coordsToPixels(rectLeft, rectBottom); break; }
17893       }
17894       break;
17895     }
17896     case 9:
17897     {
17898       switch (currentRegion)
17899       {
17900         case 2: { beforeTraverse << coordsToPixels(rectRight, rectBottom); break; }
17901         case 1: { beforeTraverse << coordsToPixels(rectRight, rectBottom); afterTraverse << coordsToPixels(rectLeft, rectTop); break; }
17902         case 4: { beforeTraverse << coordsToPixels(rectRight, rectBottom); break; }
17903       }
17904       break;
17905     }
17906   }
17907 }
17908
17909 /*! \internal
17910   
17911   Calculates the (minimum) distance (in pixels) the curve's representation has from the given \a
17912   pixelPoint in pixels. This is used to determine whether the curve was clicked or not, e.g. in
17913   \ref selectTest.
17914 */
17915 double QCPCurve::pointDistance(const QPointF &pixelPoint) const
17916 {
17917   if (mData->isEmpty())
17918   {
17919     qDebug() << Q_FUNC_INFO << "requested point distance on curve" << mName << "without data";
17920     return 500;
17921   }
17922   if (mData->size() == 1)
17923   {
17924     QPointF dataPoint = coordsToPixels(mData->constBegin().key(), mData->constBegin().value().value);
17925     return QVector2D(dataPoint-pixelPoint).length();
17926   }
17927   
17928   // calculate minimum distance to line segments:
17929   QVector<QPointF> *lineData = new QVector<QPointF>;
17930   getCurveData(lineData);
17931   double minDistSqr = std::numeric_limits<double>::max();
17932   for (int i=0; i<lineData->size()-1; ++i)
17933   {
17934     double currentDistSqr = distSqrToLine(lineData->at(i), lineData->at(i+1), pixelPoint);
17935     if (currentDistSqr < minDistSqr)
17936       minDistSqr = currentDistSqr;
17937   }
17938   delete lineData;
17939   return qSqrt(minDistSqr);
17940 }
17941
17942 /* inherits documentation from base class */
17943 QCPRange QCPCurve::getKeyRange(bool &foundRange, SignDomain inSignDomain) const
17944 {
17945   QCPRange range;
17946   bool haveLower = false;
17947   bool haveUpper = false;
17948   
17949   double current;
17950   
17951   QCPCurveDataMap::const_iterator it = mData->constBegin();
17952   while (it != mData->constEnd())
17953   {
17954     current = it.value().key;
17955     if (!qIsNaN(current) && !qIsNaN(it.value().value))
17956     {
17957       if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current < 0) || (inSignDomain == sdPositive && current > 0))
17958       {
17959         if (current < range.lower || !haveLower)
17960         {
17961           range.lower = current;
17962           haveLower = true;
17963         }
17964         if (current > range.upper || !haveUpper)
17965         {
17966           range.upper = current;
17967           haveUpper = true;
17968         }
17969       }
17970     }
17971     ++it;
17972   }
17973   
17974   foundRange = haveLower && haveUpper;
17975   return range;
17976 }
17977
17978 /* inherits documentation from base class */
17979 QCPRange QCPCurve::getValueRange(bool &foundRange, SignDomain inSignDomain) const
17980 {
17981   QCPRange range;
17982   bool haveLower = false;
17983   bool haveUpper = false;
17984   
17985   double current;
17986   
17987   QCPCurveDataMap::const_iterator it = mData->constBegin();
17988   while (it != mData->constEnd())
17989   {
17990     current = it.value().value;
17991     if (!qIsNaN(current) && !qIsNaN(it.value().key))
17992     {
17993       if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current < 0) || (inSignDomain == sdPositive && current > 0))
17994       {
17995         if (current < range.lower || !haveLower)
17996         {
17997           range.lower = current;
17998           haveLower = true;
17999         }
18000         if (current > range.upper || !haveUpper)
18001         {
18002           range.upper = current;
18003           haveUpper = true;
18004         }
18005       }
18006     }
18007     ++it;
18008   }
18009   
18010   foundRange = haveLower && haveUpper;
18011   return range;
18012 }
18013
18014
18015 ////////////////////////////////////////////////////////////////////////////////////////////////////
18016 //////////////////// QCPBarsGroup
18017 ////////////////////////////////////////////////////////////////////////////////////////////////////
18018
18019 /*! \class QCPBarsGroup
18020   \brief Groups multiple QCPBars together so they appear side by side
18021   
18022   \image html QCPBarsGroup.png
18023   
18024   When showing multiple QCPBars in one plot which have bars at identical keys, it may be desirable
18025   to have them appearing next to each other at each key. This is what adding the respective QCPBars
18026   plottables to a QCPBarsGroup achieves. (An alternative approach is to stack them on top of each
18027   other, see \ref QCPBars::moveAbove.)
18028   
18029   \section qcpbarsgroup-usage Usage
18030   
18031   To add a QCPBars plottable to the group, create a new group and then add the respective bars
18032   intances:
18033   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpbarsgroup-creation
18034   Alternatively to appending to the group like shown above, you can also set the group on the
18035   QCPBars plottable via \ref QCPBars::setBarsGroup.
18036   
18037   The spacing between the bars can be configured via \ref setSpacingType and \ref setSpacing. The
18038   bars in this group appear in the plot in the order they were appended. To insert a bars plottable
18039   at a certain index position, or to reposition a bars plottable which is already in the group, use
18040   \ref insert.
18041   
18042   To remove specific bars from the group, use either \ref remove or call \ref
18043   QCPBars::setBarsGroup "QCPBars::setBarsGroup(0)" on the respective bars plottable.
18044   
18045   To clear the entire group, call \ref clear, or simply delete the group.
18046   
18047   \section qcpbarsgroup-example Example
18048   
18049   The image above is generated with the following code:
18050   \snippet documentation/doc-image-generator/mainwindow.cpp qcpbarsgroup-example
18051 */
18052
18053 /* start of documentation of inline functions */
18054
18055 /*! \fn QList<QCPBars*> QCPBarsGroup::bars() const
18056   
18057   Returns all bars currently in this group.
18058   
18059   \see bars(int index)
18060 */
18061
18062 /*! \fn int QCPBarsGroup::size() const
18063   
18064   Returns the number of QCPBars plottables that are part of this group.
18065   
18066 */
18067
18068 /*! \fn bool QCPBarsGroup::isEmpty() const
18069   
18070   Returns whether this bars group is empty.
18071   
18072   \see size
18073 */
18074
18075 /*! \fn bool QCPBarsGroup::contains(QCPBars *bars)
18076   
18077   Returns whether the specified \a bars plottable is part of this group.
18078   
18079 */
18080
18081 /* end of documentation of inline functions */
18082
18083 /*!
18084   Constructs a new bars group for the specified QCustomPlot instance.
18085 */
18086 QCPBarsGroup::QCPBarsGroup(QCustomPlot *parentPlot) :
18087   QObject(parentPlot),
18088   mParentPlot(parentPlot),
18089   mSpacingType(stAbsolute),
18090   mSpacing(4)
18091 {
18092 }
18093
18094 QCPBarsGroup::~QCPBarsGroup()
18095 {
18096   clear();
18097 }
18098
18099 /*!
18100   Sets how the spacing between adjacent bars is interpreted. See \ref SpacingType.
18101   
18102   The actual spacing can then be specified with \ref setSpacing.
18103
18104   \see setSpacing
18105 */
18106 void QCPBarsGroup::setSpacingType(SpacingType spacingType)
18107 {
18108   mSpacingType = spacingType;
18109 }
18110
18111 /*!
18112   Sets the spacing between adjacent bars. What the number passed as \a spacing actually means, is
18113   defined by the current \ref SpacingType, which can be set with \ref setSpacingType.
18114
18115   \see setSpacingType
18116 */
18117 void QCPBarsGroup::setSpacing(double spacing)
18118 {
18119   mSpacing = spacing;
18120 }
18121
18122 /*!
18123   Returns the QCPBars instance with the specified \a index in this group. If no such QCPBars
18124   exists, returns 0.
18125
18126   \see bars(), size
18127 */
18128 QCPBars *QCPBarsGroup::bars(int index) const
18129 {
18130   if (index >= 0 && index < mBars.size())
18131   {
18132     return mBars.at(index);
18133   } else
18134   {
18135     qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
18136     return 0;
18137   }
18138 }
18139
18140 /*!
18141   Removes all QCPBars plottables from this group.
18142
18143   \see isEmpty
18144 */
18145 void QCPBarsGroup::clear()
18146 {
18147   foreach (QCPBars *bars, mBars) // since foreach takes a copy, removing bars in the loop is okay
18148     bars->setBarsGroup(0); // removes itself via removeBars
18149 }
18150
18151 /*!
18152   Adds the specified \a bars plottable to this group. Alternatively, you can also use \ref
18153   QCPBars::setBarsGroup on the \a bars instance.
18154
18155   \see insert, remove
18156 */
18157 void QCPBarsGroup::append(QCPBars *bars)
18158 {
18159   if (!bars)
18160   {
18161     qDebug() << Q_FUNC_INFO << "bars is 0";
18162     return;
18163   }
18164     
18165   if (!mBars.contains(bars))
18166     bars->setBarsGroup(this);
18167   else
18168     qDebug() << Q_FUNC_INFO << "bars plottable is already in this bars group:" << reinterpret_cast<quintptr>(bars);
18169 }
18170
18171 /*!
18172   Inserts the specified \a bars plottable into this group at the specified index position \a i.
18173   This gives you full control over the ordering of the bars.
18174   
18175   \a bars may already be part of this group. In that case, \a bars is just moved to the new index
18176   position.
18177
18178   \see append, remove
18179 */
18180 void QCPBarsGroup::insert(int i, QCPBars *bars)
18181 {
18182   if (!bars)
18183   {
18184     qDebug() << Q_FUNC_INFO << "bars is 0";
18185     return;
18186   }
18187   
18188   // first append to bars list normally:
18189   if (!mBars.contains(bars))
18190     bars->setBarsGroup(this);
18191   // then move to according position:
18192   mBars.move(mBars.indexOf(bars), qBound(0, i, mBars.size()-1));
18193 }
18194
18195 /*!
18196   Removes the specified \a bars plottable from this group.
18197   
18198   \see contains, clear
18199 */
18200 void QCPBarsGroup::remove(QCPBars *bars)
18201 {
18202   if (!bars)
18203   {
18204     qDebug() << Q_FUNC_INFO << "bars is 0";
18205     return;
18206   }
18207   
18208   if (mBars.contains(bars))
18209     bars->setBarsGroup(0);
18210   else
18211     qDebug() << Q_FUNC_INFO << "bars plottable is not in this bars group:" << reinterpret_cast<quintptr>(bars);
18212 }
18213
18214 /*! \internal
18215   
18216   Adds the specified \a bars to the internal mBars list of bars. This method does not change the
18217   barsGroup property on \a bars.
18218   
18219   \see unregisterBars
18220 */
18221 void QCPBarsGroup::registerBars(QCPBars *bars)
18222 {
18223   if (!mBars.contains(bars))
18224     mBars.append(bars);
18225 }
18226
18227 /*! \internal
18228   
18229   Removes the specified \a bars from the internal mBars list of bars. This method does not change
18230   the barsGroup property on \a bars.
18231   
18232   \see registerBars
18233 */
18234 void QCPBarsGroup::unregisterBars(QCPBars *bars)
18235 {
18236   mBars.removeOne(bars);
18237 }
18238
18239 /*! \internal
18240   
18241   Returns the pixel offset in the key dimension the specified \a bars plottable should have at the
18242   given key coordinate \a keyCoord. The offset is relative to the pixel position of the key
18243   coordinate \a keyCoord.
18244 */
18245 double QCPBarsGroup::keyPixelOffset(const QCPBars *bars, double keyCoord)
18246 {
18247   // find list of all base bars in case some mBars are stacked:
18248   QList<const QCPBars*> baseBars;
18249   foreach (const QCPBars *b, mBars)
18250   {
18251     while (b->barBelow())
18252       b = b->barBelow();
18253     if (!baseBars.contains(b))
18254       baseBars.append(b);
18255   }
18256   // find base bar this "bars" is stacked on:
18257   const QCPBars *thisBase = bars;
18258   while (thisBase->barBelow())
18259     thisBase = thisBase->barBelow();
18260   
18261   // determine key pixel offset of this base bars considering all other base bars in this barsgroup:
18262   double result = 0;
18263   int index = baseBars.indexOf(thisBase);
18264   if (index >= 0)
18265   {
18266     int startIndex;
18267     double lowerPixelWidth, upperPixelWidth;
18268     if (baseBars.size() % 2 == 1 && index == (baseBars.size()-1)/2) // is center bar (int division on purpose)
18269     {
18270       return result;
18271     } else if (index < (baseBars.size()-1)/2.0) // bar is to the left of center
18272     {
18273       if (baseBars.size() % 2 == 0) // even number of bars
18274       {
18275         startIndex = baseBars.size()/2-1;
18276         result -= getPixelSpacing(baseBars.at(startIndex), keyCoord)*0.5; // half of middle spacing
18277       } else // uneven number of bars
18278       {
18279         startIndex = (baseBars.size()-1)/2-1;
18280         baseBars.at((baseBars.size()-1)/2)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth);
18281         result -= qAbs(upperPixelWidth-lowerPixelWidth)*0.5; // half of center bar
18282         result -= getPixelSpacing(baseBars.at((baseBars.size()-1)/2), keyCoord); // center bar spacing
18283       }
18284       for (int i=startIndex; i>index; --i) // add widths and spacings of bars in between center and our bars
18285       {
18286         baseBars.at(i)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth);
18287         result -= qAbs(upperPixelWidth-lowerPixelWidth);
18288         result -= getPixelSpacing(baseBars.at(i), keyCoord);
18289       }
18290       // finally half of our bars width:
18291       baseBars.at(index)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth);
18292       result -= qAbs(upperPixelWidth-lowerPixelWidth)*0.5;
18293     } else // bar is to the right of center
18294     {
18295       if (baseBars.size() % 2 == 0) // even number of bars
18296       {
18297         startIndex = baseBars.size()/2;
18298         result += getPixelSpacing(baseBars.at(startIndex), keyCoord)*0.5; // half of middle spacing
18299       } else // uneven number of bars
18300       {
18301         startIndex = (baseBars.size()-1)/2+1;
18302         baseBars.at((baseBars.size()-1)/2)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth);
18303         result += qAbs(upperPixelWidth-lowerPixelWidth)*0.5; // half of center bar
18304         result += getPixelSpacing(baseBars.at((baseBars.size()-1)/2), keyCoord); // center bar spacing
18305       }
18306       for (int i=startIndex; i<index; ++i) // add widths and spacings of bars in between center and our bars
18307       {
18308         baseBars.at(i)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth);
18309         result += qAbs(upperPixelWidth-lowerPixelWidth);
18310         result += getPixelSpacing(baseBars.at(i), keyCoord);
18311       }
18312       // finally half of our bars width:
18313       baseBars.at(index)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth);
18314       result += qAbs(upperPixelWidth-lowerPixelWidth)*0.5;
18315     }
18316   }
18317   return result;
18318 }
18319
18320 /*! \internal
18321   
18322   Returns the spacing in pixels which is between this \a bars and the following one, both at the
18323   key coordinate \a keyCoord.
18324   
18325   \note Typically the returned value doesn't depend on \a bars or \a keyCoord. \a bars is only
18326   needed to get acces to the key axis transformation and axis rect for the modes \ref
18327   stAxisRectRatio and \ref stPlotCoords. The \a keyCoord is only relevant for spacings given in
18328   \ref stPlotCoords on a logarithmic axis.
18329 */
18330 double QCPBarsGroup::getPixelSpacing(const QCPBars *bars, double keyCoord)
18331 {
18332   switch (mSpacingType)
18333   {
18334     case stAbsolute:
18335     {
18336       return mSpacing;
18337     }
18338     case stAxisRectRatio:
18339     {
18340       if (bars->keyAxis()->orientation() == Qt::Horizontal)
18341         return bars->keyAxis()->axisRect()->width()*mSpacing;
18342       else
18343         return bars->keyAxis()->axisRect()->height()*mSpacing;
18344     }
18345     case stPlotCoords:
18346     {
18347       double keyPixel = bars->keyAxis()->coordToPixel(keyCoord);
18348       return bars->keyAxis()->coordToPixel(keyCoord+mSpacing)-keyPixel;
18349     }
18350   }
18351   return 0;
18352 }
18353
18354
18355 ////////////////////////////////////////////////////////////////////////////////////////////////////
18356 //////////////////// QCPBarData
18357 ////////////////////////////////////////////////////////////////////////////////////////////////////
18358
18359 /*! \class QCPBarData
18360   \brief Holds the data of one single data point (one bar) for QCPBars.
18361   
18362   The container for storing multiple data points is \ref QCPBarDataMap.
18363   
18364   The stored data is:
18365   \li \a key: coordinate on the key axis of this bar
18366   \li \a value: height coordinate on the value axis of this bar
18367   
18368   \see QCPBarDataaMap
18369 */
18370
18371 /*!
18372   Constructs a bar data point with key and value set to zero.
18373 */
18374 QCPBarData::QCPBarData() :
18375   key(0),
18376   value(0)
18377 {
18378 }
18379
18380 /*!
18381   Constructs a bar data point with the specified \a key and \a value.
18382 */
18383 QCPBarData::QCPBarData(double key, double value) :
18384   key(key),
18385   value(value)
18386 {
18387 }
18388
18389
18390 ////////////////////////////////////////////////////////////////////////////////////////////////////
18391 //////////////////// QCPBars
18392 ////////////////////////////////////////////////////////////////////////////////////////////////////
18393
18394 /*! \class QCPBars
18395   \brief A plottable representing a bar chart in a plot.
18396
18397   \image html QCPBars.png
18398   
18399   To plot data, assign it with the \ref setData or \ref addData functions.
18400   
18401   \section appearance Changing the appearance
18402   
18403   The appearance of the bars is determined by the pen and the brush (\ref setPen, \ref setBrush).
18404   The width of the individual bars can be controlled with \ref setWidthType and \ref setWidth.
18405   
18406   Bar charts are stackable. This means, two QCPBars plottables can be placed on top of each other
18407   (see \ref QCPBars::moveAbove). So when two bars are at the same key position, they will appear
18408   stacked.
18409   
18410   If you would like to group multiple QCPBars plottables together so they appear side by side as
18411   shown below, use QCPBarsGroup.
18412   
18413   \image html QCPBarsGroup.png
18414   
18415   \section usage Usage
18416   
18417   Like all data representing objects in QCustomPlot, the QCPBars is a plottable
18418   (QCPAbstractPlottable). So the plottable-interface of QCustomPlot applies
18419   (QCustomPlot::plottable, QCustomPlot::addPlottable, QCustomPlot::removePlottable, etc.)
18420   
18421   Usually, you first create an instance:
18422   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpbars-creation-1
18423   add it to the customPlot with QCustomPlot::addPlottable:
18424   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpbars-creation-2
18425   and then modify the properties of the newly created plottable, e.g.:
18426   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpbars-creation-3
18427 */
18428
18429 /* start of documentation of inline functions */
18430
18431 /*! \fn QCPBars *QCPBars::barBelow() const
18432   Returns the bars plottable that is directly below this bars plottable.
18433   If there is no such plottable, returns 0.
18434   
18435   \see barAbove, moveBelow, moveAbove
18436 */
18437
18438 /*! \fn QCPBars *QCPBars::barAbove() const
18439   Returns the bars plottable that is directly above this bars plottable.
18440   If there is no such plottable, returns 0.
18441   
18442   \see barBelow, moveBelow, moveAbove
18443 */
18444
18445 /* end of documentation of inline functions */
18446
18447 /*!
18448   Constructs a bar chart which uses \a keyAxis as its key axis ("x") and \a valueAxis as its value
18449   axis ("y"). \a keyAxis and \a valueAxis must reside in the same QCustomPlot instance and not have
18450   the same orientation. If either of these restrictions is violated, a corresponding message is
18451   printed to the debug output (qDebug), the construction is not aborted, though.
18452   
18453   The constructed QCPBars can be added to the plot with QCustomPlot::addPlottable, QCustomPlot
18454   then takes ownership of the bar chart.
18455 */
18456 QCPBars::QCPBars(QCPAxis *keyAxis, QCPAxis *valueAxis) :
18457   QCPAbstractPlottable(keyAxis, valueAxis),
18458   mData(new QCPBarDataMap),
18459   mWidth(0.75),
18460   mWidthType(wtPlotCoords),
18461   mBarsGroup(0),
18462   mBaseValue(0)
18463 {
18464   // modify inherited properties from abstract plottable:
18465   mPen.setColor(Qt::blue);
18466   mPen.setStyle(Qt::SolidLine);
18467   mBrush.setColor(QColor(40, 50, 255, 30));
18468   mBrush.setStyle(Qt::SolidPattern);
18469   mSelectedPen = mPen;
18470   mSelectedPen.setWidthF(2.5);
18471   mSelectedPen.setColor(QColor(80, 80, 255)); // lighter than Qt::blue of mPen
18472   mSelectedBrush = mBrush;
18473 }
18474
18475 QCPBars::~QCPBars()
18476 {
18477   setBarsGroup(0);
18478   if (mBarBelow || mBarAbove)
18479     connectBars(mBarBelow.data(), mBarAbove.data()); // take this bar out of any stacking
18480   delete mData;
18481 }
18482
18483 /*!
18484   Sets the width of the bars.
18485
18486   How the number passed as \a width is interpreted (e.g. screen pixels, plot coordinates,...),
18487   depends on the currently set width type, see \ref setWidthType and \ref WidthType.
18488 */
18489 void QCPBars::setWidth(double width)
18490 {
18491   mWidth = width;
18492 }
18493
18494 /*!
18495   Sets how the width of the bars is defined. See the documentation of \ref WidthType for an
18496   explanation of the possible values for \a widthType.
18497   
18498   The default value is \ref wtPlotCoords.
18499   
18500   \see setWidth
18501 */
18502 void QCPBars::setWidthType(QCPBars::WidthType widthType)
18503 {
18504   mWidthType = widthType;
18505 }
18506
18507 /*!
18508   Sets to which QCPBarsGroup this QCPBars instance belongs to. Alternatively, you can also use \ref
18509   QCPBarsGroup::append.
18510   
18511   To remove this QCPBars from any group, set \a barsGroup to 0.
18512 */
18513 void QCPBars::setBarsGroup(QCPBarsGroup *barsGroup)
18514 {
18515   // deregister at old group:
18516   if (mBarsGroup)
18517     mBarsGroup->unregisterBars(this);
18518   mBarsGroup = barsGroup;
18519   // register at new group:
18520   if (mBarsGroup)
18521     mBarsGroup->registerBars(this);
18522 }
18523
18524 /*!
18525   Sets the base value of this bars plottable.
18526
18527   The base value defines where on the value coordinate the bars start. How far the bars extend from
18528   the base value is given by their individual value data. For example, if the base value is set to
18529   1, a bar with data value 2 will have its lowest point at value coordinate 1 and highest point at
18530   3.
18531   
18532   For stacked bars, only the base value of the bottom-most QCPBars has meaning.
18533   
18534   The default base value is 0.
18535 */
18536 void QCPBars::setBaseValue(double baseValue)
18537 {
18538   mBaseValue = baseValue;
18539 }
18540
18541 /*!
18542   Replaces the current data with the provided \a data.
18543   
18544   If \a copy is set to true, data points in \a data will only be copied. if false, the plottable
18545   takes ownership of the passed data and replaces the internal data pointer with it. This is
18546   significantly faster than copying for large datasets.
18547 */
18548 void QCPBars::setData(QCPBarDataMap *data, bool copy)
18549 {
18550   if (mData == data)
18551   {
18552     qDebug() << Q_FUNC_INFO << "The data pointer is already in (and owned by) this plottable" << reinterpret_cast<quintptr>(data);
18553     return;
18554   }
18555   if (copy)
18556   {
18557     *mData = *data;
18558   } else
18559   {
18560     delete mData;
18561     mData = data;
18562   }
18563 }
18564
18565 /*! \overload
18566   
18567   Replaces the current data with the provided points in \a key and \a value tuples. The
18568   provided vectors should have equal length. Else, the number of added points will be the size of
18569   the smallest vector.
18570 */
18571 void QCPBars::setData(const QVector<double> &key, const QVector<double> &value)
18572 {
18573   mData->clear();
18574   int n = key.size();
18575   n = qMin(n, value.size());
18576   QCPBarData newData;
18577   for (int i=0; i<n; ++i)
18578   {
18579     newData.key = key[i];
18580     newData.value = value[i];
18581     mData->insertMulti(newData.key, newData);
18582   }
18583 }
18584
18585 /*!
18586   Moves this bars plottable below \a bars. In other words, the bars of this plottable will appear
18587   below the bars of \a bars. The move target \a bars must use the same key and value axis as this
18588   plottable.
18589   
18590   Inserting into and removing from existing bar stacking is handled gracefully. If \a bars already
18591   has a bars object below itself, this bars object is inserted between the two. If this bars object
18592   is already between two other bars, the two other bars will be stacked on top of each other after
18593   the operation.
18594   
18595   To remove this bars plottable from any stacking, set \a bars to 0.
18596   
18597   \see moveBelow, barAbove, barBelow
18598 */
18599 void QCPBars::moveBelow(QCPBars *bars)
18600 {
18601   if (bars == this) return;
18602   if (bars && (bars->keyAxis() != mKeyAxis.data() || bars->valueAxis() != mValueAxis.data()))
18603   {
18604     qDebug() << Q_FUNC_INFO << "passed QCPBars* doesn't have same key and value axis as this QCPBars";
18605     return;
18606   }
18607   // remove from stacking:
18608   connectBars(mBarBelow.data(), mBarAbove.data()); // Note: also works if one (or both) of them is 0
18609   // if new bar given, insert this bar below it:
18610   if (bars)
18611   {
18612     if (bars->mBarBelow)
18613       connectBars(bars->mBarBelow.data(), this);
18614     connectBars(this, bars);
18615   }
18616 }
18617
18618 /*!
18619   Moves this bars plottable above \a bars. In other words, the bars of this plottable will appear
18620   above the bars of \a bars. The move target \a bars must use the same key and value axis as this
18621   plottable.
18622   
18623   Inserting into and removing from existing bar stacking is handled gracefully. If \a bars already
18624   has a bars object above itself, this bars object is inserted between the two. If this bars object
18625   is already between two other bars, the two other bars will be stacked on top of each other after
18626   the operation.
18627   
18628   To remove this bars plottable from any stacking, set \a bars to 0.
18629   
18630   \see moveBelow, barBelow, barAbove
18631 */
18632 void QCPBars::moveAbove(QCPBars *bars)
18633 {
18634   if (bars == this) return;
18635   if (bars && (bars->keyAxis() != mKeyAxis.data() || bars->valueAxis() != mValueAxis.data()))
18636   {
18637     qDebug() << Q_FUNC_INFO << "passed QCPBars* doesn't have same key and value axis as this QCPBars";
18638     return;
18639   }
18640   // remove from stacking:
18641   connectBars(mBarBelow.data(), mBarAbove.data()); // Note: also works if one (or both) of them is 0
18642   // if new bar given, insert this bar above it:
18643   if (bars)
18644   {
18645     if (bars->mBarAbove)
18646       connectBars(this, bars->mBarAbove.data());
18647     connectBars(bars, this);
18648   }
18649 }
18650
18651 /*!
18652   Adds the provided data points in \a dataMap to the current data.
18653   \see removeData
18654 */
18655 void QCPBars::addData(const QCPBarDataMap &dataMap)
18656 {
18657   mData->unite(dataMap);
18658 }
18659
18660 /*! \overload
18661   Adds the provided single data point in \a data to the current data.
18662   \see removeData
18663 */
18664 void QCPBars::addData(const QCPBarData &data)
18665 {
18666   mData->insertMulti(data.key, data);
18667 }
18668
18669 /*! \overload
18670   Adds the provided single data point as \a key and \a value tuple to the current data
18671   \see removeData
18672 */
18673 void QCPBars::addData(double key, double value)
18674 {
18675   QCPBarData newData;
18676   newData.key = key;
18677   newData.value = value;
18678   mData->insertMulti(newData.key, newData);
18679 }
18680
18681 /*! \overload
18682   Adds the provided data points as \a key and \a value tuples to the current data.
18683   \see removeData
18684 */
18685 void QCPBars::addData(const QVector<double> &keys, const QVector<double> &values)
18686 {
18687   int n = keys.size();
18688   n = qMin(n, values.size());
18689   QCPBarData newData;
18690   for (int i=0; i<n; ++i)
18691   {
18692     newData.key = keys[i];
18693     newData.value = values[i];
18694     mData->insertMulti(newData.key, newData);
18695   }
18696 }
18697
18698 /*!
18699   Removes all data points with key smaller than \a key.
18700   \see addData, clearData
18701 */
18702 void QCPBars::removeDataBefore(double key)
18703 {
18704   QCPBarDataMap::iterator it = mData->begin();
18705   while (it != mData->end() && it.key() < key)
18706     it = mData->erase(it);
18707 }
18708
18709 /*!
18710   Removes all data points with key greater than \a key.
18711   \see addData, clearData
18712 */
18713 void QCPBars::removeDataAfter(double key)
18714 {
18715   if (mData->isEmpty()) return;
18716   QCPBarDataMap::iterator it = mData->upperBound(key);
18717   while (it != mData->end())
18718     it = mData->erase(it);
18719 }
18720
18721 /*!
18722   Removes all data points with key between \a fromKey and \a toKey. if \a fromKey is
18723   greater or equal to \a toKey, the function does nothing. To remove a single data point with known
18724   key, use \ref removeData(double key).
18725   
18726   \see addData, clearData
18727 */
18728 void QCPBars::removeData(double fromKey, double toKey)
18729 {
18730   if (fromKey >= toKey || mData->isEmpty()) return;
18731   QCPBarDataMap::iterator it = mData->upperBound(fromKey);
18732   QCPBarDataMap::iterator itEnd = mData->upperBound(toKey);
18733   while (it != itEnd)
18734     it = mData->erase(it);
18735 }
18736
18737 /*! \overload
18738   
18739   Removes a single data point at \a key. If the position is not known with absolute precision,
18740   consider using \ref removeData(double fromKey, double toKey) with a small fuzziness interval
18741   around the suspected position, depeding on the precision with which the key is known.
18742   
18743   \see addData, clearData
18744 */
18745 void QCPBars::removeData(double key)
18746 {
18747   mData->remove(key);
18748 }
18749
18750 /*!
18751   Removes all data points.
18752   \see removeData, removeDataAfter, removeDataBefore
18753 */
18754 void QCPBars::clearData()
18755 {
18756   mData->clear();
18757 }
18758
18759 /* inherits documentation from base class */
18760 double QCPBars::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
18761 {
18762   Q_UNUSED(details)
18763   if (onlySelectable && !mSelectable)
18764     return -1;
18765   if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
18766   
18767   if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()))
18768   {
18769     QCPBarDataMap::ConstIterator it;
18770     for (it = mData->constBegin(); it != mData->constEnd(); ++it)
18771     {
18772       if (getBarPolygon(it.value().key, it.value().value).boundingRect().contains(pos))
18773         return mParentPlot->selectionTolerance()*0.99;
18774     }
18775   }
18776   return -1;
18777 }
18778
18779 /* inherits documentation from base class */
18780 void QCPBars::draw(QCPPainter *painter)
18781 {
18782   if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
18783   if (mData->isEmpty()) return;
18784   
18785   QCPBarDataMap::const_iterator it, lower, upperEnd;
18786   getVisibleDataBounds(lower, upperEnd);
18787   for (it = lower; it != upperEnd; ++it)
18788   {
18789     // check data validity if flag set:
18790 #ifdef QCUSTOMPLOT_CHECK_DATA
18791     if (QCP::isInvalidData(it.value().key, it.value().value))
18792       qDebug() << Q_FUNC_INFO << "Data point at" << it.key() << "of drawn range invalid." << "Plottable name:" << name();
18793 #endif
18794     QPolygonF barPolygon = getBarPolygon(it.key(), it.value().value);
18795     // draw bar fill:
18796     if (mainBrush().style() != Qt::NoBrush && mainBrush().color().alpha() != 0)
18797     {
18798       applyFillAntialiasingHint(painter);
18799       painter->setPen(Qt::NoPen);
18800       painter->setBrush(mainBrush());
18801       painter->drawPolygon(barPolygon);
18802     }
18803     // draw bar line:
18804     if (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0)
18805     {
18806       applyDefaultAntialiasingHint(painter);
18807       painter->setPen(mainPen());
18808       painter->setBrush(Qt::NoBrush);
18809       painter->drawPolyline(barPolygon);
18810     }
18811   }
18812 }
18813
18814 /* inherits documentation from base class */
18815 void QCPBars::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const
18816 {
18817   // draw filled rect:
18818   applyDefaultAntialiasingHint(painter);
18819   painter->setBrush(mBrush);
18820   painter->setPen(mPen);
18821   QRectF r = QRectF(0, 0, rect.width()*0.67, rect.height()*0.67);
18822   r.moveCenter(rect.center());
18823   painter->drawRect(r);
18824 }
18825
18826 /*!  \internal
18827   
18828   called by \ref draw to determine which data (key) range is visible at the current key axis range
18829   setting, so only that needs to be processed. It also takes into account the bar width.
18830   
18831   \a lower returns an iterator to the lowest data point that needs to be taken into account when
18832   plotting. Note that in order to get a clean plot all the way to the edge of the axis rect, \a
18833   lower may still be just outside the visible range.
18834   
18835   \a upperEnd returns an iterator one higher than the highest visible data point. Same as before, \a
18836   upperEnd may also lie just outside of the visible range.
18837   
18838   if the bars plottable contains no data, both \a lower and \a upperEnd point to constEnd.
18839 */
18840 void QCPBars::getVisibleDataBounds(QCPBarDataMap::const_iterator &lower, QCPBarDataMap::const_iterator &upperEnd) const
18841 {
18842   if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
18843   if (mData->isEmpty())
18844   {
18845     lower = mData->constEnd();
18846     upperEnd = mData->constEnd();
18847     return;
18848   }
18849   
18850   // get visible data range as QMap iterators
18851   lower = mData->lowerBound(mKeyAxis.data()->range().lower);
18852   upperEnd = mData->upperBound(mKeyAxis.data()->range().upper);
18853   double lowerPixelBound = mKeyAxis.data()->coordToPixel(mKeyAxis.data()->range().lower);
18854   double upperPixelBound = mKeyAxis.data()->coordToPixel(mKeyAxis.data()->range().upper);
18855   bool isVisible = false;
18856   // walk left from lbound to find lower bar that actually is completely outside visible pixel range:
18857   QCPBarDataMap::const_iterator it = lower;
18858   while (it != mData->constBegin())
18859   {
18860     --it;
18861     QRectF barBounds = getBarPolygon(it.value().key, it.value().value).boundingRect();
18862     if (mKeyAxis.data()->orientation() == Qt::Horizontal)
18863       isVisible = ((!mKeyAxis.data()->rangeReversed() && barBounds.right() >= lowerPixelBound) || (mKeyAxis.data()->rangeReversed() && barBounds.left() <= lowerPixelBound));
18864     else // keyaxis is vertical
18865       isVisible = ((!mKeyAxis.data()->rangeReversed() && barBounds.top() <= lowerPixelBound) || (mKeyAxis.data()->rangeReversed() && barBounds.bottom() >= lowerPixelBound));
18866     if (isVisible)
18867       lower = it;
18868     else
18869       break;
18870   }
18871   // walk right from ubound to find upper bar that actually is completely outside visible pixel range:
18872   it = upperEnd;
18873   while (it != mData->constEnd())
18874   {
18875     QRectF barBounds = getBarPolygon(upperEnd.value().key, upperEnd.value().value).boundingRect();
18876     if (mKeyAxis.data()->orientation() == Qt::Horizontal)
18877       isVisible = ((!mKeyAxis.data()->rangeReversed() && barBounds.left() <= upperPixelBound) || (mKeyAxis.data()->rangeReversed() && barBounds.right() >= upperPixelBound));
18878     else // keyaxis is vertical
18879       isVisible = ((!mKeyAxis.data()->rangeReversed() && barBounds.bottom() >= upperPixelBound) || (mKeyAxis.data()->rangeReversed() && barBounds.top() <= upperPixelBound));
18880     if (isVisible)
18881       upperEnd = it+1;
18882     else
18883       break;
18884     ++it;
18885   }
18886 }
18887
18888 /*! \internal
18889   
18890   Returns the polygon of a single bar with \a key and \a value. The Polygon is open at the bottom
18891   and shifted according to the bar stacking (see \ref moveAbove) and base value (see \ref
18892   setBaseValue).
18893 */
18894 QPolygonF QCPBars::getBarPolygon(double key, double value) const
18895 {
18896   QCPAxis *keyAxis = mKeyAxis.data();
18897   QCPAxis *valueAxis = mValueAxis.data();
18898   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return QPolygonF(); }
18899   
18900   QPolygonF result;
18901   double lowerPixelWidth, upperPixelWidth;
18902   getPixelWidth(key, lowerPixelWidth, upperPixelWidth);
18903   double base = getStackedBaseValue(key, value >= 0);
18904   double basePixel = valueAxis->coordToPixel(base);
18905   double valuePixel = valueAxis->coordToPixel(base+value);
18906   double keyPixel = keyAxis->coordToPixel(key);
18907   if (mBarsGroup)
18908     keyPixel += mBarsGroup->keyPixelOffset(this, key);
18909   if (keyAxis->orientation() == Qt::Horizontal)
18910   {
18911     result << QPointF(keyPixel+lowerPixelWidth, basePixel);
18912     result << QPointF(keyPixel+lowerPixelWidth, valuePixel);
18913     result << QPointF(keyPixel+upperPixelWidth, valuePixel);
18914     result << QPointF(keyPixel+upperPixelWidth, basePixel);
18915   } else
18916   {
18917     result << QPointF(basePixel, keyPixel+lowerPixelWidth);
18918     result << QPointF(valuePixel, keyPixel+lowerPixelWidth);
18919     result << QPointF(valuePixel, keyPixel+upperPixelWidth);
18920     result << QPointF(basePixel, keyPixel+upperPixelWidth);
18921   }
18922   return result;
18923 }
18924
18925 /*! \internal
18926   
18927   This function is used to determine the width of the bar at coordinate \a key, according to the
18928   specified width (\ref setWidth) and width type (\ref setWidthType).
18929   
18930   The output parameters \a lower and \a upper return the number of pixels the bar extends to lower
18931   and higher keys, relative to the \a key coordinate (so with a non-reversed horizontal axis, \a
18932   lower is negative and \a upper positive).
18933 */
18934 void QCPBars::getPixelWidth(double key, double &lower, double &upper) const
18935 {
18936   switch (mWidthType)
18937   {
18938     case wtAbsolute:
18939     {
18940       upper = mWidth*0.5;
18941       lower = -upper;
18942       if (mKeyAxis && (mKeyAxis.data()->rangeReversed() ^ (mKeyAxis.data()->orientation() == Qt::Vertical)))
18943         qSwap(lower, upper);
18944       break;
18945     }
18946     case wtAxisRectRatio:
18947     {
18948       if (mKeyAxis && mKeyAxis.data()->axisRect())
18949       {
18950         if (mKeyAxis.data()->orientation() == Qt::Horizontal)
18951           upper = mKeyAxis.data()->axisRect()->width()*mWidth*0.5;
18952         else
18953           upper = mKeyAxis.data()->axisRect()->height()*mWidth*0.5;
18954         lower = -upper;
18955         if (mKeyAxis && (mKeyAxis.data()->rangeReversed() ^ (mKeyAxis.data()->orientation() == Qt::Vertical)))
18956           qSwap(lower, upper);
18957       } else
18958         qDebug() << Q_FUNC_INFO << "No key axis or axis rect defined";
18959       break;
18960     }
18961     case wtPlotCoords:
18962     {
18963       if (mKeyAxis)
18964       {
18965         double keyPixel = mKeyAxis.data()->coordToPixel(key);
18966         upper = mKeyAxis.data()->coordToPixel(key+mWidth*0.5)-keyPixel;
18967         lower = mKeyAxis.data()->coordToPixel(key-mWidth*0.5)-keyPixel;
18968         // no need to qSwap(lower, higher) when range reversed, because higher/lower are gained by
18969         // coordinate transform which includes range direction
18970       } else
18971         qDebug() << Q_FUNC_INFO << "No key axis defined";
18972       break;
18973     }
18974   }
18975 }
18976
18977 /*! \internal
18978   
18979   This function is called to find at which value to start drawing the base of a bar at \a key, when
18980   it is stacked on top of another QCPBars (e.g. with \ref moveAbove).
18981   
18982   positive and negative bars are separated per stack (positive are stacked above baseValue upwards,
18983   negative are stacked below baseValue downwards). This can be indicated with \a positive. So if the
18984   bar for which we need the base value is negative, set \a positive to false.
18985 */
18986 double QCPBars::getStackedBaseValue(double key, bool positive) const
18987 {
18988   if (mBarBelow)
18989   {
18990     double max = 0; // don't use mBaseValue here because only base value of bottom-most bar has meaning in a bar stack
18991     // find bars of mBarBelow that are approximately at key and find largest one:
18992     double epsilon = qAbs(key)*1e-6; // should be safe even when changed to use float at some point
18993     if (key == 0)
18994       epsilon = 1e-6;
18995     QCPBarDataMap::const_iterator it = mBarBelow.data()->mData->lowerBound(key-epsilon);
18996     QCPBarDataMap::const_iterator itEnd = mBarBelow.data()->mData->upperBound(key+epsilon);
18997     while (it != itEnd)
18998     {
18999       if ((positive && it.value().value > max) ||
19000           (!positive && it.value().value < max))
19001         max = it.value().value;
19002       ++it;
19003     }
19004     // recurse down the bar-stack to find the total height:
19005     return max + mBarBelow.data()->getStackedBaseValue(key, positive);
19006   } else
19007     return mBaseValue;
19008 }
19009
19010 /*! \internal
19011
19012   Connects \a below and \a above to each other via their mBarAbove/mBarBelow properties. The bar(s)
19013   currently above lower and below upper will become disconnected to lower/upper.
19014   
19015   If lower is zero, upper will be disconnected at the bottom.
19016   If upper is zero, lower will be disconnected at the top.
19017 */
19018 void QCPBars::connectBars(QCPBars *lower, QCPBars *upper)
19019 {
19020   if (!lower && !upper) return;
19021   
19022   if (!lower) // disconnect upper at bottom
19023   {
19024     // disconnect old bar below upper:
19025     if (upper->mBarBelow && upper->mBarBelow.data()->mBarAbove.data() == upper)
19026       upper->mBarBelow.data()->mBarAbove = 0;
19027     upper->mBarBelow = 0;
19028   } else if (!upper) // disconnect lower at top
19029   {
19030     // disconnect old bar above lower:
19031     if (lower->mBarAbove && lower->mBarAbove.data()->mBarBelow.data() == lower)
19032       lower->mBarAbove.data()->mBarBelow = 0;
19033     lower->mBarAbove = 0;
19034   } else // connect lower and upper
19035   {
19036     // disconnect old bar above lower:
19037     if (lower->mBarAbove && lower->mBarAbove.data()->mBarBelow.data() == lower)
19038       lower->mBarAbove.data()->mBarBelow = 0;
19039     // disconnect old bar below upper:
19040     if (upper->mBarBelow && upper->mBarBelow.data()->mBarAbove.data() == upper)
19041       upper->mBarBelow.data()->mBarAbove = 0;
19042     lower->mBarAbove = upper;
19043     upper->mBarBelow = lower;
19044   }
19045 }
19046
19047 /* inherits documentation from base class */
19048 QCPRange QCPBars::getKeyRange(bool &foundRange, SignDomain inSignDomain) const
19049 {
19050   QCPRange range;
19051   bool haveLower = false;
19052   bool haveUpper = false;
19053   
19054   double current;
19055   QCPBarDataMap::const_iterator it = mData->constBegin();
19056   while (it != mData->constEnd())
19057   {
19058     current = it.value().key;
19059     if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current < 0) || (inSignDomain == sdPositive && current > 0))
19060     {
19061       if (current < range.lower || !haveLower)
19062       {
19063         range.lower = current;
19064         haveLower = true;
19065       }
19066       if (current > range.upper || !haveUpper)
19067       {
19068         range.upper = current;
19069         haveUpper = true;
19070       }
19071     }
19072     ++it;
19073   }
19074   // determine exact range of bars by including bar width and barsgroup offset:
19075   if (haveLower && mKeyAxis)
19076   {
19077     double lowerPixelWidth, upperPixelWidth, keyPixel;
19078     getPixelWidth(range.lower, lowerPixelWidth, upperPixelWidth);
19079     keyPixel = mKeyAxis.data()->coordToPixel(range.lower) + lowerPixelWidth;
19080     if (mBarsGroup)
19081       keyPixel += mBarsGroup->keyPixelOffset(this, range.lower);
19082     range.lower = mKeyAxis.data()->pixelToCoord(keyPixel);
19083   }
19084   if (haveUpper && mKeyAxis)
19085   {
19086     double lowerPixelWidth, upperPixelWidth, keyPixel;
19087     getPixelWidth(range.upper, lowerPixelWidth, upperPixelWidth);
19088     keyPixel = mKeyAxis.data()->coordToPixel(range.upper) + upperPixelWidth;
19089     if (mBarsGroup)
19090       keyPixel += mBarsGroup->keyPixelOffset(this, range.upper);
19091     range.upper = mKeyAxis.data()->pixelToCoord(keyPixel);
19092   }
19093   foundRange = haveLower && haveUpper;
19094   return range;
19095 }
19096
19097 /* inherits documentation from base class */
19098 QCPRange QCPBars::getValueRange(bool &foundRange, SignDomain inSignDomain) const
19099 {
19100   QCPRange range;
19101   range.lower = mBaseValue;
19102   range.upper = mBaseValue;
19103   bool haveLower = true; // set to true, because baseValue should always be visible in bar charts
19104   bool haveUpper = true; // set to true, because baseValue should always be visible in bar charts
19105   double current;
19106   
19107   QCPBarDataMap::const_iterator it = mData->constBegin();
19108   while (it != mData->constEnd())
19109   {
19110     current = it.value().value + getStackedBaseValue(it.value().key, it.value().value >= 0);
19111     if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current < 0) || (inSignDomain == sdPositive && current > 0))
19112     {
19113       if (current < range.lower || !haveLower)
19114       {
19115         range.lower = current;
19116         haveLower = true;
19117       }
19118       if (current > range.upper || !haveUpper)
19119       {
19120         range.upper = current;
19121         haveUpper = true;
19122       }
19123     }
19124     ++it;
19125   }
19126   
19127   foundRange = true; // return true because bar charts always have the 0-line visible
19128   return range;
19129 }
19130
19131
19132 ////////////////////////////////////////////////////////////////////////////////////////////////////
19133 //////////////////// QCPStatisticalBox
19134 ////////////////////////////////////////////////////////////////////////////////////////////////////
19135
19136 /*! \class QCPStatisticalBox
19137   \brief A plottable representing a single statistical box in a plot.
19138
19139   \image html QCPStatisticalBox.png
19140   
19141   To plot data, assign it with the individual parameter functions or use \ref setData to set all
19142   parameters at once. The individual functions are:
19143   \li \ref setMinimum
19144   \li \ref setLowerQuartile
19145   \li \ref setMedian
19146   \li \ref setUpperQuartile
19147   \li \ref setMaximum
19148   
19149   Additionally you can define a list of outliers, drawn as scatter datapoints:
19150   \li \ref setOutliers
19151   
19152   \section appearance Changing the appearance
19153   
19154   The appearance of the box itself is controlled via \ref setPen and \ref setBrush. You may change
19155   the width of the box with \ref setWidth in plot coordinates (not pixels).
19156
19157   Analog functions exist for the minimum/maximum-whiskers: \ref setWhiskerPen, \ref
19158   setWhiskerBarPen, \ref setWhiskerWidth. The whisker width is the width of the bar at the top
19159   (maximum) and bottom (minimum).
19160   
19161   The median indicator line has its own pen, \ref setMedianPen.
19162   
19163   If the whisker backbone pen is changed, make sure to set the capStyle to Qt::FlatCap. Else, the
19164   backbone line might exceed the whisker bars by a few pixels due to the pen cap being not
19165   perfectly flat.
19166   
19167   The Outlier data points are drawn as normal scatter points. Their look can be controlled with
19168   \ref setOutlierStyle
19169   
19170   \section usage Usage
19171   
19172   Like all data representing objects in QCustomPlot, the QCPStatisticalBox is a plottable.
19173   Usually, you first create an instance and add it to the customPlot:
19174   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpstatisticalbox-creation-1
19175   and then modify the properties of the newly created plottable, e.g.:
19176   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpstatisticalbox-creation-2
19177 */
19178
19179 /*!
19180   Constructs a statistical box which uses \a keyAxis as its key axis ("x") and \a valueAxis as its
19181   value axis ("y"). \a keyAxis and \a valueAxis must reside in the same QCustomPlot instance and
19182   not have the same orientation. If either of these restrictions is violated, a corresponding
19183   message is printed to the debug output (qDebug), the construction is not aborted, though.
19184   
19185   The constructed statistical box can be added to the plot with QCustomPlot::addPlottable,
19186   QCustomPlot then takes ownership of the statistical box.
19187 */
19188 QCPStatisticalBox::QCPStatisticalBox(QCPAxis *keyAxis, QCPAxis *valueAxis) :
19189   QCPAbstractPlottable(keyAxis, valueAxis),
19190   mKey(0),
19191   mMinimum(0),
19192   mLowerQuartile(0),
19193   mMedian(0),
19194   mUpperQuartile(0),
19195   mMaximum(0)
19196 {
19197   setOutlierStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, Qt::blue, 6));
19198   setWhiskerWidth(0.2);
19199   setWidth(0.5);
19200   
19201   setPen(QPen(Qt::black));
19202   setSelectedPen(QPen(Qt::blue, 2.5));
19203   setMedianPen(QPen(Qt::black, 3, Qt::SolidLine, Qt::FlatCap));
19204   setWhiskerPen(QPen(Qt::black, 0, Qt::DashLine, Qt::FlatCap));
19205   setWhiskerBarPen(QPen(Qt::black));
19206   setBrush(Qt::NoBrush);
19207   setSelectedBrush(Qt::NoBrush);
19208 }
19209
19210 /*!
19211   Sets the key coordinate of the statistical box.
19212 */
19213 void QCPStatisticalBox::setKey(double key)
19214 {
19215   mKey = key;
19216 }
19217
19218 /*!
19219   Sets the parameter "minimum" of the statistical box plot. This is the position of the lower
19220   whisker, typically the minimum measurement of the sample that's not considered an outlier.
19221   
19222   \see setMaximum, setWhiskerPen, setWhiskerBarPen, setWhiskerWidth
19223 */
19224 void QCPStatisticalBox::setMinimum(double value)
19225 {
19226   mMinimum = value;
19227 }
19228
19229 /*!
19230   Sets the parameter "lower Quartile" of the statistical box plot. This is the lower end of the
19231   box. The lower and the upper quartiles are the two statistical quartiles around the median of the
19232   sample, they contain 50% of the sample data.
19233   
19234   \see setUpperQuartile, setPen, setBrush, setWidth
19235 */
19236 void QCPStatisticalBox::setLowerQuartile(double value)
19237 {
19238   mLowerQuartile = value;
19239 }
19240
19241 /*!
19242   Sets the parameter "median" of the statistical box plot. This is the value of the median mark
19243   inside the quartile box. The median separates the sample data in half (50% of the sample data is
19244   below/above the median).
19245   
19246   \see setMedianPen
19247 */
19248 void QCPStatisticalBox::setMedian(double value)
19249 {
19250   mMedian = value;
19251 }
19252
19253 /*!
19254   Sets the parameter "upper Quartile" of the statistical box plot. This is the upper end of the
19255   box. The lower and the upper quartiles are the two statistical quartiles around the median of the
19256   sample, they contain 50% of the sample data.
19257   
19258   \see setLowerQuartile, setPen, setBrush, setWidth
19259 */
19260 void QCPStatisticalBox::setUpperQuartile(double value)
19261 {
19262   mUpperQuartile = value;
19263 }
19264
19265 /*!
19266   Sets the parameter "maximum" of the statistical box plot. This is the position of the upper
19267   whisker, typically the maximum measurement of the sample that's not considered an outlier.
19268   
19269   \see setMinimum, setWhiskerPen, setWhiskerBarPen, setWhiskerWidth
19270 */
19271 void QCPStatisticalBox::setMaximum(double value)
19272 {
19273   mMaximum = value;
19274 }
19275
19276 /*!
19277   Sets a vector of outlier values that will be drawn as scatters. Any data points in the sample
19278   that are not within the whiskers (\ref setMinimum, \ref setMaximum) should be considered outliers
19279   and displayed as such.
19280   
19281   \see setOutlierStyle
19282 */
19283 void QCPStatisticalBox::setOutliers(const QVector<double> &values)
19284 {
19285   mOutliers = values;
19286 }
19287
19288 /*!
19289   Sets all parameters of the statistical box plot at once.
19290   
19291   \see setKey, setMinimum, setLowerQuartile, setMedian, setUpperQuartile, setMaximum
19292 */
19293 void QCPStatisticalBox::setData(double key, double minimum, double lowerQuartile, double median, double upperQuartile, double maximum)
19294 {
19295   setKey(key);
19296   setMinimum(minimum);
19297   setLowerQuartile(lowerQuartile);
19298   setMedian(median);
19299   setUpperQuartile(upperQuartile);
19300   setMaximum(maximum);
19301 }
19302
19303 /*!
19304   Sets the width of the box in key coordinates.
19305   
19306   \see setWhiskerWidth
19307 */
19308 void QCPStatisticalBox::setWidth(double width)
19309 {
19310   mWidth = width;
19311 }
19312
19313 /*!
19314   Sets the width of the whiskers (\ref setMinimum, \ref setMaximum) in key coordinates.
19315   
19316   \see setWidth
19317 */
19318 void QCPStatisticalBox::setWhiskerWidth(double width)
19319 {
19320   mWhiskerWidth = width;
19321 }
19322
19323 /*!
19324   Sets the pen used for drawing the whisker backbone (That's the line parallel to the value axis).
19325   
19326   Make sure to set the \a pen capStyle to Qt::FlatCap to prevent the whisker backbone from reaching
19327   a few pixels past the whisker bars, when using a non-zero pen width.
19328   
19329   \see setWhiskerBarPen
19330 */
19331 void QCPStatisticalBox::setWhiskerPen(const QPen &pen)
19332 {
19333   mWhiskerPen = pen;
19334 }
19335
19336 /*!
19337   Sets the pen used for drawing the whisker bars (Those are the lines parallel to the key axis at
19338   each end of the whisker backbone).
19339   
19340   \see setWhiskerPen
19341 */
19342 void QCPStatisticalBox::setWhiskerBarPen(const QPen &pen)
19343 {
19344   mWhiskerBarPen = pen;
19345 }
19346
19347 /*!
19348   Sets the pen used for drawing the median indicator line inside the statistical box.
19349 */
19350 void QCPStatisticalBox::setMedianPen(const QPen &pen)
19351 {
19352   mMedianPen = pen;
19353 }
19354
19355 /*!
19356   Sets the appearance of the outlier data points.
19357   
19358   \see setOutliers
19359 */
19360 void QCPStatisticalBox::setOutlierStyle(const QCPScatterStyle &style)
19361 {
19362   mOutlierStyle = style;
19363 }
19364
19365 /* inherits documentation from base class */
19366 void QCPStatisticalBox::clearData()
19367 {
19368   setOutliers(QVector<double>());
19369   setKey(0);
19370   setMinimum(0);
19371   setLowerQuartile(0);
19372   setMedian(0);
19373   setUpperQuartile(0);
19374   setMaximum(0);
19375 }
19376
19377 /* inherits documentation from base class */
19378 double QCPStatisticalBox::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
19379 {
19380   Q_UNUSED(details)
19381   if (onlySelectable && !mSelectable)
19382     return -1;
19383   if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
19384   
19385   if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()))
19386   {
19387     double posKey, posValue;
19388     pixelsToCoords(pos, posKey, posValue);
19389     // quartile box:
19390     QCPRange keyRange(mKey-mWidth*0.5, mKey+mWidth*0.5);
19391     QCPRange valueRange(mLowerQuartile, mUpperQuartile);
19392     if (keyRange.contains(posKey) && valueRange.contains(posValue))
19393       return mParentPlot->selectionTolerance()*0.99;
19394     
19395     // min/max whiskers:
19396     if (QCPRange(mMinimum, mMaximum).contains(posValue))
19397       return qAbs(mKeyAxis.data()->coordToPixel(mKey)-mKeyAxis.data()->coordToPixel(posKey));
19398   }
19399   return -1;
19400 }
19401
19402 /* inherits documentation from base class */
19403 void QCPStatisticalBox::draw(QCPPainter *painter)
19404 {
19405   if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
19406
19407   // check data validity if flag set:
19408 #ifdef QCUSTOMPLOT_CHECK_DATA
19409   if (QCP::isInvalidData(mKey, mMedian) ||
19410       QCP::isInvalidData(mLowerQuartile, mUpperQuartile) ||
19411       QCP::isInvalidData(mMinimum, mMaximum))
19412     qDebug() << Q_FUNC_INFO << "Data point at" << mKey << "of drawn range has invalid data." << "Plottable name:" << name();
19413   for (int i=0; i<mOutliers.size(); ++i)
19414     if (QCP::isInvalidData(mOutliers.at(i)))
19415       qDebug() << Q_FUNC_INFO << "Data point outlier at" << mKey << "of drawn range invalid." << "Plottable name:" << name();
19416 #endif
19417   
19418   QRectF quartileBox;
19419   drawQuartileBox(painter, &quartileBox);
19420   
19421   painter->save();
19422   painter->setClipRect(quartileBox, Qt::IntersectClip);
19423   drawMedian(painter);
19424   painter->restore();
19425   
19426   drawWhiskers(painter);
19427   drawOutliers(painter);
19428 }
19429
19430 /* inherits documentation from base class */
19431 void QCPStatisticalBox::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const
19432 {
19433   // draw filled rect:
19434   applyDefaultAntialiasingHint(painter);
19435   painter->setPen(mPen);
19436   painter->setBrush(mBrush);
19437   QRectF r = QRectF(0, 0, rect.width()*0.67, rect.height()*0.67);
19438   r.moveCenter(rect.center());
19439   painter->drawRect(r);
19440 }
19441
19442 /*! \internal
19443   
19444   Draws the quartile box. \a box is an output parameter that returns the quartile box (in pixel
19445   coordinates) which is used to set the clip rect of the painter before calling \ref drawMedian (so
19446   the median doesn't draw outside the quartile box).
19447 */
19448 void QCPStatisticalBox::drawQuartileBox(QCPPainter *painter, QRectF *quartileBox) const
19449 {
19450   QRectF box;
19451   box.setTopLeft(coordsToPixels(mKey-mWidth*0.5, mUpperQuartile));
19452   box.setBottomRight(coordsToPixels(mKey+mWidth*0.5, mLowerQuartile));
19453   applyDefaultAntialiasingHint(painter);
19454   painter->setPen(mainPen());
19455   painter->setBrush(mainBrush());
19456   painter->drawRect(box);
19457   if (quartileBox)
19458     *quartileBox = box;
19459 }
19460
19461 /*! \internal
19462   
19463   Draws the median line inside the quartile box.
19464 */
19465 void QCPStatisticalBox::drawMedian(QCPPainter *painter) const
19466 {
19467   QLineF medianLine;
19468   medianLine.setP1(coordsToPixels(mKey-mWidth*0.5, mMedian));
19469   medianLine.setP2(coordsToPixels(mKey+mWidth*0.5, mMedian));
19470   applyDefaultAntialiasingHint(painter);
19471   painter->setPen(mMedianPen);
19472   painter->drawLine(medianLine);
19473 }
19474
19475 /*! \internal
19476   
19477   Draws both whisker backbones and bars.
19478 */
19479 void QCPStatisticalBox::drawWhiskers(QCPPainter *painter) const
19480 {
19481   QLineF backboneMin, backboneMax, barMin, barMax;
19482   backboneMax.setPoints(coordsToPixels(mKey, mUpperQuartile), coordsToPixels(mKey, mMaximum));
19483   backboneMin.setPoints(coordsToPixels(mKey, mLowerQuartile), coordsToPixels(mKey, mMinimum));
19484   barMax.setPoints(coordsToPixels(mKey-mWhiskerWidth*0.5, mMaximum), coordsToPixels(mKey+mWhiskerWidth*0.5, mMaximum));
19485   barMin.setPoints(coordsToPixels(mKey-mWhiskerWidth*0.5, mMinimum), coordsToPixels(mKey+mWhiskerWidth*0.5, mMinimum));
19486   applyErrorBarsAntialiasingHint(painter);
19487   painter->setPen(mWhiskerPen);
19488   painter->drawLine(backboneMin);
19489   painter->drawLine(backboneMax);
19490   painter->setPen(mWhiskerBarPen);
19491   painter->drawLine(barMin);
19492   painter->drawLine(barMax);
19493 }
19494
19495 /*! \internal
19496   
19497   Draws the outlier scatter points.
19498 */
19499 void QCPStatisticalBox::drawOutliers(QCPPainter *painter) const
19500 {
19501   applyScattersAntialiasingHint(painter);
19502   mOutlierStyle.applyTo(painter, mPen);
19503   for (int i=0; i<mOutliers.size(); ++i)
19504     mOutlierStyle.drawShape(painter, coordsToPixels(mKey, mOutliers.at(i)));
19505 }
19506
19507 /* inherits documentation from base class */
19508 QCPRange QCPStatisticalBox::getKeyRange(bool &foundRange, SignDomain inSignDomain) const
19509 {
19510   foundRange = true;
19511   if (inSignDomain == sdBoth)
19512   {
19513     return QCPRange(mKey-mWidth*0.5, mKey+mWidth*0.5);
19514   } else if (inSignDomain == sdNegative)
19515   {
19516     if (mKey+mWidth*0.5 < 0)
19517       return QCPRange(mKey-mWidth*0.5, mKey+mWidth*0.5);
19518     else if (mKey < 0)
19519       return QCPRange(mKey-mWidth*0.5, mKey);
19520     else
19521     {
19522       foundRange = false;
19523       return QCPRange();
19524     }
19525   } else if (inSignDomain == sdPositive)
19526   {
19527     if (mKey-mWidth*0.5 > 0)
19528       return QCPRange(mKey-mWidth*0.5, mKey+mWidth*0.5);
19529     else if (mKey > 0)
19530       return QCPRange(mKey, mKey+mWidth*0.5);
19531     else
19532     {
19533       foundRange = false;
19534       return QCPRange();
19535     }
19536   }
19537   foundRange = false;
19538   return QCPRange();
19539 }
19540
19541 /* inherits documentation from base class */
19542 QCPRange QCPStatisticalBox::getValueRange(bool &foundRange, SignDomain inSignDomain) const
19543 {
19544   QVector<double> values; // values that must be considered (i.e. all outliers and the five box-parameters)
19545   values.reserve(mOutliers.size() + 5);
19546   values << mMaximum << mUpperQuartile << mMedian << mLowerQuartile << mMinimum;
19547   values << mOutliers;
19548   // go through values and find the ones in legal range:
19549   bool haveUpper = false;
19550   bool haveLower = false;
19551   double upper = 0;
19552   double lower = 0;
19553   for (int i=0; i<values.size(); ++i)
19554   {
19555     if ((inSignDomain == sdNegative && values.at(i) < 0) ||
19556         (inSignDomain == sdPositive && values.at(i) > 0) ||
19557         (inSignDomain == sdBoth))
19558     {
19559       if (values.at(i) > upper || !haveUpper)
19560       {
19561         upper = values.at(i);
19562         haveUpper = true;
19563       }
19564       if (values.at(i) < lower || !haveLower)
19565       {
19566         lower = values.at(i);
19567         haveLower = true;
19568       }
19569     }
19570   }
19571   // return the bounds if we found some sensible values:
19572   if (haveLower && haveUpper)
19573   {
19574     foundRange = true;
19575     return QCPRange(lower, upper);
19576   } else // might happen if all values are in other sign domain
19577   {
19578     foundRange = false;
19579     return QCPRange();
19580   }
19581 }
19582
19583
19584 ////////////////////////////////////////////////////////////////////////////////////////////////////
19585 //////////////////// QCPColorMapData
19586 ////////////////////////////////////////////////////////////////////////////////////////////////////
19587
19588 /*! \class QCPColorMapData
19589   \brief Holds the two-dimensional data of a QCPColorMap plottable.
19590   
19591   This class is a data storage for \ref QCPColorMap. It holds a two-dimensional array, which \ref
19592   QCPColorMap then displays as a 2D image in the plot, where the array values are represented by a
19593   color, depending on the value.
19594   
19595   The size of the array can be controlled via \ref setSize (or \ref setKeySize, \ref setValueSize).
19596   Which plot coordinates these cells correspond to can be configured with \ref setRange (or \ref
19597   setKeyRange, \ref setValueRange).
19598   
19599   The data cells can be accessed in two ways: They can be directly addressed by an integer index
19600   with \ref setCell. This is the fastest method. Alternatively, they can be addressed by their plot
19601   coordinate with \ref setData. plot coordinate to cell index transformations and vice versa are
19602   provided by the functions \ref coordToCell and \ref cellToCoord.
19603   
19604   This class also buffers the minimum and maximum values that are in the data set, to provide
19605   QCPColorMap::rescaleDataRange with the necessary information quickly. Setting a cell to a value
19606   that is greater than the current maximum increases this maximum to the new value. However,
19607   setting the cell that currently holds the maximum value to a smaller value doesn't decrease the
19608   maximum again, because finding the true new maximum would require going through the entire data
19609   array, which might be time consuming. The same holds for the data minimum. This functionality is
19610   given by \ref recalculateDataBounds, such that you can decide when it is sensible to find the
19611   true current minimum and maximum. The method QCPColorMap::rescaleDataRange offers a convenience
19612   parameter \a recalculateDataBounds which may be set to true to automatically call \ref
19613   recalculateDataBounds internally.
19614 */
19615
19616 /* start of documentation of inline functions */
19617
19618 /*! \fn bool QCPColorMapData::isEmpty() const
19619   
19620   Returns whether this instance carries no data. This is equivalent to having a size where at least
19621   one of the dimensions is 0 (see \ref setSize).
19622 */
19623
19624 /* end of documentation of inline functions */
19625
19626 /*!
19627   Constructs a new QCPColorMapData instance. The instance has \a keySize cells in the key direction
19628   and \a valueSize cells in the value direction. These cells will be displayed by the \ref QCPColorMap
19629   at the coordinates \a keyRange and \a valueRange.
19630   
19631   \see setSize, setKeySize, setValueSize, setRange, setKeyRange, setValueRange
19632 */
19633 QCPColorMapData::QCPColorMapData(int keySize, int valueSize, const QCPRange &keyRange, const QCPRange &valueRange) :
19634   mKeySize(0),
19635   mValueSize(0),
19636   mKeyRange(keyRange),
19637   mValueRange(valueRange),
19638   mIsEmpty(true),
19639   mData(0),
19640   mDataModified(true)
19641 {
19642   setSize(keySize, valueSize);
19643   fill(0);
19644 }
19645
19646 QCPColorMapData::~QCPColorMapData()
19647 {
19648   if (mData)
19649     delete[] mData;
19650 }
19651
19652 /*!
19653   Constructs a new QCPColorMapData instance copying the data and range of \a other.
19654 */
19655 QCPColorMapData::QCPColorMapData(const QCPColorMapData &other) :
19656   mKeySize(0),
19657   mValueSize(0),
19658   mIsEmpty(true),
19659   mData(0),
19660   mDataModified(true)
19661 {
19662   *this = other;
19663 }
19664
19665 /*!
19666   Overwrites this color map data instance with the data stored in \a other.
19667 */
19668 QCPColorMapData &QCPColorMapData::operator=(const QCPColorMapData &other)
19669 {
19670   if (&other != this)
19671   {
19672     const int keySize = other.keySize();
19673     const int valueSize = other.valueSize();
19674     setSize(keySize, valueSize);
19675     setRange(other.keyRange(), other.valueRange());
19676     if (!mIsEmpty)
19677       memcpy(mData, other.mData, sizeof(mData[0])*keySize*valueSize);
19678     mDataBounds = other.mDataBounds;
19679     mDataModified = true;
19680   }
19681   return *this;
19682 }
19683
19684 /* undocumented getter */
19685 double QCPColorMapData::data(double key, double value)
19686 {
19687   int keyCell = (key-mKeyRange.lower)/(mKeyRange.upper-mKeyRange.lower)*(mKeySize-1)+0.5;
19688   int valueCell = (value-mValueRange.lower)/(mValueRange.upper-mValueRange.lower)*(mValueSize-1)+0.5;
19689   if (keyCell >= 0 && keyCell < mKeySize && valueCell >= 0 && valueCell < mValueSize)
19690     return mData[valueCell*mKeySize + keyCell];
19691   else
19692     return 0;
19693 }
19694
19695 /* undocumented getter */
19696 double QCPColorMapData::cell(int keyIndex, int valueIndex)
19697 {
19698   if (keyIndex >= 0 && keyIndex < mKeySize && valueIndex >= 0 && valueIndex < mValueSize)
19699     return mData[valueIndex*mKeySize + keyIndex];
19700   else
19701     return 0;
19702 }
19703
19704 /*!
19705   Resizes the data array to have \a keySize cells in the key dimension and \a valueSize cells in
19706   the value dimension.
19707
19708   The current data is discarded and the map cells are set to 0, unless the map had already the
19709   requested size.
19710   
19711   Setting at least one of \a keySize or \a valueSize to zero frees the internal data array and \ref
19712   isEmpty returns true.
19713
19714   \see setRange, setKeySize, setValueSize
19715 */
19716 void QCPColorMapData::setSize(int keySize, int valueSize)
19717 {
19718   if (keySize != mKeySize || valueSize != mValueSize)
19719   {
19720     mKeySize = keySize;
19721     mValueSize = valueSize;
19722     if (mData)
19723       delete[] mData;
19724     mIsEmpty = mKeySize == 0 || mValueSize == 0;
19725     if (!mIsEmpty)
19726     {
19727 #ifdef __EXCEPTIONS
19728       try { // 2D arrays get memory intensive fast. So if the allocation fails, at least output debug message
19729 #endif
19730       mData = new double[mKeySize*mValueSize];
19731 #ifdef __EXCEPTIONS
19732       } catch (...) { mData = 0; }
19733 #endif
19734       if (mData)
19735         fill(0);
19736       else
19737         qDebug() << Q_FUNC_INFO << "out of memory for data dimensions "<< mKeySize << "*" << mValueSize;
19738     } else
19739       mData = 0;
19740     mDataModified = true;
19741   }
19742 }
19743
19744 /*!
19745   Resizes the data array to have \a keySize cells in the key dimension.
19746
19747   The current data is discarded and the map cells are set to 0, unless the map had already the
19748   requested size.
19749   
19750   Setting \a keySize to zero frees the internal data array and \ref isEmpty returns true.
19751
19752   \see setKeyRange, setSize, setValueSize
19753 */
19754 void QCPColorMapData::setKeySize(int keySize)
19755 {
19756   setSize(keySize, mValueSize);
19757 }
19758
19759 /*!
19760   Resizes the data array to have \a valueSize cells in the value dimension.
19761
19762   The current data is discarded and the map cells are set to 0, unless the map had already the
19763   requested size.
19764   
19765   Setting \a valueSize to zero frees the internal data array and \ref isEmpty returns true.
19766
19767   \see setValueRange, setSize, setKeySize
19768 */
19769 void QCPColorMapData::setValueSize(int valueSize)
19770 {
19771   setSize(mKeySize, valueSize);
19772 }
19773
19774 /*!
19775   Sets the coordinate ranges the data shall be distributed over. This defines the rectangular area
19776   covered by the color map in plot coordinates.
19777   
19778   The outer cells will be centered on the range boundaries given to this function. For example, if
19779   the key size (\ref setKeySize) is 3 and \a keyRange is set to <tt>QCPRange(2, 3)</tt> there will
19780   be cells centered on the key coordinates 2, 2.5 and 3.
19781  
19782   \see setSize
19783 */
19784 void QCPColorMapData::setRange(const QCPRange &keyRange, const QCPRange &valueRange)
19785 {
19786   setKeyRange(keyRange);
19787   setValueRange(valueRange);
19788 }
19789
19790 /*!
19791   Sets the coordinate range the data shall be distributed over in the key dimension. Together with
19792   the value range, This defines the rectangular area covered by the color map in plot coordinates.
19793   
19794   The outer cells will be centered on the range boundaries given to this function. For example, if
19795   the key size (\ref setKeySize) is 3 and \a keyRange is set to <tt>QCPRange(2, 3)</tt> there will
19796   be cells centered on the key coordinates 2, 2.5 and 3.
19797  
19798   \see setRange, setValueRange, setSize
19799 */
19800 void QCPColorMapData::setKeyRange(const QCPRange &keyRange)
19801 {
19802   mKeyRange = keyRange;
19803 }
19804
19805 /*!
19806   Sets the coordinate range the data shall be distributed over in the value dimension. Together with
19807   the key range, This defines the rectangular area covered by the color map in plot coordinates.
19808   
19809   The outer cells will be centered on the range boundaries given to this function. For example, if
19810   the value size (\ref setValueSize) is 3 and \a valueRange is set to <tt>QCPRange(2, 3)</tt> there
19811   will be cells centered on the value coordinates 2, 2.5 and 3.
19812  
19813   \see setRange, setKeyRange, setSize
19814 */
19815 void QCPColorMapData::setValueRange(const QCPRange &valueRange)
19816 {
19817   mValueRange = valueRange;
19818 }
19819
19820 /*!
19821   Sets the data of the cell, which lies at the plot coordinates given by \a key and \a value, to \a
19822   z.
19823   
19824   \note The QCPColorMap always displays the data at equal key/value intervals, even if the key or
19825   value axis is set to a logarithmic scaling. If you want to use QCPColorMap with logarithmic axes,
19826   you shouldn't use the \ref QCPColorMapData::setData method as it uses a linear transformation to
19827   determine the cell index. Rather directly access the cell index with \ref
19828   QCPColorMapData::setCell.
19829  
19830   \see setCell, setRange
19831 */
19832 void QCPColorMapData::setData(double key, double value, double z)
19833 {
19834   int keyCell = (key-mKeyRange.lower)/(mKeyRange.upper-mKeyRange.lower)*(mKeySize-1)+0.5;
19835   int valueCell = (value-mValueRange.lower)/(mValueRange.upper-mValueRange.lower)*(mValueSize-1)+0.5;
19836   if (keyCell >= 0 && keyCell < mKeySize && valueCell >= 0 && valueCell < mValueSize)
19837   {
19838     mData[valueCell*mKeySize + keyCell] = z;
19839     if (z < mDataBounds.lower)
19840       mDataBounds.lower = z;
19841     if (z > mDataBounds.upper)
19842       mDataBounds.upper = z;
19843      mDataModified = true;
19844   }
19845 }
19846
19847 /*!
19848   Sets the data of the cell with indices \a keyIndex and \a valueIndex to \a z. The indices
19849   enumerate the cells starting from zero, up to the map's size-1 in the respective dimension (see
19850   \ref setSize).
19851   
19852   In the standard plot configuration (horizontal key axis and vertical value axis, both not
19853   range-reversed), the cell with indices (0, 0) is in the bottom left corner and the cell with
19854   indices (keySize-1, valueSize-1) is in the top right corner of the color map.
19855   
19856   \see setData, setSize
19857 */
19858 void QCPColorMapData::setCell(int keyIndex, int valueIndex, double z)
19859 {
19860   if (keyIndex >= 0 && keyIndex < mKeySize && valueIndex >= 0 && valueIndex < mValueSize)
19861   {
19862     mData[valueIndex*mKeySize + keyIndex] = z;
19863     if (z < mDataBounds.lower)
19864       mDataBounds.lower = z;
19865     if (z > mDataBounds.upper)
19866       mDataBounds.upper = z;
19867      mDataModified = true;
19868   }
19869 }
19870
19871 /*!
19872   Goes through the data and updates the buffered minimum and maximum data values.
19873   
19874   Calling this method is only advised if you are about to call \ref QCPColorMap::rescaleDataRange
19875   and can not guarantee that the cells holding the maximum or minimum data haven't been overwritten
19876   with a smaller or larger value respectively, since the buffered maximum/minimum values have been
19877   updated the last time. Why this is the case is explained in the class description (\ref
19878   QCPColorMapData).
19879   
19880   Note that the method \ref QCPColorMap::rescaleDataRange provides a parameter \a
19881   recalculateDataBounds for convenience. Setting this to true will call this method for you, before
19882   doing the rescale.
19883 */
19884 void QCPColorMapData::recalculateDataBounds()
19885 {
19886   if (mKeySize > 0 && mValueSize > 0)
19887   {
19888     double minHeight = mData[0];
19889     double maxHeight = mData[0];
19890     const int dataCount = mValueSize*mKeySize;
19891     for (int i=0; i<dataCount; ++i)
19892     {
19893       if (mData[i] > maxHeight)
19894         maxHeight = mData[i];
19895       if (mData[i] < minHeight)
19896         minHeight = mData[i];
19897     }
19898     mDataBounds.lower = minHeight;
19899     mDataBounds.upper = maxHeight;
19900   }
19901 }
19902
19903 /*!
19904   Frees the internal data memory.
19905   
19906   This is equivalent to calling \ref setSize "setSize(0, 0)".
19907 */
19908 void QCPColorMapData::clear()
19909 {
19910   setSize(0, 0);
19911 }
19912
19913 /*!
19914   Sets all cells to the value \a z.
19915 */
19916 void QCPColorMapData::fill(double z)
19917 {
19918   const int dataCount = mValueSize*mKeySize;
19919   for (int i=0; i<dataCount; ++i)
19920     mData[i] = z;
19921   mDataBounds = QCPRange(z, z);
19922   mDataModified = true;
19923 }
19924
19925 /*!
19926   Transforms plot coordinates given by \a key and \a value to cell indices of this QCPColorMapData
19927   instance. The resulting cell indices are returned via the output parameters \a keyIndex and \a
19928   valueIndex.
19929   
19930   The retrieved key/value cell indices can then be used for example with \ref setCell.
19931   
19932   If you are only interested in a key or value index, you may pass 0 as \a valueIndex or \a
19933   keyIndex.
19934   
19935   \note The QCPColorMap always displays the data at equal key/value intervals, even if the key or
19936   value axis is set to a logarithmic scaling. If you want to use QCPColorMap with logarithmic axes,
19937   you shouldn't use the \ref QCPColorMapData::coordToCell method as it uses a linear transformation to
19938   determine the cell index.
19939   
19940   \see cellToCoord, QCPAxis::coordToPixel
19941 */
19942 void QCPColorMapData::coordToCell(double key, double value, int *keyIndex, int *valueIndex) const
19943 {
19944   if (keyIndex)
19945     *keyIndex = (key-mKeyRange.lower)/(mKeyRange.upper-mKeyRange.lower)*(mKeySize-1)+0.5;
19946   if (valueIndex)
19947     *valueIndex = (value-mValueRange.lower)/(mValueRange.upper-mValueRange.lower)*(mValueSize-1)+0.5;
19948 }
19949
19950 /*!
19951   Transforms cell indices given by \a keyIndex and \a valueIndex to cell indices of this QCPColorMapData
19952   instance. The resulting coordinates are returned via the output parameters \a key and \a
19953   value.
19954   
19955   If you are only interested in a key or value coordinate, you may pass 0 as \a key or \a
19956   value.
19957   
19958   \note The QCPColorMap always displays the data at equal key/value intervals, even if the key or
19959   value axis is set to a logarithmic scaling. If you want to use QCPColorMap with logarithmic axes,
19960   you shouldn't use the \ref QCPColorMapData::cellToCoord method as it uses a linear transformation to
19961   determine the cell index.
19962   
19963   \see coordToCell, QCPAxis::pixelToCoord
19964 */
19965 void QCPColorMapData::cellToCoord(int keyIndex, int valueIndex, double *key, double *value) const
19966 {
19967   if (key)
19968     *key = keyIndex/(double)(mKeySize-1)*(mKeyRange.upper-mKeyRange.lower)+mKeyRange.lower;
19969   if (value)
19970     *value = valueIndex/(double)(mValueSize-1)*(mValueRange.upper-mValueRange.lower)+mValueRange.lower;
19971 }
19972
19973
19974 ////////////////////////////////////////////////////////////////////////////////////////////////////
19975 //////////////////// QCPColorMap
19976 ////////////////////////////////////////////////////////////////////////////////////////////////////
19977
19978 /*! \class QCPColorMap
19979   \brief A plottable representing a two-dimensional color map in a plot.
19980
19981   \image html QCPColorMap.png
19982   
19983   The data is stored in the class \ref QCPColorMapData, which can be accessed via the data()
19984   method.
19985   
19986   A color map has three dimensions to represent a data point: The \a key dimension, the \a value
19987   dimension and the \a data dimension. As with other plottables such as graphs, \a key and \a value
19988   correspond to two orthogonal axes on the QCustomPlot surface that you specify in the QCPColorMap
19989   constructor. The \a data dimension however is encoded as the color of the point at (\a key, \a
19990   value).
19991
19992   Set the number of points (or \a cells) in the key/value dimension via \ref
19993   QCPColorMapData::setSize. The plot coordinate range over which these points will be displayed is
19994   specified via \ref QCPColorMapData::setRange. The first cell will be centered on the lower range
19995   boundary and the last cell will be centered on the upper range boundary. The data can be set by
19996   either accessing the cells directly with QCPColorMapData::setCell or by addressing the cells via
19997   their plot coordinates with \ref QCPColorMapData::setData. If possible, you should prefer
19998   setCell, since it doesn't need to do any coordinate transformation and thus performs a bit
19999   better.
20000   
20001   The cell with index (0, 0) is at the bottom left, if the color map uses normal (i.e. not reversed)
20002   key and value axes.
20003   
20004   To show the user which colors correspond to which \a data values, a \ref QCPColorScale is
20005   typically placed to the right of the axis rect. See the documentation there for details on how to
20006   add and use a color scale.
20007   
20008   \section appearance Changing the appearance
20009   
20010   The central part of the appearance is the color gradient, which can be specified via \ref
20011   setGradient. See the documentation of \ref QCPColorGradient for details on configuring a color
20012   gradient.
20013   
20014   The \a data range that is mapped to the colors of the gradient can be specified with \ref
20015   setDataRange. To make the data range encompass the whole data set minimum to maximum, call \ref
20016   rescaleDataRange.
20017   
20018   \section usage Usage
20019   
20020   Like all data representing objects in QCustomPlot, the QCPColorMap is a plottable
20021   (QCPAbstractPlottable). So the plottable-interface of QCustomPlot applies
20022   (QCustomPlot::plottable, QCustomPlot::addPlottable, QCustomPlot::removePlottable, etc.)
20023   
20024   Usually, you first create an instance and add it to the customPlot:
20025   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpcolormap-creation-1
20026   and then modify the properties of the newly created color map, e.g.:
20027   \snippet documentation/doc-code-snippets/mainwindow.cpp qcpcolormap-creation-2
20028   
20029   \note The QCPColorMap always displays the data at equal key/value intervals, even if the key or
20030   value axis is set to a logarithmic scaling. If you want to use QCPColorMap with logarithmic axes,
20031   you shouldn't use the \ref QCPColorMapData::setData method as it uses a linear transformation to
20032   determine the cell index. Rather directly access the cell index with \ref
20033   QCPColorMapData::setCell.
20034 */
20035
20036 /* start documentation of inline functions */
20037
20038 /*! \fn QCPColorMapData *QCPColorMap::data() const
20039   
20040   Returns a pointer to the internal data storage of type \ref QCPColorMapData. Access this to
20041   modify data points (cells) and the color map key/value range.
20042   
20043   \see setData
20044 */
20045
20046 /* end documentation of inline functions */
20047
20048 /* start documentation of signals */
20049
20050 /*! \fn void QCPColorMap::dataRangeChanged(QCPRange newRange);
20051   
20052   This signal is emitted when the data range changes.
20053   
20054   \see setDataRange
20055 */
20056
20057 /*! \fn void QCPColorMap::dataScaleTypeChanged(QCPAxis::ScaleType scaleType);
20058   
20059   This signal is emitted when the data scale type changes.
20060   
20061   \see setDataScaleType
20062 */
20063
20064 /*! \fn void QCPColorMap::gradientChanged(QCPColorGradient newGradient);
20065   
20066   This signal is emitted when the gradient changes.
20067   
20068   \see setGradient
20069 */
20070
20071 /* end documentation of signals */
20072
20073 /*!
20074   Constructs a color map with the specified \a keyAxis and \a valueAxis.
20075   
20076   The constructed QCPColorMap can be added to the plot with QCustomPlot::addPlottable, QCustomPlot
20077   then takes ownership of the color map.
20078 */
20079 QCPColorMap::QCPColorMap(QCPAxis *keyAxis, QCPAxis *valueAxis) :
20080   QCPAbstractPlottable(keyAxis, valueAxis),
20081   mDataScaleType(QCPAxis::stLinear),
20082   mMapData(new QCPColorMapData(10, 10, QCPRange(0, 5), QCPRange(0, 5))),
20083   mInterpolate(true),
20084   mTightBoundary(false),
20085   mMapImageInvalidated(true)
20086 {
20087 }
20088
20089 QCPColorMap::~QCPColorMap()
20090 {
20091   delete mMapData;
20092 }
20093
20094 /*!
20095   Replaces the current \ref data with the provided \a data.
20096   
20097   If \a copy is set to true, the \a data object will only be copied. if false, the color map
20098   takes ownership of the passed data and replaces the internal data pointer with it. This is
20099   significantly faster than copying for large datasets.
20100 */
20101 void QCPColorMap::setData(QCPColorMapData *data, bool copy)
20102 {
20103   if (mMapData == data)
20104   {
20105     qDebug() << Q_FUNC_INFO << "The data pointer is already in (and owned by) this plottable" << reinterpret_cast<quintptr>(data);
20106     return;
20107   }
20108   if (copy)
20109   {
20110     *mMapData = *data;
20111   } else
20112   {
20113     delete mMapData;
20114     mMapData = data;
20115   }
20116   mMapImageInvalidated = true;
20117 }
20118
20119 /*!
20120   Sets the data range of this color map to \a dataRange. The data range defines which data values
20121   are mapped to the color gradient.
20122   
20123   To make the data range span the full range of the data set, use \ref rescaleDataRange.
20124   
20125   \see QCPColorScale::setDataRange
20126 */
20127 void QCPColorMap::setDataRange(const QCPRange &dataRange)
20128 {
20129   if (!QCPRange::validRange(dataRange)) return;
20130   if (mDataRange.lower != dataRange.lower || mDataRange.upper != dataRange.upper)
20131   {
20132     if (mDataScaleType == QCPAxis::stLogarithmic)
20133       mDataRange = dataRange.sanitizedForLogScale();
20134     else
20135       mDataRange = dataRange.sanitizedForLinScale();
20136     mMapImageInvalidated = true;
20137     emit dataRangeChanged(mDataRange);
20138   }
20139 }
20140
20141 /*!
20142   Sets whether the data is correlated with the color gradient linearly or logarithmically.
20143   
20144   \see QCPColorScale::setDataScaleType
20145 */
20146 void QCPColorMap::setDataScaleType(QCPAxis::ScaleType scaleType)
20147 {
20148   if (mDataScaleType != scaleType)
20149   {
20150     mDataScaleType = scaleType;
20151     mMapImageInvalidated = true;
20152     emit dataScaleTypeChanged(mDataScaleType);
20153     if (mDataScaleType == QCPAxis::stLogarithmic)
20154       setDataRange(mDataRange.sanitizedForLogScale());
20155   }
20156 }
20157
20158 /*!
20159   Sets the color gradient that is used to represent the data. For more details on how to create an
20160   own gradient or use one of the preset gradients, see \ref QCPColorGradient.
20161   
20162   The colors defined by the gradient will be used to represent data values in the currently set
20163   data range, see \ref setDataRange. Data points that are outside this data range will either be
20164   colored uniformly with the respective gradient boundary color, or the gradient will repeat,
20165   depending on \ref QCPColorGradient::setPeriodic.
20166   
20167   \see QCPColorScale::setGradient
20168 */
20169 void QCPColorMap::setGradient(const QCPColorGradient &gradient)
20170 {
20171   if (mGradient != gradient)
20172   {
20173     mGradient = gradient;
20174     mMapImageInvalidated = true;
20175     emit gradientChanged(mGradient);
20176   }
20177 }
20178
20179 /*!
20180   Sets whether the color map image shall use bicubic interpolation when displaying the color map
20181   shrinked or expanded, and not at a 1:1 pixel-to-data scale.
20182   
20183   \image html QCPColorMap-interpolate.png "A 10*10 color map, with interpolation and without interpolation enabled"
20184 */
20185 void QCPColorMap::setInterpolate(bool enabled)
20186 {
20187   mInterpolate = enabled;
20188   mMapImageInvalidated = true; // because oversampling factors might need to change
20189 }
20190
20191 /*!
20192   Sets whether the outer most data rows and columns are clipped to the specified key and value
20193   range (see \ref QCPColorMapData::setKeyRange, \ref QCPColorMapData::setValueRange).
20194   
20195   if \a enabled is set to false, the data points at the border of the color map are drawn with the
20196   same width and height as all other data points. Since the data points are represented by
20197   rectangles of one color centered on the data coordinate, this means that the shown color map
20198   extends by half a data point over the specified key/value range in each direction.
20199   
20200   \image html QCPColorMap-tightboundary.png "A color map, with tight boundary enabled and disabled"
20201 */
20202 void QCPColorMap::setTightBoundary(bool enabled)
20203 {
20204   mTightBoundary = enabled;
20205 }
20206
20207 /*!
20208   Associates the color scale \a colorScale with this color map.
20209   
20210   This means that both the color scale and the color map synchronize their gradient, data range and
20211   data scale type (\ref setGradient, \ref setDataRange, \ref setDataScaleType). Multiple color maps
20212   can be associated with one single color scale. This causes the color maps to also synchronize
20213   those properties, via the mutual color scale.
20214   
20215   This function causes the color map to adopt the current color gradient, data range and data scale
20216   type of \a colorScale. After this call, you may change these properties at either the color map
20217   or the color scale, and the setting will be applied to both.
20218   
20219   Pass 0 as \a colorScale to disconnect the color scale from this color map again.
20220 */
20221 void QCPColorMap::setColorScale(QCPColorScale *colorScale)
20222 {
20223   if (mColorScale) // unconnect signals from old color scale
20224   {
20225     disconnect(this, SIGNAL(dataRangeChanged(QCPRange)), mColorScale.data(), SLOT(setDataRange(QCPRange)));
20226     disconnect(this, SIGNAL(dataScaleTypeChanged(QCPAxis::ScaleType)), mColorScale.data(), SLOT(setDataScaleType(QCPAxis::ScaleType)));
20227     disconnect(this, SIGNAL(gradientChanged(QCPColorGradient)), mColorScale.data(), SLOT(setGradient(QCPColorGradient)));
20228     disconnect(mColorScale.data(), SIGNAL(dataRangeChanged(QCPRange)), this, SLOT(setDataRange(QCPRange)));
20229     disconnect(mColorScale.data(), SIGNAL(gradientChanged(QCPColorGradient)), this, SLOT(setGradient(QCPColorGradient)));
20230     disconnect(mColorScale.data(), SIGNAL(dataScaleTypeChanged(QCPAxis::ScaleType)), this, SLOT(setDataScaleType(QCPAxis::ScaleType)));
20231   }
20232   mColorScale = colorScale;
20233   if (mColorScale) // connect signals to new color scale
20234   {
20235     setGradient(mColorScale.data()->gradient());
20236     setDataRange(mColorScale.data()->dataRange());
20237     setDataScaleType(mColorScale.data()->dataScaleType());
20238     connect(this, SIGNAL(dataRangeChanged(QCPRange)), mColorScale.data(), SLOT(setDataRange(QCPRange)));
20239     connect(this, SIGNAL(dataScaleTypeChanged(QCPAxis::ScaleType)), mColorScale.data(), SLOT(setDataScaleType(QCPAxis::ScaleType)));
20240     connect(this, SIGNAL(gradientChanged(QCPColorGradient)), mColorScale.data(), SLOT(setGradient(QCPColorGradient)));
20241     connect(mColorScale.data(), SIGNAL(dataRangeChanged(QCPRange)), this, SLOT(setDataRange(QCPRange)));
20242     connect(mColorScale.data(), SIGNAL(gradientChanged(QCPColorGradient)), this, SLOT(setGradient(QCPColorGradient)));
20243     connect(mColorScale.data(), SIGNAL(dataScaleTypeChanged(QCPAxis::ScaleType)), this, SLOT(setDataScaleType(QCPAxis::ScaleType)));
20244   }
20245 }
20246
20247 /*!
20248   Sets the data range (\ref setDataRange) to span the minimum and maximum values that occur in the
20249   current data set. This corresponds to the \ref rescaleKeyAxis or \ref rescaleValueAxis methods,
20250   only for the third data dimension of the color map.
20251   
20252   The minimum and maximum values of the data set are buffered in the internal QCPColorMapData
20253   instance (\ref data). As data is updated via its \ref QCPColorMapData::setCell or \ref
20254   QCPColorMapData::setData, the buffered minimum and maximum values are updated, too. For
20255   performance reasons, however, they are only updated in an expanding fashion. So the buffered
20256   maximum can only increase and the buffered minimum can only decrease. In consequence, changes to
20257   the data that actually lower the maximum of the data set (by overwriting the cell holding the
20258   current maximum with a smaller value), aren't recognized and the buffered maximum overestimates
20259   the true maximum of the data set. The same happens for the buffered minimum. To recalculate the
20260   true minimum and maximum by explicitly looking at each cell, the method
20261   QCPColorMapData::recalculateDataBounds can be used. For convenience, setting the parameter \a
20262   recalculateDataBounds calls this method before setting the data range to the buffered minimum and
20263   maximum.
20264   
20265   \see setDataRange
20266 */
20267 void QCPColorMap::rescaleDataRange(bool recalculateDataBounds)
20268 {
20269   if (recalculateDataBounds)
20270     mMapData->recalculateDataBounds();
20271   setDataRange(mMapData->dataBounds());
20272 }
20273
20274 /*!
20275   Takes the current appearance of the color map and updates the legend icon, which is used to
20276   represent this color map in the legend (see \ref QCPLegend).
20277   
20278   The \a transformMode specifies whether the rescaling is done by a faster, low quality image
20279   scaling algorithm (Qt::FastTransformation) or by a slower, higher quality algorithm
20280   (Qt::SmoothTransformation).
20281   
20282   The current color map appearance is scaled down to \a thumbSize. Ideally, this should be equal to
20283   the size of the legend icon (see \ref QCPLegend::setIconSize). If it isn't exactly the configured
20284   legend icon size, the thumb will be rescaled during drawing of the legend item.
20285   
20286   \see setDataRange
20287 */
20288 void QCPColorMap::updateLegendIcon(Qt::TransformationMode transformMode, const QSize &thumbSize)
20289 {
20290   if (mMapImage.isNull() && !data()->isEmpty())
20291     updateMapImage(); // try to update map image if it's null (happens if no draw has happened yet)
20292   
20293   if (!mMapImage.isNull()) // might still be null, e.g. if data is empty, so check here again
20294   {
20295     bool mirrorX = (keyAxis()->orientation() == Qt::Horizontal ? keyAxis() : valueAxis())->rangeReversed();
20296     bool mirrorY = (valueAxis()->orientation() == Qt::Vertical ? valueAxis() : keyAxis())->rangeReversed();
20297     mLegendIcon = QPixmap::fromImage(mMapImage.mirrored(mirrorX, mirrorY)).scaled(thumbSize, Qt::KeepAspectRatio, transformMode);
20298   }
20299 }
20300
20301 /*!
20302   Clears the colormap data by calling \ref QCPColorMapData::clear() on the internal data. This also
20303   resizes the map to 0x0 cells.
20304 */
20305 void QCPColorMap::clearData()
20306 {
20307   mMapData->clear();
20308 }
20309
20310 /* inherits documentation from base class */
20311 double QCPColorMap::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
20312 {
20313   Q_UNUSED(details)
20314   if (onlySelectable && !mSelectable)
20315     return -1;
20316   if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
20317   
20318   if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()))
20319   {
20320     double posKey, posValue;
20321     pixelsToCoords(pos, posKey, posValue);
20322     if (mMapData->keyRange().contains(posKey) && mMapData->valueRange().contains(posValue))
20323       return mParentPlot->selectionTolerance()*0.99;
20324   }
20325   return -1;
20326 }
20327
20328 /*! \internal
20329   
20330   Updates the internal map image buffer by going through the internal \ref QCPColorMapData and
20331   turning the data values into color pixels with \ref QCPColorGradient::colorize.
20332   
20333   This method is called by \ref QCPColorMap::draw if either the data has been modified or the map image
20334   has been invalidated for a different reason (e.g. a change of the data range with \ref
20335   setDataRange).
20336   
20337   If the map cell count is low, the image created will be oversampled in order to avoid a
20338   QPainter::drawImage bug which makes inner pixel boundaries jitter when stretch-drawing images
20339   without smooth transform enabled. Accordingly, oversampling isn't performed if \ref
20340   setInterpolate is true.
20341 */
20342 void QCPColorMap::updateMapImage()
20343 {
20344   QCPAxis *keyAxis = mKeyAxis.data();
20345   if (!keyAxis) return;
20346   if (mMapData->isEmpty()) return;
20347   
20348   const int keySize = mMapData->keySize();
20349   const int valueSize = mMapData->valueSize();
20350   int keyOversamplingFactor = mInterpolate ? 1 : (int)(1.0+100.0/(double)keySize); // make mMapImage have at least size 100, factor becomes 1 if size > 200 or interpolation is on
20351   int valueOversamplingFactor = mInterpolate ? 1 : (int)(1.0+100.0/(double)valueSize); // make mMapImage have at least size 100, factor becomes 1 if size > 200 or interpolation is on
20352   
20353   // resize mMapImage to correct dimensions including possible oversampling factors, according to key/value axes orientation:
20354   if (keyAxis->orientation() == Qt::Horizontal && (mMapImage.width() != keySize*keyOversamplingFactor || mMapImage.height() != valueSize*valueOversamplingFactor))
20355     mMapImage = QImage(QSize(keySize*keyOversamplingFactor, valueSize*valueOversamplingFactor), QImage::Format_RGB32);
20356   else if (keyAxis->orientation() == Qt::Vertical && (mMapImage.width() != valueSize*valueOversamplingFactor || mMapImage.height() != keySize*keyOversamplingFactor))
20357     mMapImage = QImage(QSize(valueSize*valueOversamplingFactor, keySize*keyOversamplingFactor), QImage::Format_RGB32);
20358   
20359   QImage *localMapImage = &mMapImage; // this is the image on which the colorization operates. Either the final mMapImage, or if we need oversampling, mUndersampledMapImage
20360   if (keyOversamplingFactor > 1 || valueOversamplingFactor > 1)
20361   {
20362     // resize undersampled map image to actual key/value cell sizes:
20363     if (keyAxis->orientation() == Qt::Horizontal && (mUndersampledMapImage.width() != keySize || mUndersampledMapImage.height() != valueSize))
20364       mUndersampledMapImage = QImage(QSize(keySize, valueSize), QImage::Format_RGB32);
20365     else if (keyAxis->orientation() == Qt::Vertical && (mUndersampledMapImage.width() != valueSize || mUndersampledMapImage.height() != keySize))
20366       mUndersampledMapImage = QImage(QSize(valueSize, keySize), QImage::Format_RGB32);
20367     localMapImage = &mUndersampledMapImage; // make the colorization run on the undersampled image
20368   } else if (!mUndersampledMapImage.isNull())
20369     mUndersampledMapImage = QImage(); // don't need oversampling mechanism anymore (map size has changed) but mUndersampledMapImage still has nonzero size, free it
20370   
20371   const double *rawData = mMapData->mData;
20372   if (keyAxis->orientation() == Qt::Horizontal)
20373   {
20374     const int lineCount = valueSize;
20375     const int rowCount = keySize;
20376     for (int line=0; line<lineCount; ++line)
20377     {
20378       QRgb* pixels = reinterpret_cast<QRgb*>(localMapImage->scanLine(lineCount-1-line)); // invert scanline index because QImage counts scanlines from top, but our vertical index counts from bottom (mathematical coordinate system)
20379       mGradient.colorize(rawData+line*rowCount, mDataRange, pixels, rowCount, 1, mDataScaleType==QCPAxis::stLogarithmic);
20380     }
20381   } else // keyAxis->orientation() == Qt::Vertical
20382   {
20383     const int lineCount = keySize;
20384     const int rowCount = valueSize;
20385     for (int line=0; line<lineCount; ++line)
20386     {
20387       QRgb* pixels = reinterpret_cast<QRgb*>(localMapImage->scanLine(lineCount-1-line)); // invert scanline index because QImage counts scanlines from top, but our vertical index counts from bottom (mathematical coordinate system)
20388       mGradient.colorize(rawData+line, mDataRange, pixels, rowCount, lineCount, mDataScaleType==QCPAxis::stLogarithmic);
20389     }
20390   }
20391   
20392   if (keyOversamplingFactor > 1 || valueOversamplingFactor > 1)
20393   {
20394     if (keyAxis->orientation() == Qt::Horizontal)
20395       mMapImage = mUndersampledMapImage.scaled(keySize*keyOversamplingFactor, valueSize*valueOversamplingFactor, Qt::IgnoreAspectRatio, Qt::FastTransformation);
20396     else
20397       mMapImage = mUndersampledMapImage.scaled(valueSize*valueOversamplingFactor, keySize*keyOversamplingFactor, Qt::IgnoreAspectRatio, Qt::FastTransformation);
20398   }
20399   mMapData->mDataModified = false;
20400   mMapImageInvalidated = false;
20401 }
20402
20403 /* inherits documentation from base class */
20404 void QCPColorMap::draw(QCPPainter *painter)
20405 {
20406   if (mMapData->isEmpty()) return;
20407   if (!mKeyAxis || !mValueAxis) return;
20408   applyDefaultAntialiasingHint(painter);
20409   
20410   if (mMapData->mDataModified || mMapImageInvalidated)
20411     updateMapImage();
20412   
20413   // use buffer if painting vectorized (PDF):
20414   bool useBuffer = painter->modes().testFlag(QCPPainter::pmVectorized);
20415   QCPPainter *localPainter = painter; // will be redirected to paint on mapBuffer if painting vectorized
20416   QRectF mapBufferTarget; // the rect in absolute widget coordinates where the visible map portion/buffer will end up in
20417   QPixmap mapBuffer;
20418   double mapBufferPixelRatio = 3; // factor by which DPI is increased in embedded bitmaps
20419   if (useBuffer)
20420   {
20421     mapBufferTarget = painter->clipRegion().boundingRect();
20422     mapBuffer = QPixmap((mapBufferTarget.size()*mapBufferPixelRatio).toSize());
20423     mapBuffer.fill(Qt::transparent);
20424     localPainter = new QCPPainter(&mapBuffer);
20425     localPainter->scale(mapBufferPixelRatio, mapBufferPixelRatio);
20426     localPainter->translate(-mapBufferTarget.topLeft());
20427   }
20428   
20429   QRectF imageRect = QRectF(coordsToPixels(mMapData->keyRange().lower, mMapData->valueRange().lower),
20430                             coordsToPixels(mMapData->keyRange().upper, mMapData->valueRange().upper)).normalized();
20431   // extend imageRect to contain outer halves/quarters of bordering/cornering pixels (cells are centered on map range boundary):
20432   double halfCellWidth = 0; // in pixels
20433   double halfCellHeight = 0; // in pixels
20434   if (keyAxis()->orientation() == Qt::Horizontal)
20435   {
20436     if (mMapData->keySize() > 1)
20437       halfCellWidth = 0.5*imageRect.width()/(double)(mMapData->keySize()-1);
20438     if (mMapData->valueSize() > 1)
20439       halfCellHeight = 0.5*imageRect.height()/(double)(mMapData->valueSize()-1);
20440   } else // keyAxis orientation is Qt::Vertical
20441   {
20442     if (mMapData->keySize() > 1)
20443       halfCellHeight = 0.5*imageRect.height()/(double)(mMapData->keySize()-1);
20444     if (mMapData->valueSize() > 1)
20445       halfCellWidth = 0.5*imageRect.width()/(double)(mMapData->valueSize()-1);
20446   }
20447   imageRect.adjust(-halfCellWidth, -halfCellHeight, halfCellWidth, halfCellHeight);
20448   bool mirrorX = (keyAxis()->orientation() == Qt::Horizontal ? keyAxis() : valueAxis())->rangeReversed();
20449   bool mirrorY = (valueAxis()->orientation() == Qt::Vertical ? valueAxis() : keyAxis())->rangeReversed();
20450   bool smoothBackup = localPainter->renderHints().testFlag(QPainter::SmoothPixmapTransform);
20451   localPainter->setRenderHint(QPainter::SmoothPixmapTransform, mInterpolate);
20452   QRegion clipBackup;
20453   if (mTightBoundary)
20454   {
20455     clipBackup = localPainter->clipRegion();
20456     QRectF tightClipRect = QRectF(coordsToPixels(mMapData->keyRange().lower, mMapData->valueRange().lower),
20457                                   coordsToPixels(mMapData->keyRange().upper, mMapData->valueRange().upper)).normalized();
20458     localPainter->setClipRect(tightClipRect, Qt::IntersectClip);
20459   }
20460   localPainter->drawImage(imageRect, mMapImage.mirrored(mirrorX, mirrorY));
20461   if (mTightBoundary)
20462     localPainter->setClipRegion(clipBackup);
20463   localPainter->setRenderHint(QPainter::SmoothPixmapTransform, smoothBackup);
20464   
20465   if (useBuffer) // localPainter painted to mapBuffer, so now draw buffer with original painter
20466   {
20467     delete localPainter;
20468     painter->drawPixmap(mapBufferTarget.toRect(), mapBuffer);
20469   }
20470 }
20471
20472 /* inherits documentation from base class */
20473 void QCPColorMap::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const
20474 {
20475   applyDefaultAntialiasingHint(painter);
20476   // draw map thumbnail:
20477   if (!mLegendIcon.isNull())
20478   {
20479     QPixmap scaledIcon = mLegendIcon.scaled(rect.size().toSize(), Qt::KeepAspectRatio, Qt::FastTransformation);
20480     QRectF iconRect = QRectF(0, 0, scaledIcon.width(), scaledIcon.height());
20481     iconRect.moveCenter(rect.center());
20482     painter->drawPixmap(iconRect.topLeft(), scaledIcon);
20483   }
20484   /*
20485   // draw frame:
20486   painter->setBrush(Qt::NoBrush);
20487   painter->setPen(Qt::black);
20488   painter->drawRect(rect.adjusted(1, 1, 0, 0));
20489   */
20490 }
20491
20492 /* inherits documentation from base class */
20493 QCPRange QCPColorMap::getKeyRange(bool &foundRange, SignDomain inSignDomain) const
20494 {
20495   foundRange = true;
20496   QCPRange result = mMapData->keyRange();
20497   result.normalize();
20498   if (inSignDomain == QCPAbstractPlottable::sdPositive)
20499   {
20500     if (result.lower <= 0 && result.upper > 0)
20501       result.lower = result.upper*1e-3;
20502     else if (result.lower <= 0 && result.upper <= 0)
20503       foundRange = false;
20504   } else if (inSignDomain == QCPAbstractPlottable::sdNegative)
20505   {
20506     if (result.upper >= 0 && result.lower < 0)
20507       result.upper = result.lower*1e-3;
20508     else if (result.upper >= 0 && result.lower >= 0)
20509       foundRange = false;
20510   }
20511   return result;
20512 }
20513
20514 /* inherits documentation from base class */
20515 QCPRange QCPColorMap::getValueRange(bool &foundRange, SignDomain inSignDomain) const
20516 {
20517   foundRange = true;
20518   QCPRange result = mMapData->valueRange();
20519   result.normalize();
20520   if (inSignDomain == QCPAbstractPlottable::sdPositive)
20521   {
20522     if (result.lower <= 0 && result.upper > 0)
20523       result.lower = result.upper*1e-3;
20524     else if (result.lower <= 0 && result.upper <= 0)
20525       foundRange = false;
20526   } else if (inSignDomain == QCPAbstractPlottable::sdNegative)
20527   {
20528     if (result.upper >= 0 && result.lower < 0)
20529       result.upper = result.lower*1e-3;
20530     else if (result.upper >= 0 && result.lower >= 0)
20531       foundRange = false;
20532   }
20533   return result;
20534 }
20535
20536
20537 ////////////////////////////////////////////////////////////////////////////////////////////////////
20538 //////////////////// QCPFinancialData
20539 ////////////////////////////////////////////////////////////////////////////////////////////////////
20540
20541 /*! \class QCPFinancialData
20542   \brief Holds the data of one single data point for QCPFinancial.
20543   
20544   The container for storing multiple data points is \ref QCPFinancialDataMap.
20545   
20546   The stored data is:
20547   \li \a key: coordinate on the key axis of this data point
20548   \li \a open: The opening value at the data point
20549   \li \a high: The high/maximum value at the data point
20550   \li \a low: The low/minimum value at the data point
20551   \li \a close: The closing value at the data point
20552   
20553   \see QCPFinancialDataMap
20554 */
20555
20556 /*!
20557   Constructs a data point with key and all values set to zero.
20558 */
20559 QCPFinancialData::QCPFinancialData() :
20560   key(0),
20561   open(0),
20562   high(0),
20563   low(0),
20564   close(0)
20565 {
20566 }
20567
20568 /*!
20569   Constructs a data point with the specified \a key and OHLC values.
20570 */
20571 QCPFinancialData::QCPFinancialData(double key, double open, double high, double low, double close) :
20572   key(key),
20573   open(open),
20574   high(high),
20575   low(low),
20576   close(close)
20577 {
20578 }
20579
20580
20581 ////////////////////////////////////////////////////////////////////////////////////////////////////
20582 //////////////////// QCPFinancial
20583 ////////////////////////////////////////////////////////////////////////////////////////////////////
20584
20585 /*! \class QCPFinancial
20586   \brief A plottable representing a financial stock chart
20587
20588   \image html QCPFinancial.png
20589   
20590   This plottable represents time series data binned to certain intervals, mainly used for stock
20591   charts. The two common representations OHLC (Open-High-Low-Close) bars and Candlesticks can be
20592   set via \ref setChartStyle.
20593   
20594   The data is passed via \ref setData as a set of open/high/low/close values at certain keys
20595   (typically times). This means the data must be already binned appropriately. If data is only
20596   available as a series of values (e.g. \a price against \a time), you can use the static
20597   convenience function \ref timeSeriesToOhlc to generate binned OHLC-data which can then be passed
20598   to \ref setData.
20599   
20600   The width of the OHLC bars/candlesticks can be controlled with \ref setWidth and is given in plot
20601   key coordinates. A typical choice is to set it to (or slightly less than) one bin interval width.
20602   
20603   \section appearance Changing the appearance
20604   
20605   Charts can be either single- or two-colored (\ref setTwoColored). If set to be single-colored,
20606   lines are drawn with the plottable's pen (\ref setPen) and fills with the brush (\ref setBrush).
20607   
20608   If set to two-colored, positive changes of the value during an interval (\a close >= \a open) are
20609   represented with a different pen and brush than negative changes (\a close < \a open). These can
20610   be configured with \ref setPenPositive, \ref setPenNegative, \ref setBrushPositive, and \ref
20611   setBrushNegative. In two-colored mode, the normal plottable pen/brush is ignored. Upon selection
20612   however, the normal selected pen/brush (\ref setSelectedPen, \ref setSelectedBrush) is used,
20613   irrespective of whether the chart is single- or two-colored.
20614   
20615 */
20616
20617 /* start of documentation of inline functions */
20618
20619 /*! \fn QCPFinancialDataMap *QCPFinancial::data() const
20620   
20621   Returns a pointer to the internal data storage of type \ref QCPFinancialDataMap. You may use it to
20622   directly manipulate the data, which may be more convenient and faster than using the regular \ref
20623   setData or \ref addData methods, in certain situations.
20624 */
20625
20626 /* end of documentation of inline functions */
20627
20628 /*!
20629   Constructs a financial chart which uses \a keyAxis as its key axis ("x") and \a valueAxis as its value
20630   axis ("y"). \a keyAxis and \a valueAxis must reside in the same QCustomPlot instance and not have
20631   the same orientation. If either of these restrictions is violated, a corresponding message is
20632   printed to the debug output (qDebug), the construction is not aborted, though.
20633   
20634   The constructed QCPFinancial can be added to the plot with QCustomPlot::addPlottable, QCustomPlot
20635   then takes ownership of the financial chart.
20636 */
20637 QCPFinancial::QCPFinancial(QCPAxis *keyAxis, QCPAxis *valueAxis) :
20638   QCPAbstractPlottable(keyAxis, valueAxis),
20639   mData(0),
20640   mChartStyle(csOhlc),
20641   mWidth(0.5),
20642   mTwoColored(false),
20643   mBrushPositive(QBrush(QColor(210, 210, 255))),
20644   mBrushNegative(QBrush(QColor(255, 210, 210))),
20645   mPenPositive(QPen(QColor(10, 40, 180))),
20646   mPenNegative(QPen(QColor(180, 40, 10)))
20647 {
20648   mData = new QCPFinancialDataMap;
20649   
20650   setSelectedPen(QPen(QColor(80, 80, 255), 2.5));
20651   setSelectedBrush(QBrush(QColor(80, 80, 255)));
20652 }
20653
20654 QCPFinancial::~QCPFinancial()
20655 {
20656   delete mData;
20657 }
20658
20659 /*!
20660   Replaces the current data with the provided \a data.
20661   
20662   If \a copy is set to true, data points in \a data will only be copied. if false, the plottable
20663   takes ownership of the passed data and replaces the internal data pointer with it. This is
20664   significantly faster than copying for large datasets.
20665   
20666   Alternatively, you can also access and modify the plottable's data via the \ref data method, which
20667   returns a pointer to the internal \ref QCPFinancialDataMap.
20668   
20669   \see timeSeriesToOhlc
20670 */
20671 void QCPFinancial::setData(QCPFinancialDataMap *data, bool copy)
20672 {
20673   if (mData == data)
20674   {
20675     qDebug() << Q_FUNC_INFO << "The data pointer is already in (and owned by) this plottable" << reinterpret_cast<quintptr>(data);
20676     return;
20677   }
20678   if (copy)
20679   {
20680     *mData = *data;
20681   } else
20682   {
20683     delete mData;
20684     mData = data;
20685   }
20686 }
20687
20688 /*! \overload
20689   
20690   Replaces the current data with the provided open/high/low/close data. The provided vectors should
20691   have equal length. Else, the number of added points will be the size of the smallest vector.
20692   
20693   \see timeSeriesToOhlc
20694 */
20695 void QCPFinancial::setData(const QVector<double> &key, const QVector<double> &open, const QVector<double> &high, const QVector<double> &low, const QVector<double> &close)
20696 {
20697   mData->clear();
20698   int n = key.size();
20699   n = qMin(n, open.size());
20700   n = qMin(n, high.size());
20701   n = qMin(n, low.size());
20702   n = qMin(n, close.size());
20703   for (int i=0; i<n; ++i)
20704   {
20705     mData->insertMulti(key[i], QCPFinancialData(key[i], open[i], high[i], low[i], close[i]));
20706   }
20707 }
20708
20709 /*!
20710   Sets which representation style shall be used to display the OHLC data.
20711 */
20712 void QCPFinancial::setChartStyle(QCPFinancial::ChartStyle style)
20713 {
20714   mChartStyle = style;
20715 }
20716
20717 /*!
20718   Sets the width of the individual bars/candlesticks to \a width in plot key coordinates.
20719   
20720   A typical choice is to set it to (or slightly less than) one bin interval width.
20721 */
20722 void QCPFinancial::setWidth(double width)
20723 {
20724   mWidth = width;
20725 }
20726
20727 /*!
20728   Sets whether this chart shall contrast positive from negative trends per data point by using two
20729   separate colors to draw the respective bars/candlesticks.
20730   
20731   If \a twoColored is false, the normal plottable's pen and brush are used (\ref setPen, \ref
20732   setBrush).
20733   
20734   \see setPenPositive, setPenNegative, setBrushPositive, setBrushNegative
20735 */
20736 void QCPFinancial::setTwoColored(bool twoColored)
20737 {
20738   mTwoColored = twoColored;
20739 }
20740
20741 /*!
20742   If \ref setTwoColored is set to true, this function controls the brush that is used to draw fills
20743   of data points with a positive trend (i.e. bars/candlesticks with close >= open).
20744   
20745   If \a twoColored is false, the normal plottable's pen and brush are used (\ref setPen, \ref
20746   setBrush).
20747   
20748   \see setBrushNegative, setPenPositive, setPenNegative
20749 */
20750 void QCPFinancial::setBrushPositive(const QBrush &brush)
20751 {
20752   mBrushPositive = brush;
20753 }
20754
20755 /*!
20756   If \ref setTwoColored is set to true, this function controls the brush that is used to draw fills
20757   of data points with a negative trend (i.e. bars/candlesticks with close < open).
20758   
20759   If \a twoColored is false, the normal plottable's pen and brush are used (\ref setPen, \ref
20760   setBrush).
20761   
20762   \see setBrushPositive, setPenNegative, setPenPositive
20763 */
20764 void QCPFinancial::setBrushNegative(const QBrush &brush)
20765 {
20766   mBrushNegative = brush;
20767 }
20768
20769 /*!
20770   If \ref setTwoColored is set to true, this function controls the pen that is used to draw
20771   outlines of data points with a positive trend (i.e. bars/candlesticks with close >= open).
20772   
20773   If \a twoColored is false, the normal plottable's pen and brush are used (\ref setPen, \ref
20774   setBrush).
20775   
20776   \see setPenNegative, setBrushPositive, setBrushNegative
20777 */
20778 void QCPFinancial::setPenPositive(const QPen &pen)
20779 {
20780   mPenPositive = pen;
20781 }
20782
20783 /*!
20784   If \ref setTwoColored is set to true, this function controls the pen that is used to draw
20785   outlines of data points with a negative trend (i.e. bars/candlesticks with close < open).
20786   
20787   If \a twoColored is false, the normal plottable's pen and brush are used (\ref setPen, \ref
20788   setBrush).
20789   
20790   \see setPenPositive, setBrushNegative, setBrushPositive
20791 */
20792 void QCPFinancial::setPenNegative(const QPen &pen)
20793 {
20794   mPenNegative = pen;
20795 }
20796
20797 /*!
20798   Adds the provided data points in \a dataMap to the current data.
20799   
20800   Alternatively, you can also access and modify the data via the \ref data method, which returns a
20801   pointer to the internal \ref QCPFinancialDataMap.
20802   
20803   \see removeData
20804 */
20805 void QCPFinancial::addData(const QCPFinancialDataMap &dataMap)
20806 {
20807   mData->unite(dataMap);
20808 }
20809
20810 /*! \overload
20811   
20812   Adds the provided single data point in \a data to the current data.
20813   
20814   Alternatively, you can also access and modify the data via the \ref data method, which returns a
20815   pointer to the internal \ref QCPFinancialData.
20816   
20817   \see removeData
20818 */
20819 void QCPFinancial::addData(const QCPFinancialData &data)
20820 {
20821   mData->insertMulti(data.key, data);
20822 }
20823
20824 /*! \overload
20825   
20826   Adds the provided single data point given by \a key, \a open, \a high, \a low, and \a close to
20827   the current data.
20828   
20829   Alternatively, you can also access and modify the data via the \ref data method, which returns a
20830   pointer to the internal \ref QCPFinancialData.
20831   
20832   \see removeData
20833 */
20834 void QCPFinancial::addData(double key, double open, double high, double low, double close)
20835 {
20836   mData->insertMulti(key, QCPFinancialData(key, open, high, low, close));
20837 }
20838
20839 /*! \overload
20840   
20841   Adds the provided open/high/low/close data to the current data.
20842   
20843   Alternatively, you can also access and modify the data via the \ref data method, which returns a
20844   pointer to the internal \ref QCPFinancialData.
20845   
20846   \see removeData
20847 */
20848 void QCPFinancial::addData(const QVector<double> &key, const QVector<double> &open, const QVector<double> &high, const QVector<double> &low, const QVector<double> &close)
20849 {
20850   int n = key.size();
20851   n = qMin(n, open.size());
20852   n = qMin(n, high.size());
20853   n = qMin(n, low.size());
20854   n = qMin(n, close.size());
20855   for (int i=0; i<n; ++i)
20856   {
20857     mData->insertMulti(key[i], QCPFinancialData(key[i], open[i], high[i], low[i], close[i]));
20858   }
20859 }
20860
20861 /*!
20862   Removes all data points with keys smaller than \a key.
20863   
20864   \see addData, clearData
20865 */
20866 void QCPFinancial::removeDataBefore(double key)
20867 {
20868   QCPFinancialDataMap::iterator it = mData->begin();
20869   while (it != mData->end() && it.key() < key)
20870     it = mData->erase(it);
20871 }
20872
20873 /*!
20874   Removes all data points with keys greater than \a key.
20875   
20876   \see addData, clearData
20877 */
20878 void QCPFinancial::removeDataAfter(double key)
20879 {
20880   if (mData->isEmpty()) return;
20881   QCPFinancialDataMap::iterator it = mData->upperBound(key);
20882   while (it != mData->end())
20883     it = mData->erase(it);
20884 }
20885
20886 /*!
20887   Removes all data points with keys between \a fromKey and \a toKey. if \a fromKey is greater or
20888   equal to \a toKey, the function does nothing. To remove a single data point with known key, use
20889   \ref removeData(double key).
20890   
20891   \see addData, clearData
20892 */
20893 void QCPFinancial::removeData(double fromKey, double toKey)
20894 {
20895   if (fromKey >= toKey || mData->isEmpty()) return;
20896   QCPFinancialDataMap::iterator it = mData->upperBound(fromKey);
20897   QCPFinancialDataMap::iterator itEnd = mData->upperBound(toKey);
20898   while (it != itEnd)
20899     it = mData->erase(it);
20900 }
20901
20902 /*! \overload
20903   
20904   Removes a single data point at \a key. If the position is not known with absolute precision,
20905   consider using \ref removeData(double fromKey, double toKey) with a small fuzziness interval
20906   around the suspected position, depeding on the precision with which the key is known.
20907
20908   \see addData, clearData
20909 */
20910 void QCPFinancial::removeData(double key)
20911 {
20912   mData->remove(key);
20913 }
20914
20915 /*!
20916   Removes all data points.
20917   
20918   \see removeData, removeDataAfter, removeDataBefore
20919 */
20920 void QCPFinancial::clearData()
20921 {
20922   mData->clear();
20923 }
20924
20925 /* inherits documentation from base class */
20926 double QCPFinancial::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
20927 {
20928   Q_UNUSED(details)
20929   if (onlySelectable && !mSelectable)
20930     return -1;
20931   if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
20932   
20933   if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()))
20934   {
20935     // get visible data range:
20936     QCPFinancialDataMap::const_iterator lower, upper; // note that upper is the actual upper point, and not 1 step after the upper point
20937     getVisibleDataBounds(lower, upper);
20938     if (lower == mData->constEnd() || upper == mData->constEnd())
20939       return -1;
20940     // perform select test according to configured style:
20941     switch (mChartStyle)
20942     {
20943       case QCPFinancial::csOhlc:
20944         return ohlcSelectTest(pos, lower, upper+1); break;
20945       case QCPFinancial::csCandlestick:
20946         return candlestickSelectTest(pos, lower, upper+1); break;
20947     }
20948   }
20949   return -1;
20950 }
20951
20952 /*!
20953   A convenience function that converts time series data (\a value against \a time) to OHLC binned
20954   data points. The return value can then be passed on to \ref setData.
20955   
20956   The size of the bins can be controlled with \a timeBinSize in the same units as \a time is given.
20957   For example, if the unit of \a time is seconds and single OHLC/Candlesticks should span an hour
20958   each, set \a timeBinSize to 3600.
20959   
20960   \a timeBinOffset allows to control precisely at what \a time coordinate a bin should start. The
20961   value passed as \a timeBinOffset doesn't need to be in the range encompassed by the \a time keys.
20962   It merely defines the mathematical offset/phase of the bins that will be used to process the
20963   data.
20964 */
20965 QCPFinancialDataMap QCPFinancial::timeSeriesToOhlc(const QVector<double> &time, const QVector<double> &value, double timeBinSize, double timeBinOffset)
20966 {
20967   QCPFinancialDataMap map;
20968   int count = qMin(time.size(), value.size());
20969   if (count == 0)
20970     return QCPFinancialDataMap();
20971   
20972   QCPFinancialData currentBinData(0, value.first(), value.first(), value.first(), value.first());
20973   int currentBinIndex = qFloor((time.first()-timeBinOffset)/timeBinSize+0.5);
20974   for (int i=0; i<count; ++i)
20975   {
20976     int index = qFloor((time.at(i)-timeBinOffset)/timeBinSize+0.5);
20977     if (currentBinIndex == index) // data point still in current bin, extend high/low:
20978     {
20979       if (value.at(i) < currentBinData.low) currentBinData.low = value.at(i);
20980       if (value.at(i) > currentBinData.high) currentBinData.high = value.at(i);
20981       if (i == count-1) // last data point is in current bin, finalize bin:
20982       {
20983         currentBinData.close = value.at(i);
20984         currentBinData.key = timeBinOffset+(index)*timeBinSize;
20985         map.insert(currentBinData.key, currentBinData);
20986       }
20987     } else // data point not anymore in current bin, set close of old and open of new bin, and add old to map:
20988     {
20989       // finalize current bin:
20990       currentBinData.close = value.at(i-1);
20991       currentBinData.key = timeBinOffset+(index-1)*timeBinSize;
20992       map.insert(currentBinData.key, currentBinData);
20993       // start next bin:
20994       currentBinIndex = index;
20995       currentBinData.open = value.at(i);
20996       currentBinData.high = value.at(i);
20997       currentBinData.low = value.at(i);
20998     }
20999   }
21000   
21001   return map;
21002 }
21003
21004 /* inherits documentation from base class */
21005 void QCPFinancial::draw(QCPPainter *painter)
21006 {
21007   // get visible data range:
21008   QCPFinancialDataMap::const_iterator lower, upper; // note that upper is the actual upper point, and not 1 step after the upper point
21009   getVisibleDataBounds(lower, upper);
21010   if (lower == mData->constEnd() || upper == mData->constEnd())
21011     return;
21012   
21013   // draw visible data range according to configured style:
21014   switch (mChartStyle)
21015   {
21016     case QCPFinancial::csOhlc:
21017       drawOhlcPlot(painter, lower, upper+1); break;
21018     case QCPFinancial::csCandlestick:
21019       drawCandlestickPlot(painter, lower, upper+1); break;
21020   }
21021 }
21022
21023 /* inherits documentation from base class */
21024 void QCPFinancial::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const
21025 {
21026   painter->setAntialiasing(false); // legend icon especially of csCandlestick looks better without antialiasing
21027   if (mChartStyle == csOhlc)
21028   {
21029     if (mTwoColored)
21030     {
21031       // draw upper left half icon with positive color:
21032       painter->setBrush(mBrushPositive);
21033       painter->setPen(mPenPositive);
21034       painter->setClipRegion(QRegion(QPolygon() << rect.bottomLeft().toPoint() << rect.topRight().toPoint() << rect.topLeft().toPoint()));
21035       painter->drawLine(QLineF(0, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft()));
21036       painter->drawLine(QLineF(rect.width()*0.2, rect.height()*0.3, rect.width()*0.2, rect.height()*0.5).translated(rect.topLeft()));
21037       painter->drawLine(QLineF(rect.width()*0.8, rect.height()*0.5, rect.width()*0.8, rect.height()*0.7).translated(rect.topLeft()));
21038       // draw bottom right hald icon with negative color:
21039       painter->setBrush(mBrushNegative);
21040       painter->setPen(mPenNegative);
21041       painter->setClipRegion(QRegion(QPolygon() << rect.bottomLeft().toPoint() << rect.topRight().toPoint() << rect.bottomRight().toPoint()));
21042       painter->drawLine(QLineF(0, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft()));
21043       painter->drawLine(QLineF(rect.width()*0.2, rect.height()*0.3, rect.width()*0.2, rect.height()*0.5).translated(rect.topLeft()));
21044       painter->drawLine(QLineF(rect.width()*0.8, rect.height()*0.5, rect.width()*0.8, rect.height()*0.7).translated(rect.topLeft()));
21045     } else
21046     {
21047       painter->setBrush(mBrush);
21048       painter->setPen(mPen);
21049       painter->drawLine(QLineF(0, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft()));
21050       painter->drawLine(QLineF(rect.width()*0.2, rect.height()*0.3, rect.width()*0.2, rect.height()*0.5).translated(rect.topLeft()));
21051       painter->drawLine(QLineF(rect.width()*0.8, rect.height()*0.5, rect.width()*0.8, rect.height()*0.7).translated(rect.topLeft()));
21052     }
21053   } else if (mChartStyle == csCandlestick)
21054   {
21055     if (mTwoColored)
21056     {
21057       // draw upper left half icon with positive color:
21058       painter->setBrush(mBrushPositive);
21059       painter->setPen(mPenPositive);
21060       painter->setClipRegion(QRegion(QPolygon() << rect.bottomLeft().toPoint() << rect.topRight().toPoint() << rect.topLeft().toPoint()));
21061       painter->drawLine(QLineF(0, rect.height()*0.5, rect.width()*0.25, rect.height()*0.5).translated(rect.topLeft()));
21062       painter->drawLine(QLineF(rect.width()*0.75, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft()));
21063       painter->drawRect(QRectF(rect.width()*0.25, rect.height()*0.25, rect.width()*0.5, rect.height()*0.5).translated(rect.topLeft()));
21064       // draw bottom right hald icon with negative color:
21065       painter->setBrush(mBrushNegative);
21066       painter->setPen(mPenNegative);
21067       painter->setClipRegion(QRegion(QPolygon() << rect.bottomLeft().toPoint() << rect.topRight().toPoint() << rect.bottomRight().toPoint()));
21068       painter->drawLine(QLineF(0, rect.height()*0.5, rect.width()*0.25, rect.height()*0.5).translated(rect.topLeft()));
21069       painter->drawLine(QLineF(rect.width()*0.75, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft()));
21070       painter->drawRect(QRectF(rect.width()*0.25, rect.height()*0.25, rect.width()*0.5, rect.height()*0.5).translated(rect.topLeft()));
21071     } else
21072     {
21073       painter->setBrush(mBrush);
21074       painter->setPen(mPen);
21075       painter->drawLine(QLineF(0, rect.height()*0.5, rect.width()*0.25, rect.height()*0.5).translated(rect.topLeft()));
21076       painter->drawLine(QLineF(rect.width()*0.75, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft()));
21077       painter->drawRect(QRectF(rect.width()*0.25, rect.height()*0.25, rect.width()*0.5, rect.height()*0.5).translated(rect.topLeft()));
21078     }
21079   }
21080 }
21081
21082 /* inherits documentation from base class */
21083 QCPRange QCPFinancial::getKeyRange(bool &foundRange, QCPAbstractPlottable::SignDomain inSignDomain) const
21084 {
21085   QCPRange range;
21086   bool haveLower = false;
21087   bool haveUpper = false;
21088   
21089   double current;
21090   QCPFinancialDataMap::const_iterator it = mData->constBegin();
21091   while (it != mData->constEnd())
21092   {
21093     current = it.value().key;
21094     if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current < 0) || (inSignDomain == sdPositive && current > 0))
21095     {
21096       if (current < range.lower || !haveLower)
21097       {
21098         range.lower = current;
21099         haveLower = true;
21100       }
21101       if (current > range.upper || !haveUpper)
21102       {
21103         range.upper = current;
21104         haveUpper = true;
21105       }
21106     }
21107     ++it;
21108   }
21109   // determine exact range by including width of bars/flags:
21110   if (haveLower && mKeyAxis)
21111     range.lower = range.lower-mWidth*0.5;
21112   if (haveUpper && mKeyAxis)
21113     range.upper = range.upper+mWidth*0.5;
21114   foundRange = haveLower && haveUpper;
21115   return range;
21116 }
21117
21118 /* inherits documentation from base class */
21119 QCPRange QCPFinancial::getValueRange(bool &foundRange, QCPAbstractPlottable::SignDomain inSignDomain) const
21120 {
21121   QCPRange range;
21122   bool haveLower = false;
21123   bool haveUpper = false;
21124   
21125   QCPFinancialDataMap::const_iterator it = mData->constBegin();
21126   while (it != mData->constEnd())
21127   {
21128     // high:
21129     if (inSignDomain == sdBoth || (inSignDomain == sdNegative && it.value().high < 0) || (inSignDomain == sdPositive && it.value().high > 0))
21130     {
21131       if (it.value().high < range.lower || !haveLower)
21132       {
21133         range.lower = it.value().high;
21134         haveLower = true;
21135       }
21136       if (it.value().high > range.upper || !haveUpper)
21137       {
21138         range.upper = it.value().high;
21139         haveUpper = true;
21140       }
21141     }
21142     // low:
21143     if (inSignDomain == sdBoth || (inSignDomain == sdNegative && it.value().low < 0) || (inSignDomain == sdPositive && it.value().low > 0))
21144     {
21145       if (it.value().low < range.lower || !haveLower)
21146       {
21147         range.lower = it.value().low;
21148         haveLower = true;
21149       }
21150       if (it.value().low > range.upper || !haveUpper)
21151       {
21152         range.upper = it.value().low;
21153         haveUpper = true;
21154       }
21155     }
21156     ++it;
21157   }
21158   
21159   foundRange = haveLower && haveUpper;
21160   return range;
21161 }
21162
21163 /*! \internal
21164   
21165   Draws the data from \a begin to \a end as OHLC bars with the provided \a painter.
21166
21167   This method is a helper function for \ref draw. It is used when the chart style is \ref csOhlc.
21168 */
21169 void QCPFinancial::drawOhlcPlot(QCPPainter *painter, const QCPFinancialDataMap::const_iterator &begin, const QCPFinancialDataMap::const_iterator &end)
21170 {
21171   QCPAxis *keyAxis = mKeyAxis.data();
21172   QCPAxis *valueAxis = mValueAxis.data();
21173   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
21174   
21175   QPen linePen;
21176   
21177   if (keyAxis->orientation() == Qt::Horizontal)
21178   {
21179     for (QCPFinancialDataMap::const_iterator it = begin; it != end; ++it)
21180     {
21181       if (mSelected)
21182         linePen = mSelectedPen;
21183       else if (mTwoColored)
21184         linePen = it.value().close >= it.value().open ? mPenPositive : mPenNegative;
21185       else
21186         linePen = mPen;
21187       painter->setPen(linePen);
21188       double keyPixel = keyAxis->coordToPixel(it.value().key);
21189       double openPixel = valueAxis->coordToPixel(it.value().open);
21190       double closePixel = valueAxis->coordToPixel(it.value().close);
21191       // draw backbone:
21192       painter->drawLine(QPointF(keyPixel, valueAxis->coordToPixel(it.value().high)), QPointF(keyPixel, valueAxis->coordToPixel(it.value().low)));
21193       // draw open:
21194       double keyWidthPixels = keyPixel-keyAxis->coordToPixel(it.value().key-mWidth*0.5); // sign of this makes sure open/close are on correct sides
21195       painter->drawLine(QPointF(keyPixel-keyWidthPixels, openPixel), QPointF(keyPixel, openPixel));
21196       // draw close:
21197       painter->drawLine(QPointF(keyPixel, closePixel), QPointF(keyPixel+keyWidthPixels, closePixel));
21198     }
21199   } else
21200   {
21201     for (QCPFinancialDataMap::const_iterator it = begin; it != end; ++it)
21202     {
21203       if (mSelected)
21204         linePen = mSelectedPen;
21205       else if (mTwoColored)
21206         linePen = it.value().close >= it.value().open ? mPenPositive : mPenNegative;
21207       else
21208         linePen = mPen;
21209       painter->setPen(linePen);
21210       double keyPixel = keyAxis->coordToPixel(it.value().key);
21211       double openPixel = valueAxis->coordToPixel(it.value().open);
21212       double closePixel = valueAxis->coordToPixel(it.value().close);
21213       // draw backbone:
21214       painter->drawLine(QPointF(valueAxis->coordToPixel(it.value().high), keyPixel), QPointF(valueAxis->coordToPixel(it.value().low), keyPixel));
21215       // draw open:
21216       double keyWidthPixels = keyPixel-keyAxis->coordToPixel(it.value().key-mWidth*0.5); // sign of this makes sure open/close are on correct sides
21217       painter->drawLine(QPointF(openPixel, keyPixel-keyWidthPixels), QPointF(openPixel, keyPixel));
21218       // draw close:
21219       painter->drawLine(QPointF(closePixel, keyPixel), QPointF(closePixel, keyPixel+keyWidthPixels));
21220     }
21221   }
21222 }
21223
21224 /*! \internal
21225   
21226   Draws the data from \a begin to \a end as Candlesticks with the provided \a painter.
21227
21228   This method is a helper function for \ref draw. It is used when the chart style is \ref csCandlestick.
21229 */
21230 void QCPFinancial::drawCandlestickPlot(QCPPainter *painter, const QCPFinancialDataMap::const_iterator &begin, const QCPFinancialDataMap::const_iterator &end)
21231 {
21232   QCPAxis *keyAxis = mKeyAxis.data();
21233   QCPAxis *valueAxis = mValueAxis.data();
21234   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
21235   
21236   QPen linePen;
21237   QBrush boxBrush;
21238   
21239   if (keyAxis->orientation() == Qt::Horizontal)
21240   {
21241     for (QCPFinancialDataMap::const_iterator it = begin; it != end; ++it)
21242     {
21243       if (mSelected)
21244       {
21245         linePen = mSelectedPen;
21246         boxBrush = mSelectedBrush;
21247       } else if (mTwoColored)
21248       {
21249         if (it.value().close >= it.value().open)
21250         {
21251           linePen = mPenPositive;
21252           boxBrush = mBrushPositive;
21253         } else
21254         {
21255           linePen = mPenNegative;
21256           boxBrush = mBrushNegative;
21257         }
21258       } else
21259       {
21260         linePen = mPen;
21261         boxBrush = mBrush;
21262       }
21263       painter->setPen(linePen);
21264       painter->setBrush(boxBrush);
21265       double keyPixel = keyAxis->coordToPixel(it.value().key);
21266       double openPixel = valueAxis->coordToPixel(it.value().open);
21267       double closePixel = valueAxis->coordToPixel(it.value().close);
21268       // draw high:
21269       painter->drawLine(QPointF(keyPixel, valueAxis->coordToPixel(it.value().high)), QPointF(keyPixel, valueAxis->coordToPixel(qMax(it.value().open, it.value().close))));
21270       // draw low:
21271       painter->drawLine(QPointF(keyPixel, valueAxis->coordToPixel(it.value().low)), QPointF(keyPixel, valueAxis->coordToPixel(qMin(it.value().open, it.value().close))));
21272       // draw open-close box:
21273       double keyWidthPixels = keyPixel-keyAxis->coordToPixel(it.value().key-mWidth*0.5);
21274       painter->drawRect(QRectF(QPointF(keyPixel-keyWidthPixels, closePixel), QPointF(keyPixel+keyWidthPixels, openPixel)));
21275     }
21276   } else // keyAxis->orientation() == Qt::Vertical
21277   {
21278     for (QCPFinancialDataMap::const_iterator it = begin; it != end; ++it)
21279     {
21280       if (mSelected)
21281       {
21282         linePen = mSelectedPen;
21283         boxBrush = mSelectedBrush;
21284       } else if (mTwoColored)
21285       {
21286         if (it.value().close >= it.value().open)
21287         {
21288           linePen = mPenPositive;
21289           boxBrush = mBrushPositive;
21290         } else
21291         {
21292           linePen = mPenNegative;
21293           boxBrush = mBrushNegative;
21294         }
21295       } else
21296       {
21297         linePen = mPen;
21298         boxBrush = mBrush;
21299       }
21300       painter->setPen(linePen);
21301       painter->setBrush(boxBrush);
21302       double keyPixel = keyAxis->coordToPixel(it.value().key);
21303       double openPixel = valueAxis->coordToPixel(it.value().open);
21304       double closePixel = valueAxis->coordToPixel(it.value().close);
21305       // draw high:
21306       painter->drawLine(QPointF(valueAxis->coordToPixel(it.value().high), keyPixel), QPointF(valueAxis->coordToPixel(qMax(it.value().open, it.value().close)), keyPixel));
21307       // draw low:
21308       painter->drawLine(QPointF(valueAxis->coordToPixel(it.value().low), keyPixel), QPointF(valueAxis->coordToPixel(qMin(it.value().open, it.value().close)), keyPixel));
21309       // draw open-close box:
21310       double keyWidthPixels = keyPixel-keyAxis->coordToPixel(it.value().key-mWidth*0.5);
21311       painter->drawRect(QRectF(QPointF(closePixel, keyPixel-keyWidthPixels), QPointF(openPixel, keyPixel+keyWidthPixels)));
21312     }
21313   }
21314 }
21315
21316 /*! \internal
21317   
21318   This method is a helper function for \ref selectTest. It is used to test for selection when the
21319   chart style is \ref csOhlc. It only tests against the data points between \a begin and \a end.
21320 */
21321 double QCPFinancial::ohlcSelectTest(const QPointF &pos, const QCPFinancialDataMap::const_iterator &begin, const QCPFinancialDataMap::const_iterator &end) const
21322 {
21323   QCPAxis *keyAxis = mKeyAxis.data();
21324   QCPAxis *valueAxis = mValueAxis.data();
21325   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
21326
21327   double minDistSqr = std::numeric_limits<double>::max();
21328   QCPFinancialDataMap::const_iterator it;
21329   if (keyAxis->orientation() == Qt::Horizontal)
21330   {
21331     for (it = begin; it != end; ++it)
21332     {
21333       double keyPixel = keyAxis->coordToPixel(it.value().key);
21334       // calculate distance to backbone:
21335       double currentDistSqr = distSqrToLine(QPointF(keyPixel, valueAxis->coordToPixel(it.value().high)), QPointF(keyPixel, valueAxis->coordToPixel(it.value().low)), pos);
21336       if (currentDistSqr < minDistSqr)
21337         minDistSqr = currentDistSqr;
21338     }
21339   } else // keyAxis->orientation() == Qt::Vertical
21340   {
21341     for (it = begin; it != end; ++it)
21342     {
21343       double keyPixel = keyAxis->coordToPixel(it.value().key);
21344       // calculate distance to backbone:
21345       double currentDistSqr = distSqrToLine(QPointF(valueAxis->coordToPixel(it.value().high), keyPixel), QPointF(valueAxis->coordToPixel(it.value().low), keyPixel), pos);
21346       if (currentDistSqr < minDistSqr)
21347         minDistSqr = currentDistSqr;
21348     }
21349   }
21350   return qSqrt(minDistSqr);
21351 }
21352
21353 /*! \internal
21354   
21355   This method is a helper function for \ref selectTest. It is used to test for selection when the
21356   chart style is \ref csCandlestick. It only tests against the data points between \a begin and \a
21357   end.
21358 */
21359 double QCPFinancial::candlestickSelectTest(const QPointF &pos, const QCPFinancialDataMap::const_iterator &begin, const QCPFinancialDataMap::const_iterator &end) const
21360 {
21361   QCPAxis *keyAxis = mKeyAxis.data();
21362   QCPAxis *valueAxis = mValueAxis.data();
21363   if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; }
21364
21365   double minDistSqr = std::numeric_limits<double>::max();
21366   QCPFinancialDataMap::const_iterator it;
21367   if (keyAxis->orientation() == Qt::Horizontal)
21368   {
21369     for (it = begin; it != end; ++it)
21370     {
21371       double currentDistSqr;
21372       // determine whether pos is in open-close-box:
21373       QCPRange boxKeyRange(it.value().key-mWidth*0.5, it.value().key+mWidth*0.5);
21374       QCPRange boxValueRange(it.value().close, it.value().open);
21375       double posKey, posValue;
21376       pixelsToCoords(pos, posKey, posValue);
21377       if (boxKeyRange.contains(posKey) && boxValueRange.contains(posValue)) // is in open-close-box
21378       {
21379         currentDistSqr = mParentPlot->selectionTolerance()*0.99 * mParentPlot->selectionTolerance()*0.99;
21380       } else
21381       {
21382         // calculate distance to high/low lines:
21383         double keyPixel = keyAxis->coordToPixel(it.value().key);
21384         double highLineDistSqr = distSqrToLine(QPointF(keyPixel, valueAxis->coordToPixel(it.value().high)), QPointF(keyPixel, valueAxis->coordToPixel(qMax(it.value().open, it.value().close))), pos);
21385         double lowLineDistSqr = distSqrToLine(QPointF(keyPixel, valueAxis->coordToPixel(it.value().low)), QPointF(keyPixel, valueAxis->coordToPixel(qMin(it.value().open, it.value().close))), pos);
21386         currentDistSqr = qMin(highLineDistSqr, lowLineDistSqr);
21387       }
21388       if (currentDistSqr < minDistSqr)
21389         minDistSqr = currentDistSqr;
21390     }
21391   } else // keyAxis->orientation() == Qt::Vertical
21392   {
21393     for (it = begin; it != end; ++it)
21394     {
21395       double currentDistSqr;
21396       // determine whether pos is in open-close-box:
21397       QCPRange boxKeyRange(it.value().key-mWidth*0.5, it.value().key+mWidth*0.5);
21398       QCPRange boxValueRange(it.value().close, it.value().open);
21399       double posKey, posValue;
21400       pixelsToCoords(pos, posKey, posValue);
21401       if (boxKeyRange.contains(posKey) && boxValueRange.contains(posValue)) // is in open-close-box
21402       {
21403         currentDistSqr = mParentPlot->selectionTolerance()*0.99 * mParentPlot->selectionTolerance()*0.99;
21404       } else
21405       {
21406         // calculate distance to high/low lines:
21407         double keyPixel = keyAxis->coordToPixel(it.value().key);
21408         double highLineDistSqr = distSqrToLine(QPointF(valueAxis->coordToPixel(it.value().high), keyPixel), QPointF(valueAxis->coordToPixel(qMax(it.value().open, it.value().close)), keyPixel), pos);
21409         double lowLineDistSqr = distSqrToLine(QPointF(valueAxis->coordToPixel(it.value().low), keyPixel), QPointF(valueAxis->coordToPixel(qMin(it.value().open, it.value().close)), keyPixel), pos);
21410         currentDistSqr = qMin(highLineDistSqr, lowLineDistSqr);
21411       }
21412       if (currentDistSqr < minDistSqr)
21413         minDistSqr = currentDistSqr;
21414     }
21415   }
21416   return qSqrt(minDistSqr);
21417 }
21418
21419 /*!  \internal
21420   
21421   called by the drawing methods to determine which data (key) range is visible at the current key
21422   axis range setting, so only that needs to be processed.
21423   
21424   \a lower returns an iterator to the lowest data point that needs to be taken into account when
21425   plotting. Note that in order to get a clean plot all the way to the edge of the axis rect, \a
21426   lower may still be just outside the visible range.
21427   
21428   \a upper returns an iterator to the highest data point. Same as before, \a upper may also lie
21429   just outside of the visible range.
21430   
21431   if the plottable contains no data, both \a lower and \a upper point to constEnd.
21432   
21433   \see QCPGraph::getVisibleDataBounds
21434 */
21435 void QCPFinancial::getVisibleDataBounds(QCPFinancialDataMap::const_iterator &lower, QCPFinancialDataMap::const_iterator &upper) const
21436 {
21437   if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
21438   if (mData->isEmpty())
21439   {
21440     lower = mData->constEnd();
21441     upper = mData->constEnd();
21442     return;
21443   }
21444   
21445   // get visible data range as QMap iterators
21446   QCPFinancialDataMap::const_iterator lbound = mData->lowerBound(mKeyAxis.data()->range().lower);
21447   QCPFinancialDataMap::const_iterator ubound = mData->upperBound(mKeyAxis.data()->range().upper);
21448   bool lowoutlier = lbound != mData->constBegin(); // indicates whether there exist points below axis range
21449   bool highoutlier = ubound != mData->constEnd(); // indicates whether there exist points above axis range
21450   
21451   lower = (lowoutlier ? lbound-1 : lbound); // data point range that will be actually drawn
21452   upper = (highoutlier ? ubound : ubound-1); // data point range that will be actually drawn
21453 }
21454
21455
21456 ////////////////////////////////////////////////////////////////////////////////////////////////////
21457 //////////////////// QCPItemStraightLine
21458 ////////////////////////////////////////////////////////////////////////////////////////////////////
21459
21460 /*! \class QCPItemStraightLine
21461   \brief A straight line that spans infinitely in both directions
21462
21463   \image html QCPItemStraightLine.png "Straight line example. Blue dotted circles are anchors, solid blue discs are positions."
21464
21465   It has two positions, \a point1 and \a point2, which define the straight line.
21466 */
21467
21468 /*!
21469   Creates a straight line item and sets default values.
21470   
21471   The constructed item can be added to the plot with QCustomPlot::addItem.
21472 */
21473 QCPItemStraightLine::QCPItemStraightLine(QCustomPlot *parentPlot) :
21474   QCPAbstractItem(parentPlot),
21475   point1(createPosition(QLatin1String("point1"))),
21476   point2(createPosition(QLatin1String("point2")))
21477 {
21478   point1->setCoords(0, 0);
21479   point2->setCoords(1, 1);
21480   
21481   setPen(QPen(Qt::black));
21482   setSelectedPen(QPen(Qt::blue,2));
21483 }
21484
21485 QCPItemStraightLine::~QCPItemStraightLine()
21486 {
21487 }
21488
21489 /*!
21490   Sets the pen that will be used to draw the line
21491   
21492   \see setSelectedPen
21493 */
21494 void QCPItemStraightLine::setPen(const QPen &pen)
21495 {
21496   mPen = pen;
21497 }
21498
21499 /*!
21500   Sets the pen that will be used to draw the line when selected
21501   
21502   \see setPen, setSelected
21503 */
21504 void QCPItemStraightLine::setSelectedPen(const QPen &pen)
21505 {
21506   mSelectedPen = pen;
21507 }
21508
21509 /* inherits documentation from base class */
21510 double QCPItemStraightLine::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
21511 {
21512   Q_UNUSED(details)
21513   if (onlySelectable && !mSelectable)
21514     return -1;
21515   
21516   return distToStraightLine(QVector2D(point1->pixelPoint()), QVector2D(point2->pixelPoint()-point1->pixelPoint()), QVector2D(pos));
21517 }
21518
21519 /* inherits documentation from base class */
21520 void QCPItemStraightLine::draw(QCPPainter *painter)
21521 {
21522   QVector2D start(point1->pixelPoint());
21523   QVector2D end(point2->pixelPoint());
21524   // get visible segment of straight line inside clipRect:
21525   double clipPad = mainPen().widthF();
21526   QLineF line = getRectClippedStraightLine(start, end-start, clipRect().adjusted(-clipPad, -clipPad, clipPad, clipPad));
21527   // paint visible segment, if existent:
21528   if (!line.isNull())
21529   {
21530     painter->setPen(mainPen());
21531     painter->drawLine(line);
21532   }
21533 }
21534
21535 /*! \internal
21536
21537   finds the shortest distance of \a point to the straight line defined by the base point \a
21538   base and the direction vector \a vec.
21539   
21540   This is a helper function for \ref selectTest.
21541 */
21542 double QCPItemStraightLine::distToStraightLine(const QVector2D &base, const QVector2D &vec, const QVector2D &point) const
21543 {
21544   return qAbs((base.y()-point.y())*vec.x()-(base.x()-point.x())*vec.y())/vec.length();
21545 }
21546
21547 /*! \internal
21548
21549   Returns the section of the straight line defined by \a base and direction vector \a
21550   vec, that is visible in the specified \a rect.
21551   
21552   This is a helper function for \ref draw.
21553 */
21554 QLineF QCPItemStraightLine::getRectClippedStraightLine(const QVector2D &base, const QVector2D &vec, const QRect &rect) const
21555 {
21556   double bx, by;
21557   double gamma;
21558   QLineF result;
21559   if (vec.x() == 0 && vec.y() == 0)
21560     return result;
21561   if (qFuzzyIsNull(vec.x())) // line is vertical
21562   {
21563     // check top of rect:
21564     bx = rect.left();
21565     by = rect.top();
21566     gamma = base.x()-bx + (by-base.y())*vec.x()/vec.y();
21567     if (gamma >= 0 && gamma <= rect.width())
21568       result.setLine(bx+gamma, rect.top(), bx+gamma, rect.bottom()); // no need to check bottom because we know line is vertical
21569   } else if (qFuzzyIsNull(vec.y())) // line is horizontal
21570   {
21571     // check left of rect:
21572     bx = rect.left();
21573     by = rect.top();
21574     gamma = base.y()-by + (bx-base.x())*vec.y()/vec.x();
21575     if (gamma >= 0 && gamma <= rect.height())
21576       result.setLine(rect.left(), by+gamma, rect.right(), by+gamma); // no need to check right because we know line is horizontal
21577   } else // line is skewed
21578   {
21579     QList<QVector2D> pointVectors;
21580     // check top of rect:
21581     bx = rect.left();
21582     by = rect.top();
21583     gamma = base.x()-bx + (by-base.y())*vec.x()/vec.y();
21584     if (gamma >= 0 && gamma <= rect.width())
21585       pointVectors.append(QVector2D(bx+gamma, by));
21586     // check bottom of rect:
21587     bx = rect.left();
21588     by = rect.bottom();
21589     gamma = base.x()-bx + (by-base.y())*vec.x()/vec.y();
21590     if (gamma >= 0 && gamma <= rect.width())
21591       pointVectors.append(QVector2D(bx+gamma, by));
21592     // check left of rect:
21593     bx = rect.left();
21594     by = rect.top();
21595     gamma = base.y()-by + (bx-base.x())*vec.y()/vec.x();
21596     if (gamma >= 0 && gamma <= rect.height())
21597       pointVectors.append(QVector2D(bx, by+gamma));
21598     // check right of rect:
21599     bx = rect.right();
21600     by = rect.top();
21601     gamma = base.y()-by + (bx-base.x())*vec.y()/vec.x();
21602     if (gamma >= 0 && gamma <= rect.height())
21603       pointVectors.append(QVector2D(bx, by+gamma));
21604     
21605     // evaluate points:
21606     if (pointVectors.size() == 2)
21607     {
21608       result.setPoints(pointVectors.at(0).toPointF(), pointVectors.at(1).toPointF());
21609     } else if (pointVectors.size() > 2)
21610     {
21611       // line probably goes through corner of rect, and we got two points there. single out the point pair with greatest distance:
21612       double distSqrMax = 0;
21613       QVector2D pv1, pv2;
21614       for (int i=0; i<pointVectors.size()-1; ++i)
21615       {
21616         for (int k=i+1; k<pointVectors.size(); ++k)
21617         {
21618           double distSqr = (pointVectors.at(i)-pointVectors.at(k)).lengthSquared();
21619           if (distSqr > distSqrMax)
21620           {
21621             pv1 = pointVectors.at(i);
21622             pv2 = pointVectors.at(k);
21623             distSqrMax = distSqr;
21624           }
21625         }
21626       }
21627       result.setPoints(pv1.toPointF(), pv2.toPointF());
21628     }
21629   }
21630   return result;
21631 }
21632
21633 /*! \internal
21634
21635   Returns the pen that should be used for drawing lines. Returns mPen when the
21636   item is not selected and mSelectedPen when it is.
21637 */
21638 QPen QCPItemStraightLine::mainPen() const
21639 {
21640   return mSelected ? mSelectedPen : mPen;
21641 }
21642
21643
21644 ////////////////////////////////////////////////////////////////////////////////////////////////////
21645 //////////////////// QCPItemLine
21646 ////////////////////////////////////////////////////////////////////////////////////////////////////
21647
21648 /*! \class QCPItemLine
21649   \brief A line from one point to another
21650
21651   \image html QCPItemLine.png "Line example. Blue dotted circles are anchors, solid blue discs are positions."
21652
21653   It has two positions, \a start and \a end, which define the end points of the line.
21654   
21655   With \ref setHead and \ref setTail you may set different line ending styles, e.g. to create an arrow.
21656 */
21657
21658 /*!
21659   Creates a line item and sets default values.
21660   
21661   The constructed item can be added to the plot with QCustomPlot::addItem.
21662 */
21663 QCPItemLine::QCPItemLine(QCustomPlot *parentPlot) :
21664   QCPAbstractItem(parentPlot),
21665   start(createPosition(QLatin1String("start"))),
21666   end(createPosition(QLatin1String("end")))
21667 {
21668   start->setCoords(0, 0);
21669   end->setCoords(1, 1);
21670   
21671   setPen(QPen(Qt::black));
21672   setSelectedPen(QPen(Qt::blue,2));
21673 }
21674
21675 QCPItemLine::~QCPItemLine()
21676 {
21677 }
21678
21679 /*!
21680   Sets the pen that will be used to draw the line
21681   
21682   \see setSelectedPen
21683 */
21684 void QCPItemLine::setPen(const QPen &pen)
21685 {
21686   mPen = pen;
21687 }
21688
21689 /*!
21690   Sets the pen that will be used to draw the line when selected
21691   
21692   \see setPen, setSelected
21693 */
21694 void QCPItemLine::setSelectedPen(const QPen &pen)
21695 {
21696   mSelectedPen = pen;
21697 }
21698
21699 /*!
21700   Sets the line ending style of the head. The head corresponds to the \a end position.
21701   
21702   Note that due to the overloaded QCPLineEnding constructor, you may directly specify
21703   a QCPLineEnding::EndingStyle here, e.g. \code setHead(QCPLineEnding::esSpikeArrow) \endcode
21704   
21705   \see setTail
21706 */
21707 void QCPItemLine::setHead(const QCPLineEnding &head)
21708 {
21709   mHead = head;
21710 }
21711
21712 /*!
21713   Sets the line ending style of the tail. The tail corresponds to the \a start position.
21714   
21715   Note that due to the overloaded QCPLineEnding constructor, you may directly specify
21716   a QCPLineEnding::EndingStyle here, e.g. \code setTail(QCPLineEnding::esSpikeArrow) \endcode
21717   
21718   \see setHead
21719 */
21720 void QCPItemLine::setTail(const QCPLineEnding &tail)
21721 {
21722   mTail = tail;
21723 }
21724
21725 /* inherits documentation from base class */
21726 double QCPItemLine::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
21727 {
21728   Q_UNUSED(details)
21729   if (onlySelectable && !mSelectable)
21730     return -1;
21731   
21732   return qSqrt(distSqrToLine(start->pixelPoint(), end->pixelPoint(), pos));
21733 }
21734
21735 /* inherits documentation from base class */
21736 void QCPItemLine::draw(QCPPainter *painter)
21737 {
21738   QVector2D startVec(start->pixelPoint());
21739   QVector2D endVec(end->pixelPoint());
21740   if (startVec.toPoint() == endVec.toPoint())
21741     return;
21742   // get visible segment of straight line inside clipRect:
21743   double clipPad = qMax(mHead.boundingDistance(), mTail.boundingDistance());
21744   clipPad = qMax(clipPad, (double)mainPen().widthF());
21745   QLineF line = getRectClippedLine(startVec, endVec, clipRect().adjusted(-clipPad, -clipPad, clipPad, clipPad));
21746   // paint visible segment, if existent:
21747   if (!line.isNull())
21748   {
21749     painter->setPen(mainPen());
21750     painter->drawLine(line);
21751     painter->setBrush(Qt::SolidPattern);
21752     if (mTail.style() != QCPLineEnding::esNone)
21753       mTail.draw(painter, startVec, startVec-endVec);
21754     if (mHead.style() != QCPLineEnding::esNone)
21755       mHead.draw(painter, endVec, endVec-startVec);
21756   }
21757 }
21758
21759 /*! \internal
21760
21761   Returns the section of the line defined by \a start and \a end, that is visible in the specified
21762   \a rect.
21763   
21764   This is a helper function for \ref draw.
21765 */
21766 QLineF QCPItemLine::getRectClippedLine(const QVector2D &start, const QVector2D &end, const QRect &rect) const
21767 {
21768   bool containsStart = rect.contains(start.x(), start.y());
21769   bool containsEnd = rect.contains(end.x(), end.y());
21770   if (containsStart && containsEnd)
21771     return QLineF(start.toPointF(), end.toPointF());
21772   
21773   QVector2D base = start;
21774   QVector2D vec = end-start;
21775   double bx, by;
21776   double gamma, mu;
21777   QLineF result;
21778   QList<QVector2D> pointVectors;
21779
21780   if (!qFuzzyIsNull(vec.y())) // line is not horizontal
21781   {
21782     // check top of rect:
21783     bx = rect.left();
21784     by = rect.top();
21785     mu = (by-base.y())/vec.y();
21786     if (mu >= 0 && mu <= 1)
21787     {
21788       gamma = base.x()-bx + mu*vec.x();
21789       if (gamma >= 0 && gamma <= rect.width())
21790         pointVectors.append(QVector2D(bx+gamma, by));
21791     }
21792     // check bottom of rect:
21793     bx = rect.left();
21794     by = rect.bottom();
21795     mu = (by-base.y())/vec.y();
21796     if (mu >= 0 && mu <= 1)
21797     {
21798       gamma = base.x()-bx + mu*vec.x();
21799       if (gamma >= 0 && gamma <= rect.width())
21800         pointVectors.append(QVector2D(bx+gamma, by));
21801     }
21802   }
21803   if (!qFuzzyIsNull(vec.x())) // line is not vertical
21804   {
21805     // check left of rect:
21806     bx = rect.left();
21807     by = rect.top();
21808     mu = (bx-base.x())/vec.x();
21809     if (mu >= 0 && mu <= 1)
21810     {
21811       gamma = base.y()-by + mu*vec.y();
21812       if (gamma >= 0 && gamma <= rect.height())
21813         pointVectors.append(QVector2D(bx, by+gamma));
21814     }
21815     // check right of rect:
21816     bx = rect.right();
21817     by = rect.top();
21818     mu = (bx-base.x())/vec.x();
21819     if (mu >= 0 && mu <= 1)
21820     {
21821       gamma = base.y()-by + mu*vec.y();
21822       if (gamma >= 0 && gamma <= rect.height())
21823         pointVectors.append(QVector2D(bx, by+gamma));
21824     }
21825   }
21826   
21827   if (containsStart)
21828     pointVectors.append(start);
21829   if (containsEnd)
21830     pointVectors.append(end);
21831   
21832   // evaluate points:
21833   if (pointVectors.size() == 2)
21834   {
21835     result.setPoints(pointVectors.at(0).toPointF(), pointVectors.at(1).toPointF());
21836   } else if (pointVectors.size() > 2)
21837   {
21838     // line probably goes through corner of rect, and we got two points there. single out the point pair with greatest distance:
21839     double distSqrMax = 0;
21840     QVector2D pv1, pv2;
21841     for (int i=0; i<pointVectors.size()-1; ++i)
21842     {
21843       for (int k=i+1; k<pointVectors.size(); ++k)
21844       {
21845         double distSqr = (pointVectors.at(i)-pointVectors.at(k)).lengthSquared();
21846         if (distSqr > distSqrMax)
21847         {
21848           pv1 = pointVectors.at(i);
21849           pv2 = pointVectors.at(k);
21850           distSqrMax = distSqr;
21851         }
21852       }
21853     }
21854     result.setPoints(pv1.toPointF(), pv2.toPointF());
21855   }
21856   return result;
21857 }
21858
21859 /*! \internal
21860
21861   Returns the pen that should be used for drawing lines. Returns mPen when the
21862   item is not selected and mSelectedPen when it is.
21863 */
21864 QPen QCPItemLine::mainPen() const
21865 {
21866   return mSelected ? mSelectedPen : mPen;
21867 }
21868
21869
21870 ////////////////////////////////////////////////////////////////////////////////////////////////////
21871 //////////////////// QCPItemCurve
21872 ////////////////////////////////////////////////////////////////////////////////////////////////////
21873
21874 /*! \class QCPItemCurve
21875   \brief A curved line from one point to another
21876
21877   \image html QCPItemCurve.png "Curve example. Blue dotted circles are anchors, solid blue discs are positions."
21878
21879   It has four positions, \a start and \a end, which define the end points of the line, and two
21880   control points which define the direction the line exits from the start and the direction from
21881   which it approaches the end: \a startDir and \a endDir.
21882   
21883   With \ref setHead and \ref setTail you may set different line ending styles, e.g. to create an
21884   arrow.
21885   
21886   Often it is desirable for the control points to stay at fixed relative positions to the start/end
21887   point. This can be achieved by setting the parent anchor e.g. of \a startDir simply to \a start,
21888   and then specify the desired pixel offset with QCPItemPosition::setCoords on \a startDir.
21889 */
21890
21891 /*!
21892   Creates a curve item and sets default values.
21893   
21894   The constructed item can be added to the plot with QCustomPlot::addItem.
21895 */
21896 QCPItemCurve::QCPItemCurve(QCustomPlot *parentPlot) :
21897   QCPAbstractItem(parentPlot),
21898   start(createPosition(QLatin1String("start"))),
21899   startDir(createPosition(QLatin1String("startDir"))),
21900   endDir(createPosition(QLatin1String("endDir"))),
21901   end(createPosition(QLatin1String("end")))
21902 {
21903   start->setCoords(0, 0);
21904   startDir->setCoords(0.5, 0);
21905   endDir->setCoords(0, 0.5);
21906   end->setCoords(1, 1);
21907   
21908   setPen(QPen(Qt::black));
21909   setSelectedPen(QPen(Qt::blue,2));
21910 }
21911
21912 QCPItemCurve::~QCPItemCurve()
21913 {
21914 }
21915
21916 /*!
21917   Sets the pen that will be used to draw the line
21918   
21919   \see setSelectedPen
21920 */
21921 void QCPItemCurve::setPen(const QPen &pen)
21922 {
21923   mPen = pen;
21924 }
21925
21926 /*!
21927   Sets the pen that will be used to draw the line when selected
21928   
21929   \see setPen, setSelected
21930 */
21931 void QCPItemCurve::setSelectedPen(const QPen &pen)
21932 {
21933   mSelectedPen = pen;
21934 }
21935
21936 /*!
21937   Sets the line ending style of the head. The head corresponds to the \a end position.
21938   
21939   Note that due to the overloaded QCPLineEnding constructor, you may directly specify
21940   a QCPLineEnding::EndingStyle here, e.g. \code setHead(QCPLineEnding::esSpikeArrow) \endcode
21941   
21942   \see setTail
21943 */
21944 void QCPItemCurve::setHead(const QCPLineEnding &head)
21945 {
21946   mHead = head;
21947 }
21948
21949 /*!
21950   Sets the line ending style of the tail. The tail corresponds to the \a start position.
21951   
21952   Note that due to the overloaded QCPLineEnding constructor, you may directly specify
21953   a QCPLineEnding::EndingStyle here, e.g. \code setTail(QCPLineEnding::esSpikeArrow) \endcode
21954   
21955   \see setHead
21956 */
21957 void QCPItemCurve::setTail(const QCPLineEnding &tail)
21958 {
21959   mTail = tail;
21960 }
21961
21962 /* inherits documentation from base class */
21963 double QCPItemCurve::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
21964 {
21965   Q_UNUSED(details)
21966   if (onlySelectable && !mSelectable)
21967     return -1;
21968   
21969   QPointF startVec(start->pixelPoint());
21970   QPointF startDirVec(startDir->pixelPoint());
21971   QPointF endDirVec(endDir->pixelPoint());
21972   QPointF endVec(end->pixelPoint());
21973
21974   QPainterPath cubicPath(startVec);
21975   cubicPath.cubicTo(startDirVec, endDirVec, endVec);
21976   
21977   QPolygonF polygon = cubicPath.toSubpathPolygons().first();
21978   double minDistSqr = std::numeric_limits<double>::max();
21979   for (int i=1; i<polygon.size(); ++i)
21980   {
21981     double distSqr = distSqrToLine(polygon.at(i-1), polygon.at(i), pos);
21982     if (distSqr < minDistSqr)
21983       minDistSqr = distSqr;
21984   }
21985   return qSqrt(minDistSqr);
21986 }
21987
21988 /* inherits documentation from base class */
21989 void QCPItemCurve::draw(QCPPainter *painter)
21990 {
21991   QPointF startVec(start->pixelPoint());
21992   QPointF startDirVec(startDir->pixelPoint());
21993   QPointF endDirVec(endDir->pixelPoint());
21994   QPointF endVec(end->pixelPoint());
21995   if (QVector2D(endVec-startVec).length() > 1e10f) // too large curves cause crash
21996     return;
21997
21998   QPainterPath cubicPath(startVec);
21999   cubicPath.cubicTo(startDirVec, endDirVec, endVec);
22000
22001   // paint visible segment, if existent:
22002   QRect clip = clipRect().adjusted(-mainPen().widthF(), -mainPen().widthF(), mainPen().widthF(), mainPen().widthF());
22003   QRect cubicRect = cubicPath.controlPointRect().toRect();
22004   if (cubicRect.isEmpty()) // may happen when start and end exactly on same x or y position
22005     cubicRect.adjust(0, 0, 1, 1);
22006   if (clip.intersects(cubicRect))
22007   {
22008     painter->setPen(mainPen());
22009     painter->drawPath(cubicPath);
22010     painter->setBrush(Qt::SolidPattern);
22011     if (mTail.style() != QCPLineEnding::esNone)
22012       mTail.draw(painter, QVector2D(startVec), M_PI-cubicPath.angleAtPercent(0)/180.0*M_PI);
22013     if (mHead.style() != QCPLineEnding::esNone)
22014       mHead.draw(painter, QVector2D(endVec), -cubicPath.angleAtPercent(1)/180.0*M_PI);
22015   }
22016 }
22017
22018 /*! \internal
22019
22020   Returns the pen that should be used for drawing lines. Returns mPen when the
22021   item is not selected and mSelectedPen when it is.
22022 */
22023 QPen QCPItemCurve::mainPen() const
22024 {
22025   return mSelected ? mSelectedPen : mPen;
22026 }
22027
22028
22029 ////////////////////////////////////////////////////////////////////////////////////////////////////
22030 //////////////////// QCPItemRect
22031 ////////////////////////////////////////////////////////////////////////////////////////////////////
22032
22033 /*! \class QCPItemRect
22034   \brief A rectangle
22035
22036   \image html QCPItemRect.png "Rectangle example. Blue dotted circles are anchors, solid blue discs are positions."
22037
22038   It has two positions, \a topLeft and \a bottomRight, which define the rectangle.
22039 */
22040
22041 /*!
22042   Creates a rectangle item and sets default values.
22043   
22044   The constructed item can be added to the plot with QCustomPlot::addItem.
22045 */
22046 QCPItemRect::QCPItemRect(QCustomPlot *parentPlot) :
22047   QCPAbstractItem(parentPlot),
22048   topLeft(createPosition(QLatin1String("topLeft"))),
22049   bottomRight(createPosition(QLatin1String("bottomRight"))),
22050   top(createAnchor(QLatin1String("top"), aiTop)),
22051   topRight(createAnchor(QLatin1String("topRight"), aiTopRight)),
22052   right(createAnchor(QLatin1String("right"), aiRight)),
22053   bottom(createAnchor(QLatin1String("bottom"), aiBottom)),
22054   bottomLeft(createAnchor(QLatin1String("bottomLeft"), aiBottomLeft)),
22055   left(createAnchor(QLatin1String("left"), aiLeft))
22056 {
22057   topLeft->setCoords(0, 1);
22058   bottomRight->setCoords(1, 0);
22059   
22060   setPen(QPen(Qt::black));
22061   setSelectedPen(QPen(Qt::blue,2));
22062   setBrush(Qt::NoBrush);
22063   setSelectedBrush(Qt::NoBrush);
22064 }
22065
22066 QCPItemRect::~QCPItemRect()
22067 {
22068 }
22069
22070 /*!
22071   Sets the pen that will be used to draw the line of the rectangle
22072   
22073   \see setSelectedPen, setBrush
22074 */
22075 void QCPItemRect::setPen(const QPen &pen)
22076 {
22077   mPen = pen;
22078 }
22079
22080 /*!
22081   Sets the pen that will be used to draw the line of the rectangle when selected
22082   
22083   \see setPen, setSelected
22084 */
22085 void QCPItemRect::setSelectedPen(const QPen &pen)
22086 {
22087   mSelectedPen = pen;
22088 }
22089
22090 /*!
22091   Sets the brush that will be used to fill the rectangle. To disable filling, set \a brush to
22092   Qt::NoBrush.
22093   
22094   \see setSelectedBrush, setPen
22095 */
22096 void QCPItemRect::setBrush(const QBrush &brush)
22097 {
22098   mBrush = brush;
22099 }
22100
22101 /*!
22102   Sets the brush that will be used to fill the rectangle when selected. To disable filling, set \a
22103   brush to Qt::NoBrush.
22104   
22105   \see setBrush
22106 */
22107 void QCPItemRect::setSelectedBrush(const QBrush &brush)
22108 {
22109   mSelectedBrush = brush;
22110 }
22111
22112 /* inherits documentation from base class */
22113 double QCPItemRect::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
22114 {
22115   Q_UNUSED(details)
22116   if (onlySelectable && !mSelectable)
22117     return -1;
22118   
22119   QRectF rect = QRectF(topLeft->pixelPoint(), bottomRight->pixelPoint()).normalized();
22120   bool filledRect = mBrush.style() != Qt::NoBrush && mBrush.color().alpha() != 0;
22121   return rectSelectTest(rect, pos, filledRect);
22122 }
22123
22124 /* inherits documentation from base class */
22125 void QCPItemRect::draw(QCPPainter *painter)
22126 {
22127   QPointF p1 = topLeft->pixelPoint();
22128   QPointF p2 = bottomRight->pixelPoint();
22129   if (p1.toPoint() == p2.toPoint())
22130     return;
22131   QRectF rect = QRectF(p1, p2).normalized();
22132   double clipPad = mainPen().widthF();
22133   QRectF boundingRect = rect.adjusted(-clipPad, -clipPad, clipPad, clipPad);
22134   if (boundingRect.intersects(clipRect())) // only draw if bounding rect of rect item is visible in cliprect
22135   {
22136     painter->setPen(mainPen());
22137     painter->setBrush(mainBrush());
22138     painter->drawRect(rect);
22139   }
22140 }
22141
22142 /* inherits documentation from base class */
22143 QPointF QCPItemRect::anchorPixelPoint(int anchorId) const
22144 {
22145   QRectF rect = QRectF(topLeft->pixelPoint(), bottomRight->pixelPoint());
22146   switch (anchorId)
22147   {
22148     case aiTop:         return (rect.topLeft()+rect.topRight())*0.5;
22149     case aiTopRight:    return rect.topRight();
22150     case aiRight:       return (rect.topRight()+rect.bottomRight())*0.5;
22151     case aiBottom:      return (rect.bottomLeft()+rect.bottomRight())*0.5;
22152     case aiBottomLeft:  return rect.bottomLeft();
22153     case aiLeft:        return (rect.topLeft()+rect.bottomLeft())*0.5;
22154   }
22155   
22156   qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId;
22157   return QPointF();
22158 }
22159
22160 /*! \internal
22161
22162   Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected
22163   and mSelectedPen when it is.
22164 */
22165 QPen QCPItemRect::mainPen() const
22166 {
22167   return mSelected ? mSelectedPen : mPen;
22168 }
22169
22170 /*! \internal
22171
22172   Returns the brush that should be used for drawing fills of the item. Returns mBrush when the item
22173   is not selected and mSelectedBrush when it is.
22174 */
22175 QBrush QCPItemRect::mainBrush() const
22176 {
22177   return mSelected ? mSelectedBrush : mBrush;
22178 }
22179
22180
22181 ////////////////////////////////////////////////////////////////////////////////////////////////////
22182 //////////////////// QCPItemText
22183 ////////////////////////////////////////////////////////////////////////////////////////////////////
22184
22185 /*! \class QCPItemText
22186   \brief A text label
22187
22188   \image html QCPItemText.png "Text example. Blue dotted circles are anchors, solid blue discs are positions."
22189
22190   Its position is defined by the member \a position and the setting of \ref setPositionAlignment.
22191   The latter controls which part of the text rect shall be aligned with \a position.
22192   
22193   The text alignment itself (i.e. left, center, right) can be controlled with \ref
22194   setTextAlignment.
22195   
22196   The text may be rotated around the \a position point with \ref setRotation.
22197 */
22198
22199 /*!
22200   Creates a text item and sets default values.
22201   
22202   The constructed item can be added to the plot with QCustomPlot::addItem.
22203 */
22204 QCPItemText::QCPItemText(QCustomPlot *parentPlot) :
22205   QCPAbstractItem(parentPlot),
22206   position(createPosition(QLatin1String("position"))),
22207   topLeft(createAnchor(QLatin1String("topLeft"), aiTopLeft)),
22208   top(createAnchor(QLatin1String("top"), aiTop)),
22209   topRight(createAnchor(QLatin1String("topRight"), aiTopRight)),
22210   right(createAnchor(QLatin1String("right"), aiRight)),
22211   bottomRight(createAnchor(QLatin1String("bottomRight"), aiBottomRight)),
22212   bottom(createAnchor(QLatin1String("bottom"), aiBottom)),
22213   bottomLeft(createAnchor(QLatin1String("bottomLeft"), aiBottomLeft)),
22214   left(createAnchor(QLatin1String("left"), aiLeft))
22215 {
22216   position->setCoords(0, 0);
22217   
22218   setRotation(0);
22219   setTextAlignment(Qt::AlignTop|Qt::AlignHCenter);
22220   setPositionAlignment(Qt::AlignCenter);
22221   setText(QLatin1String("text"));
22222   
22223   setPen(Qt::NoPen);
22224   setSelectedPen(Qt::NoPen);
22225   setBrush(Qt::NoBrush);
22226   setSelectedBrush(Qt::NoBrush);
22227   setColor(Qt::black);
22228   setSelectedColor(Qt::blue);
22229 }
22230
22231 QCPItemText::~QCPItemText()
22232 {
22233 }
22234
22235 /*!
22236   Sets the color of the text.
22237 */
22238 void QCPItemText::setColor(const QColor &color)
22239 {
22240   mColor = color;
22241 }
22242
22243 /*!
22244   Sets the color of the text that will be used when the item is selected.
22245 */
22246 void QCPItemText::setSelectedColor(const QColor &color)
22247 {
22248   mSelectedColor = color;
22249 }
22250
22251 /*!
22252   Sets the pen that will be used do draw a rectangular border around the text. To disable the
22253   border, set \a pen to Qt::NoPen.
22254   
22255   \see setSelectedPen, setBrush, setPadding
22256 */
22257 void QCPItemText::setPen(const QPen &pen)
22258 {
22259   mPen = pen;
22260 }
22261
22262 /*!
22263   Sets the pen that will be used do draw a rectangular border around the text, when the item is
22264   selected. To disable the border, set \a pen to Qt::NoPen.
22265   
22266   \see setPen
22267 */
22268 void QCPItemText::setSelectedPen(const QPen &pen)
22269 {
22270   mSelectedPen = pen;
22271 }
22272
22273 /*!
22274   Sets the brush that will be used do fill the background of the text. To disable the
22275   background, set \a brush to Qt::NoBrush.
22276   
22277   \see setSelectedBrush, setPen, setPadding
22278 */
22279 void QCPItemText::setBrush(const QBrush &brush)
22280 {
22281   mBrush = brush;
22282 }
22283
22284 /*!
22285   Sets the brush that will be used do fill the background of the text, when the item is selected. To disable the
22286   background, set \a brush to Qt::NoBrush.
22287   
22288   \see setBrush
22289 */
22290 void QCPItemText::setSelectedBrush(const QBrush &brush)
22291 {
22292   mSelectedBrush = brush;
22293 }
22294
22295 /*!
22296   Sets the font of the text.
22297   
22298   \see setSelectedFont, setColor
22299 */
22300 void QCPItemText::setFont(const QFont &font)
22301 {
22302   mFont = font;
22303 }
22304
22305 /*!
22306   Sets the font of the text that will be used when the item is selected.
22307   
22308   \see setFont
22309 */
22310 void QCPItemText::setSelectedFont(const QFont &font)
22311 {
22312   mSelectedFont = font;
22313 }
22314
22315 /*!
22316   Sets the text that will be displayed. Multi-line texts are supported by inserting a line break
22317   character, e.g. '\n'.
22318   
22319   \see setFont, setColor, setTextAlignment
22320 */
22321 void QCPItemText::setText(const QString &text)
22322 {
22323   mText = text;
22324 }
22325
22326 /*!
22327   Sets which point of the text rect shall be aligned with \a position.
22328   
22329   Examples:
22330   \li If \a alignment is <tt>Qt::AlignHCenter | Qt::AlignTop</tt>, the text will be positioned such
22331   that the top of the text rect will be horizontally centered on \a position.
22332   \li If \a alignment is <tt>Qt::AlignLeft | Qt::AlignBottom</tt>, \a position will indicate the
22333   bottom left corner of the text rect.
22334   
22335   If you want to control the alignment of (multi-lined) text within the text rect, use \ref
22336   setTextAlignment.
22337 */
22338 void QCPItemText::setPositionAlignment(Qt::Alignment alignment)
22339 {
22340   mPositionAlignment = alignment;
22341 }
22342
22343 /*!
22344   Controls how (multi-lined) text is aligned inside the text rect (typically Qt::AlignLeft, Qt::AlignCenter or Qt::AlignRight).
22345 */
22346 void QCPItemText::setTextAlignment(Qt::Alignment alignment)
22347 {
22348   mTextAlignment = alignment;
22349 }
22350
22351 /*!
22352   Sets the angle in degrees by which the text (and the text rectangle, if visible) will be rotated
22353   around \a position.
22354 */
22355 void QCPItemText::setRotation(double degrees)
22356 {
22357   mRotation = degrees;
22358 }
22359
22360 /*!
22361   Sets the distance between the border of the text rectangle and the text. The appearance (and
22362   visibility) of the text rectangle can be controlled with \ref setPen and \ref setBrush.
22363 */
22364 void QCPItemText::setPadding(const QMargins &padding)
22365 {
22366   mPadding = padding;
22367 }
22368
22369 /* inherits documentation from base class */
22370 double QCPItemText::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
22371 {
22372   Q_UNUSED(details)
22373   if (onlySelectable && !mSelectable)
22374     return -1;
22375   
22376   // The rect may be rotated, so we transform the actual clicked pos to the rotated
22377   // coordinate system, so we can use the normal rectSelectTest function for non-rotated rects:
22378   QPointF positionPixels(position->pixelPoint());
22379   QTransform inputTransform;
22380   inputTransform.translate(positionPixels.x(), positionPixels.y());
22381   inputTransform.rotate(-mRotation);
22382   inputTransform.translate(-positionPixels.x(), -positionPixels.y());
22383   QPointF rotatedPos = inputTransform.map(pos);
22384   QFontMetrics fontMetrics(mFont);
22385   QRect textRect = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip|mTextAlignment, mText);
22386   QRect textBoxRect = textRect.adjusted(-mPadding.left(), -mPadding.top(), mPadding.right(), mPadding.bottom());
22387   QPointF textPos = getTextDrawPoint(positionPixels, textBoxRect, mPositionAlignment);
22388   textBoxRect.moveTopLeft(textPos.toPoint());
22389
22390   return rectSelectTest(textBoxRect, rotatedPos, true);
22391 }
22392
22393 /* inherits documentation from base class */
22394 void QCPItemText::draw(QCPPainter *painter)
22395 {
22396   QPointF pos(position->pixelPoint());
22397   QTransform transform = painter->transform();
22398   transform.translate(pos.x(), pos.y());
22399   if (!qFuzzyIsNull(mRotation))
22400     transform.rotate(mRotation);
22401   painter->setFont(mainFont());
22402   QRect textRect = painter->fontMetrics().boundingRect(0, 0, 0, 0, Qt::TextDontClip|mTextAlignment, mText);
22403   QRect textBoxRect = textRect.adjusted(-mPadding.left(), -mPadding.top(), mPadding.right(), mPadding.bottom());
22404   QPointF textPos = getTextDrawPoint(QPointF(0, 0), textBoxRect, mPositionAlignment); // 0, 0 because the transform does the translation
22405   textRect.moveTopLeft(textPos.toPoint()+QPoint(mPadding.left(), mPadding.top()));
22406   textBoxRect.moveTopLeft(textPos.toPoint());
22407   double clipPad = mainPen().widthF();
22408   QRect boundingRect = textBoxRect.adjusted(-clipPad, -clipPad, clipPad, clipPad);
22409   if (transform.mapRect(boundingRect).intersects(painter->transform().mapRect(clipRect())))
22410   {
22411     painter->setTransform(transform);
22412     if ((mainBrush().style() != Qt::NoBrush && mainBrush().color().alpha() != 0) ||
22413         (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0))
22414     {
22415       painter->setPen(mainPen());
22416       painter->setBrush(mainBrush());
22417       painter->drawRect(textBoxRect);
22418     }
22419     painter->setBrush(Qt::NoBrush);
22420     painter->setPen(QPen(mainColor()));
22421     painter->drawText(textRect, Qt::TextDontClip|mTextAlignment, mText);
22422   }
22423 }
22424
22425 /* inherits documentation from base class */
22426 QPointF QCPItemText::anchorPixelPoint(int anchorId) const
22427 {
22428   // get actual rect points (pretty much copied from draw function):
22429   QPointF pos(position->pixelPoint());
22430   QTransform transform;
22431   transform.translate(pos.x(), pos.y());
22432   if (!qFuzzyIsNull(mRotation))
22433     transform.rotate(mRotation);
22434   QFontMetrics fontMetrics(mainFont());
22435   QRect textRect = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip|mTextAlignment, mText);
22436   QRectF textBoxRect = textRect.adjusted(-mPadding.left(), -mPadding.top(), mPadding.right(), mPadding.bottom());
22437   QPointF textPos = getTextDrawPoint(QPointF(0, 0), textBoxRect, mPositionAlignment); // 0, 0 because the transform does the translation
22438   textBoxRect.moveTopLeft(textPos.toPoint());
22439   QPolygonF rectPoly = transform.map(QPolygonF(textBoxRect));
22440   
22441   switch (anchorId)
22442   {
22443     case aiTopLeft:     return rectPoly.at(0);
22444     case aiTop:         return (rectPoly.at(0)+rectPoly.at(1))*0.5;
22445     case aiTopRight:    return rectPoly.at(1);
22446     case aiRight:       return (rectPoly.at(1)+rectPoly.at(2))*0.5;
22447     case aiBottomRight: return rectPoly.at(2);
22448     case aiBottom:      return (rectPoly.at(2)+rectPoly.at(3))*0.5;
22449     case aiBottomLeft:  return rectPoly.at(3);
22450     case aiLeft:        return (rectPoly.at(3)+rectPoly.at(0))*0.5;
22451   }
22452   
22453   qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId;
22454   return QPointF();
22455 }
22456
22457 /*! \internal
22458   
22459   Returns the point that must be given to the QPainter::drawText function (which expects the top
22460   left point of the text rect), according to the position \a pos, the text bounding box \a rect and
22461   the requested \a positionAlignment.
22462   
22463   For example, if \a positionAlignment is <tt>Qt::AlignLeft | Qt::AlignBottom</tt> the returned point
22464   will be shifted upward by the height of \a rect, starting from \a pos. So if the text is finally
22465   drawn at that point, the lower left corner of the resulting text rect is at \a pos.
22466 */
22467 QPointF QCPItemText::getTextDrawPoint(const QPointF &pos, const QRectF &rect, Qt::Alignment positionAlignment) const
22468 {
22469   if (positionAlignment == 0 || positionAlignment == (Qt::AlignLeft|Qt::AlignTop))
22470     return pos;
22471   
22472   QPointF result = pos; // start at top left
22473   if (positionAlignment.testFlag(Qt::AlignHCenter))
22474     result.rx() -= rect.width()/2.0;
22475   else if (positionAlignment.testFlag(Qt::AlignRight))
22476     result.rx() -= rect.width();
22477   if (positionAlignment.testFlag(Qt::AlignVCenter))
22478     result.ry() -= rect.height()/2.0;
22479   else if (positionAlignment.testFlag(Qt::AlignBottom))
22480     result.ry() -= rect.height();
22481   return result;
22482 }
22483
22484 /*! \internal
22485
22486   Returns the font that should be used for drawing text. Returns mFont when the item is not selected
22487   and mSelectedFont when it is.
22488 */
22489 QFont QCPItemText::mainFont() const
22490 {
22491   return mSelected ? mSelectedFont : mFont;
22492 }
22493
22494 /*! \internal
22495
22496   Returns the color that should be used for drawing text. Returns mColor when the item is not
22497   selected and mSelectedColor when it is.
22498 */
22499 QColor QCPItemText::mainColor() const
22500 {
22501   return mSelected ? mSelectedColor : mColor;
22502 }
22503
22504 /*! \internal
22505
22506   Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected
22507   and mSelectedPen when it is.
22508 */
22509 QPen QCPItemText::mainPen() const
22510 {
22511   return mSelected ? mSelectedPen : mPen;
22512 }
22513
22514 /*! \internal
22515
22516   Returns the brush that should be used for drawing fills of the item. Returns mBrush when the item
22517   is not selected and mSelectedBrush when it is.
22518 */
22519 QBrush QCPItemText::mainBrush() const
22520 {
22521   return mSelected ? mSelectedBrush : mBrush;
22522 }
22523
22524
22525 ////////////////////////////////////////////////////////////////////////////////////////////////////
22526 //////////////////// QCPItemEllipse
22527 ////////////////////////////////////////////////////////////////////////////////////////////////////
22528
22529 /*! \class QCPItemEllipse
22530   \brief An ellipse
22531
22532   \image html QCPItemEllipse.png "Ellipse example. Blue dotted circles are anchors, solid blue discs are positions."
22533
22534   It has two positions, \a topLeft and \a bottomRight, which define the rect the ellipse will be drawn in.
22535 */
22536
22537 /*!
22538   Creates an ellipse item and sets default values.
22539   
22540   The constructed item can be added to the plot with QCustomPlot::addItem.
22541 */
22542 QCPItemEllipse::QCPItemEllipse(QCustomPlot *parentPlot) :
22543   QCPAbstractItem(parentPlot),
22544   topLeft(createPosition(QLatin1String("topLeft"))),
22545   bottomRight(createPosition(QLatin1String("bottomRight"))),
22546   topLeftRim(createAnchor(QLatin1String("topLeftRim"), aiTopLeftRim)),
22547   top(createAnchor(QLatin1String("top"), aiTop)),
22548   topRightRim(createAnchor(QLatin1String("topRightRim"), aiTopRightRim)),
22549   right(createAnchor(QLatin1String("right"), aiRight)),
22550   bottomRightRim(createAnchor(QLatin1String("bottomRightRim"), aiBottomRightRim)),
22551   bottom(createAnchor(QLatin1String("bottom"), aiBottom)),
22552   bottomLeftRim(createAnchor(QLatin1String("bottomLeftRim"), aiBottomLeftRim)),
22553   left(createAnchor(QLatin1String("left"), aiLeft)),
22554   center(createAnchor(QLatin1String("center"), aiCenter))
22555 {
22556   topLeft->setCoords(0, 1);
22557   bottomRight->setCoords(1, 0);
22558   
22559   setPen(QPen(Qt::black));
22560   setSelectedPen(QPen(Qt::blue, 2));
22561   setBrush(Qt::NoBrush);
22562   setSelectedBrush(Qt::NoBrush);
22563 }
22564
22565 QCPItemEllipse::~QCPItemEllipse()
22566 {
22567 }
22568
22569 /*!
22570   Sets the pen that will be used to draw the line of the ellipse
22571   
22572   \see setSelectedPen, setBrush
22573 */
22574 void QCPItemEllipse::setPen(const QPen &pen)
22575 {
22576   mPen = pen;
22577 }
22578
22579 /*!
22580   Sets the pen that will be used to draw the line of the ellipse when selected
22581   
22582   \see setPen, setSelected
22583 */
22584 void QCPItemEllipse::setSelectedPen(const QPen &pen)
22585 {
22586   mSelectedPen = pen;
22587 }
22588
22589 /*!
22590   Sets the brush that will be used to fill the ellipse. To disable filling, set \a brush to
22591   Qt::NoBrush.
22592   
22593   \see setSelectedBrush, setPen
22594 */
22595 void QCPItemEllipse::setBrush(const QBrush &brush)
22596 {
22597   mBrush = brush;
22598 }
22599
22600 /*!
22601   Sets the brush that will be used to fill the ellipse when selected. To disable filling, set \a
22602   brush to Qt::NoBrush.
22603   
22604   \see setBrush
22605 */
22606 void QCPItemEllipse::setSelectedBrush(const QBrush &brush)
22607 {
22608   mSelectedBrush = brush;
22609 }
22610
22611 /* inherits documentation from base class */
22612 double QCPItemEllipse::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
22613 {
22614   Q_UNUSED(details)
22615   if (onlySelectable && !mSelectable)
22616     return -1;
22617   
22618   double result = -1;
22619   QPointF p1 = topLeft->pixelPoint();
22620   QPointF p2 = bottomRight->pixelPoint();
22621   QPointF center((p1+p2)/2.0);
22622   double a = qAbs(p1.x()-p2.x())/2.0;
22623   double b = qAbs(p1.y()-p2.y())/2.0;
22624   double x = pos.x()-center.x();
22625   double y = pos.y()-center.y();
22626   
22627   // distance to border:
22628   double c = 1.0/qSqrt(x*x/(a*a)+y*y/(b*b));
22629   result = qAbs(c-1)*qSqrt(x*x+y*y);
22630   // filled ellipse, allow click inside to count as hit:
22631   if (result > mParentPlot->selectionTolerance()*0.99 && mBrush.style() != Qt::NoBrush && mBrush.color().alpha() != 0)
22632   {
22633     if (x*x/(a*a) + y*y/(b*b) <= 1)
22634       result = mParentPlot->selectionTolerance()*0.99;
22635   }
22636   return result;
22637 }
22638
22639 /* inherits documentation from base class */
22640 void QCPItemEllipse::draw(QCPPainter *painter)
22641 {
22642   QPointF p1 = topLeft->pixelPoint();
22643   QPointF p2 = bottomRight->pixelPoint();
22644   if (p1.toPoint() == p2.toPoint())
22645     return;
22646   QRectF ellipseRect = QRectF(p1, p2).normalized();
22647   QRect clip = clipRect().adjusted(-mainPen().widthF(), -mainPen().widthF(), mainPen().widthF(), mainPen().widthF());
22648   if (ellipseRect.intersects(clip)) // only draw if bounding rect of ellipse is visible in cliprect
22649   {
22650     painter->setPen(mainPen());
22651     painter->setBrush(mainBrush());
22652 #ifdef __EXCEPTIONS
22653     try // drawEllipse sometimes throws exceptions if ellipse is too big
22654     {
22655 #endif
22656       painter->drawEllipse(ellipseRect);
22657 #ifdef __EXCEPTIONS
22658     } catch (...)
22659     {
22660       qDebug() << Q_FUNC_INFO << "Item too large for memory, setting invisible";
22661       setVisible(false);
22662     }
22663 #endif
22664   }
22665 }
22666
22667 /* inherits documentation from base class */
22668 QPointF QCPItemEllipse::anchorPixelPoint(int anchorId) const
22669 {
22670   QRectF rect = QRectF(topLeft->pixelPoint(), bottomRight->pixelPoint());
22671   switch (anchorId)
22672   {
22673     case aiTopLeftRim:     return rect.center()+(rect.topLeft()-rect.center())*1/qSqrt(2);
22674     case aiTop:            return (rect.topLeft()+rect.topRight())*0.5;
22675     case aiTopRightRim:    return rect.center()+(rect.topRight()-rect.center())*1/qSqrt(2);
22676     case aiRight:          return (rect.topRight()+rect.bottomRight())*0.5;
22677     case aiBottomRightRim: return rect.center()+(rect.bottomRight()-rect.center())*1/qSqrt(2);
22678     case aiBottom:         return (rect.bottomLeft()+rect.bottomRight())*0.5;
22679     case aiBottomLeftRim:  return rect.center()+(rect.bottomLeft()-rect.center())*1/qSqrt(2);
22680     case aiLeft:           return (rect.topLeft()+rect.bottomLeft())*0.5;
22681     case aiCenter:         return (rect.topLeft()+rect.bottomRight())*0.5;
22682   }
22683   
22684   qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId;
22685   return QPointF();
22686 }
22687
22688 /*! \internal
22689
22690   Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected
22691   and mSelectedPen when it is.
22692 */
22693 QPen QCPItemEllipse::mainPen() const
22694 {
22695   return mSelected ? mSelectedPen : mPen;
22696 }
22697
22698 /*! \internal
22699
22700   Returns the brush that should be used for drawing fills of the item. Returns mBrush when the item
22701   is not selected and mSelectedBrush when it is.
22702 */
22703 QBrush QCPItemEllipse::mainBrush() const
22704 {
22705   return mSelected ? mSelectedBrush : mBrush;
22706 }
22707
22708
22709 ////////////////////////////////////////////////////////////////////////////////////////////////////
22710 //////////////////// QCPItemPixmap
22711 ////////////////////////////////////////////////////////////////////////////////////////////////////
22712
22713 /*! \class QCPItemPixmap
22714   \brief An arbitrary pixmap
22715
22716   \image html QCPItemPixmap.png "Pixmap example. Blue dotted circles are anchors, solid blue discs are positions."
22717
22718   It has two positions, \a topLeft and \a bottomRight, which define the rectangle the pixmap will
22719   be drawn in. Depending on the scale setting (\ref setScaled), the pixmap will be either scaled to
22720   fit the rectangle or be drawn aligned to the topLeft position.
22721   
22722   If scaling is enabled and \a topLeft is further to the bottom/right than \a bottomRight (as shown
22723   on the right side of the example image), the pixmap will be flipped in the respective
22724   orientations.
22725 */
22726
22727 /*!
22728   Creates a rectangle item and sets default values.
22729   
22730   The constructed item can be added to the plot with QCustomPlot::addItem.
22731 */
22732 QCPItemPixmap::QCPItemPixmap(QCustomPlot *parentPlot) :
22733   QCPAbstractItem(parentPlot),
22734   topLeft(createPosition(QLatin1String("topLeft"))),
22735   bottomRight(createPosition(QLatin1String("bottomRight"))),
22736   top(createAnchor(QLatin1String("top"), aiTop)),
22737   topRight(createAnchor(QLatin1String("topRight"), aiTopRight)),
22738   right(createAnchor(QLatin1String("right"), aiRight)),
22739   bottom(createAnchor(QLatin1String("bottom"), aiBottom)),
22740   bottomLeft(createAnchor(QLatin1String("bottomLeft"), aiBottomLeft)),
22741   left(createAnchor(QLatin1String("left"), aiLeft)),
22742   mScaledPixmapInvalidated(true)
22743 {
22744   topLeft->setCoords(0, 1);
22745   bottomRight->setCoords(1, 0);
22746   
22747   setPen(Qt::NoPen);
22748   setSelectedPen(QPen(Qt::blue));
22749   setScaled(false, Qt::KeepAspectRatio, Qt::SmoothTransformation);
22750 }
22751
22752 QCPItemPixmap::~QCPItemPixmap()
22753 {
22754 }
22755
22756 /*!
22757   Sets the pixmap that will be displayed.
22758 */
22759 void QCPItemPixmap::setPixmap(const QPixmap &pixmap)
22760 {
22761   mPixmap = pixmap;
22762   mScaledPixmapInvalidated = true;
22763   if (mPixmap.isNull())
22764     qDebug() << Q_FUNC_INFO << "pixmap is null";
22765 }
22766
22767 /*!
22768   Sets whether the pixmap will be scaled to fit the rectangle defined by the \a topLeft and \a
22769   bottomRight positions.
22770 */
22771 void QCPItemPixmap::setScaled(bool scaled, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformationMode)
22772 {
22773   mScaled = scaled;
22774   mAspectRatioMode = aspectRatioMode;
22775   mTransformationMode = transformationMode;
22776   mScaledPixmapInvalidated = true;
22777 }
22778
22779 /*!
22780   Sets the pen that will be used to draw a border around the pixmap.
22781   
22782   \see setSelectedPen, setBrush
22783 */
22784 void QCPItemPixmap::setPen(const QPen &pen)
22785 {
22786   mPen = pen;
22787 }
22788
22789 /*!
22790   Sets the pen that will be used to draw a border around the pixmap when selected
22791   
22792   \see setPen, setSelected
22793 */
22794 void QCPItemPixmap::setSelectedPen(const QPen &pen)
22795 {
22796   mSelectedPen = pen;
22797 }
22798
22799 /* inherits documentation from base class */
22800 double QCPItemPixmap::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
22801 {
22802   Q_UNUSED(details)
22803   if (onlySelectable && !mSelectable)
22804     return -1;
22805   
22806   return rectSelectTest(getFinalRect(), pos, true);
22807 }
22808
22809 /* inherits documentation from base class */
22810 void QCPItemPixmap::draw(QCPPainter *painter)
22811 {
22812   bool flipHorz = false;
22813   bool flipVert = false;
22814   QRect rect = getFinalRect(&flipHorz, &flipVert);
22815   double clipPad = mainPen().style() == Qt::NoPen ? 0 : mainPen().widthF();
22816   QRect boundingRect = rect.adjusted(-clipPad, -clipPad, clipPad, clipPad);
22817   if (boundingRect.intersects(clipRect()))
22818   {
22819     updateScaledPixmap(rect, flipHorz, flipVert);
22820     painter->drawPixmap(rect.topLeft(), mScaled ? mScaledPixmap : mPixmap);
22821     QPen pen = mainPen();
22822     if (pen.style() != Qt::NoPen)
22823     {
22824       painter->setPen(pen);
22825       painter->setBrush(Qt::NoBrush);
22826       painter->drawRect(rect);
22827     }
22828   }
22829 }
22830
22831 /* inherits documentation from base class */
22832 QPointF QCPItemPixmap::anchorPixelPoint(int anchorId) const
22833 {
22834   bool flipHorz;
22835   bool flipVert;
22836   QRect rect = getFinalRect(&flipHorz, &flipVert);
22837   // we actually want denormal rects (negative width/height) here, so restore
22838   // the flipped state:
22839   if (flipHorz)
22840     rect.adjust(rect.width(), 0, -rect.width(), 0);
22841   if (flipVert)
22842     rect.adjust(0, rect.height(), 0, -rect.height());
22843   
22844   switch (anchorId)
22845   {
22846     case aiTop:         return (rect.topLeft()+rect.topRight())*0.5;
22847     case aiTopRight:    return rect.topRight();
22848     case aiRight:       return (rect.topRight()+rect.bottomRight())*0.5;
22849     case aiBottom:      return (rect.bottomLeft()+rect.bottomRight())*0.5;
22850     case aiBottomLeft:  return rect.bottomLeft();
22851     case aiLeft:        return (rect.topLeft()+rect.bottomLeft())*0.5;;
22852   }
22853   
22854   qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId;
22855   return QPointF();
22856 }
22857
22858 /*! \internal
22859   
22860   Creates the buffered scaled image (\a mScaledPixmap) to fit the specified \a finalRect. The
22861   parameters \a flipHorz and \a flipVert control whether the resulting image shall be flipped
22862   horizontally or vertically. (This is used when \a topLeft is further to the bottom/right than \a
22863   bottomRight.)
22864   
22865   This function only creates the scaled pixmap when the buffered pixmap has a different size than
22866   the expected result, so calling this function repeatedly, e.g. in the \ref draw function, does
22867   not cause expensive rescaling every time.
22868   
22869   If scaling is disabled, sets mScaledPixmap to a null QPixmap.
22870 */
22871 void QCPItemPixmap::updateScaledPixmap(QRect finalRect, bool flipHorz, bool flipVert)
22872 {
22873   if (mPixmap.isNull())
22874     return;
22875   
22876   if (mScaled)
22877   {
22878     if (finalRect.isNull())
22879       finalRect = getFinalRect(&flipHorz, &flipVert);
22880     if (mScaledPixmapInvalidated || finalRect.size() != mScaledPixmap.size())
22881     {
22882       mScaledPixmap = mPixmap.scaled(finalRect.size(), mAspectRatioMode, mTransformationMode);
22883       if (flipHorz || flipVert)
22884         mScaledPixmap = QPixmap::fromImage(mScaledPixmap.toImage().mirrored(flipHorz, flipVert));
22885     }
22886   } else if (!mScaledPixmap.isNull())
22887     mScaledPixmap = QPixmap();
22888   mScaledPixmapInvalidated = false;
22889 }
22890
22891 /*! \internal
22892   
22893   Returns the final (tight) rect the pixmap is drawn in, depending on the current item positions
22894   and scaling settings.
22895   
22896   The output parameters \a flippedHorz and \a flippedVert return whether the pixmap should be drawn
22897   flipped horizontally or vertically in the returned rect. (The returned rect itself is always
22898   normalized, i.e. the top left corner of the rect is actually further to the top/left than the
22899   bottom right corner). This is the case when the item position \a topLeft is further to the
22900   bottom/right than \a bottomRight.
22901   
22902   If scaling is disabled, returns a rect with size of the original pixmap and the top left corner
22903   aligned with the item position \a topLeft. The position \a bottomRight is ignored.
22904 */
22905 QRect QCPItemPixmap::getFinalRect(bool *flippedHorz, bool *flippedVert) const
22906 {
22907   QRect result;
22908   bool flipHorz = false;
22909   bool flipVert = false;
22910   QPoint p1 = topLeft->pixelPoint().toPoint();
22911   QPoint p2 = bottomRight->pixelPoint().toPoint();
22912   if (p1 == p2)
22913     return QRect(p1, QSize(0, 0));
22914   if (mScaled)
22915   {
22916     QSize newSize = QSize(p2.x()-p1.x(), p2.y()-p1.y());
22917     QPoint topLeft = p1;
22918     if (newSize.width() < 0)
22919     {
22920       flipHorz = true;
22921       newSize.rwidth() *= -1;
22922       topLeft.setX(p2.x());
22923     }
22924     if (newSize.height() < 0)
22925     {
22926       flipVert = true;
22927       newSize.rheight() *= -1;
22928       topLeft.setY(p2.y());
22929     }
22930     QSize scaledSize = mPixmap.size();
22931     scaledSize.scale(newSize, mAspectRatioMode);
22932     result = QRect(topLeft, scaledSize);
22933   } else
22934   {
22935     result = QRect(p1, mPixmap.size());
22936   }
22937   if (flippedHorz)
22938     *flippedHorz = flipHorz;
22939   if (flippedVert)
22940     *flippedVert = flipVert;
22941   return result;
22942 }
22943
22944 /*! \internal
22945
22946   Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected
22947   and mSelectedPen when it is.
22948 */
22949 QPen QCPItemPixmap::mainPen() const
22950 {
22951   return mSelected ? mSelectedPen : mPen;
22952 }
22953
22954
22955 ////////////////////////////////////////////////////////////////////////////////////////////////////
22956 //////////////////// QCPItemTracer
22957 ////////////////////////////////////////////////////////////////////////////////////////////////////
22958
22959 /*! \class QCPItemTracer
22960   \brief Item that sticks to QCPGraph data points
22961
22962   \image html QCPItemTracer.png "Tracer example. Blue dotted circles are anchors, solid blue discs are positions."
22963
22964   The tracer can be connected with a QCPGraph via \ref setGraph. Then it will automatically adopt
22965   the coordinate axes of the graph and update its \a position to be on the graph's data. This means
22966   the key stays controllable via \ref setGraphKey, but the value will follow the graph data. If a
22967   QCPGraph is connected, note that setting the coordinates of the tracer item directly via \a
22968   position will have no effect because they will be overriden in the next redraw (this is when the
22969   coordinate update happens).
22970   
22971   If the specified key in \ref setGraphKey is outside the key bounds of the graph, the tracer will
22972   stay at the corresponding end of the graph.
22973   
22974   With \ref setInterpolating you may specify whether the tracer may only stay exactly on data
22975   points or whether it interpolates data points linearly, if given a key that lies between two data
22976   points of the graph.
22977   
22978   The tracer has different visual styles, see \ref setStyle. It is also possible to make the tracer
22979   have no own visual appearance (set the style to \ref tsNone), and just connect other item
22980   positions to the tracer \a position (used as an anchor) via \ref
22981   QCPItemPosition::setParentAnchor.
22982   
22983   \note The tracer position is only automatically updated upon redraws. So when the data of the
22984   graph changes and immediately afterwards (without a redraw) the a position coordinates of the
22985   tracer are retrieved, they will not reflect the updated data of the graph. In this case \ref
22986   updatePosition must be called manually, prior to reading the tracer coordinates.
22987 */
22988
22989 /*!
22990   Creates a tracer item and sets default values.
22991   
22992   The constructed item can be added to the plot with QCustomPlot::addItem.
22993 */
22994 QCPItemTracer::QCPItemTracer(QCustomPlot *parentPlot) :
22995   QCPAbstractItem(parentPlot),
22996   position(createPosition(QLatin1String("position"))),
22997   mGraph(0)
22998 {
22999   position->setCoords(0, 0);
23000
23001   setBrush(Qt::NoBrush);
23002   setSelectedBrush(Qt::NoBrush);
23003   setPen(QPen(Qt::black));
23004   setSelectedPen(QPen(Qt::blue, 2));
23005   setStyle(tsCrosshair);
23006   setSize(6);
23007   setInterpolating(false);
23008   setGraphKey(0);
23009 }
23010
23011 QCPItemTracer::~QCPItemTracer()
23012 {
23013 }
23014
23015 /*!
23016   Sets the pen that will be used to draw the line of the tracer
23017   
23018   \see setSelectedPen, setBrush
23019 */
23020 void QCPItemTracer::setPen(const QPen &pen)
23021 {
23022   mPen = pen;
23023 }
23024
23025 /*!
23026   Sets the pen that will be used to draw the line of the tracer when selected
23027   
23028   \see setPen, setSelected
23029 */
23030 void QCPItemTracer::setSelectedPen(const QPen &pen)
23031 {
23032   mSelectedPen = pen;
23033 }
23034
23035 /*!
23036   Sets the brush that will be used to draw any fills of the tracer
23037   
23038   \see setSelectedBrush, setPen
23039 */
23040 void QCPItemTracer::setBrush(const QBrush &brush)
23041 {
23042   mBrush = brush;
23043 }
23044
23045 /*!
23046   Sets the brush that will be used to draw any fills of the tracer, when selected.
23047   
23048   \see setBrush, setSelected
23049 */
23050 void QCPItemTracer::setSelectedBrush(const QBrush &brush)
23051 {
23052   mSelectedBrush = brush;
23053 }
23054
23055 /*!
23056   Sets the size of the tracer in pixels, if the style supports setting a size (e.g. \ref tsSquare
23057   does, \ref tsCrosshair does not).
23058 */
23059 void QCPItemTracer::setSize(double size)
23060 {
23061   mSize = size;
23062 }
23063
23064 /*!
23065   Sets the style/visual appearance of the tracer.
23066   
23067   If you only want to use the tracer \a position as an anchor for other items, set \a style to
23068   \ref tsNone.
23069 */
23070 void QCPItemTracer::setStyle(QCPItemTracer::TracerStyle style)
23071 {
23072   mStyle = style;
23073 }
23074
23075 /*!
23076   Sets the QCPGraph this tracer sticks to. The tracer \a position will be set to type
23077   QCPItemPosition::ptPlotCoords and the axes will be set to the axes of \a graph.
23078   
23079   To free the tracer from any graph, set \a graph to 0. The tracer \a position can then be placed
23080   freely like any other item position. This is the state the tracer will assume when its graph gets
23081   deleted while still attached to it.
23082   
23083   \see setGraphKey
23084 */
23085 void QCPItemTracer::setGraph(QCPGraph *graph)
23086 {
23087   if (graph)
23088   {
23089     if (graph->parentPlot() == mParentPlot)
23090     {
23091       position->setType(QCPItemPosition::ptPlotCoords);
23092       position->setAxes(graph->keyAxis(), graph->valueAxis());
23093       mGraph = graph;
23094       updatePosition();
23095     } else
23096       qDebug() << Q_FUNC_INFO << "graph isn't in same QCustomPlot instance as this item";
23097   } else
23098   {
23099     mGraph = 0;
23100   }
23101 }
23102
23103 /*!
23104   Sets the key of the graph's data point the tracer will be positioned at. This is the only free
23105   coordinate of a tracer when attached to a graph.
23106   
23107   Depending on \ref setInterpolating, the tracer will be either positioned on the data point
23108   closest to \a key, or will stay exactly at \a key and interpolate the value linearly.
23109   
23110   \see setGraph, setInterpolating
23111 */
23112 void QCPItemTracer::setGraphKey(double key)
23113 {
23114   mGraphKey = key;
23115 }
23116
23117 /*!
23118   Sets whether the value of the graph's data points shall be interpolated, when positioning the
23119   tracer.
23120   
23121   If \a enabled is set to false and a key is given with \ref setGraphKey, the tracer is placed on
23122   the data point of the graph which is closest to the key, but which is not necessarily exactly
23123   there. If \a enabled is true, the tracer will be positioned exactly at the specified key, and
23124   the appropriate value will be interpolated from the graph's data points linearly.
23125   
23126   \see setGraph, setGraphKey
23127 */
23128 void QCPItemTracer::setInterpolating(bool enabled)
23129 {
23130   mInterpolating = enabled;
23131 }
23132
23133 /* inherits documentation from base class */
23134 double QCPItemTracer::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
23135 {
23136   Q_UNUSED(details)
23137   if (onlySelectable && !mSelectable)
23138     return -1;
23139
23140   QPointF center(position->pixelPoint());
23141   double w = mSize/2.0;
23142   QRect clip = clipRect();
23143   switch (mStyle)
23144   {
23145     case tsNone: return -1;
23146     case tsPlus:
23147     {
23148       if (clipRect().intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect()))
23149         return qSqrt(qMin(distSqrToLine(center+QPointF(-w, 0), center+QPointF(w, 0), pos),
23150                           distSqrToLine(center+QPointF(0, -w), center+QPointF(0, w), pos)));
23151       break;
23152     }
23153     case tsCrosshair:
23154     {
23155       return qSqrt(qMin(distSqrToLine(QPointF(clip.left(), center.y()), QPointF(clip.right(), center.y()), pos),
23156                         distSqrToLine(QPointF(center.x(), clip.top()), QPointF(center.x(), clip.bottom()), pos)));
23157     }
23158     case tsCircle:
23159     {
23160       if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect()))
23161       {
23162         // distance to border:
23163         double centerDist = QVector2D(center-pos).length();
23164         double circleLine = w;
23165         double result = qAbs(centerDist-circleLine);
23166         // filled ellipse, allow click inside to count as hit:
23167         if (result > mParentPlot->selectionTolerance()*0.99 && mBrush.style() != Qt::NoBrush && mBrush.color().alpha() != 0)
23168         {
23169           if (centerDist <= circleLine)
23170             result = mParentPlot->selectionTolerance()*0.99;
23171         }
23172         return result;
23173       }
23174       break;
23175     }
23176     case tsSquare:
23177     {
23178       if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect()))
23179       {
23180         QRectF rect = QRectF(center-QPointF(w, w), center+QPointF(w, w));
23181         bool filledRect = mBrush.style() != Qt::NoBrush && mBrush.color().alpha() != 0;
23182         return rectSelectTest(rect, pos, filledRect);
23183       }
23184       break;
23185     }
23186   }
23187   return -1;
23188 }
23189
23190 /* inherits documentation from base class */
23191 void QCPItemTracer::draw(QCPPainter *painter)
23192 {
23193   updatePosition();
23194   if (mStyle == tsNone)
23195     return;
23196
23197   painter->setPen(mainPen());
23198   painter->setBrush(mainBrush());
23199   QPointF center(position->pixelPoint());
23200   double w = mSize/2.0;
23201   QRect clip = clipRect();
23202   switch (mStyle)
23203   {
23204     case tsNone: return;
23205     case tsPlus:
23206     {
23207       if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect()))
23208       {
23209         painter->drawLine(QLineF(center+QPointF(-w, 0), center+QPointF(w, 0)));
23210         painter->drawLine(QLineF(center+QPointF(0, -w), center+QPointF(0, w)));
23211       }
23212       break;
23213     }
23214     case tsCrosshair:
23215     {
23216       if (center.y() > clip.top() && center.y() < clip.bottom())
23217         painter->drawLine(QLineF(clip.left(), center.y(), clip.right(), center.y()));
23218       if (center.x() > clip.left() && center.x() < clip.right())
23219         painter->drawLine(QLineF(center.x(), clip.top(), center.x(), clip.bottom()));
23220       break;
23221     }
23222     case tsCircle:
23223     {
23224       if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect()))
23225         painter->drawEllipse(center, w, w);
23226       break;
23227     }
23228     case tsSquare:
23229     {
23230       if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect()))
23231         painter->drawRect(QRectF(center-QPointF(w, w), center+QPointF(w, w)));
23232       break;
23233     }
23234   }
23235 }
23236
23237 /*!
23238   If the tracer is connected with a graph (\ref setGraph), this function updates the tracer's \a
23239   position to reside on the graph data, depending on the configured key (\ref setGraphKey).
23240   
23241   It is called automatically on every redraw and normally doesn't need to be called manually. One
23242   exception is when you want to read the tracer coordinates via \a position and are not sure that
23243   the graph's data (or the tracer key with \ref setGraphKey) hasn't changed since the last redraw.
23244   In that situation, call this function before accessing \a position, to make sure you don't get
23245   out-of-date coordinates.
23246   
23247   If there is no graph set on this tracer, this function does nothing.
23248 */
23249 void QCPItemTracer::updatePosition()
23250 {
23251   if (mGraph)
23252   {
23253     if (mParentPlot->hasPlottable(mGraph))
23254     {
23255       if (mGraph->data()->size() > 1)
23256       {
23257         QCPDataMap::const_iterator first = mGraph->data()->constBegin();
23258         QCPDataMap::const_iterator last = mGraph->data()->constEnd()-1;
23259         if (mGraphKey < first.key())
23260           position->setCoords(first.key(), first.value().value);
23261         else if (mGraphKey > last.key())
23262           position->setCoords(last.key(), last.value().value);
23263         else
23264         {
23265           QCPDataMap::const_iterator it = mGraph->data()->lowerBound(mGraphKey);
23266           if (it != first) // mGraphKey is somewhere between iterators
23267           {
23268             QCPDataMap::const_iterator prevIt = it-1;
23269             if (mInterpolating)
23270             {
23271               // interpolate between iterators around mGraphKey:
23272               double slope = 0;
23273               if (!qFuzzyCompare((double)it.key(), (double)prevIt.key()))
23274                 slope = (it.value().value-prevIt.value().value)/(it.key()-prevIt.key());
23275               position->setCoords(mGraphKey, (mGraphKey-prevIt.key())*slope+prevIt.value().value);
23276             } else
23277             {
23278               // find iterator with key closest to mGraphKey:
23279               if (mGraphKey < (prevIt.key()+it.key())*0.5)
23280                 it = prevIt;
23281               position->setCoords(it.key(), it.value().value);
23282             }
23283           } else // mGraphKey is exactly on first iterator
23284             position->setCoords(it.key(), it.value().value);
23285         }
23286       } else if (mGraph->data()->size() == 1)
23287       {
23288         QCPDataMap::const_iterator it = mGraph->data()->constBegin();
23289         position->setCoords(it.key(), it.value().value);
23290       } else
23291         qDebug() << Q_FUNC_INFO << "graph has no data";
23292     } else
23293       qDebug() << Q_FUNC_INFO << "graph not contained in QCustomPlot instance (anymore)";
23294   }
23295 }
23296
23297 /*! \internal
23298
23299   Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected
23300   and mSelectedPen when it is.
23301 */
23302 QPen QCPItemTracer::mainPen() const
23303 {
23304   return mSelected ? mSelectedPen : mPen;
23305 }
23306
23307 /*! \internal
23308
23309   Returns the brush that should be used for drawing fills of the item. Returns mBrush when the item
23310   is not selected and mSelectedBrush when it is.
23311 */
23312 QBrush QCPItemTracer::mainBrush() const
23313 {
23314   return mSelected ? mSelectedBrush : mBrush;
23315 }
23316
23317
23318 ////////////////////////////////////////////////////////////////////////////////////////////////////
23319 //////////////////// QCPItemBracket
23320 ////////////////////////////////////////////////////////////////////////////////////////////////////
23321
23322 /*! \class QCPItemBracket
23323   \brief A bracket for referencing/highlighting certain parts in the plot.
23324
23325   \image html QCPItemBracket.png "Bracket example. Blue dotted circles are anchors, solid blue discs are positions."
23326
23327   It has two positions, \a left and \a right, which define the span of the bracket. If \a left is
23328   actually farther to the left than \a right, the bracket is opened to the bottom, as shown in the
23329   example image.
23330   
23331   The bracket supports multiple styles via \ref setStyle. The length, i.e. how far the bracket
23332   stretches away from the embraced span, can be controlled with \ref setLength.
23333   
23334   \image html QCPItemBracket-length.png
23335   <center>Demonstrating the effect of different values for \ref setLength, for styles \ref
23336   bsCalligraphic and \ref bsSquare. Anchors and positions are displayed for reference.</center>
23337   
23338   It provides an anchor \a center, to allow connection of other items, e.g. an arrow (QCPItemLine
23339   or QCPItemCurve) or a text label (QCPItemText), to the bracket.
23340 */
23341
23342 /*!
23343   Creates a bracket item and sets default values.
23344   
23345   The constructed item can be added to the plot with QCustomPlot::addItem.
23346 */
23347 QCPItemBracket::QCPItemBracket(QCustomPlot *parentPlot) :
23348   QCPAbstractItem(parentPlot),
23349   left(createPosition(QLatin1String("left"))),
23350   right(createPosition(QLatin1String("right"))),
23351   center(createAnchor(QLatin1String("center"), aiCenter))
23352 {
23353   left->setCoords(0, 0);
23354   right->setCoords(1, 1);
23355   
23356   setPen(QPen(Qt::black));
23357   setSelectedPen(QPen(Qt::blue, 2));
23358   setLength(8);
23359   setStyle(bsCalligraphic);
23360 }
23361
23362 QCPItemBracket::~QCPItemBracket()
23363 {
23364 }
23365
23366 /*!
23367   Sets the pen that will be used to draw the bracket.
23368   
23369   Note that when the style is \ref bsCalligraphic, only the color will be taken from the pen, the
23370   stroke and width are ignored. To change the apparent stroke width of a calligraphic bracket, use
23371   \ref setLength, which has a similar effect.
23372   
23373   \see setSelectedPen
23374 */
23375 void QCPItemBracket::setPen(const QPen &pen)
23376 {
23377   mPen = pen;
23378 }
23379
23380 /*!
23381   Sets the pen that will be used to draw the bracket when selected
23382   
23383   \see setPen, setSelected
23384 */
23385 void QCPItemBracket::setSelectedPen(const QPen &pen)
23386 {
23387   mSelectedPen = pen;
23388 }
23389
23390 /*!
23391   Sets the \a length in pixels how far the bracket extends in the direction towards the embraced
23392   span of the bracket (i.e. perpendicular to the <i>left</i>-<i>right</i>-direction)
23393   
23394   \image html QCPItemBracket-length.png
23395   <center>Demonstrating the effect of different values for \ref setLength, for styles \ref
23396   bsCalligraphic and \ref bsSquare. Anchors and positions are displayed for reference.</center>
23397 */
23398 void QCPItemBracket::setLength(double length)
23399 {
23400   mLength = length;
23401 }
23402
23403 /*!
23404   Sets the style of the bracket, i.e. the shape/visual appearance.
23405   
23406   \see setPen
23407 */
23408 void QCPItemBracket::setStyle(QCPItemBracket::BracketStyle style)
23409 {
23410   mStyle = style;
23411 }
23412
23413 /* inherits documentation from base class */
23414 double QCPItemBracket::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
23415 {
23416   Q_UNUSED(details)
23417   if (onlySelectable && !mSelectable)
23418     return -1;
23419   
23420   QVector2D leftVec(left->pixelPoint());
23421   QVector2D rightVec(right->pixelPoint());
23422   if (leftVec.toPoint() == rightVec.toPoint())
23423     return -1;
23424   
23425   QVector2D widthVec = (rightVec-leftVec)*0.5f;
23426   QVector2D lengthVec(-widthVec.y(), widthVec.x());
23427   lengthVec = lengthVec.normalized()*mLength;
23428   QVector2D centerVec = (rightVec+leftVec)*0.5f-lengthVec;
23429   
23430   switch (mStyle)
23431   {
23432     case QCPItemBracket::bsSquare:
23433     case QCPItemBracket::bsRound:
23434     {
23435       double a = distSqrToLine((centerVec-widthVec).toPointF(), (centerVec+widthVec).toPointF(), pos);
23436       double b = distSqrToLine((centerVec-widthVec+lengthVec).toPointF(), (centerVec-widthVec).toPointF(), pos);
23437       double c = distSqrToLine((centerVec+widthVec+lengthVec).toPointF(), (centerVec+widthVec).toPointF(), pos);
23438       return qSqrt(qMin(qMin(a, b), c));
23439     }
23440     case QCPItemBracket::bsCurly:
23441     case QCPItemBracket::bsCalligraphic:
23442     {
23443       double a = distSqrToLine((centerVec-widthVec*0.75f+lengthVec*0.15f).toPointF(), (centerVec+lengthVec*0.3f).toPointF(), pos);
23444       double b = distSqrToLine((centerVec-widthVec+lengthVec*0.7f).toPointF(), (centerVec-widthVec*0.75f+lengthVec*0.15f).toPointF(), pos);
23445       double c = distSqrToLine((centerVec+widthVec*0.75f+lengthVec*0.15f).toPointF(), (centerVec+lengthVec*0.3f).toPointF(), pos);
23446       double d = distSqrToLine((centerVec+widthVec+lengthVec*0.7f).toPointF(), (centerVec+widthVec*0.75f+lengthVec*0.15f).toPointF(), pos);
23447       return qSqrt(qMin(qMin(a, b), qMin(c, d)));
23448     }
23449   }
23450   return -1;
23451 }
23452
23453 /* inherits documentation from base class */
23454 void QCPItemBracket::draw(QCPPainter *painter)
23455 {
23456   QVector2D leftVec(left->pixelPoint());
23457   QVector2D rightVec(right->pixelPoint());
23458   if (leftVec.toPoint() == rightVec.toPoint())
23459     return;
23460   
23461   QVector2D widthVec = (rightVec-leftVec)*0.5f;
23462   QVector2D lengthVec(-widthVec.y(), widthVec.x());
23463   lengthVec = lengthVec.normalized()*mLength;
23464   QVector2D centerVec = (rightVec+leftVec)*0.5f-lengthVec;
23465
23466   QPolygon boundingPoly;
23467   boundingPoly << leftVec.toPoint() << rightVec.toPoint()
23468                << (rightVec-lengthVec).toPoint() << (leftVec-lengthVec).toPoint();
23469   QRect clip = clipRect().adjusted(-mainPen().widthF(), -mainPen().widthF(), mainPen().widthF(), mainPen().widthF());
23470   if (clip.intersects(boundingPoly.boundingRect()))
23471   {
23472     painter->setPen(mainPen());
23473     switch (mStyle)
23474     {
23475       case bsSquare:
23476       {
23477         painter->drawLine((centerVec+widthVec).toPointF(), (centerVec-widthVec).toPointF());
23478         painter->drawLine((centerVec+widthVec).toPointF(), (centerVec+widthVec+lengthVec).toPointF());
23479         painter->drawLine((centerVec-widthVec).toPointF(), (centerVec-widthVec+lengthVec).toPointF());
23480         break;
23481       }
23482       case bsRound:
23483       {
23484         painter->setBrush(Qt::NoBrush);
23485         QPainterPath path;
23486         path.moveTo((centerVec+widthVec+lengthVec).toPointF());
23487         path.cubicTo((centerVec+widthVec).toPointF(), (centerVec+widthVec).toPointF(), centerVec.toPointF());
23488         path.cubicTo((centerVec-widthVec).toPointF(), (centerVec-widthVec).toPointF(), (centerVec-widthVec+lengthVec).toPointF());
23489         painter->drawPath(path);
23490         break;
23491       }
23492       case bsCurly:
23493       {
23494         painter->setBrush(Qt::NoBrush);
23495         QPainterPath path;
23496         path.moveTo((centerVec+widthVec+lengthVec).toPointF());
23497         path.cubicTo((centerVec+widthVec-lengthVec*0.8f).toPointF(), (centerVec+0.4f*widthVec+lengthVec).toPointF(), centerVec.toPointF());
23498         path.cubicTo((centerVec-0.4f*widthVec+lengthVec).toPointF(), (centerVec-widthVec-lengthVec*0.8f).toPointF(), (centerVec-widthVec+lengthVec).toPointF());
23499         painter->drawPath(path);
23500         break;
23501       }
23502       case bsCalligraphic:
23503       {
23504         painter->setPen(Qt::NoPen);
23505         painter->setBrush(QBrush(mainPen().color()));
23506         QPainterPath path;
23507         path.moveTo((centerVec+widthVec+lengthVec).toPointF());
23508         
23509         path.cubicTo((centerVec+widthVec-lengthVec*0.8f).toPointF(), (centerVec+0.4f*widthVec+0.8f*lengthVec).toPointF(), centerVec.toPointF());
23510         path.cubicTo((centerVec-0.4f*widthVec+0.8f*lengthVec).toPointF(), (centerVec-widthVec-lengthVec*0.8f).toPointF(), (centerVec-widthVec+lengthVec).toPointF());
23511         
23512         path.cubicTo((centerVec-widthVec-lengthVec*0.5f).toPointF(), (centerVec-0.2f*widthVec+1.2f*lengthVec).toPointF(), (centerVec+lengthVec*0.2f).toPointF());
23513         path.cubicTo((centerVec+0.2f*widthVec+1.2f*lengthVec).toPointF(), (centerVec+widthVec-lengthVec*0.5f).toPointF(), (centerVec+widthVec+lengthVec).toPointF());
23514         
23515         painter->drawPath(path);
23516         break;
23517       }
23518     }
23519   }
23520 }
23521
23522 /* inherits documentation from base class */
23523 QPointF QCPItemBracket::anchorPixelPoint(int anchorId) const
23524 {
23525   QVector2D leftVec(left->pixelPoint());
23526   QVector2D rightVec(right->pixelPoint());
23527   if (leftVec.toPoint() == rightVec.toPoint())
23528     return leftVec.toPointF();
23529   
23530   QVector2D widthVec = (rightVec-leftVec)*0.5f;
23531   QVector2D lengthVec(-widthVec.y(), widthVec.x());
23532   lengthVec = lengthVec.normalized()*mLength;
23533   QVector2D centerVec = (rightVec+leftVec)*0.5f-lengthVec;
23534   
23535   switch (anchorId)
23536   {
23537     case aiCenter:
23538       return centerVec.toPointF();
23539   }
23540   qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId;
23541   return QPointF();
23542 }
23543
23544 /*! \internal
23545
23546   Returns the pen that should be used for drawing lines. Returns mPen when the
23547   item is not selected and mSelectedPen when it is.
23548 */
23549 QPen QCPItemBracket::mainPen() const
23550 {
23551     return mSelected ? mSelectedPen : mPen;
23552 }
23553